diff options
Diffstat (limited to 'recipes-kernel/linux/files/0015-Quark-GPIO-1-2-quark.patch')
-rw-r--r-- | recipes-kernel/linux/files/0015-Quark-GPIO-1-2-quark.patch | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/recipes-kernel/linux/files/0015-Quark-GPIO-1-2-quark.patch b/recipes-kernel/linux/files/0015-Quark-GPIO-1-2-quark.patch new file mode 100644 index 0000000..ec541dc --- /dev/null +++ b/recipes-kernel/linux/files/0015-Quark-GPIO-1-2-quark.patch @@ -0,0 +1,272 @@ +From xxxx Mon Sep 17 00:00:00 2001 +From: Josef Ahmad <josef.ahmad@linux.intel.com> +Date: Tue, 11 Feb 2014 16:28:26 +0000 +Subject: [PATCH 15/21] Quark GPIO 1/2 + +--- + drivers/gpio/Kconfig | 7 ++- + drivers/gpio/gpiolib.c | 130 ++++++++++++++++++++++++++++++++++++++++++++ + include/asm-generic/gpio.h | 4 ++ + include/linux/gpio.h | 10 ++++ + 4 files changed, 149 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig +index 682de75..afab416 100644 +--- a/drivers/gpio/Kconfig ++++ b/drivers/gpio/Kconfig +@@ -243,13 +243,14 @@ config GPIO_VR41XX + Say yes here to support the NEC VR4100 series General-purpose I/O Uint + + config GPIO_SCH +- tristate "Intel SCH/TunnelCreek/Centerton GPIO" ++ tristate "Intel SCH/TunnelCreek/Centerton/Quark GPIO" + depends on PCI && X86 + select MFD_CORE + select LPC_SCH + help + Say yes here to support GPIO interface on Intel Poulsbo SCH, +- Intel Tunnel Creek processor or Intel Centerton processor. ++ Intel Tunnel Creek processor, Intel Centerton processor or Intel ++ Quark. + The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are + powered by the core power rail and are turned off during sleep + modes (S3 and higher). The remaining four GPIOs are powered by +@@ -261,6 +262,8 @@ config GPIO_SCH + The Intel Centerton processor has a total of 30 GPIO pins. + Twenty-one are powered by the core power rail and 9 from the + suspend power supply. ++ The Intel Quark has 2 GPIOs powered by the core power well and 6 ++ form the suspend power well. + + config GPIO_ICH + tristate "Intel ICH GPIO" +diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c +index 5359ca7..5e897ff 100644 +--- a/drivers/gpio/gpiolib.c ++++ b/drivers/gpio/gpiolib.c +@@ -60,11 +60,17 @@ struct gpio_desc { + #define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */ + #define FLAG_OPEN_DRAIN 8 /* Gpio is open drain type */ + #define FLAG_OPEN_SOURCE 9 /* Gpio is open source type */ ++#define FLAG_PULLUP 10 /* Gpio drive is resistive pullup */ ++#define FLAG_PULLDOWN 11 /* Gpio drive is resistive pulldown */ ++#define FLAG_STRONG 12 /* Gpio drive is strong (fast output) */ ++#define FLAG_HIZ 13 /* Gpio drive is Hi-Z (input) */ + + #define ID_SHIFT 16 /* add new flags before this one */ + + #define GPIO_FLAGS_MASK ((1 << ID_SHIFT) - 1) + #define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE)) ++#define GPIO_DRIVE_MASK (BIT(FLAG_PULLUP) | BIT(FLAG_PULLDOWN) \ ++ | BIT(FLAG_STRONG) | BIT(FLAG_HIZ)) + + #ifdef CONFIG_DEBUG_FS + const char *label; +@@ -243,6 +249,10 @@ static DEFINE_MUTEX(sysfs_lock); + * * is read/write as zero/nonzero + * * also affects existing and subsequent "falling" and "rising" + * /edge configuration ++ * /drive ++ * * sets signal drive mode ++ * * is read/write as "pullup", "pulldown", "strong" or "hiz" ++ * + */ + + static ssize_t gpio_direction_show(struct device *dev, +@@ -573,9 +583,85 @@ static ssize_t gpio_active_low_store(struct device *dev, + static const DEVICE_ATTR(active_low, 0644, + gpio_active_low_show, gpio_active_low_store); + ++static ssize_t gpio_drive_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ const struct gpio_desc *desc = dev_get_drvdata(dev); ++ ssize_t status; ++ ++ mutex_lock(&sysfs_lock); ++ ++ if (!test_bit(FLAG_EXPORT, &desc->flags)) { ++ status = -EIO; ++ } else { ++ if (test_bit(FLAG_PULLUP, &desc->flags)) ++ status = sprintf(buf, "pullup\n"); ++ else if (test_bit(FLAG_PULLDOWN, &desc->flags)) ++ status = sprintf(buf, "pulldown\n"); ++ else if (test_bit(FLAG_STRONG, &desc->flags)) ++ status = sprintf(buf, "strong\n"); ++ else if (test_bit(FLAG_HIZ, &desc->flags)) ++ status = sprintf(buf, "hiz\n"); ++ else ++ status = -EINVAL; ++ } ++ ++ mutex_unlock(&sysfs_lock); ++ return status; ++} ++ ++static ssize_t gpio_drive_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t size) ++{ ++ struct gpio_desc *desc = dev_get_drvdata(dev); ++ unsigned gpio = desc - gpio_desc; ++ ssize_t status; ++ ++ mutex_lock(&sysfs_lock); ++ ++ if (!test_bit(FLAG_EXPORT, &desc->flags)) ++ status = -EIO; ++ else { ++ if (sysfs_streq(buf, "pullup")) { ++ status = gpio_set_drive(gpio, GPIOF_DRIVE_PULLUP); ++ if (!status) { ++ desc->flags &= ~GPIO_DRIVE_MASK; ++ set_bit(FLAG_PULLUP, &desc->flags); ++ } ++ } else if (sysfs_streq(buf, "pulldown")) { ++ status = gpio_set_drive(gpio, GPIOF_DRIVE_PULLDOWN); ++ if (!status) { ++ desc->flags &= ~GPIO_DRIVE_MASK; ++ set_bit(FLAG_PULLDOWN, &desc->flags); ++ } ++ } else if (sysfs_streq(buf, "strong")) { ++ status = gpio_set_drive(gpio, GPIOF_DRIVE_STRONG); ++ if (!status) { ++ desc->flags &= ~GPIO_DRIVE_MASK; ++ set_bit(FLAG_STRONG, &desc->flags); ++ } ++ } else if (sysfs_streq(buf, "hiz")) { ++ status = gpio_set_drive(gpio, GPIOF_DRIVE_HIZ); ++ if (!status) { ++ desc->flags &= ~GPIO_DRIVE_MASK; ++ set_bit(FLAG_HIZ, &desc->flags); ++ } ++ } else { ++ status = -EINVAL; ++ } ++ } ++ ++ mutex_unlock(&sysfs_lock); ++ return status ? : size; ++} ++ ++static const DEVICE_ATTR(drive, 0644, ++ gpio_drive_show, gpio_drive_store); ++ + static const struct attribute *gpio_attrs[] = { + &dev_attr_value.attr, + &dev_attr_active_low.attr, ++ &dev_attr_drive.attr, + NULL, + }; + +@@ -1677,6 +1763,50 @@ fail: + } + EXPORT_SYMBOL_GPL(gpio_set_debounce); + ++/** ++ * gpio_set_drive - sets drive @mode for a @gpio ++ * @gpio: the gpio to set the drive mode ++ * @mode: the drive mode ++ */ ++int gpio_set_drive(unsigned gpio, unsigned mode) ++{ ++ unsigned long flags; ++ struct gpio_chip *chip; ++ struct gpio_desc *desc = &gpio_desc[gpio]; ++ int status = -EINVAL; ++ ++ spin_lock_irqsave(&gpio_lock, flags); ++ ++ if (!gpio_is_valid(gpio)) ++ goto fail; ++ chip = desc->chip; ++ if (!chip || !chip->set || !chip->set_drive) ++ goto fail; ++ gpio -= chip->base; ++ if (gpio >= chip->ngpio) ++ goto fail; ++ status = gpio_ensure_requested(desc, gpio); ++ 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); ++ ++ return chip->set_drive(chip, gpio, mode); ++ ++fail: ++ spin_unlock_irqrestore(&gpio_lock, flags); ++ if (status) ++ pr_debug("%s: gpio-%d status %d\n", ++ __func__, gpio, status); ++ ++ return status; ++} ++EXPORT_SYMBOL_GPL(gpio_set_drive); ++ + /* I/O calls are only valid after configuration completed; the relevant + * "is this a valid GPIO" error checks should already have been done. + * +diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h +index 20ca766..8265ccc 100644 +--- a/include/asm-generic/gpio.h ++++ b/include/asm-generic/gpio.h +@@ -65,6 +65,7 @@ struct device_node; + * @direction_output: configures signal "offset" as output, or returns error + * @set_debounce: optional hook for setting debounce time for specified gpio in + * interrupt triggered gpio chips ++ * @set_drive: optional hook for setting the drive signal for "offset" + * @set: assigns output value for signal "offset" + * @to_irq: optional hook supporting non-static gpio_to_irq() mappings; + * implementation may not sleep +@@ -113,6 +114,8 @@ struct gpio_chip { + unsigned offset, int value); + int (*set_debounce)(struct gpio_chip *chip, + unsigned offset, unsigned debounce); ++ int (*set_drive)(struct gpio_chip *chip, ++ unsigned offset, unsigned mode); + + void (*set)(struct gpio_chip *chip, + unsigned offset, int value); +@@ -172,6 +175,7 @@ extern int gpio_direction_input(unsigned gpio); + extern int gpio_direction_output(unsigned gpio, int value); + + extern int gpio_set_debounce(unsigned gpio, unsigned debounce); ++extern int gpio_set_drive(unsigned gpio, unsigned mode); + + extern int gpio_get_value_cansleep(unsigned gpio); + extern void gpio_set_value_cansleep(unsigned gpio, int value); +diff --git a/include/linux/gpio.h b/include/linux/gpio.h +index bfe6656..cadd9d2 100644 +--- a/include/linux/gpio.h ++++ b/include/linux/gpio.h +@@ -27,6 +27,11 @@ + #define GPIOF_EXPORT_DIR_FIXED (GPIOF_EXPORT) + #define GPIOF_EXPORT_DIR_CHANGEABLE (GPIOF_EXPORT | GPIOF_EXPORT_CHANGEABLE) + ++#define GPIOF_DRIVE_PULLUP (1 << 6) ++#define GPIOF_DRIVE_PULLDOWN (1 << 7) ++#define GPIOF_DRIVE_STRONG (1 << 8) ++#define GPIOF_DRIVE_HIZ (1 << 9) ++ + /** + * struct gpio - a structure describing a GPIO with configuration + * @gpio: the GPIO number +@@ -156,6 +161,11 @@ static inline int gpio_set_debounce(unsigned gpio, unsigned debounce) + return -ENOSYS; + } + ++static inline int gpio_set_drive(unsigned gpio, unsigned mode) ++{ ++ return -ENOSYS; ++} ++ + static inline int gpio_get_value(unsigned gpio) + { + /* GPIO can never have been requested or set as {in,out}put */ +-- +1.7.4.1 + |