Input: atmel_mxt_ts - support capacitive keys
authorAndré Apitzsch <git@apitzsch.eu>
Tue, 2 May 2023 03:16:52 +0000 (20:16 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Tue, 2 May 2023 03:22:09 +0000 (20:22 -0700)
Add support for touch keys found in some Atmel touch controller
configurations.

Reviewed-by: Claudiu Beznea <claudiu.beznea@microchip.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: André Apitzsch <git@apitzsch.eu>
Link: https://lore.kernel.org/r/20230407-atmel_keys-v2-2-92446a4343cb@apitzsch.eu
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
drivers/input/touchscreen/atmel_mxt_ts.c

index 996bf43..edea182 100644 (file)
@@ -55,6 +55,7 @@
 #define MXT_TOUCH_KEYARRAY_T15         15
 #define MXT_TOUCH_PROXIMITY_T23                23
 #define MXT_TOUCH_PROXKEY_T52          52
+#define MXT_TOUCH_PTC_KEYS_T97         97
 #define MXT_PROCI_GRIPFACE_T20         20
 #define MXT_PROCG_NOISE_T22            22
 #define MXT_PROCI_ONETOUCH_T24         24
@@ -326,9 +327,13 @@ struct mxt_data {
        u16 T71_address;
        u8 T9_reportid_min;
        u8 T9_reportid_max;
+       u8 T15_reportid_min;
+       u8 T15_reportid_max;
        u16 T18_address;
        u8 T19_reportid;
        u16 T44_address;
+       u8 T97_reportid_min;
+       u8 T97_reportid_max;
        u8 T100_reportid_min;
        u8 T100_reportid_max;
 
@@ -344,6 +349,9 @@ struct mxt_data {
        u32 *t19_keymap;
        unsigned int t19_num_keys;
 
+       u32 *t15_keymap;
+       unsigned int t15_num_keys;
+
        enum mxt_suspend_mode suspend_mode;
 
        u32 wakeup_method;
@@ -375,6 +383,7 @@ static bool mxt_object_readable(unsigned int type)
        case MXT_TOUCH_KEYARRAY_T15:
        case MXT_TOUCH_PROXIMITY_T23:
        case MXT_TOUCH_PROXKEY_T52:
+       case MXT_TOUCH_PTC_KEYS_T97:
        case MXT_TOUCH_MULTITOUCHSCREEN_T100:
        case MXT_PROCI_GRIPFACE_T20:
        case MXT_PROCG_NOISE_T22:
@@ -891,6 +900,24 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
        data->update_input = true;
 }
 
+static void mxt_proc_t15_messages(struct mxt_data *data, u8 *message)
+{
+       struct input_dev *input_dev = data->input_dev;
+       unsigned long keystates = get_unaligned_le32(&message[2]);
+       int key;
+
+       for (key = 0; key < data->t15_num_keys; key++)
+               input_report_key(input_dev, data->t15_keymap[key],
+                                keystates & BIT(key));
+
+       data->update_input = true;
+}
+
+static void mxt_proc_t97_messages(struct mxt_data *data, u8 *message)
+{
+       mxt_proc_t15_messages(data, message);
+}
+
 static void mxt_proc_t100_message(struct mxt_data *data, u8 *message)
 {
        struct device *dev = &data->client->dev;
@@ -1017,6 +1044,12 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message)
        } else if (report_id >= data->T9_reportid_min &&
                   report_id <= data->T9_reportid_max) {
                mxt_proc_t9_message(data, message);
+       } else if (report_id >= data->T15_reportid_min &&
+                  report_id <= data->T15_reportid_max) {
+               mxt_proc_t15_messages(data, message);
+       } else if (report_id >= data->T97_reportid_min &&
+                  report_id <= data->T97_reportid_max) {
+               mxt_proc_t97_messages(data, message);
        } else if (report_id >= data->T100_reportid_min &&
                   report_id <= data->T100_reportid_max) {
                mxt_proc_t100_message(data, message);
@@ -1689,9 +1722,13 @@ static void mxt_free_object_table(struct mxt_data *data)
        data->T71_address = 0;
        data->T9_reportid_min = 0;
        data->T9_reportid_max = 0;
+       data->T15_reportid_min = 0;
+       data->T15_reportid_max = 0;
        data->T18_address = 0;
        data->T19_reportid = 0;
        data->T44_address = 0;
+       data->T97_reportid_min = 0;
+       data->T97_reportid_max = 0;
        data->T100_reportid_min = 0;
        data->T100_reportid_max = 0;
        data->max_reportid = 0;
@@ -1764,6 +1801,10 @@ static int mxt_parse_object_table(struct mxt_data *data,
                                                object->num_report_ids - 1;
                        data->num_touchids = object->num_report_ids;
                        break;
+               case MXT_TOUCH_KEYARRAY_T15:
+                       data->T15_reportid_min = min_id;
+                       data->T15_reportid_max = max_id;
+                       break;
                case MXT_SPT_COMMSCONFIG_T18:
                        data->T18_address = object->start_address;
                        break;
@@ -1773,6 +1814,10 @@ static int mxt_parse_object_table(struct mxt_data *data,
                case MXT_SPT_GPIOPWM_T19:
                        data->T19_reportid = min_id;
                        break;
+               case MXT_TOUCH_PTC_KEYS_T97:
+                       data->T97_reportid_min = min_id;
+                       data->T97_reportid_max = max_id;
+                       break;
                case MXT_TOUCH_MULTITOUCHSCREEN_T100:
                        data->multitouch = MXT_TOUCH_MULTITOUCHSCREEN_T100;
                        data->T100_reportid_min = min_id;
@@ -2050,6 +2095,7 @@ static int mxt_initialize_input_device(struct mxt_data *data)
        int error;
        unsigned int num_mt_slots;
        unsigned int mt_flags = 0;
+       int i;
 
        switch (data->multitouch) {
        case MXT_TOUCH_MULTI_T9:
@@ -2095,6 +2141,10 @@ static int mxt_initialize_input_device(struct mxt_data *data)
        input_dev->open = mxt_input_open;
        input_dev->close = mxt_input_close;
 
+       input_dev->keycode = data->t15_keymap;
+       input_dev->keycodemax = data->t15_num_keys;
+       input_dev->keycodesize = sizeof(data->t15_keymap[0]);
+
        input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
 
        /* For single touch */
@@ -2162,6 +2212,13 @@ static int mxt_initialize_input_device(struct mxt_data *data)
                                     0, 255, 0, 0);
        }
 
+       /* For T15 and T97 Key Array */
+       if (data->T15_reportid_min || data->T97_reportid_min) {
+               for (i = 0; i < data->t15_num_keys; i++)
+                       input_set_capability(input_dev,
+                                            EV_KEY, data->t15_keymap[i]);
+       }
+
        input_set_drvdata(input_dev, data);
 
        error = input_register_device(input_dev);
@@ -3080,8 +3137,10 @@ static void mxt_input_close(struct input_dev *dev)
 static int mxt_parse_device_properties(struct mxt_data *data)
 {
        static const char keymap_property[] = "linux,gpio-keymap";
+       static const char buttons_property[] = "linux,keycodes";
        struct device *dev = &data->client->dev;
        u32 *keymap;
+       u32 *buttonmap;
        int n_keys;
        int error;
 
@@ -3111,6 +3170,32 @@ static int mxt_parse_device_properties(struct mxt_data *data)
                data->t19_num_keys = n_keys;
        }
 
+       if (device_property_present(dev, buttons_property)) {
+               n_keys = device_property_count_u32(dev, buttons_property);
+               if (n_keys <= 0) {
+                       error = n_keys < 0 ? n_keys : -EINVAL;
+                       dev_err(dev, "invalid/malformed '%s' property: %d\n",
+                               buttons_property, error);
+                       return error;
+               }
+
+               buttonmap = devm_kmalloc_array(dev, n_keys, sizeof(*buttonmap),
+                                              GFP_KERNEL);
+               if (!buttonmap)
+                       return -ENOMEM;
+
+               error = device_property_read_u32_array(dev, buttons_property,
+                                                      buttonmap, n_keys);
+               if (error) {
+                       dev_err(dev, "failed to parse '%s' property: %d\n",
+                               buttons_property, error);
+                       return error;
+               }
+
+               data->t15_keymap = buttonmap;
+               data->t15_num_keys = n_keys;
+       }
+
        return 0;
 }