pinctrl/gpio: non-linear GPIO ranges accesible from gpiolib
This patch adds the infrastructure required to register non-linear gpio ranges through gpiolib and the standard GPIO device tree bindings. Signed-off-by: Christian Ruppert <christian.ruppert@abilis.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
parent
c8ce878206
commit
586a87e6ed
|
@ -87,8 +87,10 @@ controllers. The gpio-ranges property described below represents this, and
|
|||
contains information structures as follows:
|
||||
|
||||
gpio-range-list ::= <single-gpio-range> [gpio-range-list]
|
||||
single-gpio-range ::=
|
||||
single-gpio-range ::= <numeric-gpio-range> | <named-gpio-range>
|
||||
numeric-gpio-range ::=
|
||||
<pinctrl-phandle> <gpio-base> <pinctrl-base> <count>
|
||||
named-gpio-range ::= <pinctrl-phandle> <gpio-base> '<0 0>'
|
||||
gpio-phandle : phandle to pin controller node.
|
||||
gpio-base : Base GPIO ID in the GPIO controller
|
||||
pinctrl-base : Base pinctrl pin ID in the pin controller
|
||||
|
@ -97,6 +99,19 @@ contains information structures as follows:
|
|||
The "pin controller node" mentioned above must conform to the bindings
|
||||
described in ../pinctrl/pinctrl-bindings.txt.
|
||||
|
||||
In case named gpio ranges are used (ranges with both <pinctrl-base> and
|
||||
<count> set to 0), the property gpio-ranges-group-names contains one string
|
||||
for every single-gpio-range in gpio-ranges:
|
||||
gpiorange-names-list ::= <gpiorange-name> [gpiorange-names-list]
|
||||
gpiorange-name : Name of the pingroup associated to the GPIO range in
|
||||
the respective pin controller.
|
||||
|
||||
Elements of gpiorange-names-list corresponding to numeric ranges contain
|
||||
the empty string. Elements of gpiorange-names-list corresponding to named
|
||||
ranges contain the name of a pin group defined in the respective pin
|
||||
controller. The number of pins/GPIOs in the range is the number of pins in
|
||||
that pin group.
|
||||
|
||||
Previous versions of this binding required all pin controller nodes that
|
||||
were referenced by any gpio-ranges property to contain a property named
|
||||
#gpio-range-cells with value <3>. This requirement is now deprecated.
|
||||
|
@ -104,7 +119,7 @@ However, that property may still exist in older device trees for
|
|||
compatibility reasons, and would still be required even in new device
|
||||
trees that need to be compatible with older software.
|
||||
|
||||
Example:
|
||||
Example 1:
|
||||
|
||||
qe_pio_e: gpio-controller@1460 {
|
||||
#gpio-cells = <2>;
|
||||
|
@ -117,3 +132,24 @@ Example:
|
|||
Here, a single GPIO controller has GPIOs 0..9 routed to pin controller
|
||||
pinctrl1's pins 20..29, and GPIOs 10..19 routed to pin controller pinctrl2's
|
||||
pins 50..59.
|
||||
|
||||
Example 2:
|
||||
|
||||
gpio_pio_i: gpio-controller@14B0 {
|
||||
#gpio-cells = <2>;
|
||||
compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
|
||||
reg = <0x1480 0x18>;
|
||||
gpio-controller;
|
||||
gpio-ranges = <&pinctrl1 0 20 10>,
|
||||
<&pinctrl2 10 0 0>,
|
||||
<&pinctrl1 15 0 10>,
|
||||
<&pinctrl2 25 0 0>;
|
||||
gpio-ranges-group-names = "",
|
||||
"foo",
|
||||
"",
|
||||
"bar";
|
||||
};
|
||||
|
||||
Here, three GPIO ranges are defined wrt. two pin controllers. pinctrl1 GPIO
|
||||
ranges are defined using pin numbers whereas the GPIO ranges wrt. pinctrl2
|
||||
are named "foo" and "bar".
|
||||
|
|
|
@ -190,10 +190,15 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
|
|||
struct of_phandle_args pinspec;
|
||||
struct pinctrl_dev *pctldev;
|
||||
int index = 0, ret;
|
||||
const char *name;
|
||||
static const char group_names_propname[] = "gpio-ranges-group-names";
|
||||
struct property *group_names;
|
||||
|
||||
if (!np)
|
||||
return;
|
||||
|
||||
group_names = of_find_property(np, group_names_propname, NULL);
|
||||
|
||||
for (;; index++) {
|
||||
ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3,
|
||||
index, &pinspec);
|
||||
|
@ -204,14 +209,56 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
|
|||
if (!pctldev)
|
||||
break;
|
||||
|
||||
ret = gpiochip_add_pin_range(chip,
|
||||
pinctrl_dev_get_devname(pctldev),
|
||||
pinspec.args[0],
|
||||
pinspec.args[1],
|
||||
pinspec.args[2]);
|
||||
if (pinspec.args[2]) {
|
||||
if (group_names) {
|
||||
ret = of_property_read_string_index(np,
|
||||
group_names_propname,
|
||||
index, &name);
|
||||
if (strlen(name)) {
|
||||
pr_err("%s: Group name of numeric GPIO ranges must be the empty string.\n",
|
||||
np->full_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* npins != 0: linear range */
|
||||
ret = gpiochip_add_pin_range(chip,
|
||||
pinctrl_dev_get_devname(pctldev),
|
||||
pinspec.args[0],
|
||||
pinspec.args[1],
|
||||
pinspec.args[2]);
|
||||
if (ret)
|
||||
break;
|
||||
} else {
|
||||
/* npins == 0: special range */
|
||||
if (pinspec.args[1]) {
|
||||
pr_err("%s: Illegal gpio-range format.\n",
|
||||
np->full_name);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
if (!group_names) {
|
||||
pr_err("%s: GPIO group range requested but no %s property.\n",
|
||||
np->full_name, group_names_propname);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = of_property_read_string_index(np,
|
||||
group_names_propname,
|
||||
index, &name);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
if (!strlen(name)) {
|
||||
pr_err("%s: Group name of GPIO group range cannot be the empty string.\n",
|
||||
np->full_name);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = gpiochip_add_pingroup_range(chip, pctldev,
|
||||
pinspec.args[0], name);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1319,6 +1319,53 @@ EXPORT_SYMBOL_GPL(gpiochip_find);
|
|||
|
||||
#ifdef CONFIG_PINCTRL
|
||||
|
||||
/**
|
||||
* gpiochip_add_pingroup_range() - add a range for GPIO <-> pin mapping
|
||||
* @chip: the gpiochip to add the range for
|
||||
* @pinctrl: the dev_name() of the pin controller to map to
|
||||
* @gpio_offset: the start offset in the current gpio_chip number space
|
||||
* @pin_group: name of the pin group inside the pin controller
|
||||
*/
|
||||
int gpiochip_add_pingroup_range(struct gpio_chip *chip,
|
||||
struct pinctrl_dev *pctldev,
|
||||
unsigned int gpio_offset, const char *pin_group)
|
||||
{
|
||||
struct gpio_pin_range *pin_range;
|
||||
int ret;
|
||||
|
||||
pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL);
|
||||
if (!pin_range) {
|
||||
pr_err("%s: GPIO chip: failed to allocate pin ranges\n",
|
||||
chip->label);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Use local offset as range ID */
|
||||
pin_range->range.id = gpio_offset;
|
||||
pin_range->range.gc = chip;
|
||||
pin_range->range.name = chip->label;
|
||||
pin_range->range.base = chip->base + gpio_offset;
|
||||
pin_range->pctldev = pctldev;
|
||||
|
||||
ret = pinctrl_get_group_pins(pctldev, pin_group,
|
||||
&pin_range->range.pins,
|
||||
&pin_range->range.npins);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
pinctrl_add_gpio_range(pctldev, &pin_range->range);
|
||||
|
||||
pr_debug("GPIO chip %s: created GPIO range %d->%d ==> %s PINGRP %s\n",
|
||||
chip->label, gpio_offset,
|
||||
gpio_offset + pin_range->range.npins - 1,
|
||||
pinctrl_dev_get_devname(pctldev), pin_group);
|
||||
|
||||
list_add_tail(&pin_range->node, &chip->pin_ranges);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_add_pingroup_range);
|
||||
|
||||
/**
|
||||
* gpiochip_add_pin_range() - add a range for GPIO <-> pin mapping
|
||||
* @chip: the gpiochip to add the range for
|
||||
|
|
|
@ -462,6 +462,20 @@ struct pinctrl_dev *pinctrl_find_and_add_gpio_range(const char *devname,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(pinctrl_find_and_add_gpio_range);
|
||||
|
||||
int pinctrl_get_group_pins(struct pinctrl_dev *pctldev, const char *pin_group,
|
||||
const unsigned **pins, unsigned *num_pins)
|
||||
{
|
||||
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
|
||||
int gs;
|
||||
|
||||
gs = pinctrl_get_group_selector(pctldev, pin_group);
|
||||
if (gs < 0)
|
||||
return gs;
|
||||
|
||||
return pctlops->get_group_pins(pctldev, gs, pins, num_pins);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pinctrl_get_group_pins);
|
||||
|
||||
/**
|
||||
* pinctrl_find_gpio_range_from_pin() - locate the GPIO range for a pin
|
||||
* @pctldev: the pin controller device to look in
|
||||
|
|
|
@ -228,6 +228,9 @@ struct gpio_pin_range {
|
|||
int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
|
||||
unsigned int gpio_offset, unsigned int pin_offset,
|
||||
unsigned int npins);
|
||||
int gpiochip_add_pingroup_range(struct gpio_chip *chip,
|
||||
struct pinctrl_dev *pctldev,
|
||||
unsigned int gpio_offset, const char *pin_group);
|
||||
void gpiochip_remove_pin_ranges(struct gpio_chip *chip);
|
||||
|
||||
#else
|
||||
|
@ -239,6 +242,13 @@ gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int
|
||||
gpiochip_add_pingroup_range(struct gpio_chip *chip,
|
||||
struct pinctrl_dev *pctldev,
|
||||
unsigned int gpio_offset, const char *pin_group)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
gpiochip_remove_pin_ranges(struct gpio_chip *chip)
|
||||
|
|
|
@ -80,6 +80,7 @@ static inline int irq_to_gpio(unsigned int irq)
|
|||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
|
||||
struct device;
|
||||
struct gpio_chip;
|
||||
|
@ -220,6 +221,15 @@ gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int
|
||||
gpiochip_add_pingroup_range(struct gpio_chip *chip,
|
||||
struct pinctrl_dev *pctldev,
|
||||
unsigned int gpio_offset, const char *pin_group)
|
||||
{
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
gpiochip_remove_pin_ranges(struct gpio_chip *chip)
|
||||
{
|
||||
|
|
|
@ -144,6 +144,9 @@ extern struct pinctrl_dev *pinctrl_find_and_add_gpio_range(const char *devname,
|
|||
extern struct pinctrl_gpio_range *
|
||||
pinctrl_find_gpio_range_from_pin(struct pinctrl_dev *pctldev,
|
||||
unsigned int pin);
|
||||
extern int pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
|
||||
const char *pin_group, const unsigned **pins,
|
||||
unsigned *num_pins);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
extern struct pinctrl_dev *of_pinctrl_get(struct device_node *np);
|
||||
|
|
Loading…
Reference in New Issue