175259966STodd Fischer /*
275259966STodd Fischer * Touchscreen driver for the tps6507x chip.
375259966STodd Fischer *
475259966STodd Fischer * Copyright (c) 2009 RidgeRun (todd.fischer@ridgerun.com)
575259966STodd Fischer *
675259966STodd Fischer * Credits:
775259966STodd Fischer *
875259966STodd Fischer * Using code from tsc2007, MtekVision Co., Ltd.
975259966STodd Fischer *
1075259966STodd Fischer * For licencing details see kernel-base/COPYING
1175259966STodd Fischer *
1275259966STodd Fischer * TPS65070, TPS65073, TPS650731, and TPS650732 support
1375259966STodd Fischer * 10 bit touch screen interface.
1475259966STodd Fischer */
1575259966STodd Fischer
1675259966STodd Fischer #include <linux/module.h>
1775259966STodd Fischer #include <linux/workqueue.h>
1875259966STodd Fischer #include <linux/slab.h>
1975259966STodd Fischer #include <linux/input.h>
2075259966STodd Fischer #include <linux/platform_device.h>
2175259966STodd Fischer #include <linux/mfd/tps6507x.h>
2275259966STodd Fischer #include <linux/input/tps6507x-ts.h>
2375259966STodd Fischer #include <linux/delay.h>
2475259966STodd Fischer
2575259966STodd Fischer #define TSC_DEFAULT_POLL_PERIOD 30 /* ms */
2675259966STodd Fischer #define TPS_DEFAULT_MIN_PRESSURE 0x30
2775259966STodd Fischer #define MAX_10BIT ((1 << 10) - 1)
2875259966STodd Fischer
2975259966STodd Fischer #define TPS6507X_ADCONFIG_CONVERT_TS (TPS6507X_ADCONFIG_AD_ENABLE | \
3075259966STodd Fischer TPS6507X_ADCONFIG_START_CONVERSION | \
3175259966STodd Fischer TPS6507X_ADCONFIG_INPUT_REAL_TSC)
3275259966STodd Fischer #define TPS6507X_ADCONFIG_POWER_DOWN_TS (TPS6507X_ADCONFIG_INPUT_REAL_TSC)
3375259966STodd Fischer
3475259966STodd Fischer struct ts_event {
3575259966STodd Fischer u16 x;
3675259966STodd Fischer u16 y;
3775259966STodd Fischer u16 pressure;
3875259966STodd Fischer };
3975259966STodd Fischer
4075259966STodd Fischer struct tps6507x_ts {
4175259966STodd Fischer struct device *dev;
42*7cca5a34SDmitry Torokhov struct input_dev *input;
4375259966STodd Fischer struct tps6507x_dev *mfd;
445705b8acSDmitry Torokhov char phys[32];
455705b8acSDmitry Torokhov struct ts_event tc;
4602a71600SDmitry Torokhov u16 min_pressure;
4702a71600SDmitry Torokhov bool pendown;
4875259966STodd Fischer };
4975259966STodd Fischer
tps6507x_read_u8(struct tps6507x_ts * tsc,u8 reg,u8 * data)5075259966STodd Fischer static int tps6507x_read_u8(struct tps6507x_ts *tsc, u8 reg, u8 *data)
5175259966STodd Fischer {
52e5e66ed0SJavier Martinez Canillas return tsc->mfd->read_dev(tsc->mfd, reg, 1, data);
5375259966STodd Fischer }
5475259966STodd Fischer
tps6507x_write_u8(struct tps6507x_ts * tsc,u8 reg,u8 data)5575259966STodd Fischer static int tps6507x_write_u8(struct tps6507x_ts *tsc, u8 reg, u8 data)
5675259966STodd Fischer {
5775259966STodd Fischer return tsc->mfd->write_dev(tsc->mfd, reg, 1, &data);
5875259966STodd Fischer }
5975259966STodd Fischer
tps6507x_adc_conversion(struct tps6507x_ts * tsc,u8 tsc_mode,u16 * value)6075259966STodd Fischer static s32 tps6507x_adc_conversion(struct tps6507x_ts *tsc,
6175259966STodd Fischer u8 tsc_mode, u16 *value)
6275259966STodd Fischer {
6375259966STodd Fischer s32 ret;
6475259966STodd Fischer u8 adc_status;
6575259966STodd Fischer u8 result;
6675259966STodd Fischer
6775259966STodd Fischer /* Route input signal to A/D converter */
6875259966STodd Fischer
6975259966STodd Fischer ret = tps6507x_write_u8(tsc, TPS6507X_REG_TSCMODE, tsc_mode);
7075259966STodd Fischer if (ret) {
7175259966STodd Fischer dev_err(tsc->dev, "TSC mode read failed\n");
7275259966STodd Fischer goto err;
7375259966STodd Fischer }
7475259966STodd Fischer
7575259966STodd Fischer /* Start A/D conversion */
7675259966STodd Fischer
7775259966STodd Fischer ret = tps6507x_write_u8(tsc, TPS6507X_REG_ADCONFIG,
7875259966STodd Fischer TPS6507X_ADCONFIG_CONVERT_TS);
7975259966STodd Fischer if (ret) {
8075259966STodd Fischer dev_err(tsc->dev, "ADC config write failed\n");
8175259966STodd Fischer return ret;
8275259966STodd Fischer }
8375259966STodd Fischer
8475259966STodd Fischer do {
8575259966STodd Fischer ret = tps6507x_read_u8(tsc, TPS6507X_REG_ADCONFIG,
8675259966STodd Fischer &adc_status);
8775259966STodd Fischer if (ret) {
8875259966STodd Fischer dev_err(tsc->dev, "ADC config read failed\n");
8975259966STodd Fischer goto err;
9075259966STodd Fischer }
9175259966STodd Fischer } while (adc_status & TPS6507X_ADCONFIG_START_CONVERSION);
9275259966STodd Fischer
9375259966STodd Fischer ret = tps6507x_read_u8(tsc, TPS6507X_REG_ADRESULT_2, &result);
9475259966STodd Fischer if (ret) {
9575259966STodd Fischer dev_err(tsc->dev, "ADC result 2 read failed\n");
9675259966STodd Fischer goto err;
9775259966STodd Fischer }
9875259966STodd Fischer
9975259966STodd Fischer *value = (result & TPS6507X_REG_ADRESULT_2_MASK) << 8;
10075259966STodd Fischer
10175259966STodd Fischer ret = tps6507x_read_u8(tsc, TPS6507X_REG_ADRESULT_1, &result);
10275259966STodd Fischer if (ret) {
10375259966STodd Fischer dev_err(tsc->dev, "ADC result 1 read failed\n");
10475259966STodd Fischer goto err;
10575259966STodd Fischer }
10675259966STodd Fischer
10775259966STodd Fischer *value |= result;
10875259966STodd Fischer
10975259966STodd Fischer dev_dbg(tsc->dev, "TSC channel %d = 0x%X\n", tsc_mode, *value);
11075259966STodd Fischer
11175259966STodd Fischer err:
11275259966STodd Fischer return ret;
11375259966STodd Fischer }
11475259966STodd Fischer
11575259966STodd Fischer /* Need to call tps6507x_adc_standby() after using A/D converter for the
11675259966STodd Fischer * touch screen interrupt to work properly.
11775259966STodd Fischer */
11875259966STodd Fischer
tps6507x_adc_standby(struct tps6507x_ts * tsc)11975259966STodd Fischer static s32 tps6507x_adc_standby(struct tps6507x_ts *tsc)
12075259966STodd Fischer {
12175259966STodd Fischer s32 ret;
12275259966STodd Fischer u8 val;
12375259966STodd Fischer
12475259966STodd Fischer ret = tps6507x_write_u8(tsc, TPS6507X_REG_ADCONFIG,
12575259966STodd Fischer TPS6507X_ADCONFIG_INPUT_TSC);
12675259966STodd Fischer if (ret)
12775259966STodd Fischer return ret;
12875259966STodd Fischer
12975259966STodd Fischer ret = tps6507x_write_u8(tsc, TPS6507X_REG_TSCMODE,
13075259966STodd Fischer TPS6507X_TSCMODE_STANDBY);
13175259966STodd Fischer if (ret)
13275259966STodd Fischer return ret;
13375259966STodd Fischer
13475259966STodd Fischer ret = tps6507x_read_u8(tsc, TPS6507X_REG_INT, &val);
13575259966STodd Fischer if (ret)
13675259966STodd Fischer return ret;
13775259966STodd Fischer
13875259966STodd Fischer while (val & TPS6507X_REG_TSC_INT) {
13975259966STodd Fischer mdelay(10);
14075259966STodd Fischer ret = tps6507x_read_u8(tsc, TPS6507X_REG_INT, &val);
14175259966STodd Fischer if (ret)
14275259966STodd Fischer return ret;
14375259966STodd Fischer }
14475259966STodd Fischer
14575259966STodd Fischer return ret;
14675259966STodd Fischer }
14775259966STodd Fischer
tps6507x_ts_poll(struct input_dev * input_dev)148*7cca5a34SDmitry Torokhov static void tps6507x_ts_poll(struct input_dev *input_dev)
14975259966STodd Fischer {
150*7cca5a34SDmitry Torokhov struct tps6507x_ts *tsc = input_get_drvdata(input_dev);
15102a71600SDmitry Torokhov bool pendown;
15275259966STodd Fischer s32 ret;
15375259966STodd Fischer
15475259966STodd Fischer ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_PRESSURE,
15575259966STodd Fischer &tsc->tc.pressure);
15675259966STodd Fischer if (ret)
15775259966STodd Fischer goto done;
15875259966STodd Fischer
15975259966STodd Fischer pendown = tsc->tc.pressure > tsc->min_pressure;
16075259966STodd Fischer
16175259966STodd Fischer if (unlikely(!pendown && tsc->pendown)) {
16275259966STodd Fischer dev_dbg(tsc->dev, "UP\n");
16375259966STodd Fischer input_report_key(input_dev, BTN_TOUCH, 0);
16475259966STodd Fischer input_report_abs(input_dev, ABS_PRESSURE, 0);
16575259966STodd Fischer input_sync(input_dev);
16602a71600SDmitry Torokhov tsc->pendown = false;
16775259966STodd Fischer }
16875259966STodd Fischer
16975259966STodd Fischer if (pendown) {
17075259966STodd Fischer
17175259966STodd Fischer if (!tsc->pendown) {
17275259966STodd Fischer dev_dbg(tsc->dev, "DOWN\n");
17375259966STodd Fischer input_report_key(input_dev, BTN_TOUCH, 1);
17475259966STodd Fischer } else
17575259966STodd Fischer dev_dbg(tsc->dev, "still down\n");
17675259966STodd Fischer
17775259966STodd Fischer ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_X_POSITION,
17875259966STodd Fischer &tsc->tc.x);
17975259966STodd Fischer if (ret)
18075259966STodd Fischer goto done;
18175259966STodd Fischer
18275259966STodd Fischer ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_Y_POSITION,
18375259966STodd Fischer &tsc->tc.y);
18475259966STodd Fischer if (ret)
18575259966STodd Fischer goto done;
18675259966STodd Fischer
18775259966STodd Fischer input_report_abs(input_dev, ABS_X, tsc->tc.x);
18875259966STodd Fischer input_report_abs(input_dev, ABS_Y, tsc->tc.y);
18975259966STodd Fischer input_report_abs(input_dev, ABS_PRESSURE, tsc->tc.pressure);
19075259966STodd Fischer input_sync(input_dev);
19102a71600SDmitry Torokhov tsc->pendown = true;
19275259966STodd Fischer }
19375259966STodd Fischer
19475259966STodd Fischer done:
1955705b8acSDmitry Torokhov tps6507x_adc_standby(tsc);
19675259966STodd Fischer }
19775259966STodd Fischer
tps6507x_ts_probe(struct platform_device * pdev)19875259966STodd Fischer static int tps6507x_ts_probe(struct platform_device *pdev)
19975259966STodd Fischer {
20075259966STodd Fischer struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
2015705b8acSDmitry Torokhov const struct tps6507x_board *tps_board;
2025705b8acSDmitry Torokhov const struct touchscreen_init_data *init_data;
2035705b8acSDmitry Torokhov struct tps6507x_ts *tsc;
20475259966STodd Fischer struct input_dev *input_dev;
2055705b8acSDmitry Torokhov int error;
20675259966STodd Fischer
2075705b8acSDmitry Torokhov /*
20875259966STodd Fischer * tps_board points to pmic related constants
20975259966STodd Fischer * coming from the board-evm file.
21075259966STodd Fischer */
2115705b8acSDmitry Torokhov tps_board = dev_get_platdata(tps6507x_dev->dev);
21275259966STodd Fischer if (!tps_board) {
21375259966STodd Fischer dev_err(tps6507x_dev->dev,
21475259966STodd Fischer "Could not find tps6507x platform data\n");
2155705b8acSDmitry Torokhov return -ENODEV;
21675259966STodd Fischer }
21775259966STodd Fischer
2185705b8acSDmitry Torokhov /*
21975259966STodd Fischer * init_data points to array of regulator_init structures
22075259966STodd Fischer * coming from the board-evm file.
22175259966STodd Fischer */
22275259966STodd Fischer init_data = tps_board->tps6507x_ts_init_data;
22375259966STodd Fischer
2242e2a0db8SYegor Yefremov tsc = devm_kzalloc(&pdev->dev, sizeof(struct tps6507x_ts), GFP_KERNEL);
22575259966STodd Fischer if (!tsc) {
22675259966STodd Fischer dev_err(tps6507x_dev->dev, "failed to allocate driver data\n");
2275705b8acSDmitry Torokhov return -ENOMEM;
22875259966STodd Fischer }
22975259966STodd Fischer
23075259966STodd Fischer tsc->mfd = tps6507x_dev;
23175259966STodd Fischer tsc->dev = tps6507x_dev->dev;
2325705b8acSDmitry Torokhov tsc->min_pressure = init_data ?
2335705b8acSDmitry Torokhov init_data->min_pressure : TPS_DEFAULT_MIN_PRESSURE;
2345705b8acSDmitry Torokhov
2355705b8acSDmitry Torokhov snprintf(tsc->phys, sizeof(tsc->phys),
2365705b8acSDmitry Torokhov "%s/input0", dev_name(tsc->dev));
2375705b8acSDmitry Torokhov
238*7cca5a34SDmitry Torokhov input_dev = devm_input_allocate_device(&pdev->dev);
239*7cca5a34SDmitry Torokhov if (!input_dev) {
2405705b8acSDmitry Torokhov dev_err(tsc->dev, "Failed to allocate polled input device.\n");
2412e2a0db8SYegor Yefremov return -ENOMEM;
24275259966STodd Fischer }
24375259966STodd Fischer
244*7cca5a34SDmitry Torokhov tsc->input = input_dev;
245*7cca5a34SDmitry Torokhov input_set_drvdata(input_dev, tsc);
2465705b8acSDmitry Torokhov
247*7cca5a34SDmitry Torokhov input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
24875259966STodd Fischer input_set_abs_params(input_dev, ABS_X, 0, MAX_10BIT, 0, 0);
24975259966STodd Fischer input_set_abs_params(input_dev, ABS_Y, 0, MAX_10BIT, 0, 0);
25075259966STodd Fischer input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_10BIT, 0, 0);
25175259966STodd Fischer
25275259966STodd Fischer input_dev->name = "TPS6507x Touchscreen";
25375259966STodd Fischer input_dev->phys = tsc->phys;
2545705b8acSDmitry Torokhov input_dev->dev.parent = tsc->dev;
2555705b8acSDmitry Torokhov input_dev->id.bustype = BUS_I2C;
25675259966STodd Fischer if (init_data) {
25775259966STodd Fischer input_dev->id.vendor = init_data->vendor;
25875259966STodd Fischer input_dev->id.product = init_data->product;
25975259966STodd Fischer input_dev->id.version = init_data->version;
26075259966STodd Fischer }
26175259966STodd Fischer
26275259966STodd Fischer error = tps6507x_adc_standby(tsc);
26375259966STodd Fischer if (error)
2642e2a0db8SYegor Yefremov return error;
26575259966STodd Fischer
266*7cca5a34SDmitry Torokhov error = input_setup_polling(input_dev, tps6507x_ts_poll);
267*7cca5a34SDmitry Torokhov if (error)
268*7cca5a34SDmitry Torokhov return error;
269*7cca5a34SDmitry Torokhov
270*7cca5a34SDmitry Torokhov input_set_poll_interval(input_dev,
271*7cca5a34SDmitry Torokhov init_data ? init_data->poll_period :
272*7cca5a34SDmitry Torokhov TSC_DEFAULT_POLL_PERIOD);
273*7cca5a34SDmitry Torokhov
274*7cca5a34SDmitry Torokhov error = input_register_device(input_dev);
27575259966STodd Fischer if (error)
27675259966STodd Fischer return error;
27775259966STodd Fischer
27875259966STodd Fischer return 0;
27975259966STodd Fischer }
28075259966STodd Fischer
28175259966STodd Fischer static struct platform_driver tps6507x_ts_driver = {
28275259966STodd Fischer .driver = {
28375259966STodd Fischer .name = "tps6507x-ts",
28475259966STodd Fischer },
28575259966STodd Fischer .probe = tps6507x_ts_probe,
28675259966STodd Fischer };
287cdcc96e2SJJ Ding module_platform_driver(tps6507x_ts_driver);
28875259966STodd Fischer
28975259966STodd Fischer MODULE_AUTHOR("Todd Fischer <todd.fischer@ridgerun.com>");
29075259966STodd Fischer MODULE_DESCRIPTION("TPS6507x - TouchScreen driver");
29175259966STodd Fischer MODULE_LICENSE("GPL v2");
29279026ff2SUwe Kleine-König MODULE_ALIAS("platform:tps6507x-ts");
293