Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / arch / mips / ath79 / gpio.c
diff --git a/kernel/arch/mips/ath79/gpio.c b/kernel/arch/mips/ath79/gpio.c
new file mode 100644 (file)
index 0000000..8d025b0
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ *  Atheros AR71XX/AR724X/AR913X GPIO API support
+ *
+ *  Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
+ *  Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+#include "common.h"
+
+static void __iomem *ath79_gpio_base;
+static unsigned long ath79_gpio_count;
+static DEFINE_SPINLOCK(ath79_gpio_lock);
+
+static void __ath79_gpio_set_value(unsigned gpio, int value)
+{
+       void __iomem *base = ath79_gpio_base;
+
+       if (value)
+               __raw_writel(1 << gpio, base + AR71XX_GPIO_REG_SET);
+       else
+               __raw_writel(1 << gpio, base + AR71XX_GPIO_REG_CLEAR);
+}
+
+static int __ath79_gpio_get_value(unsigned gpio)
+{
+       return (__raw_readl(ath79_gpio_base + AR71XX_GPIO_REG_IN) >> gpio) & 1;
+}
+
+static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned offset)
+{
+       return __ath79_gpio_get_value(offset);
+}
+
+static void ath79_gpio_set_value(struct gpio_chip *chip,
+                                 unsigned offset, int value)
+{
+       __ath79_gpio_set_value(offset, value);
+}
+
+static int ath79_gpio_direction_input(struct gpio_chip *chip,
+                                      unsigned offset)
+{
+       void __iomem *base = ath79_gpio_base;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ath79_gpio_lock, flags);
+
+       __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << offset),
+                    base + AR71XX_GPIO_REG_OE);
+
+       spin_unlock_irqrestore(&ath79_gpio_lock, flags);
+
+       return 0;
+}
+
+static int ath79_gpio_direction_output(struct gpio_chip *chip,
+                                       unsigned offset, int value)
+{
+       void __iomem *base = ath79_gpio_base;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ath79_gpio_lock, flags);
+
+       if (value)
+               __raw_writel(1 << offset, base + AR71XX_GPIO_REG_SET);
+       else
+               __raw_writel(1 << offset, base + AR71XX_GPIO_REG_CLEAR);
+
+       __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << offset),
+                    base + AR71XX_GPIO_REG_OE);
+
+       spin_unlock_irqrestore(&ath79_gpio_lock, flags);
+
+       return 0;
+}
+
+static int ar934x_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       void __iomem *base = ath79_gpio_base;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ath79_gpio_lock, flags);
+
+       __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << offset),
+                    base + AR71XX_GPIO_REG_OE);
+
+       spin_unlock_irqrestore(&ath79_gpio_lock, flags);
+
+       return 0;
+}
+
+static int ar934x_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+                                       int value)
+{
+       void __iomem *base = ath79_gpio_base;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ath79_gpio_lock, flags);
+
+       if (value)
+               __raw_writel(1 << offset, base + AR71XX_GPIO_REG_SET);
+       else
+               __raw_writel(1 << offset, base + AR71XX_GPIO_REG_CLEAR);
+
+       __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << offset),
+                    base + AR71XX_GPIO_REG_OE);
+
+       spin_unlock_irqrestore(&ath79_gpio_lock, flags);
+
+       return 0;
+}
+
+static struct gpio_chip ath79_gpio_chip = {
+       .label                  = "ath79",
+       .get                    = ath79_gpio_get_value,
+       .set                    = ath79_gpio_set_value,
+       .direction_input        = ath79_gpio_direction_input,
+       .direction_output       = ath79_gpio_direction_output,
+       .base                   = 0,
+};
+
+static void __iomem *ath79_gpio_get_function_reg(void)
+{
+       u32 reg = 0;
+
+       if (soc_is_ar71xx() ||
+           soc_is_ar724x() ||
+           soc_is_ar913x() ||
+           soc_is_ar933x())
+               reg = AR71XX_GPIO_REG_FUNC;
+       else if (soc_is_ar934x())
+               reg = AR934X_GPIO_REG_FUNC;
+       else
+               BUG();
+
+       return ath79_gpio_base + reg;
+}
+
+void ath79_gpio_function_setup(u32 set, u32 clear)
+{
+       void __iomem *reg = ath79_gpio_get_function_reg();
+       unsigned long flags;
+
+       spin_lock_irqsave(&ath79_gpio_lock, flags);
+
+       __raw_writel((__raw_readl(reg) & ~clear) | set, reg);
+       /* flush write */
+       __raw_readl(reg);
+
+       spin_unlock_irqrestore(&ath79_gpio_lock, flags);
+}
+
+void ath79_gpio_function_enable(u32 mask)
+{
+       ath79_gpio_function_setup(mask, 0);
+}
+
+void ath79_gpio_function_disable(u32 mask)
+{
+       ath79_gpio_function_setup(0, mask);
+}
+
+void __init ath79_gpio_init(void)
+{
+       int err;
+
+       if (soc_is_ar71xx())
+               ath79_gpio_count = AR71XX_GPIO_COUNT;
+       else if (soc_is_ar7240())
+               ath79_gpio_count = AR7240_GPIO_COUNT;
+       else if (soc_is_ar7241() || soc_is_ar7242())
+               ath79_gpio_count = AR7241_GPIO_COUNT;
+       else if (soc_is_ar913x())
+               ath79_gpio_count = AR913X_GPIO_COUNT;
+       else if (soc_is_ar933x())
+               ath79_gpio_count = AR933X_GPIO_COUNT;
+       else if (soc_is_ar934x())
+               ath79_gpio_count = AR934X_GPIO_COUNT;
+       else if (soc_is_qca955x())
+               ath79_gpio_count = QCA955X_GPIO_COUNT;
+       else
+               BUG();
+
+       ath79_gpio_base = ioremap_nocache(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE);
+       ath79_gpio_chip.ngpio = ath79_gpio_count;
+       if (soc_is_ar934x() || soc_is_qca955x()) {
+               ath79_gpio_chip.direction_input = ar934x_gpio_direction_input;
+               ath79_gpio_chip.direction_output = ar934x_gpio_direction_output;
+       }
+
+       err = gpiochip_add(&ath79_gpio_chip);
+       if (err)
+               panic("cannot add AR71xx GPIO chip, error=%d", err);
+}
+
+int gpio_get_value(unsigned gpio)
+{
+       if (gpio < ath79_gpio_count)
+               return __ath79_gpio_get_value(gpio);
+
+       return __gpio_get_value(gpio);
+}
+EXPORT_SYMBOL(gpio_get_value);
+
+void gpio_set_value(unsigned gpio, int value)
+{
+       if (gpio < ath79_gpio_count)
+               __ath79_gpio_set_value(gpio, value);
+       else
+               __gpio_set_value(gpio, value);
+}
+EXPORT_SYMBOL(gpio_set_value);
+
+int gpio_to_irq(unsigned gpio)
+{
+       /* FIXME */
+       return -EINVAL;
+}
+EXPORT_SYMBOL(gpio_to_irq);
+
+int irq_to_gpio(unsigned irq)
+{
+       /* FIXME */
+       return -EINVAL;
+}
+EXPORT_SYMBOL(irq_to_gpio);