Thread (16 messages) 16 messages, 2 authors, 2010-07-05
STALE5827d

[PATCH 3/6] U6715 gpio platform driver This driver is U6 platform generic (V2)

From: Russell King - ARM Linux <hidden>
Date: 2010-06-24 14:26:44

On Thu, May 27, 2010 at 10:27:29AM +0200, Philippe Langlais wrote:
quoted hunk ↗ jump to hunk
Signed-off-by: Philippe Langlais <redacted>
---
 arch/arm/mach-u67xx/board_u67xx_wavex.c |  469 ++++++++++++++++++++
 arch/arm/mach-u67xx/devices.c           |   12 +-
 arch/arm/plat-u6xxx/Makefile            |    2 +-
 arch/arm/plat-u6xxx/gpio.c              |  716 +++++++++++++++++++++++++++++++
 arch/arm/plat-u6xxx/include/mach/gpio.h |  396 +++++++++++++++++
 5 files changed, 1588 insertions(+), 7 deletions(-)
 create mode 100644 arch/arm/plat-u6xxx/gpio.c
 create mode 100644 arch/arm/plat-u6xxx/include/mach/gpio.h
diff --git a/arch/arm/mach-u67xx/board_u67xx_wavex.c b/arch/arm/mach-u67xx/board_u67xx_wavex.c
index 2a806e7..a21e465 100644
--- a/arch/arm/mach-u67xx/board_u67xx_wavex.c
+++ b/arch/arm/mach-u67xx/board_u67xx_wavex.c
@@ -24,6 +24,474 @@
 #include <asm/mach/arch.h>
 #include <mach/irqs.h>
 #include <mach/timer.h>
