summaryrefslogtreecommitdiff
path: root/drivers/gpio
diff options
context:
space:
mode:
authorIgor Opaniuk <igor.opaniuk@toradex.com>2020-11-17 14:38:38 +0200
committerIgor Opaniuk <igor.opaniuk@toradex.com>2020-11-17 14:38:38 +0200
commit8bb9d758833ea1d0622277981b5225980ba0a42d (patch)
tree2281499b2970e563f522db7ebc9d03bebfda4bfa /drivers/gpio
parent0316046d152a1817bd0b4faff8e34c212a936a5e (diff)
parent3b59d4725be760cd276094079b4fbe7bd44e1464 (diff)
Merge branch 'toradex_5.4-2.1.x-imx' into HEAD
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/gpio-arizona.c7
-rw-r--r--drivers/gpio/gpio-aspeed.c4
-rw-r--r--drivers/gpio/gpio-dwapb.c34
-rw-r--r--drivers/gpio/gpio-mockup.c2
-rw-r--r--drivers/gpio/gpio-pca953x.c129
-rw-r--r--drivers/gpio/gpio-rcar.c4
-rw-r--r--drivers/gpio/gpio-siox.c1
-rw-r--r--drivers/gpio/gpio-sprd.c3
-rw-r--r--drivers/gpio/gpio-tc3589x.c2
-rw-r--r--drivers/gpio/sgpio-aspeed.c134
10 files changed, 240 insertions, 80 deletions
diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c
index 5640efe5e750..5bda38e0780f 100644
--- a/drivers/gpio/gpio-arizona.c
+++ b/drivers/gpio/gpio-arizona.c
@@ -64,6 +64,7 @@ static int arizona_gpio_get(struct gpio_chip *chip, unsigned offset)
ret = pm_runtime_get_sync(chip->parent);
if (ret < 0) {
dev_err(chip->parent, "Failed to resume: %d\n", ret);
+ pm_runtime_put_autosuspend(chip->parent);
return ret;
}
@@ -72,12 +73,15 @@ static int arizona_gpio_get(struct gpio_chip *chip, unsigned offset)
if (ret < 0) {
dev_err(chip->parent, "Failed to drop cache: %d\n",
ret);
+ pm_runtime_put_autosuspend(chip->parent);
return ret;
}
ret = regmap_read(arizona->regmap, reg, &val);
- if (ret < 0)
+ if (ret < 0) {
+ pm_runtime_put_autosuspend(chip->parent);
return ret;
+ }
pm_runtime_mark_last_busy(chip->parent);
pm_runtime_put_autosuspend(chip->parent);
@@ -106,6 +110,7 @@ static int arizona_gpio_direction_out(struct gpio_chip *chip,
ret = pm_runtime_get_sync(chip->parent);
if (ret < 0) {
dev_err(chip->parent, "Failed to resume: %d\n", ret);
+ pm_runtime_put(chip->parent);
return ret;
}
}
diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c
index 09e53c5f3b0a..2820c59b5f07 100644
--- a/drivers/gpio/gpio-aspeed.c
+++ b/drivers/gpio/gpio-aspeed.c
@@ -1115,8 +1115,8 @@ static const struct aspeed_gpio_config ast2500_config =
static const struct aspeed_bank_props ast2600_bank_props[] = {
/* input output */
- {5, 0xffffffff, 0x0000ffff}, /* U/V/W/X */
- {6, 0xffff0000, 0x0fff0000}, /* Y/Z */
+ {5, 0xffffffff, 0xffffff00}, /* U/V/W/X */
+ {6, 0x0000ffff, 0x0000ffff}, /* Y/Z */
{ },
};
diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c
index 92e127e74813..ed6061b5cca1 100644
--- a/drivers/gpio/gpio-dwapb.c
+++ b/drivers/gpio/gpio-dwapb.c
@@ -49,7 +49,9 @@
#define GPIO_EXT_PORTC 0x58
#define GPIO_EXT_PORTD 0x5c
+#define DWAPB_DRIVER_NAME "gpio-dwapb"
#define DWAPB_MAX_PORTS 4
+
#define GPIO_EXT_PORT_STRIDE 0x04 /* register stride 32 bits */
#define GPIO_SWPORT_DR_STRIDE 0x0c /* register stride 3*32 bits */
#define GPIO_SWPORT_DDR_STRIDE 0x0c /* register stride 3*32 bits */
@@ -398,7 +400,7 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
return;
err = irq_alloc_domain_generic_chips(gpio->domain, ngpio, 2,
- "gpio-dwapb", handle_level_irq,
+ DWAPB_DRIVER_NAME, handle_level_irq,
IRQ_NOREQUEST, 0,
IRQ_GC_INIT_NESTED_LOCK);
if (err) {
@@ -455,7 +457,7 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
*/
err = devm_request_irq(gpio->dev, pp->irq[0],
dwapb_irq_handler_mfd,
- IRQF_SHARED, "gpio-dwapb-mfd", gpio);
+ IRQF_SHARED, DWAPB_DRIVER_NAME, gpio);
if (err) {
dev_err(gpio->dev, "error requesting IRQ\n");
irq_domain_remove(gpio->domain);
@@ -533,26 +535,33 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
dwapb_configure_irqs(gpio, port, pp);
err = gpiochip_add_data(&port->gc, port);
- if (err)
+ if (err) {
dev_err(gpio->dev, "failed to register gpiochip for port%d\n",
port->idx);
- else
- port->is_registered = true;
+ return err;
+ }
/* Add GPIO-signaled ACPI event support */
- if (pp->has_irq)
- acpi_gpiochip_request_interrupts(&port->gc);
+ acpi_gpiochip_request_interrupts(&port->gc);
- return err;
+ port->is_registered = true;
+
+ return 0;
}
static void dwapb_gpio_unregister(struct dwapb_gpio *gpio)
{
unsigned int m;
- for (m = 0; m < gpio->nr_ports; ++m)
- if (gpio->ports[m].is_registered)
- gpiochip_remove(&gpio->ports[m].gc);
+ for (m = 0; m < gpio->nr_ports; ++m) {
+ struct dwapb_gpio_port *port = &gpio->ports[m];
+
+ if (!port->is_registered)
+ continue;
+
+ acpi_gpiochip_free_interrupts(&port->gc);
+ gpiochip_remove(&port->gc);
+ }
}
static struct dwapb_platform_data *
@@ -836,7 +845,7 @@ static SIMPLE_DEV_PM_OPS(dwapb_gpio_pm_ops, dwapb_gpio_suspend,
static struct platform_driver dwapb_gpio_driver = {
.driver = {
- .name = "gpio-dwapb",
+ .name = DWAPB_DRIVER_NAME,
.pm = &dwapb_gpio_pm_ops,
.of_match_table = of_match_ptr(dwapb_of_match),
.acpi_match_table = ACPI_PTR(dwapb_acpi_match),
@@ -850,3 +859,4 @@ module_platform_driver(dwapb_gpio_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jamie Iles");
MODULE_DESCRIPTION("Synopsys DesignWare APB GPIO driver");
+MODULE_ALIAS("platform:" DWAPB_DRIVER_NAME);
diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c
index 213aedc97dc2..9c1c4d81aa7b 100644
--- a/drivers/gpio/gpio-mockup.c
+++ b/drivers/gpio/gpio-mockup.c
@@ -497,6 +497,7 @@ static int __init gpio_mockup_init(void)
err = platform_driver_register(&gpio_mockup_driver);
if (err) {
gpio_mockup_err("error registering platform driver\n");
+ debugfs_remove_recursive(gpio_mockup_dbg_dir);
return err;
}
@@ -527,6 +528,7 @@ static int __init gpio_mockup_init(void)
gpio_mockup_err("error registering device");
platform_driver_unregister(&gpio_mockup_driver);
gpio_mockup_unregister_pdevs();
+ debugfs_remove_recursive(gpio_mockup_dbg_dir);
return PTR_ERR(pdev);
}
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 12f12da3e4f3..effcafbc09bf 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -108,6 +108,84 @@ static const struct i2c_device_id pca953x_id[] = {
};
MODULE_DEVICE_TABLE(i2c, pca953x_id);
+#ifdef CONFIG_GPIO_PCA953X_IRQ
+
+#include <linux/dmi.h>
+#include <linux/gpio.h>
+#include <linux/list.h>
+
+static const struct dmi_system_id pca953x_dmi_acpi_irq_info[] = {
+ {
+ /*
+ * On Intel Galileo Gen 2 board the IRQ pin of one of
+ * the I²C GPIO expanders, which has GpioInt() resource,
+ * is provided as an absolute number instead of being
+ * relative. Since first controller (gpio-sch.c) and
+ * second (gpio-dwapb.c) are at the fixed bases, we may
+ * safely refer to the number in the global space to get
+ * an IRQ out of it.
+ */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "GalileoGen2"),
+ },
+ },
+ {}
+};
+
+#ifdef CONFIG_ACPI
+static int pca953x_acpi_get_pin(struct acpi_resource *ares, void *data)
+{
+ struct acpi_resource_gpio *agpio;
+ int *pin = data;
+
+ if (acpi_gpio_get_irq_resource(ares, &agpio))
+ *pin = agpio->pin_table[0];
+ return 1;
+}
+
+static int pca953x_acpi_find_pin(struct device *dev)
+{
+ struct acpi_device *adev = ACPI_COMPANION(dev);
+ int pin = -ENOENT, ret;
+ LIST_HEAD(r);
+
+ ret = acpi_dev_get_resources(adev, &r, pca953x_acpi_get_pin, &pin);
+ acpi_dev_free_resource_list(&r);
+ if (ret < 0)
+ return ret;
+
+ return pin;
+}
+#else
+static inline int pca953x_acpi_find_pin(struct device *dev) { return -ENXIO; }
+#endif
+
+static int pca953x_acpi_get_irq(struct device *dev)
+{
+ int pin, ret;
+
+ pin = pca953x_acpi_find_pin(dev);
+ if (pin < 0)
+ return pin;
+
+ dev_info(dev, "Applying ACPI interrupt quirk (GPIO %d)\n", pin);
+
+ if (!gpio_is_valid(pin))
+ return -EINVAL;
+
+ ret = gpio_request(pin, "pca953x interrupt");
+ if (ret)
+ return ret;
+
+ ret = gpio_to_irq(pin);
+
+ /* When pin is used as an IRQ, no need to keep it requested */
+ gpio_free(pin);
+
+ return ret;
+}
+#endif
+
static const struct acpi_device_id pca953x_acpi_ids[] = {
{ "INT3491", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
{ }
@@ -307,8 +385,23 @@ static const struct regmap_config pca953x_i2c_regmap = {
.volatile_reg = pca953x_volatile_register,
.cache_type = REGCACHE_RBTREE,
- /* REVISIT: should be 0x7f but some 24 bit chips use REG_ADDR_AI */
- .max_register = 0xff,
+ .max_register = 0x7f,
+};
+
+static const struct regmap_config pca953x_ai_i2c_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .read_flag_mask = REG_ADDR_AI,
+ .write_flag_mask = REG_ADDR_AI,
+
+ .readable_reg = pca953x_readable_register,
+ .writeable_reg = pca953x_writeable_register,
+ .volatile_reg = pca953x_volatile_register,
+
+ .disable_locking = true,
+ .cache_type = REGCACHE_RBTREE,
+ .max_register = 0x7f,
};
static u8 pca953x_recalc_addr(struct pca953x_chip *chip, int reg, int off,
@@ -319,18 +412,6 @@ static u8 pca953x_recalc_addr(struct pca953x_chip *chip, int reg, int off,
int pinctrl = (reg & PCAL_PINCTRL_MASK) << 1;
u8 regaddr = pinctrl | addr | (off / BANK_SZ);
- /* Single byte read doesn't need AI bit set. */
- if (!addrinc)
- return regaddr;
-
- /* Chips with 24 and more GPIOs always support Auto Increment */
- if (write && NBANK(chip) > 2)
- regaddr |= REG_ADDR_AI;
-
- /* PCA9575 needs address-increment on multi-byte writes */
- if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE)
- regaddr |= REG_ADDR_AI;
-
return regaddr;
}
@@ -771,6 +852,12 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
u8 reg_direction[MAX_BANK];
int ret, i;
+ if (dmi_first_match(pca953x_dmi_acpi_irq_info)) {
+ ret = pca953x_acpi_get_irq(&client->dev);
+ if (ret > 0)
+ client->irq = ret;
+ }
+
if (!client->irq)
return 0;
@@ -898,6 +985,7 @@ static int pca953x_probe(struct i2c_client *client,
int ret;
u32 invert = 0;
struct regulator *reg;
+ const struct regmap_config *regmap_config;
chip = devm_kzalloc(&client->dev,
sizeof(struct pca953x_chip), GFP_KERNEL);
@@ -965,7 +1053,17 @@ static int pca953x_probe(struct i2c_client *client,
i2c_set_clientdata(client, chip);
- chip->regmap = devm_regmap_init_i2c(client, &pca953x_i2c_regmap);
+ pca953x_setup_gpio(chip, chip->driver_data & PCA_GPIO_MASK);
+
+ if (NBANK(chip) > 2 || PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) {
+ dev_info(&client->dev, "using AI\n");
+ regmap_config = &pca953x_ai_i2c_regmap;
+ } else {
+ dev_info(&client->dev, "using no AI\n");
+ regmap_config = &pca953x_i2c_regmap;
+ }
+
+ chip->regmap = devm_regmap_init_i2c(client, regmap_config);
if (IS_ERR(chip->regmap)) {
ret = PTR_ERR(chip->regmap);
goto err_exit;
@@ -1000,7 +1098,6 @@ static int pca953x_probe(struct i2c_client *client,
/* initialize cached registers from their original values.
* we can't share this chip with another i2c master.
*/
- pca953x_setup_gpio(chip, chip->driver_data & PCA_GPIO_MASK);
if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE) {
chip->regs = &pca953x_regs;
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index 187984d26f47..f0b6c68e848e 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -250,8 +250,10 @@ static int gpio_rcar_request(struct gpio_chip *chip, unsigned offset)
int error;
error = pm_runtime_get_sync(p->dev);
- if (error < 0)
+ if (error < 0) {
+ pm_runtime_put(p->dev);
return error;
+ }
error = pinctrl_gpio_request(chip->base + offset);
if (error)
diff --git a/drivers/gpio/gpio-siox.c b/drivers/gpio/gpio-siox.c
index 006a7e6a75f2..7e70d2d06c3f 100644
--- a/drivers/gpio/gpio-siox.c
+++ b/drivers/gpio/gpio-siox.c
@@ -245,6 +245,7 @@ static int gpio_siox_probe(struct siox_device *sdevice)
girq->chip = &ddata->ichip;
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_level_irq;
+ girq->threaded = true;
ret = devm_gpiochip_add_data(dev, &ddata->gchip, NULL);
if (ret)
diff --git a/drivers/gpio/gpio-sprd.c b/drivers/gpio/gpio-sprd.c
index d7314d39ab65..36ea8a3bd451 100644
--- a/drivers/gpio/gpio-sprd.c
+++ b/drivers/gpio/gpio-sprd.c
@@ -149,17 +149,20 @@ static int sprd_gpio_irq_set_type(struct irq_data *data,
sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 0);
sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 0);
sprd_gpio_update(chip, offset, SPRD_GPIO_IEV, 1);
+ sprd_gpio_update(chip, offset, SPRD_GPIO_IC, 1);
irq_set_handler_locked(data, handle_edge_irq);
break;
case IRQ_TYPE_EDGE_FALLING:
sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 0);
sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 0);
sprd_gpio_update(chip, offset, SPRD_GPIO_IEV, 0);
+ sprd_gpio_update(chip, offset, SPRD_GPIO_IC, 1);
irq_set_handler_locked(data, handle_edge_irq);
break;
case IRQ_TYPE_EDGE_BOTH:
sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 0);
sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 1);
+ sprd_gpio_update(chip, offset, SPRD_GPIO_IC, 1);
irq_set_handler_locked(data, handle_edge_irq);
break;
case IRQ_TYPE_LEVEL_HIGH:
diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c
index 75b1135b383a..daf29044d0f1 100644
--- a/drivers/gpio/gpio-tc3589x.c
+++ b/drivers/gpio/gpio-tc3589x.c
@@ -209,7 +209,7 @@ static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d)
continue;
tc3589x_gpio->oldregs[i][j] = new;
- tc3589x_reg_write(tc3589x, regmap[i] + j * 8, new);
+ tc3589x_reg_write(tc3589x, regmap[i] + j, new);
}
}
diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/sgpio-aspeed.c
index 8319812593e3..3a5dfb8ded1f 100644
--- a/drivers/gpio/sgpio-aspeed.c
+++ b/drivers/gpio/sgpio-aspeed.c
@@ -17,7 +17,17 @@
#include <linux/spinlock.h>
#include <linux/string.h>
-#define MAX_NR_SGPIO 80
+/*
+ * MAX_NR_HW_GPIO represents the number of actual hardware-supported GPIOs (ie,
+ * slots within the clocked serial GPIO data). Since each HW GPIO is both an
+ * input and an output, we provide MAX_NR_HW_GPIO * 2 lines on our gpiochip
+ * device.
+ *
+ * We use SGPIO_OUTPUT_OFFSET to define the split between the inputs and
+ * outputs; the inputs start at line 0, the outputs start at OUTPUT_OFFSET.
+ */
+#define MAX_NR_HW_SGPIO 80
+#define SGPIO_OUTPUT_OFFSET MAX_NR_HW_SGPIO
#define ASPEED_SGPIO_CTRL 0x54
@@ -30,8 +40,8 @@ struct aspeed_sgpio {
struct clk *pclk;
spinlock_t lock;
void __iomem *base;
- uint32_t dir_in[3];
int irq;
+ int n_sgpio;
};
struct aspeed_sgpio_bank {
@@ -111,31 +121,69 @@ static void __iomem *bank_reg(struct aspeed_sgpio *gpio,
}
}
-#define GPIO_BANK(x) ((x) >> 5)
-#define GPIO_OFFSET(x) ((x) & 0x1f)
+#define GPIO_BANK(x) ((x % SGPIO_OUTPUT_OFFSET) >> 5)
+#define GPIO_OFFSET(x) ((x % SGPIO_OUTPUT_OFFSET) & 0x1f)
#define GPIO_BIT(x) BIT(GPIO_OFFSET(x))
static const struct aspeed_sgpio_bank *to_bank(unsigned int offset)
{
- unsigned int bank = GPIO_BANK(offset);
+ unsigned int bank;
+
+ bank = GPIO_BANK(offset);
WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks));
return &aspeed_sgpio_banks[bank];
}
+static int aspeed_sgpio_init_valid_mask(struct gpio_chip *gc,
+ unsigned long *valid_mask, unsigned int ngpios)
+{
+ struct aspeed_sgpio *sgpio = gpiochip_get_data(gc);
+ int n = sgpio->n_sgpio;
+ int c = SGPIO_OUTPUT_OFFSET - n;
+
+ WARN_ON(ngpios < MAX_NR_HW_SGPIO * 2);
+
+ /* input GPIOs in the lower range */
+ bitmap_set(valid_mask, 0, n);
+ bitmap_clear(valid_mask, n, c);
+
+ /* output GPIOS above SGPIO_OUTPUT_OFFSET */
+ bitmap_set(valid_mask, SGPIO_OUTPUT_OFFSET, n);
+ bitmap_clear(valid_mask, SGPIO_OUTPUT_OFFSET + n, c);
+
+ return 0;
+}
+
+static void aspeed_sgpio_irq_init_valid_mask(struct gpio_chip *gc,
+ unsigned long *valid_mask, unsigned int ngpios)
+{
+ struct aspeed_sgpio *sgpio = gpiochip_get_data(gc);
+ int n = sgpio->n_sgpio;
+
+ WARN_ON(ngpios < MAX_NR_HW_SGPIO * 2);
+
+ /* input GPIOs in the lower range */
+ bitmap_set(valid_mask, 0, n);
+ bitmap_clear(valid_mask, n, ngpios - n);
+}
+
+static bool aspeed_sgpio_is_input(unsigned int offset)
+{
+ return offset < SGPIO_OUTPUT_OFFSET;
+}
+
static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
{
struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
const struct aspeed_sgpio_bank *bank = to_bank(offset);
unsigned long flags;
enum aspeed_sgpio_reg reg;
- bool is_input;
int rc = 0;
spin_lock_irqsave(&gpio->lock, flags);
- is_input = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
- reg = is_input ? reg_val : reg_rdata;
+ reg = aspeed_sgpio_is_input(offset) ? reg_val : reg_rdata;
rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset));
spin_unlock_irqrestore(&gpio->lock, flags);
@@ -143,22 +191,31 @@ static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
return rc;
}
-static void sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val)
+static int sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val)
{
struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
const struct aspeed_sgpio_bank *bank = to_bank(offset);
- void __iomem *addr;
+ void __iomem *addr_r, *addr_w;
u32 reg = 0;
- addr = bank_reg(gpio, bank, reg_val);
- reg = ioread32(addr);
+ if (aspeed_sgpio_is_input(offset))
+ return -EINVAL;
+
+ /* Since this is an output, read the cached value from rdata, then
+ * update val. */
+ addr_r = bank_reg(gpio, bank, reg_rdata);
+ addr_w = bank_reg(gpio, bank, reg_val);
+
+ reg = ioread32(addr_r);
if (val)
reg |= GPIO_BIT(offset);
else
reg &= ~GPIO_BIT(offset);
- iowrite32(reg, addr);
+ iowrite32(reg, addr_w);
+
+ return 0;
}
static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val)
@@ -175,43 +232,28 @@ static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val)
static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset)
{
- struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
- unsigned long flags;
-
- spin_lock_irqsave(&gpio->lock, flags);
- gpio->dir_in[GPIO_BANK(offset)] |= GPIO_BIT(offset);
- spin_unlock_irqrestore(&gpio->lock, flags);
-
- return 0;
+ return aspeed_sgpio_is_input(offset) ? 0 : -EINVAL;
}
static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val)
{
struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
unsigned long flags;
+ int rc;
- spin_lock_irqsave(&gpio->lock, flags);
-
- gpio->dir_in[GPIO_BANK(offset)] &= ~GPIO_BIT(offset);
- sgpio_set_value(gc, offset, val);
+ /* No special action is required for setting the direction; we'll
+ * error-out in sgpio_set_value if this isn't an output GPIO */
+ spin_lock_irqsave(&gpio->lock, flags);
+ rc = sgpio_set_value(gc, offset, val);
spin_unlock_irqrestore(&gpio->lock, flags);
- return 0;
+ return rc;
}
static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset)
{
- int dir_status;
- struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
- unsigned long flags;
-
- spin_lock_irqsave(&gpio->lock, flags);
- dir_status = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
- spin_unlock_irqrestore(&gpio->lock, flags);
-
- return dir_status;
-
+ return !!aspeed_sgpio_is_input(offset);
}
static void irqd_to_aspeed_sgpio_data(struct irq_data *d,
@@ -402,6 +444,7 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
irq = &gpio->chip.irq;
irq->chip = &aspeed_sgpio_irqchip;
+ irq->init_valid_mask = aspeed_sgpio_irq_init_valid_mask;
irq->handler = handle_bad_irq;
irq->default_type = IRQ_TYPE_NONE;
irq->parent_handler = aspeed_sgpio_irq_handler;
@@ -409,17 +452,15 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
irq->parents = &gpio->irq;
irq->num_parents = 1;
- /* set IRQ settings and Enable Interrupt */
+ /* Apply default IRQ settings */
for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
bank = &aspeed_sgpio_banks[i];
/* set falling or level-low irq */
iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0));
/* trigger type is edge */
iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1));
- /* dual edge trigger mode. */
- iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type2));
- /* enable irq */
- iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_enable));
+ /* single edge trigger */
+ iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type2));
}
return 0;
@@ -452,11 +493,12 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev)
if (rc < 0) {
dev_err(&pdev->dev, "Could not read ngpios property\n");
return -EINVAL;
- } else if (nr_gpios > MAX_NR_SGPIO) {
+ } else if (nr_gpios > MAX_NR_HW_SGPIO) {
dev_err(&pdev->dev, "Number of GPIOs exceeds the maximum of %d: %d\n",
- MAX_NR_SGPIO, nr_gpios);
+ MAX_NR_HW_SGPIO, nr_gpios);
return -EINVAL;
}
+ gpio->n_sgpio = nr_gpios;
rc = of_property_read_u32(pdev->dev.of_node, "bus-frequency", &sgpio_freq);
if (rc < 0) {
@@ -497,7 +539,8 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev)
spin_lock_init(&gpio->lock);
gpio->chip.parent = &pdev->dev;
- gpio->chip.ngpio = nr_gpios;
+ gpio->chip.ngpio = MAX_NR_HW_SGPIO * 2;
+ gpio->chip.init_valid_mask = aspeed_sgpio_init_valid_mask;
gpio->chip.direction_input = aspeed_sgpio_dir_in;
gpio->chip.direction_output = aspeed_sgpio_dir_out;
gpio->chip.get_direction = aspeed_sgpio_get_direction;
@@ -509,9 +552,6 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev)
gpio->chip.label = dev_name(&pdev->dev);
gpio->chip.base = -1;
- /* set all SGPIO pins as input (1). */
- memset(gpio->dir_in, 0xff, sizeof(gpio->dir_in));
-
aspeed_sgpio_setup_irqs(gpio, pdev);
rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);