diff options
| author | Jiri Kosina <jkosina@suse.com> | 2026-06-16 22:56:57 +0300 |
|---|---|---|
| committer | Jiri Kosina <jkosina@suse.com> | 2026-06-16 22:56:57 +0300 |
| commit | 50d9413e70de18af16bea74fe5d4cb01fa18cec1 (patch) | |
| tree | 6f0ac060384b9f09e5e16fb626af2d51b9fe73ed | |
| parent | 2f67fc40034a3b557450c50b3d6e027867d04b5a (diff) | |
| parent | efab84c398c17d2575e8a308c243915baae3affa (diff) | |
| download | linux-50d9413e70de18af16bea74fe5d4cb01fa18cec1.tar.xz | |
Merge branch 'for-7.2/cp2112' into for-linus
- fwnode support for cp2112 (Danny Kaehn)
- fix for cp2112 firmware-based speed configuration, if available (Danny Kaehn)
| -rw-r--r-- | drivers/hid/hid-cp2112.c | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c index 803b883ae875..04379db93571 100644 --- a/drivers/hid/hid-cp2112.c +++ b/drivers/hid/hid-cp2112.c @@ -29,6 +29,18 @@ #include <linux/usb/ch9.h> #include "hid-ids.h" +/** + * enum cp2112_child_acpi_cell_addrs - Child ACPI addresses for CP2112 sub-functions + * Note that the enum values are explicitly defined, as this defines the interface + * between ACPI and Linux + * @CP2112_I2C_ADR: Address for I2C node + * @CP2112_GPIO_ADR: Address for GPIO node + */ +enum cp2112_child_acpi_cell_addrs { + CP2112_I2C_ADR = 0, + CP2112_GPIO_ADR = 1, +}; + #define CP2112_REPORT_MAX_LENGTH 64 #define CP2112_GPIO_CONFIG_LENGTH 5 #define CP2112_GPIO_GET_LENGTH 2 @@ -1208,7 +1220,11 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id) struct cp2112_device *dev; u8 buf[3]; struct cp2112_smbus_config_report config; + struct fwnode_handle *cp2112_fwnode; + struct fwnode_handle *child; struct gpio_irq_chip *girq; + struct i2c_timings timings; + u32 addr; int ret; dev = devm_kzalloc(&hdev->dev, sizeof(*dev), GFP_KERNEL); @@ -1226,6 +1242,28 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id) return ret; } + cp2112_fwnode = dev_fwnode(&hdev->dev); + if (is_acpi_device_node(cp2112_fwnode)) { + fwnode_for_each_child_node(cp2112_fwnode, child) { + ret = acpi_get_local_address(ACPI_HANDLE_FWNODE(child), &addr); + if (ret) + continue; + + switch (addr) { + case CP2112_I2C_ADR: + device_set_node(&dev->adap.dev, child); + break; + case CP2112_GPIO_ADR: + dev->gc.fwnode = child; + break; + } + } + } else if (is_of_node(cp2112_fwnode)) { + child = fwnode_get_named_child_node(cp2112_fwnode, "i2c"); + device_set_node(&dev->adap.dev, child); + fwnode_handle_put(child); + } + ret = hid_parse(hdev); if (ret) { hid_err(hdev, "parse failed\n"); @@ -1271,6 +1309,9 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id) goto err_power_normal; } + i2c_parse_fw_timings(&dev->adap.dev, &timings, true); + + config.clock_speed = cpu_to_be32(timings.bus_freq_hz); config.retry_time = cpu_to_be16(1); ret = cp2112_hid_output(hdev, (u8 *)&config, sizeof(config), |
