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

HID: i2c-hid: Make elan touch controllers power on after panel is enabled

Introduce a new HID quirk to indicate that this device has to be enabled
after the panel's backlight is enabled, and update the driver data for
the elan devices to enable this quirk. This cannot be a I2C HID quirk
because the kernel needs to acknowledge this before powering up the
device and read the VID/PID. When this quirk is enabled, register
.panel_enabled()/.panel_disabling() instead for the panel follower.

Also rename the *panel_prepare* functions into *panel_follower* because
they could be called in other situations now.

Fixes: bd3cba00dcc63 ("HID: i2c-hid: elan: Add support for Elan eKTH6915 i2c-hid touchscreens")
Fixes: d06651bebf99e ("HID: i2c-hid: elan: Add elan-ekth6a12nay timing")
Reviewed-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Pin-yen Lin <treapking@chromium.org>
Acked-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Link: https://lore.kernel.org/r/20250818115015.2909525-2-treapking@chromium.org

authored by

Pin-yen Lin and committed by
Douglas Anderson
cbdd16b8 2eb22214

+40 -19
+28 -18
drivers/hid/i2c-hid/i2c-hid-core.c
··· 112 112 113 113 struct i2chid_ops *ops; 114 114 struct drm_panel_follower panel_follower; 115 - struct work_struct panel_follower_prepare_work; 115 + struct work_struct panel_follower_work; 116 116 bool is_panel_follower; 117 - bool prepare_work_finished; 117 + bool panel_follower_work_finished; 118 118 }; 119 119 120 120 static const struct i2c_hid_quirks { ··· 1110 1110 return ret; 1111 1111 } 1112 1112 1113 - static void ihid_core_panel_prepare_work(struct work_struct *work) 1113 + static void ihid_core_panel_follower_work(struct work_struct *work) 1114 1114 { 1115 1115 struct i2c_hid *ihid = container_of(work, struct i2c_hid, 1116 - panel_follower_prepare_work); 1116 + panel_follower_work); 1117 1117 struct hid_device *hid = ihid->hid; 1118 1118 int ret; 1119 1119 ··· 1130 1130 if (ret) 1131 1131 dev_warn(&ihid->client->dev, "Power on failed: %d\n", ret); 1132 1132 else 1133 - WRITE_ONCE(ihid->prepare_work_finished, true); 1133 + WRITE_ONCE(ihid->panel_follower_work_finished, true); 1134 1134 1135 1135 /* 1136 1136 * The work APIs provide a number of memory ordering guarantees ··· 1139 1139 * guarantee that a write that happened in the work is visible after 1140 1140 * cancel_work_sync(). We'll add a write memory barrier here to match 1141 1141 * with i2c_hid_core_panel_unpreparing() to ensure that our write to 1142 - * prepare_work_finished is visible there. 1142 + * panel_follower_work_finished is visible there. 1143 1143 */ 1144 1144 smp_wmb(); 1145 1145 } 1146 1146 1147 - static int i2c_hid_core_panel_prepared(struct drm_panel_follower *follower) 1147 + static int i2c_hid_core_panel_follower_resume(struct drm_panel_follower *follower) 1148 1148 { 1149 1149 struct i2c_hid *ihid = container_of(follower, struct i2c_hid, panel_follower); 1150 1150 ··· 1152 1152 * Powering on a touchscreen can be a slow process. Queue the work to 1153 1153 * the system workqueue so we don't block the panel's power up. 1154 1154 */ 1155 - WRITE_ONCE(ihid->prepare_work_finished, false); 1156 - schedule_work(&ihid->panel_follower_prepare_work); 1155 + WRITE_ONCE(ihid->panel_follower_work_finished, false); 1156 + schedule_work(&ihid->panel_follower_work); 1157 1157 1158 1158 return 0; 1159 1159 } 1160 1160 1161 - static int i2c_hid_core_panel_unpreparing(struct drm_panel_follower *follower) 1161 + static int i2c_hid_core_panel_follower_suspend(struct drm_panel_follower *follower) 1162 1162 { 1163 1163 struct i2c_hid *ihid = container_of(follower, struct i2c_hid, panel_follower); 1164 1164 1165 - cancel_work_sync(&ihid->panel_follower_prepare_work); 1165 + cancel_work_sync(&ihid->panel_follower_work); 1166 1166 1167 - /* Match with ihid_core_panel_prepare_work() */ 1167 + /* Match with ihid_core_panel_follower_work() */ 1168 1168 smp_rmb(); 1169 - if (!READ_ONCE(ihid->prepare_work_finished)) 1169 + if (!READ_ONCE(ihid->panel_follower_work_finished)) 1170 1170 return 0; 1171 1171 1172 1172 return i2c_hid_core_suspend(ihid, true); 1173 1173 } 1174 1174 1175 - static const struct drm_panel_follower_funcs i2c_hid_core_panel_follower_funcs = { 1176 - .panel_prepared = i2c_hid_core_panel_prepared, 1177 - .panel_unpreparing = i2c_hid_core_panel_unpreparing, 1175 + static const struct drm_panel_follower_funcs 1176 + i2c_hid_core_panel_follower_prepare_funcs = { 1177 + .panel_prepared = i2c_hid_core_panel_follower_resume, 1178 + .panel_unpreparing = i2c_hid_core_panel_follower_suspend, 1179 + }; 1180 + 1181 + static const struct drm_panel_follower_funcs 1182 + i2c_hid_core_panel_follower_enable_funcs = { 1183 + .panel_enabled = i2c_hid_core_panel_follower_resume, 1184 + .panel_disabling = i2c_hid_core_panel_follower_suspend, 1178 1185 }; 1179 1186 1180 1187 static int i2c_hid_core_register_panel_follower(struct i2c_hid *ihid) ··· 1189 1182 struct device *dev = &ihid->client->dev; 1190 1183 int ret; 1191 1184 1192 - ihid->panel_follower.funcs = &i2c_hid_core_panel_follower_funcs; 1185 + if (ihid->hid->initial_quirks | HID_QUIRK_POWER_ON_AFTER_BACKLIGHT) 1186 + ihid->panel_follower.funcs = &i2c_hid_core_panel_follower_enable_funcs; 1187 + else 1188 + ihid->panel_follower.funcs = &i2c_hid_core_panel_follower_prepare_funcs; 1193 1189 1194 1190 /* 1195 1191 * If we're not in control of our own power up/power down then we can't ··· 1247 1237 init_waitqueue_head(&ihid->wait); 1248 1238 mutex_init(&ihid->cmd_lock); 1249 1239 mutex_init(&ihid->reset_lock); 1250 - INIT_WORK(&ihid->panel_follower_prepare_work, ihid_core_panel_prepare_work); 1240 + INIT_WORK(&ihid->panel_follower_work, ihid_core_panel_follower_work); 1251 1241 1252 1242 /* we need to allocate the command buffer without knowing the maximum 1253 1243 * size of the reports. Let's use HID_MIN_BUFFER_SIZE, then we do the
+10 -1
drivers/hid/i2c-hid/i2c-hid-of-elan.c
··· 8 8 #include <linux/delay.h> 9 9 #include <linux/device.h> 10 10 #include <linux/gpio/consumer.h> 11 + #include <linux/hid.h> 11 12 #include <linux/i2c.h> 12 13 #include <linux/kernel.h> 13 14 #include <linux/module.h> ··· 24 23 unsigned int post_power_delay_ms; 25 24 u16 hid_descriptor_address; 26 25 const char *main_supply_name; 26 + bool power_after_backlight; 27 27 }; 28 28 29 29 struct i2c_hid_of_elan { ··· 99 97 { 100 98 struct i2c_hid_of_elan *ihid_elan; 101 99 int ret; 100 + u32 quirks = 0; 102 101 103 102 ihid_elan = devm_kzalloc(&client->dev, sizeof(*ihid_elan), GFP_KERNEL); 104 103 if (!ihid_elan) ··· 134 131 } 135 132 } 136 133 134 + if (ihid_elan->chip_data->power_after_backlight) 135 + quirks = HID_QUIRK_POWER_ON_AFTER_BACKLIGHT; 136 + 137 137 ret = i2c_hid_core_probe(client, &ihid_elan->ops, 138 - ihid_elan->chip_data->hid_descriptor_address, 0); 138 + ihid_elan->chip_data->hid_descriptor_address, 139 + quirks); 139 140 if (ret) 140 141 goto err_deassert_reset; 141 142 ··· 157 150 .post_gpio_reset_on_delay_ms = 300, 158 151 .hid_descriptor_address = 0x0001, 159 152 .main_supply_name = "vcc33", 153 + .power_after_backlight = true, 160 154 }; 161 155 162 156 static const struct elan_i2c_hid_chip_data elan_ekth6a12nay_chip_data = { ··· 165 157 .post_gpio_reset_on_delay_ms = 300, 166 158 .hid_descriptor_address = 0x0001, 167 159 .main_supply_name = "vcc33", 160 + .power_after_backlight = true, 168 161 }; 169 162 170 163 static const struct elan_i2c_hid_chip_data ilitek_ili9882t_chip_data = {
+2
include/linux/hid.h
··· 364 364 * | @HID_QUIRK_HAVE_SPECIAL_DRIVER: 365 365 * | @HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE: 366 366 * | @HID_QUIRK_IGNORE_SPECIAL_DRIVER 367 + * | @HID_QUIRK_POWER_ON_AFTER_BACKLIGHT 367 368 * | @HID_QUIRK_FULLSPEED_INTERVAL: 368 369 * | @HID_QUIRK_NO_INIT_REPORTS: 369 370 * | @HID_QUIRK_NO_IGNORE: ··· 392 391 #define HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE BIT(20) 393 392 #define HID_QUIRK_NOINVERT BIT(21) 394 393 #define HID_QUIRK_IGNORE_SPECIAL_DRIVER BIT(22) 394 + #define HID_QUIRK_POWER_ON_AFTER_BACKLIGHT BIT(23) 395 395 #define HID_QUIRK_FULLSPEED_INTERVAL BIT(28) 396 396 #define HID_QUIRK_NO_INIT_REPORTS BIT(29) 397 397 #define HID_QUIRK_NO_IGNORE BIT(30)