diff options
Diffstat (limited to 'drivers/gpio/gpiolib-of.c')
-rw-r--r-- | drivers/gpio/gpiolib-of.c | 137 |
1 files changed, 113 insertions, 24 deletions
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 2e537ee979f3..eb667f8f1ead 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -203,6 +203,15 @@ static void of_gpio_try_fixup_polarity(const struct device_node *np, */ { "qi,lb60", "rb-gpios", true }, #endif +#if IS_ENABLED(CONFIG_IEEE802154_CA8210) + /* + * According to the datasheet, the NRST pin 27 is an active-low + * signal. However, the device tree schema and admittedly + * the out-of-tree implementations have been used for a long + * time incorrectly by describing reset GPIO as active-high. + */ + { "cascoda,ca8210", "reset-gpio", false }, +#endif #if IS_ENABLED(CONFIG_PCI_LANTIQ) /* * According to the PCI specification, the RST# pin is an @@ -929,7 +938,7 @@ struct notifier_block gpio_of_notifier = { #endif /* CONFIG_OF_DYNAMIC */ /** - * of_gpio_simple_xlate - translate gpiospec to the GPIO number and flags + * of_gpio_twocell_xlate - translate twocell gpiospec to the GPIO number and flags * @gc: pointer to the gpio_chip structure * @gpiospec: GPIO specifier as found in the device tree * @flags: a flags pointer to fill in @@ -941,9 +950,9 @@ struct notifier_block gpio_of_notifier = { * Returns: * GPIO number (>= 0) on success, negative errno on failure. */ -static int of_gpio_simple_xlate(struct gpio_chip *gc, - const struct of_phandle_args *gpiospec, - u32 *flags) +static int of_gpio_twocell_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, + u32 *flags) { /* * We're discouraging gpio_cells < 2, since that way you'll have to @@ -951,7 +960,7 @@ static int of_gpio_simple_xlate(struct gpio_chip *gc, * number and the flags from a single gpio cell -- this is possible, * but not recommended). */ - if (gc->of_gpio_n_cells < 2) { + if (gc->of_gpio_n_cells != 2) { WARN_ON(1); return -EINVAL; } @@ -968,6 +977,49 @@ static int of_gpio_simple_xlate(struct gpio_chip *gc, return gpiospec->args[0]; } +/** + * of_gpio_threecell_xlate - translate threecell gpiospec to the GPIO number and flags + * @gc: pointer to the gpio_chip structure + * @gpiospec: GPIO specifier as found in the device tree + * @flags: a flags pointer to fill in + * + * This is simple translation function, suitable for the most 1:n mapped + * GPIO chips, i.e. several GPIO chip instances from one device tree node. + * In this case the following binding is implied: + * + * foo-gpios = <&gpio instance offset flags>; + * + * Returns: + * GPIO number (>= 0) on success, negative errno on failure. + */ +static int of_gpio_threecell_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, + u32 *flags) +{ + if (gc->of_gpio_n_cells != 3) { + WARN_ON(1); + return -EINVAL; + } + + if (WARN_ON(gpiospec->args_count != 3)) + return -EINVAL; + + /* + * Check chip instance number, the driver responds with true if + * this is the chip we are looking for. + */ + if (!gc->of_node_instance_match(gc, gpiospec->args[0])) + return -EINVAL; + + if (gpiospec->args[1] >= gc->ngpio) + return -EINVAL; + + if (flags) + *flags = gpiospec->args[2]; + + return gpiospec->args[1]; +} + #if IS_ENABLED(CONFIG_OF_GPIO_MM_GPIOCHIP) #include <linux/gpio/legacy-of-mm-gpiochip.h> /** @@ -1057,6 +1109,9 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) const char *name; static const char group_names_propname[] = "gpio-ranges-group-names"; bool has_group_names; + int offset; /* Offset of the first GPIO line on the chip */ + int pin; /* Pin base number in the range */ + int count; /* Number of pins/GPIO lines to map */ np = dev_of_node(&chip->gpiodev->dev); if (!np) @@ -1065,7 +1120,15 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) has_group_names = of_property_present(np, group_names_propname); for (;; index++) { - ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, + /* + * Ordinary phandles contain 2-3 cells: + * gpios = <&gpio [instance] offset flags>; + * Ranges always contain one more cell: + * gpio-ranges <&pinctrl [gpio_instance] gpio_offet pin_offet count>; + * This is why we parse chip->of_gpio_n_cells + 1 cells + */ + ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", + chip->of_gpio_n_cells + 1, index, &pinspec); if (ret) break; @@ -1075,13 +1138,33 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) if (!pctldev) return -EPROBE_DEFER; + if (chip->of_gpio_n_cells == 3) { + /* First cell is the gpiochip instance number */ + offset = pinspec.args[1]; + pin = pinspec.args[2]; + count = pinspec.args[3]; + } else { + offset = pinspec.args[0]; + pin = pinspec.args[1]; + count = pinspec.args[2]; + } + + /* + * With multiple GPIO chips per node, check that this chip is the + * right instance. + */ + if (chip->of_node_instance_match && + (chip->of_gpio_n_cells == 3) && + !chip->of_node_instance_match(chip, pinspec.args[0])) + continue; + /* Ignore ranges outside of this GPIO chip */ - if (pinspec.args[0] >= (chip->offset + chip->ngpio)) + if (offset >= (chip->offset + chip->ngpio)) continue; - if (pinspec.args[0] + pinspec.args[2] <= chip->offset) + if (offset + count <= chip->offset) continue; - if (pinspec.args[2]) { + if (count) { /* npins != 0: linear range */ if (has_group_names) { of_property_read_string_index(np, @@ -1095,27 +1178,27 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) } /* Trim the range to fit this GPIO chip */ - if (chip->offset > pinspec.args[0]) { - trim = chip->offset - pinspec.args[0]; - pinspec.args[2] -= trim; - pinspec.args[1] += trim; - pinspec.args[0] = 0; + if (chip->offset > offset) { + trim = chip->offset - offset; + count -= trim; + pin += trim; + offset = 0; } else { - pinspec.args[0] -= chip->offset; + offset -= chip->offset; } - if ((pinspec.args[0] + pinspec.args[2]) > chip->ngpio) - pinspec.args[2] = chip->ngpio - pinspec.args[0]; + if ((offset + count) > chip->ngpio) + count = chip->ngpio - offset; ret = gpiochip_add_pin_range(chip, pinctrl_dev_get_devname(pctldev), - pinspec.args[0], - pinspec.args[1], - pinspec.args[2]); + offset, + pin, + count); if (ret) return ret; } else { /* npins == 0: special range */ - if (pinspec.args[1]) { + if (pin) { pr_err("%pOF: Illegal gpio-range format.\n", np); break; @@ -1140,7 +1223,7 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) } ret = gpiochip_add_pingroup_range(chip, pctldev, - pinspec.args[0], name); + offset, name); if (ret) return ret; } @@ -1163,8 +1246,14 @@ int of_gpiochip_add(struct gpio_chip *chip) return 0; if (!chip->of_xlate) { - chip->of_gpio_n_cells = 2; - chip->of_xlate = of_gpio_simple_xlate; + if (chip->of_gpio_n_cells == 3) { + if (!chip->of_node_instance_match) + return -EINVAL; + chip->of_xlate = of_gpio_threecell_xlate; + } else { + chip->of_gpio_n_cells = 2; + chip->of_xlate = of_gpio_twocell_xlate; + } } if (chip->of_gpio_n_cells > MAX_PHANDLE_ARGS) |