Skip to contentSkip to conversation

usb/gpio/i2c: Add Intel USBIO USB IO-expander drivers

PATCH Superseded Hans de Goede 3 participants 11 messages Sep 7, 2025 – Sep 10, 2025

Subsystems (4)

v2 of 6 Superseded Latest is v6 →

lore
Share & tools
lore

Hans de Goede

author maintainer
#0 lore raw

v2 cover usb/gpio/i2c: Add Intel USBIO USB IO-expander drivers

Hi All,

Here is v2 of the patch series to add support for the Intel USBIO USB IO-expander used by the MIPI cameras on various new (Meteor Lake and later) Intel laptops.

Changes in v2:
- Split usbio-bridge mutex into ctrl_mutex and bulk_mutex
- Drop SPI support since this is not used on devices in the field
- Rework disconnect handling to be more robust
- Several different revisions need special casing add a quirks mechanism for this
- Stop using stdint.h (uintX_t) types
- Use __le16, __le32 type + cpu_to_le16() and friends for on wire words
- Properly check auxiliary_device_add() return value
- Add a mutex to the GPIO driver to protect usbio_gpio_update_config() calls, which read-modify-write banks[x].config, racing with each other
- Adjust usbio_gpio_get() to have an int return value and propagate the usbio_control_msg() return value
- Various (small) style fixes from Sakari's review of all 3 patches

The first patch adds an USB bridge driver which registers auxbus children for the GPIO and I2C functions of the USBIO chip.

The second and third patch add a GPIO resp. an I2C driver for the auxbus children using the IO functions exported by the USB bridge driver.

The second and third patch depend on the IO functions exported by the first patch. So to merge this we will need either an immutable tag on the USB tree, or all 3 patches can be merged through the USB tree with acks from the GPIO and I2C subsystem maintainers.

Regards,

Hans

Israel Cepeda (3):
usb: misc: Add Intel USBIO bridge driver
gpio: Add Intel USBIO GPIO driver
i2c: Add Intel USBIO I2C driver

 MAINTAINERS                    |  10 +
 drivers/gpio/Kconfig           |  11 +
 drivers/gpio/Makefile          |   1 +
 drivers/gpio/gpio-usbio.c      | 266 ++++++++++++
 drivers/i2c/busses/Kconfig     |  11 +
 drivers/i2c/busses/Makefile    |   1 +
 drivers/i2c/busses/i2c-usbio.c | 325 ++++++++++++++
 drivers/usb/misc/Kconfig       |  14 +
 drivers/usb/misc/Makefile      |   1 +
 drivers/usb/misc/usbio.c       | 748 +++++++++++++++++++++++++++++++++
 include/linux/usb/usbio.h      | 177 ++++++++
 11 files changed, 1565 insertions(+)
 create mode 100644 drivers/gpio/gpio-usbio.c
 create mode 100644 drivers/i2c/busses/i2c-usbio.c
 create mode 100644 drivers/usb/misc/usbio.c
 create mode 100644 include/linux/usb/usbio.h
Signature · 1 line
2.51.0
author maintainer
#1 lore raw

PATCH v2 1/3 usb: misc: Add Intel USBIO bridge driver

From: Israel Cepeda <[email protected]>

Add a driver for the Intel USBIO USB IO-expander used by the MIPI cameras on various new (Meteor Lake and later) Intel laptops.

This is an USB bridge driver which adds auxbus child devices for the GPIO, I2C and SPI functions of the USBIO chip and which exports IO-functions for the drivers for the auxbus child devices to communicate with the USBIO device's firmware.

---
Changes in v2:
- Split usbio-bridge mutex into ctrl_mutex and bulk_mutex
- Drop SPI support since this is not used on devices in the field
- Rework disconnect handling to be more robust
- Several different revisions need special casing add a quirks mechanism for this
- Stop using stdint.h (uintX_t) types
- Use __le16, __le32 type + cpu_to_le16() and friends for on wire words
- Properly check auxiliary_device_add() return value
- Some small style fixes from Sakari's review

---
 MAINTAINERS               |   8 +
 drivers/usb/misc/Kconfig  |  14 +
 drivers/usb/misc/Makefile |   1 +
 drivers/usb/misc/usbio.c  | 749 ++++++++++++++++++++++++++++++++++++++
 include/linux/usb/usbio.h | 177 +++++++++
 5 files changed, 949 insertions(+)
 create mode 100644 drivers/usb/misc/usbio.c
 create mode 100644 include/linux/usb/usbio.h
MAINTAINERS +8 -0
index d91348a66738..3410699ad0b2 100644
@@ -12694,6 +12694,14 @@ S:	Maintained
 F:	Documentation/admin-guide/pm/intel_uncore_frequency_scaling.rst
 F:	drivers/platform/x86/intel/uncore-frequency/
 
+INTEL USBIO USB I/O EXPANDER DRIVERS
+M:	Israel Cepeda <[email protected]>
+M:	Hans de Goede <[email protected]>
+R:	Sakari Ailus <[email protected]>
+S:	Maintained
+F:	drivers/usb/misc/usbio.c
+F:	include/linux/usb/usbio.h
+
 INTEL VENDOR SPECIFIC EXTENDED CAPABILITIES DRIVER
 M:	David E. Box <[email protected]>
 S:	Supported
drivers/usb/misc/Kconfig +14 -0
index 6497c4e81e95..bfe08e15d051 100644
@@ -178,6 +178,20 @@ config USB_LJCA
 	  This driver can also be built as a module. If so, the module
 	  will be called usb-ljca.
 
