aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpiolib-of.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio/gpiolib-of.c')
-rw-r--r--drivers/gpio/gpiolib-of.c204
1 files changed, 91 insertions, 113 deletions
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 0ad288ab6262..0e4e1291604d 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -289,6 +289,36 @@ int of_get_named_gpio_flags(const struct device_node *np, const char *list_name,
}
EXPORT_SYMBOL_GPL(of_get_named_gpio_flags);
+/* Converts gpio_lookup_flags into bitmask of GPIO_* values */
+static unsigned long of_convert_gpio_flags(enum of_gpio_flags flags)
+{
+ unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
+
+ if (flags & OF_GPIO_ACTIVE_LOW)
+ lflags |= GPIO_ACTIVE_LOW;
+
+ if (flags & OF_GPIO_SINGLE_ENDED) {
+ if (flags & OF_GPIO_OPEN_DRAIN)
+ lflags |= GPIO_OPEN_DRAIN;
+ else
+ lflags |= GPIO_OPEN_SOURCE;
+ }
+
+ if (flags & OF_GPIO_TRANSITORY)
+ lflags |= GPIO_TRANSITORY;
+
+ if (flags & OF_GPIO_PULL_UP)
+ lflags |= GPIO_PULL_UP;
+
+ if (flags & OF_GPIO_PULL_DOWN)
+ lflags |= GPIO_PULL_DOWN;
+
+ if (flags & OF_GPIO_PULL_DISABLE)
+ lflags |= GPIO_PULL_DISABLE;
+
+ return lflags;
+}
+
/**
* gpiod_get_from_of_node() - obtain a GPIO from an OF node
* @node: handle of the OF node
@@ -308,26 +338,14 @@ struct gpio_desc *gpiod_get_from_of_node(const struct device_node *node,
enum gpiod_flags dflags,
const char *label)
{
- unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
+ unsigned long lflags;
struct gpio_desc *desc;
- enum of_gpio_flags flags;
- bool active_low = false;
- bool single_ended = false;
- bool open_drain = false;
- bool transitory = false;
+ enum of_gpio_flags of_flags;
int ret;
- desc = of_get_named_gpiod_flags(node, propname,
- index, &flags);
-
- if (!desc || IS_ERR(desc)) {
+ desc = of_get_named_gpiod_flags(node, propname, index, &of_flags);
+ if (!desc || IS_ERR(desc))
return desc;
- }
-
- active_low = flags & OF_GPIO_ACTIVE_LOW;
- single_ended = flags & OF_GPIO_SINGLE_ENDED;
- open_drain = flags & OF_GPIO_OPEN_DRAIN;
- transitory = flags & OF_GPIO_TRANSITORY;
ret = gpiod_request(desc, label);
if (ret == -EBUSY && (dflags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
@@ -335,24 +353,7 @@ struct gpio_desc *gpiod_get_from_of_node(const struct device_node *node,
if (ret)
return ERR_PTR(ret);
- if (active_low)
- lflags |= GPIO_ACTIVE_LOW;
-
- if (single_ended) {
- if (open_drain)
- lflags |= GPIO_OPEN_DRAIN;
- else
- lflags |= GPIO_OPEN_SOURCE;
- }
-
- if (transitory)
- lflags |= GPIO_TRANSITORY;
-
- if (flags & OF_GPIO_PULL_UP)
- lflags |= GPIO_PULL_UP;
-
- if (flags & OF_GPIO_PULL_DOWN)
- lflags |= GPIO_PULL_DOWN;
+ lflags = of_convert_gpio_flags(of_flags);
ret = gpiod_configure_flags(desc, propname, lflags, dflags);
if (ret < 0) {
@@ -369,12 +370,12 @@ EXPORT_SYMBOL_GPL(gpiod_get_from_of_node);
* properties should be named "foo-gpios" so we have this special kludge for
* them.
*/
-static struct gpio_desc *of_find_spi_gpio(struct device *dev, const char *con_id,
+static struct gpio_desc *of_find_spi_gpio(struct device_node *np,
+ const char *con_id,
+ unsigned int idx,
enum of_gpio_flags *of_flags)
{
char prop_name[32]; /* 32 is max size of property name */
- const struct device_node *np = dev->of_node;
- struct gpio_desc *desc;
/*
* Hopefully the compiler stubs the rest of the function if this
@@ -390,8 +391,7 @@ static struct gpio_desc *of_find_spi_gpio(struct device *dev, const char *con_id
/* Will be "gpio-sck", "gpio-mosi" or "gpio-miso" */
snprintf(prop_name, sizeof(prop_name), "%s-%s", "gpio", con_id);
- desc = of_get_named_gpiod_flags(np, prop_name, 0, of_flags);
- return desc;
+ return of_get_named_gpiod_flags(np, prop_name, idx, of_flags);
}
/*
@@ -399,13 +399,11 @@ static struct gpio_desc *of_find_spi_gpio(struct device *dev, const char *con_id
* lines rather than "cs-gpios" like all other SPI hardware. Account for this
* with a special quirk.
*/
-static struct gpio_desc *of_find_spi_cs_gpio(struct device *dev,
+static struct gpio_desc *of_find_spi_cs_gpio(struct device_node *np,
const char *con_id,
unsigned int idx,
- unsigned long *flags)
+ enum of_gpio_flags *of_flags)
{
- const struct device_node *np = dev->of_node;
-
if (!IS_ENABLED(CONFIG_SPI_MASTER))
return ERR_PTR(-ENOENT);
@@ -423,7 +421,7 @@ static struct gpio_desc *of_find_spi_cs_gpio(struct device *dev,
* uses just "gpios" so translate to that when "cs-gpios" is
* requested.
*/
- return of_find_gpio(dev, NULL, idx, flags);
+ return of_get_named_gpiod_flags(np, "gpios", idx, of_flags);
}
/*
@@ -431,7 +429,9 @@ static struct gpio_desc *of_find_spi_cs_gpio(struct device *dev,
* properties should be named "foo-gpios" so we have this special kludge for
* them.
*/
-static struct gpio_desc *of_find_regulator_gpio(struct device *dev, const char *con_id,
+static struct gpio_desc *of_find_regulator_gpio(struct device_node *np,
+ const char *con_id,
+ unsigned int idx,
enum of_gpio_flags *of_flags)
{
/* These are the connection IDs we accept as legacy GPIO phandles */
@@ -440,8 +440,6 @@ static struct gpio_desc *of_find_regulator_gpio(struct device *dev, const char *
"wlf,ldo1ena", /* WM8994 */
"wlf,ldo2ena", /* WM8994 */
};
- const struct device_node *np = dev->of_node;
- struct gpio_desc *desc;
int i;
if (!IS_ENABLED(CONFIG_REGULATOR))
@@ -454,12 +452,12 @@ static struct gpio_desc *of_find_regulator_gpio(struct device *dev, const char *
if (i < 0)
return ERR_PTR(-ENOENT);
- desc = of_get_named_gpiod_flags(np, con_id, 0, of_flags);
- return desc;
+ return of_get_named_gpiod_flags(np, con_id, idx, of_flags);
}
-static struct gpio_desc *of_find_arizona_gpio(struct device *dev,
+static struct gpio_desc *of_find_arizona_gpio(struct device_node *np,
const char *con_id,
+ unsigned int idx,
enum of_gpio_flags *of_flags)
{
if (!IS_ENABLED(CONFIG_MFD_ARIZONA))
@@ -468,17 +466,18 @@ static struct gpio_desc *of_find_arizona_gpio(struct device *dev,
if (!con_id || strcmp(con_id, "wlf,reset"))
return ERR_PTR(-ENOENT);
- return of_get_named_gpiod_flags(dev->of_node, con_id, 0, of_flags);
+ return of_get_named_gpiod_flags(np, con_id, idx, of_flags);
}
-static struct gpio_desc *of_find_usb_gpio(struct device *dev,
+static struct gpio_desc *of_find_usb_gpio(struct device_node *np,
const char *con_id,
+ unsigned int idx,
enum of_gpio_flags *of_flags)
{
/*
- * Currently this USB quirk is only for the Fairchild FUSB302 host which is using
- * an undocumented DT GPIO line named "fcs,int_n" without the compulsory "-gpios"
- * suffix.
+ * Currently this USB quirk is only for the Fairchild FUSB302 host
+ * which is using an undocumented DT GPIO line named "fcs,int_n"
+ * without the compulsory "-gpios" suffix.
*/
if (!IS_ENABLED(CONFIG_TYPEC_FUSB302))
return ERR_PTR(-ENOENT);
@@ -486,14 +485,28 @@ static struct gpio_desc *of_find_usb_gpio(struct device *dev,
if (!con_id || strcmp(con_id, "fcs,int_n"))
return ERR_PTR(-ENOENT);
- return of_get_named_gpiod_flags(dev->of_node, con_id, 0, of_flags);
+ return of_get_named_gpiod_flags(np, con_id, idx, of_flags);
}
+typedef struct gpio_desc *(*of_find_gpio_quirk)(struct device_node *np,
+ const char *con_id,
+ unsigned int idx,
+ enum of_gpio_flags *of_flags);
+static const of_find_gpio_quirk of_find_gpio_quirks[] = {
+ of_find_spi_gpio,
+ of_find_spi_cs_gpio,
+ of_find_regulator_gpio,
+ of_find_arizona_gpio,
+ of_find_usb_gpio,
+ NULL
+};
+
struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
unsigned int idx, unsigned long *flags)
{
char prop_name[32]; /* 32 is max size of property name */
enum of_gpio_flags of_flags;
+ const of_find_gpio_quirk *q;
struct gpio_desc *desc;
unsigned int i;
@@ -513,49 +526,14 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
break;
}
- if (gpiod_not_found(desc)) {
- /* Special handling for SPI GPIOs if used */
- desc = of_find_spi_gpio(dev, con_id, &of_flags);
- }
-
- if (gpiod_not_found(desc)) {
- /* This quirk looks up flags and all */
- desc = of_find_spi_cs_gpio(dev, con_id, idx, flags);
- if (!IS_ERR(desc))
- return desc;
- }
-
- if (gpiod_not_found(desc)) {
- /* Special handling for regulator GPIOs if used */
- desc = of_find_regulator_gpio(dev, con_id, &of_flags);
- }
-
- if (gpiod_not_found(desc))
- desc = of_find_arizona_gpio(dev, con_id, &of_flags);
-
- if (gpiod_not_found(desc))
- desc = of_find_usb_gpio(dev, con_id, &of_flags);
+ /* Properly named GPIO was not found, try workarounds */
+ for (q = of_find_gpio_quirks; gpiod_not_found(desc) && *q; q++)
+ desc = (*q)(dev->of_node, con_id, idx, &of_flags);
if (IS_ERR(desc))
return desc;
- if (of_flags & OF_GPIO_ACTIVE_LOW)
- *flags |= GPIO_ACTIVE_LOW;
-
- if (of_flags & OF_GPIO_SINGLE_ENDED) {
- if (of_flags & OF_GPIO_OPEN_DRAIN)
- *flags |= GPIO_OPEN_DRAIN;
- else
- *flags |= GPIO_OPEN_SOURCE;
- }
-
- if (of_flags & OF_GPIO_TRANSITORY)
- *flags |= GPIO_TRANSITORY;
-
- if (of_flags & OF_GPIO_PULL_UP)
- *flags |= GPIO_PULL_UP;
- if (of_flags & OF_GPIO_PULL_DOWN)
- *flags |= GPIO_PULL_DOWN;
+ *flags = of_convert_gpio_flags(of_flags);
return desc;
}
@@ -613,14 +591,7 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
if (IS_ERR(desc))
return desc;
- if (xlate_flags & OF_GPIO_ACTIVE_LOW)
- *lflags |= GPIO_ACTIVE_LOW;
- if (xlate_flags & OF_GPIO_TRANSITORY)
- *lflags |= GPIO_TRANSITORY;
- if (xlate_flags & OF_GPIO_PULL_UP)
- *lflags |= GPIO_PULL_UP;
- if (xlate_flags & OF_GPIO_PULL_DOWN)
- *lflags |= GPIO_PULL_DOWN;
+ *lflags = of_convert_gpio_flags(xlate_flags);
if (of_property_read_bool(np, "input"))
*dflags |= GPIOD_IN;
@@ -711,19 +682,16 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip)
static void of_gpiochip_remove_hog(struct gpio_chip *chip,
struct device_node *hog)
{
- struct gpio_desc *descs = chip->gpiodev->descs;
- unsigned int i;
+ struct gpio_desc *desc;
- for (i = 0; i < chip->ngpio; i++) {
- if (test_bit(FLAG_IS_HOGGED, &descs[i].flags) &&
- descs[i].hog == hog)
- gpiochip_free_own_desc(&descs[i]);
- }
+ for_each_gpio_desc_with_flag(chip, desc, FLAG_IS_HOGGED)
+ if (desc->hog == hog)
+ gpiochip_free_own_desc(desc);
}
static int of_gpiochip_match_node(struct gpio_chip *chip, void *data)
{
- return chip->gpiodev->dev.of_node == data;
+ return device_match_of_node(&chip->gpiodev->dev, data);
}
static struct gpio_chip *of_find_gpiochip_by_node(struct device_node *np)
@@ -863,7 +831,8 @@ int of_mm_gpiochip_add_data(struct device_node *np,
if (mm_gc->save_regs)
mm_gc->save_regs(mm_gc);
- mm_gc->gc.of_node = np;
+ of_node_put(mm_gc->gc.of_node);
+ mm_gc->gc.of_node = of_node_get(np);
ret = gpiochip_add_data(gc, data);
if (ret)
@@ -871,6 +840,7 @@ int of_mm_gpiochip_add_data(struct device_node *np,
return 0;
err2:
+ of_node_put(np);
iounmap(mm_gc->regs);
err1:
kfree(gc->label);
@@ -912,7 +882,7 @@ static void of_gpiochip_init_valid_mask(struct gpio_chip *chip)
i, &start);
of_property_read_u32_index(np, "gpio-reserved-ranges",
i + 1, &count);
- if (start >= chip->ngpio || start + count >= chip->ngpio)
+ if (start >= chip->ngpio || start + count > chip->ngpio)
continue;
bitmap_clear(chip->valid_mask, start, count);
@@ -933,6 +903,11 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip)
if (!np)
return 0;
+ if (!of_property_read_bool(np, "gpio-ranges") &&
+ chip->of_gpio_ranges_fallback) {
+ return chip->of_gpio_ranges_fallback(chip, np);
+ }
+
group_names = of_find_property(np, group_names_propname, NULL);
for (;; index++) {
@@ -1046,6 +1021,9 @@ void of_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev)
if (gc->parent)
gdev->dev.of_node = gc->parent->of_node;
+ if (gc->fwnode)
+ gc->of_node = to_of_node(gc->fwnode);
+
/* If the gpiochip has an assigned OF node this takes precedence */
if (gc->of_node)
gdev->dev.of_node = gc->of_node;