Skip to content

Commit 541c5b0

Browse files
author
Bartosz Golaszewski
committed
Merge branch 'ib-scmi-pinctrl-gpio' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl into gpio/for-next
Pull in the SCMI GPIO driver along with its pinctrl dependencies.
2 parents 7803501 + 7671f49 commit 541c5b0

9 files changed

Lines changed: 255 additions & 13 deletions

File tree

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
2+
%YAML 1.2
3+
---
4+
$id: http://devicetree.org/schemas/gpio/pin-control-gpio.yaml#
5+
$schema: http://devicetree.org/meta-schemas/core.yaml#
6+
7+
title: Pin control based generic GPIO controller
8+
9+
description:
10+
The pin control-based GPIO will facilitate a pin controller's ability
11+
to drive electric lines high/low and other generic properties of a
12+
pin controller to perform general-purpose one-bit binary I/O.
13+
14+
maintainers:
15+
- Dan Carpenter <dan.carpenter@linaro.org>
16+
17+
properties:
18+
compatible:
19+
const: scmi-pinctrl-gpio
20+
21+
gpio-controller: true
22+
23+
"#gpio-cells":
24+
const: 2
25+
26+
gpio-line-names: true
27+
28+
gpio-ranges: true
29+
30+
ngpios: true
31+
32+
patternProperties:
33+
"^.+-hog(-[0-9]+)?$":
34+
type: object
35+
36+
required:
37+
- gpio-hog
38+
39+
required:
40+
- compatible
41+
- gpio-controller
42+
- "#gpio-cells"
43+
- gpio-ranges
44+
- ngpios
45+
46+
additionalProperties: false
47+
48+
examples:
49+
- |
50+
gpio {
51+
compatible = "scmi-pinctrl-gpio";
52+
gpio-controller;
53+
#gpio-cells = <2>;
54+
ngpios = <4>;
55+
gpio-line-names = "gpio_5_17", "gpio_5_20", "gpio_5_22", "gpio_2_1";
56+
gpio-ranges = <&scmi_pinctrl 0 30 4>;
57+
pinctrl-names = "default";
58+
pinctrl-0 = <&keys_pins>;
59+
};