+config USB_USBIO
+	tristate "Intel USBIO Bridge support"
+	depends on USB && ACPI
+	select AUXILIARY_BUS
+	help
+	  This adds support for Intel USBIO drivers.
+	  This enables the USBIO bridge driver module in charge to talk
+	  to the USB device. Additional drivers such as GPIO_USBIO and
+	  I2C_USBIO must be enabled in order to use the device's full
+	  functionality.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called usbio.
+
 source "drivers/usb/misc/sisusbvga/Kconfig"
 
 config USB_LD
drivers/usb/misc/Makefile +1 -0
index 0cd5bc8f52fe..494ab0377f35 100644
@@ -12,6 +12,7 @@ obj-$(CONFIG_USB_EMI62)			+= emi62.o
 obj-$(CONFIG_USB_EZUSB_FX2)		+= ezusb.o
 obj-$(CONFIG_APPLE_MFI_FASTCHARGE)	+= apple-mfi-fastcharge.o
 obj-$(CONFIG_USB_LJCA)			+= usb-ljca.o
+obj-$(CONFIG_USB_USBIO)			+= usbio.o
 obj-$(CONFIG_USB_IDMOUSE)		+= idmouse.o
 obj-$(CONFIG_USB_IOWARRIOR)		+= iowarrior.o
 obj-$(CONFIG_USB_ISIGHTFW)		+= isight_firmware.o
drivers/usb/misc/usbio.c new file +749 -0

749 lines not on this page · raw message

include/linux/usb/usbio.h new file +177 -0

177 lines not on this page · raw message

Signature · 1 line
2.51.0
author maintainer
#2 lore raw

PATCH v2 2/3 gpio: Add Intel USBIO GPIO driver

In reply to Hans de Goede

From: Israel Cepeda <[email protected]>

Add a a driver for the GPIO auxbus child device of the Intel USBIO USB IO-expander used by the MIPI cameras on various new (Meteor Lake and later) Intel laptops.

---
Changes in v2:
- Add a config_mutex protect usbio_gpio_update_config() calls, which read-modify-write banks[x].config, racing with each other
- Adjust usbio_gpio_get() to have an int return value and propagate the usbio_control_msg() return value
- Use __le16, __le32 type + cpu_to_le16() and friends for on wire words
- Some small style fixes from Sakari's review

---
 MAINTAINERS               |   1 +
 drivers/gpio/Kconfig      |  11 ++
 drivers/gpio/Makefile     |   1 +
 drivers/gpio/gpio-usbio.c | 267 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 280 insertions(+)
 create mode 100644 drivers/gpio/gpio-usbio.c
MAINTAINERS +1 -0
index 3410699ad0b2..53694bd91861 100644
@@ -12699,6 +12699,7 @@ M:	Israel Cepeda <[email protected]>
 M:	Hans de Goede <[email protected]>
 R:	Sakari Ailus <[email protected]>
 S:	Maintained
+F:	drivers/gpio/gpio-usbio.c
 F:	drivers/usb/misc/usbio.c
 F:	include/linux/usb/usbio.h
 
drivers/gpio/Kconfig +11 -0
index e43abb322fa6..5d3ca3dd2687 100644
@@ -1448,6 +1448,17 @@ config GPIO_LJCA
 	  This driver can also be built as a module. If so, the module
 	  will be called gpio-ljca.
 
+config GPIO_USBIO
+	tristate "Intel USBIO GPIO support"
+	depends on USB_USBIO
+	default USB_USBIO
+	help
+	  Select this option to enable GPIO driver for the INTEL
+	  USBIO driver stack.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called gpio_usbio.
+
 config GPIO_LP3943
 	tristate "TI/National Semiconductor LP3943 GPIO expander"
 	depends on MFD_LP3943
drivers/gpio/Makefile +1 -0
index 379f55e9ed1e..8c55e2d5de42 100644
@@ -90,6 +90,7 @@ obj-$(CONFIG_GPIO_JANZ_TTL)		+= gpio-janz-ttl.o
 obj-$(CONFIG_GPIO_KEMPLD)		+= gpio-kempld.o
 obj-$(CONFIG_GPIO_LATCH)		+= gpio-latch.o
 obj-$(CONFIG_GPIO_LJCA) 		+= gpio-ljca.o
+obj-$(CONFIG_GPIO_USBIO) 		+= gpio-usbio.o
 obj-$(CONFIG_GPIO_LOGICVC)		+= gpio-logicvc.o
 obj-$(CONFIG_GPIO_LOONGSON1)		+= gpio-loongson1.o
 obj-$(CONFIG_GPIO_LOONGSON)		+= gpio-loongson.o
drivers/gpio/gpio-usbio.c new file +267 -0

267 lines not on this page · raw message

Signature · 1 line
2.51.0
#3 lore raw

Re: [PATCH v2 2/3] gpio: Add Intel USBIO GPIO driver

Quoted 115 lines · Hans de Goede

From: Israel Cepeda <[email protected]>

Add a a driver for the GPIO auxbus child device of the Intel USBIO USB IO-expander used by the MIPI cameras on various new (Meteor Lake and later) Intel laptops.

---
Changes in v2:
- Add a config_mutex protect usbio_gpio_update_config() calls, which read-modify-write banks[x].config, racing with each other
- Adjust usbio_gpio_get() to have an int return value and propagate the usbio_control_msg() return value
- Use __le16, __le32 type + cpu_to_le16() and friends for on wire words
- Some small style fixes from Sakari's review

---
 MAINTAINERS               |   1 +
 drivers/gpio/Kconfig      |  11 ++
 drivers/gpio/Makefile     |   1 +
 drivers/gpio/gpio-usbio.c | 267 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 280 insertions(+)
 create mode 100644 drivers/gpio/gpio-usbio.c
