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 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 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 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 11975259966STodd Fischer static s32 tps6507x_adc_standby(struct tps6507x_ts *tsc) 12075259966STodd Fischer { 12175259966STodd Fischer s32 ret; 12275259966STodd Fischer s32 loops = 0; 12375259966STodd Fischer u8 val; 12475259966STodd Fischer 12575259966STodd Fischer ret = tps6507x_write_u8(tsc, TPS6507X_REG_ADCONFIG, 12675259966STodd Fischer TPS6507X_ADCONFIG_INPUT_TSC); 12775259966STodd Fischer if (ret) 12875259966STodd Fischer return ret; 12975259966STodd Fischer 13075259966STodd Fischer ret = tps6507x_write_u8(tsc, TPS6507X_REG_TSCMODE, 13175259966STodd Fischer TPS6507X_TSCMODE_STANDBY); 13275259966STodd Fischer if (ret) 13375259966STodd Fischer return ret; 13475259966STodd Fischer 13575259966STodd Fischer ret = tps6507x_read_u8(tsc, TPS6507X_REG_INT, &val); 13675259966STodd Fischer if (ret) 13775259966STodd Fischer return ret; 13875259966STodd Fischer 13975259966STodd Fischer while (val & TPS6507X_REG_TSC_INT) { 14075259966STodd Fischer mdelay(10); 14175259966STodd Fischer ret = tps6507x_read_u8(tsc, TPS6507X_REG_INT, &val); 14275259966STodd Fischer if (ret) 14375259966STodd Fischer return ret; 14475259966STodd Fischer loops++; 14575259966STodd Fischer } 14675259966STodd Fischer 14775259966STodd Fischer return ret; 14875259966STodd Fischer } 14975259966STodd Fischer 150*7cca5a34SDmitry Torokhov static void tps6507x_ts_poll(struct input_dev *input_dev) 15175259966STodd Fischer { 152*7cca5a34SDmitry Torokhov struct tps6507x_ts *tsc = input_get_drvdata(input_dev); 15302a71600SDmitry Torokhov bool pendown; 15475259966STodd Fischer s32 ret; 15575259966STodd Fischer 15675259966STodd Fischer ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_PRESSURE, 15775259966STodd Fischer &tsc->tc.pressure); 15875259966STodd Fischer if (ret) 15975259966STodd Fischer goto done; 16075259966STodd Fischer 16175259966STodd Fischer pendown = tsc->tc.pressure > tsc->min_pressure; 16275259966STodd Fischer 16375259966STodd Fischer if (unlikely(!pendown && tsc->pendown)) { 16475259966STodd Fischer dev_dbg(tsc->dev, "UP\n"); 16575259966STodd Fischer input_report_key(input_dev, BTN_TOUCH, 0); 16675259966STodd Fischer input_report_abs(input_dev, ABS_PRESSURE, 0); 16775259966STodd Fischer input_sync(input_dev); 16802a71600SDmitry Torokhov tsc->pendown = false; 16975259966STodd Fischer } 17075259966STodd Fischer 17175259966STodd Fischer if (pendown) { 17275259966STodd Fischer 17375259966STodd Fischer if (!tsc->pendown) { 17475259966STodd Fischer dev_dbg(tsc->dev, "DOWN\n"); 17575259966STodd Fischer input_report_key(input_dev, BTN_TOUCH, 1); 17675259966STodd Fischer } else 17775259966STodd Fischer dev_dbg(tsc->dev, "still down\n"); 17875259966STodd Fischer 17975259966STodd Fischer ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_X_POSITION, 18075259966STodd Fischer &tsc->tc.x); 18175259966STodd Fischer if (ret) 18275259966STodd Fischer goto done; 18375259966STodd Fischer 18475259966STodd Fischer ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_Y_POSITION, 18575259966STodd Fischer &tsc->tc.y); 18675259966STodd Fischer if (ret) 18775259966STodd Fischer goto done; 18875259966STodd Fischer 18975259966STodd Fischer input_report_abs(input_dev, ABS_X, tsc->tc.x); 19075259966STodd Fischer input_report_abs(input_dev, ABS_Y, tsc->tc.y); 19175259966STodd Fischer input_report_abs(input_dev, ABS_PRESSURE, tsc->tc.pressure); 19275259966STodd Fischer input_sync(input_dev); 19302a71600SDmitry Torokhov tsc->pendown = true; 19475259966STodd Fischer } 19575259966STodd Fischer 19675259966STodd Fischer done: 1975705b8acSDmitry Torokhov tps6507x_adc_standby(tsc); 19875259966STodd Fischer } 19975259966STodd Fischer 20075259966STodd Fischer static int tps6507x_ts_probe(struct platform_device *pdev) 20175259966STodd Fischer { 20275259966STodd Fischer struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent); 2035705b8acSDmitry Torokhov const struct tps6507x_board *tps_board; 2045705b8acSDmitry Torokhov const struct touchscreen_init_data *init_data; 2055705b8acSDmitry Torokhov struct tps6507x_ts *tsc; 20675259966STodd Fischer struct input_dev *input_dev; 2075705b8acSDmitry Torokhov int error; 20875259966STodd Fischer 2095705b8acSDmitry Torokhov /* 21075259966STodd Fischer * tps_board points to pmic related constants 21175259966STodd Fischer * coming from the board-evm file. 21275259966STodd Fischer */ 2135705b8acSDmitry Torokhov tps_board = dev_get_platdata(tps6507x_dev->dev); 21475259966STodd Fischer if (!tps_board) { 21575259966STodd Fischer dev_err(tps6507x_dev->dev, 21675259966STodd Fischer "Could not find tps6507x platform data\n"); 2175705b8acSDmitry Torokhov return -ENODEV; 21875259966STodd Fischer } 21975259966STodd Fischer 2205705b8acSDmitry Torokhov /* 22175259966STodd Fischer * init_data points to array of regulator_init structures 22275259966STodd Fischer * coming from the board-evm file. 22375259966STodd Fischer */ 22475259966STodd Fischer init_data = tps_board->tps6507x_ts_init_data; 22575259966STodd Fischer 2262e2a0db8SYegor Yefremov tsc = devm_kzalloc(&pdev->dev, sizeof(struct tps6507x_ts), GFP_KERNEL); 22775259966STodd Fischer if (!tsc) { 22875259966STodd Fischer dev_err(tps6507x_dev->dev, "failed to allocate driver data\n"); 2295705b8acSDmitry Torokhov return -ENOMEM; 23075259966STodd Fischer } 23175259966STodd Fischer 23275259966STodd Fischer tsc->mfd = tps6507x_dev; 23375259966STodd Fischer tsc->dev = tps6507x_dev->dev; 2345705b8acSDmitry Torokhov tsc->min_pressure = init_data ? 2355705b8acSDmitry Torokhov init_data->min_pressure : TPS_DEFAULT_MIN_PRESSURE; 2365705b8acSDmitry Torokhov 2375705b8acSDmitry Torokhov snprintf(tsc->phys, sizeof(tsc->phys), 2385705b8acSDmitry Torokhov "%s/input0", dev_name(tsc->dev)); 2395705b8acSDmitry Torokhov 240*7cca5a34SDmitry Torokhov input_dev = devm_input_allocate_device(&pdev->dev); 241*7cca5a34SDmitry Torokhov if (!input_dev) { 2425705b8acSDmitry Torokhov dev_err(tsc->dev, "Failed to allocate polled input device.\n"); 2432e2a0db8SYegor Yefremov return -ENOMEM; 24475259966STodd Fischer } 24575259966STodd Fischer 246*7cca5a34SDmitry Torokhov tsc->input = input_dev; 247*7cca5a34SDmitry Torokhov input_set_drvdata(input_dev, tsc); 2485705b8acSDmitry Torokhov 249*7cca5a34SDmitry Torokhov input_set_capability(input_dev, EV_KEY, BTN_TOUCH); 25075259966STodd Fischer input_set_abs_params(input_dev, ABS_X, 0, MAX_10BIT, 0, 0); 25175259966STodd Fischer input_set_abs_params(input_dev, ABS_Y, 0, MAX_10BIT, 0, 0); 25275259966STodd Fischer input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_10BIT, 0, 0); 25375259966STodd Fischer 25475259966STodd Fischer input_dev->name = "TPS6507x Touchscreen"; 25575259966STodd Fischer input_dev->phys = tsc->phys; 2565705b8acSDmitry Torokhov input_dev->dev.parent = tsc->dev; 2575705b8acSDmitry Torokhov input_dev->id.bustype = BUS_I2C; 25875259966STodd Fischer if (init_data) { 25975259966STodd Fischer input_dev->id.vendor = init_data->vendor; 26075259966STodd Fischer input_dev->id.product = init_data->product; 26175259966STodd Fischer input_dev->id.version = init_data->version; 26275259966STodd Fischer } 26375259966STodd Fischer 26475259966STodd Fischer error = tps6507x_adc_standby(tsc); 26575259966STodd Fischer if (error) 2662e2a0db8SYegor Yefremov return error; 26775259966STodd Fischer 268*7cca5a34SDmitry Torokhov error = input_setup_polling(input_dev, tps6507x_ts_poll); 269*7cca5a34SDmitry Torokhov if (error) 270*7cca5a34SDmitry Torokhov return error; 271*7cca5a34SDmitry Torokhov 272*7cca5a34SDmitry Torokhov input_set_poll_interval(input_dev, 273*7cca5a34SDmitry Torokhov init_data ? init_data->poll_period : 274*7cca5a34SDmitry Torokhov TSC_DEFAULT_POLL_PERIOD); 275*7cca5a34SDmitry Torokhov 276*7cca5a34SDmitry Torokhov error = input_register_device(input_dev); 27775259966STodd Fischer if (error) 27875259966STodd Fischer return error; 27975259966STodd Fischer 28075259966STodd Fischer return 0; 28175259966STodd Fischer } 28275259966STodd Fischer 28375259966STodd Fischer static struct platform_driver tps6507x_ts_driver = { 28475259966STodd Fischer .driver = { 28575259966STodd Fischer .name = "tps6507x-ts", 28675259966STodd Fischer }, 28775259966STodd Fischer .probe = tps6507x_ts_probe, 28875259966STodd Fischer }; 289cdcc96e2SJJ Ding module_platform_driver(tps6507x_ts_driver); 29075259966STodd Fischer 29175259966STodd Fischer MODULE_AUTHOR("Todd Fischer <todd.fischer@ridgerun.com>"); 29275259966STodd Fischer MODULE_DESCRIPTION("TPS6507x - TouchScreen driver"); 29375259966STodd Fischer MODULE_LICENSE("GPL v2"); 29479026ff2SUwe Kleine-König MODULE_ALIAS("platform:tps6507x-ts"); 295