aboutsummaryrefslogtreecommitdiffstats
path: root/recipes-kernel/linux/files/0015-Quark-GPIO-1-2-quark.patch
diff options
context:
space:
mode:
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.patch442
1 files changed, 432 insertions, 10 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
index ec541dc..4fabc14 100644
--- a/recipes-kernel/linux/files/0015-Quark-GPIO-1-2-quark.patch
+++ b/recipes-kernel/linux/files/0015-Quark-GPIO-1-2-quark.patch
@@ -1,17 +1,18 @@
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
+Date: Wed, 9 Apr 2014 16:57:30 +0100
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(-)
+ drivers/gpio/Kconfig | 9 +-
+ drivers/gpio/gpio-pca953x.c | 235 ++++++++++++++++++++++++++++++++++----------
+ drivers/gpio/gpiolib.c | 130 ++++++++++++++++++++++++
+ include/asm-generic/gpio.h | 4 +
+ include/linux/gpio.h | 10 ++
+ 5 files changed, 332 insertions(+), 56 deletions(-)
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
-index 682de75..afab416 100644
+index 682de75..447e51a 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -243,13 +243,14 @@ config GPIO_VR41XX
@@ -40,6 +41,430 @@ index 682de75..afab416 100644
config GPIO_ICH
tristate "Intel ICH GPIO"
+@@ -363,7 +366,7 @@ config GPIO_PCA953X
+
+ config GPIO_PCA953X_IRQ
+ bool "Interrupt controller support for PCA953x"
+- depends on GPIO_PCA953X=y
++ depends on GPIO_PCA953X
+ help
+ Say yes here to enable the pca953x to be used as an interrupt
+ controller. It requires the driver to be built in the kernel.
+diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
+index cc102d2..6ac3b87 100644
+--- a/drivers/gpio/gpio-pca953x.c
++++ b/drivers/gpio/gpio-pca953x.c
+@@ -29,6 +29,12 @@
+ #define PCA953X_INVERT 2
+ #define PCA953X_DIRECTION 3
+
++#define PCAL953X_IN_LATCH 34
++#define PCAL953X_PUPD_EN 35
++#define PCAL953X_PUPD_SEL 36
++#define PCAL953X_INT_MASK 37
++#define PCAL953X_INT_STAT 38
++
+ #define REG_ADDR_AI 0x80
+
+ #define PCA957X_IN 0
+@@ -44,29 +50,32 @@
+ #define PCA_INT 0x0100
+ #define PCA953X_TYPE 0x1000
+ #define PCA957X_TYPE 0x2000
++#define PCAL953X_TYPE 0x4000
++
+
+ static const struct i2c_device_id pca953x_id[] = {
+- { "pca9534", 8 | PCA953X_TYPE | PCA_INT, },
+- { "pca9535", 16 | PCA953X_TYPE | PCA_INT, },
+- { "pca9536", 4 | PCA953X_TYPE, },
+- { "pca9537", 4 | PCA953X_TYPE | PCA_INT, },
+- { "pca9538", 8 | PCA953X_TYPE | PCA_INT, },
+- { "pca9539", 16 | PCA953X_TYPE | PCA_INT, },
+- { "pca9554", 8 | PCA953X_TYPE | PCA_INT, },
+- { "pca9555", 16 | PCA953X_TYPE | PCA_INT, },
+- { "pca9556", 8 | PCA953X_TYPE, },
+- { "pca9557", 8 | PCA953X_TYPE, },
+- { "pca9574", 8 | PCA957X_TYPE | PCA_INT, },
+- { "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
+-
+- { "max7310", 8 | PCA953X_TYPE, },
+- { "max7312", 16 | PCA953X_TYPE | PCA_INT, },
+- { "max7313", 16 | PCA953X_TYPE | PCA_INT, },
+- { "max7315", 8 | PCA953X_TYPE | PCA_INT, },
+- { "pca6107", 8 | PCA953X_TYPE | PCA_INT, },
+- { "tca6408", 8 | PCA953X_TYPE | PCA_INT, },
+- { "tca6416", 16 | PCA953X_TYPE | PCA_INT, },
+- { "tca6424", 24 | PCA953X_TYPE | PCA_INT, },
++ { "pca9534", 8 | PCA953X_TYPE | PCA_INT, },
++ { "pca9535", 16 | PCA953X_TYPE | PCA_INT, },
++ { "pca9536", 4 | PCA953X_TYPE, },
++ { "pca9537", 4 | PCA953X_TYPE | PCA_INT, },
++ { "pca9538", 8 | PCA953X_TYPE | PCA_INT, },
++ { "pca9539", 16 | PCA953X_TYPE | PCA_INT, },
++ { "pca9554", 8 | PCA953X_TYPE | PCA_INT, },
++ { "pca9555", 16 | PCA953X_TYPE | PCA_INT, },
++ { "pcal9555a", 16 | PCAL953X_TYPE | PCA_INT, },
++ { "pca9556", 8 | PCA953X_TYPE, },
++ { "pca9557", 8 | PCA953X_TYPE, },
++ { "pca9574", 8 | PCA957X_TYPE | PCA_INT, },
++ { "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
++
++ { "max7310", 8 | PCA953X_TYPE, },
++ { "max7312", 16 | PCA953X_TYPE | PCA_INT, },
++ { "max7313", 16 | PCA953X_TYPE | PCA_INT, },
++ { "max7315", 8 | PCA953X_TYPE | PCA_INT, },
++ { "pca6107", 8 | PCA953X_TYPE | PCA_INT, },
++ { "tca6408", 8 | PCA953X_TYPE | PCA_INT, },
++ { "tca6416", 16 | PCA953X_TYPE | PCA_INT, },
++ { "tca6424", 24 | PCA953X_TYPE | PCA_INT, },
+ { }
+ };
+ MODULE_DEVICE_TABLE(i2c, pca953x_id);
+@@ -75,6 +84,8 @@ struct pca953x_chip {
+ unsigned gpio_start;
+ u32 reg_output;
+ u32 reg_direction;
++ u32 reg_pupd_en;
++ u32 reg_pupd_sel;
+ struct mutex i2c_lock;
+
+ #ifdef CONFIG_GPIO_PCA953X_IRQ
+@@ -105,9 +116,9 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
+ (reg << 2) | REG_ADDR_AI,
+ 3,
+ (u8 *) &val);
+- }
+- else {
++ } else {
+ switch (chip->chip_type) {
++ case PCAL953X_TYPE:
+ case PCA953X_TYPE:
+ ret = i2c_smbus_write_word_data(chip->client,
+ reg << 1, val);
+@@ -139,8 +150,7 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val)
+ if (chip->gpio_chip.ngpio <= 8) {
+ ret = i2c_smbus_read_byte_data(chip->client, reg);
+ *val = ret;
+- }
+- else if (chip->gpio_chip.ngpio == 24) {
++ } else if (chip->gpio_chip.ngpio == 24) {
+ *val = 0;
+ ret = i2c_smbus_read_i2c_block_data(chip->client,
+ (reg << 2) | REG_ADDR_AI,
+@@ -172,6 +182,7 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
+ reg_val = chip->reg_direction | (1u << off);
+
+ switch (chip->chip_type) {
++ case PCAL953X_TYPE:
+ case PCA953X_TYPE:
+ offset = PCA953X_DIRECTION;
+ break;
+@@ -207,6 +218,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
+ reg_val = chip->reg_output & ~(1u << off);
+
+ switch (chip->chip_type) {
++ case PCAL953X_TYPE:
+ case PCA953X_TYPE:
+ offset = PCA953X_OUTPUT;
+ break;
+@@ -223,6 +235,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
+ /* then direction */
+ reg_val = chip->reg_direction & ~(1u << off);
+ switch (chip->chip_type) {
++ case PCAL953X_TYPE:
+ case PCA953X_TYPE:
+ offset = PCA953X_DIRECTION;
+ break;
+@@ -251,6 +264,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
+
+ mutex_lock(&chip->i2c_lock);
+ switch (chip->chip_type) {
++ case PCAL953X_TYPE:
+ case PCA953X_TYPE:
+ offset = PCA953X_INPUT;
+ break;
+@@ -286,6 +300,7 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
+ reg_val = chip->reg_output & ~(1u << off);
+
+ switch (chip->chip_type) {
++ case PCAL953X_TYPE:
+ case PCA953X_TYPE:
+ offset = PCA953X_OUTPUT;
+ break;
+@@ -302,6 +317,60 @@ exit:
+ mutex_unlock(&chip->i2c_lock);
+ }
+
++static int pca953x_gpio_set_drive(struct gpio_chip *gc,
++ unsigned off, unsigned mode)
++{
++ struct pca953x_chip *chip;
++ u32 pupd_en_reg_val, pupd_sel_reg_val;
++ int ret = 0;
++
++ chip = container_of(gc, struct pca953x_chip, gpio_chip);
++
++ if (chip->chip_type != PCAL953X_TYPE)
++ return -EINVAL;
++
++ mutex_lock(&chip->i2c_lock);
++
++ switch (mode) {
++ case GPIOF_DRIVE_PULLUP:
++ pupd_en_reg_val = chip->reg_pupd_en | (1u << off);
++ pupd_sel_reg_val = chip->reg_pupd_sel | (1u << off);
++ break;
++ case GPIOF_DRIVE_PULLDOWN:
++ pupd_en_reg_val = chip->reg_pupd_en | (1u << off);
++ pupd_sel_reg_val = chip->reg_pupd_sel & ~(1u << off);
++ break;
++ case GPIOF_DRIVE_STRONG:
++ case GPIOF_DRIVE_HIZ:
++ pupd_en_reg_val = chip->reg_pupd_en & ~(1u << off);
++ pupd_sel_reg_val = chip->reg_pupd_sel;
++ break;
++ default:
++ ret = -EINVAL;
++ goto exit;
++ }
++
++ if (pupd_en_reg_val != chip->reg_pupd_en) {
++ ret = pca953x_write_reg(chip, PCAL953X_PUPD_EN,
++ pupd_en_reg_val);
++ if (ret)
++ goto exit;
++ chip->reg_pupd_en = pupd_en_reg_val;
++ }
++
++ if (pupd_sel_reg_val != chip->reg_pupd_sel) {
++ ret = pca953x_write_reg(chip, PCAL953X_PUPD_SEL,
++ pupd_sel_reg_val);
++ if (ret)
++ goto exit;
++ chip->reg_pupd_sel = pupd_sel_reg_val;
++ }
++
++exit:
++ mutex_unlock(&chip->i2c_lock);
++ return ret;
++}
++
+ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
+ {
+ struct gpio_chip *gc;
+@@ -320,6 +389,9 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
+ gc->dev = &chip->client->dev;
+ gc->owner = THIS_MODULE;
+ gc->names = chip->names;
++
++ if (chip->chip_type == PCAL953X_TYPE)
++ gc->set_drive = pca953x_gpio_set_drive;
+ }
+
+ #ifdef CONFIG_GPIO_PCA953X_IRQ
+@@ -368,6 +440,15 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
+ new_irqs &= ~(1 << level);
+ }
+
++ if (chip->chip_type == PCAL953X_TYPE) {
++ /* Enable latch on interrupt-enabled inputs */
++ pca953x_write_reg(chip, PCAL953X_IN_LATCH,
++ chip->irq_mask);
++ /* Unmask enabled interrupts */
++ pca953x_write_reg(chip, PCAL953X_INT_MASK,
++ ~chip->irq_mask);
++ }
++
+ mutex_unlock(&chip->irq_lock);
+ }
+
+@@ -412,6 +493,24 @@ static u32 pca953x_irq_pending(struct pca953x_chip *chip)
+ u32 trigger;
+ int ret, offset = 0;
+
++ if (chip->chip_type == PCAL953X_TYPE) {
++ /* Read the current interrupt status from the device */
++ ret = pca953x_read_reg(chip, PCAL953X_INT_STAT, &pending);
++ if (ret)
++ return 0;
++
++ /* Check latched inputs and clear interrupt status */
++ ret = pca953x_read_reg(chip, PCA953X_INPUT, &cur_stat);
++ if (ret)
++ return 0;
++
++ /* Apply filter for rising/falling edge selection */
++ pending &= (~cur_stat & chip->irq_trig_fall) |
++ (cur_stat & chip->irq_trig_raise);
++
++ return pending;
++ }
++
+ switch (chip->chip_type) {
+ case PCA953X_TYPE:
+ offset = PCA953X_INPUT;
+@@ -468,37 +567,43 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
+ int irq_base)
+ {
+ struct i2c_client *client = chip->client;
+- int ret, offset = 0;
++ int ret = 0, offset = 0;
++ unsigned long flags;
+ u32 temporary;
+
+ if (irq_base != -1
+ && (id->driver_data & PCA_INT)) {
+ int lvl;
+
+- switch (chip->chip_type) {
+- case PCA953X_TYPE:
+- offset = PCA953X_INPUT;
+- break;
+- case PCA957X_TYPE:
+- offset = PCA957X_IN;
+- break;
++ if (chip->chip_type != PCAL953X_TYPE) {
++ switch (chip->chip_type) {
++ case PCA953X_TYPE:
++ offset = PCA953X_INPUT;
++ break;
++ case PCA957X_TYPE:
++ offset = PCA957X_IN;
++ break;
++ }
++ ret = pca953x_read_reg(chip, offset, &temporary);
++ chip->irq_stat = temporary;
++ if (ret)
++ goto out_failed;
++
++ /*
++ * There is no way to know which GPIO line generated the
++ * interrupt. We have to rely on the previous read for
++ * this purpose.
++ */
++ chip->irq_stat &= chip->reg_direction;
+ }
+- ret = pca953x_read_reg(chip, offset, &temporary);
+- chip->irq_stat = temporary;
+- if (ret)
+- goto out_failed;
+-
+- /*
+- * There is no way to know which GPIO line generated the
+- * interrupt. We have to rely on the previous read for
+- * this purpose.
+- */
+- chip->irq_stat &= chip->reg_direction;
+ mutex_init(&chip->irq_lock);
+
+- chip->irq_base = irq_alloc_descs(-1, irq_base, chip->gpio_chip.ngpio, -1);
+- if (chip->irq_base < 0)
++ chip->irq_base = irq_alloc_descs(-1, irq_base,
++ chip->gpio_chip.ngpio, -1);
++ if (chip->irq_base < 0) {
++ ret = chip->irq_base;
+ goto out_failed;
++ }
+
+ chip->domain = irq_domain_add_legacy(client->dev.of_node,
+ chip->gpio_chip.ngpio,
+@@ -525,10 +630,15 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
+ #endif
+ }
+
++ if (chip->chip_type == PCAL953X_TYPE)
++ flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
++ else
++ flags = IRQF_TRIGGER_LOW | IRQF_ONESHOT;
++
+ ret = request_threaded_irq(client->irq,
+ NULL,
+ pca953x_irq_handler,
+- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
++ flags,
+ dev_name(&client->dev), chip);
+ if (ret) {
+ dev_err(&client->dev, "failed to request irq %d\n",
+@@ -537,6 +647,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
+ }
+
+ chip->gpio_chip.to_irq = pca953x_gpio_to_irq;
++ } else {
++ chip->irq_base = -1;
+ }
+
+ return 0;
+@@ -594,7 +706,8 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert)
+
+ *gpio_base = -1;
+ val = of_get_property(node, "linux,gpio-base", &size);
+- WARN(val, "%s: device-tree property 'linux,gpio-base' is deprecated!", __func__);
++ WARN(val, "%s: device-tree property 'linux,gpio-base' is deprecated!",
++ __func__);
+ if (val) {
+ if (size != sizeof(*val))
+ dev_warn(&client->dev, "%s: wrong linux,gpio-base\n",
+@@ -604,7 +717,8 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert)
+ }
+
+ val = of_get_property(node, "polarity", NULL);
+- WARN(val, "%s: device-tree property 'polarity' is deprecated!", __func__);
++ WARN(val, "%s: device-tree property 'polarity' is deprecated!",
++ __func__);
+ if (val)
+ *invert = *val;
+ }
+@@ -620,6 +734,18 @@ static int device_pca953x_init(struct pca953x_chip *chip, u32 invert)
+ {
+ int ret;
+
++ if (chip->chip_type == PCAL953X_TYPE) {
++ ret = pca953x_read_reg(chip, PCAL953X_PUPD_EN,
++ &chip->reg_pupd_en);
++ if (ret)
++ goto out;
++
++ ret = pca953x_read_reg(chip, PCAL953X_PUPD_SEL,
++ &chip->reg_pupd_sel);
++ if (ret)
++ goto out;
++ }
++
+ ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output);
+ if (ret)
+ goto out;
+@@ -688,15 +814,18 @@ static int pca953x_probe(struct i2c_client *client,
+ } else {
+ pca953x_get_alt_pdata(client, &chip->gpio_start, &invert);
+ #ifdef CONFIG_OF_GPIO
+- /* If I2C node has no interrupts property, disable GPIO interrupts */
+- if (of_find_property(client->dev.of_node, "interrupts", NULL) == NULL)
++ /* If I2C node has no interrupts property, disable
++ * GPIO interrupts */
++ if (of_find_property(client->dev.of_node,
++ "interrupts", NULL) == NULL)
+ irq_base = -1;
+ #endif
+ }
+
+ chip->client = client;
+
+- chip->chip_type = id->driver_data & (PCA953X_TYPE | PCA957X_TYPE);
++ chip->chip_type = id->driver_data &
++ (PCAL953X_TYPE | PCA953X_TYPE | PCA957X_TYPE);
+
+ mutex_init(&chip->i2c_lock);
+
+@@ -705,7 +834,7 @@ static int pca953x_probe(struct i2c_client *client,
+ */
+ pca953x_setup_gpio(chip, id->driver_data & PCA_GPIO_MASK);
+
+- if (chip->chip_type == PCA953X_TYPE)
++ if (chip->chip_type & (PCA953X_TYPE | PCAL953X_TYPE))
+ ret = device_pca953x_init(chip, invert);
+ else
+ ret = device_pca957x_init(chip, invert);
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 5359ca7..5e897ff 100644
--- a/drivers/gpio/gpiolib.c
@@ -267,6 +692,3 @@ index bfe6656..cadd9d2 100644
static inline int gpio_get_value(unsigned gpio)
{
/* GPIO can never have been requested or set as {in,out}put */
---
-1.7.4.1
-