drivers/firmware/arm_scmi/pinctrl.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,8 @@ static int scmi_pinctrl_request_free(const struct scmi_protocol_handle *ph,
578578
tx->flags = cpu_to_le32(type);
579579

580580
ret = ph->xops->do_xfer(ph, t);
581+
if (ret == -EOPNOTSUPP)
582+
ret = 0;
581583
ph->xops->xfer_put(ph, t);
582584

583585
return ret;

drivers/gpio/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,19 @@ config GPIO_BRCMSTB
241241
help
242242
Say yes here to enable GPIO support for Broadcom STB (BCM7XXX) SoCs.
243243

244+
config GPIO_BY_PINCTRL
245+
tristate "GPIO support based on a pure pin control backend"
246+
depends on GPIOLIB
247+
help
248+
Support for generic GPIO handling based on top of pin control.
249+
Traditionally, firmware creates a GPIO interface or a pin
250+
controller interface and we have a driver to support it. But
251+
in SCMI, the pin control interface is generic and we can
252+
create a simple GPIO device based on the pin control interface
253+
without doing anything custom.
254+
255+
This driver used to do GPIO over the ARM SCMI protocol.
256+
244257
config GPIO_CADENCE
245258
tristate "Cadence GPIO support"
246259
depends on OF

drivers/gpio/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
5151
obj-$(CONFIG_GPIO_BLZP1600) += gpio-blzp1600.o
5252
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
5353
obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
54+
obj-$(CONFIG_GPIO_BY_PINCTRL) += gpio-by-pinctrl.o
5455
obj-$(CONFIG_GPIO_CADENCE) += gpio-cadence.o
5556
obj-$(CONFIG_GPIO_CGBC) += gpio-cgbc.o
5657
obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o

drivers/gpio/gpio-by-pinctrl.c

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
//
3+
// Copyright (C) 2026 Linaro Inc.
4+
// Author: AKASHI takahiro <takahiro.akashi@linaro.org>
5+
6+
#include <linux/errno.h>
7+
#include <linux/gpio/driver.h>
8+
#include <linux/mod_devicetable.h>
9+
#include <linux/module.h>
10+
#include <linux/pinctrl/consumer.h>
11+
#include <linux/platform_device.h>
12+
#include <linux/types.h>
13+
14+
#include "gpiolib.h"
15+
16+
static int pin_control_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
17+
{
18+
unsigned long config;
19+
int ret;
20+
21+
config = PIN_CONFIG_OUTPUT_ENABLE;
22+
ret = pinctrl_gpio_get_config(gc, offset, &config);
23+
if (ret)
24+
return ret;
25+
if (config)
26+
return GPIO_LINE_DIRECTION_OUT;
27+
28+
return GPIO_LINE_DIRECTION_IN;
29+
}
30+
31+
static int pin_control_gpio_direction_output(struct gpio_chip *chip,
32+
unsigned int offset, int val)
33+
{
34+
return pinctrl_gpio_direction_output(chip, offset);
35+
}
36+
37+
static int pin_control_gpio_get(struct gpio_chip *chip, unsigned int offset)
38+
{
39+
unsigned long config;
40+
int ret;
41+
42+
config = PIN_CONFIG_LEVEL;
43+
ret = pinctrl_gpio_get_config(chip, offset, &config);
44+
if (ret)
45+
return ret;
46+
47+
return !!config;
48+
}
49+
50+
static int pin_control_gpio_set(struct gpio_chip *chip, unsigned int offset,
51+
int val)
52+
{
53+
unsigned long config;
54+
55+
config = pinconf_to_config_packed(PIN_CONFIG_LEVEL, val);
56+
return pinctrl_gpio_set_config(chip, offset, config);
57+
}
58+
59+
static int pin_control_gpio_probe(struct platform_device *pdev)
60+
{
61+
struct device *dev = &pdev->dev;
62+
struct gpio_chip *chip;
63+
64+
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
65+
if (!chip)
66+
return -ENOMEM;
67+
68+
chip->label = dev_name(dev);
69+
chip->parent = dev;
70+
chip->base = -1;
71+
72+
chip->request = gpiochip_generic_request;
73+
chip->free = gpiochip_generic_free;
74+
chip->get_direction = pin_control_gpio_get_direction;
75+
chip->direction_input = pinctrl_gpio_direction_input;
76+
chip->direction_output = pin_control_gpio_direction_output;
77+
chip->get = pin_control_gpio_get;
78+
chip->set = pin_control_gpio_set;
79+
chip->set_config = gpiochip_generic_config;
80+
81+
return devm_gpiochip_add_data(dev, chip, NULL);
82+
}
83+
84+
static const struct of_device_id pin_control_gpio_match[] = {
85+
{ .compatible = "scmi-pinctrl-gpio" },
86+
{ /* sentinel */ }
87+
};
88+
MODULE_DEVICE_TABLE(of, pin_control_gpio_match);
89+
90+
static struct platform_driver pin_control_gpio_driver = {
91+
.probe = pin_control_gpio_probe,
92+
.driver = {
93+
.name = "pin-control-gpio",
94+
.of_match_table = pin_control_gpio_match,
95+
},
96+
};
97+
module_platform_driver(pin_control_gpio_driver);
98+
99+
MODULE_AUTHOR("AKASHI Takahiro <takahiro.akashi@linaro.org>");
100+
MODULE_DESCRIPTION("Pinctrl based GPIO driver");
101+
MODULE_LICENSE("GPL");

drivers/pinctrl/core.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <linux/pinctrl/consumer.h>
3131
#include <linux/pinctrl/devinfo.h>
3232
#include <linux/pinctrl/machine.h>
33+
#include <linux/pinctrl/pinconf.h>
3334
#include <linux/pinctrl/pinctrl.h>
3435

3536
#include "core.h"
@@ -938,6 +939,36 @@ int pinctrl_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
938939
}
939940
EXPORT_SYMBOL_GPL(pinctrl_gpio_set_config);
940941

