0001
0002
0003
0004
0005
0006
0007 #include <linux/delay.h>
0008 #include <linux/gpio/consumer.h>
0009 #include <linux/i2c.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/input.h>
0012 #include <linux/input/mt.h>
0013 #include <linux/input/touchscreen.h>
0014 #include <linux/irq.h>
0015 #include <linux/regulator/consumer.h>
0016 #include <linux/regmap.h>
0017
0018 #include <asm/unaligned.h>
0019
0020 #define HY46XX_CHKSUM_CODE 0x1
0021 #define HY46XX_FINGER_NUM 0x2
0022 #define HY46XX_CHKSUM_LEN 0x7
0023 #define HY46XX_THRESHOLD 0x80
0024 #define HY46XX_GLOVE_EN 0x84
0025 #define HY46XX_REPORT_SPEED 0x88
0026 #define HY46XX_PWR_NOISE_EN 0x89
0027 #define HY46XX_FILTER_DATA 0x8A
0028 #define HY46XX_GAIN 0x92
0029 #define HY46XX_EDGE_OFFSET 0x93
0030 #define HY46XX_RX_NR_USED 0x94
0031 #define HY46XX_TX_NR_USED 0x95
0032 #define HY46XX_PWR_MODE 0xA5
0033 #define HY46XX_FW_VERSION 0xA6
0034 #define HY46XX_LIB_VERSION 0xA7
0035 #define HY46XX_TP_INFO 0xA8
0036 #define HY46XX_TP_CHIP_ID 0xA9
0037 #define HY46XX_BOOT_VER 0xB0
0038
0039 #define HY46XX_TPLEN 0x6
0040 #define HY46XX_REPORT_PKT_LEN 0x44
0041
0042 #define HY46XX_MAX_SUPPORTED_POINTS 11
0043
0044 #define TOUCH_EVENT_DOWN 0x00
0045 #define TOUCH_EVENT_UP 0x01
0046 #define TOUCH_EVENT_CONTACT 0x02
0047 #define TOUCH_EVENT_RESERVED 0x03
0048
0049 struct hycon_hy46xx_data {
0050 struct i2c_client *client;
0051 struct input_dev *input;
0052 struct touchscreen_properties prop;
0053 struct regulator *vcc;
0054
0055 struct gpio_desc *reset_gpio;
0056
0057 struct mutex mutex;
0058 struct regmap *regmap;
0059
0060 int threshold;
0061 bool glove_enable;
0062 int report_speed;
0063 bool noise_filter_enable;
0064 int filter_data;
0065 int gain;
0066 int edge_offset;
0067 int rx_number_used;
0068 int tx_number_used;
0069 int power_mode;
0070 int fw_version;
0071 int lib_version;
0072 int tp_information;
0073 int tp_chip_id;
0074 int bootloader_version;
0075 };
0076
0077 static const struct regmap_config hycon_hy46xx_i2c_regmap_config = {
0078 .reg_bits = 8,
0079 .val_bits = 8,
0080 };
0081
0082 static bool hycon_hy46xx_check_checksum(struct hycon_hy46xx_data *tsdata, u8 *buf)
0083 {
0084 u8 chksum = 0;
0085 int i;
0086
0087 for (i = 2; i < buf[HY46XX_CHKSUM_LEN]; i++)
0088 chksum += buf[i];
0089
0090 if (chksum == buf[HY46XX_CHKSUM_CODE])
0091 return true;
0092
0093 dev_err_ratelimited(&tsdata->client->dev,
0094 "checksum error: 0x%02x expected, got 0x%02x\n",
0095 chksum, buf[HY46XX_CHKSUM_CODE]);
0096
0097 return false;
0098 }
0099
0100 static irqreturn_t hycon_hy46xx_isr(int irq, void *dev_id)
0101 {
0102 struct hycon_hy46xx_data *tsdata = dev_id;
0103 struct device *dev = &tsdata->client->dev;
0104 u8 rdbuf[HY46XX_REPORT_PKT_LEN];
0105 int i, x, y, id;
0106 int error;
0107
0108 memset(rdbuf, 0, sizeof(rdbuf));
0109
0110 error = regmap_bulk_read(tsdata->regmap, 0, rdbuf, sizeof(rdbuf));
0111 if (error) {
0112 dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n",
0113 error);
0114 goto out;
0115 }
0116
0117 if (!hycon_hy46xx_check_checksum(tsdata, rdbuf))
0118 goto out;
0119
0120 for (i = 0; i < HY46XX_MAX_SUPPORTED_POINTS; i++) {
0121 u8 *buf = &rdbuf[3 + (HY46XX_TPLEN * i)];
0122 int type = buf[0] >> 6;
0123
0124 if (type == TOUCH_EVENT_RESERVED)
0125 continue;
0126
0127 x = get_unaligned_be16(buf) & 0x0fff;
0128 y = get_unaligned_be16(buf + 2) & 0x0fff;
0129
0130 id = buf[2] >> 4;
0131
0132 input_mt_slot(tsdata->input, id);
0133 if (input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER,
0134 type != TOUCH_EVENT_UP))
0135 touchscreen_report_pos(tsdata->input, &tsdata->prop,
0136 x, y, true);
0137 }
0138
0139 input_mt_report_pointer_emulation(tsdata->input, false);
0140 input_sync(tsdata->input);
0141
0142 out:
0143 return IRQ_HANDLED;
0144 }
0145
0146 struct hycon_hy46xx_attribute {
0147 struct device_attribute dattr;
0148 size_t field_offset;
0149 u8 address;
0150 u8 limit_low;
0151 u8 limit_high;
0152 };
0153
0154 #define HYCON_ATTR_U8(_field, _mode, _address, _limit_low, _limit_high) \
0155 struct hycon_hy46xx_attribute hycon_hy46xx_attr_##_field = { \
0156 .dattr = __ATTR(_field, _mode, \
0157 hycon_hy46xx_setting_show, \
0158 hycon_hy46xx_setting_store), \
0159 .field_offset = offsetof(struct hycon_hy46xx_data, _field), \
0160 .address = _address, \
0161 .limit_low = _limit_low, \
0162 .limit_high = _limit_high, \
0163 }
0164
0165 #define HYCON_ATTR_BOOL(_field, _mode, _address) \
0166 struct hycon_hy46xx_attribute hycon_hy46xx_attr_##_field = { \
0167 .dattr = __ATTR(_field, _mode, \
0168 hycon_hy46xx_setting_show, \
0169 hycon_hy46xx_setting_store), \
0170 .field_offset = offsetof(struct hycon_hy46xx_data, _field), \
0171 .address = _address, \
0172 .limit_low = false, \
0173 .limit_high = true, \
0174 }
0175
0176 static ssize_t hycon_hy46xx_setting_show(struct device *dev,
0177 struct device_attribute *dattr, char *buf)
0178 {
0179 struct i2c_client *client = to_i2c_client(dev);
0180 struct hycon_hy46xx_data *tsdata = i2c_get_clientdata(client);
0181 struct hycon_hy46xx_attribute *attr =
0182 container_of(dattr, struct hycon_hy46xx_attribute, dattr);
0183 u8 *field = (u8 *)tsdata + attr->field_offset;
0184 size_t count = 0;
0185 int error = 0;
0186 int val;
0187
0188 mutex_lock(&tsdata->mutex);
0189
0190 error = regmap_read(tsdata->regmap, attr->address, &val);
0191 if (error < 0) {
0192 dev_err(&tsdata->client->dev,
0193 "Failed to fetch attribute %s, error %d\n",
0194 dattr->attr.name, error);
0195 goto out;
0196 }
0197
0198 if (val != *field) {
0199 dev_warn(&tsdata->client->dev,
0200 "%s: read (%d) and stored value (%d) differ\n",
0201 dattr->attr.name, val, *field);
0202 *field = val;
0203 }
0204
0205 count = scnprintf(buf, PAGE_SIZE, "%d\n", val);
0206
0207 out:
0208 mutex_unlock(&tsdata->mutex);
0209 return error ?: count;
0210 }
0211
0212 static ssize_t hycon_hy46xx_setting_store(struct device *dev,
0213 struct device_attribute *dattr,
0214 const char *buf, size_t count)
0215 {
0216 struct i2c_client *client = to_i2c_client(dev);
0217 struct hycon_hy46xx_data *tsdata = i2c_get_clientdata(client);
0218 struct hycon_hy46xx_attribute *attr =
0219 container_of(dattr, struct hycon_hy46xx_attribute, dattr);
0220 u8 *field = (u8 *)tsdata + attr->field_offset;
0221 unsigned int val;
0222 int error;
0223
0224 mutex_lock(&tsdata->mutex);
0225
0226 error = kstrtouint(buf, 0, &val);
0227 if (error)
0228 goto out;
0229
0230 if (val < attr->limit_low || val > attr->limit_high) {
0231 error = -ERANGE;
0232 goto out;
0233 }
0234
0235 error = regmap_write(tsdata->regmap, attr->address, val);
0236 if (error < 0) {
0237 dev_err(&tsdata->client->dev,
0238 "Failed to update attribute %s, error: %d\n",
0239 dattr->attr.name, error);
0240 goto out;
0241 }
0242 *field = val;
0243
0244 out:
0245 mutex_unlock(&tsdata->mutex);
0246 return error ?: count;
0247 }
0248
0249 static HYCON_ATTR_U8(threshold, 0644, HY46XX_THRESHOLD, 0, 255);
0250 static HYCON_ATTR_BOOL(glove_enable, 0644, HY46XX_GLOVE_EN);
0251 static HYCON_ATTR_U8(report_speed, 0644, HY46XX_REPORT_SPEED, 0, 255);
0252 static HYCON_ATTR_BOOL(noise_filter_enable, 0644, HY46XX_PWR_NOISE_EN);
0253 static HYCON_ATTR_U8(filter_data, 0644, HY46XX_FILTER_DATA, 0, 5);
0254 static HYCON_ATTR_U8(gain, 0644, HY46XX_GAIN, 0, 5);
0255 static HYCON_ATTR_U8(edge_offset, 0644, HY46XX_EDGE_OFFSET, 0, 5);
0256 static HYCON_ATTR_U8(fw_version, 0444, HY46XX_FW_VERSION, 0, 255);
0257 static HYCON_ATTR_U8(lib_version, 0444, HY46XX_LIB_VERSION, 0, 255);
0258 static HYCON_ATTR_U8(tp_information, 0444, HY46XX_TP_INFO, 0, 255);
0259 static HYCON_ATTR_U8(tp_chip_id, 0444, HY46XX_TP_CHIP_ID, 0, 255);
0260 static HYCON_ATTR_U8(bootloader_version, 0444, HY46XX_BOOT_VER, 0, 255);
0261
0262 static struct attribute *hycon_hy46xx_attrs[] = {
0263 &hycon_hy46xx_attr_threshold.dattr.attr,
0264 &hycon_hy46xx_attr_glove_enable.dattr.attr,
0265 &hycon_hy46xx_attr_report_speed.dattr.attr,
0266 &hycon_hy46xx_attr_noise_filter_enable.dattr.attr,
0267 &hycon_hy46xx_attr_filter_data.dattr.attr,
0268 &hycon_hy46xx_attr_gain.dattr.attr,
0269 &hycon_hy46xx_attr_edge_offset.dattr.attr,
0270 &hycon_hy46xx_attr_fw_version.dattr.attr,
0271 &hycon_hy46xx_attr_lib_version.dattr.attr,
0272 &hycon_hy46xx_attr_tp_information.dattr.attr,
0273 &hycon_hy46xx_attr_tp_chip_id.dattr.attr,
0274 &hycon_hy46xx_attr_bootloader_version.dattr.attr,
0275 NULL
0276 };
0277
0278 static const struct attribute_group hycon_hy46xx_attr_group = {
0279 .attrs = hycon_hy46xx_attrs,
0280 };
0281
0282 static void hycon_hy46xx_get_defaults(struct device *dev, struct hycon_hy46xx_data *tsdata)
0283 {
0284 bool val_bool;
0285 int error;
0286 u32 val;
0287
0288 error = device_property_read_u32(dev, "hycon,threshold", &val);
0289 if (!error) {
0290 error = regmap_write(tsdata->regmap, HY46XX_THRESHOLD, val);
0291 if (error < 0)
0292 goto out;
0293
0294 tsdata->threshold = val;
0295 }
0296
0297 val_bool = device_property_read_bool(dev, "hycon,glove-enable");
0298 error = regmap_write(tsdata->regmap, HY46XX_GLOVE_EN, val_bool);
0299 if (error < 0)
0300 goto out;
0301 tsdata->glove_enable = val_bool;
0302
0303 error = device_property_read_u32(dev, "hycon,report-speed-hz", &val);
0304 if (!error) {
0305 error = regmap_write(tsdata->regmap, HY46XX_REPORT_SPEED, val);
0306 if (error < 0)
0307 goto out;
0308
0309 tsdata->report_speed = val;
0310 }
0311
0312 val_bool = device_property_read_bool(dev, "hycon,noise-filter-enable");
0313 error = regmap_write(tsdata->regmap, HY46XX_PWR_NOISE_EN, val_bool);
0314 if (error < 0)
0315 goto out;
0316 tsdata->noise_filter_enable = val_bool;
0317
0318 error = device_property_read_u32(dev, "hycon,filter-data", &val);
0319 if (!error) {
0320 error = regmap_write(tsdata->regmap, HY46XX_FILTER_DATA, val);
0321 if (error < 0)
0322 goto out;
0323
0324 tsdata->filter_data = val;
0325 }
0326
0327 error = device_property_read_u32(dev, "hycon,gain", &val);
0328 if (!error) {
0329 error = regmap_write(tsdata->regmap, HY46XX_GAIN, val);
0330 if (error < 0)
0331 goto out;
0332
0333 tsdata->gain = val;
0334 }
0335
0336 error = device_property_read_u32(dev, "hycon,edge-offset", &val);
0337 if (!error) {
0338 error = regmap_write(tsdata->regmap, HY46XX_EDGE_OFFSET, val);
0339 if (error < 0)
0340 goto out;
0341
0342 tsdata->edge_offset = val;
0343 }
0344
0345 return;
0346 out:
0347 dev_err(&tsdata->client->dev, "Failed to set default settings");
0348 }
0349
0350 static void hycon_hy46xx_get_parameters(struct hycon_hy46xx_data *tsdata)
0351 {
0352 int error;
0353 u32 val;
0354
0355 error = regmap_read(tsdata->regmap, HY46XX_THRESHOLD, &val);
0356 if (error < 0)
0357 goto out;
0358 tsdata->threshold = val;
0359
0360 error = regmap_read(tsdata->regmap, HY46XX_GLOVE_EN, &val);
0361 if (error < 0)
0362 goto out;
0363 tsdata->glove_enable = val;
0364
0365 error = regmap_read(tsdata->regmap, HY46XX_REPORT_SPEED, &val);
0366 if (error < 0)
0367 goto out;
0368 tsdata->report_speed = val;
0369
0370 error = regmap_read(tsdata->regmap, HY46XX_PWR_NOISE_EN, &val);
0371 if (error < 0)
0372 goto out;
0373 tsdata->noise_filter_enable = val;
0374
0375 error = regmap_read(tsdata->regmap, HY46XX_FILTER_DATA, &val);
0376 if (error < 0)
0377 goto out;
0378 tsdata->filter_data = val;
0379
0380 error = regmap_read(tsdata->regmap, HY46XX_GAIN, &val);
0381 if (error < 0)
0382 goto out;
0383 tsdata->gain = val;
0384
0385 error = regmap_read(tsdata->regmap, HY46XX_EDGE_OFFSET, &val);
0386 if (error < 0)
0387 goto out;
0388 tsdata->edge_offset = val;
0389
0390 error = regmap_read(tsdata->regmap, HY46XX_RX_NR_USED, &val);
0391 if (error < 0)
0392 goto out;
0393 tsdata->rx_number_used = val;
0394
0395 error = regmap_read(tsdata->regmap, HY46XX_TX_NR_USED, &val);
0396 if (error < 0)
0397 goto out;
0398 tsdata->tx_number_used = val;
0399
0400 error = regmap_read(tsdata->regmap, HY46XX_PWR_MODE, &val);
0401 if (error < 0)
0402 goto out;
0403 tsdata->power_mode = val;
0404
0405 error = regmap_read(tsdata->regmap, HY46XX_FW_VERSION, &val);
0406 if (error < 0)
0407 goto out;
0408 tsdata->fw_version = val;
0409
0410 error = regmap_read(tsdata->regmap, HY46XX_LIB_VERSION, &val);
0411 if (error < 0)
0412 goto out;
0413 tsdata->lib_version = val;
0414
0415 error = regmap_read(tsdata->regmap, HY46XX_TP_INFO, &val);
0416 if (error < 0)
0417 goto out;
0418 tsdata->tp_information = val;
0419
0420 error = regmap_read(tsdata->regmap, HY46XX_TP_CHIP_ID, &val);
0421 if (error < 0)
0422 goto out;
0423 tsdata->tp_chip_id = val;
0424
0425 error = regmap_read(tsdata->regmap, HY46XX_BOOT_VER, &val);
0426 if (error < 0)
0427 goto out;
0428 tsdata->bootloader_version = val;
0429
0430 return;
0431 out:
0432 dev_err(&tsdata->client->dev, "Failed to read default settings");
0433 }
0434
0435 static void hycon_hy46xx_disable_regulator(void *arg)
0436 {
0437 struct hycon_hy46xx_data *data = arg;
0438
0439 regulator_disable(data->vcc);
0440 }
0441
0442 static int hycon_hy46xx_probe(struct i2c_client *client,
0443 const struct i2c_device_id *id)
0444 {
0445 struct hycon_hy46xx_data *tsdata;
0446 struct input_dev *input;
0447 int error;
0448
0449 dev_dbg(&client->dev, "probing for HYCON HY46XX I2C\n");
0450
0451 tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL);
0452 if (!tsdata)
0453 return -ENOMEM;
0454
0455 tsdata->vcc = devm_regulator_get(&client->dev, "vcc");
0456 if (IS_ERR(tsdata->vcc)) {
0457 error = PTR_ERR(tsdata->vcc);
0458 if (error != -EPROBE_DEFER)
0459 dev_err(&client->dev,
0460 "failed to request regulator: %d\n", error);
0461 return error;
0462 }
0463
0464 error = regulator_enable(tsdata->vcc);
0465 if (error < 0) {
0466 dev_err(&client->dev, "failed to enable vcc: %d\n", error);
0467 return error;
0468 }
0469
0470 error = devm_add_action_or_reset(&client->dev,
0471 hycon_hy46xx_disable_regulator,
0472 tsdata);
0473 if (error)
0474 return error;
0475
0476 tsdata->reset_gpio = devm_gpiod_get_optional(&client->dev,
0477 "reset", GPIOD_OUT_LOW);
0478 if (IS_ERR(tsdata->reset_gpio)) {
0479 error = PTR_ERR(tsdata->reset_gpio);
0480 dev_err(&client->dev,
0481 "Failed to request GPIO reset pin, error %d\n", error);
0482 return error;
0483 }
0484
0485 if (tsdata->reset_gpio) {
0486 usleep_range(5000, 6000);
0487 gpiod_set_value_cansleep(tsdata->reset_gpio, 1);
0488 usleep_range(5000, 6000);
0489 gpiod_set_value_cansleep(tsdata->reset_gpio, 0);
0490 msleep(1000);
0491 }
0492
0493 input = devm_input_allocate_device(&client->dev);
0494 if (!input) {
0495 dev_err(&client->dev, "failed to allocate input device.\n");
0496 return -ENOMEM;
0497 }
0498
0499 mutex_init(&tsdata->mutex);
0500 tsdata->client = client;
0501 tsdata->input = input;
0502
0503 tsdata->regmap = devm_regmap_init_i2c(client,
0504 &hycon_hy46xx_i2c_regmap_config);
0505 if (IS_ERR(tsdata->regmap)) {
0506 dev_err(&client->dev, "regmap allocation failed\n");
0507 return PTR_ERR(tsdata->regmap);
0508 }
0509
0510 hycon_hy46xx_get_defaults(&client->dev, tsdata);
0511 hycon_hy46xx_get_parameters(tsdata);
0512
0513 input->name = "Hycon Capacitive Touch";
0514 input->id.bustype = BUS_I2C;
0515 input->dev.parent = &client->dev;
0516
0517 input_set_abs_params(input, ABS_MT_POSITION_X, 0, -1, 0, 0);
0518 input_set_abs_params(input, ABS_MT_POSITION_Y, 0, -1, 0, 0);
0519
0520 touchscreen_parse_properties(input, true, &tsdata->prop);
0521
0522 error = input_mt_init_slots(input, HY46XX_MAX_SUPPORTED_POINTS,
0523 INPUT_MT_DIRECT);
0524 if (error) {
0525 dev_err(&client->dev, "Unable to init MT slots.\n");
0526 return error;
0527 }
0528
0529 i2c_set_clientdata(client, tsdata);
0530
0531 error = devm_request_threaded_irq(&client->dev, client->irq,
0532 NULL, hycon_hy46xx_isr, IRQF_ONESHOT,
0533 client->name, tsdata);
0534 if (error) {
0535 dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
0536 return error;
0537 }
0538
0539 error = devm_device_add_group(&client->dev, &hycon_hy46xx_attr_group);
0540 if (error)
0541 return error;
0542
0543 error = input_register_device(input);
0544 if (error)
0545 return error;
0546
0547 dev_dbg(&client->dev,
0548 "HYCON HY46XX initialized: IRQ %d, Reset pin %d.\n",
0549 client->irq,
0550 tsdata->reset_gpio ? desc_to_gpio(tsdata->reset_gpio) : -1);
0551
0552 return 0;
0553 }
0554
0555 static const struct i2c_device_id hycon_hy46xx_id[] = {
0556 { .name = "hy4613" },
0557 { .name = "hy4614" },
0558 { .name = "hy4621" },
0559 { .name = "hy4623" },
0560 { .name = "hy4633" },
0561 { .name = "hy4635" },
0562 { }
0563 };
0564 MODULE_DEVICE_TABLE(i2c, hycon_hy46xx_id);
0565
0566 static const struct of_device_id hycon_hy46xx_of_match[] = {
0567 { .compatible = "hycon,hy4613" },
0568 { .compatible = "hycon,hy4614" },
0569 { .compatible = "hycon,hy4621" },
0570 { .compatible = "hycon,hy4623" },
0571 { .compatible = "hycon,hy4633" },
0572 { .compatible = "hycon,hy4635" },
0573 { }
0574 };
0575 MODULE_DEVICE_TABLE(of, hycon_hy46xx_of_match);
0576
0577 static struct i2c_driver hycon_hy46xx_driver = {
0578 .driver = {
0579 .name = "hycon_hy46xx",
0580 .of_match_table = hycon_hy46xx_of_match,
0581 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
0582 },
0583 .id_table = hycon_hy46xx_id,
0584 .probe = hycon_hy46xx_probe,
0585 };
0586
0587 module_i2c_driver(hycon_hy46xx_driver);
0588
0589 MODULE_AUTHOR("Giulio Benetti <giulio.benetti@benettiengineering.com>");
0590 MODULE_DESCRIPTION("HYCON HY46XX I2C Touchscreen Driver");
0591 MODULE_LICENSE("GPL v2");