diff mbox series

[v10,3/3] HID: cp2112: Fwnode Support

Message ID 20240205170920.93499-4-danny.kaehn@plexus.com (mailing list archive)
State New
Delegated to: Jiri Kosina
Headers show
Series Firmware Support for USB-HID Devices and CP2112 | expand

Commit Message

Danny Kaehn Feb. 5, 2024, 5:09 p.m. UTC
Support describing the CP2112's I2C and GPIO interfaces in firmware.

I2C and GPIO child nodes can either be children with names "i2c" and
"gpio", or, for ACPI, device nodes with _ADR Zero and One,
respectively.

Additionally, support configuring the I2C bus speed from the
clock-frequency device property.

Signed-off-by: Danny Kaehn <danny.kaehn@plexus.com>
---

Modeled this version based on Andy's email [1], but made the following
primary changes:
1. Use enum instead of #defines at Benjamin's request
2. Change if() else on checking name existence to allow a fwnode to
have a name that doesn't match to still be checked for its ACPI address
(since fwnode_get_name() _does_ still return a name for ACPI nodes)
3. Continue gracefully / silently if matching fwnodes fails

ACPI compatibility re-tested in QEMU as per conversations in v8.

NOTE: now that I'm not using device_get_named_child_node(), I am no longer
being left with a fwnode reference. I am not entirely sure if I
_need_ one for how I am using the handles, so I have left out the calls
to fwnode_handle_get() and fwnode_hand_put() for now. Plese correct me if
this is a situation where a reference should be held until the driver
is removed. Note that this has been present since v9, but I intended to
include this comment on that patch.

[1] https://lore.kernel.org/all/ZBhYXwjPeRiZwxMT@smile.fi.intel.com/

 drivers/hid/hid-cp2112.c | 50 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

Comments

Andy Shevchenko Feb. 6, 2024, 2:05 p.m. UTC | #1
On Mon, Feb 05, 2024 at 11:09:22AM -0600, Danny Kaehn wrote:
> Support describing the CP2112's I2C and GPIO interfaces in firmware.
> 
> I2C and GPIO child nodes can either be children with names "i2c" and
> "gpio", or, for ACPI, device nodes with _ADR Zero and One,
> respectively.

> Additionally, support configuring the I2C bus speed from the
> clock-frequency device property.

This has to be in a separate patch, which may predecess this one.

...

> +		name = fwnode_get_name(child);
> +		if (name) {
> +			ret = match_string(cp2112_cell_names,
> +							ARRAY_SIZE(cp2112_cell_names), name);
> +			if (ret >= 0)
> +				addr = ret;
> +		}
> +		if (!name || ret < 0)
> +			ret = acpi_get_local_address(ACPI_HANDLE_FWNODE(child), &addr);
> +
> +		if (ret < 0)
> +			continue;

I don't like this piece (esp. due to possible matching with node name which
may not be so reliable), but I have no better solution right now.

Maybe this way (this doesn't particularly solve the issue but seems better
to me)?

		ret = acpi_get_local_address(ACPI_HANDLE_FWNODE(child), &addr);
		if (ret) {
			/* If no ACPI given or compiled, fallback to matching names */
			name = fwnode_get_name(child);
			if (!name)
				continue;

			ret = match_string(cp2112_cell_names, ARRAY_SIZE(cp2112_cell_names), name);
			if (ret < 0)
				continue;

			addr = ret;
		}
kernel test robot Feb. 6, 2024, 3:54 p.m. UTC | #2
Hi Danny,

kernel test robot noticed the following build warnings:

[auto build test WARNING on hid/for-next]
[also build test WARNING on robh/for-next andi-shyti/i2c/i2c-host linus/master v6.8-rc3 next-20240206]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Danny-Kaehn/dt-bindings-i2c-Add-CP2112-HID-USB-to-SMBus-Bridge/20240206-015922
base:   https://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git for-next
patch link:    https://lore.kernel.org/r/20240205170920.93499-4-danny.kaehn%40plexus.com
patch subject: [PATCH v10 3/3] HID: cp2112: Fwnode Support
config: x86_64-randconfig-102-20240206 (https://download.01.org/0day-ci/archive/20240206/202402062306.UUQJhqxi-lkp@intel.com/config)
compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240206/202402062306.UUQJhqxi-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202402062306.UUQJhqxi-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/hid/hid-cp2112.c:41: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst
    * CP2112 Fwnode child names.


vim +41 drivers/hid/hid-cp2112.c

    39	
    40	/**
  > 41	 * CP2112 Fwnode child names.
    42	 * CP2112 sub-functions can be described by named fwnode children or by ACPI _ADR
    43	 */
    44	static const char * const cp2112_cell_names[] = {
    45		[CP2112_I2C_ADR]	= "i2c",
    46		[CP2112_GPIO_ADR]	= "gpio",
    47	};
    48
diff mbox series

Patch

diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c
index 20a0d1315d90..2ec0e5b95845 100644
--- a/drivers/hid/hid-cp2112.c
+++ b/drivers/hid/hid-cp2112.c
@@ -27,6 +27,25 @@ 
 #include <linux/usb/ch9.h>
 #include "hid-ids.h"
 
+/**
+ * enum cp2112_child_acpi_cell_addrs - Child ACPI addresses for CP2112 sub-functions
+ * @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,
+};
+
+/**
+ * CP2112 Fwnode child names.
+ * CP2112 sub-functions can be described by named fwnode children or by ACPI _ADR
+ */
+static const char * const cp2112_cell_names[] = {
+	[CP2112_I2C_ADR]	= "i2c",
+	[CP2112_GPIO_ADR]	= "gpio",
+};
+
 #define CP2112_REPORT_MAX_LENGTH		64
 #define CP2112_GPIO_CONFIG_LENGTH		5
 #define CP2112_GPIO_GET_LENGTH			2
@@ -1195,7 +1214,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 *child;
 	struct gpio_irq_chip *girq;
+	struct i2c_timings timings;
+	const char *name;
+	u32 addr;
 	int ret;
 
 	dev = devm_kzalloc(&hdev->dev, sizeof(*dev), GFP_KERNEL);
@@ -1209,6 +1232,30 @@  static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
 	mutex_init(&dev->lock);
 
+	device_for_each_child_node(&hdev->dev, child) {
+		name = fwnode_get_name(child);
+		if (name) {
+			ret = match_string(cp2112_cell_names,
+							ARRAY_SIZE(cp2112_cell_names), name);
+			if (ret >= 0)
+				addr = ret;
+		}
+		if (!name || ret < 0)
+			ret = acpi_get_local_address(ACPI_HANDLE_FWNODE(child), &addr);
+
+		if (ret < 0)
+			continue;
+
+		switch (addr) {
+		case CP2112_I2C_ADR:
+			device_set_node(&dev->adap.dev, child);
+			break;
+		case CP2112_GPIO_ADR:
+			dev->gc.fwnode = child;
+			break;
+		}
+	}
+
 	ret = hid_parse(hdev);
 	if (ret) {
 		hid_err(hdev, "parse failed\n");
@@ -1254,6 +1301,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),