aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Norris <briannorris@chromium.org>2017-02-09 21:03:57 -0500
committerJiri Kosina <jkosina@suse.cz>2017-03-06 07:48:44 -0500
commit572d3c6444979a6a49c6b464110563f578e8dece (patch)
treeedfa44f72e6d60a0b4ca84705e39f6a3b8dd9812
parentcb5cfd91a7ae5ae355e657e5ce4931836b7665eb (diff)
HID: i2c-hid: support regulator power on/off
On some boards, we need to enable a regulator before using the HID, and it's also nice to save power in suspend by disabling it. Support an optional "vdd-supply" and a companion initialization delay. Signed-off-by: Brian Norris <briannorris@chromium.org> Signed-off-by: Caesar Wang <wxt@rock-chips.com> Acked-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Reviewed-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Cc: Jiri Kosina <jikos@kernel.org> Cc: linux-input@vger.kernel.org Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.c42
-rw-r--r--include/linux/i2c/i2c-hid.h6
2 files changed, 46 insertions, 2 deletions
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index ea3c3546cef7..a3f6daf0886b 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -994,6 +994,11 @@ static int i2c_hid_of_probe(struct i2c_client *client,
994 } 994 }
995 pdata->hid_descriptor_address = val; 995 pdata->hid_descriptor_address = val;
996 996
997 ret = of_property_read_u32(dev->of_node, "post-power-on-delay-ms",
998 &val);
999 if (!ret)
1000 pdata->post_power_delay_ms = val;
1001
997 return 0; 1002 return 0;
998} 1003}
999 1004
@@ -1053,6 +1058,24 @@ static int i2c_hid_probe(struct i2c_client *client,
1053 ihid->pdata = *platform_data; 1058 ihid->pdata = *platform_data;
1054 } 1059 }
1055 1060
1061 ihid->pdata.supply = devm_regulator_get(&client->dev, "vdd");
1062 if (IS_ERR(ihid->pdata.supply)) {
1063 ret = PTR_ERR(ihid->pdata.supply);
1064 if (ret != -EPROBE_DEFER)
1065 dev_err(&client->dev, "Failed to get regulator: %d\n",
1066 ret);
1067 return ret;
1068 }
1069
1070 ret = regulator_enable(ihid->pdata.supply);
1071 if (ret < 0) {
1072 dev_err(&client->dev, "Failed to enable regulator: %d\n",
1073 ret);
1074 goto err;
1075 }
1076 if (ihid->pdata.post_power_delay_ms)
1077 msleep(ihid->pdata.post_power_delay_ms);
1078
1056 i2c_set_clientdata(client, ihid); 1079 i2c_set_clientdata(client, ihid);
1057 1080
1058 ihid->client = client; 1081 ihid->client = client;
@@ -1068,7 +1091,7 @@ static int i2c_hid_probe(struct i2c_client *client,
1068 * real computation later. */ 1091 * real computation later. */
1069 ret = i2c_hid_alloc_buffers(ihid, HID_MIN_BUFFER_SIZE); 1092 ret = i2c_hid_alloc_buffers(ihid, HID_MIN_BUFFER_SIZE);
1070 if (ret < 0) 1093 if (ret < 0)
1071 goto err; 1094 goto err_regulator;
1072 1095
1073 pm_runtime_get_noresume(&client->dev); 1096 pm_runtime_get_noresume(&client->dev);
1074 pm_runtime_set_active(&client->dev); 1097 pm_runtime_set_active(&client->dev);
@@ -1125,6 +1148,9 @@ err_pm:
1125 pm_runtime_put_noidle(&client->dev); 1148 pm_runtime_put_noidle(&client->dev);
1126 pm_runtime_disable(&client->dev); 1149 pm_runtime_disable(&client->dev);
1127 1150
1151err_regulator:
1152 regulator_disable(ihid->pdata.supply);
1153
1128err: 1154err:
1129 i2c_hid_free_buffers(ihid); 1155 i2c_hid_free_buffers(ihid);
1130 kfree(ihid); 1156 kfree(ihid);
@@ -1149,6 +1175,8 @@ static int i2c_hid_remove(struct i2c_client *client)
1149 if (ihid->bufsize) 1175 if (ihid->bufsize)
1150 i2c_hid_free_buffers(ihid); 1176 i2c_hid_free_buffers(ihid);
1151 1177
1178 regulator_disable(ihid->pdata.supply);
1179
1152 kfree(ihid); 1180 kfree(ihid);
1153 1181
1154 return 0; 1182 return 0;
@@ -1199,6 +1227,10 @@ static int i2c_hid_suspend(struct device *dev)
1199 else 1227 else
1200 hid_warn(hid, "Failed to enable irq wake: %d\n", 1228 hid_warn(hid, "Failed to enable irq wake: %d\n",
1201 wake_status); 1229 wake_status);
1230 } else {
1231 ret = regulator_disable(ihid->pdata.supply);
1232 if (ret < 0)
1233 hid_warn(hid, "Failed to disable supply: %d\n", ret);
1202 } 1234 }
1203 1235
1204 return 0; 1236 return 0;
@@ -1212,7 +1244,13 @@ static int i2c_hid_resume(struct device *dev)
1212 struct hid_device *hid = ihid->hid; 1244 struct hid_device *hid = ihid->hid;
1213 int wake_status; 1245 int wake_status;
1214 1246
1215 if (device_may_wakeup(&client->dev) && ihid->irq_wake_enabled) { 1247 if (!device_may_wakeup(&client->dev)) {
1248 ret = regulator_enable(ihid->pdata.supply);
1249 if (ret < 0)
1250 hid_warn(hid, "Failed to enable supply: %d\n", ret);
1251 if (ihid->pdata.post_power_delay_ms)
1252 msleep(ihid->pdata.post_power_delay_ms);
1253 } else if (ihid->irq_wake_enabled) {
1216 wake_status = disable_irq_wake(client->irq); 1254 wake_status = disable_irq_wake(client->irq);
1217 if (!wake_status) 1255 if (!wake_status)
1218 ihid->irq_wake_enabled = false; 1256 ihid->irq_wake_enabled = false;
diff --git a/include/linux/i2c/i2c-hid.h b/include/linux/i2c/i2c-hid.h
index 7aa901d92058..1fb088239d12 100644
--- a/include/linux/i2c/i2c-hid.h
+++ b/include/linux/i2c/i2c-hid.h
@@ -14,9 +14,13 @@
14 14
15#include <linux/types.h> 15#include <linux/types.h>
16 16
17struct regulator;
18
17/** 19/**
18 * struct i2chid_platform_data - used by hid over i2c implementation. 20 * struct i2chid_platform_data - used by hid over i2c implementation.
19 * @hid_descriptor_address: i2c register where the HID descriptor is stored. 21 * @hid_descriptor_address: i2c register where the HID descriptor is stored.
22 * @supply: regulator for powering on the device.
23 * @post_power_delay_ms: delay after powering on before device is usable.
20 * 24 *
21 * Note that it is the responsibility of the platform driver (or the acpi 5.0 25 * Note that it is the responsibility of the platform driver (or the acpi 5.0
22 * driver, or the flattened device tree) to setup the irq related to the gpio in 26 * driver, or the flattened device tree) to setup the irq related to the gpio in
@@ -31,6 +35,8 @@
31 */ 35 */
32struct i2c_hid_platform_data { 36struct i2c_hid_platform_data {
33 u16 hid_descriptor_address; 37 u16 hid_descriptor_address;
38 struct regulator *supply;
39 int post_power_delay_ms;
34}; 40};
35 41
36#endif /* __LINUX_I2C_HID_H */ 42#endif /* __LINUX_I2C_HID_H */