diff --git a/drivers/gpio/gpio-imx.c b/drivers/gpio/gpio-imx.c index bfb0119..d8bcea2 100644 --- a/drivers/gpio/gpio-imx.c +++ b/drivers/gpio/gpio-imx.c @@ -93,7 +93,7 @@ void __iomem *base = imxgpio->base; u32 val; - gpio_set_value(gpio + chip->base, value); + imx_gpio_set_value(chip, gpio, value); val = readl(base + imxgpio->regs->gdir); val |= 1 << gpio; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 1f57c76..a3e17ad 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -13,6 +14,7 @@ struct gpio_info { struct gpio_chip *chip; bool requested; + bool active_low; char *label; }; @@ -45,6 +47,15 @@ return NULL; } +static int gpio_adjust_value(struct gpio_info *gi, + int value) +{ + if (value < 0) + return value; + + return !!value ^ gi->active_low; +} + int gpio_request(unsigned gpio, const char *label) { struct gpio_info *gi = gpio_to_desc(gpio); @@ -69,6 +80,7 @@ } gi->requested = true; + gi->active_low = false; gi->label = xstrdup(label); done: @@ -93,6 +105,7 @@ gi->chip->ops->free(gi->chip, gpio - gi->chip->base); gi->requested = false; + gi->active_low = false; free(gi->label); gi->label = NULL; } @@ -111,11 +124,20 @@ if (err) return err; - if (flags & GPIOF_DIR_IN) + if (flags & GPIOF_ACTIVE_LOW) { + struct gpio_info *gi = gpio_to_desc(gpio); + gi->active_low = true; + } + + if (flags & GPIOF_DIR_IN) { err = gpio_direction_input(gpio); - else + } else if (flags & GPIOF_LOGICAL) { + err = gpio_direction_active(gpio, + !!(flags & GPIOF_INIT_ACTIVE)); + } else { err = gpio_direction_output(gpio, - (flags & GPIOF_INIT_HIGH) ? 1 : 0); + !!(flags & GPIOF_INIT_HIGH)); + } if (err) goto free_gpio; @@ -178,6 +200,13 @@ } EXPORT_SYMBOL(gpio_set_value); +void gpio_set_active(unsigned gpio, bool value) +{ + struct gpio_info *gi = gpio_to_desc(gpio); + gpio_set_value(gpio, gpio_adjust_value(gi, value)); +} +EXPORT_SYMBOL(gpio_set_active); + int gpio_get_value(unsigned gpio) { struct gpio_info *gi = gpio_to_desc(gpio); @@ -196,6 +225,13 @@ } EXPORT_SYMBOL(gpio_get_value); +int gpio_is_active(unsigned gpio) +{ + struct gpio_info *gi = gpio_to_desc(gpio); + return gpio_adjust_value(gi, gpio_get_value(gpio)); +} +EXPORT_SYMBOL(gpio_is_active); + int gpio_direction_output(unsigned gpio, int value) { struct gpio_info *gi = gpio_to_desc(gpio); @@ -215,6 +251,13 @@ } EXPORT_SYMBOL(gpio_direction_output); +int gpio_direction_active(unsigned gpio, bool value) +{ + struct gpio_info *gi = gpio_to_desc(gpio); + return gpio_direction_output(gpio, gpio_adjust_value(gi, value)); +} +EXPORT_SYMBOL(gpio_direction_active); + int gpio_direction_input(unsigned gpio) { struct gpio_info *gi = gpio_to_desc(gpio); @@ -262,6 +305,99 @@ return base; } +static int of_hog_gpio(struct device_node *np, struct gpio_chip *chip, + unsigned int idx) +{ + struct device_node *chip_np = chip->dev->device_node; + unsigned long flags = 0; + u32 gpio_cells, gpio_num, gpio_flags; + int ret, gpio; + const char *name = NULL; + + ret = of_property_read_u32(chip_np, "#gpio-cells", &gpio_cells); + if (ret) + return ret; + + /* + * Support for GPIOs that don't have #gpio-cells set to 2 is + * not implemented + */ + if (WARN_ON(gpio_cells != 2)) + return -ENOTSUPP; + + ret = of_property_read_u32_index(np, "gpios", idx * gpio_cells, + &gpio_num); + if (ret) + return ret; + + ret = of_property_read_u32_index(np, "gpios", idx * gpio_cells + 1, + &gpio_flags); + if (ret) + return ret; + + if (gpio_flags & OF_GPIO_ACTIVE_LOW) + flags |= GPIOF_ACTIVE_LOW; + + gpio = gpio_get_num(chip->dev, gpio_num); + if (ret == -EPROBE_DEFER) + return ret; + + if (ret < 0) { + dev_err(chip->dev, "unable to get gpio %u\n", gpio_num); + return ret; + } + + + /* + * Note that, in order to be compatible with Linux, the code + * below interprets 'output-high' as to mean 'output-active'. + * That is, when processed for active-low GPIO, it will result + * in output being asserted logically 'active', but physically + * 'low'. + * + * Conversely it means that specifying 'output-low' for + * 'active-low' GPIO would result in 'high' level observed on + * the corresponding pin + * + */ + if (of_property_read_bool(np, "input")) + flags |= GPIOF_DIR_IN; + else if (of_property_read_bool(np, "output-low")) + flags |= GPIOF_OUT_INIT_INACTIVE; + else if (of_property_read_bool(np, "output-high")) + flags |= GPIOF_OUT_INIT_ACTIVE; + else + return -EINVAL; + + of_property_read_string(np, "line-name", &name); + + return gpio_request_one(gpio, flags, name); +} + +static int of_gpiochip_scan_hogs(struct gpio_chip *chip) +{ + struct device_node *np; + int ret, i; + + for_each_available_child_of_node(chip->dev->device_node, np) { + if (!of_property_read_bool(np, "gpio-hog")) + continue; + + for (ret = 0, i = 0; + !ret; + ret = of_hog_gpio(np, chip, i), i++) + ; + /* + * We ignore -EOVERFLOW because it serves us as an + * indicator that there's no more GPIOs to handle. + */ + if (ret < 0 && ret != -EOVERFLOW) + return ret; + } + + return 0; +} + int gpiochip_add(struct gpio_chip *chip) { int base, i; @@ -280,7 +416,7 @@ for (i = chip->base; i < chip->base + chip->ngpio; i++) gpio_desc[i].chip = chip; - return 0; + return of_gpiochip_scan_hogs(chip); } void gpiochip_remove(struct gpio_chip *chip) @@ -334,7 +470,7 @@ printf(" GPIO %*d: %*s %*s %*s %s\n", 4, i, 3, (dir < 0) ? "unk" : ((dir == GPIOF_DIR_IN) ? "in" : "out"), 3, (val < 0) ? "unk" : ((val == 0) ? "lo" : "hi"), - 9, gi->requested ? "true" : "false", + 12, gi->requested ? (gi->active_low ? "active low" : "true") : "false", (gi->requested && gi->label) ? gi->label : ""); } diff --git a/drivers/phy/usb-nop-xceiv.c b/drivers/phy/usb-nop-xceiv.c index d403fe4..b124e6c 100644 --- a/drivers/phy/usb-nop-xceiv.c +++ b/drivers/phy/usb-nop-xceiv.c @@ -22,12 +22,15 @@ #include #include #include +#include +#include struct nop_usbphy { struct usb_phy usb_phy; struct phy *phy; struct phy_provider *provider; struct clk *clk; + int reset; }; static struct phy *nop_usbphy_xlate(struct device_d *dev, @@ -40,9 +43,22 @@ static int nop_usbphy_init(struct phy *phy) { + int ret; struct nop_usbphy *nopphy = phy_get_drvdata(phy); - return clk_enable(nopphy->clk); + ret = clk_enable(nopphy->clk); + if (ret < 0) + return ret; + + if (gpio_is_valid(nopphy->reset)) { + /* + * Let's wait for 100 ms before deasserting reset line + */ + mdelay(100); + gpio_set_active(nopphy->reset, false); + } + + return 0; } static struct usb_phy *nop_usbphy_to_usbphy(struct phy *phy) @@ -61,6 +77,9 @@ { int ret; struct nop_usbphy *nopphy; + enum of_gpio_flags of_flags; + char *name = NULL; + unsigned long flags = GPIOF_OUT_INIT_ACTIVE; nopphy = xzalloc(sizeof(*nopphy)); @@ -70,6 +89,20 @@ if (IS_ERR(nopphy->clk)) nopphy->clk = NULL; + nopphy->reset = of_get_named_gpio_flags(dev->device_node, + "reset-gpios", 0, &of_flags); + if (gpio_is_valid(nopphy->reset)) { + /* assert reset */ + + if (of_flags & OF_GPIO_ACTIVE_LOW) + flags |= GPIOF_ACTIVE_LOW; + + name = basprintf("%s reset", dev_name(dev)); + ret = gpio_request_one(nopphy->reset, flags, name); + if (ret < 0) + goto err_free; + } + /* FIXME: Add vbus regulator support */ /* FIXME: Add vbus-detect-gpio support */ @@ -77,7 +110,7 @@ nopphy->phy = phy_create(dev, NULL, &nop_phy_ops, NULL); if (IS_ERR(nopphy->phy)) { ret = PTR_ERR(nopphy->phy); - goto err_free; + goto release_gpio; } phy_set_drvdata(nopphy->phy, nopphy); @@ -85,13 +118,17 @@ nopphy->provider = of_phy_provider_register(dev, nop_usbphy_xlate); if (IS_ERR(nopphy->provider)) { ret = PTR_ERR(nopphy->provider); - goto err_free; + goto release_gpio; } return 0; + +release_gpio: + if (gpio_is_valid(nopphy->reset)) + gpio_free(nopphy->reset); err_free: free(nopphy); - + free(name); return ret; }; diff --git a/include/gpio.h b/include/gpio.h index 7b3f512..56aae22 100644 --- a/include/gpio.h +++ b/include/gpio.h @@ -6,6 +6,11 @@ int gpio_get_value(unsigned gpio); int gpio_direction_output(unsigned gpio, int value); int gpio_direction_input(unsigned gpio); + +void gpio_set_active(unsigned gpio, bool state); +int gpio_is_active(unsigned gpio); +int gpio_direction_active(unsigned gpio, bool state); + #else static inline void gpio_set_value(unsigned gpio, int value) { @@ -22,6 +27,18 @@ { return -EINVAL; } + +static inline void gpio_set_active(unsigned gpio, int value) +{ +} +static inline int gpio_is_active(unsigned gpio) +{ + return 0; +} +static inline int gpio_direction_active(unsigned gpio, int value) +{ + return -EINVAL; +} #endif #define ARCH_NR_GPIOS 256 @@ -45,6 +62,14 @@ #define GPIOF_OUT_INIT_LOW (GPIOF_DIR_OUT | GPIOF_INIT_LOW) #define GPIOF_OUT_INIT_HIGH (GPIOF_DIR_OUT | GPIOF_INIT_HIGH) +#define GPIOF_LOGICAL BIT(2) +#define GPIOF_ACTIVE_HIGH GPIOF_LOGICAL +#define GPIOF_ACTIVE_LOW (BIT(3) | GPIOF_LOGICAL) +#define GPIOF_INIT_INACTIVE GPIOF_LOGICAL +#define GPIOF_INIT_ACTIVE (GPIOF_LOGICAL | GPIOF_INIT_HIGH) +#define GPIOF_OUT_INIT_ACTIVE (GPIOF_DIR_OUT | GPIOF_INIT_ACTIVE) +#define GPIOF_OUT_INIT_INACTIVE (GPIOF_DIR_OUT | GPIOF_INIT_INACTIVE) + /** * struct gpio - a structure describing a GPIO with configuration * @gpio: the GPIO number