This repository has been archived on 2025-06-06. You can view files and clone it, but cannot push or open issues or pull requests.
Files
android-g900/kernel-2.6.33/drivers/input/touchscreen/ak4183.c
2010-09-05 20:34:22 +06:00

491 lines
12 KiB
C
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* drivers/input/touchscreen/ak4183.c
*
* Copyright (c) 2010 Angell
* Angell Fear <angell@angellfear.ru>
*
* Using code from:
* tsc2007.c
*
* Copyright (c) 2008 MtekVision Co., Ltd.
* Copyright (c) 2005 David Brownell
* Copyright (c) 2006 Nokia Corporation
* - corgi_ts.c
* Copyright (C) 2004-2005 Richard Purdie
* - omap_ts.[hc], ads7846.h, ts_osk.c
* Copyright (C) 2002 MontaVista Software
* Copyright (C) 2004 Texas Instruments
* Copyright (C) 2005 Dirk Behme
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/i2c/ak4183.h>
#define TS_POLL_DELAY 10 /* us delay between samples */
#define TS_POLL_PERIOD 100 /* us delay between samples */
#define AK4183_12BIT 1 /* 12 bit mode */
#define devdbg(x...) printk(x)
#define AK4183_BIT_S (0x1 << 7)
#define AK4183_BIT_A2 (0x1 << 6)
#define AK4183_BIT_A1 (0x1 << 5)
#define AK4183_BIT_A0 (0x1 << 4)
#define AK4183_BIT_PD0 (0x1 << 2)
#define AK4183_BIT_MODE (0x1 << 1)
#define MAX_12BIT ((1 << 12) - 1)
#if AK4183_12BIT
#define ADC_ON_12BIT 0
#else
#define ADC_ON_12BIT AK4183_BIT_MODE
#endif
#define READ_X ( ADC_ON_12BIT | AK4183_BIT_S | AK4183_BIT_A2 )
#define READ_Y ( ADC_ON_12BIT | AK4183_BIT_S | AK4183_BIT_A0 | AK4183_BIT_A2 )
#define READ_Z1 ( ADC_ON_12BIT | AK4183_BIT_S | AK4183_BIT_A1 | AK4183_BIT_A2 )
#define READ_Z2 ( ADC_ON_12BIT | AK4183_BIT_S | AK4183_BIT_A0 | AK4183_BIT_A1 | AK4183_BIT_A2 )
#define READ_AX ( ADC_ON_12BIT | AK4183_BIT_S )
#define READ_AY ( ADC_ON_12BIT | AK4183_BIT_S | AK4183_BIT_A0 )
#define READ_AXY ( ADC_ON_12BIT | AK4183_BIT_S | AK4183_BIT_A1 )
#define PWRDOWN ( AK4183_BIT_S | AK4183_BIT_PD0 )
/*
BIT Name Function
7 S Start Bit. “1” Accelerate and Axis Command, “0”: Sleep mode Command
6-4 A2-A0 Channel Selection Bits. Analog inputs to the A/D converter and the activated driver switches are
selected. Please see the following table for the detail.
3 X1 Dont care
2 PD0 Power down bit (refer to power-down control)
1 MODE Resolution of A/D converter. “0”: 12 bit output “1”: 8 bit output
0 X2 Dont care
*/
struct ts_event {
u16 x;
u16 y;
u16 z1, z2;
u32 prs;
};
struct ak4183 {
struct input_dev *input;
char phys[32];
struct delayed_work work;
struct i2c_client *client;
u16 model;
u16 x_plate_ohms;
u16 y_plate_ohms;
bool pendown;
int irq;
int (*get_pendown_state)(void);
void (*clear_penirq)(void);
};
/*
0 4000 left 32 ïðàâî 419
âåðõ ëåâî X=0x0150 Y=0x0ee0 P=0x0106
âåðõ ïðàâî X=0x0e50 Y=0x0ee0 P=0x0104
íèç ëåâî X=0x0110 Y=0x0090 P=0x00ea
íèç ïðàâî X=0x0dc0 Y=0x0080 P=0x00ec
wince
CalibrationData 2174,1990 563,3553 700,465 3463,506 3440,3547
wince hex
CalibrationData 0x87E,0x7C6 0x233,0xDE1 0x2BC,0x1D1 0xD87,0x1FA 0xD70,0xDDB
ñåðåäèíà, âåðõ ëåâî,íèç ëåâî,íèç ïðàâî, âåðõ ïðàâî
*/
static int abs_x[3] = {0x0110, 0x0dc0, 1};
module_param_array(abs_x, int, NULL, 0);
MODULE_PARM_DESC(abs_x, "Touchscreen absolute X min, max, fuzz");
static int abs_y[3] = {0x0ee0, 0x0080, 1};
module_param_array(abs_y, int, NULL, 0);
MODULE_PARM_DESC(abs_y, "Touchscreen absolute Y min, max, fuzz");
static int abs_p[3] = {0, MAX_12BIT, 0};
module_param_array(abs_p, int, NULL, 0);
MODULE_PARM_DESC(abs_p, "Touchscreen absolute Pressure min, max, fuzz");
static inline int ak4183_xfer(struct ak4183 *tsc, u8 cmd)
{
s32 data;
u16 val;
data = i2c_smbus_read_word_data(tsc->client, cmd);
if (data < 0) {
dev_err(&tsc->client->dev, "i2c io error: %d\n", data);
return data;
}
/* The protocol and raw data format from i2c interface:
* S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P
* Where DataLow has [D11-D4], DataHigh has [D3-D0 << 4 | Dummy 4bit].
*/
val = swab16(data) >> 4;
devdbg("data: 0x%x, val: 0x%x\n", data, val);
return val;
}
static void ak4183_read_values(struct ak4183 *tsc, struct ts_event *tc)
{
/* y- still on; turn on only y+ (and ADC) */
tc->y = ak4183_xfer(tsc, READ_Y);
/* turn y- off, x+ on, then leave in lowpower */
tc->x = ak4183_xfer(tsc, READ_X);
/* turn y+ off, x- on; we'll use formula #1 */
tc->z1 = ak4183_xfer(tsc, READ_Z1);
tc->z2 = ak4183_xfer(tsc, READ_Z2);
/** calcilate pressure resistance **/
tc->prs = 0;
/* range filtering */
if (tc->x == MAX_12BIT)
tc->x = 0;
/* compute touch pressure resistance using equation #1 */
#if 1
if (likely(tc->x && tc->z1)) {
//tc->prs = tc->z2 - tc->z1;
tc->prs = (tc->z2 / tc->z1 - 1);
tc->prs *= (tc->x/256);
tc->prs *= tsc->x_plate_ohms;
tc->prs /= tc->z1;
//tc->prs = (tc->prs + 2047) >> 12;
}else
tc->prs = 0;
#else
if(likely(tc->x && tc->z1)) {
//tc->prs = (tsc->x_plate_ohms * tc->x * (tc->z2 - tc->z1) ) / (4096 * tc->z1); // 12 áèò
tc->prs = tsc->x_plate_ohms;
tc->prs *= tc->x;
tc->prs /= 4096;
tc->prs *= ((4096/tc->z1) - 1);
tc->prs -= tsc->y_plate_ohms * (1 - (tc->y / 4096));
}
#endif
/*
Rtouch = (Rxplate) * (Xposition/4096) * [(Z2/Z1) 1]
Rtouch = (Rxplate*Xposition/4096)*[(4096/Z1) 1] Ryplate*[1 (Yposition/4096)]
*/
printk(KERN_INFO "ts: calc X = 0x%04x Y = 0x%04x Z1 = 0x%04x, Z2 = 0x%04x, PRS = 0x%04x\n", tc->x, tc->y, tc->z1, tc->z2, tc->prs);
/* Prepare for next touch reading - power down ADC, enable PENIRQ */
//ak4183_xfer(tsc, PWRDOWN);
}
static void ak4183_send_up_event(struct ak4183 *tsc)
{
struct input_dev *input = tsc->input;
devdbg("ak4183: send_up_event\n");
input_report_key(input, BTN_TOUCH, 0);
input_report_abs(input, ABS_PRESSURE, 0);
input_sync(input);
}
static void ak4183_work(struct work_struct *work)
{
struct ak4183 *ts = container_of(to_delayed_work(work), struct ak4183, work);
struct ts_event tc;
/*
* NOTE: We can't rely on the pressure to determine the pen down
* state, even though this controller has a pressure sensor.
* The pressure value can fluctuate for quite a while after
* lifting the pen and in some cases may not even settle at the
* expected value.
*
* The only safe way to check for the pen up condition is in the
* work function by reading the pen signal state (it's a GPIO
* and IRQ). Unfortunately such callback is not always available,
* in that case we have rely on the pressure anyway.
*/
if (ts->get_pendown_state) {
if (unlikely(!ts->get_pendown_state())) {
devdbg("ak4183: pendown_state = UP\n");
ak4183_send_up_event(ts);
ts->pendown = false;
goto out;
}
devdbg("ak4183: pen is still down\n");
}
ak4183_read_values(ts, &tc);
if (tc.prs > MAX_12BIT) {
/*
* Sample found inconsistent by debouncing or pressure is
* beyond the maximum. Don't report it to user space,
* repeat at least once more the measurement.
*/
devdbg("ak4183: ignored pressure %d\n", tc.prs);
goto out;
}
if (tc.prs) {
struct input_dev *input = ts->input;
if (!ts->pendown) {
devdbg("ak4183: DOWN\n");
input_report_key(input, BTN_TOUCH, 1);
ts->pendown = true;
}
input_report_abs(input, ABS_X, tc.x);
input_report_abs(input, ABS_Y, tc.y);
input_report_abs(input, ABS_PRESSURE, tc.prs);
input_sync(input);
} else if (!ts->get_pendown_state && ts->pendown) {
/*
* We don't have callback to check pendown state, so we
* have to assume that since pressure reported is 0 the
* pen was lifted up.
*/
ak4183_send_up_event(ts);
ts->pendown = false;
}
out:
if (ts->pendown)
schedule_delayed_work(&ts->work,
usecs_to_jiffies(TS_POLL_PERIOD));
else
enable_irq(ts->irq);
}
static irqreturn_t ak4183_irq(int irq, void *handle)
{
struct ak4183 *ts = handle;
if (!ts->get_pendown_state || likely(ts->get_pendown_state())) {
disable_irq_nosync(ts->irq);
schedule_delayed_work(&ts->work,
usecs_to_jiffies(TS_POLL_DELAY));
}
if (ts->clear_penirq)
{
ts->clear_penirq();
}
schedule_delayed_work(&ts->work,
usecs_to_jiffies(TS_POLL_DELAY));
return IRQ_HANDLED;
}
static void ak4183_free_irq(struct ak4183 *ts)
{
free_irq(ts->irq, ts);
if (cancel_delayed_work_sync(&ts->work)) {
/*
* Work was pending, therefore we need to enable
* IRQ here to balance the disable_irq() done in the
* interrupt handler.
*/
enable_irq(ts->irq);
}
}
static int __devinit ak4183_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct ak4183 *ts;
struct ak4183_platform_data *pdata = pdata = client->dev.platform_data;
struct input_dev *input_dev;
int err;
if (!pdata) {
dev_err(&client->dev, "platform data is required!\n");
printk(KERN_ERR "ak4183: platform data is required!\n");
return -EINVAL;
}
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_WORD_DATA))
{
printk(KERN_ERR "ak4183: err i2c_check_functionality!\n");
return -EIO;
}
ts = kzalloc(sizeof(struct ak4183), GFP_KERNEL);
input_dev = input_allocate_device();
if (!ts || !input_dev) {
err = -ENOMEM;
printk(KERN_ERR "ak4183: err input_allocate_device!\n");
goto err_free_mem;
}
ts->client = client;
ts->irq = client->irq;
ts->input = input_dev;
INIT_DELAYED_WORK(&ts->work, ak4183_work);
ts->model = pdata->model;
ts->x_plate_ohms = pdata->x_plate_ohms;
ts->get_pendown_state = pdata->get_pendown_state;
ts->clear_penirq = pdata->clear_penirq;
snprintf(ts->phys, sizeof(ts->phys),
"%s/input0", dev_name(&client->dev));
input_dev->name = "AK4183 Touchscreen";
input_dev->phys = ts->phys;
input_dev->id.bustype = BUS_I2C;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
// input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
input_set_abs_params(input_dev, ABS_X, abs_x[0], abs_x[1], abs_x[2], 0);
// input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
input_set_abs_params(input_dev, ABS_Y, abs_y[0], abs_y[1], abs_y[2], 0);
input_set_abs_params(input_dev, ABS_PRESSURE, abs_p[0], abs_p[1], abs_p[2], 0);
// input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
if (pdata->init_platform_hw)
pdata->init_platform_hw();
//76 I 1 0 FE
err = request_irq(ts->irq, ak4183_irq,
IRQF_TRIGGER_FALLING,
client->dev.driver->name, ts);
if (err < 0) {
dev_err(&client->dev, "irq %d busy?\n", ts->irq);
printk(KERN_ERR "ak4183: err irq %d busy?\n",ts->irq);
goto err_free_mem;
}
/* Prepare for touch readings - power down ADC and enable PENIRQ */
/* err = ak4183_xfer(ts, PWRDOWN);
if (err < 0){
goto err_free_irq;
printk(KERN_ERR "ak4183: err ak4183_xfer\n");
}
*/
err = input_register_device(input_dev);
if (err){
goto err_free_irq;
printk(KERN_ERR "ak4183: err input_register_device\n");
}
i2c_set_clientdata(client, ts);
return 0;
err_free_irq:
ak4183_free_irq(ts);
if (pdata->exit_platform_hw)
pdata->exit_platform_hw();
err_free_mem:
input_free_device(input_dev);
kfree(ts);
return err;
}
static int __devexit ak4183_remove(struct i2c_client *client)
{
struct ak4183 *ts = i2c_get_clientdata(client);
struct ak4183_platform_data *pdata = client->dev.platform_data;
ak4183_free_irq(ts);
if (pdata->exit_platform_hw)
pdata->exit_platform_hw();
input_unregister_device(ts->input);
kfree(ts);
return 0;
}
static struct i2c_device_id ak4183_idtable[] = {
{ "ak4183", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ak4183_idtable);
static struct i2c_driver ak4183_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "ak4183"
},
.id_table = ak4183_idtable,
.probe = ak4183_probe,
.remove = __devexit_p(ak4183_remove),
};
static int __init ak4183_init(void)
{
return i2c_add_driver(&ak4183_driver);
}
static void __exit ak4183_exit(void)
{
i2c_del_driver(&ak4183_driver);
}
module_init(ak4183_init);
module_exit(ak4183_exit);
MODULE_AUTHOR("angell <angell@angellfear.ru>");
MODULE_DESCRIPTION("AK4183 TouchScreen Driver");
MODULE_LICENSE("GPL");