Browse Source

dm: gpio: add BCM6345 gpio driver

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>
Álvaro Fernández Rojas 8 years ago
parent
commit
e64bdb2fcf
3 changed files with 132 additions and 0 deletions
  1. 6 0
      drivers/gpio/Kconfig
  2. 1 0
      drivers/gpio/Makefile
  3. 125 0
      drivers/gpio/bcm6345_gpio.c

+ 6 - 0
drivers/gpio/Kconfig

@@ -21,6 +21,12 @@ config ALTERA_PIO
 	  Select this to enable PIO for Altera devices. Please find
 	  Select this to enable PIO for Altera devices. Please find
 	  details on the "Embedded Peripherals IP User Guide" of Altera.
 	  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
 config DWAPB_GPIO
 	bool "DWAPB GPIO driver"
 	bool "DWAPB GPIO driver"
 	depends on DM && DM_GPIO
 	depends on DM && DM_GPIO

+ 1 - 0
drivers/gpio/Makefile

@@ -16,6 +16,7 @@ obj-$(CONFIG_DM_74X164)		+= 74x164_gpio.o
 
 
 obj-$(CONFIG_AT91_GPIO)	+= at91_gpio.o
 obj-$(CONFIG_AT91_GPIO)	+= at91_gpio.o
 obj-$(CONFIG_ATMEL_PIO4)	+= atmel_pio4.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_ICH6_GPIO)	+= intel_ich6_gpio.o
 obj-$(CONFIG_INTEL_BROADWELL_GPIO)	+= intel_broadwell_gpio.o
 obj-$(CONFIG_INTEL_BROADWELL_GPIO)	+= intel_broadwell_gpio.o
 obj-$(CONFIG_KIRKWOOD_GPIO)	+= kw_gpio.o
 obj-$(CONFIG_KIRKWOOD_GPIO)	+= kw_gpio.o

+ 125 - 0
drivers/gpio/bcm6345_gpio.c

@@ -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,
+};