[PATCH 19/19] MPC5125/GPIO: add a generic GPIO driver

Juergen Borleis jbe at pengutronix.de
Tue Oct 7 07:22:18 PDT 2014


The MPC5125 can handle up to 64 GPIOs divided in two units to control them.
Note: this driver cannot be used with a MPC521 or MPC5123!

Signed-off-by: Juergen Borleis <jbe at pengutronix.de>
---
 arch/ppc/include/asm/gpio.h                  |  28 ++++++
 arch/ppc/mach-mpc5xxx/Kconfig                |   1 +
 arch/ppc/mach-mpc5xxx/include/mach/mpc512x.h |   2 +
 drivers/gpio/Kconfig                         |   6 ++
 drivers/gpio/Makefile                        |   1 +
 drivers/gpio/gpio-mpc5125.c                  | 136 +++++++++++++++++++++++++++
 6 files changed, 174 insertions(+)
 create mode 100644 arch/ppc/include/asm/gpio.h
 create mode 100644 drivers/gpio/gpio-mpc5125.c

diff --git a/arch/ppc/include/asm/gpio.h b/arch/ppc/include/asm/gpio.h
new file mode 100644
index 0000000..63b712d
--- /dev/null
+++ b/arch/ppc/include/asm/gpio.h
@@ -0,0 +1,28 @@
+#ifndef _ARCH_PPC_GPIO_H
+#define _ARCH_PPC_GPIO_H
+
+#ifndef CONFIG_GPIOLIB
+#include <mach/gpio.h>
+#else /* CONFIG_GPIOLIB */
+#ifdef CONFIG_SOC_MPC5125
+# define ARCH_NR_GPIOS 64
+#else
+# error "GPIO count for this architecture is undefined"
+#endif
+
+static inline int gpio_is_valid(int gpio)
+{
+	if (gpio < 0)
+		return 0;
+	if (gpio < ARCH_NR_GPIOS)
+		return 1;
+	return 0;
+}
+
+void gpio_set_value(unsigned gpio, int value);
+int gpio_get_value(unsigned gpio);
+int gpio_direction_output(unsigned gpio, int value);
+int gpio_direction_input(unsigned gpio);
+#endif /* CONFIG_GPIOLIB */
+
+#endif /* _ARCH_PPC_GPIO_H */
diff --git a/arch/ppc/mach-mpc5xxx/Kconfig b/arch/ppc/mach-mpc5xxx/Kconfig
index a65c21d..0e969b7 100644
--- a/arch/ppc/mach-mpc5xxx/Kconfig
+++ b/arch/ppc/mach-mpc5xxx/Kconfig
@@ -35,6 +35,7 @@ config SOC_MPC5125
 	bool
 	select MPC5xxx
 	select ARCH_MPC512X
+	select GPIOLIB
 
 config MPC5xxx
 	bool
diff --git a/arch/ppc/mach-mpc5xxx/include/mach/mpc512x.h b/arch/ppc/mach-mpc5xxx/include/mach/mpc512x.h
index ed60f2a..20df42f 100644
--- a/arch/ppc/mach-mpc5xxx/include/mach/mpc512x.h
+++ b/arch/ppc/mach-mpc5xxx/include/mach/mpc512x.h
@@ -54,6 +54,8 @@
 #define MPC512X_RESET	(CFG_MBAR + 0x00E00)
 #define MPC512X_CLKM	(CFG_MBAR + 0x00f00)
 #define MPC512X_WDT	(CFG_MBAR + 0x00900)
+#define MPC512X_GPIO1	(CFG_MBAR + 0x01100)
+#define MPC512X_GPIO2	(CFG_MBAR + 0x01180)
 #define MPC512X_FEC1	(CFG_MBAR + 0x02800)
 #define MPC512X_FEC2	(CFG_MBAR + 0x04800)
 #define MPC512X_DRAMC	(CFG_MBAR + 0x09000)
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 0ca7df4..e16ff80 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -110,6 +110,12 @@ config GPIO_DESIGNWARE
 	help
 	  Say Y or M here to build support for the Synopsys DesignWare APB
 	  GPIO block.
+
+config GPIO_MPC5125
+	tristate "PowerPC MPC5125 GPIO driver"
+	depends on SOC_MPC5125
+	help
+	  Say Y here to build support for the MPC5125 GPIO block.
 endmenu
 
 endif
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 510d146..82206db 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -15,3 +15,4 @@ obj-$(CONFIG_GPIO_PL061)	+= gpio-pl061.o
 obj-$(CONFIG_GPIO_STMPE)	+= gpio-stmpe.o
 obj-$(CONFIG_GPIO_TEGRA)	+= gpio-tegra.o
 obj-$(CONFIG_GPIO_DESIGNWARE)	+= gpio-dw.o
