gpio: msm: Add v3 gpio support for copper

Beginning with copper, the gpio TLMM register and interrupt
mappings have changed. Add a new version to support the new
mappings.

Change-Id: I5c8bd148dd6ac38aa59448c9aab98e04183e14f1
Signed-off-by: Sathish Ambley <sambley@codeaurora.org>
diff --git a/drivers/gpio/gpio-msm-v3.c b/drivers/gpio/gpio-msm-v3.c
new file mode 100644
index 0000000..49ad517
--- /dev/null
+++ b/drivers/gpio/gpio-msm-v3.c
@@ -0,0 +1,217 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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 <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/gpiomux.h>
+#include "gpio-msm-common.h"
+
+/* Bits of interest in the GPIO_IN_OUT register.
+ */
+enum {
+	GPIO_IN_BIT  = 0,
+	GPIO_OUT_BIT = 1
+};
+
+/* Bits of interest in the GPIO_INTR_STATUS register.
+ */
+enum {
+	INTR_STATUS_BIT = 0,
+};
+
+/* Bits of interest in the GPIO_CFG register.
+ */
+enum {
+	GPIO_OE_BIT = 9,
+};
+
+/* Bits of interest in the GPIO_INTR_CFG register.
+ */
+enum {
+	INTR_ENABLE_BIT        = 0,
+	INTR_POL_CTL_BIT       = 1,
+	INTR_DECT_CTL_BIT      = 2,
+	INTR_RAW_STATUS_EN_BIT = 4,
+	INTR_TARGET_PROC_BIT   = 5,
+	INTR_DIR_CONN_EN_BIT   = 8,
+};
+
+/*
+ * There is no 'DC_POLARITY_LO' because the GIC is incapable
+ * of asserting on falling edge or level-low conditions.  Even though
+ * the registers allow for low-polarity inputs, the case can never arise.
+ */
+enum {
+	DC_GPIO_SEL_BIT = 0,
+	DC_POLARITY_BIT	= 8,
+};
+
+/*
+ * When a GPIO triggers, two separate decisions are made, controlled
+ * by two separate flags.
+ *
+ * - First, INTR_RAW_STATUS_EN controls whether or not the GPIO_INTR_STATUS
+ * register for that GPIO will be updated to reflect the triggering of that
+ * gpio.  If this bit is 0, this register will not be updated.
+ * - Second, INTR_ENABLE controls whether an interrupt is triggered.
+ *
+ * If INTR_ENABLE is set and INTR_RAW_STATUS_EN is NOT set, an interrupt
+ * can be triggered but the status register will not reflect it.
+ */
+#define INTR_RAW_STATUS_EN BIT(INTR_RAW_STATUS_EN_BIT)
+#define INTR_ENABLE        BIT(INTR_ENABLE_BIT)
+#define INTR_POL_CTL_HI    BIT(INTR_POL_CTL_BIT)
+#define INTR_DIR_CONN_EN   BIT(INTR_DIR_CONN_EN_BIT)
+#define DC_POLARITY_HI     BIT(DC_POLARITY_BIT)
+
+#define INTR_TARGET_PROC_APPS    (4 << INTR_TARGET_PROC_BIT)
+#define INTR_TARGET_PROC_NONE    (7 << INTR_TARGET_PROC_BIT)
+
+#define INTR_DECT_CTL_LEVEL      (0 << INTR_DECT_CTL_BIT)
+#define INTR_DECT_CTL_POS_EDGE   (1 << INTR_DECT_CTL_BIT)
+#define INTR_DECT_CTL_NEG_EDGE   (2 << INTR_DECT_CTL_BIT)
+#define INTR_DECT_CTL_DUAL_EDGE  (3 << INTR_DECT_CTL_BIT)
+#define INTR_DECT_CTL_MASK       (3 << INTR_DECT_CTL_BIT)
+
+#define GPIO_CONFIG(gpio)        (MSM_TLMM_BASE + 0x1000 + (0x10 * (gpio)))
+#define GPIO_IN_OUT(gpio)        (MSM_TLMM_BASE + 0x1004 + (0x10 * (gpio)))
+#define GPIO_INTR_CFG(gpio)      (MSM_TLMM_BASE + 0x1008 + (0x10 * (gpio)))
+#define GPIO_INTR_STATUS(gpio)   (MSM_TLMM_BASE + 0x100c + (0x10 * (gpio)))
+#define GPIO_DIR_CONN_INTR(intr) (MSM_TLMM_BASE + 0x2800 + (0x04 * (intr)))
+
+static inline void set_gpio_bits(unsigned n, void __iomem *reg)
+{
+	__raw_writel(__raw_readl(reg) | n, reg);
+}
+
+static inline void clr_gpio_bits(unsigned n, void __iomem *reg)
+{
+	__raw_writel(__raw_readl(reg) & ~n, reg);
+}
+
+unsigned __msm_gpio_get_inout(unsigned gpio)
+{
+	return __raw_readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN_BIT);
+}
+
+void __msm_gpio_set_inout(unsigned gpio, unsigned val)
+{
+	__raw_writel(val ? BIT(GPIO_OUT_BIT) : 0, GPIO_IN_OUT(gpio));
+}
+
+void __msm_gpio_set_config_direction(unsigned gpio, int input, int val)
+{
+	if (input) {
+		clr_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(gpio));
+	} else {
+		__msm_gpio_set_inout(gpio, val);
+		set_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(gpio));
+	}
+}
+
+void __msm_gpio_set_polarity(unsigned gpio, unsigned val)
+{
+	if (val)
+		clr_gpio_bits(INTR_POL_CTL_HI, GPIO_INTR_CFG(gpio));
+	else
+		set_gpio_bits(INTR_POL_CTL_HI, GPIO_INTR_CFG(gpio));
+}
+
+unsigned __msm_gpio_get_intr_status(unsigned gpio)
+{
+	return __raw_readl(GPIO_INTR_STATUS(gpio)) &
+					BIT(INTR_STATUS_BIT);
+}
+
+void __msm_gpio_set_intr_status(unsigned gpio)
+{
+	__raw_writel(BIT(INTR_STATUS_BIT), GPIO_INTR_STATUS(gpio));
+}
+
+unsigned __msm_gpio_get_intr_config(unsigned gpio)
+{
+	return __raw_readl(GPIO_INTR_CFG(gpio));
+}
+
+void __msm_gpio_set_intr_cfg_enable(unsigned gpio, unsigned val)
+{
+	unsigned cfg;
+
+	cfg = __raw_readl(GPIO_INTR_CFG(gpio));
+	if (val) {
+		cfg &= ~(INTR_TARGET_PROC_NONE | INTR_DIR_CONN_EN);
+		cfg |= INTR_RAW_STATUS_EN | INTR_ENABLE | INTR_TARGET_PROC_APPS;
+	} else {
+		cfg &= ~(INTR_TARGET_PROC_APPS | INTR_RAW_STATUS_EN |
+			INTR_ENABLE);
+		cfg |= INTR_TARGET_PROC_NONE;
+	}
+	__raw_writel(cfg, GPIO_INTR_CFG(gpio));
+}
+
+void __msm_gpio_set_intr_cfg_type(unsigned gpio, unsigned type)
+{
+	unsigned cfg;
+
+	cfg = __raw_readl(GPIO_INTR_CFG(gpio));
+	cfg &= ~INTR_DECT_CTL_MASK;
+	if (type == IRQ_TYPE_EDGE_RISING)
+		cfg |= INTR_DECT_CTL_POS_EDGE;
+	else if (type == IRQ_TYPE_EDGE_FALLING)
+		cfg |= INTR_DECT_CTL_NEG_EDGE;
+	else if (type == IRQ_TYPE_EDGE_BOTH)
+		cfg |= INTR_DECT_CTL_DUAL_EDGE;
+	else
+		cfg |= INTR_DECT_CTL_LEVEL;
+
+	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
+		cfg |= INTR_POL_CTL_HI;
+	else
+		cfg &= ~INTR_POL_CTL_HI;
+
+	__raw_writel(cfg, GPIO_INTR_CFG(gpio));
+}
+
+void __gpio_tlmm_config(unsigned config)
+{
+	unsigned flags;
+	unsigned gpio = GPIO_PIN(config);
+
+	flags = ((GPIO_DIR(config) << 9) & (0x1 << 9)) |
+		((GPIO_DRVSTR(config) << 6) & (0x7 << 6)) |
+		((GPIO_FUNC(config) << 2) & (0xf << 2)) |
+		((GPIO_PULL(config) & 0x3));
+	__raw_writel(flags, GPIO_CONFIG(gpio));
+}
+
+void __msm_gpio_install_direct_irq(unsigned gpio, unsigned irq,
+					unsigned int input_polarity)
+{
+	unsigned cfg;
+
+	set_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(gpio));
+	cfg = __raw_readl(GPIO_INTR_CFG(gpio));
+	cfg &= ~(INTR_TARGET_PROC_NONE | INTR_RAW_STATUS_EN | INTR_ENABLE);
+	cfg |= INTR_TARGET_PROC_APPS | INTR_DIR_CONN_EN;
+	__raw_writel(cfg, GPIO_INTR_CFG(gpio));
+
+	cfg = gpio;
+	if (input_polarity)
+		cfg |= DC_POLARITY_HI;
+	__raw_writel(cfg, GPIO_DIR_CONN_INTR(irq));
+}