MAINTAINERS +1 -0
index 3410699ad0b2..53694bd91861 100644
@@ -12699,6 +12699,7 @@ M:	Israel Cepeda <[email protected]>
 M:	Hans de Goede <[email protected]>
 R:	Sakari Ailus <[email protected]>
 S:	Maintained
+F:	drivers/gpio/gpio-usbio.c
 F:	drivers/usb/misc/usbio.c
 F:	include/linux/usb/usbio.h
 
drivers/gpio/Kconfig +11 -0
index e43abb322fa6..5d3ca3dd2687 100644
@@ -1448,6 +1448,17 @@ config GPIO_LJCA
 	  This driver can also be built as a module. If so, the module
 	  will be called gpio-ljca.
 
+config GPIO_USBIO
+	tristate "Intel USBIO GPIO support"
+	depends on USB_USBIO
+	default USB_USBIO
+	help
+	  Select this option to enable GPIO driver for the INTEL
+	  USBIO driver stack.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called gpio_usbio.
+
 config GPIO_LP3943
 	tristate "TI/National Semiconductor LP3943 GPIO expander"
 	depends on MFD_LP3943
drivers/gpio/Makefile +1 -0
index 379f55e9ed1e..8c55e2d5de42 100644
@@ -90,6 +90,7 @@ obj-$(CONFIG_GPIO_JANZ_TTL)		+= gpio-janz-ttl.o
 obj-$(CONFIG_GPIO_KEMPLD)		+= gpio-kempld.o
 obj-$(CONFIG_GPIO_LATCH)		+= gpio-latch.o
 obj-$(CONFIG_GPIO_LJCA) 		+= gpio-ljca.o
+obj-$(CONFIG_GPIO_USBIO) 		+= gpio-usbio.o
 obj-$(CONFIG_GPIO_LOGICVC)		+= gpio-logicvc.o
 obj-$(CONFIG_GPIO_LOONGSON1)		+= gpio-loongson1.o
 obj-$(CONFIG_GPIO_LOONGSON)		+= gpio-loongson.o
drivers/gpio/gpio-usbio.c new file +38 -0
new file mode 100644
index 000000000000..1df32105cf51
@@ -0,0 +1,267 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 Intel Corporation.
+ * Copyright (c) 2025 Red Hat, Inc.
+ */
+
+#include <linux/acpi.h>
+#include <linux/auxiliary_bus.h>
+#include <linux/cleanup.h>
+#include <linux/dev_printk.h>
+#include <linux/device.h>
+#include <linux/gpio/driver.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/usb/usbio.h>
+
+struct usbio_gpio_bank {
+	u8 config[USBIO_GPIOSPERBANK];
+	u32 bitmap;
+};
+
+struct usbio_gpio {
+	struct mutex config_mutex; /* Protects banks[x].config */
+	struct usbio_gpio_bank banks[USBIO_MAX_GPIOBANKS];
+	struct gpio_chip gc;
+	struct auxiliary_device *adev;
+};
+
+static const struct acpi_device_id usbio_gpio_acpi_hids[] = {
+	{ "INTC1007" }, /* MTL */
+	{ "INTC10B2" }, /* ARL */
+	{ "INTC10B5" }, /* LNL */
+	{ "INTC10E2" }, /* PTL */
+	{ }
+};
+
+static bool usbio_gpio_get_bank_and_pin(struct gpio_chip *gc, unsigned int offset,
+					struct usbio_gpio_bank **bank_ret,

drivers/gpio/gpio-usbio.c line 48

Quoted 10 lines
drivers/gpio/gpio-usbio.c new file +10 -0
+					unsigned int *pin_ret)
+{
+	struct usbio_gpio *gpio = gpiochip_get_data(gc);
+	struct device *dev = &gpio->adev->dev;
+	struct usbio_gpio_bank *bank;
+	unsigned int pin;
+
+	if (offset >= gc->ngpio)
+		return false;
+

No need for that, GPIO core will make sure this never happens.

Quoted 103 lines
drivers/gpio/gpio-usbio.c new file +103 -0
+	bank = &gpio->banks[offset / USBIO_GPIOSPERBANK];
+	pin = offset % USBIO_GPIOSPERBANK;
+	if (~bank->bitmap & BIT(pin)) {
+		/* The FW bitmap sometimes is invalid, warn and continue */
+		dev_warn_once(dev, FW_BUG "GPIO %u is not in FW pins bitmap\n", offset);
+	}
+
+	*bank_ret = bank;
+	*pin_ret = pin;
+	return true;
+}
+
+static int usbio_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+	struct usbio_gpio_bank *bank;
+	unsigned int pin;
+	u8 cfg;
+
+	if (!usbio_gpio_get_bank_and_pin(gc, offset, &bank, &pin))
+		return -EINVAL;
+
+	cfg = bank->config[pin] & USBIO_GPIO_PINMOD_MASK;
+
+	return (cfg == USBIO_GPIO_PINMOD_OUTPUT) ?
+		GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
+}
+
+static int usbio_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+	struct usbio_gpio *gpio = gpiochip_get_data(gc);
+	struct usbio_gpio_bank *bank;
+	struct usbio_gpio_rw gbuf;
+	unsigned int pin;
+	int ret;
+
+	if (!usbio_gpio_get_bank_and_pin(gc, offset, &bank, &pin))
+		return -EINVAL;
+
+	gbuf.bankid = offset / USBIO_GPIOSPERBANK;
+	gbuf.pincount  = 1;
+	gbuf.pin = pin;
+
+	ret = usbio_control_msg(gpio->adev, USBIO_PKTTYPE_GPIO, USBIO_GPIOCMD_READ,
+				&gbuf, sizeof(gbuf) - sizeof(gbuf.value),
+				&gbuf, sizeof(gbuf));
+	if (ret != sizeof(gbuf))
+		return (ret < 0) ? ret : -EPROTO;
+
+	return (le32_to_cpu(gbuf.value) >> pin) & 1;
+}
+
+static int usbio_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
+{
+	struct usbio_gpio *gpio = gpiochip_get_data(gc);
+	struct usbio_gpio_bank *bank;
+	struct usbio_gpio_rw gbuf;
+	unsigned int pin;
+
+	if (!usbio_gpio_get_bank_and_pin(gc, offset, &bank, &pin))
+		return -EINVAL;
+
+	gbuf.bankid = offset / USBIO_GPIOSPERBANK;
+	gbuf.pincount  = 1;
+	gbuf.pin = pin;
+	gbuf.value = cpu_to_le32(value << pin);
+
+	return usbio_control_msg(gpio->adev, USBIO_PKTTYPE_GPIO, USBIO_GPIOCMD_WRITE,
+				 &gbuf, sizeof(gbuf), NULL, 0);
+}
+
+static int usbio_gpio_update_config(struct gpio_chip *gc, unsigned int offset,
+				    u8 mask, u8 value)
+{
+	struct usbio_gpio *gpio = gpiochip_get_data(gc);
+	struct usbio_gpio_bank *bank;
+	struct usbio_gpio_init gbuf;
+	unsigned int pin;
+
+	if (!usbio_gpio_get_bank_and_pin(gc, offset, &bank, &pin))
+		return -EINVAL;
+
+	guard(mutex)(&gpio->config_mutex);
+
+	bank->config[pin] &= ~mask;
+	bank->config[pin] |= value;
+
+	gbuf.bankid = offset / USBIO_GPIOSPERBANK;
+	gbuf.config = bank->config[pin];
+	gbuf.pincount  = 1;
+	gbuf.pin = pin;
+
+	return usbio_control_msg(gpio->adev, USBIO_PKTTYPE_GPIO, USBIO_GPIOCMD_INIT,
+				 &gbuf, sizeof(gbuf), NULL, 0);
+}
+
+static int usbio_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
+{
+	return usbio_gpio_update_config(gc, offset, USBIO_GPIO_PINMOD_MASK,
+					USBIO_GPIO_SET_PINMOD(USBIO_GPIO_PINMOD_INPUT));
+}
+
+static int usbio_gpio_direction_output(struct gpio_chip *gc,
+		unsigned int offset, int value)

