diff options
author | Jeremy Kerr <jk@ozlabs.org> | 2015-10-23 09:31:53 +0300 |
---|---|---|
committer | Jeremy Kerr <jk@ozlabs.org> | 2015-10-27 10:15:50 +0300 |
commit | 302fccccca9d5e1338925c99c8e52107e5f204ae (patch) | |
tree | d7660b2458bd1f013bf40984cc01d4bab27a33d1 | |
parent | 4da0fb77804ab2b253245141cf0fbcaec0ce8e53 (diff) | |
download | linux-302fccccca9d5e1338925c99c8e52107e5f204ae.tar.xz |
gpio/aspeed: Expose entire bank as one gpio chip
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
-rw-r--r-- | arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts | 29 | ||||
-rw-r--r-- | drivers/gpio/gpio-aspeed.c | 106 |
2 files changed, 98 insertions, 37 deletions
diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts b/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts index d90e4ba391d5..e63ddb910822 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts @@ -145,34 +145,9 @@ clocks = <&clk_apb>; }; - gpio0: gpio@1e780000 { + gpio: gpio@1e780000 { compatible = "aspeed,ast2400-gpio"; - reg = <0x1e780000 0x20>; - }; - - gpio1: gpio@1e780020 { - compatible = "aspeed,ast2400-gpio"; - reg = <0x1e780020 0x20>; - }; - - gpio2: gpio@1e780070 { - compatible = "aspeed,ast2400-gpio"; - reg = <0x1e780070 0x8>; - }; - - gpio3: gpio@1e780078 { - compatible = "aspeed,ast2400-gpio"; - reg = <0x1e780078 0x8>; - }; - - gpio4: gpio@1e780080 { - compatible = "aspeed,ast2400-gpio"; - reg = <0x1e780080 0x8>; - }; - - gpio5: gpio@1e780088 { - compatible = "aspeed,ast2400-gpio"; - reg = <0x1e780088 0x8>; + reg = <0x1e780000 0x1000>; }; uart1: serial@1e783000 { diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index f34726081b3b..829537163ffd 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -23,6 +23,42 @@ struct aspeed_gpio { void __iomem *base; }; +struct aspeed_gpio_bank { + uint16_t val_regs; + char names[4]; +}; + +static struct aspeed_gpio_bank aspeed_gpio_banks[] = { + { + .val_regs = 0x0000, + .names = { 'A', 'B', 'C', 'D' }, + }, + { + .val_regs = 0x0020, + .names = { 'E', 'F', 'G', 'H' }, + }, + { + .val_regs = 0x0070, + .names = { 'I', 'J', 'K', 'L' }, + }, + { + .val_regs = 0x0078, + .names = { 'M', 'N', 'O', 'P' }, + }, + { + .val_regs = 0x0080, + .names = { 'Q', 'R', 'S', 'T' }, + }, + { + .val_regs = 0x0088, + .names = { 'U', 'V', 'W', 'X' }, + }, +}; + +#define GPIO_BANK(x) ((x) >> 5) +#define GPIO_OFFSET(x) ((x) & 0x1f) +#define GPIO_BIT(x) BIT(GPIO_OFFSET(x)) + #define GPIO_DATA 0x00 #define GPIO_DIR 0x04 @@ -31,29 +67,46 @@ static inline struct aspeed_gpio *to_aspeed_gpio(struct gpio_chip *chip) return container_of(chip, struct aspeed_gpio, chip); } +static struct aspeed_gpio_bank *to_bank(unsigned int offset) +{ + unsigned int bank = GPIO_BANK(offset); + WARN_ON(bank > ARRAY_SIZE(aspeed_gpio_banks)); + return &aspeed_gpio_banks[bank]; +} + +static void *bank_val_reg(struct aspeed_gpio *gpio, + struct aspeed_gpio_bank *bank, + unsigned int reg) +{ + return gpio->base + bank->val_regs + reg; +} + static int aspeed_gpio_get(struct gpio_chip *gc, unsigned int offset) { struct aspeed_gpio *gpio = to_aspeed_gpio(gc); + struct aspeed_gpio_bank *bank = to_bank(offset); - return !!(ioread32(gpio->base + GPIO_DATA) & BIT(offset)); + return !!(ioread32(bank_val_reg(gpio, bank, GPIO_DATA)) + & GPIO_BIT(offset)); } static void aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, int val) { struct aspeed_gpio *gpio = to_aspeed_gpio(gc); + struct aspeed_gpio_bank *bank = to_bank(offset); unsigned long flags; u32 reg; spin_lock_irqsave(&gpio->lock, flags); - reg = ioread32(gpio->base + GPIO_DATA); + reg = ioread32(bank_val_reg(gpio, bank, GPIO_DATA)); if (val) - reg |= BIT(offset); + reg |= GPIO_BIT(offset); else - reg &= ~BIT(offset); + reg &= ~GPIO_BIT(offset); - iowrite32(reg, gpio->base + GPIO_DATA); + iowrite32(reg, bank_val_reg(gpio, bank, GPIO_DATA)); spin_unlock_irqrestore(&gpio->lock, flags); } @@ -61,13 +114,14 @@ static void aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, static int aspeed_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) { struct aspeed_gpio *gpio = to_aspeed_gpio(gc); + struct aspeed_gpio_bank *bank = to_bank(offset); unsigned long flags; u32 reg; spin_lock_irqsave(&gpio->lock, flags); - reg = ioread32(gpio->base + GPIO_DIR); - iowrite32(reg & ~BIT(offset), gpio->base + GPIO_DIR); + reg = ioread32(bank_val_reg(gpio, bank, GPIO_DIR)); + iowrite32(reg & ~GPIO_BIT(offset), bank_val_reg(gpio, bank, GPIO_DIR)); spin_unlock_irqrestore(&gpio->lock, flags); @@ -78,19 +132,49 @@ static int aspeed_gpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val) { struct aspeed_gpio *gpio = to_aspeed_gpio(gc); + struct aspeed_gpio_bank *bank = to_bank(offset); unsigned long flags; u32 reg; spin_lock_irqsave(&gpio->lock, flags); - reg = ioread32(gpio->base + GPIO_DIR); - iowrite32(reg | BIT(offset), gpio->base + GPIO_DIR); + reg = ioread32(bank_val_reg(gpio, bank, GPIO_DIR)); + iowrite32(reg | GPIO_BIT(offset), bank_val_reg(gpio, bank, GPIO_DIR)); spin_unlock_irqrestore(&gpio->lock, flags); return 0; } +static void aspeed_gpio_set_names(struct aspeed_gpio *gpio) +{ + const char format[] = "GPIOXn"; + char *namebuf, **names; + unsigned int i; + + /* our buffer of name pointers */ + names = devm_kmalloc_array(gpio->chip.dev, gpio->chip.ngpio, + sizeof(char *), GFP_KERNEL); + + /* and one contiguous buffer for the names themselves */ + namebuf = devm_kmalloc_array(gpio->chip.dev, gpio->chip.ngpio, + sizeof(format), GFP_KERNEL); + + for (i = 0; i < gpio->chip.ngpio; i++) { + struct aspeed_gpio_bank *bank = to_bank(i); + char *name = namebuf + (i * sizeof(format)); + int bit = GPIO_OFFSET(i); + + memcpy(name, format, 4); + name[4] = bank->names[bit >> 3]; + name[5] = '0' + (bit % 8); + name[6] = '\0'; + names[i] = name; + } + + gpio->chip.names = (const char * const *)names; +} + static int __init aspeed_gpio_probe(struct platform_device *pdev) { struct resource *res; @@ -110,7 +194,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) spin_lock_init(&gpio->lock); - gpio->chip.ngpio = 32; + gpio->chip.ngpio = ARRAY_SIZE(aspeed_gpio_banks) * 32; gpio->chip.dev = &pdev->dev; gpio->chip.direction_input = aspeed_gpio_dir_in; @@ -120,6 +204,8 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) gpio->chip.label = dev_name(&pdev->dev); gpio->chip.base = -1; + aspeed_gpio_set_names(gpio); + platform_set_drvdata(pdev, gpio); return gpiochip_add(&gpio->chip); |