Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: exc3000 - add EXC80H60 and EXC80H84 support

This adds support for EXC80H60 and EXCH84 controllers, which
use a different event type id and have two extra bits for the
resolution (so the maximum is 16K instead of 4K).

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Acked-by: Rob Herring <robh@kernel.org>
Link: https://lore.kernel.org/r/20200805160520.456570-3-sebastian.reichel@collabora.com
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Sebastian Reichel and committed by
Dmitry Torokhov
3bdd21c6 1053653f

+70 -15
+4 -1
Documentation/devicetree/bindings/input/touchscreen/eeti,exc3000.yaml
··· 14 14 15 15 properties: 16 16 compatible: 17 - const: eeti,exc3000 17 + enum: 18 + - eeti,exc3000 19 + - eeti,exc80h60 20 + - eeti,exc80h84 18 21 reg: 19 22 const: 0x2a 20 23 interrupts:
+66 -14
drivers/input/touchscreen/exc3000.c
··· 16 16 #include <linux/interrupt.h> 17 17 #include <linux/module.h> 18 18 #include <linux/of.h> 19 + #include <linux/sizes.h> 19 20 #include <linux/timer.h> 20 21 #include <asm/unaligned.h> 21 22 ··· 24 23 #define EXC3000_SLOTS_PER_FRAME 5 25 24 #define EXC3000_LEN_FRAME 66 26 25 #define EXC3000_LEN_POINT 10 27 - #define EXC3000_MT_EVENT 6 26 + 27 + #define EXC3000_MT1_EVENT 0x06 28 + #define EXC3000_MT2_EVENT 0x18 29 + 28 30 #define EXC3000_TIMEOUT_MS 100 31 + 32 + static const struct i2c_device_id exc3000_id[]; 33 + 34 + struct eeti_dev_info { 35 + const char *name; 36 + int max_xy; 37 + }; 38 + 39 + enum eeti_dev_id { 40 + EETI_EXC3000, 41 + EETI_EXC80H60, 42 + EETI_EXC80H84, 43 + }; 44 + 45 + static struct eeti_dev_info exc3000_info[] = { 46 + [EETI_EXC3000] = { 47 + .name = "EETI EXC3000 Touch Screen", 48 + .max_xy = SZ_4K - 1, 49 + }, 50 + [EETI_EXC80H60] = { 51 + .name = "EETI EXC80H60 Touch Screen", 52 + .max_xy = SZ_16K - 1, 53 + }, 54 + [EETI_EXC80H84] = { 55 + .name = "EETI EXC80H84 Touch Screen", 56 + .max_xy = SZ_16K - 1, 57 + }, 58 + }; 29 59 30 60 struct exc3000_data { 31 61 struct i2c_client *client; 62 + const struct eeti_dev_info *info; 32 63 struct input_dev *input; 33 64 struct touchscreen_properties prop; 34 65 struct timer_list timer; ··· 91 58 input_sync(data->input); 92 59 } 93 60 94 - static int exc3000_read_frame(struct i2c_client *client, u8 *buf) 61 + static int exc3000_read_frame(struct exc3000_data *data, u8 *buf) 95 62 { 63 + struct i2c_client *client = data->client; 64 + u8 expected_event = EXC3000_MT1_EVENT; 96 65 int ret; 66 + 67 + if (data->info->max_xy == SZ_16K - 1) 68 + expected_event = EXC3000_MT2_EVENT; 97 69 98 70 ret = i2c_master_send(client, "'", 2); 99 71 if (ret < 0) ··· 114 76 if (ret != EXC3000_LEN_FRAME) 115 77 return -EIO; 116 78 117 - if (get_unaligned_le16(buf) != EXC3000_LEN_FRAME || 118 - buf[2] != EXC3000_MT_EVENT) 79 + if (get_unaligned_le16(buf) != EXC3000_LEN_FRAME) 80 + return -EINVAL; 81 + 82 + if (buf[2] != expected_event) 119 83 return -EINVAL; 120 84 121 85 return 0; 122 86 } 123 87 124 - static int exc3000_read_data(struct i2c_client *client, 88 + static int exc3000_read_data(struct exc3000_data *data, 125 89 u8 *buf, int *n_slots) 126 90 { 127 91 int error; 128 92 129 - error = exc3000_read_frame(client, buf); 93 + error = exc3000_read_frame(data, buf); 130 94 if (error) 131 95 return error; 132 96 ··· 138 98 139 99 if (*n_slots > EXC3000_SLOTS_PER_FRAME) { 140 100 /* Read 2nd frame to get the rest of the contacts. */ 141 - error = exc3000_read_frame(client, buf + EXC3000_LEN_FRAME); 101 + error = exc3000_read_frame(data, buf + EXC3000_LEN_FRAME); 142 102 if (error) 143 103 return error; 144 104 ··· 158 118 int slots, total_slots; 159 119 int error; 160 120 161 - error = exc3000_read_data(data->client, buf, &total_slots); 121 + error = exc3000_read_data(data, buf, &total_slots); 162 122 if (error) { 163 123 /* Schedule a timer to release "stuck" contacts */ 164 124 mod_timer(&data->timer, ··· 189 149 { 190 150 struct exc3000_data *data; 191 151 struct input_dev *input; 192 - int error; 152 + int error, max_xy; 193 153 194 154 data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); 195 155 if (!data) 196 156 return -ENOMEM; 197 157 198 158 data->client = client; 159 + data->info = device_get_match_data(&client->dev); 160 + if (!data->info) { 161 + enum eeti_dev_id eeti_dev_id = 162 + i2c_match_id(exc3000_id, client)->driver_data; 163 + data->info = &exc3000_info[eeti_dev_id]; 164 + } 199 165 timer_setup(&data->timer, exc3000_timer, 0); 200 166 201 167 input = devm_input_allocate_device(&client->dev); ··· 210 164 211 165 data->input = input; 212 166 213 - input->name = "EETI EXC3000 Touch Screen"; 167 + input->name = data->info->name; 214 168 input->id.bustype = BUS_I2C; 215 169 216 - input_set_abs_params(input, ABS_MT_POSITION_X, 0, 4095, 0, 0); 217 - input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 4095, 0, 0); 170 + max_xy = data->info->max_xy; 171 + input_set_abs_params(input, ABS_MT_POSITION_X, 0, max_xy, 0, 0); 172 + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, max_xy, 0, 0); 173 + 218 174 touchscreen_parse_properties(input, true, &data->prop); 219 175 220 176 error = input_mt_init_slots(input, EXC3000_NUM_SLOTS, ··· 238 190 } 239 191 240 192 static const struct i2c_device_id exc3000_id[] = { 241 - { "exc3000", 0 }, 193 + { "exc3000", EETI_EXC3000 }, 194 + { "exc80h60", EETI_EXC80H60 }, 195 + { "exc80h84", EETI_EXC80H84 }, 242 196 { } 243 197 }; 244 198 MODULE_DEVICE_TABLE(i2c, exc3000_id); 245 199 246 200 #ifdef CONFIG_OF 247 201 static const struct of_device_id exc3000_of_match[] = { 248 - { .compatible = "eeti,exc3000" }, 202 + { .compatible = "eeti,exc3000", .data = &exc3000_info[EETI_EXC3000] }, 203 + { .compatible = "eeti,exc80h60", .data = &exc3000_info[EETI_EXC80H60] }, 204 + { .compatible = "eeti,exc80h84", .data = &exc3000_info[EETI_EXC80H84] }, 249 205 { } 250 206 }; 251 207 MODULE_DEVICE_TABLE(of, exc3000_of_match);