drivers/gpio/gpio-usbio.c line 161

Quoted 10 lines
drivers/gpio/gpio-usbio.c new file +10 -0
+{
+	int ret;
+
+	ret = usbio_gpio_update_config(gc, offset, USBIO_GPIO_PINMOD_MASK,
+				       USBIO_GPIO_SET_PINMOD(USBIO_GPIO_PINMOD_OUTPUT));
+	if (ret)
+		return ret;
+
+	usbio_gpio_set(gc, offset, value);
+	return 0;

return usbio_gpio_set(gc, offset, value);?

Quoted 61 lines
drivers/gpio/gpio-usbio.c new file +61 -0
+}
+
+static int usbio_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
+		unsigned long config)
+{
+	u8 value;
+
+	switch (pinconf_to_config_param(config)) {
+	case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
+		value = USBIO_GPIO_SET_PINCFG(USBIO_GPIO_PINCFG_DEFAULT);
+		break;
+	case PIN_CONFIG_BIAS_PULL_UP:
+		value = USBIO_GPIO_SET_PINCFG(USBIO_GPIO_PINCFG_PULLUP);
+		break;
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		value = USBIO_GPIO_SET_PINCFG(USBIO_GPIO_PINCFG_PULLDOWN);
+		break;
+	case PIN_CONFIG_DRIVE_PUSH_PULL:
+		value = USBIO_GPIO_SET_PINCFG(USBIO_GPIO_PINCFG_PUSHPULL);
+		break;
+	default:
+		return -ENOTSUPP;
+	}
+
+	return usbio_gpio_update_config(gc, offset, USBIO_GPIO_PINCFG_MASK, value);
+}
+
+static int usbio_gpio_probe(struct auxiliary_device *adev,
+		const struct auxiliary_device_id *adev_id)
+{
+	struct usbio_gpio_bank_desc *bank_desc;
+	struct device *dev = &adev->dev;
+	struct usbio_gpio *gpio;
+	int bank, ret;
+
+	bank_desc = dev_get_platdata(dev);
+	if (!bank_desc)
+		return -EINVAL;
+
+	gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL);
+	if (!gpio)
+		return -ENOMEM;
+
+	ret = devm_mutex_init(dev, &gpio->config_mutex);
+	if (ret)
+		return ret;
+
+	gpio->adev = adev;
+
+	usbio_acpi_bind(gpio->adev, usbio_gpio_acpi_hids);
+
+	for (bank = 0; bank < USBIO_MAX_GPIOBANKS && bank_desc[bank].bmap; bank++)
+		gpio->banks[bank].bitmap = le32_to_cpu(bank_desc[bank].bmap);
+
+	gpio->gc.label = ACPI_COMPANION(dev) ?
+					acpi_dev_name(ACPI_COMPANION(dev)) : dev_name(dev);
+	gpio->gc.parent = dev;
+	gpio->gc.owner = THIS_MODULE;
+	gpio->gc.get_direction = usbio_gpio_get_direction;
+	gpio->gc.direction_input = usbio_gpio_direction_input;
+	gpio->gc.direction_output = usbio_gpio_direction_output;

