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-10-26 16:04:19 +06:00

474 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 SashaG <...>
* Copyright (c) 2010 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/delay.h>
#include <linux/i2c/ak4183.h>
#define TS_POLL_DELAY 10 /* us delay between samples */
#define TS_POLL_PERIOD 1000 /* us delay between samples */
#define AK4183_12BIT 1 /*12 bit resolution*/
#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_R8BIT (0x1 << 1)
#define MAX_12BIT ((1 << 12) - 1)
#if AK4183_12BIT
#define ADC_ON_12BIT 0
#else
#define ADC_ON_12BIT AK4183_BIT_R8BIT
#endif
/*
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
*/
#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 )
#define samples 200
////touch calib test data
#define tmc_ax -11
//-0,05705; *200
#define tmc_bx 566382
//2831,91107; *200
#define tmc_x0 450
//450;
#define tmc_x10 476382
//bx-x0
#define tmc_ax_m_x0 -5135
//ax*x0
#define tmc_ay -11
//-0,05579;
#define tmc_by 593736
//2968,68213 *200
#define tmc_y0 440
//440;
#define tmc_y10 505736
//bx-x0
#define tmc_ay_m_y0 -4910
//ay*y0
struct ts_event {
u16 x;
u16 y;
u16 z1, z2;
};
struct ak4183 {
struct input_dev *input;
char phys[32];
struct delayed_work work;
struct i2c_client *client;
u16 model;
u16 x_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, 20};
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, 20};
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, 0xfff, 2};
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;
//dev_dbg(&tsc->client->dev, "data: 0x%x, val: 0x%x\n", data, val);
return val;
}
static u32 ak4183_read_values(struct ak4183 *tsc, struct ts_event *tc)
{
u32 rt = 0;
s32 rtt = 0;
//s32 x,y;
tc->x = ak4183_xfer(tsc, READ_X);//x
tc->y = ak4183_xfer(tsc, READ_Y);//y
//devdbg(KERN_INFO "AK4183: %5i;%5i;",
// tc->x,tc->y);
tc->z1 = ak4183_xfer(tsc,READ_Z1);//z1
tc->z2 = ak4183_xfer(tsc,READ_Z2);//z2
if (likely(tc->x && tc->z1)) {
/* compute touch pressure resistance using equation #1 */
rt = tc->x*(tc->z2-tc->z1)/(tc->z1);
if (rt<6350){ // min toch
rtt=rt-5000;//for func ; 0-max touch
if (rt<5000){rt=5000;} // max
rt=(6350-rt)*3;//0xFFF max
if (rt>=0xFFF) {rt=0xFFE;}//max
// devdbg(KERN_INFO "AK4183: %5u;%5u;%5u;%5u;%5u;",
// tc->x,tc->y,tc->z1,tc->z2,rtt);
}else{
rt=0;//no touch
}
}
//todo : need pwrdown
if (rt){//*200
tc->x=(u32)(((s32)(tc->x)*tmc_x10+rtt*tmc_ax_m_x0)/(tmc_x10+tmc_ax*rtt));
tc->y=(u32)(((s32)(tc->y)*tmc_y10+rtt*tmc_ay_m_y0)/(tmc_y10+tmc_ay*rtt));
}
return rt;
}
static void ak4183_send_up_event(struct ak4183 *tsc)
{
struct input_dev *input = tsc->input;
dev_dbg(&tsc->client->dev, "UP\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;
u32 rt;
/*
* 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 he 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())) {
ak4183_send_up_event(ts);
ts->pendown = false;
goto out;
}
//dev_dbg(&ts->client->dev, "pen is still down\n");
}
rt = ak4183_read_values(ts, &tc);
if (rt > 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.
*/
dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
goto out;
}
if (rt) {
struct input_dev *input = ts->input;
if (!ts->pendown) {
dev_dbg(&ts->client->dev, "DOWN\n");
input_report_key(input, BTN_TOUCH, 1);
ts->pendown = true;
}
devdbg("ak4183 x = 0x%4x,y = 0x%4x,rt = 0x%4x", tc.x, tc.y, rt);
input_report_abs(input, ABS_X, tc.x);
input_report_abs(input, ABS_Y, tc.y);
input_report_abs(input, ABS_PRESSURE, rt);
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");
return -EINVAL;
}
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_WORD_DATA))
{
dev_err(&client->dev, "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;
dev_err(&client->dev, "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, abs_x[0], abs_x[1], abs_x[2], 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, 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);
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;
dev_err(&client->dev, "err ak4183_xfer\n");
}
*/
err = input_register_device(input_dev);
if (err){
goto err_free_irq;
dev_err(&client->dev, "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", 0x48 },
{ }
};
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");