+#include <mach/gpio.h>
linux/gpio.h
+
+#include <mach/scon.h>
+
+/**
+ * SCON initial settings
+ * Allows to define the PIN multiplexing for all the platform (Linux and Modem)
+ */
+struct u6_scon_config u6_scon_init_config[SCON_REGISTER_NB] = {
+ {
+	(void __iomem *) SCON_SYSMUX0_REG,
IOMEM() to eliminate the cast?
+/* GPIO def settings to avoid HW issue */
+struct u6_gpio_config u6_gpio_init_config[] = {
+	/* GPIO A bank */
+	{
+		.gpio = GPIO_A5,
+		.dir = GPIO_DIR_OUTPUT	,
Unnecessary spaces between 'OUTPUT' and ','
quoted hunk ↗ jump to hunk
+		.value = 1,
+	},
+	{
+		.gpio = GPIO_A6,
+		.dir = GPIO_DIR_OUTPUT	,
+		.value = 1,
+	},
+	{
+		.gpio = GPIO_A7,
+		.dir = GPIO_DIR_OUTPUT	,
+		.value = 0,
+	},
+	{
+		.gpio = GPIO_A8,
+		.dir = GPIO_DIR_OUTPUT	,
+		.value = 1,
+	},
+	{
+		.gpio = GPIO_A9,
+		.dir = GPIO_DIR_OUTPUT	,
+		.value = 1,
+	},
+	{
+		.gpio = GPIO_A13,
+		.dir = GPIO_DIR_OUTPUT	,
+		.value = 0,
+	},
+	{
+		.gpio = GPIO_A17,
+		.dir = GPIO_DIR_OUTPUT	,
+		.value = 0,
+	},
+	{
+		.gpio = GPIO_A21,
+		.dir = GPIO_DIR_OUTPUT	,
+		.value = 0,
+	},
+	{
+		.gpio = GPIO_A23,
+		.dir = GPIO_DIR_OUTPUT	,
+		.value = 0,
+	},
+	{
+		.gpio = GPIO_A24,
+		.dir = GPIO_DIR_OUTPUT	,
+		.value = 1,
+	},
+	{
+		.gpio = GPIO_A25,
+		.dir = GPIO_DIR_OUTPUT	,
+		.value = 0,
+	},
+	{
+		.gpio = GPIO_A30,
+		.dir = GPIO_DIR_OUTPUT	,
+		.value = 0,
+	},
+	/* GPIO B bank */
+	/* GPIO C bank */
+	/* GPIO D bank */
+	{
+		.gpio = GPIO_D0,
+		.dir = GPIO_DIR_OUTPUT	,
+		.value = 0,
+	},
+	{
+		.gpio = GPIO_D24,
+		.dir = GPIO_DIR_OUTPUT	,
+		.value = 0,
+	},
+	{
+		.gpio = GPIO_D29,
+		.dir = GPIO_DIR_OUTPUT	,
+		.value = 0,
+	},
+	/* GPIO E bank */
+	{
+		.gpio = GPIO_E31,
+		.dir = GPIO_DIR_OUTPUT	,
+		.value = 0,
+	},
+	/* GPIO F bank */
+	{
+		.gpio = GPIO_F0,
+		.dir = GPIO_DIR_OUTPUT	,
+		.value = 0,
+	},
+	{
+		.gpio = GPIO_F1,
+		.dir = GPIO_DIR_OUTPUT	,
+		.value = 0,
+	},
+	{
+		.gpio = GPIO_F2,
+		.dir = GPIO_DIR_OUTPUT	,
+		.value = 0,
+	},
+	{
+		.gpio = GPIO_F9,
+		.dir = GPIO_DIR_OUTPUT	,
+		.value = 0,
+	}
+};
+
+u32 gpio_to_configure = ARRAY_SIZE(u6_gpio_init_config);
 
 /* List of board specific devices */
 static struct platform_device *devices[] __initdata = {
@@ -31,6 +499,7 @@ static struct platform_device *devices[] __initdata = {
 
 void __init u67xx_init(void)
 {
+	u6_gpio_init();
 	/* Add specific board devices */
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 }
diff --git a/arch/arm/mach-u67xx/devices.c b/arch/arm/mach-u67xx/devices.c
index 0ead380..8e812fb 100644
--- a/arch/arm/mach-u67xx/devices.c
+++ b/arch/arm/mach-u67xx/devices.c
@@ -48,12 +48,12 @@ unsigned char extint_to_gpio[NR_EXTINT] = {
 EXPORT_SYMBOL(extint_to_gpio);
 
 struct gpio_bank u6_gpio_bank[6] = {
-	{(void __iomem *)GPIOA_PINS_REG, (void __iomem *)SCON_SYSMUX0_REG},
-	{(void __iomem *)GPIOB_PINS_REG, (void __iomem *)SCON_SYSMUX2_REG},
-	{(void __iomem *)GPIOC_PINS_REG, (void __iomem *)SCON_SYSMUX4_REG},
-	{(void __iomem *)GPIOD_PINS_REG, (void __iomem *)SCON_SYSMUX6_REG},
-	{(void __iomem *)GPIOE_PINS_REG, (void __iomem *)SCON_SYSMUX8_REG},
-	{(void __iomem *)GPIOF_PINS_REG, (void __iomem *)SCON_SYSMUX10_REG},
+	{GPIOA_PINS_REG, SCON_SYSMUX0_REG},
+	{GPIOB_PINS_REG, SCON_SYSMUX2_REG},
+	{GPIOC_PINS_REG, SCON_SYSMUX4_REG},
+	{GPIOD_PINS_REG, SCON_SYSMUX6_REG},
+	{GPIOE_PINS_REG, SCON_SYSMUX8_REG},
+	{GPIOF_PINS_REG, SCON_SYSMUX10_REG},
 };
 
 static struct gpio_data u6_gpio_data = {
diff --git a/arch/arm/plat-u6xxx/Makefile b/arch/arm/plat-u6xxx/Makefile
index afdf82b..3d6898e 100644
--- a/arch/arm/plat-u6xxx/Makefile
+++ b/arch/arm/plat-u6xxx/Makefile
@@ -3,6 +3,6 @@
 #
 
 # Common support
-obj-y := io.o irq.o clock.o
+obj-y := io.o irq.o clock.o gpio.o
 
 obj-$(CONFIG_U6_MTU_TIMER) += timer.o
diff --git a/arch/arm/plat-u6xxx/gpio.c b/arch/arm/plat-u6xxx/gpio.c
new file mode 100644
index 0000000..40e25fc
--- /dev/null
+++ b/arch/arm/plat-u6xxx/gpio.c
@@ -0,0 +1,716 @@
+/*
+ * linux/arch/arm/plat-u6xxx/gpio.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Loic Pallardy <loic.pallardy@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ * Support functions for GPIO
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/sysdev.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <mach/irqs.h>
+#include <mach/gpio.h>
+#include <asm/mach/irq.h>
+#include <mach/scon.h>
asm/ before mach/.
+
+/*
+ * PN5220 GPIO/MUX registers
+ * defined in asm/arch/registers.h
+ */
+
+#define U6_GPIO_PINS_OFFSET	0
+#define U6_GPIO_OUTPUT_OFFSET	4
+#define U6_GPIO_DIR_OFFSET	8
+
+#define U6_MUX2_OFFSET		4
+
+static struct gpio_bank *gpio_bank_desc;
+static int gpio_bank_count;
+
+static inline struct gpio_bank *get_gpio_bank(int gpio)
+{
+	/* 32 GPIOs per bank */
+	return &(gpio_bank_desc[gpio >> 5]);
+}
+
+static inline int get_gpio_index(int gpio)
+{
+	return gpio & 0x1f;
+}
+
+static int check_gpio(int gpio)
+{
+	int retval = ((unsigned int)gpio) < GPIO_COUNT;
+	if (unlikely(!retval)) {
+		printk(KERN_ERR "u6-gpio: invalid GPIO %d\n", gpio);
+		dump_stack();
+	}
	return WARN_ON((unsigned int)gpio < GPIO_COUNT);

or use WARN(condition, format) if you want a custom message.
+static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
+{
+	u32 reg = bank->gpio_base;
+	u32 l;
+
+	/* select direction register */
+	reg += U6_GPIO_DIR_OFFSET;
+
+	/* in register 0 = input, 1 = output */
+	l = inl(reg);
inl/outl are for PCI/ISA based IO accesses/emulation.  I don't think your
GPIO block is a PCI/ISA peripheral, so it should not be using these macros.
+static int initialized;
+
+static int __init u6_gpio_probe(struct platform_device *pdev)
+{
+	int i, j;
+	int gpio = 0;
+	struct gpio_bank *bank;
+	struct gpio_data *data = pdev->dev.platform_data;
+	unsigned long flags;
+
+	initialized = 1;
Why is this here when you're really wanting to prevent the platform
driver structure being registered more than once?
+
+	printk(KERN_INFO "U6 GPIO\n");
+	gpio_bank_desc = data->gpio_bank_desc;
+	gpio_bank_count = data->nb_banks;
+
+	for (i = 0; i < gpio_bank_count; i++) {
+		int gpio_count = 32;	/* 32 GPIO per bank */
+		bank = &gpio_bank_desc[i];
+		bank->reserved_map = 0;
+		spin_lock_init(&bank->lock);
+
+		bank->chip.request = u6_gpio_acquire;
+		bank->chip.free = u6_gpio_release;
+		bank->chip.direction_input = gpio_input;
+		bank->chip.get = gpio_get;
+		bank->chip.direction_output = gpio_output;
+		bank->chip.set = gpio_set;
+		bank->chip.to_irq = gpio_2irq;
+		bank->chip.label = "gpio";
+		bank->chip.base = gpio;
+		gpio += gpio_count;
+
+		bank->chip.ngpio = gpio_count;
+
+		gpiochip_add(&bank->chip);
+
+	}
+
+	/* for extint */
+	for (j = IRQ_COUNT; j < IRQ_COUNT + NR_EXTINT; j++) {
+		set_irq_chip(j, &gpio_irq_chip);
+		set_irq_handler(j, handle_simple_irq);
+		set_irq_flags(j, IRQF_VALID);
+	}
+
+	hw_raw_local_irq_save(flags);
+	/* mask all EXT IRQ sources before registring handler */
+	/* read status */
+	j = inl(EXTINT_STATUS_REG) & inl(EXTINT_ENABLE3_REG);
+	/* clear IRQ source(s) */
+	outl(j, EXTINT_STATUS_REG);
+
+	outl(0, EXTINT_ENABLE3_REG);
+
+	/* set irq in low level */
+	set_irq_type(IRQ_EXTINT3, IRQF_TRIGGER_LOW);
+
+	/* chained GPIO-IRQ on EXTINT3 */
+	set_irq_chained_handler(IRQ_EXTINT3, gpio_irq_handler);
+	hw_raw_local_irq_restore(flags);
+
+	return 0;
+}
+
+static struct platform_driver u6_gpio_driver = {
+	.probe = u6_gpio_probe,
+	.remove = NULL,
+	.suspend = NULL,
+	.resume = NULL,
+	.driver = {
+		   .name = "u6-gpio",
+		   },
+};
+
+static struct sysdev_class u6_gpio_sysclass = {
+	.name = "gpio",
+	.suspend = 0,		/*u6_gpio_suspend, */
+	.resume = 0,		/*u6_gpio_resume, */
+};
+
+static struct sys_device u6_gpio_device = {
+	.id = 0,
+	.cls = &u6_gpio_sysclass,
+};
+
+/*
+ * This may get called early from board specific init
+ * for boards that have interrupts routed via FPGA.
+ */
+int u6_gpio_init(void)
+{
+	if (!initialized)
+		return platform_driver_register(&u6_gpio_driver);
Shouldn't this set 'initialized' once the platform driver has been
registered to prevent the platform driver being registered again?
+	else
+		return 0;
+}
+
+static int __init u6_gpio_sysinit(void)
+{
+	int ret = 0;
+
+	if (!initialized)
+		ret = u6_gpio_init();
Why not just call u6_gpio_init(), which handles the special case anyway?
quoted hunk ↗ jump to hunk
+
+	if (ret == 0) {
+		ret = sysdev_class_register(&u6_gpio_sysclass);
+		if (ret == 0)
+			ret = sysdev_register(&u6_gpio_device);
+	}
+
+	return ret;
+}
+
+arch_initcall(u6_gpio_sysinit);
diff --git a/arch/arm/plat-u6xxx/include/mach/gpio.h b/arch/arm/plat-u6xxx/include/mach/gpio.h
new file mode 100644
index 0000000..a205f1c
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/gpio.h
@@ -0,0 +1,396 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/gpio.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Loic Pallardy <loic.pallardy@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ * GPIO handling defines and functions
+ */
+
+#ifndef __ASM_PLAT_U6_GPIO_H
+#define __ASM_PLAT_U6_GPIO_H
+
+#include <linux/io.h>
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/gpio.h>
Recursive include of mach/gpio.h
+
+#include <linux/errno.h>
+#include <asm-generic/gpio.h>
linux/ includes before asm and mach includes.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help