drivers/gpio/gpio-usbio.c line 232

Quoted 10 lines
drivers/gpio/gpio-usbio.c new file +10 -0
+	gpio->gc.get = usbio_gpio_get;
+	gpio->gc.set = usbio_gpio_set;
+	gpio->gc.set_config = usbio_gpio_set_config;
+	gpio->gc.base = -1;
+	gpio->gc.ngpio = bank * USBIO_GPIOSPERBANK;
+	gpio->gc.can_sleep = true;
+
+	auxiliary_set_drvdata(adev, gpio);
+
+	ret = gpiochip_add_data(&gpio->gc, gpio);

Please use the devres variant, you'll be able to drop the remove() callback.

Quoted 36 lines
drivers/gpio/gpio-usbio.c new file +35 -1
+	if (ret)
+		return ret;
+
+	if (has_acpi_companion(dev))
+		acpi_dev_clear_dependencies(ACPI_COMPANION(dev));
+
+	return 0;
+}
+
+static void usbio_gpio_remove(struct auxiliary_device *adev)
+{
+	struct usbio_gpio *gpio = auxiliary_get_drvdata(adev);
+
+	gpiochip_remove(&gpio->gc);
+}
+
+static const struct auxiliary_device_id usbio_gpio_id_table[] = {
+	{ "usbio.usbio-gpio" },
+	{ }
+};
+MODULE_DEVICE_TABLE(auxiliary, usbio_gpio_id_table);
+
+static struct auxiliary_driver usbio_gpio_driver = {
+	.name = USBIO_GPIO_CLIENT,
+	.probe = usbio_gpio_probe,
+	.remove = usbio_gpio_remove,
+	.id_table = usbio_gpio_id_table
+};
+module_auxiliary_driver(usbio_gpio_driver);
+
+MODULE_DESCRIPTION("Intel USBIO GPIO driver");
+MODULE_AUTHOR("Israel Cepeda <[email protected]>");
+MODULE_AUTHOR("Hans de Goede <[email protected]>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("USBIO");
--
Quoted 3 lines

2.51.0

Looks good otherwise.

Bartosz

author maintainer
#4 lore raw

Re: [PATCH v2 2/3] gpio: Add Intel USBIO GPIO driver

Hi Bartosz,

Thank you for the review.

Quoted 120 lines · Bartosz Golaszewski
Quoted 119 lines · Hans de Goede

From: Israel Cepeda <[email protected]>

Add a a driver for the GPIO auxbus child device of the Intel USBIO USB IO-expander used by the MIPI cameras on various new (Meteor Lake and later) Intel laptops.

---
Changes in v2:
- Add a config_mutex protect usbio_gpio_update_config() calls, which read-modify-write banks[x].config, racing with each other
- Adjust usbio_gpio_get() to have an int return value and propagate the usbio_control_msg() return value
- Use __le16, __le32 type + cpu_to_le16() and friends for on wire words
- Some small style fixes from Sakari's review

---
 MAINTAINERS               |   1 +
 drivers/gpio/Kconfig      |  11 ++
 drivers/gpio/Makefile     |   1 +
 drivers/gpio/gpio-usbio.c | 267 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 280 insertions(+)
 create mode 100644 drivers/gpio/gpio-usbio.c
MAINTAINERS +1 -0
index 3410699ad0b2..53694bd91861 100644
@@ -12699,6 +12699,7 @@ M:	Israel Cepeda <[email protected]>
 M:	Hans de Goede <[email protected]>
 R:	Sakari Ailus <[email protected]>
 S:	Maintained
+F:	drivers/gpio/gpio-usbio.c
 F:	drivers/usb/misc/usbio.c
 F:	include/linux/usb/usbio.h
 
drivers/gpio/Kconfig +11 -0
index e43abb322fa6..5d3ca3dd2687 100644
@@ -1448,6 +1448,17 @@ config GPIO_LJCA
 	  This driver can also be built as a module. If so, the module
 	  will be called gpio-ljca.
 
+config GPIO_USBIO
+	tristate "Intel USBIO GPIO support"
+	depends on USB_USBIO
+	default USB_USBIO
+	help
+	  Select this option to enable GPIO driver for the INTEL
+	  USBIO driver stack.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called gpio_usbio.
+
 config GPIO_LP3943
 	tristate "TI/National Semiconductor LP3943 GPIO expander"
 	depends on MFD_LP3943
drivers/gpio/Makefile +1 -0
index 379f55e9ed1e..8c55e2d5de42 100644
@@ -90,6 +90,7 @@ obj-$(CONFIG_GPIO_JANZ_TTL)		+= gpio-janz-ttl.o
 obj-$(CONFIG_GPIO_KEMPLD)		+= gpio-kempld.o
 obj-$(CONFIG_GPIO_LATCH)		+= gpio-latch.o
 obj-$(CONFIG_GPIO_LJCA) 		+= gpio-ljca.o
+obj-$(CONFIG_GPIO_USBIO) 		+= gpio-usbio.o
 obj-$(CONFIG_GPIO_LOGICVC)		+= gpio-logicvc.o
 obj-$(CONFIG_GPIO_LOONGSON1)		+= gpio-loongson1.o
 obj-$(CONFIG_GPIO_LOONGSON)		+= gpio-loongson.o
drivers/gpio/gpio-usbio.c new file +42 -0
new file mode 100644
index 000000000000..1df32105cf51
@@ -0,0 +1,267 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 Intel Corporation.
+ * Copyright (c) 2025 Red Hat, Inc.
+ */
+
+#include <linux/acpi.h>
+#include <linux/auxiliary_bus.h>
+#include <linux/cleanup.h>
+#include <linux/dev_printk.h>
+#include <linux/device.h>
+#include <linux/gpio/driver.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/usb/usbio.h>
+
+struct usbio_gpio_bank {
+	u8 config[USBIO_GPIOSPERBANK];
+	u32 bitmap;
+};
+
+struct usbio_gpio {
+	struct mutex config_mutex; /* Protects banks[x].config */
+	struct usbio_gpio_bank banks[USBIO_MAX_GPIOBANKS];
+	struct gpio_chip gc;
+	struct auxiliary_device *adev;
+};
+
+static const struct acpi_device_id usbio_gpio_acpi_hids[] = {
+	{ "INTC1007" }, /* MTL */
+	{ "INTC10B2" }, /* ARL */
+	{ "INTC10B5" }, /* LNL */
+	{ "INTC10E2" }, /* PTL */
+	{ }
+};
+
+static bool usbio_gpio_get_bank_and_pin(struct gpio_chip *gc, unsigned int offset,
+					struct usbio_gpio_bank **bank_ret,
+					unsigned int *pin_ret)
+{
+	struct usbio_gpio *gpio = gpiochip_get_data(gc);
+	struct device *dev = &gpio->adev->dev;
Quoted 8 lines

drivers/gpio/gpio-usbio.c line 48

Quoted 6 lines
drivers/gpio/gpio-usbio.c new file +6 -0
+	struct usbio_gpio_bank *bank;
+	unsigned int pin;
+
+	if (offset >= gc->ngpio)
+		return false;
+

No need for that, GPIO core will make sure this never happens.

Ack, will fix for v3. That also allows making this function return void further simplyfying things.

Quoted 11 lines
Quoted 11 lines
drivers/gpio/gpio-usbio.c new file +11 -0
+	bank = &gpio->banks[offset / USBIO_GPIOSPERBANK];
+	pin = offset % USBIO_GPIOSPERBANK;
+	if (~bank->bitmap & BIT(pin)) {
+		/* The FW bitmap sometimes is invalid, warn and continue */
+		dev_warn_once(dev, FW_BUG "GPIO %u is not in FW pins bitmap\n", offset);
+	}
+
+	*bank_ret = bank;
+	*pin_ret = pin;
+	return true;
+}

...

Quoted 6 lines
Quoted 6 lines
drivers/gpio/gpio-usbio.c new file +6 -0
+static int usbio_gpio_direction_output(struct gpio_chip *gc,
+		unsigned int offset, int value)
+{
+	int ret;
+
+	ret = usbio_gpio_update_config(gc, offset, USBIO_GPIO_PINMOD_MASK,
Quoted 8 lines

drivers/gpio/gpio-usbio.c line 161

Quoted 6 lines
drivers/gpio/gpio-usbio.c new file +6 -0
+				       USBIO_GPIO_SET_PINMOD(USBIO_GPIO_PINMOD_OUTPUT));
+	if (ret)
+		return ret;
+
+	usbio_gpio_set(gc, offset, value);
+	return 0;

return usbio_gpio_set(gc, offset, value);?

Ack, usbio_gpio_set() returned void in v1, hence this construct. Will fix for v3.

Quoted 1 line
Quoted 1 line

+}

...

Quoted 3 lines
Quoted 3 lines
drivers/gpio/gpio-usbio.c new file +3 -0
+static int usbio_gpio_probe(struct auxiliary_device *adev,
+		const struct auxiliary_device_id *adev_id)
+{

...

Quoted 5 lines

drivers/gpio/gpio-usbio.c line 232

Quoted 3 lines
drivers/gpio/gpio-usbio.c new file +3 -0
+	auxiliary_set_drvdata(adev, gpio);
+
+	ret = gpiochip_add_data(&gpio->gc, gpio);

Please use the devres variant, you'll be able to drop the remove() callback.

Ack, will fix for v3.

Quoted 33 lines
Quoted 33 lines
drivers/gpio/gpio-usbio.c new file +33 -0
+	if (ret)
+		return ret;
+
+	if (has_acpi_companion(dev))
+		acpi_dev_clear_dependencies(ACPI_COMPANION(dev));
+
+	return 0;
+}
+
+static void usbio_gpio_remove(struct auxiliary_device *adev)
+{
+	struct usbio_gpio *gpio = auxiliary_get_drvdata(adev);
+
+	gpiochip_remove(&gpio->gc);
+}
+
+static const struct auxiliary_device_id usbio_gpio_id_table[] = {
+	{ "usbio.usbio-gpio" },
+	{ }
+};
+MODULE_DEVICE_TABLE(auxiliary, usbio_gpio_id_table);
+
+static struct auxiliary_driver usbio_gpio_driver = {
+	.name = USBIO_GPIO_CLIENT,
+	.probe = usbio_gpio_probe,
+	.remove = usbio_gpio_remove,
+	.id_table = usbio_gpio_id_table
+};
+module_auxiliary_driver(usbio_gpio_driver);
+
+MODULE_DESCRIPTION("Intel USBIO GPIO driver");
+MODULE_AUTHOR("Israel Cepeda <[email protected]>");
+MODULE_AUTHOR("Hans de Goede <[email protected]>");
Quoted 8 lines
Quoted 6 lines
drivers/gpio/gpio-usbio.c new file +2 -1
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("USBIO");
--

2.51.0

Looks good otherwise.

Thank you I'll go and preparare a standalone v3 (since the other 2 patches have no reviews yet).

As mentioned in the cover-letter it is probably easiest if Greg merges the entire series through his usb tree once everything has been reviewed.

Once I've send it, can you please ack v3 for merging through Greg's USB tree?

Regards,

Hans

#5 lore raw

Re: [PATCH v2 2/3] gpio: Add Intel USBIO GPIO driver

Quoted 4 lines · Hans de Goede

Thank you I'll go and preparare a standalone v3 (since the other 2 patches have no reviews yet).

Please, don't do this. This is a great way to confuse everyone involved. :(

Quoted 7 lines

As mentioned in the cover-letter it is probably easiest if Greg merges the entire series through his usb tree once everything has been reviewed.

Once I've send it, can you please ack v3 for merging through Greg's USB tree?

I would prefer to ack a patch that's part of a proper series, this split makes no sense.

Bart

author maintainer
#6 lore raw

Re: [PATCH v2 2/3] gpio: Add Intel USBIO GPIO driver

Hi,

Quoted 7 lines · Bartosz Golaszewski
Quoted 4 lines · Hans de Goede

Thank you I'll go and preparare a standalone v3 (since the other 2 patches have no reviews yet).

Please, don't do this. This is a great way to confuse everyone involved. :(

Usually I'm not a fan of this myself either, but in this case it seemed appropriate (see below). Regardless it is too late now since I already send v3.

Quoted 10 lines
Quoted 7 lines

As mentioned in the cover-letter it is probably easiest if Greg merges the entire series through his usb tree once everything has been reviewed.

Once I've send it, can you please ack v3 for merging through Greg's USB tree?

I would prefer to ack a patch that's part of a proper series, this split makes no sense.

Since v3 should be the final version, my plan is to put v3 into the v3 series unmodified, so both v3 postings will be identiacal), preferably with your ack already added.