942+
/**
943+
* pinctrl_gpio_get_config() - Get the config for a given GPIO pin
944+
* @gc: GPIO chip structure from the GPIO subsystem
945+
* @offset: hardware offset of the GPIO relative to the controller
946+
* @config: the configuration to query. On success it holds the result
947+
* Return: 0 on success, negative errno otherwise
948+
*/
949+
int pinctrl_gpio_get_config(struct gpio_chip *gc, unsigned int offset, unsigned long *config)
950+
{
951+
struct pinctrl_gpio_range *range;
952+
struct pinctrl_dev *pctldev;
953+
int ret, pin;
954+
955+
ret = pinctrl_get_device_gpio_range(gc, offset, &pctldev, &range);
956+
if (ret)
957+
return ret;
958+
959+
mutex_lock(&pctldev->mutex);
960+
pin = gpio_to_pin(range, gc, offset);
961+
ret = pin_config_get_for_pin(pctldev, pin, config);
962+
mutex_unlock(&pctldev->mutex);
963+
964+
if (ret)
965+
return ret;
966+
967+
*config = pinconf_to_config_argument(*config);
968+
return 0;
969+
}
970+
EXPORT_SYMBOL_GPL(pinctrl_gpio_get_config);
971+
941972
static struct pinctrl_state *find_state(struct pinctrl *p,
942973
const char *name)
943974
{

drivers/pinctrl/pinconf.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,12 @@ static inline int pinconf_set_config(struct pinctrl_dev *pctldev, unsigned int p
7474
return -ENOTSUPP;
7575
}
7676

77+
static inline int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned int pin,
78+
unsigned long *config)
79+
{
80+
return -ENOTSUPP;
81+
}
82+
7783
#endif
7884

7985
#if defined(CONFIG_PINCONF) && defined(CONFIG_DEBUG_FS)

