[RFC PATCH v2] draft for gpio pinconf
Ludovic Desroches
ludovic.desroches at microchip.com
Tue Dec 19 01:40:25 PST 2017
Signed-off-by: Ludovic Desroches <ludovic.desroches at microchip.com>
---
Hi,
After discussing with Maxime Ripard, I realize that the first approach
may not be a good one.
For instance, the drive-strength is a digital value so it will take
ake several bits. Having a whole pin configuration in 32 bits may not
be the right solution.
My aim is to use the existing pinconf bindings.
This patch is a draft to test the feasibility. Sorry to provide it in
this state (several ugly hacks) but I didn't want to spend time on a clean
solution if it will be rejected.
arch/arm/boot/dts/at91-sama5d2_xplained.dts | 6 +-----
arch/arm/boot/dts/sama5d2.dtsi | 2 +-
drivers/gpio/gpiolib-of.c | 10 +++++++++-
drivers/gpio/gpiolib.c | 24 +++++++++++++++++++-----
drivers/gpio/gpiolib.h | 2 ++
drivers/pinctrl/core.c | 5 ++---
drivers/pinctrl/pinctrl-at91-pio4.c | 19 +++++++++++++++++++
include/linux/gpio/driver.h | 5 +++--
include/linux/pinctrl/consumer.h | 4 ++--
9 files changed, 58 insertions(+), 19 deletions(-)
diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts
index 56de21de2779..709c9c3ae622 100644
--- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts
+++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts
@@ -413,7 +413,6 @@
};
pinctrl_key_gpio_default: key_gpio_default {
- pinmux = <PIN_PB9__GPIO>;
bias-pull-up;
};
@@ -545,12 +544,9 @@
gpio_keys {
compatible = "gpio-keys";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_key_gpio_default>;
-
bp1 {
label = "PB_USER";
- gpios = <&pioA PIN_PB9 GPIO_ACTIVE_LOW>;
+ gpios = <&pioA PIN_PB9 GPIO_ACTIVE_LOW &pinctrl_key_gpio_default>;
linux,code = <0x104>;
wakeup-source;
};
diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi
index b44e63995583..cccd404192cc 100644
--- a/arch/arm/boot/dts/sama5d2.dtsi
+++ b/arch/arm/boot/dts/sama5d2.dtsi
@@ -1444,7 +1444,7 @@
interrupt-controller;
#interrupt-cells = <2>;
gpio-controller;
- #gpio-cells = <2>;
+ #gpio-cells = <3>;
clocks = <&pioA_clk>;
};
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 4a2b8d3397c7..605017a4d2d8 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -46,7 +46,7 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip,
{
int ret;
- if (chip->of_gpio_n_cells != gpiospec->args_count)
+ if (chip->of_gpio_n_cells > gpiospec->args_count)
return ERR_PTR(-EINVAL);
ret = chip->of_xlate(chip, gpiospec, flags);
@@ -93,6 +93,14 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
if (IS_ERR(desc))
goto out;
+ if (gpiospec.args_count > chip->of_gpio_n_cells) {
+ desc->np_pincfg = of_parse_phandle(np, propname, gpiospec.args_count);
+ if (!desc->np_pincfg) {
+ printk("ERROR\n");
+ goto out;
+ }
+ }
+
pr_debug("%s: parsed '%s' property of node '%pOF[%d]' - status (%d)\n",
__func__, propname, np, index,
PTR_ERR_OR_ZERO(desc));
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 0621baddfddc..543a120a0f84 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -29,6 +29,8 @@
#include <uapi/linux/gpio.h>
#include "gpiolib.h"
+#include "../pinctrl/core.h"
+#include "../pinctrl/pinconf.h"
#define CREATE_TRACE_POINTS
#include <trace/events/gpio.h>
@@ -1997,9 +1999,9 @@ EXPORT_SYMBOL_GPL(gpiochip_generic_free);
* @config: the configuration to be applied
*/
int gpiochip_generic_config(struct gpio_chip *chip, unsigned offset,
- unsigned long config)
+ unsigned long *configs, unsigned num_configs)
{
- return pinctrl_gpio_set_config(chip->gpiodev->base + offset, config);
+ return pinctrl_gpio_set_config(chip->gpiodev->base + offset, configs, num_configs);
}
EXPORT_SYMBOL_GPL(gpiochip_generic_config);
@@ -2161,6 +2163,18 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
goto done;
}
}
+ if (chip->set_config) {
+ unsigned long *configs;
+ unsigned num_configs;
+ int ret;
+
+ ret = pinconf_generic_parse_dt_config(desc->np_pincfg, NULL, &configs, &num_configs);
+ if (ret < 0) {
+ /* TODO */
+ }
+ chip->set_config(chip, gpio_chip_hwgpio(desc), configs, num_configs);
+ kfree(configs);
+ }
if (chip->get_direction) {
/* chip->get_direction may sleep */
spin_unlock_irqrestore(&gpio_lock, flags);
@@ -2404,7 +2418,7 @@ static int gpio_set_drive_single_ended(struct gpio_chip *gc, unsigned offset,
{
unsigned long config = { PIN_CONF_PACKED(mode, 0) };
- return gc->set_config ? gc->set_config(gc, offset, config) : -ENOTSUPP;
+ return gc->set_config ? gc->set_config(gc, offset, &config, 1) : -ENOTSUPP;
}
static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value)
@@ -2529,7 +2543,7 @@ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
}
config = pinconf_to_config_packed(PIN_CONFIG_INPUT_DEBOUNCE, debounce);
- return chip->set_config(chip, gpio_chip_hwgpio(desc), config);
+ return chip->set_config(chip, gpio_chip_hwgpio(desc), &config, 1);
}
EXPORT_SYMBOL_GPL(gpiod_set_debounce);
@@ -2565,7 +2579,7 @@ int gpiod_set_transitory(struct gpio_desc *desc, bool transitory)
packed = pinconf_to_config_packed(PIN_CONFIG_PERSIST_STATE,
!transitory);
gpio = gpio_chip_hwgpio(desc);
- rc = chip->set_config(chip, gpio, packed);
+ rc = chip->set_config(chip, gpio, &packed, 1);
if (rc == -ENOTSUPP) {
dev_dbg(&desc->gdev->dev, "Persistence not supported for GPIO %d\n",
gpio);
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index 5e1f7cc6eeb6..79119548cc33 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -215,6 +215,8 @@ struct gpio_desc {
const char *label;
/* Name of the GPIO */
const char *name;
+ /* Pin configuration node */
+ struct device_node *np_pincfg;
};
int gpiod_request(struct gpio_desc *desc, const char *label);
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index 4c8d5b23e4d0..89976f35a6a3 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -857,9 +857,8 @@ EXPORT_SYMBOL_GPL(pinctrl_gpio_direction_output);
* they need to call the underlying pin controller to change GPIO config
* (for example set debounce time).
*/
-int pinctrl_gpio_set_config(unsigned gpio, unsigned long config)
+int pinctrl_gpio_set_config(unsigned gpio, unsigned long *configs, unsigned num_configs)
{
- unsigned long configs[] = { config };
struct pinctrl_gpio_range *range;
struct pinctrl_dev *pctldev;
int ret, pin;
@@ -870,7 +869,7 @@ int pinctrl_gpio_set_config(unsigned gpio, unsigned long config)
mutex_lock(&pctldev->mutex);
pin = gpio_to_pin(range, gpio);
- ret = pinconf_set_config(pctldev, pin, configs, ARRAY_SIZE(configs));
+ ret = pinconf_set_config(pctldev, pin, configs, num_configs);
mutex_unlock(&pctldev->mutex);
return ret;
diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c
index b1ca838dd80a..477a4d7ddbaf 100644
--- a/drivers/pinctrl/pinctrl-at91-pio4.c
+++ b/drivers/pinctrl/pinctrl-at91-pio4.c
@@ -358,12 +358,15 @@ static int atmel_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
}
static struct gpio_chip atmel_gpio_chip = {
+ .request = gpiochip_generic_request,
+ .free = gpiochip_generic_free,
.direction_input = atmel_gpio_direction_input,
.get = atmel_gpio_get,
.direction_output = atmel_gpio_direction_output,
.set = atmel_gpio_set,
.to_irq = atmel_gpio_to_irq,
.base = 0,
+ .set_config = gpiochip_generic_config,
};
/* --- PINCTRL --- */
@@ -643,11 +646,26 @@ static int atmel_pmx_set_mux(struct pinctrl_dev *pctldev,
return 0;
}
+static int atmel_pmx_gpio_request_enable(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset)
+{
+ u32 conf;
+
+ conf = atmel_pin_config_read(pctldev, offset);
+ conf &= (~ATMEL_PIO_CFGR_FUNC_MASK);
+ atmel_pin_config_write(pctldev, offset, conf);
+
+ dev_dbg(pctldev->dev, "enable pin %u as GPIO\n", offset);
+
+ return 0;
+}
+
static const struct pinmux_ops atmel_pmxops = {
+ .gpio_request_enable = atmel_pmx_gpio_request_enable,
.get_functions_count = atmel_pmx_get_functions_count,
.get_function_name = atmel_pmx_get_function_name,
.get_function_groups = atmel_pmx_get_function_groups,
.set_mux = atmel_pmx_set_mux,
+ .strict = true,
};
static int atmel_conf_pin_config_group_get(struct pinctrl_dev *pctldev,
@@ -817,6 +835,7 @@ static void atmel_conf_pin_config_dbg_show(struct pinctrl_dev *pctldev,
}
static const struct pinconf_ops atmel_confops = {
+ .pin_config_set = atmel_conf_pin_config_group_set,
.pin_config_group_get = atmel_conf_pin_config_group_get,
.pin_config_group_set = atmel_conf_pin_config_group_set,
.pin_config_dbg_show = atmel_conf_pin_config_dbg_show,
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 55e672592fa9..b54968cd6dfc 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -247,7 +247,8 @@ struct gpio_chip {
unsigned long *bits);
int (*set_config)(struct gpio_chip *chip,
unsigned offset,
- unsigned long config);
+ unsigned long *configs,
+ unsigned num_configs);
int (*to_irq)(struct gpio_chip *chip,
unsigned offset);
@@ -490,7 +491,7 @@ static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gpiochip,
int gpiochip_generic_request(struct gpio_chip *chip, unsigned offset);
void gpiochip_generic_free(struct gpio_chip *chip, unsigned offset);
int gpiochip_generic_config(struct gpio_chip *chip, unsigned offset,
- unsigned long config);
+ unsigned long *configs, unsigned num_configs);
#ifdef CONFIG_PINCTRL
diff --git a/include/linux/pinctrl/consumer.h b/include/linux/pinctrl/consumer.h
index 0412cc9833e9..14be53e1e053 100644
--- a/include/linux/pinctrl/consumer.h
+++ b/include/linux/pinctrl/consumer.h
@@ -29,7 +29,7 @@ extern int pinctrl_gpio_request(unsigned gpio);
extern void pinctrl_gpio_free(unsigned gpio);
extern int pinctrl_gpio_direction_input(unsigned gpio);
extern int pinctrl_gpio_direction_output(unsigned gpio);
-extern int pinctrl_gpio_set_config(unsigned gpio, unsigned long config);
+extern int pinctrl_gpio_set_config(unsigned gpio, unsigned long *configs, unsigned num_configs);
extern struct pinctrl * __must_check pinctrl_get(struct device *dev);
extern void pinctrl_put(struct pinctrl *p);
@@ -81,7 +81,7 @@ static inline int pinctrl_gpio_direction_output(unsigned gpio)
return 0;
}
-static inline int pinctrl_gpio_set_config(unsigned gpio, unsigned long config)
+static inline int pinctrl_gpio_set_config(unsigned gpio, unsigned long *configs, unsigned num_configs)
{
return 0;
}
--
2.12.2
More information about the linux-arm-kernel
mailing list