I chose to send out v3 separately, so that you can already check it an ack it now.

Also in my experience reviewing new versions is easier when things are still fresh in ones mind and I dunno when the other bits will get reviewed.

Regards,

Hans

author maintainer
#7 lore raw

PATCH v2 3/3 i2c: Add Intel USBIO I2C driver

In reply to Hans de Goede

From: Israel Cepeda <[email protected]>

Add a a driver for the I2C auxbus child device of the Intel USBIO USB IO-expander used by the MIPI cameras on various new (Meteor Lake and later) Intel laptops.

---
Changes in v2:
- Use new quirks mechanism to treat various revisions differently
- Use __le16, __le32 type + cpu_to_le16() and friends for on wire words
- Some small style fixes from Sakari's review

---
 MAINTAINERS                    |   1 +
 drivers/i2c/busses/Kconfig     |  11 ++
 drivers/i2c/busses/Makefile    |   1 +
 drivers/i2c/busses/i2c-usbio.c | 325 +++++++++++++++++++++++++++++++++
 4 files changed, 338 insertions(+)
 create mode 100644 drivers/i2c/busses/i2c-usbio.c
MAINTAINERS +1 -0
index 53694bd91861..0f5de266d6df 100644
@@ -12700,6 +12700,7 @@ M:	Hans de Goede <[email protected]>
 R:	Sakari Ailus <[email protected]>
 S:	Maintained
 F:	drivers/gpio/gpio-usbio.c