+obj-$(CONFIG_GPIO_MPC5125)	+= gpio-mpc5125.o
diff --git a/drivers/gpio/gpio-mpc5125.c b/drivers/gpio/gpio-mpc5125.c
new file mode 100644
index 0000000..8d1bcb3
--- /dev/null
+++ b/drivers/gpio/gpio-mpc5125.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2014 Juergen Borleis, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <init.h>
+#include <asm/io.h>
+#include <gpio.h>
+#include <mach/mpc5xxx.h>
+
+#define GPIO_DIR 0
+#define GPIO_ODR 1
+#define GPIO_DAT 2
+#define GPIO_IER 3
+#define GPIO_IMR 4
+#define GPIO_ICR1 5
+#define GPIO_ICR2 6
+
+struct mpc5125_gpio_chip {
+	u32 __iomem *base;
+	struct gpio_chip chip;
+};
+
+static unsigned gpio_no_to_bit(unsigned gpio)
+{
+	/*
+	 * GPIO0 is the highest bit in the register m(
+	 *  regular notation: GPIO0 is register bit 31
+	 *  PPC notation: GPIO0 is register bit 0
+	 */
+	return 1 << (31 - gpio);
+}
+
+static void mpc5125_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
+{
+	struct mpc5125_gpio_chip *mpcgpio = container_of(chip, struct mpc5125_gpio_chip, chip);
+
+	if (value != 0)
+		setbits_be32(&mpcgpio->base[GPIO_DAT], gpio_no_to_bit(gpio));
+	else
+		clrbits_be32(&mpcgpio->base[GPIO_DAT], gpio_no_to_bit(gpio));
+}
+
+static int mpc5125_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+	struct mpc5125_gpio_chip *mpcgpio = container_of(chip, struct mpc5125_gpio_chip, chip);
+
+	clrbits_be32(&mpcgpio->base[GPIO_DIR], gpio_no_to_bit(gpio));
+	return 0;
+}
+
+static int mpc5125_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value)
+{
+	struct mpc5125_gpio_chip *mpcgpio = container_of(chip, struct mpc5125_gpio_chip, chip);
+
+	/* GPIO 0 ... 3 in GPIO unit 1 are input only */
+	if (mpcgpio->chip.dev->id == 0 && gpio < 4) {
+		dev_err(mpcgpio->chip.dev, "GPIO %u is input only\n", gpio);
+		return -ENODEV;
+	}
+
+	if (value != 0)
+		setbits_be32(&mpcgpio->base[GPIO_DAT], gpio_no_to_bit(gpio));
+	else
+		clrbits_be32(&mpcgpio->base[GPIO_DAT], gpio_no_to_bit(gpio));
+	setbits_be32(&mpcgpio->base[GPIO_DIR], gpio_no_to_bit(gpio));
+
+	return 0;
+}
+
+static int mpc5125_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
+{
+	struct mpc5125_gpio_chip *mpcgpio = container_of(chip, struct mpc5125_gpio_chip, chip);
+
+	return in_be32(&mpcgpio->base[GPIO_DAT]) & gpio_no_to_bit(gpio) ? 1 : 0;
+}
+
+static int mpc5125_get_direction(struct gpio_chip *chip, unsigned gpio)
+{
+	struct mpc5125_gpio_chip *mpcgpio = container_of(chip, struct mpc5125_gpio_chip, chip);
+
+	return in_be32(&mpcgpio->base[GPIO_DIR]) & gpio_no_to_bit(gpio) ?
+					GPIOF_DIR_OUT : GPIOF_DIR_IN;
+}
+
+static struct gpio_ops mpc5125_gpio_ops = {
+	.direction_input = mpc5125_gpio_direction_input,
+	.direction_output = mpc5125_gpio_direction_output,
+	.get = mpc5125_gpio_get_value,
+	.set = mpc5125_gpio_set_value,
+	.get_direction = mpc5125_get_direction,
+};
+
+static int mpc5125_gpio_probe(struct device_d *dev)
+{
+	struct mpc5125_gpio_chip *mpcgpio;
+
+	mpcgpio = xzalloc(sizeof(*mpcgpio));
+	mpcgpio->base = dev_request_mem_region(dev, 0);
+	mpcgpio->chip.ops = &mpc5125_gpio_ops;
+	mpcgpio->chip.base = dev->id * 32;
+	mpcgpio->chip.ngpio = 32;
+	mpcgpio->chip.dev = dev;
+	gpiochip_add(&mpcgpio->chip);
+
+	dev_dbg(dev, "probed gpiochip%d with base %d\n", dev->id, mpcgpio->chip.base);
+
+	return 0;
+}
+
+static struct driver_d mpc5125_gpio_driver = {
+	.name = "mpc5125-gpio",
+	.probe = mpc5125_gpio_probe,
+};
+
+static int mpc5125_gpio_add(void)
+{
+	platform_driver_register(&mpc5125_gpio_driver);
+	add_generic_device("mpc5125-gpio", 0, NULL, MPC512X_GPIO1,
+				0x80, IORESOURCE_MEM, NULL);
+	add_generic_device("mpc5125-gpio", 1, NULL, MPC512X_GPIO2,
+				0x80, IORESOURCE_MEM, NULL);
+	return 0;
+}
+coredevice_initcall(mpc5125_gpio_add);
-- 
2.1.0




More information about the barebox mailing list