1/* 2 * Touchscreen driver for the tps6507x chip. 3 * 4 * Copyright (c) 2009 RidgeRun (todd.fischer@ridgerun.com) 5 * 6 * Credits: 7 * 8 * Using code from tsc2007, MtekVision Co., Ltd. 9 * 10 * For licencing details see kernel-base/COPYING 11 * 12 * TPS65070, TPS65073, TPS650731, and TPS650732 support 13 * 10 bit touch screen interface. 14 */ 15 16#include <linux/module.h> 17#include <linux/workqueue.h> 18#include <linux/slab.h> 19#include <linux/input.h> 20#include <linux/input-polldev.h> 21#include <linux/platform_device.h> 22#include <linux/mfd/tps6507x.h> 23#include <linux/input/tps6507x-ts.h> 24#include <linux/delay.h> 25 26#define TSC_DEFAULT_POLL_PERIOD 30 /* ms */ 27#define TPS_DEFAULT_MIN_PRESSURE 0x30 28#define MAX_10BIT ((1 << 10) - 1) 29 30#define TPS6507X_ADCONFIG_CONVERT_TS (TPS6507X_ADCONFIG_AD_ENABLE | \ 31 TPS6507X_ADCONFIG_START_CONVERSION | \ 32 TPS6507X_ADCONFIG_INPUT_REAL_TSC) 33#define TPS6507X_ADCONFIG_POWER_DOWN_TS (TPS6507X_ADCONFIG_INPUT_REAL_TSC) 34 35struct ts_event { 36 u16 x; 37 u16 y; 38 u16 pressure; 39}; 40 41struct tps6507x_ts { 42 struct device *dev; 43 struct input_polled_dev *poll_dev; 44 struct tps6507x_dev *mfd; 45 char phys[32]; 46 struct ts_event tc; 47 u16 min_pressure; 48 bool pendown; 49}; 50 51static int tps6507x_read_u8(struct tps6507x_ts *tsc, u8 reg, u8 *data) 52{ 53 int err; 54 55 err = tsc->mfd->read_dev(tsc->mfd, reg, 1, data); 56 57 if (err) 58 return err; 59 60 return 0; 61} 62 63static int tps6507x_write_u8(struct tps6507x_ts *tsc, u8 reg, u8 data) 64{ 65 return tsc->mfd->write_dev(tsc->mfd, reg, 1, &data); 66} 67 68static s32 tps6507x_adc_conversion(struct tps6507x_ts *tsc, 69 u8 tsc_mode, u16 *value) 70{ 71 s32 ret; 72 u8 adc_status; 73 u8 result; 74 75 /* Route input signal to A/D converter */ 76 77 ret = tps6507x_write_u8(tsc, TPS6507X_REG_TSCMODE, tsc_mode); 78 if (ret) { 79 dev_err(tsc->dev, "TSC mode read failed\n"); 80 goto err; 81 } 82 83 /* Start A/D conversion */ 84 85 ret = tps6507x_write_u8(tsc, TPS6507X_REG_ADCONFIG, 86 TPS6507X_ADCONFIG_CONVERT_TS); 87 if (ret) { 88 dev_err(tsc->dev, "ADC config write failed\n"); 89 return ret; 90 } 91 92 do { 93 ret = tps6507x_read_u8(tsc, TPS6507X_REG_ADCONFIG, 94 &adc_status); 95 if (ret) { 96 dev_err(tsc->dev, "ADC config read failed\n"); 97 goto err; 98 } 99 } while (adc_status & TPS6507X_ADCONFIG_START_CONVERSION); 100 101 ret = tps6507x_read_u8(tsc, TPS6507X_REG_ADRESULT_2, &result); 102 if (ret) { 103 dev_err(tsc->dev, "ADC result 2 read failed\n"); 104 goto err; 105 } 106 107 *value = (result & TPS6507X_REG_ADRESULT_2_MASK) << 8; 108 109 ret = tps6507x_read_u8(tsc, TPS6507X_REG_ADRESULT_1, &result); 110 if (ret) { 111 dev_err(tsc->dev, "ADC result 1 read failed\n"); 112 goto err; 113 } 114 115 *value |= result; 116 117 dev_dbg(tsc->dev, "TSC channel %d = 0x%X\n", tsc_mode, *value); 118 119err: 120 return ret; 121} 122 123/* Need to call tps6507x_adc_standby() after using A/D converter for the 124 * touch screen interrupt to work properly. 125 */ 126 127static s32 tps6507x_adc_standby(struct tps6507x_ts *tsc) 128{ 129 s32 ret; 130 s32 loops = 0; 131 u8 val; 132 133 ret = tps6507x_write_u8(tsc, TPS6507X_REG_ADCONFIG, 134 TPS6507X_ADCONFIG_INPUT_TSC); 135 if (ret) 136 return ret; 137 138 ret = tps6507x_write_u8(tsc, TPS6507X_REG_TSCMODE, 139 TPS6507X_TSCMODE_STANDBY); 140 if (ret) 141 return ret; 142 143 ret = tps6507x_read_u8(tsc, TPS6507X_REG_INT, &val); 144 if (ret) 145 return ret; 146 147 while (val & TPS6507X_REG_TSC_INT) { 148 mdelay(10); 149 ret = tps6507x_read_u8(tsc, TPS6507X_REG_INT, &val); 150 if (ret) 151 return ret; 152 loops++; 153 } 154 155 return ret; 156} 157 158static void tps6507x_ts_poll(struct input_polled_dev *poll_dev) 159{ 160 struct tps6507x_ts *tsc = poll_dev->private; 161 struct input_dev *input_dev = poll_dev->input; 162 bool pendown; 163 s32 ret; 164 165 ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_PRESSURE, 166 &tsc->tc.pressure); 167 if (ret) 168 goto done; 169 170 pendown = tsc->tc.pressure > tsc->min_pressure; 171 172 if (unlikely(!pendown && tsc->pendown)) { 173 dev_dbg(tsc->dev, "UP\n"); 174 input_report_key(input_dev, BTN_TOUCH, 0); 175 input_report_abs(input_dev, ABS_PRESSURE, 0); 176 input_sync(input_dev); 177 tsc->pendown = false; 178 } 179 180 if (pendown) { 181 182 if (!tsc->pendown) { 183 dev_dbg(tsc->dev, "DOWN\n"); 184 input_report_key(input_dev, BTN_TOUCH, 1); 185 } else 186 dev_dbg(tsc->dev, "still down\n"); 187 188 ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_X_POSITION, 189 &tsc->tc.x); 190 if (ret) 191 goto done; 192 193 ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_Y_POSITION, 194 &tsc->tc.y); 195 if (ret) 196 goto done; 197 198 input_report_abs(input_dev, ABS_X, tsc->tc.x); 199 input_report_abs(input_dev, ABS_Y, tsc->tc.y); 200 input_report_abs(input_dev, ABS_PRESSURE, tsc->tc.pressure); 201 input_sync(input_dev); 202 tsc->pendown = true; 203 } 204 205done: 206 tps6507x_adc_standby(tsc); 207} 208 209static int tps6507x_ts_probe(struct platform_device *pdev) 210{ 211 struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent); 212 const struct tps6507x_board *tps_board; 213 const struct touchscreen_init_data *init_data; 214 struct tps6507x_ts *tsc; 215 struct input_polled_dev *poll_dev; 216 struct input_dev *input_dev; 217 int error; 218 219 /* 220 * tps_board points to pmic related constants 221 * coming from the board-evm file. 222 */ 223 tps_board = dev_get_platdata(tps6507x_dev->dev); 224 if (!tps_board) { 225 dev_err(tps6507x_dev->dev, 226 "Could not find tps6507x platform data\n"); 227 return -ENODEV; 228 } 229 230 /* 231 * init_data points to array of regulator_init structures 232 * coming from the board-evm file. 233 */ 234 init_data = tps_board->tps6507x_ts_init_data; 235 236 tsc = kzalloc(sizeof(struct tps6507x_ts), GFP_KERNEL); 237 if (!tsc) { 238 dev_err(tps6507x_dev->dev, "failed to allocate driver data\n"); 239 return -ENOMEM; 240 } 241 242 tsc->mfd = tps6507x_dev; 243 tsc->dev = tps6507x_dev->dev; 244 tsc->min_pressure = init_data ? 245 init_data->min_pressure : TPS_DEFAULT_MIN_PRESSURE; 246 247 snprintf(tsc->phys, sizeof(tsc->phys), 248 "%s/input0", dev_name(tsc->dev)); 249 250 poll_dev = input_allocate_polled_device(); 251 if (!poll_dev) { 252 dev_err(tsc->dev, "Failed to allocate polled input device.\n"); 253 error = -ENOMEM; 254 goto err_free_mem; 255 } 256 257 tsc->poll_dev = poll_dev; 258 259 poll_dev->private = tsc; 260 poll_dev->poll = tps6507x_ts_poll; 261 poll_dev->poll_interval = init_data ? 262 init_data->poll_period : TSC_DEFAULT_POLL_PERIOD; 263 264 input_dev = poll_dev->input; 265 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 266 input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); 267 268 input_set_abs_params(input_dev, ABS_X, 0, MAX_10BIT, 0, 0); 269 input_set_abs_params(input_dev, ABS_Y, 0, MAX_10BIT, 0, 0); 270 input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_10BIT, 0, 0); 271 272 input_dev->name = "TPS6507x Touchscreen"; 273 input_dev->phys = tsc->phys; 274 input_dev->dev.parent = tsc->dev; 275 input_dev->id.bustype = BUS_I2C; 276 if (init_data) { 277 input_dev->id.vendor = init_data->vendor; 278 input_dev->id.product = init_data->product; 279 input_dev->id.version = init_data->version; 280 } 281 282 error = tps6507x_adc_standby(tsc); 283 if (error) 284 goto err_free_polled_dev; 285 286 error = input_register_polled_device(poll_dev); 287 if (error) 288 goto err_free_polled_dev; 289 290 platform_set_drvdata(pdev, tsc); 291 292 return 0; 293 294err_free_polled_dev: 295 input_free_polled_device(poll_dev); 296err_free_mem: 297 kfree(tsc); 298 return error; 299} 300 301static int tps6507x_ts_remove(struct platform_device *pdev) 302{ 303 struct tps6507x_ts *tsc = platform_get_drvdata(pdev); 304 struct input_polled_dev *poll_dev = tsc->poll_dev; 305 306 input_unregister_polled_device(poll_dev); 307 input_free_polled_device(poll_dev); 308 309 kfree(tsc); 310 311 return 0; 312} 313 314static struct platform_driver tps6507x_ts_driver = { 315 .driver = { 316 .name = "tps6507x-ts", 317 }, 318 .probe = tps6507x_ts_probe, 319 .remove = tps6507x_ts_remove, 320}; 321module_platform_driver(tps6507x_ts_driver); 322 323MODULE_AUTHOR("Todd Fischer <todd.fischer@ridgerun.com>"); 324MODULE_DESCRIPTION("TPS6507x - TouchScreen driver"); 325MODULE_LICENSE("GPL v2"); 326MODULE_ALIAS("platform:tps6507x-ts"); 327