+F:	drivers/i2c/busses/i2c-usbio.c
 F:	drivers/usb/misc/usbio.c
 F:	include/linux/usb/usbio.h
 
drivers/i2c/busses/Kconfig +11 -0
index 070d014fdc5d..06b1b702fd7a 100644
@@ -1357,6 +1357,17 @@ config I2C_LJCA
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-ljca.
 
+config I2C_USBIO
+	tristate "Intel USBIO I2C Adapter support"
+	depends on USB_USBIO
+	default USB_USBIO
+	help
+	  Select this option to enable I2C driver for the INTEL
+	  USBIO driver stack.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c_usbio.
+
 config I2C_CP2615
 	tristate "Silicon Labs CP2615 USB sound card and I2C adapter"
 	depends on USB
drivers/i2c/busses/Makefile +1 -0
index 04db855fdfd6..401a79c9767e 100644
@@ -135,6 +135,7 @@ obj-$(CONFIG_I2C_GXP)		+= i2c-gxp.o
 obj-$(CONFIG_I2C_DIOLAN_U2C)	+= i2c-diolan-u2c.o
 obj-$(CONFIG_I2C_DLN2)		+= i2c-dln2.o
 obj-$(CONFIG_I2C_LJCA)		+= i2c-ljca.o
+obj-$(CONFIG_I2C_USBIO)		+= i2c-usbio.o
 obj-$(CONFIG_I2C_CP2615) += i2c-cp2615.o
 obj-$(CONFIG_I2C_PARPORT)	+= i2c-parport.o
 obj-$(CONFIG_I2C_PCI1XXXX)	+= i2c-mchp-pci1xxxx.o
drivers/i2c/busses/i2c-usbio.c new file +325 -0

325 lines not on this page · raw message

Signature · 1 line
2.51.0
#8 lore raw
In reply to Hans de Goede
Quoted 24 lines · Hans de Goede

Hi All,

Here is v2 of the patch series to add support for the Intel USBIO USB IO-expander used by the MIPI cameras on various new (Meteor Lake and later) Intel laptops.

