1/* 2 * FocalTech FT6236 TouchScreen driver. 3 * 4 * Copyright (c) 2010 Focal tech Ltd. 5 * 6 * This software is licensed under the terms of the GNU General Public 7 * License version 2, as published by the Free Software Foundation, and 8 * may be copied, distributed, and modified under those terms. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 */ 15 16#include <linux/delay.h> 17#include <linux/gpio/consumer.h> 18#include <linux/i2c.h> 19#include <linux/input.h> 20#include <linux/input/mt.h> 21#include <linux/interrupt.h> 22#include <linux/module.h> 23#include <linux/property.h> 24 25#define FT6236_MAX_TOUCH_POINTS 2 26 27#define FT6236_REG_TH_GROUP 0x80 28#define FT6236_REG_PERIODACTIVE 0x88 29#define FT6236_REG_LIB_VER_H 0xa1 30#define FT6236_REG_LIB_VER_L 0xa2 31#define FT6236_REG_CIPHER 0xa3 32#define FT6236_REG_FIRMID 0xa6 33#define FT6236_REG_FOCALTECH_ID 0xa8 34#define FT6236_REG_RELEASE_CODE_ID 0xaf 35 36#define FT6236_EVENT_PRESS_DOWN 0 37#define FT6236_EVENT_LIFT_UP 1 38#define FT6236_EVENT_CONTACT 2 39#define FT6236_EVENT_NO_EVENT 3 40 41struct ft6236_data { 42 struct i2c_client *client; 43 struct input_dev *input; 44 struct gpio_desc *reset_gpio; 45 u32 max_x; 46 u32 max_y; 47 bool invert_x; 48 bool invert_y; 49 bool swap_xy; 50}; 51 52/* 53 * This struct is a touchpoint as stored in hardware. Note that the id, 54 * as well as the event, are stored in the upper nybble of the hi byte. 55 */ 56struct ft6236_touchpoint { 57 union { 58 u8 xhi; 59 u8 event; 60 }; 61 u8 xlo; 62 union { 63 u8 yhi; 64 u8 id; 65 }; 66 u8 ylo; 67 u8 weight; 68 u8 misc; 69} __packed; 70 71/* This packet represents the register map as read from offset 0 */ 72struct ft6236_packet { 73 u8 dev_mode; 74 u8 gest_id; 75 u8 touches; 76 struct ft6236_touchpoint points[FT6236_MAX_TOUCH_POINTS]; 77} __packed; 78 79static int ft6236_read(struct i2c_client *client, u8 reg, u8 len, void *data) 80{ 81 int error; 82 83 error = i2c_smbus_read_i2c_block_data(client, reg, len, data); 84 if (error < 0) 85 return error; 86 87 if (error != len) 88 return -EIO; 89 90 return 0; 91} 92 93static irqreturn_t ft6236_interrupt(int irq, void *dev_id) 94{ 95 struct ft6236_data *ft6236 = dev_id; 96 struct device *dev = &ft6236->client->dev; 97 struct input_dev *input = ft6236->input; 98 struct ft6236_packet buf; 99 u8 touches; 100 int i, error; 101 102 error = ft6236_read(ft6236->client, 0, sizeof(buf), &buf); 103 if (error) { 104 dev_err(dev, "read touchdata failed %d\n", error); 105 return IRQ_HANDLED; 106 } 107 108 touches = buf.touches & 0xf; 109 if (touches > FT6236_MAX_TOUCH_POINTS) { 110 dev_dbg(dev, 111 "%d touch points reported, only %d are supported\n", 112 touches, FT6236_MAX_TOUCH_POINTS); 113 touches = FT6236_MAX_TOUCH_POINTS; 114 } 115 116 for (i = 0; i < touches; i++) { 117 struct ft6236_touchpoint *point = &buf.points[i]; 118 u16 x = ((point->xhi & 0xf) << 8) | buf.points[i].xlo; 119 u16 y = ((point->yhi & 0xf) << 8) | buf.points[i].ylo; 120 u8 event = point->event >> 6; 121 u8 id = point->id >> 4; 122 bool act = (event == FT6236_EVENT_PRESS_DOWN || 123 event == FT6236_EVENT_CONTACT); 124 125 input_mt_slot(input, id); 126 input_mt_report_slot_state(input, MT_TOOL_FINGER, act); 127 if (!act) 128 continue; 129 130 if (ft6236->invert_x) 131 x = ft6236->max_x - x; 132 133 if (ft6236->invert_y) 134 y = ft6236->max_y - y; 135 136 if (ft6236->swap_xy) { 137 input_report_abs(input, ABS_MT_POSITION_X, y); 138 input_report_abs(input, ABS_MT_POSITION_Y, x); 139 } else { 140 input_report_abs(input, ABS_MT_POSITION_X, x); 141 input_report_abs(input, ABS_MT_POSITION_Y, y); 142 } 143 } 144 145 input_mt_sync_frame(input); 146 input_sync(input); 147 148 return IRQ_HANDLED; 149} 150 151static u8 ft6236_debug_read_byte(struct ft6236_data *ft6236, u8 reg) 152{ 153 struct i2c_client *client = ft6236->client; 154 u8 val = 0; 155 int error; 156 157 error = ft6236_read(client, reg, 1, &val); 158 if (error) 159 dev_dbg(&client->dev, 160 "error reading register 0x%02x: %d\n", reg, error); 161 162 return val; 163} 164 165static void ft6236_debug_info(struct ft6236_data *ft6236) 166{ 167 struct device *dev = &ft6236->client->dev; 168 169 dev_dbg(dev, "Touch threshold is %d\n", 170 ft6236_debug_read_byte(ft6236, FT6236_REG_TH_GROUP) * 4); 171 dev_dbg(dev, "Report rate is %dHz\n", 172 ft6236_debug_read_byte(ft6236, FT6236_REG_PERIODACTIVE) * 10); 173 dev_dbg(dev, "Firmware library version 0x%02x%02x\n", 174 ft6236_debug_read_byte(ft6236, FT6236_REG_LIB_VER_H), 175 ft6236_debug_read_byte(ft6236, FT6236_REG_LIB_VER_L)); 176 dev_dbg(dev, "Firmware version 0x%02x\n", 177 ft6236_debug_read_byte(ft6236, FT6236_REG_FIRMID)); 178 dev_dbg(dev, "Chip vendor ID 0x%02x\n", 179 ft6236_debug_read_byte(ft6236, FT6236_REG_CIPHER)); 180 dev_dbg(dev, "CTPM vendor ID 0x%02x\n", 181 ft6236_debug_read_byte(ft6236, FT6236_REG_FOCALTECH_ID)); 182 dev_dbg(dev, "Release code version 0x%02x\n", 183 ft6236_debug_read_byte(ft6236, FT6236_REG_RELEASE_CODE_ID)); 184} 185 186static void ft6236_reset(struct ft6236_data *ft6236) 187{ 188 if (!ft6236->reset_gpio) 189 return; 190 191 gpiod_set_value_cansleep(ft6236->reset_gpio, 1); 192 usleep_range(5000, 20000); 193 gpiod_set_value_cansleep(ft6236->reset_gpio, 0); 194 msleep(300); 195} 196 197static int ft6236_probe(struct i2c_client *client, 198 const struct i2c_device_id *id) 199{ 200 struct device *dev = &client->dev; 201 struct ft6236_data *ft6236; 202 struct input_dev *input; 203 u32 fuzz_x = 0, fuzz_y = 0; 204 u8 val; 205 int error; 206 207 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) 208 return -ENXIO; 209 210 if (!client->irq) { 211 dev_err(dev, "irq is missing\n"); 212 return -EINVAL; 213 } 214 215 ft6236 = devm_kzalloc(dev, sizeof(*ft6236), GFP_KERNEL); 216 if (!ft6236) 217 return -ENOMEM; 218 219 ft6236->client = client; 220 ft6236->reset_gpio = devm_gpiod_get_optional(dev, "reset", 221 GPIOD_OUT_LOW); 222 if (IS_ERR(ft6236->reset_gpio)) { 223 error = PTR_ERR(ft6236->reset_gpio); 224 if (error != -EPROBE_DEFER) 225 dev_err(dev, "error getting reset gpio: %d\n", error); 226 return error; 227 } 228 229 ft6236_reset(ft6236); 230 231 /* verify that the controller is present */ 232 error = ft6236_read(client, 0x00, 1, &val); 233 if (error) { 234 dev_err(dev, "failed to read from controller: %d\n", error); 235 return error; 236 } 237 238 ft6236_debug_info(ft6236); 239 240 input = devm_input_allocate_device(dev); 241 if (!input) 242 return -ENOMEM; 243 244 ft6236->input = input; 245 input->name = client->name; 246 input->id.bustype = BUS_I2C; 247 248 if (device_property_read_u32(dev, "touchscreen-size-x", 249 &ft6236->max_x) || 250 device_property_read_u32(dev, "touchscreen-size-y", 251 &ft6236->max_y)) { 252 dev_err(dev, "touchscreen-size-x and/or -y missing\n"); 253 return -EINVAL; 254 } 255 256 device_property_read_u32(dev, "touchscreen-fuzz-x", &fuzz_x); 257 device_property_read_u32(dev, "touchscreen-fuzz-y", &fuzz_y); 258 ft6236->invert_x = device_property_read_bool(dev, 259 "touchscreen-inverted-x"); 260 ft6236->invert_y = device_property_read_bool(dev, 261 "touchscreen-inverted-y"); 262 ft6236->swap_xy = device_property_read_bool(dev, 263 "touchscreen-swapped-x-y"); 264 265 if (ft6236->swap_xy) { 266 input_set_abs_params(input, ABS_MT_POSITION_X, 0, 267 ft6236->max_y, fuzz_y, 0); 268 input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 269 ft6236->max_x, fuzz_x, 0); 270 } else { 271 input_set_abs_params(input, ABS_MT_POSITION_X, 0, 272 ft6236->max_x, fuzz_x, 0); 273 input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 274 ft6236->max_y, fuzz_y, 0); 275 } 276 277 error = input_mt_init_slots(input, FT6236_MAX_TOUCH_POINTS, 278 INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); 279 if (error) 280 return error; 281 282 error = devm_request_threaded_irq(dev, client->irq, NULL, 283 ft6236_interrupt, IRQF_ONESHOT, 284 client->name, ft6236); 285 if (error) { 286 dev_err(dev, "request irq %d failed: %d\n", client->irq, error); 287 return error; 288 } 289 290 error = input_register_device(input); 291 if (error) { 292 dev_err(dev, "failed to register input device: %d\n", error); 293 return error; 294 } 295 296 return 0; 297} 298 299#ifdef CONFIG_OF 300static const struct of_device_id ft6236_of_match[] = { 301 { .compatible = "focaltech,ft6236", }, 302 { } 303}; 304MODULE_DEVICE_TABLE(of, ft6236_of_match); 305#endif 306 307static const struct i2c_device_id ft6236_id[] = { 308 { "ft6236", }, 309 { } 310}; 311MODULE_DEVICE_TABLE(i2c, ft6236_id); 312 313static struct i2c_driver ft6236_driver = { 314 .driver = { 315 .name = "ft6236", 316 .of_match_table = of_match_ptr(ft6236_of_match), 317 }, 318 .probe = ft6236_probe, 319 .id_table = ft6236_id, 320}; 321module_i2c_driver(ft6236_driver); 322 323MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>"); 324MODULE_AUTHOR("Noralf Tr��nnes <noralf@tronnes.org>"); 325MODULE_DESCRIPTION("FocalTech FT6236 TouchScreen driver"); 326MODULE_LICENSE("GPL v2"); 327