File Index
Files and directories
Sign in
FILE

gpio-usbio.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpio/gpio-usbio.c 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
 16struct usbio_gpio_bank {
 17	u8 config[USBIO_GPIOSPERBANK];
 18	u32 bitmap;
 19};
 20
 21struct 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
 28static const struct acpi_device_id usbio_gpio_acpi_hids[] = {
 29	{ "INTC1007" }, /* MTL */
 30	{ "INTC10B2" }, /* ARL */
 31	{ "INTC10B5" }, /* LNL */
 32	{ "INTC10D1" }, /* MTL-CVF */
 33	{ "INTC10E2" }, /* PTL */
 34	{ }
 35};
 36
 37static void usbio_gpio_get_bank_and_pin(struct gpio_chip *gc, unsigned int offset,
 38					struct usbio_gpio_bank **bank_ret,
 39					unsigned int *pin_ret)
 40{
 41	struct usbio_gpio *gpio = gpiochip_get_data(gc);
 42	struct device *dev = &gpio->adev->dev;
 43	struct usbio_gpio_bank *bank;
 44	unsigned int pin;
 45
 46	bank = &gpio->banks[offset / USBIO_GPIOSPERBANK];
 47	pin = offset % USBIO_GPIOSPERBANK;
 48	if (~bank->bitmap & BIT(pin)) {
 49		/* The FW bitmap sometimes is invalid, warn and continue */
 50		dev_warn_once(dev, FW_BUG "GPIO %u is not in FW pins bitmap\n", offset);
 51	}
 52
 53	*bank_ret = bank;
 54	*pin_ret = pin;
 55}
 56
 57static int usbio_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
 58{
 59	struct usbio_gpio_bank *bank;
 60	unsigned int pin;
 61	u8 cfg;
 62
 63	usbio_gpio_get_bank_and_pin(gc, offset, &bank, &pin);
 64
 65	cfg = bank->config[pin] & USBIO_GPIO_PINMOD_MASK;
 66
 67	return (cfg == USBIO_GPIO_PINMOD_OUTPUT) ?
 68		GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
 69}
 70
 71static int usbio_gpio_get(struct gpio_chip *gc, unsigned int offset)
 72{
 73	struct usbio_gpio *gpio = gpiochip_get_data(gc);
 74	struct usbio_gpio_bank *bank;
 75	struct usbio_gpio_rw gbuf;
 76	unsigned int pin;
 77	int ret;
 78
 79	usbio_gpio_get_bank_and_pin(gc, offset, &bank, &pin);
 80
 81	gbuf.bankid = offset / USBIO_GPIOSPERBANK;
 82	gbuf.pincount  = 1;
 83	gbuf.pin = pin;
 84
 85	ret = usbio_control_msg(gpio->adev, USBIO_PKTTYPE_GPIO, USBIO_GPIOCMD_READ,
 86				&gbuf, sizeof(gbuf) - sizeof(gbuf.value),
 87				&gbuf, sizeof(gbuf));
 88	if (ret != sizeof(gbuf))
 89		return (ret < 0) ? ret : -EPROTO;
 90
 91	return (le32_to_cpu(gbuf.value) >> pin) & 1;
 92}
 93
 94static int usbio_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
 95{
 96	struct usbio_gpio *gpio = gpiochip_get_data(gc);
 97	struct usbio_gpio_bank *bank;
 98	struct usbio_gpio_rw gbuf;
 99	unsigned int pin;
100
101	usbio_gpio_get_bank_and_pin(gc, offset, &bank, &pin);
102
103	gbuf.bankid = offset / USBIO_GPIOSPERBANK;
104	gbuf.pincount  = 1;
105	gbuf.pin = pin;
106	gbuf.value = cpu_to_le32(value << pin);
107
108	return usbio_control_msg(gpio->adev, USBIO_PKTTYPE_GPIO, USBIO_GPIOCMD_WRITE,
109				 &gbuf, sizeof(gbuf), NULL, 0);
110}
111
112static int usbio_gpio_update_config(struct gpio_chip *gc, unsigned int offset,
113				    u8 mask, u8 value)
114{
115	struct usbio_gpio *gpio = gpiochip_get_data(gc);
116	struct usbio_gpio_bank *bank;
117	struct usbio_gpio_init gbuf;
118	unsigned int pin;
119
120	usbio_gpio_get_bank_and_pin(gc, offset, &bank, &pin);
121
122	guard(mutex)(&gpio->config_mutex);
123
124	bank->config[pin] &= ~mask;
125	bank->config[pin] |= value;
126
127	gbuf.bankid = offset / USBIO_GPIOSPERBANK;
128	gbuf.config = bank->config[pin];
129	gbuf.pincount  = 1;
130	gbuf.pin = pin;
131
132	return usbio_control_msg(gpio->adev, USBIO_PKTTYPE_GPIO, USBIO_GPIOCMD_INIT,
133				 &gbuf, sizeof(gbuf), NULL, 0);
134}
135
136static int usbio_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
137{
138	return usbio_gpio_update_config(gc, offset, USBIO_GPIO_PINMOD_MASK,
139					USBIO_GPIO_SET_PINMOD(USBIO_GPIO_PINMOD_INPUT));
140}
141
142static int usbio_gpio_direction_output(struct gpio_chip *gc,
143		unsigned int offset, int value)
144{
145	int ret;
146
147	ret = usbio_gpio_update_config(gc, offset, USBIO_GPIO_PINMOD_MASK,
148				       USBIO_GPIO_SET_PINMOD(USBIO_GPIO_PINMOD_OUTPUT));
149	if (ret)
150		return ret;
151
152	return usbio_gpio_set(gc, offset, value);
153}
154
155static int usbio_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
156		unsigned long config)
157{
158	u8 value;
159
160	switch (pinconf_to_config_param(config)) {
161	case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
162		value = USBIO_GPIO_SET_PINCFG(USBIO_GPIO_PINCFG_DEFAULT);
163		break;
164	case PIN_CONFIG_BIAS_PULL_UP:
165		value = USBIO_GPIO_SET_PINCFG(USBIO_GPIO_PINCFG_PULLUP);
166		break;
167	case PIN_CONFIG_BIAS_PULL_DOWN:
168		value = USBIO_GPIO_SET_PINCFG(USBIO_GPIO_PINCFG_PULLDOWN);
169		break;
170	case PIN_CONFIG_DRIVE_PUSH_PULL:
171		value = USBIO_GPIO_SET_PINCFG(USBIO_GPIO_PINCFG_PUSHPULL);
172		break;
173	default:
174		return -ENOTSUPP;
175	}
176
177	return usbio_gpio_update_config(gc, offset, USBIO_GPIO_PINCFG_MASK, value);
178}
179
180static int usbio_gpio_probe(struct auxiliary_device *adev,
181		const struct auxiliary_device_id *adev_id)
182{
183	struct usbio_gpio_bank_desc *bank_desc;
184	struct device *dev = &adev->dev;
185	struct usbio_gpio *gpio;
186	int bank, ret;
187
188	bank_desc = dev_get_platdata(dev);
189	if (!bank_desc)
190		return -EINVAL;
191
192	gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL);
193	if (!gpio)
194		return -ENOMEM;
195
196	ret = devm_mutex_init(dev, &gpio->config_mutex);
197	if (ret)
198		return ret;
199
200	gpio->adev = adev;
201
202	usbio_acpi_bind(gpio->adev, usbio_gpio_acpi_hids);
203
204	for (bank = 0; bank < USBIO_MAX_GPIOBANKS && bank_desc[bank].bmap; bank++)
205		gpio->banks[bank].bitmap = le32_to_cpu(bank_desc[bank].bmap);
206
207	gpio->gc.label = ACPI_COMPANION(dev) ?
208					acpi_dev_name(ACPI_COMPANION(dev)) : dev_name(dev);
209	gpio->gc.parent = dev;
210	gpio->gc.owner = THIS_MODULE;
211	gpio->gc.get_direction = usbio_gpio_get_direction;
212	gpio->gc.direction_input = usbio_gpio_direction_input;
213	gpio->gc.direction_output = usbio_gpio_direction_output;
214	gpio->gc.get = usbio_gpio_get;
215	gpio->gc.set = usbio_gpio_set;
216	gpio->gc.set_config = usbio_gpio_set_config;
217	gpio->gc.base = -1;
218	gpio->gc.ngpio = bank * USBIO_GPIOSPERBANK;
219	gpio->gc.can_sleep = true;
220
221	ret = devm_gpiochip_add_data(dev, &gpio->gc, gpio);
222	if (ret)
223		return ret;
224
225	if (has_acpi_companion(dev))
226		acpi_dev_clear_dependencies(ACPI_COMPANION(dev));
227
228	return 0;
229}
230
231static const struct auxiliary_device_id usbio_gpio_id_table[] = {
232	{ "usbio.usbio-gpio" },
233	{ }
234};
235MODULE_DEVICE_TABLE(auxiliary, usbio_gpio_id_table);
236
237static struct auxiliary_driver usbio_gpio_driver = {
238	.name = USBIO_GPIO_CLIENT,
239	.probe = usbio_gpio_probe,
240	.id_table = usbio_gpio_id_table
241};
242module_auxiliary_driver(usbio_gpio_driver);
243
244MODULE_DESCRIPTION("Intel USBIO GPIO driver");
245MODULE_AUTHOR("Israel Cepeda <israel.a.cepeda.lopez@intel.com>");
246MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>");
247MODULE_LICENSE("GPL");
248MODULE_IMPORT_NS("USBIO");
~/ Read-only file preview.