summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Kerr <jk@ozlabs.org>2015-10-23 09:31:53 +0300
committerJeremy Kerr <jk@ozlabs.org>2015-10-27 10:15:50 +0300
commit302fccccca9d5e1338925c99c8e52107e5f204ae (patch)
treed7660b2458bd1f013bf40984cc01d4bab27a33d1
parent4da0fb77804ab2b253245141cf0fbcaec0ce8e53 (diff)
downloadlinux-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.dts29
-rw-r--r--drivers/gpio/gpio-aspeed.c106
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);