···11+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause22+%YAML 1.233+---44+$id: http://devicetree.org/schemas/gpio/pin-control-gpio.yaml#55+$schema: http://devicetree.org/meta-schemas/core.yaml#66+77+title: Pin control based generic GPIO controller88+99+description:1010+ The pin control-based GPIO will facilitate a pin controller's ability1111+ to drive electric lines high/low and other generic properties of a1212+ pin controller to perform general-purpose one-bit binary I/O.1313+1414+maintainers:1515+ - Dan Carpenter <dan.carpenter@linaro.org>1616+1717+properties:1818+ compatible:1919+ const: scmi-pinctrl-gpio2020+2121+ gpio-controller: true2222+2323+ "#gpio-cells":2424+ const: 22525+2626+ gpio-line-names: true2727+2828+ gpio-ranges: true2929+3030+ ngpios: true3131+3232+patternProperties:3333+ "^.+-hog(-[0-9]+)?$":3434+ type: object3535+3636+ required:3737+ - gpio-hog3838+3939+required:4040+ - compatible4141+ - gpio-controller4242+ - "#gpio-cells"4343+ - gpio-ranges4444+ - ngpios4545+4646+additionalProperties: false4747+4848+examples:4949+ - |5050+ gpio {5151+ compatible = "scmi-pinctrl-gpio";5252+ gpio-controller;5353+ #gpio-cells = <2>;5454+ ngpios = <4>;5555+ gpio-line-names = "gpio_5_17", "gpio_5_20", "gpio_5_22", "gpio_2_1";5656+ gpio-ranges = <&scmi_pinctrl 0 30 4>;5757+ pinctrl-names = "default";5858+ pinctrl-0 = <&keys_pins>;5959+ };
+2
drivers/firmware/arm_scmi/pinctrl.c
···578578 tx->flags = cpu_to_le32(type);579579580580 ret = ph->xops->do_xfer(ph, t);581581+ if (ret == -EOPNOTSUPP)582582+ ret = 0;581583 ph->xops->xfer_put(ph, t);582584583585 return ret;
+13
drivers/gpio/Kconfig
···246246 help247247 Say yes here to enable GPIO support for Broadcom STB (BCM7XXX) SoCs.248248249249+config GPIO_BY_PINCTRL250250+ tristate "GPIO support based on a pure pin control backend"251251+ depends on GPIOLIB252252+ help253253+ Support for generic GPIO handling based on top of pin control.254254+ Traditionally, firmware creates a GPIO interface or a pin255255+ controller interface and we have a driver to support it. But256256+ in SCMI, the pin control interface is generic and we can257257+ create a simple GPIO device based on the pin control interface258258+ without doing anything custom.259259+260260+ This driver used to do GPIO over the ARM SCMI protocol.261261+249262config GPIO_CADENCE250263 tristate "Cadence GPIO support"251264 depends on OF_GPIO
···11+// SPDX-License-Identifier: GPL-2.022+//33+// Copyright (C) 2026 Linaro Inc.44+// Author: AKASHI takahiro <takahiro.akashi@linaro.org>55+66+#include <linux/errno.h>77+#include <linux/gpio/driver.h>88+#include <linux/mod_devicetable.h>99+#include <linux/module.h>1010+#include <linux/pinctrl/consumer.h>1111+#include <linux/platform_device.h>1212+#include <linux/types.h>1313+1414+#include "gpiolib.h"1515+1616+static int pin_control_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)1717+{1818+ unsigned long config;1919+ int ret;2020+2121+ config = PIN_CONFIG_OUTPUT_ENABLE;2222+ ret = pinctrl_gpio_get_config(gc, offset, &config);2323+ if (ret)2424+ return ret;2525+ if (config)2626+ return GPIO_LINE_DIRECTION_OUT;2727+2828+ return GPIO_LINE_DIRECTION_IN;2929+}3030+3131+static int pin_control_gpio_direction_output(struct gpio_chip *chip,3232+ unsigned int offset, int val)3333+{3434+ return pinctrl_gpio_direction_output(chip, offset);3535+}3636+3737+static int pin_control_gpio_get(struct gpio_chip *chip, unsigned int offset)3838+{3939+ unsigned long config;4040+ int ret;4141+4242+ config = PIN_CONFIG_LEVEL;4343+ ret = pinctrl_gpio_get_config(chip, offset, &config);4444+ if (ret)4545+ return ret;4646+4747+ return !!config;4848+}4949+5050+static int pin_control_gpio_set(struct gpio_chip *chip, unsigned int offset,5151+ int val)5252+{5353+ unsigned long config;5454+5555+ config = pinconf_to_config_packed(PIN_CONFIG_LEVEL, val);5656+ return pinctrl_gpio_set_config(chip, offset, config);5757+}5858+5959+static int pin_control_gpio_probe(struct platform_device *pdev)6060+{6161+ struct device *dev = &pdev->dev;6262+ struct gpio_chip *chip;6363+6464+ chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);6565+ if (!chip)6666+ return -ENOMEM;6767+6868+ chip->label = dev_name(dev);6969+ chip->parent = dev;7070+ chip->base = -1;7171+7272+ chip->request = gpiochip_generic_request;7373+ chip->free = gpiochip_generic_free;7474+ chip->get_direction = pin_control_gpio_get_direction;7575+ chip->direction_input = pinctrl_gpio_direction_input;7676+ chip->direction_output = pin_control_gpio_direction_output;7777+ chip->get = pin_control_gpio_get;7878+ chip->set = pin_control_gpio_set;7979+ chip->set_config = gpiochip_generic_config;8080+8181+ return devm_gpiochip_add_data(dev, chip, NULL);8282+}8383+8484+static const struct of_device_id pin_control_gpio_match[] = {8585+ { .compatible = "scmi-pinctrl-gpio" },8686+ { /* sentinel */ }8787+};8888+MODULE_DEVICE_TABLE(of, pin_control_gpio_match);8989+9090+static struct platform_driver pin_control_gpio_driver = {9191+ .probe = pin_control_gpio_probe,9292+ .driver = {9393+ .name = "pin-control-gpio",9494+ .of_match_table = pin_control_gpio_match,9595+ },9696+};9797+module_platform_driver(pin_control_gpio_driver);9898+9999+MODULE_AUTHOR("AKASHI Takahiro <takahiro.akashi@linaro.org>");100100+MODULE_DESCRIPTION("Pinctrl based GPIO driver");101101+MODULE_LICENSE("GPL");
+31
drivers/pinctrl/core.c
···3030#include <linux/pinctrl/consumer.h>3131#include <linux/pinctrl/devinfo.h>3232#include <linux/pinctrl/machine.h>3333+#include <linux/pinctrl/pinconf.h>3334#include <linux/pinctrl/pinctrl.h>34353536#include "core.h"···938937 return ret;939938}940939EXPORT_SYMBOL_GPL(pinctrl_gpio_set_config);940940+941941+/**942942+ * pinctrl_gpio_get_config() - Get the config for a given GPIO pin943943+ * @gc: GPIO chip structure from the GPIO subsystem944944+ * @offset: hardware offset of the GPIO relative to the controller945945+ * @config: the configuration to query. On success it holds the result946946+ * Return: 0 on success, negative errno otherwise947947+ */948948+int pinctrl_gpio_get_config(struct gpio_chip *gc, unsigned int offset, unsigned long *config)949949+{950950+ struct pinctrl_gpio_range *range;951951+ struct pinctrl_dev *pctldev;952952+ int ret, pin;953953+954954+ ret = pinctrl_get_device_gpio_range(gc, offset, &pctldev, &range);955955+ if (ret)956956+ return ret;957957+958958+ mutex_lock(&pctldev->mutex);959959+ pin = gpio_to_pin(range, gc, offset);960960+ ret = pin_config_get_for_pin(pctldev, pin, config);961961+ mutex_unlock(&pctldev->mutex);962962+963963+ if (ret)964964+ return ret;965965+966966+ *config = pinconf_to_config_argument(*config);967967+ return 0;968968+}969969+EXPORT_SYMBOL_GPL(pinctrl_gpio_get_config);941970942971static struct pinctrl_state *find_state(struct pinctrl *p,943972 const char *name)
+6
drivers/pinctrl/pinconf.h
···7474 return -ENOTSUPP;7575}76767777+static inline int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned int pin,7878+ unsigned long *config)7979+{8080+ return -ENOTSUPP;8181+}8282+7783#endif78847985#if defined(CONFIG_PINCONF) && defined(CONFIG_DEBUG_FS)
+33-13
drivers/pinctrl/pinctrl-scmi.c
···251251 case PIN_CONFIG_MODE_LOW_POWER:252252 *type = SCMI_PIN_LOW_POWER_MODE;253253 break;254254- case PIN_CONFIG_LEVEL:255255- *type = SCMI_PIN_OUTPUT_VALUE;256256- break;257254 case PIN_CONFIG_OUTPUT_ENABLE:258255 *type = SCMI_PIN_OUTPUT_MODE;259259- break;260260- case PIN_CONFIG_OUTPUT_IMPEDANCE_OHMS:261261- *type = SCMI_PIN_OUTPUT_VALUE;262256 break;263257 case PIN_CONFIG_POWER_SOURCE:264258 *type = SCMI_PIN_POWER_SOURCE;···270276 return 0;271277}272278279279+static int pinctrl_scmi_map_pinconf_type_get(enum pin_config_param param,280280+ enum scmi_pinctrl_conf_type *type)281281+{282282+ if (param == PIN_CONFIG_LEVEL) {283283+ *type = SCMI_PIN_INPUT_VALUE;284284+ return 0;285285+ }286286+287287+ return pinctrl_scmi_map_pinconf_type(param, type);288288+}289289+290290+static int pinctrl_scmi_map_pinconf_type_set(enum pin_config_param param,291291+ enum scmi_pinctrl_conf_type *type)292292+{293293+ if (param == PIN_CONFIG_LEVEL) {294294+ *type = SCMI_PIN_OUTPUT_VALUE;295295+ return 0;296296+ }297297+298298+ return pinctrl_scmi_map_pinconf_type(param, type);299299+}300300+273301static int pinctrl_scmi_pinconf_get(struct pinctrl_dev *pctldev,274302 unsigned int pin, unsigned long *config)275303{···306290307291 config_type = pinconf_to_config_param(*config);308292309309- ret = pinctrl_scmi_map_pinconf_type(config_type, &type);293293+ ret = pinctrl_scmi_map_pinconf_type_get(config_type, &type);310294 if (ret)311295 return ret;312296···361345 unsigned long *configs,362346 unsigned int num_configs)363347{364364- int i, ret;348348+ int i, cnt, ret;365349 struct scmi_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);366350 enum scmi_pinctrl_conf_type config_type[SCMI_NUM_CONFIGS];367351 u32 config_value[SCMI_NUM_CONFIGS];···377361 if (ret)378362 return ret;379363364364+ cnt = 0;380365 for (i = 0; i < num_configs; i++) {381366 param = pinconf_to_config_param(configs[i]);382382- ret = pinctrl_scmi_map_pinconf_type(param, &p_config_type[i]);367367+ if (param == PIN_CONFIG_PERSIST_STATE)368368+ continue;369369+ ret = pinctrl_scmi_map_pinconf_type_set(param, &p_config_type[cnt]);383370 if (ret) {384371 dev_err(pmx->dev, "Error map pinconf_type %d\n", ret);385372 goto free_config;386373 }387387- p_config_value[i] = pinconf_to_config_argument(configs[i]);374374+ p_config_value[cnt] = pinconf_to_config_argument(configs[i]);375375+ cnt++;388376 }389377390390- ret = pinctrl_ops->settings_conf(pmx->ph, pin, PIN_TYPE, num_configs,378378+ ret = pinctrl_ops->settings_conf(pmx->ph, pin, PIN_TYPE, cnt,391379 p_config_type, p_config_value);392380 if (ret)393381 dev_err(pmx->dev, "Error parsing config %d\n", ret);···425405426406 for (i = 0; i < num_configs; i++) {427407 param = pinconf_to_config_param(configs[i]);428428- ret = pinctrl_scmi_map_pinconf_type(param, &p_config_type[i]);408408+ ret = pinctrl_scmi_map_pinconf_type_set(param, &p_config_type[i]);429409 if (ret) {430410 dev_err(pmx->dev, "Error map pinconf_type %d\n", ret);431411 goto free_config;···460440 return -EINVAL;461441462442 config_type = pinconf_to_config_param(*config);463463- ret = pinctrl_scmi_map_pinconf_type(config_type, &type);443443+ ret = pinctrl_scmi_map_pinconf_type_get(config_type, &type);464444 if (ret) {465445 dev_err(pmx->dev, "Error map pinconf_type %d\n", ret);466446 return ret;
+9
include/linux/pinctrl/consumer.h
···3535 unsigned int offset);3636int pinctrl_gpio_set_config(struct gpio_chip *gc, unsigned int offset,3737 unsigned long config);3838+int pinctrl_gpio_get_config(struct gpio_chip *gc, unsigned int offset,3939+ unsigned long *config);38403941struct pinctrl * __must_check pinctrl_get(struct device *dev);4042void pinctrl_put(struct pinctrl *p);···999710098static inline int10199pinctrl_gpio_direction_output(struct gpio_chip *gc, unsigned int offset)100100+{101101+ return 0;102102+}103103+104104+static inline int105105+pinctrl_gpio_get_config(struct gpio_chip *gc, unsigned int offset,106106+ unsigned long *config)102107{103108 return 0;104109}