Re: [v8 1/1] gpio: aspeed: Add SGPIO driver

2019-08-23 Thread Linus Walleij
On Tue, Aug 20, 2019 at 11:05 PM Hongwei Zhang  wrote:

> Add SGPIO driver support for Aspeed AST2500 SoC.
>
> Signed-off-by: Hongwei Zhang 
> Reviewed-by:   Andrew Jeffery 

This v8 patch applied for v5.4, thanks!

Yours,
Linus Walleij


[v8 1/1] gpio: aspeed: Add SGPIO driver

2019-08-20 Thread Hongwei Zhang
Add SGPIO driver support for Aspeed AST2500 SoC.

Signed-off-by: Hongwei Zhang 
Reviewed-by:   Andrew Jeffery 
---
 drivers/gpio/sgpio-aspeed.c | 533 
 1 file changed, 533 insertions(+)
 create mode 100644 drivers/gpio/sgpio-aspeed.c

diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/sgpio-aspeed.c
new file mode 100644
index 000..7e99860
--- /dev/null
+++ b/drivers/gpio/sgpio-aspeed.c
@@ -0,0 +1,533 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2019 American Megatrends International LLC.
+ *
+ * Author: Karthikeyan Mani 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define MAX_NR_SGPIO   80
+
+#define ASPEED_SGPIO_CTRL  0x54
+
+#define ASPEED_SGPIO_PINS_MASK GENMASK(9, 6)
+#define ASPEED_SGPIO_CLK_DIV_MASK  GENMASK(31, 16)
+#define ASPEED_SGPIO_ENABLEBIT(0)
+
+struct aspeed_sgpio {
+   struct gpio_chip chip;
+   struct clk *pclk;
+   spinlock_t lock;
+   void __iomem *base;
+   uint32_t dir_in[3];
+   int irq;
+};
+
+struct aspeed_sgpio_bank {
+   uint16_tval_regs;
+   uint16_trdata_reg;
+   uint16_tirq_regs;
+   const char  names[4][3];
+};
+
+/*
+ * Note: The "value" register returns the input value when the GPIO is
+ *  configured as an input.
+ *
+ *  The "rdata" register returns the output value when the GPIO is
+ *  configured as an output.
+ */
+static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = {
+   {
+   .val_regs = 0x,
+   .rdata_reg = 0x0070,
+   .irq_regs = 0x0004,
+   .names = { "A", "B", "C", "D" },
+   },
+   {
+   .val_regs = 0x001C,
+   .rdata_reg = 0x0074,
+   .irq_regs = 0x0020,
+   .names = { "E", "F", "G", "H" },
+   },
+   {
+   .val_regs = 0x0038,
+   .rdata_reg = 0x0078,
+   .irq_regs = 0x003C,
+   .names = { "I", "J" },
+   },
+};
+
+enum aspeed_sgpio_reg {
+   reg_val,
+   reg_rdata,
+   reg_irq_enable,
+   reg_irq_type0,
+   reg_irq_type1,
+   reg_irq_type2,
+   reg_irq_status,
+};
+
+#define GPIO_VAL_VALUE  0x00
+#define GPIO_IRQ_ENABLE 0x00
+#define GPIO_IRQ_TYPE0  0x04
+#define GPIO_IRQ_TYPE1  0x08
+#define GPIO_IRQ_TYPE2  0x0C
+#define GPIO_IRQ_STATUS 0x10
+
+static void __iomem *bank_reg(struct aspeed_sgpio *gpio,
+const struct aspeed_sgpio_bank *bank,
+const enum aspeed_sgpio_reg reg)
+{
+   switch (reg) {
+   case reg_val:
+   return gpio->base + bank->val_regs + GPIO_VAL_VALUE;
+   case reg_rdata:
+   return gpio->base + bank->rdata_reg;
+   case reg_irq_enable:
+   return gpio->base + bank->irq_regs + GPIO_IRQ_ENABLE;
+   case reg_irq_type0:
+   return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE0;
+   case reg_irq_type1:
+   return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE1;
+   case reg_irq_type2:
+   return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2;
+   case reg_irq_status:
+   return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS;
+   default:
+   /* acturally if code runs to here, it's an error case */
+   BUG_ON(1);
+   }
+}
+
+#define GPIO_BANK(x)((x) >> 5)
+#define GPIO_OFFSET(x)  ((x) & 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);
+
+   WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks));
+   return _sgpio_banks[bank];
+}
+
+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(>lock, flags);
+
+   is_input = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
+   reg = is_input ? reg_val : reg_rdata;
+   rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset));
+
+   spin_unlock_irqrestore(>lock, flags);
+
+   return rc;
+}
+
+static void 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;
+   u32 reg = 0;
+
+   addr = bank_reg(gpio, bank, reg_val);
+   reg = ioread32(addr);
+
+   if (val)
+   reg |= GPIO_BIT(offset);
+   else
+   reg &= ~GPIO_BIT(offset);
+
+   iowrite32(reg, addr);
+}
+