summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Crispin <john@openwrt.org>2014-09-12 06:54:10 +0000
committerJohn Crispin <john@openwrt.org>2014-09-12 06:54:10 +0000
commitcb5902d6034413c3f82197e2d3a75d16e739aa12 (patch)
tree49e54876777495792c9ae3884899ae2a7ada31ea
parenta8799105d77032d2e448bd0d05486a3dc3cee24a (diff)
downloadmtk-20170518-cb5902d6034413c3f82197e2d3a75d16e739aa12.zip
mtk-20170518-cb5902d6034413c3f82197e2d3a75d16e739aa12.tar.gz
mtk-20170518-cb5902d6034413c3f82197e2d3a75d16e739aa12.tar.bz2
atheros: convert AR2315 GPIO code to platform driver
Convert gpiolib realization to platform driver and move to the appropriate subdirectory. Misc GPIO interrupt acknowledgement placed to the MISC IRQ handler since in fact we can detect only one GPIO state change. Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com> SVN-Revision: 42512
-rw-r--r--target/linux/atheros/config-3.141
-rw-r--r--target/linux/atheros/patches-3.14/100-board.patch175
-rw-r--r--target/linux/atheros/patches-3.14/103-ar2315_gpio.patch315
-rw-r--r--target/linux/atheros/patches-3.14/105-ar2315_pci.patch8
4 files changed, 327 insertions, 172 deletions
diff --git a/target/linux/atheros/config-3.14 b/target/linux/atheros/config-3.14
index 5d1041a..8c6e68d 100644
--- a/target/linux/atheros/config-3.14
+++ b/target/linux/atheros/config-3.14
@@ -44,6 +44,7 @@ CONFIG_GENERIC_NET_UTILS=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GPIOLIB=y
+CONFIG_GPIO_AR2315=y
CONFIG_GPIO_AR5312=y
CONFIG_GPIO_DEVRES=y
CONFIG_GPIO_SYSFS=y
diff --git a/target/linux/atheros/patches-3.14/100-board.patch b/target/linux/atheros/patches-3.14/100-board.patch
index 8ffa91c..32b6dc8 100644
--- a/target/linux/atheros/patches-3.14/100-board.patch
+++ b/target/linux/atheros/patches-3.14/100-board.patch
@@ -659,7 +659,7 @@
+#endif /* __ASM_MACH_AR231X_WAR_H */
--- /dev/null
+++ b/arch/mips/include/asm/mach-ar231x/ar2315_regs.h
-@@ -0,0 +1,630 @@
+@@ -0,0 +1,608 @@
+/*
+ * Register definitions for AR2315+
+ *
@@ -1002,32 +1002,10 @@
+#define AMBACLK_CLK_DIV_M 0x0000000c
+#define AMBACLK_CLK_DIV_S 2
+
-+/*
-+ * GPIO
-+ */
-+#define AR2315_GPIO_DI (AR2315_DSLBASE + 0x0088)
-+#define AR2315_GPIO_DO (AR2315_DSLBASE + 0x0090)
-+#define AR2315_GPIO_DIR (AR2315_DSLBASE + 0x0098)
-+#define AR2315_GPIO_INT (AR2315_DSLBASE + 0x00a0)
-+
-+#define AR2315_GPIO_DIR_M(x) (1 << (x)) /* mask for i/o */
-+#define AR2315_GPIO_DIR_O(x) (1 << (x)) /* output */
-+#define AR2315_GPIO_DIR_I(x) (0) /* input */
-+
-+#define AR2315_GPIO_INT_S(x) (x) /* interrupt enable */
-+#define AR2315_GPIO_INT_M (0x3F) /* mask for int */
-+#define AR2315_GPIO_INT_LVL(x) ((x) << 6) /* interrupt level */
-+#define AR2315_GPIO_INT_LVL_M ((0x3) << 6) /* mask for int level */
-+
-+#define AR2315_GPIO_INT_MAX_Y 1 /* Maximum value of Y for
-+ * AR2315_GPIO_INT_* macros */
-+#define AR2315_GPIO_INT_LVL_OFF 0 /* Triggerring off */
-+#define AR2315_GPIO_INT_LVL_LOW 1 /* Low Level Triggered */
-+#define AR2315_GPIO_INT_LVL_HIGH 2 /* High Level Triggered */
-+#define AR2315_GPIO_INT_LVL_EDGE 3 /* Edge Triggered */
++/* GPIO MMR base address */
++#define AR2315_GPIO (AR2315_DSLBASE + 0x0088)
+
+#define AR2315_RESET_GPIO 5
-+#define AR2315_NUM_GPIO 22
+
+/*
+ * PCI Clock Control
@@ -2009,7 +1987,7 @@
+
--- /dev/null
+++ b/arch/mips/ar231x/ar2315.c
-@@ -0,0 +1,570 @@
+@@ -0,0 +1,431 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
@@ -2049,34 +2027,6 @@
+#include "devices.h"
+#include "ar2315.h"
+
-+static u32 gpiointmask, gpiointval;
-+
-+static void ar2315_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
-+{
-+ u32 pend;
-+ int bit = -1;
-+
-+ /* only do one gpio interrupt at a time */
-+ pend = (ar231x_read_reg(AR2315_GPIO_DI) ^ gpiointval) & gpiointmask;
-+
-+ if (pend) {
-+ bit = fls(pend) - 1;
-+ pend &= ~(1 << bit);
-+ gpiointval ^= (1 << bit);
-+ }
-+
-+ if (!pend)
-+ ar231x_write_reg(AR2315_ISR, AR2315_ISR_GPIO);
-+
-+ /* Enable interrupt with edge detection */
-+ if ((ar231x_read_reg(AR2315_GPIO_DIR) & AR2315_GPIO_DIR_M(bit)) !=
-+ AR2315_GPIO_DIR_I(bit))
-+ return;
-+
-+ if (bit >= 0)
-+ generic_handle_irq(AR231X_GPIO_IRQ_BASE + bit);
-+}
-+
+static void ar2315_misc_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+ unsigned int misc_intr = ar231x_read_reg(AR2315_ISR) &
@@ -2088,9 +2038,10 @@
+ generic_handle_irq(AR2315_MISC_IRQ_TIMER);
+ else if (misc_intr & AR2315_ISR_AHB)
+ generic_handle_irq(AR2315_MISC_IRQ_AHB);
-+ else if (misc_intr & AR2315_ISR_GPIO)
++ else if (misc_intr & AR2315_ISR_GPIO) {
++ ar231x_write_reg(AR2315_ISR, AR2315_ISR_GPIO);
+ generic_handle_irq(AR2315_MISC_IRQ_GPIO);
-+ else if (misc_intr & AR2315_ISR_UART0)
++ } else if (misc_intr & AR2315_ISR_UART0)
+ generic_handle_irq(AR2315_MISC_IRQ_UART0);
+ else if (misc_intr & AR2315_ISR_WD) {
+ ar231x_write_reg(AR2315_ISR, AR2315_ISR_WD);
@@ -2124,44 +2075,6 @@
+ spurious_interrupt();
+}
+
-+static void ar2315_set_gpiointmask(int gpio, int level)
-+{
-+ u32 reg;
-+
-+ reg = ar231x_read_reg(AR2315_GPIO_INT);
-+ reg &= ~(AR2315_GPIO_INT_M | AR2315_GPIO_INT_LVL_M);
-+ reg |= gpio | AR2315_GPIO_INT_LVL(level);
-+ ar231x_write_reg(AR2315_GPIO_INT, reg);
-+}
-+
-+static void ar2315_gpio_irq_unmask(struct irq_data *d)
-+{
-+ unsigned int gpio = d->irq - AR231X_GPIO_IRQ_BASE;
-+
-+ /* Enable interrupt with edge detection */
-+ if ((ar231x_read_reg(AR2315_GPIO_DIR) & AR2315_GPIO_DIR_M(gpio)) !=
-+ AR2315_GPIO_DIR_I(gpio))
-+ return;
-+
-+ gpiointmask |= (1 << gpio);
-+ ar2315_set_gpiointmask(gpio, 3);
-+}
-+
-+static void ar2315_gpio_irq_mask(struct irq_data *d)
-+{
-+ unsigned int gpio = d->irq - AR231X_GPIO_IRQ_BASE;
-+
-+ /* Disable interrupt */
-+ gpiointmask &= ~(1 << gpio);
-+ ar2315_set_gpiointmask(gpio, 0);
-+}
-+
-+static struct irq_chip ar2315_gpio_irq_chip = {
-+ .name = "AR2315-GPIO",
-+ .irq_unmask = ar2315_gpio_irq_unmask,
-+ .irq_mask = ar2315_gpio_irq_mask,
-+};
-+
+static void
+ar2315_misc_irq_unmask(struct irq_data *d)
+{
@@ -2213,75 +2126,16 @@
+ return;
+
+ ar231x_irq_dispatch = ar2315_irq_dispatch;
-+ gpiointval = ar231x_read_reg(AR2315_GPIO_DI);
+ for (i = 0; i < AR2315_MISC_IRQ_COUNT; i++) {
+ int irq = AR231X_MISC_IRQ_BASE + i;
+
+ irq_set_chip_and_handler(irq, &ar2315_misc_irq_chip,
+ handle_level_irq);
+ }
-+ for (i = 0; i < AR2315_NUM_GPIO; i++) {
-+ int irq = AR231X_GPIO_IRQ_BASE + i;
-+
-+ irq_set_chip_and_handler(irq, &ar2315_gpio_irq_chip,
-+ handle_level_irq);
-+ }
-+ irq_set_chained_handler(AR2315_MISC_IRQ_GPIO, ar2315_gpio_irq_handler);
+ setup_irq(AR2315_MISC_IRQ_AHB, &ar2315_ahb_proc_interrupt);
+ irq_set_chained_handler(AR2315_IRQ_MISC_INTRS, ar2315_misc_irq_handler);
+}
+
-+/*
-+ * gpiolib implementation
-+ */
-+static int
-+ar2315_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
-+{
-+ return (ar231x_read_reg(AR2315_GPIO_DI) >> gpio) & 1;
-+}
-+
-+static void
-+ar2315_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
-+{
-+ u32 reg = ar231x_read_reg(AR2315_GPIO_DO);
-+
-+ reg = value ? reg | (1 << gpio) : reg & ~(1 << gpio);
-+ ar231x_write_reg(AR2315_GPIO_DO, reg);
-+}
-+
-+static int
-+ar2315_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
-+{
-+ ar231x_mask_reg(AR2315_GPIO_DIR, 1 << gpio, 0);
-+ return 0;
-+}
-+
-+static int
-+ar2315_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value)
-+{
-+ ar231x_mask_reg(AR2315_GPIO_DIR, 0, 1 << gpio);
-+ ar2315_gpio_set_value(chip, gpio, value);
-+ return 0;
-+}
-+
-+static int ar2315_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
-+{
-+ return AR231X_GPIO_IRQ_BASE + gpio;
-+}
-+
-+static struct gpio_chip ar2315_gpio_chip = {
-+ .label = "ar2315-gpio",
-+ .direction_input = ar2315_gpio_direction_input,
-+ .direction_output = ar2315_gpio_direction_output,
-+ .set = ar2315_gpio_set_value,
-+ .get = ar2315_gpio_get_value,
-+ .to_irq = ar2315_gpio_to_irq,
-+ .base = 0,
-+ .ngpio = AR2315_NUM_GPIO, /* 22 */
-+};
-+
-+/* end of gpiolib */
-+
+static void ar2315_device_reset_set(u32 mask)
+{
+ u32 val;
@@ -2511,20 +2365,6 @@
+ mips_hpt_frequency = ar2315_cpu_frequency() / 2;
+}
+
-+static int __init
-+ar2315_gpio_init(void)
-+{
-+ int ret = gpiochip_add(&ar2315_gpio_chip);
-+
-+ if (ret) {
-+ pr_err("%s: failed to add gpiochip\n", ar2315_gpio_chip.label);
-+ return ret;
-+ }
-+ pr_info("%s: registered %d GPIOs\n", ar2315_gpio_chip.label,
-+ ar2315_gpio_chip.ngpio);
-+ return ret;
-+}
-+
+void __init
+ar2315_prom_init(void)
+{
@@ -2557,7 +2397,6 @@
+ ar231x_devtype = DEV_TYPE_AR2315;
+ break;
+ }
-+ ar2315_gpio_init();
+ ar231x_board.devid = devid;
+}
+
diff --git a/target/linux/atheros/patches-3.14/103-ar2315_gpio.patch b/target/linux/atheros/patches-3.14/103-ar2315_gpio.patch
new file mode 100644
index 0000000..79feefa
--- /dev/null
+++ b/target/linux/atheros/patches-3.14/103-ar2315_gpio.patch
@@ -0,0 +1,315 @@
+--- a/arch/mips/ar231x/Kconfig
++++ b/arch/mips/ar231x/Kconfig
+@@ -7,4 +7,5 @@ config SOC_AR5312
+ config SOC_AR2315
+ bool "Atheros 2315+ support"
+ depends on ATHEROS_AR231X
++ select GPIO_AR2315
+ default y
+--- a/arch/mips/ar231x/ar2315.c
++++ b/arch/mips/ar231x/ar2315.c
+@@ -212,6 +212,34 @@ static struct platform_device ar2315_wdt
+ .num_resources = ARRAY_SIZE(ar2315_wdt_res)
+ };
+
++static struct resource ar2315_gpio_res[] = {
++ {
++ .name = "ar2315-gpio",
++ .flags = IORESOURCE_MEM,
++ .start = AR2315_GPIO,
++ .end = AR2315_GPIO + 0x10 - 1,
++ },
++ {
++ .name = "ar2315-gpio",
++ .flags = IORESOURCE_IRQ,
++ .start = AR2315_MISC_IRQ_GPIO,
++ .end = AR2315_MISC_IRQ_GPIO,
++ },
++ {
++ .name = "ar2315-gpio-irq-base",
++ .flags = IORESOURCE_IRQ,
++ .start = AR231X_GPIO_IRQ_BASE,
++ .end = AR231X_GPIO_IRQ_BASE,
++ }
++};
++
++static struct platform_device ar2315_gpio = {
++ .id = -1,
++ .name = "ar2315-gpio",
++ .resource = ar2315_gpio_res,
++ .num_resources = ARRAY_SIZE(ar2315_gpio_res)
++};
++
+ /*
+ * NB: We use mapping size that is larger than the actual flash size,
+ * but this shouldn't be a problem here, because the flash will simply
+@@ -277,6 +305,7 @@ ar2315_init_devices(void)
+ ar231x_find_config(ar2315_flash_limit());
+ ar2315_eth_data.macaddr = ar231x_board.config->enet0_mac;
+
++ platform_device_register(&ar2315_gpio);
+ ar2315_init_gpio_leds();
+ platform_device_register(&ar2315_wdt);
+ platform_device_register(&ar2315_spiflash);
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -108,6 +108,13 @@ config GPIO_MAX730X
+
+ comment "Memory mapped GPIO drivers:"
+
++config GPIO_AR2315
++ bool "AR2315 SoC GPIO support"
++ default y if SOC_AR2315
++ depends on SOC_AR2315
++ help
++ Say yes here to enable GPIO support for Atheros AR2315+ SoCs.
++
+ config GPIO_AR5312
+ bool "AR5312 SoC GPIO support"
+ default y if SOC_AR5312
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -15,6 +15,7 @@ obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o
+ obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o
+ obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o
+ obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
++obj-$(CONFIG_GPIO_AR2315) += gpio-ar2315.o
+ obj-$(CONFIG_GPIO_AR5312) += gpio-ar5312.o
+ obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
+ obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
+--- /dev/null
++++ b/drivers/gpio/gpio-ar2315.c
+@@ -0,0 +1,233 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved.
++ * Copyright (C) 2006 FON Technology, SL.
++ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
++ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
++ * Copyright (C) 2012 Alexandros C. Couloumbis <alex@ozo.com>
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/gpio.h>
++#include <linux/irq.h>
++
++#define DRIVER_NAME "ar2315-gpio"
++
++#define AR2315_GPIO_DI 0x0000
++#define AR2315_GPIO_DO 0x0008
++#define AR2315_GPIO_DIR 0x0010
++#define AR2315_GPIO_INT 0x0018
++
++#define AR2315_GPIO_DIR_M(x) (1 << (x)) /* mask for i/o */
++#define AR2315_GPIO_DIR_O(x) (1 << (x)) /* output */
++#define AR2315_GPIO_DIR_I(x) (0) /* input */
++
++#define AR2315_GPIO_INT_NUM_M 0x3F /* mask for GPIO num */
++#define AR2315_GPIO_INT_TRIG(x) ((x) << 6) /* interrupt trigger */
++#define AR2315_GPIO_INT_TRIG_M (0x3 << 6) /* mask for int trig */
++
++#define AR2315_GPIO_INT_TRIG_OFF 0 /* Triggerring off */
++#define AR2315_GPIO_INT_TRIG_LOW 1 /* Low Level Triggered */
++#define AR2315_GPIO_INT_TRIG_HIGH 2 /* High Level Triggered */
++#define AR2315_GPIO_INT_TRIG_EDGE 3 /* Edge Triggered */
++
++#define AR2315_GPIO_NUM 22
++
++static u32 ar2315_gpio_intmask;
++static u32 ar2315_gpio_intval;
++static unsigned ar2315_gpio_irq_base;
++static void __iomem *ar2315_mem;
++
++static inline u32 ar2315_gpio_reg_read(unsigned reg)
++{
++ return __raw_readl(ar2315_mem + reg);
++}
++
++static inline void ar2315_gpio_reg_write(unsigned reg, u32 val)
++{
++ __raw_writel(val, ar2315_mem + reg);
++}
++
++static inline void ar2315_gpio_reg_mask(unsigned reg, u32 mask, u32 val)
++{
++ ar2315_gpio_reg_write(reg, (ar2315_gpio_reg_read(reg) & ~mask) | val);
++}
++
++static void ar2315_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
++{
++ u32 pend;
++ int bit = -1;
++
++ /* only do one gpio interrupt at a time */
++ pend = ar2315_gpio_reg_read(AR2315_GPIO_DI);
++ pend ^= ar2315_gpio_intval;
++ pend &= ar2315_gpio_intmask;
++
++ if (pend) {
++ bit = fls(pend) - 1;
++ pend &= ~(1 << bit);
++ ar2315_gpio_intval ^= (1 << bit);
++ }
++
++ /* Enable interrupt with edge detection */
++ if ((ar2315_gpio_reg_read(AR2315_GPIO_DIR) & AR2315_GPIO_DIR_M(bit)) !=
++ AR2315_GPIO_DIR_I(bit))
++ return;
++
++ if (bit >= 0)
++ generic_handle_irq(ar2315_gpio_irq_base + bit);
++}
++
++static void ar2315_gpio_int_setup(unsigned gpio, int trig)
++{
++ u32 reg = ar2315_gpio_reg_read(AR2315_GPIO_INT);
++
++ reg &= ~(AR2315_GPIO_INT_NUM_M | AR2315_GPIO_INT_TRIG_M);
++ reg |= gpio | AR2315_GPIO_INT_TRIG(trig);
++ ar2315_gpio_reg_write(AR2315_GPIO_INT, reg);
++}
++
++static void ar2315_gpio_irq_unmask(struct irq_data *d)
++{
++ unsigned gpio = d->irq - ar2315_gpio_irq_base;
++ u32 dir = ar2315_gpio_reg_read(AR2315_GPIO_DIR);
++
++ /* Enable interrupt with edge detection */
++ if ((dir & AR2315_GPIO_DIR_M(gpio)) != AR2315_GPIO_DIR_I(gpio))
++ return;
++
++ ar2315_gpio_intmask |= (1 << gpio);
++ ar2315_gpio_int_setup(gpio, AR2315_GPIO_INT_TRIG_EDGE);
++}
++
++static void ar2315_gpio_irq_mask(struct irq_data *d)
++{
++ unsigned gpio = d->irq - ar2315_gpio_irq_base;
++
++ /* Disable interrupt */
++ ar2315_gpio_intmask &= ~(1 << gpio);
++ ar2315_gpio_int_setup(gpio, AR2315_GPIO_INT_TRIG_OFF);
++}
++
++static struct irq_chip ar2315_gpio_irq_chip = {
++ .name = DRIVER_NAME,
++ .irq_unmask = ar2315_gpio_irq_unmask,
++ .irq_mask = ar2315_gpio_irq_mask,
++};
++
++static void ar2315_gpio_irq_init(unsigned irq)
++{
++ unsigned i;
++
++ ar2315_gpio_intval = ar2315_gpio_reg_read(AR2315_GPIO_DI);
++ for (i = 0; i < AR2315_GPIO_NUM; i++) {
++ unsigned _irq = ar2315_gpio_irq_base + i;
++
++ irq_set_chip_and_handler(_irq, &ar2315_gpio_irq_chip,
++ handle_level_irq);
++ }
++ irq_set_chained_handler(irq, ar2315_gpio_irq_handler);
++}
++
++static int ar2315_gpio_get_val(struct gpio_chip *chip, unsigned gpio)
++{
++ return (ar2315_gpio_reg_read(AR2315_GPIO_DI) >> gpio) & 1;
++}
++
++static void ar2315_gpio_set_val(struct gpio_chip *chip, unsigned gpio, int val)
++{
++ u32 reg = ar2315_gpio_reg_read(AR2315_GPIO_DO);
++
++ reg = val ? reg | (1 << gpio) : reg & ~(1 << gpio);
++ ar2315_gpio_reg_write(AR2315_GPIO_DO, reg);
++}
++
++static int ar2315_gpio_dir_in(struct gpio_chip *chip, unsigned gpio)
++{
++ ar2315_gpio_reg_mask(AR2315_GPIO_DIR, 1 << gpio, 0);
++ return 0;
++}
++
++static int ar2315_gpio_dir_out(struct gpio_chip *chip, unsigned gpio, int val)
++{
++ ar2315_gpio_reg_mask(AR2315_GPIO_DIR, 0, 1 << gpio);
++ ar2315_gpio_set_val(chip, gpio, val);
++ return 0;
++}
++
++static int ar2315_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
++{
++ return ar2315_gpio_irq_base + gpio;
++}
++
++static struct gpio_chip ar2315_gpio_chip = {
++ .label = DRIVER_NAME,
++ .direction_input = ar2315_gpio_dir_in,
++ .direction_output = ar2315_gpio_dir_out,
++ .set = ar2315_gpio_set_val,
++ .get = ar2315_gpio_get_val,
++ .to_irq = ar2315_gpio_to_irq,
++ .base = 0,
++ .ngpio = AR2315_GPIO_NUM,
++};
++
++static int ar2315_gpio_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct resource *res;
++ unsigned irq;
++ int ret;
++
++ if (ar2315_mem)
++ return -EBUSY;
++
++ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
++ "ar2315-gpio-irq-base");
++ if (!res) {
++ dev_err(dev, "not found GPIO IRQ base\n");
++ return -ENXIO;
++ }
++ ar2315_gpio_irq_base = res->start;
++
++ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, DRIVER_NAME);
++ if (!res) {
++ dev_err(dev, "not found IRQ number\n");
++ return -ENXIO;
++ }
++ irq = res->start;
++
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, DRIVER_NAME);
++ ar2315_mem = devm_ioremap_resource(dev, res);
++ if (IS_ERR(ar2315_mem))
++ return PTR_ERR(ar2315_mem);
++
++ ar2315_gpio_chip.dev = dev;
++ ret = gpiochip_add(&ar2315_gpio_chip);
++ if (ret) {
++ dev_err(dev, "failed to add gpiochip\n");
++ return ret;
++ }
++
++ ar2315_gpio_irq_init(irq);
++
++ return 0;
++}
++
++static struct platform_driver ar2315_gpio_driver = {
++ .probe = ar2315_gpio_probe,
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ }
++};
++
++static int __init ar2315_gpio_init(void)
++{
++ return platform_driver_register(&ar2315_gpio_driver);
++}
++subsys_initcall(ar2315_gpio_init);
diff --git a/target/linux/atheros/patches-3.14/105-ar2315_pci.patch b/target/linux/atheros/patches-3.14/105-ar2315_pci.patch
index 7630e94..95d00a3 100644
--- a/target/linux/atheros/patches-3.14/105-ar2315_pci.patch
+++ b/target/linux/atheros/patches-3.14/105-ar2315_pci.patch
@@ -358,9 +358,9 @@
+}
--- a/arch/mips/ar231x/Kconfig
+++ b/arch/mips/ar231x/Kconfig
-@@ -8,3 +8,10 @@ config SOC_AR2315
- bool "Atheros 2315+ support"
+@@ -9,3 +9,10 @@ config SOC_AR2315
depends on ATHEROS_AR231X
+ select GPIO_AR2315
default y
+
+config PCI_AR2315
@@ -371,7 +371,7 @@
+ default y
--- a/arch/mips/ar231x/ar2315.c
+++ b/arch/mips/ar231x/ar2315.c
-@@ -104,6 +104,10 @@ ar2315_irq_dispatch(void)
+@@ -77,6 +77,10 @@ ar2315_irq_dispatch(void)
do_IRQ(AR2315_IRQ_WLAN0_INTRS);
else if (pending & CAUSEF_IP4)
do_IRQ(AR2315_IRQ_ENET0_INTRS);
@@ -382,7 +382,7 @@
else if (pending & CAUSEF_IP2)
do_IRQ(AR2315_IRQ_MISC_INTRS);
else if (pending & CAUSEF_IP7)
-@@ -568,3 +572,18 @@ ar2315_plat_setup(void)
+@@ -458,3 +462,18 @@ ar2315_plat_setup(void)
ar231x_serial_setup(AR2315_UART0, AR2315_MISC_IRQ_UART0,
ar2315_apb_frequency());
}