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