[RFC PATCH 2/2] GPIO: add gpiolib and irqchip for CSR SiRFprimaII GPIO controller

Barry Song bs14 at csr.com
Tue Jul 26 04:13:13 EDT 2011


From: Yuping Luo <yuping.luo at csr.com>

Signed-off-by: Yuping Luo <yuping.luo at csr.com>
Signed-off-by: Barry Song <baohua.song at csr.com>
---
 arch/arm/mach-prima2/include/mach/gpio.h |   34 ++
 drivers/gpio/Kconfig                     |    6 +
 drivers/gpio/Makefile                    |    1 +
 drivers/gpio/gpio-sirf.c                 |  529 ++++++++++++++++++++++++++++++
 4 files changed, 570 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-prima2/include/mach/gpio.h
 create mode 100644 drivers/gpio/gpio-sirf.c

diff --git a/arch/arm/mach-prima2/include/mach/gpio.h b/arch/arm/mach-prima2/include/mach/gpio.h
new file mode 100644
index 0000000..25673b1
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/gpio.h
@@ -0,0 +1,34 @@
+/*
+ * arch/arm/mach-prima2/include/mach/gpio.h
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef __MACH_GPIO_H
+#define __MACH_GPIO_H
+
+#include <mach/irqs.h>
+
+#ifndef CONFIG_GPIO_SIRFCPLD
+#define ARCH_NR_GPIOS	(SIRFSOC_GPIO_BANK_SIZE * SIRFSOC_GPIO_NO_OF_BANKS)
+#else
+#define ARCH_NR_GPIOS	(SIRFSOC_GPIO_BANK_SIZE * SIRFSOC_GPIO_NO_OF_BANKS + \
+	SIRFSOC_GPIO_CPLD_SIZE + SIRFSOC_GPIO_IO_CPLD_SIZE + \
+	SIRFSOC_GPIO_HS_CPLD_SIZE)
+#endif
+
+#include <linux/errno.h>
+#include <asm-generic/gpio.h>
+
+#define gpio_get_value	__gpio_get_value
+#define gpio_set_value	__gpio_set_value
+#define gpio_cansleep	__gpio_cansleep
+#define gpio_to_irq	__gpio_to_irq
+
+void gpio_set_pull(unsigned gpio, int enable);
+void gpio_pull_down(unsigned gpio);
+void gpio_pull_up(unsigned gpio);
+
+#endif
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 3634986..c5da284 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -162,6 +162,12 @@ config GPIO_SCH
 	  The Intel Tunnel Creek processor has 5 GPIOs powered by the
 	  core power rail and 9 from suspend power supply.
 
+config GPIO_SIRF
+	bool "CSR SiRFprimaII GPIO"
+	default y
+	help
+	  Say yes here to support GPIO interface on CSR SiRFprimaII.
+
 config GPIO_VX855
 	tristate "VIA VX855/VX875 GPIO"
 	depends on MFD_SUPPORT && PCI
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 7207112..f4ffd0e 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_GPIO_S5PC100)	+= gpio-s5pc100.o
 obj-$(CONFIG_GPIO_S5PV210)	+= gpio-s5pv210.o
 
 obj-$(CONFIG_GPIO_SCH)		+= gpio-sch.o
+obj-$(CONFIG_GPIO_SIRF)		+= gpio-sirf.o
 obj-$(CONFIG_GPIO_STMPE)	+= gpio-stmpe.o
 obj-$(CONFIG_GPIO_SX150X)	+= gpio-sx150x.o
 obj-$(CONFIG_GPIO_TC3589X)	+= gpio-tc3589x.o
diff --git a/drivers/gpio/gpio-sirf.c b/drivers/gpio/gpio-sirf.c
new file mode 100644
index 0000000..34b5820
--- /dev/null
+++ b/drivers/gpio/gpio-sirf.c
@@ -0,0 +1,529 @@
+/*
+ * GPIO controller driver for CSR SiRFprimaII
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/regs-gpio.h>
+#include <mach/gpio.h>
+#include <mach/pinmux.h>
+
+#define SIRFSOC_IRQ_SIRFSOC_GPIO_GROUP0         43
+#define SIRFSOC_IRQ_SIRFSOC_GPIO_GROUP1         44
+#define SIRFSOC_IRQ_SIRFSOC_GPIO_GROUP2         45
+#define SIRFSOC_IRQ_SIRFSOC_GPIO_GROUP3         46
+#define SIRFSOC_IRQ_SIRFSOC_GPIO_GROUP4         47
+
+struct gpio_bank {
+	u8 group;
+	u16 irq;
+	u32 paden_bk_map;
+	u8 wake_mask;
+
+	spinlock_t lock;
+	struct gpio_chip chip;
+};
+
+static struct gpio_bank sirfsoc_gpio_bank[SIRFSOC_GPIO_NO_OF_BANKS] = {
+	{.group = 0, .irq = SIRFSOC_IRQ_SIRFSOC_GPIO_GROUP0,},
+	{.group = 1, .irq = SIRFSOC_IRQ_SIRFSOC_GPIO_GROUP1,},
+	{.group = 2, .irq = SIRFSOC_IRQ_SIRFSOC_GPIO_GROUP2,},
+	{.group = 3, .irq = SIRFSOC_IRQ_SIRFSOC_GPIO_GROUP3,},
+	{.group = 4, .irq = SIRFSOC_IRQ_SIRFSOC_GPIO_GROUP4,}
+};
+
+static DEFINE_SPINLOCK(gpio_lock);
+
+static struct gpio_bank *sirfsoc_irq_to_bank(unsigned int irq)
+{
+	int bk;
+
+	if ((irq < SIRFSOC_GPIO_IRQ_START) || (irq >= SIRFSOC_GPIO_IRQ_END)) {
+		printk(KERN_ALERT " Invalid GPIO IRQ/Bank: %d\n", irq);
+		return NULL;
+	}
+
+	bk = (irq - SIRFSOC_GPIO_IRQ_START) / SIRFSOC_GPIO_BANK_SIZE;
+	return &sirfsoc_gpio_bank[bk];
+}
+
+static int sirfsoc_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	return SIRFSOC_GPIO_IRQ_START + (chip->base + offset);
+}
+
+static int sirfsoc_irq_to_indx(unsigned int irq)
+{
+	return (irq - SIRFSOC_GPIO_IRQ_START) % SIRFSOC_GPIO_BANK_SIZE;
+}
+
+static struct gpio_bank *sirfsoc_gpio_to_bank(unsigned int gpio)
+{
+	unsigned int bk = gpio / SIRFSOC_GPIO_BANK_SIZE;
+
+	if (bk >= SIRFSOC_GPIO_NO_OF_BANKS) {
+		printk(KERN_ALERT "Invalid GPIO Number: %d\n", gpio);
+		return NULL;
+	} else {
+		return &sirfsoc_gpio_bank[bk];
+	}
+}
+
+static int sirfsoc_gpio_to_indx(unsigned int gpio)
+{
+	return gpio % SIRFSOC_GPIO_BANK_SIZE;
+}
+
+static void sirfsoc_gpio_irq_ack(struct irq_data *d)
+{
+	struct gpio_bank *bank = sirfsoc_irq_to_bank(d->irq);
+	int index = sirfsoc_irq_to_indx(d->irq);
+	u32 status, offset;
+	unsigned long flags;
+
+	if (bank != NULL) {
+		offset = SIRFSOC_GPIO_CTRL(bank->group, index);
+		spin_lock_irqsave(&gpio_lock, flags);
+
+		status = readl(sirfsoc_gpio_pinmux_base + offset);
+
+		writel(status, sirfsoc_gpio_pinmux_base + offset);
+		pr_debug("%s: ack gpio group %d index %d, status %#x\n",
+			__func__, bank->group, index,
+			readl(sirfsoc_gpio_pinmux_base + offset));
+		spin_unlock_irqrestore(&gpio_lock, flags);
+	}
+
+}
+
+static void _sirfsoc_gpio_irq_mask(unsigned int irq)
+{
+	struct gpio_bank *bank = sirfsoc_irq_to_bank(irq);
+	int index = sirfsoc_irq_to_indx(irq);
+	u32 status, offset;
+	unsigned long flags;
+
+	if (bank != NULL) {
+		pr_debug("%s: unmask gpio group %d index %d\n", __func__,
+			bank->group, index);
+		offset = SIRFSOC_GPIO_CTRL(bank->group, index);
+		spin_lock_irqsave(&gpio_lock, flags);
+		status = readl(sirfsoc_gpio_pinmux_base + offset);
+
+		status &= ~SIRFSOC_GPIO_CTL_INTR_EN_MASK;
+		status &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK;
+
+		writel(status, sirfsoc_gpio_pinmux_base + offset);
+
+		spin_unlock_irqrestore(&gpio_lock, flags);
+	}
+}
+
+
+static void sirfsoc_gpio_irq_mask(struct irq_data *d)
+{
+	_sirfsoc_gpio_irq_mask(d->irq);
+}
+
+static void sirfsoc_gpio_irq_unmask(struct irq_data *d)
+{
+	struct gpio_bank *bank = sirfsoc_irq_to_bank(d->irq);
+	int index = sirfsoc_irq_to_indx(d->irq);
+	u32 status, offset;
+	unsigned long flags;
+
+	if (bank != NULL) {
+		pr_debug("%s: unmask gpio group %d index %d\n", __func__,
+			bank->group, index);
+		offset = SIRFSOC_GPIO_CTRL(bank->group, index);
+
+		spin_lock_irqsave(&gpio_lock, flags);
+		status = readl(sirfsoc_gpio_pinmux_base + offset);
+
+		status &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK;
+		status |= SIRFSOC_GPIO_CTL_INTR_EN_MASK;
+
+		writel(status, sirfsoc_gpio_pinmux_base + offset);
+		spin_unlock_irqrestore(&gpio_lock, flags);
+	}
+}
+
+static int sirfsoc_gpio_irq_type(struct irq_data *d, unsigned type)
+{
+	struct gpio_bank *bank = sirfsoc_irq_to_bank(d->irq);
+	int index = sirfsoc_irq_to_indx(d->irq);
+	u32 status, offset;
+	unsigned long flags;
+
+	if (bank == NULL)
+		return -EINVAL;
+
+	offset = SIRFSOC_GPIO_CTRL(bank->group, index);
+	spin_lock_irqsave(&gpio_lock, flags);
+	status = readl(sirfsoc_gpio_pinmux_base + offset);
+	status &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK;
+
+	switch (type) {
+	case IRQ_TYPE_NONE:
+		break;
+	case IRQ_TYPE_EDGE_RISING:
+		status |= (SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK);
+		status &= ~SIRFSOC_GPIO_CTL_INTR_LOW_MASK;
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		status &= ~SIRFSOC_GPIO_CTL_INTR_HIGH_MASK;
+		status |= (SIRFSOC_GPIO_CTL_INTR_LOW_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK);
+		break;
+	case IRQ_TYPE_EDGE_BOTH:
+		status |=
+			(SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_LOW_MASK |
+			 SIRFSOC_GPIO_CTL_INTR_TYPE_MASK);
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+		status &= ~(SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK);
+		status |= SIRFSOC_GPIO_CTL_INTR_LOW_MASK;
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		status |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK;
+		status &= ~(SIRFSOC_GPIO_CTL_INTR_LOW_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK);
+		break;
+	}
+
+	writel(status, sirfsoc_gpio_pinmux_base + offset);
+
+	spin_unlock_irqrestore(&gpio_lock, flags);
+
+	return 0;
+}
+
+static struct irq_chip sirfsoc_irq_chip = {
+	.name = "SiRF SoC GPIO IRQ",
+	.irq_ack = sirfsoc_gpio_irq_ack,
+	.irq_mask = sirfsoc_gpio_irq_mask,
+	.irq_unmask = sirfsoc_gpio_irq_unmask,
+	.irq_set_type = sirfsoc_gpio_irq_type,
+};
+
+static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc)
+{
+	struct gpio_bank *bank = NULL;
+	u32 status, ctrl;
+	int i, index = 0;
+
+	pr_debug("%s: irq %d\n", __func__, irq);
+
+	for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
+		if (sirfsoc_gpio_bank[i].irq == irq) {
+			bank = &sirfsoc_gpio_bank[i];
+			break;
+		}
+	}
+
+	if (bank == NULL) {
+		printk(KERN_ALERT " Invalid GPIO IRQ/Bank: %d\n", irq);
+		handle_bad_irq(irq, desc);
+		return;
+	}
+
+	status = readl(sirfsoc_gpio_pinmux_base + SIRFSOC_GPIO_INT_STATUS(bank->group));
+	if (!status) {
+		printk(KERN_WARNING
+			"%s: gpio group %d status %#x no interrupt is flaged\n",
+			__func__, bank->group, status);
+		handle_bad_irq(irq, desc);
+		return;
+	}
+
+	while (status) {
+		ctrl = readl(sirfsoc_gpio_pinmux_base + SIRFSOC_GPIO_CTRL(bank->group, index));
+
+		/*
+		 * Here we must check whether the corresponding GPIO's interrupt
+		 * has been enabled, otherwise just skip it
+		 */
+		if ((status & 0x1) && (ctrl & SIRFSOC_GPIO_CTL_INTR_EN_MASK)) {
+			pr_debug("%s: gpio group %d index %d happens\n",
+				__func__, bank->group, index);
+			irq =
+				(SIRFSOC_GPIO_IRQ_START +
+				 (bank->group * SIRFSOC_GPIO_BANK_SIZE)) + index;
+			generic_handle_irq(irq);
+		}
+
+		index++;
+		status = status >> 1;
+	}
+
+	return;
+}
+
+static inline void sirfsoc_gpio_set_input(struct gpio_bank *bank, unsigned ctrl_offset)
+{
+	u32 status;
+	status = readl(sirfsoc_gpio_pinmux_base + ctrl_offset);
+	status &= ~SIRFSOC_GPIO_CTL_OUT_EN_MASK;
+	writel(status, sirfsoc_gpio_pinmux_base + ctrl_offset);
+}
+
+static int sirfsoc_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
+	unsigned long flags;
+
+	spin_lock_irqsave(&bank->lock, flags);
+
+	/*set direction as input and disable/mask irq */
+	sirfsoc_gpio_set_input(bank, SIRFSOC_GPIO_CTRL(bank->group, offset));
+	_sirfsoc_gpio_irq_mask(sirfsoc_gpio_to_irq(chip, offset));
+	sirfsoc_get_gpio(bank->group, offset);
+
+	spin_unlock_irqrestore(&bank->lock, flags);
+	return 0;
+}
+
+static void sirfsoc_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+	struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
+	unsigned long flags;
+
+	spin_lock_irqsave(&bank->lock, flags);
+
+	/*disable irq */
+	_sirfsoc_gpio_irq_mask(sirfsoc_gpio_to_irq(chip, offset));
+
+	/*set gpio to input */
+	sirfsoc_gpio_set_input(bank, SIRFSOC_GPIO_CTRL(bank->group, offset));
+
+	if (bank->paden_bk_map & (1 << offset))
+		sirfsoc_get_gpio(bank->group, offset);
+	else
+		sirfsoc_put_gpio(bank->group, offset);
+}
+
+static int sirfsoc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+	struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
+	int index = sirfsoc_gpio_to_indx(gpio);
+	unsigned long flags;
+	unsigned offset;
+
+	offset = SIRFSOC_GPIO_CTRL(bank->group, index);
+	spin_lock_irqsave(&bank->lock, flags);
+	sirfsoc_gpio_set_input(bank, offset);
+	spin_unlock_irqrestore(&bank->lock, flags);
+	return 0;
+}
+
+static inline void sirfsoc_gpio_set_output(struct gpio_bank *bank, unsigned offset,
+	int value)
+{
+	u32 status;
+
+	status = readl(sirfsoc_gpio_pinmux_base + offset);
+	if (value)
+		status |= SIRFSOC_GPIO_CTL_DATAOUT_MASK;
+	else
+		status &= ~SIRFSOC_GPIO_CTL_DATAOUT_MASK;
+
+	status &= ~SIRFSOC_GPIO_CTL_INTR_EN_MASK;
+	status |= SIRFSOC_GPIO_CTL_OUT_EN_MASK;
+
+	writel(status, sirfsoc_gpio_pinmux_base + offset);
+}
+
+static int sirfsoc_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value)
+{
+	struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
+	int index = sirfsoc_gpio_to_indx(gpio);
+	u32 offset;
+	unsigned long flags;
+
+	offset = SIRFSOC_GPIO_CTRL(bank->group, index);
+	spin_lock_irqsave(&gpio_lock, flags);
+	sirfsoc_gpio_set_output(bank, offset, value);
+	spin_unlock_irqrestore(&gpio_lock, flags);
+
+	return 0;
+}
+
+void gpio_set_pull(unsigned gpio, int enable)
+{
+	struct gpio_bank *bank = sirfsoc_gpio_to_bank(gpio);
+	int index = sirfsoc_gpio_to_indx(gpio);
+	u32 status, offset;
+	unsigned long flags;
+
+	BUG_ON(!bank);
+
+	offset = SIRFSOC_GPIO_CTRL(bank->group, index);
+
+	spin_lock_irqsave(&gpio_lock, flags);
+
+	status = readl(sirfsoc_gpio_pinmux_base + offset);
+
+	if (enable)
+		status |= SIRFSOC_GPIO_CTL_PULL_MASK;
+	else
+		status &= ~SIRFSOC_GPIO_CTL_PULL_MASK;
+
+	writel(status, sirfsoc_gpio_pinmux_base + offset);
+
+	spin_unlock_irqrestore(&gpio_lock, flags);
+}
+EXPORT_SYMBOL(gpio_set_pull);
+
+void gpio_pull_up(unsigned int gpio)
+{
+	struct gpio_bank *bank = sirfsoc_gpio_to_bank(gpio);
+	int index = sirfsoc_gpio_to_indx(gpio);
+	u32 status, offset;
+	unsigned long flags;
+
+	BUG_ON(!bank);
+
+	gpio_set_pull(gpio, 1);
+
+	offset = SIRFSOC_GPIO_CTRL(bank->group, index);
+
+	spin_lock_irqsave(&gpio_lock, flags);
+
+	status = readl(sirfsoc_gpio_pinmux_base + offset);
+	status |= SIRFSOC_GPIO_CTL_PULL_HIGH;
+	writel(status, sirfsoc_gpio_pinmux_base + offset);
+
+	spin_unlock_irqrestore(&gpio_lock, flags);
+}
+EXPORT_SYMBOL(gpio_pull_up);
+
+void gpio_pull_down(unsigned int gpio)
+{
+	struct gpio_bank *bank = sirfsoc_gpio_to_bank(gpio);
+	int index = sirfsoc_gpio_to_indx(gpio);
+	u32 status, offset;
+	unsigned long flags;
+
+	BUG_ON(!bank);
+
+	gpio_set_pull(gpio, 1);
+
+	offset = SIRFSOC_GPIO_CTRL(bank->group, index);
+
+	spin_lock_irqsave(&gpio_lock, flags);
+
+	status = readl(sirfsoc_gpio_pinmux_base + offset);
+	status &= ~SIRFSOC_GPIO_CTL_PULL_HIGH;
+	writel(status, sirfsoc_gpio_pinmux_base + offset);
+
+	spin_unlock_irqrestore(&gpio_lock, flags);
+}
+EXPORT_SYMBOL(gpio_pull_down);
+
+static int sirfsoc_gpio_get_value(struct gpio_chip *chip, unsigned offset)
+{
+	struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
+	u32 status;
+
+	status = readl(sirfsoc_gpio_pinmux_base + SIRFSOC_GPIO_CTRL(bank->group, offset));
+
+	return !!(status & SIRFSOC_GPIO_CTL_DATAIN_MASK);
+}
+
+static void sirfsoc_gpio_set_value(struct gpio_chip *chip, unsigned offset,
+	int value)
+{
+	struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
+	u32 status;
+
+	status = readl(sirfsoc_gpio_pinmux_base + SIRFSOC_GPIO_CTRL(bank->group, offset));
+	if (value)
+		status |= SIRFSOC_GPIO_CTL_DATAOUT_MASK;
+	else
+		status &= ~SIRFSOC_GPIO_CTL_DATAOUT_MASK;
+	writel(status, sirfsoc_gpio_pinmux_base + SIRFSOC_GPIO_CTRL(bank->group, offset));
+}
+
+static int sirfsoc_gpio_probe(struct platform_device *pdev)
+{
+	int i;
+
+	struct gpio_bank *bank;
+	int gpio = 0;
+
+	for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
+		bank = &sirfsoc_gpio_bank[i];
+		spin_lock_init(&bank->lock);
+		bank->paden_bk_map = readl(sirfsoc_gpio_pinmux_base + SIRFSOC_GPIO_PAD_EN(i));
+		irq_set_chained_handler(bank->irq, sirfsoc_gpio_handle_irq);
+
+		bank->chip.request = sirfsoc_gpio_request;
+		bank->chip.free = sirfsoc_gpio_free;
+		bank->chip.direction_input = sirfsoc_gpio_direction_input;
+		bank->chip.get = sirfsoc_gpio_get_value;
+		bank->chip.direction_output = sirfsoc_gpio_direction_output;
+		bank->chip.set = sirfsoc_gpio_set_value;
+		bank->chip.to_irq = sirfsoc_gpio_to_irq;
+
+		bank->chip.label = "gpio";
+		bank->chip.base = gpio;
+
+		gpio += SIRFSOC_GPIO_BANK_SIZE;
+		bank->chip.ngpio = SIRFSOC_GPIO_BANK_SIZE;
+		gpiochip_add(&bank->chip);
+	}
+
+	for (i = SIRFSOC_GPIO_IRQ_START; i < SIRFSOC_GPIO_IRQ_END; i++) {
+		irq_set_chip(i, &sirfsoc_irq_chip);
+		irq_set_handler(i, handle_level_irq);
+		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+	}
+
+	return 0;
+}
+
+static int sirfsoc_gpio_remove(struct platform_device *dev)
+{
+	return 0;
+}
+
+static const struct of_device_id sirf_gpio_of_match[] = {
+	{.compatible = "sirf,prima2-gpio", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, sirf_gpio_of_match);
+
+static struct platform_driver sirfsoc_gpio_driver = {
+	.driver		= {
+		.name	= "sirfsoc_gpio",
+		.of_match_table = sirf_gpio_of_match,
+	},
+	.probe		= sirfsoc_gpio_probe,
+	.remove		= sirfsoc_gpio_remove,
+};
+
+static int __init sirfsoc_gpio_init(void)
+{
+	return platform_driver_register(&sirfsoc_gpio_driver);
+}
+core_initcall(sirfsoc_gpio_init);
+
+static void __exit sirfsoc_gpio_exit(void)
+{
+	platform_driver_unregister(&sirfsoc_gpio_driver);
+}
+module_exit(sirfsoc_gpio_exit);
+
+MODULE_DESCRIPTION("SiRFSoC gpio driver");
+MODULE_AUTHOR("Yuping Luo <yuping.luo at csr.com>, Barry Song <baohua.song at csr.com>");
+MODULE_LICENSE("GPL");
-- 
1.7.1



Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom
More information can be found at www.csr.com. Follow CSR on Twitter at http://twitter.com/CSR_PLC and read our blog at www.csr.com/blog



More information about the linux-arm-kernel mailing list