Commit ba984d27 authored by Jiri Kosina's avatar Jiri Kosina

Merge branch 'for-6.4/i2c-hid' into for-linus

- reset GPIO support (Hans de Goede)
parents 63f7cf66 2be40448
...@@ -23,12 +23,14 @@ config I2C_HID_ACPI ...@@ -23,12 +23,14 @@ config I2C_HID_ACPI
config I2C_HID_OF config I2C_HID_OF
tristate "HID over I2C transport layer Open Firmware driver" tristate "HID over I2C transport layer Open Firmware driver"
depends on OF # No "depends on OF" because this can also be used for manually
# (board-file) instantiated "hid-over-i2c" type i2c-clients.
select I2C_HID_CORE select I2C_HID_CORE
help help
Say Y here if you use a keyboard, a touchpad, a touchscreen, or any Say Y here if you use a keyboard, a touchpad, a touchscreen, or any
other HID based devices which is connected to your computer via I2C. other HID based devices which is connected to your computer via I2C.
This driver supports Open Firmware (Device Tree)-based systems. This driver supports Open Firmware (Device Tree)-based systems as
well as binding to manually (board-file) instantiated i2c-hid-clients.
If unsure, say N. If unsure, say N.
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -35,8 +36,10 @@ struct i2c_hid_of { ...@@ -35,8 +36,10 @@ struct i2c_hid_of {
struct i2chid_ops ops; struct i2chid_ops ops;
struct i2c_client *client; struct i2c_client *client;
struct gpio_desc *reset_gpio;
struct regulator_bulk_data supplies[2]; struct regulator_bulk_data supplies[2];
int post_power_delay_ms; int post_power_delay_ms;
int post_reset_delay_ms;
}; };
static int i2c_hid_of_power_up(struct i2chid_ops *ops) static int i2c_hid_of_power_up(struct i2chid_ops *ops)
...@@ -55,6 +58,10 @@ static int i2c_hid_of_power_up(struct i2chid_ops *ops) ...@@ -55,6 +58,10 @@ static int i2c_hid_of_power_up(struct i2chid_ops *ops)
if (ihid_of->post_power_delay_ms) if (ihid_of->post_power_delay_ms)
msleep(ihid_of->post_power_delay_ms); msleep(ihid_of->post_power_delay_ms);
gpiod_set_value_cansleep(ihid_of->reset_gpio, 0);
if (ihid_of->post_reset_delay_ms)
msleep(ihid_of->post_reset_delay_ms);
return 0; return 0;
} }
...@@ -62,6 +69,7 @@ static void i2c_hid_of_power_down(struct i2chid_ops *ops) ...@@ -62,6 +69,7 @@ static void i2c_hid_of_power_down(struct i2chid_ops *ops)
{ {
struct i2c_hid_of *ihid_of = container_of(ops, struct i2c_hid_of, ops); struct i2c_hid_of *ihid_of = container_of(ops, struct i2c_hid_of, ops);
gpiod_set_value_cansleep(ihid_of->reset_gpio, 1);
regulator_bulk_disable(ARRAY_SIZE(ihid_of->supplies), regulator_bulk_disable(ARRAY_SIZE(ihid_of->supplies),
ihid_of->supplies); ihid_of->supplies);
} }
...@@ -75,33 +83,43 @@ static int i2c_hid_of_probe(struct i2c_client *client) ...@@ -75,33 +83,43 @@ static int i2c_hid_of_probe(struct i2c_client *client)
int ret; int ret;
u32 val; u32 val;
ihid_of = devm_kzalloc(&client->dev, sizeof(*ihid_of), GFP_KERNEL); ihid_of = devm_kzalloc(dev, sizeof(*ihid_of), GFP_KERNEL);
if (!ihid_of) if (!ihid_of)
return -ENOMEM; return -ENOMEM;
ihid_of->ops.power_up = i2c_hid_of_power_up; ihid_of->ops.power_up = i2c_hid_of_power_up;
ihid_of->ops.power_down = i2c_hid_of_power_down; ihid_of->ops.power_down = i2c_hid_of_power_down;
ret = of_property_read_u32(dev->of_node, "hid-descr-addr", &val); ret = device_property_read_u32(dev, "hid-descr-addr", &val);
if (ret) { if (ret) {
dev_err(&client->dev, "HID register address not provided\n"); dev_err(dev, "HID register address not provided\n");
return -ENODEV; return -ENODEV;
} }
if (val >> 16) { if (val >> 16) {
dev_err(&client->dev, "Bad HID register address: 0x%08x\n", dev_err(dev, "Bad HID register address: 0x%08x\n", val);
val);
return -EINVAL; return -EINVAL;
} }
hid_descriptor_address = val; hid_descriptor_address = val;
if (!device_property_read_u32(&client->dev, "post-power-on-delay-ms", if (!device_property_read_u32(dev, "post-power-on-delay-ms", &val))
&val))
ihid_of->post_power_delay_ms = val; ihid_of->post_power_delay_ms = val;
/*
* Note this is a kernel internal device-property set by x86 platform code,
* this MUST not be used in devicetree files without first adding it to
* the DT bindings.
*/
if (!device_property_read_u32(dev, "post-reset-deassert-delay-ms", &val))
ihid_of->post_reset_delay_ms = val;
/* Start out with reset asserted */
ihid_of->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(ihid_of->reset_gpio))
return PTR_ERR(ihid_of->reset_gpio);
ihid_of->supplies[0].supply = "vdd"; ihid_of->supplies[0].supply = "vdd";
ihid_of->supplies[1].supply = "vddl"; ihid_of->supplies[1].supply = "vddl";
ret = devm_regulator_bulk_get(&client->dev, ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ihid_of->supplies),
ARRAY_SIZE(ihid_of->supplies),
ihid_of->supplies); ihid_of->supplies);
if (ret) if (ret)
return ret; return ret;
...@@ -116,11 +134,13 @@ static int i2c_hid_of_probe(struct i2c_client *client) ...@@ -116,11 +134,13 @@ static int i2c_hid_of_probe(struct i2c_client *client)
hid_descriptor_address, quirks); hid_descriptor_address, quirks);
} }
#ifdef CONFIG_OF
static const struct of_device_id i2c_hid_of_match[] = { static const struct of_device_id i2c_hid_of_match[] = {
{ .compatible = "hid-over-i2c" }, { .compatible = "hid-over-i2c" },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, i2c_hid_of_match); MODULE_DEVICE_TABLE(of, i2c_hid_of_match);
#endif
static const struct i2c_device_id i2c_hid_of_id_table[] = { static const struct i2c_device_id i2c_hid_of_id_table[] = {
{ "hid", 0 }, { "hid", 0 },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment