dm: gpio: add BCM6345 gpio driver
authorÁlvaro Fernández Rojas <noltari@gmail.com>
Sun, 7 May 2017 18:09:30 +0000 (20:09 +0200)
committerDaniel Schwierzeck <daniel.schwierzeck@gmail.com>
Wed, 10 May 2017 14:16:09 +0000 (16:16 +0200)
This driver is based on linux/arch/mips/bcm63xx/gpio.c, simplified to allow
defining one or two independent banks for each Broadcom SoC.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/bcm6345_gpio.c [new file with mode: 0644]

index 99516119ff1d2486c1ef902d7a060aa35a004bfc..325d053931f73decd19aa8a2e1cae81793617a7f 100644 (file)
@@ -21,6 +21,12 @@ config ALTERA_PIO
          Select this to enable PIO for Altera devices. Please find
          details on the "Embedded Peripherals IP User Guide" of Altera.
 
+config BCM6345_GPIO
+       bool "BCM6345 GPIO driver"
+       depends on DM_GPIO && ARCH_BMIPS
+       help
+         This driver supports the GPIO banks on BCM6345 SoCs.
+
 config DWAPB_GPIO
        bool "DWAPB GPIO driver"
        depends on DM && DM_GPIO
index 0ca845f54caa6bcc1111e44ad591eb7016de9429..03df558879b00963d9a6614fd0a96a06094e012f 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_DM_74X164)               += 74x164_gpio.o
 
 obj-$(CONFIG_AT91_GPIO)        += at91_gpio.o
 obj-$(CONFIG_ATMEL_PIO4)       += atmel_pio4.o
+obj-$(CONFIG_BCM6345_GPIO)     += bcm6345_gpio.o
 obj-$(CONFIG_INTEL_ICH6_GPIO)  += intel_ich6_gpio.o
 obj-$(CONFIG_INTEL_BROADWELL_GPIO)     += intel_broadwell_gpio.o
 obj-$(CONFIG_KIRKWOOD_GPIO)    += kw_gpio.o
diff --git a/drivers/gpio/bcm6345_gpio.c b/drivers/gpio/bcm6345_gpio.c
new file mode 100644 (file)
index 0000000..1c46020
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/arch/mips/bcm63xx/gpio.c:
+ *     Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ *     Copyright (C) 2008-2011 Florian Fainelli <florian@openwrt.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <dm/device.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct bcm6345_gpio_priv {
+       void __iomem *reg_dirout;
+       void __iomem *reg_data;
+};
+
+static int bcm6345_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+       struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
+
+       return !!(readl_be(priv->reg_data) & BIT(offset));
+}
+
+static int bcm6345_gpio_set_value(struct udevice *dev, unsigned offset,
+                                 int value)
+{
+       struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
+
+       if (value)
+               setbits_be32(priv->reg_data, BIT(offset));
+       else
+               clrbits_be32(priv->reg_data, BIT(offset));
+
+       return 0;
+}
+
+static int bcm6345_gpio_set_direction(void __iomem *dirout, unsigned offset,
+                                     bool input)
+{
+       if (input)
+               clrbits_be32(dirout, BIT(offset));
+       else
+               setbits_be32(dirout, BIT(offset));
+
+       return 0;
+}
+
+static int bcm6345_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+       struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
+
+       return bcm6345_gpio_set_direction(priv->reg_dirout, offset, 1);
+}
+
+static int bcm6345_gpio_direction_output(struct udevice *dev, unsigned offset,
+                                        int value)
+{
+       struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
+
+       return bcm6345_gpio_set_direction(priv->reg_dirout, offset, 0);
+}
+
+static int bcm6345_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+       struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
+
+       if (readl_be(priv->reg_dirout) & BIT(offset))
+               return GPIOF_OUTPUT;
+       else
+               return GPIOF_INPUT;
+}
+
+static const struct dm_gpio_ops bcm6345_gpio_ops = {
+       .direction_input = bcm6345_gpio_direction_input,
+       .direction_output = bcm6345_gpio_direction_output,
+       .get_value = bcm6345_gpio_get_value,
+       .set_value = bcm6345_gpio_set_value,
+       .get_function = bcm6345_gpio_get_function,
+};
+
+static int bcm6345_gpio_probe(struct udevice *dev)
+{
+       struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+       struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
+       fdt_addr_t data_addr, dirout_addr;
+       fdt_size_t data_size, dirout_size;
+
+       dirout_addr = dev_get_addr_size_index(dev, 0, &dirout_size);
+       if (dirout_addr == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       data_addr = dev_get_addr_size_index(dev, 1, &data_size);
+       if (data_addr == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       priv->reg_data = ioremap(data_addr, data_size);
+       priv->reg_dirout = ioremap(dirout_addr, dirout_size);
+
+       uc_priv->gpio_count = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
+                                             "ngpios", 32);
+       uc_priv->bank_name = dev->name;
+
+       return 0;
+}
+
+static const struct udevice_id bcm6345_gpio_ids[] = {
+       { .compatible = "brcm,bcm6345-gpio" },
+       { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(bcm6345_gpio) = {
+       .name = "bcm6345-gpio",
+       .id = UCLASS_GPIO,
+       .of_match = bcm6345_gpio_ids,
+       .ops = &bcm6345_gpio_ops,
+       .priv_auto_alloc_size = sizeof(struct bcm6345_gpio_priv),
+       .probe = bcm6345_gpio_probe,
+};