Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpio: Add Intel USBIO GPIO driver

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.

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Co-developed-by: Hans de Goede <hansg@kernel.org>
Signed-off-by: Hans de Goede <hansg@kernel.org>
Signed-off-by: Israel Cepeda <israel.a.cepeda.lopez@intel.com>
Link: https://lore.kernel.org/r/20250911181343.77398-3-hansg@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Israel Cepeda and committed by
Greg Kroah-Hartman
c122451c 121a0f83

+260
+1
MAINTAINERS
··· 12693 12693 M: Hans de Goede <hansg@kernel.org> 12694 12694 R: Sakari Ailus <sakari.ailus@linux.intel.com> 12695 12695 S: Maintained 12696 + F: drivers/gpio/gpio-usbio.c 12696 12697 F: drivers/usb/misc/usbio.c 12697 12698 F: include/linux/usb/usbio.h 12698 12699
+11
drivers/gpio/Kconfig
··· 1923 1923 GPIO driver for FTDI's MPSSE interface. These can do input and 1924 1924 output. Each MPSSE provides 16 IO pins. 1925 1925 1926 + config GPIO_USBIO 1927 + tristate "Intel USBIO GPIO support" 1928 + depends on USB_USBIO 1929 + default USB_USBIO 1930 + help 1931 + Select this option to enable GPIO driver for the INTEL 1932 + USBIO driver stack. 1933 + 1934 + This driver can also be built as a module. If so, the module 1935 + will be called gpio_usbio. 1936 + 1926 1937 endmenu 1927 1938 1928 1939 menu "Virtual GPIO drivers"
+1
drivers/gpio/Makefile
··· 192 192 obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o 193 193 obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o 194 194 obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o 195 + obj-$(CONFIG_GPIO_USBIO) += gpio-usbio.o 195 196 obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o 196 197 obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o 197 198 obj-$(CONFIG_GPIO_VIRTUSER) += gpio-virtuser.o
+247
drivers/gpio/gpio-usbio.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (c) 2025 Intel Corporation. 4 + * Copyright (c) 2025 Red Hat, Inc. 5 + */ 6 + 7 + #include <linux/acpi.h> 8 + #include <linux/auxiliary_bus.h> 9 + #include <linux/cleanup.h> 10 + #include <linux/device.h> 11 + #include <linux/gpio/driver.h> 12 + #include <linux/mutex.h> 13 + #include <linux/types.h> 14 + #include <linux/usb/usbio.h> 15 + 16 + struct usbio_gpio_bank { 17 + u8 config[USBIO_GPIOSPERBANK]; 18 + u32 bitmap; 19 + }; 20 + 21 + struct usbio_gpio { 22 + struct mutex config_mutex; /* Protects banks[x].config */ 23 + struct usbio_gpio_bank banks[USBIO_MAX_GPIOBANKS]; 24 + struct gpio_chip gc; 25 + struct auxiliary_device *adev; 26 + }; 27 + 28 + static const struct acpi_device_id usbio_gpio_acpi_hids[] = { 29 + { "INTC1007" }, /* MTL */ 30 + { "INTC10B2" }, /* ARL */ 31 + { "INTC10B5" }, /* LNL */ 32 + { "INTC10E2" }, /* PTL */ 33 + { } 34 + }; 35 + 36 + static void usbio_gpio_get_bank_and_pin(struct gpio_chip *gc, unsigned int offset, 37 + struct usbio_gpio_bank **bank_ret, 38 + unsigned int *pin_ret) 39 + { 40 + struct usbio_gpio *gpio = gpiochip_get_data(gc); 41 + struct device *dev = &gpio->adev->dev; 42 + struct usbio_gpio_bank *bank; 43 + unsigned int pin; 44 + 45 + bank = &gpio->banks[offset / USBIO_GPIOSPERBANK]; 46 + pin = offset % USBIO_GPIOSPERBANK; 47 + if (~bank->bitmap & BIT(pin)) { 48 + /* The FW bitmap sometimes is invalid, warn and continue */ 49 + dev_warn_once(dev, FW_BUG "GPIO %u is not in FW pins bitmap\n", offset); 50 + } 51 + 52 + *bank_ret = bank; 53 + *pin_ret = pin; 54 + } 55 + 56 + static int usbio_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) 57 + { 58 + struct usbio_gpio_bank *bank; 59 + unsigned int pin; 60 + u8 cfg; 61 + 62 + usbio_gpio_get_bank_and_pin(gc, offset, &bank, &pin); 63 + 64 + cfg = bank->config[pin] & USBIO_GPIO_PINMOD_MASK; 65 + 66 + return (cfg == USBIO_GPIO_PINMOD_OUTPUT) ? 67 + GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN; 68 + } 69 + 70 + static int usbio_gpio_get(struct gpio_chip *gc, unsigned int offset) 71 + { 72 + struct usbio_gpio *gpio = gpiochip_get_data(gc); 73 + struct usbio_gpio_bank *bank; 74 + struct usbio_gpio_rw gbuf; 75 + unsigned int pin; 76 + int ret; 77 + 78 + usbio_gpio_get_bank_and_pin(gc, offset, &bank, &pin); 79 + 80 + gbuf.bankid = offset / USBIO_GPIOSPERBANK; 81 + gbuf.pincount = 1; 82 + gbuf.pin = pin; 83 + 84 + ret = usbio_control_msg(gpio->adev, USBIO_PKTTYPE_GPIO, USBIO_GPIOCMD_READ, 85 + &gbuf, sizeof(gbuf) - sizeof(gbuf.value), 86 + &gbuf, sizeof(gbuf)); 87 + if (ret != sizeof(gbuf)) 88 + return (ret < 0) ? ret : -EPROTO; 89 + 90 + return (le32_to_cpu(gbuf.value) >> pin) & 1; 91 + } 92 + 93 + static int usbio_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) 94 + { 95 + struct usbio_gpio *gpio = gpiochip_get_data(gc); 96 + struct usbio_gpio_bank *bank; 97 + struct usbio_gpio_rw gbuf; 98 + unsigned int pin; 99 + 100 + usbio_gpio_get_bank_and_pin(gc, offset, &bank, &pin); 101 + 102 + gbuf.bankid = offset / USBIO_GPIOSPERBANK; 103 + gbuf.pincount = 1; 104 + gbuf.pin = pin; 105 + gbuf.value = cpu_to_le32(value << pin); 106 + 107 + return usbio_control_msg(gpio->adev, USBIO_PKTTYPE_GPIO, USBIO_GPIOCMD_WRITE, 108 + &gbuf, sizeof(gbuf), NULL, 0); 109 + } 110 + 111 + static int usbio_gpio_update_config(struct gpio_chip *gc, unsigned int offset, 112 + u8 mask, u8 value) 113 + { 114 + struct usbio_gpio *gpio = gpiochip_get_data(gc); 115 + struct usbio_gpio_bank *bank; 116 + struct usbio_gpio_init gbuf; 117 + unsigned int pin; 118 + 119 + usbio_gpio_get_bank_and_pin(gc, offset, &bank, &pin); 120 + 121 + guard(mutex)(&gpio->config_mutex); 122 + 123 + bank->config[pin] &= ~mask; 124 + bank->config[pin] |= value; 125 + 126 + gbuf.bankid = offset / USBIO_GPIOSPERBANK; 127 + gbuf.config = bank->config[pin]; 128 + gbuf.pincount = 1; 129 + gbuf.pin = pin; 130 + 131 + return usbio_control_msg(gpio->adev, USBIO_PKTTYPE_GPIO, USBIO_GPIOCMD_INIT, 132 + &gbuf, sizeof(gbuf), NULL, 0); 133 + } 134 + 135 + static int usbio_gpio_direction_input(struct gpio_chip *gc, unsigned int offset) 136 + { 137 + return usbio_gpio_update_config(gc, offset, USBIO_GPIO_PINMOD_MASK, 138 + USBIO_GPIO_SET_PINMOD(USBIO_GPIO_PINMOD_INPUT)); 139 + } 140 + 141 + static int usbio_gpio_direction_output(struct gpio_chip *gc, 142 + unsigned int offset, int value) 143 + { 144 + int ret; 145 + 146 + ret = usbio_gpio_update_config(gc, offset, USBIO_GPIO_PINMOD_MASK, 147 + USBIO_GPIO_SET_PINMOD(USBIO_GPIO_PINMOD_OUTPUT)); 148 + if (ret) 149 + return ret; 150 + 151 + return usbio_gpio_set(gc, offset, value); 152 + } 153 + 154 + static int usbio_gpio_set_config(struct gpio_chip *gc, unsigned int offset, 155 + unsigned long config) 156 + { 157 + u8 value; 158 + 159 + switch (pinconf_to_config_param(config)) { 160 + case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: 161 + value = USBIO_GPIO_SET_PINCFG(USBIO_GPIO_PINCFG_DEFAULT); 162 + break; 163 + case PIN_CONFIG_BIAS_PULL_UP: 164 + value = USBIO_GPIO_SET_PINCFG(USBIO_GPIO_PINCFG_PULLUP); 165 + break; 166 + case PIN_CONFIG_BIAS_PULL_DOWN: 167 + value = USBIO_GPIO_SET_PINCFG(USBIO_GPIO_PINCFG_PULLDOWN); 168 + break; 169 + case PIN_CONFIG_DRIVE_PUSH_PULL: 170 + value = USBIO_GPIO_SET_PINCFG(USBIO_GPIO_PINCFG_PUSHPULL); 171 + break; 172 + default: 173 + return -ENOTSUPP; 174 + } 175 + 176 + return usbio_gpio_update_config(gc, offset, USBIO_GPIO_PINCFG_MASK, value); 177 + } 178 + 179 + static int usbio_gpio_probe(struct auxiliary_device *adev, 180 + const struct auxiliary_device_id *adev_id) 181 + { 182 + struct usbio_gpio_bank_desc *bank_desc; 183 + struct device *dev = &adev->dev; 184 + struct usbio_gpio *gpio; 185 + int bank, ret; 186 + 187 + bank_desc = dev_get_platdata(dev); 188 + if (!bank_desc) 189 + return -EINVAL; 190 + 191 + gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL); 192 + if (!gpio) 193 + return -ENOMEM; 194 + 195 + ret = devm_mutex_init(dev, &gpio->config_mutex); 196 + if (ret) 197 + return ret; 198 + 199 + gpio->adev = adev; 200 + 201 + usbio_acpi_bind(gpio->adev, usbio_gpio_acpi_hids); 202 + 203 + for (bank = 0; bank < USBIO_MAX_GPIOBANKS && bank_desc[bank].bmap; bank++) 204 + gpio->banks[bank].bitmap = le32_to_cpu(bank_desc[bank].bmap); 205 + 206 + gpio->gc.label = ACPI_COMPANION(dev) ? 207 + acpi_dev_name(ACPI_COMPANION(dev)) : dev_name(dev); 208 + gpio->gc.parent = dev; 209 + gpio->gc.owner = THIS_MODULE; 210 + gpio->gc.get_direction = usbio_gpio_get_direction; 211 + gpio->gc.direction_input = usbio_gpio_direction_input; 212 + gpio->gc.direction_output = usbio_gpio_direction_output; 213 + gpio->gc.get = usbio_gpio_get; 214 + gpio->gc.set = usbio_gpio_set; 215 + gpio->gc.set_config = usbio_gpio_set_config; 216 + gpio->gc.base = -1; 217 + gpio->gc.ngpio = bank * USBIO_GPIOSPERBANK; 218 + gpio->gc.can_sleep = true; 219 + 220 + ret = devm_gpiochip_add_data(dev, &gpio->gc, gpio); 221 + if (ret) 222 + return ret; 223 + 224 + if (has_acpi_companion(dev)) 225 + acpi_dev_clear_dependencies(ACPI_COMPANION(dev)); 226 + 227 + return 0; 228 + } 229 + 230 + static const struct auxiliary_device_id usbio_gpio_id_table[] = { 231 + { "usbio.usbio-gpio" }, 232 + { } 233 + }; 234 + MODULE_DEVICE_TABLE(auxiliary, usbio_gpio_id_table); 235 + 236 + static struct auxiliary_driver usbio_gpio_driver = { 237 + .name = USBIO_GPIO_CLIENT, 238 + .probe = usbio_gpio_probe, 239 + .id_table = usbio_gpio_id_table 240 + }; 241 + module_auxiliary_driver(usbio_gpio_driver); 242 + 243 + MODULE_DESCRIPTION("Intel USBIO GPIO driver"); 244 + MODULE_AUTHOR("Israel Cepeda <israel.a.cepeda.lopez@intel.com>"); 245 + MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>"); 246 + MODULE_LICENSE("GPL"); 247 + MODULE_IMPORT_NS("USBIO");