Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2021
0004  * Author(s): Giulio Benetti <giulio.benetti@benettiengineering.com>
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     { /* sentinel */ }
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     { /* sentinel */ }
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");