Changes in v2:
- Split usbio-bridge mutex into ctrl_mutex and bulk_mutex
- Drop SPI support since this is not used on devices in the field
- Rework disconnect handling to be more robust
- Several different revisions need special casing add a quirks mechanism for this
- Stop using stdint.h (uintX_t) types
- Use __le16, __le32 type + cpu_to_le16() and friends for on wire words
- Properly check auxiliary_device_add() return value
- Add a mutex to the GPIO driver to protect usbio_gpio_update_config() calls, which read-modify-write banks[x].config, racing with each other
- Adjust usbio_gpio_get() to have an int return value and propagate the usbio_control_msg() return value
- Various (small) style fixes from Sakari's review of all 3 patches

The first patch adds an USB bridge driver which registers auxbus children for the GPIO and I2C functions of the USBIO chip.

Quoted 7 lines

The second and third patch add a GPIO resp. an I2C driver for the auxbus children using the IO functions exported by the USB bridge driver.

The second and third patch depend on the IO functions exported by the first patch. So to merge this we will need either an immutable tag on the USB tree, or all 3 patches can be merged through the USB tree with acks from the GPIO and I2C subsystem maintainers.

Either is fine with me, patch 1 looks good enough for me to queue it up now. Let me know what you want me to do.

thanks,

greg k-h

author maintainer
#9 lore raw

Hi Greg,

Quoted 28 lines · Greg Kroah-Hartman
Quoted 27 lines · Hans de Goede

Hi All,

Here is v2 of the patch series to add support for the Intel USBIO USB IO-expander used by the MIPI cameras on various new (Meteor Lake and later) Intel laptops.

Changes in v2:
- Split usbio-bridge mutex into ctrl_mutex and bulk_mutex
- Drop SPI support since this is not used on devices in the field
- Rework disconnect handling to be more robust
- Several different revisions need special casing add a quirks mechanism for this
- Stop using stdint.h (uintX_t) types
- Use __le16, __le32 type + cpu_to_le16() and friends for on wire words
- Properly check auxiliary_device_add() return value
- Add a mutex to the GPIO driver to protect usbio_gpio_update_config() calls, which read-modify-write banks[x].config, racing with each other
- Adjust usbio_gpio_get() to have an int return value and propagate the usbio_control_msg() return value
- Various (small) style fixes from Sakari's review of all 3 patches

The first patch adds an USB bridge driver which registers auxbus children for the GPIO and I2C functions of the USBIO chip.

The second and third patch add a GPIO resp. an I2C driver for the auxbus children using the IO functions exported by the USB bridge driver.

Quoted 7 lines
Quoted 4 lines

The second and third patch depend on the IO functions exported by the first patch. So to merge this we will need either an immutable tag on the USB tree, or all 3 patches can be merged through the USB tree with acks from the GPIO and I2C subsystem maintainers.

Either is fine with me, patch 1 looks good enough for me to queue it up now.

That is good news.

Quoted 1 line

Let me know what you want me to do.

I've done a v3 of just the GPIO patch since Bart had some review-comments there. Bart still had 2 more small remarks on the v3 GPIO patch. So I'm about to send out a v4 series (with just changes to the GPIO driver compared to this v2).

I hope Bart will be happy with v4, so then Bart can let you know if he prefers an immutable tag, or wants you to merge the GPIO driver into usb-next.

Once it is clear how to proceed with the GPIO driver I suggest that we get both of them merged and then wait for feedback on the I2C driver.

Regards,

Hans

#10 lore raw
Quoted 44 lines · Hans de Goede

Hi Greg,

Quoted 28 lines · Greg Kroah-Hartman
Quoted 27 lines · Hans de Goede

Hi All,

Here is v2 of the patch series to add support for the Intel USBIO USB IO-expander used by the MIPI cameras on various new (Meteor Lake and later) Intel laptops.

Changes in v2:
- Split usbio-bridge mutex into ctrl_mutex and bulk_mutex
- Drop SPI support since this is not used on devices in the field
- Rework disconnect handling to be more robust
- Several different revisions need special casing add a quirks mechanism for this
- Stop using stdint.h (uintX_t) types
- Use __le16, __le32 type + cpu_to_le16() and friends for on wire words
- Properly check auxiliary_device_add() return value
- Add a mutex to the GPIO driver to protect usbio_gpio_update_config() calls, which read-modify-write banks[x].config, racing with each other
- Adjust usbio_gpio_get() to have an int return value and propagate the usbio_control_msg() return value
- Various (small) style fixes from Sakari's review of all 3 patches

The first patch adds an USB bridge driver which registers auxbus children for the GPIO and I2C functions of the USBIO chip.

The second and third patch add a GPIO resp. an I2C driver for the auxbus children using the IO functions exported by the USB bridge driver.

Quoted 7 lines
Quoted 4 lines

The second and third patch depend on the IO functions exported by the first patch. So to merge this we will need either an immutable tag on the USB tree, or all 3 patches can be merged through the USB tree with acks from the GPIO and I2C subsystem maintainers.

Either is fine with me, patch 1 looks good enough for me to queue it up now.

That is good news.

Quoted 1 line

Let me know what you want me to do.

Quoted 9 lines

I've done a v3 of just the GPIO patch since Bart had some review-comments there. Bart still had 2 more small remarks on the v3 GPIO patch. So I'm about to send out a v4 series (with just changes to the GPIO driver compared to this v2).

I hope Bart will be happy with v4, so then Bart can let you know if he prefers an immutable tag, or wants you to merge the GPIO driver into usb-next.

Yes, an immutable branch with patch 1 would be the best approach.

Bart

Quoted 8 lines

Once it is clear how to proceed with the GPIO driver I suggest that we get both of them merged and then wait for feedback on the I2C driver.

Regards,

Hans