drivers/pinctrl/pinctrl-scmi.c

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -251,15 +251,9 @@ static int pinctrl_scmi_map_pinconf_type(enum pin_config_param param,
251251
case PIN_CONFIG_MODE_LOW_POWER:
252252
*type = SCMI_PIN_LOW_POWER_MODE;
253253
break;
254-
case PIN_CONFIG_LEVEL:
255-
*type = SCMI_PIN_OUTPUT_VALUE;
256-
break;
257254
case PIN_CONFIG_OUTPUT_ENABLE:
258255
*type = SCMI_PIN_OUTPUT_MODE;
259256
break;
260-
case PIN_CONFIG_OUTPUT_IMPEDANCE_OHMS:
261-
*type = SCMI_PIN_OUTPUT_VALUE;
262-
break;
263257
case PIN_CONFIG_POWER_SOURCE:
264258
*type = SCMI_PIN_POWER_SOURCE;
265259
break;
@@ -276,6 +270,28 @@ static int pinctrl_scmi_map_pinconf_type(enum pin_config_param param,
276270
return 0;
277271
}
278272

273+
static int pinctrl_scmi_map_pinconf_type_get(enum pin_config_param param,
274+
enum scmi_pinctrl_conf_type *type)
275+
{
276+
if (param == PIN_CONFIG_LEVEL) {
277+
*type = SCMI_PIN_INPUT_VALUE;
278+
return 0;
279+
}
280+
281+
return pinctrl_scmi_map_pinconf_type(param, type);
282+
}
283+
284+
static int pinctrl_scmi_map_pinconf_type_set(enum pin_config_param param,
285+
enum scmi_pinctrl_conf_type *type)
286+
{
287+
if (param == PIN_CONFIG_LEVEL) {
288+
*type = SCMI_PIN_OUTPUT_VALUE;
289+
return 0;
290+
}
291+
292+
return pinctrl_scmi_map_pinconf_type(param, type);
293+
}
294+
279295
static int pinctrl_scmi_pinconf_get(struct pinctrl_dev *pctldev,
280296
unsigned int pin, unsigned long *config)
281297
{
@@ -290,7 +306,7 @@ static int pinctrl_scmi_pinconf_get(struct pinctrl_dev *pctldev,
290306

291307
config_type = pinconf_to_config_param(*config);
292308

293-
ret = pinctrl_scmi_map_pinconf_type(config_type, &type);
309+
ret = pinctrl_scmi_map_pinconf_type_get(config_type, &type);
294310
if (ret)
295311
return ret;
296312

@@ -345,7 +361,7 @@ static int pinctrl_scmi_pinconf_set(struct pinctrl_dev *pctldev,
345361
unsigned long *configs,
346362
unsigned int num_configs)
347363
{
348-
int i, ret;
364+
int i, cnt, ret;
349365
struct scmi_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
350366
enum scmi_pinctrl_conf_type config_type[SCMI_NUM_CONFIGS];
351367
u32 config_value[SCMI_NUM_CONFIGS];
@@ -361,17 +377,21 @@ static int pinctrl_scmi_pinconf_set(struct pinctrl_dev *pctldev,
361377
if (ret)
362378
return ret;
363379

380+
cnt = 0;
364381
for (i = 0; i < num_configs; i++) {
365382
param = pinconf_to_config_param(configs[i]);
366-
ret = pinctrl_scmi_map_pinconf_type(param, &p_config_type[i]);
383+
if (param == PIN_CONFIG_PERSIST_STATE)
384+
continue;
385+
ret = pinctrl_scmi_map_pinconf_type_set(param, &p_config_type[cnt]);
367386
if (ret) {
368387
dev_err(pmx->dev, "Error map pinconf_type %d\n", ret);
369388
goto free_config;
370389
}
371-
p_config_value[i] = pinconf_to_config_argument(configs[i]);
390+
p_config_value[cnt] = pinconf_to_config_argument(configs[i]);
391+
cnt++;
372392
}
373393

374-
ret = pinctrl_ops->settings_conf(pmx->ph, pin, PIN_TYPE, num_configs,
394+
ret = pinctrl_ops->settings_conf(pmx->ph, pin, PIN_TYPE, cnt,
375395
p_config_type, p_config_value);
376396
if (ret)
377397
dev_err(pmx->dev, "Error parsing config %d\n", ret);
@@ -405,7 +425,7 @@ static int pinctrl_scmi_pinconf_group_set(struct pinctrl_dev *pctldev,
405425

406426
for (i = 0; i < num_configs; i++) {
407427
param = pinconf_to_config_param(configs[i]);
408-
ret = pinctrl_scmi_map_pinconf_type(param, &p_config_type[i]);
428+
ret = pinctrl_scmi_map_pinconf_type_set(param, &p_config_type[i]);
409429
if (ret) {
410430
dev_err(pmx->dev, "Error map pinconf_type %d\n", ret);
411431
goto free_config;
@@ -440,7 +460,7 @@ static int pinctrl_scmi_pinconf_group_get(struct pinctrl_dev *pctldev,
440460
return -EINVAL;
441461

442462
config_type = pinconf_to_config_param(*config);
443-
ret = pinctrl_scmi_map_pinconf_type(config_type, &type);
463+
ret = pinctrl_scmi_map_pinconf_type_get(config_type, &type);
444464
if (ret) {
445465
dev_err(pmx->dev, "Error map pinconf_type %d\n", ret);
446466
return ret;

include/linux/pinctrl/consumer.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ int pinctrl_gpio_direction_output(struct gpio_chip *gc,
3535
unsigned int offset);
3636
int pinctrl_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
3737
unsigned long config);
38+
int pinctrl_gpio_get_config(struct gpio_chip *gc, unsigned int offset,
39+
unsigned long *config);
3840

3941
struct pinctrl * __must_check pinctrl_get(struct device *dev);
4042
void pinctrl_put(struct pinctrl *p);
@@ -101,6 +103,13 @@ pinctrl_gpio_direction_output(struct gpio_chip *gc, unsigned int offset)
101103
return 0;
102104
}
103105

106+
static inline int
107+
pinctrl_gpio_get_config(struct gpio_chip *gc, unsigned int offset,
108+
unsigned long *config)
109+
{
110+
return 0;
111+
}
112+
104113
static inline int
105114
pinctrl_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
106115
unsigned long config)

0 commit comments

Comments
 (0)