Index: linux-3.12.13/drivers/gpio/gpiolib.c =================================================================== --- linux-3.12.13.orig/drivers/gpio/gpiolib.c 2014-02-22 15:32:50.000000000 -0600 +++ linux-3.12.13/drivers/gpio/gpiolib.c 2014-04-18 09:25:31.977377592 -0500 @@ -87,7 +87,9 @@ static int gpiod_request(struct gpio_desc *desc, const char *label); static void gpiod_free(struct gpio_desc *desc); static int gpiod_direction_input(struct gpio_desc *desc); +static int gpiod_direction_input_pullup(struct gpio_desc *desc, bool pullup); static int gpiod_direction_output(struct gpio_desc *desc, int value); +static int gpiod_direction_output_pullup(struct gpio_desc *desc, int value, bool pullup); static int gpiod_get_direction(const struct gpio_desc *desc); static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce); static int gpiod_get_value_cansleep(const struct gpio_desc *desc); @@ -1523,11 +1525,19 @@ if (flags & GPIOF_OPEN_SOURCE) set_bit(FLAG_OPEN_SOURCE, &desc->flags); - if (flags & GPIOF_DIR_IN) - err = gpiod_direction_input(desc); - else - err = gpiod_direction_output(desc, - (flags & GPIOF_INIT_HIGH) ? 1 : 0); + if (flags & GPIOF_DIR_IN) { + if (flags & GPIOF_PULLUP) + err = gpiod_direction_input_pullup(desc, (flags & GPIOF_PULLUP) ? true : false); + else + err = gpiod_direction_input(desc); + } else { + if (flags & GPIOF_PULLUP) + err = gpiod_direction_output_pullup(desc, + (flags & GPIOF_INIT_HIGH) ? 1 : 0, (flags & GPIOF_PULLUP) ? true : false); + else + err = gpiod_direction_output(desc, + (flags & GPIOF_INIT_HIGH) ? 1 : 0); + } if (err) goto free_gpio; @@ -1613,6 +1623,71 @@ } EXPORT_SYMBOL_GPL(gpiochip_is_requested); +static int gpiod_direction_input_pullup(struct gpio_desc *desc, bool pullup) +{ + unsigned long flags; + struct gpio_chip *chip; + int status = -EINVAL; + int offset; + + if (!desc || !desc->chip) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + + chip = desc->chip; + if (!chip->get || !chip->direction_input_pullup) { + pr_warn("%s: missing get() or direction_input_pullup() operations\n", + __func__); + return -EIO; + } + + spin_lock_irqsave(&gpio_lock, flags); + + status = gpio_ensure_requested(desc); + if (status < 0) + goto fail; + + /* now we know the gpio is valid and chip won't vanish */ + + spin_unlock_irqrestore(&gpio_lock, flags); + + might_sleep_if(chip->can_sleep); + + offset = gpio_chip_hwgpio(desc); + if (status) { + status = chip->request(chip, offset); + if (status < 0) { + pr_debug("GPIO-%d: chip request fail, %d\n", + desc_to_gpio(desc), status); + /* and it's not available to anyone else ... + * gpio_request() is the fully clean solution. + */ + goto lose; + } + } + + status = chip->direction_input_pullup(chip, offset, pullup); + if (status == 0) + clear_bit(FLAG_IS_OUT, &desc->flags); + + trace_gpio_direction(desc_to_gpio(desc), 1, status); +lose: + return status; +fail: + spin_unlock_irqrestore(&gpio_lock, flags); + if (status) + pr_debug("%s: gpio-%d status %d\n", __func__, + desc_to_gpio(desc), status); + return status; +} + +int gpio_direction_input_pullup(unsigned gpio, bool pullup) +{ + return gpiod_direction_input_pullup(gpio_to_desc(gpio), pullup); +} +EXPORT_SYMBOL_GPL(gpio_direction_input_pullup); + /* Drivers MUST set GPIO direction before making get/set calls. In * some cases this is done in early boot, before IRQs are enabled. @@ -1688,6 +1763,79 @@ } EXPORT_SYMBOL_GPL(gpio_direction_input); +static int gpiod_direction_output_pullup(struct gpio_desc *desc, int value, bool pullup) +{ + unsigned long flags; + struct gpio_chip *chip; + int status = -EINVAL; + int offset; + + if (!desc || !desc->chip) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + + /* Open drain pin should not be driven to 1 */ + if (value && test_bit(FLAG_OPEN_DRAIN, &desc->flags)) + return gpiod_direction_input(desc); + + /* Open source pin should not be driven to 0 */ + if (!value && test_bit(FLAG_OPEN_SOURCE, &desc->flags)) + return gpiod_direction_input(desc); + + chip = desc->chip; + if (!chip->set || !chip->direction_output_pullup) { + pr_warn("%s: missing set() or direction_output_pullup() operations\n", + __func__); + return -EIO; + } + + spin_lock_irqsave(&gpio_lock, flags); + + status = gpio_ensure_requested(desc); + if (status < 0) + goto fail; + + /* now we know the gpio is valid and chip won't vanish */ + + spin_unlock_irqrestore(&gpio_lock, flags); + + might_sleep_if(chip->can_sleep); + + offset = gpio_chip_hwgpio(desc); + if (status) { + status = chip->request(chip, offset); + if (status < 0) { + pr_debug("GPIO-%d: chip request fail, %d\n", + desc_to_gpio(desc), status); + /* and it's not available to anyone else ... + * gpio_request() is the fully clean solution. + */ + goto lose; + } + } + + status = chip->direction_output_pullup(chip, offset, value, pullup); + if (status == 0) + set_bit(FLAG_IS_OUT, &desc->flags); + trace_gpio_value(desc_to_gpio(desc), 0, value); + trace_gpio_direction(desc_to_gpio(desc), 0, status); +lose: + return status; +fail: + spin_unlock_irqrestore(&gpio_lock, flags); + if (status) + pr_debug("%s: gpio-%d status %d\n", __func__, + desc_to_gpio(desc), status); + return status; +} + +int gpio_direction_output_pullup(unsigned gpio, int value, bool pullup) +{ + return gpiod_direction_output_pullup(gpio_to_desc(gpio), value, pullup); +} +EXPORT_SYMBOL_GPL(gpio_direction_output_pullup); + static int gpiod_direction_output(struct gpio_desc *desc, int value) { unsigned long flags; Index: linux-3.12.13/drivers/pinctrl/pinctrl-at91.c =================================================================== --- linux-3.12.13.orig/drivers/pinctrl/pinctrl-at91.c 2014-02-22 15:32:50.000000000 -0600 +++ linux-3.12.13/drivers/pinctrl/pinctrl-at91.c 2014-04-18 09:25:31.985377595 -0500 @@ -1112,6 +1112,17 @@ return 0; } +static int at91_gpio_direction_input_pullup(struct gpio_chip *chip, unsigned offset, bool pullup) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << offset; + + writel_relaxed(mask, pio + PIO_ODR); + at91_mux_set_pullup(pio, mask, pullup); + return 0; +} + static int at91_gpio_get(struct gpio_chip *chip, unsigned offset) { struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); @@ -1146,6 +1157,20 @@ return 0; } +static int at91_gpio_direction_output_pullup(struct gpio_chip *chip, unsigned offset, + int val, bool pullup) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << offset; + + writel_relaxed(mask, pio + (val ? PIO_SODR : PIO_CODR)); + writel_relaxed(mask, pio + PIO_OER); + at91_mux_set_pullup(pio, mask, pullup); + + return 0; +} + static int at91_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); @@ -1513,8 +1538,10 @@ .request = at91_gpio_request, .free = at91_gpio_free, .direction_input = at91_gpio_direction_input, + .direction_input_pullup = at91_gpio_direction_input_pullup, .get = at91_gpio_get, .direction_output = at91_gpio_direction_output, + .direction_output_pullup = at91_gpio_direction_output_pullup, .set = at91_gpio_set, .to_irq = at91_gpio_to_irq, .dbg_show = at91_gpio_dbg_show, Index: linux-3.12.13/include/linux/gpio.h =================================================================== --- linux-3.12.13.orig/include/linux/gpio.h 2014-02-22 15:32:50.000000000 -0600 +++ linux-3.12.13/include/linux/gpio.h 2014-04-18 09:25:31.957377594 -0500 @@ -12,7 +12,10 @@ #define GPIOF_INIT_LOW (0 << 1) #define GPIOF_INIT_HIGH (1 << 1) +#define GPIOF_PULLUP (2 << 0) + #define GPIOF_IN (GPIOF_DIR_IN) +#define GPIOF_IN_PULLUP (GPIOF_DIR_IN | GPIOF_PULLUP) #define GPIOF_OUT_INIT_LOW (GPIOF_DIR_OUT | GPIOF_INIT_LOW) #define GPIOF_OUT_INIT_HIGH (GPIOF_DIR_OUT | GPIOF_INIT_HIGH) Index: linux-3.12.13/include/asm-generic/gpio.h =================================================================== --- linux-3.12.13.orig/include/asm-generic/gpio.h 2014-02-22 15:32:50.000000000 -0600 +++ linux-3.12.13/include/asm-generic/gpio.h 2014-04-18 09:26:42.669377408 -0500 @@ -62,9 +62,11 @@ * @get_direction: returns direction for signal "offset", 0=out, 1=in, * (same as GPIOF_DIR_XXX), or negative error * @direction_input: configures signal "offset" as input, or returns error + * @direction_input_pullup: configures signal "offset" as input with pullup enabled, or returns error * @get: returns value for signal "offset"; for output signals this * returns either the value actually sensed, or zero * @direction_output: configures signal "offset" as output, or returns error + * @direction_output_pullup: configures signal "offset" as output with pullup enabled, or returns error * @set_debounce: optional hook for setting debounce time for specified gpio in * interrupt triggered gpio chips * @set: assigns output value for signal "offset" @@ -111,10 +113,14 @@ unsigned offset); int (*direction_input)(struct gpio_chip *chip, unsigned offset); + int (*direction_input_pullup)(struct gpio_chip *chip, + unsigned offset, bool pullup); int (*get)(struct gpio_chip *chip, unsigned offset); int (*direction_output)(struct gpio_chip *chip, unsigned offset, int value); + int (*direction_output_pullup)(struct gpio_chip *chip, + unsigned offset, int value, bool pullup); int (*set_debounce)(struct gpio_chip *chip, unsigned offset, unsigned debounce); @@ -173,7 +179,9 @@ extern void gpio_free(unsigned gpio); extern int gpio_direction_input(unsigned gpio); +extern int gpio_direction_input_pullup(unsigned gpio, bool pullup); extern int gpio_direction_output(unsigned gpio, int value); +extern int gpio_direction_output_pullup(unsigned gpio, int value, bool pullup); extern int gpio_set_debounce(unsigned gpio, unsigned debounce);