All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4] arm: msm: gpio support
@ 2010-03-30 23:11 ` Daniel Walker
  0 siblings, 0 replies; 22+ messages in thread
From: Daniel Walker @ 2010-03-30 23:11 UTC (permalink / raw)
  To: linux-arm-kernel; +Cc: linux-arm-msm, Daniel Walker

From: Daniel Walker <c_dwalke@quicinc.com>

This adds basic gpio support in MSM using gpiolib, as well as gpio
interrupt support.

Signed-off-by: Daniel Walker <c_dwalke@quicinc.com>
---
 arch/arm/Kconfig                      |    1 +
 arch/arm/mach-msm/Makefile            |    1 +
 arch/arm/mach-msm/gpio.c              |  428 +++++++++++++++++++++++++++++++++
 arch/arm/mach-msm/gpio_hw.h           |  187 ++++++++++++++
 arch/arm/mach-msm/include/mach/gpio.h |   43 ++++
 5 files changed, 660 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-msm/gpio.c
 create mode 100644 arch/arm/mach-msm/gpio_hw.h
 create mode 100644 arch/arm/mach-msm/include/mach/gpio.h

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index cadfe2e..5e29092 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -601,6 +601,7 @@ config ARCH_MSM
 	select CPU_V6
 	select GENERIC_TIME
 	select GENERIC_CLOCKEVENTS
+	select ARCH_REQUIRE_GPIOLIB
 	help
 	  Support for Qualcomm MSM7K based systems.  This runs on the ARM11
 	  apps processor of the MSM7K and depends on a shared memory
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 147339c..47d47cb 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -4,6 +4,7 @@ obj-y += proc_comm.o
 obj-y += vreg.o
 obj-y += acpuclock-arm11.o
 obj-y += clock.o clock-7x01a.o
+obj-y += gpio.o
 
 obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o
 obj-$(CONFIG_MSM_SMD) += last_radio_log.o
diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c
new file mode 100644
index 0000000..5b95885
--- /dev/null
+++ b/arch/arm/mach-msm/gpio.c
@@ -0,0 +1,428 @@
+/* linux/arch/arm/mach-msm/gpio.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include "gpio_hw.h"
+
+#include "smd_private.h"
+
+static int msm_gpio_debug_mask;
+module_param_named(debug_mask, msm_gpio_debug_mask, int,
+		   S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define MSM_GPIO_BROKEN_INT_CLEAR 1
+
+/* private gpio_configure flags */
+#define MSM_GPIOF_ENABLE_INTERRUPT      0x10000000
+#define MSM_GPIOF_DISABLE_INTERRUPT     0x20000000
+#define MSM_GPIOF_ENABLE_WAKE           0x40000000
+#define MSM_GPIOF_DISABLE_WAKE          0x80000000
+
+static int gpio_chip_to_irq(struct gpio_chip *chip, unsigned offset);
+static void gpio_chip_set(struct gpio_chip *chip, unsigned offset, int value);
+static int gpio_chip_get(struct gpio_chip *chip, unsigned offset);
+static int gpio_chip_direction_input(struct gpio_chip *chip, unsigned offset);
+static int gpio_chip_direction_output(struct gpio_chip *chip, unsigned offset,
+				      int value);
+
+struct msm_gpio_regs {
+	void __iomem *out;
+	void __iomem *in;
+	void __iomem *int_status;
+	void __iomem *int_clear;
+	void __iomem *int_en;
+	void __iomem *int_edge;
+	void __iomem *int_pos;
+	void __iomem *oe;
+};
+
+struct msm_gpio_chip {
+	struct gpio_chip        chip;
+	struct msm_gpio_regs    regs;
+	spinlock_t		lock;
+#if MSM_GPIO_BROKEN_INT_CLEAR
+	unsigned                int_status_copy;
+#endif
+	unsigned int            both_edge_detect;
+	unsigned int            int_enable[2]; /* 0: awake, 1: sleep */
+};
+
+#define MSM_GPIO_BANK(name, reg_num, start, end)			\
+	{								\
+		.regs = {						\
+			.out =         GPIO_OUT_ ## reg_num,		\
+			.in =          GPIO_IN_ ## reg_num ,		\
+			.int_status =  GPIO_INT_STATUS_ ## reg_num,	\
+			.int_clear =   GPIO_INT_CLEAR_ ## reg_num,	\
+			.int_en =      GPIO_INT_EN_ ## reg_num,		\
+			.int_edge =    GPIO_INT_EDGE_ ## reg_num,	\
+			.int_pos =     GPIO_INT_POS_ ## reg_num,	\
+			.oe =          GPIO_OE_ ## reg_num,		\
+		},							\
+		.chip = {						\
+			.label = name,					\
+			.ngpio = end - start + 1,			\
+			.direction_input = gpio_chip_direction_input,	\
+			.direction_output = gpio_chip_direction_output,	\
+			.get = gpio_chip_get,				\
+			.set = gpio_chip_set,				\
+			.to_irq = gpio_chip_to_irq,			\
+			.base = start,					\
+		}							\
+	}
+
+struct msm_gpio_chip msm_gpio_chips[] = {
+	MSM_GPIO_BANK("bank0", 0, 0, 15),
+	MSM_GPIO_BANK("bank1", 1, 16, 42),
+	MSM_GPIO_BANK("bank2", 2, 43, 67),
+	MSM_GPIO_BANK("bank3", 3, 68, 94),
+#if defined(CONFIG_ARCH_QSD8X50)
+	MSM_GPIO_BANK("bank4", 4, 95, 103),
+	MSM_GPIO_BANK("bank5", 5, 104, 121),
+	MSM_GPIO_BANK("bank6", 6, 122, 152),
+	MSM_GPIO_BANK("bank7", 7, 153, 164),
+#else
+	MSM_GPIO_BANK("bank4", 4, 95, 106),
+	MSM_GPIO_BANK("bank5", 5, 107, 121),
+#endif
+};
+
+#define to_msm_gpio_chip(c) container_of(c, struct msm_gpio_chip, chip)
+
+static int gpio_chip_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
+	unsigned long irq_flags;
+	unsigned b = 1U << (offset);
+	unsigned v;
+
+	spin_lock_irqsave(&old_chip->lock, irq_flags);
+	b = 1U << (offset);
+
+	v = readl(old_chip->regs.oe);
+	writel(v & (~b), old_chip->regs.oe);
+
+	spin_unlock_irqrestore(&old_chip->lock, irq_flags);
+
+	return 0;
+}
+
+static int gpio_chip_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
+	unsigned long irq_flags;
+	int ret = -ENOTSUPP;
+	unsigned b;
+
+	spin_lock_irqsave(&old_chip->lock, irq_flags);
+	b = 1U << (offset);
+
+	ret = (readl(old_chip->regs.in)) & b ? 1 : 0;
+
+	spin_unlock_irqrestore(&old_chip->lock, irq_flags);
+	return ret;
+}
+
+static inline int
+msm_gpio_write(struct msm_gpio_chip *chip, unsigned n, unsigned on)
+{
+	unsigned b = 1U << n;
+	unsigned v;
+
+	v = readl(chip->regs.out);
+	if (on)
+		writel(v | b, chip->regs.out);
+	else
+		writel(v & (~b), chip->regs.out);
+
+	return 0;
+}
+
+static int
+gpio_chip_direction_output(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
+	unsigned long irq_flags;
+	unsigned v;
+
+	spin_lock_irqsave(&old_chip->lock, irq_flags);
+
+	msm_gpio_write(old_chip, offset, value);
+
+	v = readl(old_chip->regs.oe);
+	writel(v | offset, old_chip->regs.oe);
+
+	spin_unlock_irqrestore(&old_chip->lock, irq_flags);
+
+	return 0;
+}
+
+static void gpio_chip_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
+	unsigned long irq_flags;
+
+	spin_lock_irqsave(&old_chip->lock, irq_flags);
+
+	msm_gpio_write(old_chip, offset, value);
+
+	spin_unlock_irqrestore(&old_chip->lock, irq_flags);
+}
+
+static int gpio_chip_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
+	unsigned long irq_flags;
+	int ret;
+
+	spin_lock_irqsave(&old_chip->lock, irq_flags);
+	ret = MSM_GPIO_TO_INT(offset);
+	spin_unlock_irqrestore(&old_chip->lock, irq_flags);
+
+	return ret;
+}
+
+
+static void msm_gpio_update_both_edge_detect(struct msm_gpio_chip *msm_chip)
+{
+	int loop_limit = 100;
+	unsigned pol, val, val2, intstat;
+	do {
+		val = readl(msm_chip->regs.in);
+		pol = readl(msm_chip->regs.int_pos);
+		pol = (pol & ~msm_chip->both_edge_detect) |
+		      (~val & msm_chip->both_edge_detect);
+
+		writel(pol, msm_chip->regs.int_pos);
+
+		intstat = readl(msm_chip->regs.int_status);
+		val2 = readl(msm_chip->regs.in);
+
+		if (((val ^ val2) & msm_chip->both_edge_detect & ~intstat) == 0)
+			return;
+	} while (loop_limit-- > 0);
+	printk(KERN_ERR "msm_gpio_update_both_edge_detect, failed to reach stable state %x != %x\n", val, val2);
+}
+
+static void msm_gpio_irq_ack(unsigned int irq)
+{
+	unsigned long irq_flags;
+	struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+	unsigned b;
+
+	spin_lock_irqsave(&msm_chip->lock, irq_flags);
+
+	b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
+
+#if MSM_GPIO_BROKEN_INT_CLEAR
+	/* Save interrupts that already triggered before we loose them. */
+	/* Any interrupt that triggers between the read of int_status */
+	/* and the write to int_clear will still be lost though. */
+	msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
+	msm_chip->int_status_copy &= ~b;
+#endif
+	writel(b, msm_chip->regs.int_clear);
+
+	msm_gpio_update_both_edge_detect(msm_chip);
+	spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+}
+
+static void msm_gpio_irq_mask(unsigned int irq)
+{
+	unsigned long irq_flags;
+	struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+	unsigned b, v;
+
+	spin_lock_irqsave(&msm_chip->lock, irq_flags);
+
+	b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
+
+	v = readl(msm_chip->regs.int_edge);
+	/* level triggered interrupts are also latched */
+	if (!(v & b)) {
+
+	#if MSM_GPIO_BROKEN_INT_CLEAR
+		/* Save interrupts that already triggered before we loose
+		 * them. Any interrupt that triggers between the read of
+		 * int_status and the write to int_clear will still be
+		 * lost though.
+		 */
+		msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
+		msm_chip->int_status_copy &= ~b;
+	#endif
+		writel(b, msm_chip->regs.int_clear);
+		msm_gpio_update_both_edge_detect(msm_chip);
+	}
+
+	msm_chip->int_enable[0] &= ~b;
+	writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
+
+	spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+}
+
+static void msm_gpio_irq_unmask(unsigned int irq)
+{
+	unsigned long irq_flags;
+	struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+	unsigned b, v;
+
+	spin_lock_irqsave(&msm_chip->lock, irq_flags);
+
+	b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
+
+	v = readl(msm_chip->regs.int_edge);
+	/* level triggered interrupts are also latched */
+	if (!(v & b)) {
+
+	#if MSM_GPIO_BROKEN_INT_CLEAR
+		/* Save interrupts that already triggered before we loose
+		 * them. Any interrupt that triggers between the read of
+		 * int_status and the write to int_clear will still be
+		 * lost though.
+		 */
+		msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
+		msm_chip->int_status_copy &= ~b;
+	#endif
+		writel(b, msm_chip->regs.int_clear);
+		msm_gpio_update_both_edge_detect(msm_chip);
+	}
+
+	msm_chip->int_enable[0] |= b;
+	writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
+
+	spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+}
+
+static int msm_gpio_irq_set_wake(unsigned int irq, unsigned int on)
+{
+	unsigned long irq_flags;
+	struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+	unsigned b;
+
+	spin_lock_irqsave(&msm_chip->lock, irq_flags);
+
+	b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
+
+	if (on)
+		msm_chip->int_enable[1] |= b;
+	else
+		msm_chip->int_enable[1] &= ~b;
+
+	spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+
+	return 0;
+}
+
+
+static int msm_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
+{
+	unsigned long irq_flags;
+	struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+	unsigned b, v;
+
+	spin_lock_irqsave(&msm_chip->lock, irq_flags);
+
+	b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
+
+	v = readl(msm_chip->regs.int_edge);
+	if (flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) {
+		writel(v | b, msm_chip->regs.int_edge);
+		irq_desc[MSM_GPIO_TO_INT(irq - FIRST_GPIO_IRQ)].handle_irq = handle_edge_irq;
+	} else {
+		writel(v & (~b), msm_chip->regs.int_edge);
+		irq_desc[MSM_GPIO_TO_INT(irq - FIRST_GPIO_IRQ)].handle_irq = handle_level_irq;
+	}
+	if ((flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) ==
+			 (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) {
+		msm_chip->both_edge_detect |= b;
+		msm_gpio_update_both_edge_detect(msm_chip);
+	} else {
+		msm_chip->both_edge_detect &= ~b;
+		v = readl(msm_chip->regs.int_pos);
+		if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
+			writel(v | b, msm_chip->regs.int_pos);
+		else
+			writel(v & (~b), msm_chip->regs.int_pos);
+
+	}
+	spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+	return 0;
+}
+
+static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	int i, j, m;
+	unsigned v;
+
+	for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
+		struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i];
+		v = readl(msm_chip->regs.int_status);
+		v &= msm_chip->int_enable[0];
+		while (v) {
+			m = v & -v;
+			j = fls(m) - 1;
+			v &= ~m;
+			generic_handle_irq(FIRST_GPIO_IRQ + msm_chip->chip.base + j);
+		}
+	}
+	desc->chip->ack(irq);
+}
+
+static struct irq_chip msm_gpio_irq_chip = {
+	.name      = "msmgpio",
+	.ack       = msm_gpio_irq_ack,
+	.mask      = msm_gpio_irq_mask,
+	.unmask    = msm_gpio_irq_unmask,
+	.set_wake  = msm_gpio_irq_set_wake,
+	.set_type  = msm_gpio_irq_set_type,
+};
+
+static int __init msm_init_gpio(void)
+{
+	int i, j = 0;
+	for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
+		if (i - FIRST_GPIO_IRQ > msm_gpio_chips[j].chip.ngpio - 1)
+			j++;
+		set_irq_chip_data(i, &msm_gpio_chips[j]);
+		set_irq_chip(i, &msm_gpio_irq_chip);
+		set_irq_handler(i, handle_edge_irq);
+		set_irq_flags(i, IRQF_VALID);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
+		writel(0, msm_gpio_chips[i].regs.int_en);
+		spin_lock_init(&msm_gpio_chips[i].lock);
+		gpiochip_add(&msm_gpio_chips[i].chip);
+	}
+
+	set_irq_chained_handler(INT_GPIO_GROUP1, msm_gpio_irq_handler);
+	set_irq_chained_handler(INT_GPIO_GROUP2, msm_gpio_irq_handler);
+	set_irq_wake(INT_GPIO_GROUP1, 1);
+	set_irq_wake(INT_GPIO_GROUP2, 2);
+
+	return 0;
+}
+
+postcore_initcall(msm_init_gpio);
diff --git a/arch/arm/mach-msm/gpio_hw.h b/arch/arm/mach-msm/gpio_hw.h
new file mode 100644
index 0000000..f7e1b5b
--- /dev/null
+++ b/arch/arm/mach-msm/gpio_hw.h
@@ -0,0 +1,187 @@
+/* arch/arm/mach-msm/gpio_hw.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_GPIO_HW_H
+#define __ARCH_ARM_MACH_MSM_GPIO_HW_H
+
+#include <mach/msm_iomap.h>
+
+/* see 80-VA736-2 Rev C pp 695-751
+**
+** These are actually the *shadow* gpio registers, since the
+** real ones (which allow full access) are only available to the
+** ARM9 side of the world.
+**
+** Since the _BASE need to be page-aligned when we're mapping them
+** to virtual addresses, adjust for the additional offset in these
+** macros.
+*/
+
+#define GPIO1_REG(off) (MSM_GPIO1_BASE + 0x800 + (off))
+#define GPIO2_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off))
+
+#if defined(CONFIG_ARCH_MSM7X00A)
+
+/* output value */
+#define GPIO_OUT_0         GPIO1_REG(0x00)  /* gpio  15-0  */
+#define GPIO_OUT_1         GPIO2_REG(0x00)  /* gpio  42-16 */
+#define GPIO_OUT_2         GPIO1_REG(0x04)  /* gpio  67-43 */
+#define GPIO_OUT_3         GPIO1_REG(0x08)  /* gpio  94-68 */
+#define GPIO_OUT_4         GPIO1_REG(0x0C)  /* gpio 106-95 */
+#define GPIO_OUT_5         GPIO1_REG(0x50)  /* gpio 107-121 */
+
+/* same pin map as above, output enable */
+#define GPIO_OE_0          GPIO1_REG(0x10)
+#define GPIO_OE_1          GPIO2_REG(0x08)
+#define GPIO_OE_2          GPIO1_REG(0x14)
+#define GPIO_OE_3          GPIO1_REG(0x18)
+#define GPIO_OE_4          GPIO1_REG(0x1C)
+#define GPIO_OE_5          GPIO1_REG(0x54)
+
+/* same pin map as above, input read */
+#define GPIO_IN_0          GPIO1_REG(0x34)
+#define GPIO_IN_1          GPIO2_REG(0x20)
+#define GPIO_IN_2          GPIO1_REG(0x38)
+#define GPIO_IN_3          GPIO1_REG(0x3C)
+#define GPIO_IN_4          GPIO1_REG(0x40)
+#define GPIO_IN_5          GPIO1_REG(0x44)
+
+/* same pin map as above, 1=edge 0=level interrup */
+#define GPIO_INT_EDGE_0    GPIO1_REG(0x60)
+#define GPIO_INT_EDGE_1    GPIO2_REG(0x50)
+#define GPIO_INT_EDGE_2    GPIO1_REG(0x64)
+#define GPIO_INT_EDGE_3    GPIO1_REG(0x68)
+#define GPIO_INT_EDGE_4    GPIO1_REG(0x6C)
+#define GPIO_INT_EDGE_5    GPIO1_REG(0xC0)
+
+/* same pin map as above, 1=positive 0=negative */
+#define GPIO_INT_POS_0     GPIO1_REG(0x70)
+#define GPIO_INT_POS_1     GPIO2_REG(0x58)
+#define GPIO_INT_POS_2     GPIO1_REG(0x74)
+#define GPIO_INT_POS_3     GPIO1_REG(0x78)
+#define GPIO_INT_POS_4     GPIO1_REG(0x7C)
+#define GPIO_INT_POS_5     GPIO1_REG(0xBC)
+
+/* same pin map as above, interrupt enable */
+#define GPIO_INT_EN_0      GPIO1_REG(0x80)
+#define GPIO_INT_EN_1      GPIO2_REG(0x60)
+#define GPIO_INT_EN_2      GPIO1_REG(0x84)
+#define GPIO_INT_EN_3      GPIO1_REG(0x88)
+#define GPIO_INT_EN_4      GPIO1_REG(0x8C)
+#define GPIO_INT_EN_5      GPIO1_REG(0xB8)
+
+/* same pin map as above, write 1 to clear interrupt */
+#define GPIO_INT_CLEAR_0   GPIO1_REG(0x90)
+#define GPIO_INT_CLEAR_1   GPIO2_REG(0x68)
+#define GPIO_INT_CLEAR_2   GPIO1_REG(0x94)
+#define GPIO_INT_CLEAR_3   GPIO1_REG(0x98)
+#define GPIO_INT_CLEAR_4   GPIO1_REG(0x9C)
+#define GPIO_INT_CLEAR_5   GPIO1_REG(0xB4)
+
+/* same pin map as above, 1=interrupt pending */
+#define GPIO_INT_STATUS_0  GPIO1_REG(0xA0)
+#define GPIO_INT_STATUS_1  GPIO2_REG(0x70)
+#define GPIO_INT_STATUS_2  GPIO1_REG(0xA4)
+#define GPIO_INT_STATUS_3  GPIO1_REG(0xA8)
+#define GPIO_INT_STATUS_4  GPIO1_REG(0xAC)
+#define GPIO_INT_STATUS_5  GPIO1_REG(0xB0)
+
+#endif
+
+#if defined(CONFIG_ARCH_QSD8X50)
+/* output value */
+#define GPIO_OUT_0         GPIO1_REG(0x00)  /* gpio  15-0   */
+#define GPIO_OUT_1         GPIO2_REG(0x00)  /* gpio  42-16  */
+#define GPIO_OUT_2         GPIO1_REG(0x04)  /* gpio  67-43  */
+#define GPIO_OUT_3         GPIO1_REG(0x08)  /* gpio  94-68  */
+#define GPIO_OUT_4         GPIO1_REG(0x0C)  /* gpio 103-95  */
+#define GPIO_OUT_5         GPIO1_REG(0x10)  /* gpio 121-104 */
+#define GPIO_OUT_6         GPIO1_REG(0x14)  /* gpio 152-122 */
+#define GPIO_OUT_7         GPIO1_REG(0x18)  /* gpio 164-153 */
+
+/* same pin map as above, output enable */
+#define GPIO_OE_0          GPIO1_REG(0x20)
+#define GPIO_OE_1          GPIO2_REG(0x08)
+#define GPIO_OE_2          GPIO1_REG(0x24)
+#define GPIO_OE_3          GPIO1_REG(0x28)
+#define GPIO_OE_4          GPIO1_REG(0x2C)
+#define GPIO_OE_5          GPIO1_REG(0x30)
+#define GPIO_OE_6          GPIO1_REG(0x34)
+#define GPIO_OE_7          GPIO1_REG(0x38)
+
+/* same pin map as above, input read */
+#define GPIO_IN_0          GPIO1_REG(0x50)
+#define GPIO_IN_1          GPIO2_REG(0x20)
+#define GPIO_IN_2          GPIO1_REG(0x54)
+#define GPIO_IN_3          GPIO1_REG(0x58)
+#define GPIO_IN_4          GPIO1_REG(0x5C)
+#define GPIO_IN_5          GPIO1_REG(0x60)
+#define GPIO_IN_6          GPIO1_REG(0x64)
+#define GPIO_IN_7          GPIO1_REG(0x68)
+
+/* same pin map as above, 1=edge 0=level interrup */
+#define GPIO_INT_EDGE_0    GPIO1_REG(0x70)
+#define GPIO_INT_EDGE_1    GPIO2_REG(0x50)
+#define GPIO_INT_EDGE_2    GPIO1_REG(0x74)
+#define GPIO_INT_EDGE_3    GPIO1_REG(0x78)
+#define GPIO_INT_EDGE_4    GPIO1_REG(0x7C)
+#define GPIO_INT_EDGE_5    GPIO1_REG(0x80)
+#define GPIO_INT_EDGE_6    GPIO1_REG(0x84)
+#define GPIO_INT_EDGE_7    GPIO1_REG(0x88)
+
+/* same pin map as above, 1=positive 0=negative */
+#define GPIO_INT_POS_0     GPIO1_REG(0x90)
+#define GPIO_INT_POS_1     GPIO2_REG(0x58)
+#define GPIO_INT_POS_2     GPIO1_REG(0x94)
+#define GPIO_INT_POS_3     GPIO1_REG(0x98)
+#define GPIO_INT_POS_4     GPIO1_REG(0x9C)
+#define GPIO_INT_POS_5     GPIO1_REG(0xA0)
+#define GPIO_INT_POS_6     GPIO1_REG(0xA4)
+#define GPIO_INT_POS_7     GPIO1_REG(0xA8)
+
+/* same pin map as above, interrupt enable */
+#define GPIO_INT_EN_0      GPIO1_REG(0xB0)
+#define GPIO_INT_EN_1      GPIO2_REG(0x60)
+#define GPIO_INT_EN_2      GPIO1_REG(0xB4)
+#define GPIO_INT_EN_3      GPIO1_REG(0xB8)
+#define GPIO_INT_EN_4      GPIO1_REG(0xBC)
+#define GPIO_INT_EN_5      GPIO1_REG(0xC0)
+#define GPIO_INT_EN_6      GPIO1_REG(0xC4)
+#define GPIO_INT_EN_7      GPIO1_REG(0xC8)
+
+/* same pin map as above, write 1 to clear interrupt */
+#define GPIO_INT_CLEAR_0   GPIO1_REG(0xD0)
+#define GPIO_INT_CLEAR_1   GPIO2_REG(0x68)
+#define GPIO_INT_CLEAR_2   GPIO1_REG(0xD4)
+#define GPIO_INT_CLEAR_3   GPIO1_REG(0xD8)
+#define GPIO_INT_CLEAR_4   GPIO1_REG(0xDC)
+#define GPIO_INT_CLEAR_5   GPIO1_REG(0xE0)
+#define GPIO_INT_CLEAR_6   GPIO1_REG(0xE4)
+#define GPIO_INT_CLEAR_7   GPIO1_REG(0xE8)
+
+/* same pin map as above, 1=interrupt pending */
+#define GPIO_INT_STATUS_0  GPIO1_REG(0xF0)
+#define GPIO_INT_STATUS_1  GPIO2_REG(0x70)
+#define GPIO_INT_STATUS_2  GPIO1_REG(0xF4)
+#define GPIO_INT_STATUS_3  GPIO1_REG(0xF8)
+#define GPIO_INT_STATUS_4  GPIO1_REG(0xFC)
+#define GPIO_INT_STATUS_5  GPIO1_REG(0x100)
+#define GPIO_INT_STATUS_6  GPIO1_REG(0x104)
+#define GPIO_INT_STATUS_7  GPIO1_REG(0x108)
+
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h
new file mode 100644
index 0000000..784e6f5
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/gpio.h
@@ -0,0 +1,43 @@
+/* linux/include/asm-arm/arch-msm/gpio.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_GPIO_H
+#define __ASM_ARCH_MSM_GPIO_H
+
+#include <linux/interrupt.h>
+#include <asm-generic/gpio.h>
+
+static inline int gpio_get_value(unsigned gpio)
+{
+	return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+	__gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned gpio)
+{
+	return __gpio_cansleep(gpio);
+}
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+	return __gpio_to_irq(gpio);
+}
+
+#endif
-- 
1.6.2.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 1/4] arm: msm: gpio support
@ 2010-03-30 23:11 ` Daniel Walker
  0 siblings, 0 replies; 22+ messages in thread
From: Daniel Walker @ 2010-03-30 23:11 UTC (permalink / raw)
  To: linux-arm-kernel

From: Daniel Walker <c_dwalke@quicinc.com>

This adds basic gpio support in MSM using gpiolib, as well as gpio
interrupt support.

Signed-off-by: Daniel Walker <c_dwalke@quicinc.com>
---
 arch/arm/Kconfig                      |    1 +
 arch/arm/mach-msm/Makefile            |    1 +
 arch/arm/mach-msm/gpio.c              |  428 +++++++++++++++++++++++++++++++++
 arch/arm/mach-msm/gpio_hw.h           |  187 ++++++++++++++
 arch/arm/mach-msm/include/mach/gpio.h |   43 ++++
 5 files changed, 660 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-msm/gpio.c
 create mode 100644 arch/arm/mach-msm/gpio_hw.h
 create mode 100644 arch/arm/mach-msm/include/mach/gpio.h

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index cadfe2e..5e29092 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -601,6 +601,7 @@ config ARCH_MSM
 	select CPU_V6
 	select GENERIC_TIME
 	select GENERIC_CLOCKEVENTS
+	select ARCH_REQUIRE_GPIOLIB
 	help
 	  Support for Qualcomm MSM7K based systems.  This runs on the ARM11
 	  apps processor of the MSM7K and depends on a shared memory
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 147339c..47d47cb 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -4,6 +4,7 @@ obj-y += proc_comm.o
 obj-y += vreg.o
 obj-y += acpuclock-arm11.o
 obj-y += clock.o clock-7x01a.o
+obj-y += gpio.o
 
 obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o
 obj-$(CONFIG_MSM_SMD) += last_radio_log.o
diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c
new file mode 100644
index 0000000..5b95885
--- /dev/null
+++ b/arch/arm/mach-msm/gpio.c
@@ -0,0 +1,428 @@
+/* linux/arch/arm/mach-msm/gpio.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include "gpio_hw.h"
+
+#include "smd_private.h"
+
+static int msm_gpio_debug_mask;
+module_param_named(debug_mask, msm_gpio_debug_mask, int,
+		   S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define MSM_GPIO_BROKEN_INT_CLEAR 1
+
+/* private gpio_configure flags */
+#define MSM_GPIOF_ENABLE_INTERRUPT      0x10000000
+#define MSM_GPIOF_DISABLE_INTERRUPT     0x20000000
+#define MSM_GPIOF_ENABLE_WAKE           0x40000000
+#define MSM_GPIOF_DISABLE_WAKE          0x80000000
+
+static int gpio_chip_to_irq(struct gpio_chip *chip, unsigned offset);
+static void gpio_chip_set(struct gpio_chip *chip, unsigned offset, int value);
+static int gpio_chip_get(struct gpio_chip *chip, unsigned offset);
+static int gpio_chip_direction_input(struct gpio_chip *chip, unsigned offset);
+static int gpio_chip_direction_output(struct gpio_chip *chip, unsigned offset,
+				      int value);
+
+struct msm_gpio_regs {
+	void __iomem *out;
+	void __iomem *in;
+	void __iomem *int_status;
+	void __iomem *int_clear;
+	void __iomem *int_en;
+	void __iomem *int_edge;
+	void __iomem *int_pos;
+	void __iomem *oe;
+};
+
+struct msm_gpio_chip {
+	struct gpio_chip        chip;
+	struct msm_gpio_regs    regs;
+	spinlock_t		lock;
+#if MSM_GPIO_BROKEN_INT_CLEAR
+	unsigned                int_status_copy;
+#endif
+	unsigned int            both_edge_detect;
+	unsigned int            int_enable[2]; /* 0: awake, 1: sleep */
+};
+
+#define MSM_GPIO_BANK(name, reg_num, start, end)			\
+	{								\
+		.regs = {						\
+			.out =         GPIO_OUT_ ## reg_num,		\
+			.in =          GPIO_IN_ ## reg_num ,		\
+			.int_status =  GPIO_INT_STATUS_ ## reg_num,	\
+			.int_clear =   GPIO_INT_CLEAR_ ## reg_num,	\
+			.int_en =      GPIO_INT_EN_ ## reg_num,		\
+			.int_edge =    GPIO_INT_EDGE_ ## reg_num,	\
+			.int_pos =     GPIO_INT_POS_ ## reg_num,	\
+			.oe =          GPIO_OE_ ## reg_num,		\
+		},							\
+		.chip = {						\
+			.label = name,					\
+			.ngpio = end - start + 1,			\
+			.direction_input = gpio_chip_direction_input,	\
+			.direction_output = gpio_chip_direction_output,	\
+			.get = gpio_chip_get,				\
+			.set = gpio_chip_set,				\
+			.to_irq = gpio_chip_to_irq,			\
+			.base = start,					\
+		}							\
+	}
+
+struct msm_gpio_chip msm_gpio_chips[] = {
+	MSM_GPIO_BANK("bank0", 0, 0, 15),
+	MSM_GPIO_BANK("bank1", 1, 16, 42),
+	MSM_GPIO_BANK("bank2", 2, 43, 67),
+	MSM_GPIO_BANK("bank3", 3, 68, 94),
+#if defined(CONFIG_ARCH_QSD8X50)
+	MSM_GPIO_BANK("bank4", 4, 95, 103),
+	MSM_GPIO_BANK("bank5", 5, 104, 121),
+	MSM_GPIO_BANK("bank6", 6, 122, 152),
+	MSM_GPIO_BANK("bank7", 7, 153, 164),
+#else
+	MSM_GPIO_BANK("bank4", 4, 95, 106),
+	MSM_GPIO_BANK("bank5", 5, 107, 121),
+#endif
+};
+
+#define to_msm_gpio_chip(c) container_of(c, struct msm_gpio_chip, chip)
+
+static int gpio_chip_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
+	unsigned long irq_flags;
+	unsigned b = 1U << (offset);
+	unsigned v;
+
+	spin_lock_irqsave(&old_chip->lock, irq_flags);
+	b = 1U << (offset);
+
+	v = readl(old_chip->regs.oe);
+	writel(v & (~b), old_chip->regs.oe);
+
+	spin_unlock_irqrestore(&old_chip->lock, irq_flags);
+
+	return 0;
+}
+
+static int gpio_chip_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
+	unsigned long irq_flags;
+	int ret = -ENOTSUPP;
+	unsigned b;
+
+	spin_lock_irqsave(&old_chip->lock, irq_flags);
+	b = 1U << (offset);
+
+	ret = (readl(old_chip->regs.in)) & b ? 1 : 0;
+
+	spin_unlock_irqrestore(&old_chip->lock, irq_flags);
+	return ret;
+}
+
+static inline int
+msm_gpio_write(struct msm_gpio_chip *chip, unsigned n, unsigned on)
+{
+	unsigned b = 1U << n;
+	unsigned v;
+
+	v = readl(chip->regs.out);
+	if (on)
+		writel(v | b, chip->regs.out);
+	else
+		writel(v & (~b), chip->regs.out);
+
+	return 0;
+}
+
+static int
+gpio_chip_direction_output(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
+	unsigned long irq_flags;
+	unsigned v;
+
+	spin_lock_irqsave(&old_chip->lock, irq_flags);
+
+	msm_gpio_write(old_chip, offset, value);
+
+	v = readl(old_chip->regs.oe);
+	writel(v | offset, old_chip->regs.oe);
+
+	spin_unlock_irqrestore(&old_chip->lock, irq_flags);
+
+	return 0;
+}
+
+static void gpio_chip_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
+	unsigned long irq_flags;
+
+	spin_lock_irqsave(&old_chip->lock, irq_flags);
+
+	msm_gpio_write(old_chip, offset, value);
+
+	spin_unlock_irqrestore(&old_chip->lock, irq_flags);
+}
+
+static int gpio_chip_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
+	unsigned long irq_flags;
+	int ret;
+
+	spin_lock_irqsave(&old_chip->lock, irq_flags);
+	ret = MSM_GPIO_TO_INT(offset);
+	spin_unlock_irqrestore(&old_chip->lock, irq_flags);
+
+	return ret;
+}
+
+
+static void msm_gpio_update_both_edge_detect(struct msm_gpio_chip *msm_chip)
+{
+	int loop_limit = 100;
+	unsigned pol, val, val2, intstat;
+	do {
+		val = readl(msm_chip->regs.in);
+		pol = readl(msm_chip->regs.int_pos);
+		pol = (pol & ~msm_chip->both_edge_detect) |
+		      (~val & msm_chip->both_edge_detect);
+
+		writel(pol, msm_chip->regs.int_pos);
+
+		intstat = readl(msm_chip->regs.int_status);
+		val2 = readl(msm_chip->regs.in);
+
+		if (((val ^ val2) & msm_chip->both_edge_detect & ~intstat) == 0)
+			return;
+	} while (loop_limit-- > 0);
+	printk(KERN_ERR "msm_gpio_update_both_edge_detect, failed to reach stable state %x != %x\n", val, val2);
+}
+
+static void msm_gpio_irq_ack(unsigned int irq)
+{
+	unsigned long irq_flags;
+	struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+	unsigned b;
+
+	spin_lock_irqsave(&msm_chip->lock, irq_flags);
+
+	b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
+
+#if MSM_GPIO_BROKEN_INT_CLEAR
+	/* Save interrupts that already triggered before we loose them. */
+	/* Any interrupt that triggers between the read of int_status */
+	/* and the write to int_clear will still be lost though. */
+	msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
+	msm_chip->int_status_copy &= ~b;
+#endif
+	writel(b, msm_chip->regs.int_clear);
+
+	msm_gpio_update_both_edge_detect(msm_chip);
+	spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+}
+
+static void msm_gpio_irq_mask(unsigned int irq)
+{
+	unsigned long irq_flags;
+	struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+	unsigned b, v;
+
+	spin_lock_irqsave(&msm_chip->lock, irq_flags);
+
+	b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
+
+	v = readl(msm_chip->regs.int_edge);
+	/* level triggered interrupts are also latched */
+	if (!(v & b)) {
+
+	#if MSM_GPIO_BROKEN_INT_CLEAR
+		/* Save interrupts that already triggered before we loose
+		 * them. Any interrupt that triggers between the read of
+		 * int_status and the write to int_clear will still be
+		 * lost though.
+		 */
+		msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
+		msm_chip->int_status_copy &= ~b;
+	#endif
+		writel(b, msm_chip->regs.int_clear);
+		msm_gpio_update_both_edge_detect(msm_chip);
+	}
+
+	msm_chip->int_enable[0] &= ~b;
+	writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
+
+	spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+}
+
+static void msm_gpio_irq_unmask(unsigned int irq)
+{
+	unsigned long irq_flags;
+	struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+	unsigned b, v;
+
+	spin_lock_irqsave(&msm_chip->lock, irq_flags);
+
+	b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
+
+	v = readl(msm_chip->regs.int_edge);
+	/* level triggered interrupts are also latched */
+	if (!(v & b)) {
+
+	#if MSM_GPIO_BROKEN_INT_CLEAR
+		/* Save interrupts that already triggered before we loose
+		 * them. Any interrupt that triggers between the read of
+		 * int_status and the write to int_clear will still be
+		 * lost though.
+		 */
+		msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
+		msm_chip->int_status_copy &= ~b;
+	#endif
+		writel(b, msm_chip->regs.int_clear);
+		msm_gpio_update_both_edge_detect(msm_chip);
+	}
+
+	msm_chip->int_enable[0] |= b;
+	writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
+
+	spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+}
+
+static int msm_gpio_irq_set_wake(unsigned int irq, unsigned int on)
+{
+	unsigned long irq_flags;
+	struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+	unsigned b;
+
+	spin_lock_irqsave(&msm_chip->lock, irq_flags);
+
+	b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
+
+	if (on)
+		msm_chip->int_enable[1] |= b;
+	else
+		msm_chip->int_enable[1] &= ~b;
+
+	spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+
+	return 0;
+}
+
+
+static int msm_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
+{
+	unsigned long irq_flags;
+	struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+	unsigned b, v;
+
+	spin_lock_irqsave(&msm_chip->lock, irq_flags);
+
+	b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
+
+	v = readl(msm_chip->regs.int_edge);
+	if (flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) {
+		writel(v | b, msm_chip->regs.int_edge);
+		irq_desc[MSM_GPIO_TO_INT(irq - FIRST_GPIO_IRQ)].handle_irq = handle_edge_irq;
+	} else {
+		writel(v & (~b), msm_chip->regs.int_edge);
+		irq_desc[MSM_GPIO_TO_INT(irq - FIRST_GPIO_IRQ)].handle_irq = handle_level_irq;
+	}
+	if ((flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) ==
+			 (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) {
+		msm_chip->both_edge_detect |= b;
+		msm_gpio_update_both_edge_detect(msm_chip);
+	} else {
+		msm_chip->both_edge_detect &= ~b;
+		v = readl(msm_chip->regs.int_pos);
+		if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
+			writel(v | b, msm_chip->regs.int_pos);
+		else
+			writel(v & (~b), msm_chip->regs.int_pos);
+
+	}
+	spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+	return 0;
+}
+
+static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	int i, j, m;
+	unsigned v;
+
+	for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
+		struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i];
+		v = readl(msm_chip->regs.int_status);
+		v &= msm_chip->int_enable[0];
+		while (v) {
+			m = v & -v;
+			j = fls(m) - 1;
+			v &= ~m;
+			generic_handle_irq(FIRST_GPIO_IRQ + msm_chip->chip.base + j);
+		}
+	}
+	desc->chip->ack(irq);
+}
+
+static struct irq_chip msm_gpio_irq_chip = {
+	.name      = "msmgpio",
+	.ack       = msm_gpio_irq_ack,
+	.mask      = msm_gpio_irq_mask,
+	.unmask    = msm_gpio_irq_unmask,
+	.set_wake  = msm_gpio_irq_set_wake,
+	.set_type  = msm_gpio_irq_set_type,
+};
+
+static int __init msm_init_gpio(void)
+{
+	int i, j = 0;
+	for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
+		if (i - FIRST_GPIO_IRQ > msm_gpio_chips[j].chip.ngpio - 1)
+			j++;
+		set_irq_chip_data(i, &msm_gpio_chips[j]);
+		set_irq_chip(i, &msm_gpio_irq_chip);
+		set_irq_handler(i, handle_edge_irq);
+		set_irq_flags(i, IRQF_VALID);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
+		writel(0, msm_gpio_chips[i].regs.int_en);
+		spin_lock_init(&msm_gpio_chips[i].lock);
+		gpiochip_add(&msm_gpio_chips[i].chip);
+	}
+
+	set_irq_chained_handler(INT_GPIO_GROUP1, msm_gpio_irq_handler);
+	set_irq_chained_handler(INT_GPIO_GROUP2, msm_gpio_irq_handler);
+	set_irq_wake(INT_GPIO_GROUP1, 1);
+	set_irq_wake(INT_GPIO_GROUP2, 2);
+
+	return 0;
+}
+
+postcore_initcall(msm_init_gpio);
diff --git a/arch/arm/mach-msm/gpio_hw.h b/arch/arm/mach-msm/gpio_hw.h
new file mode 100644
index 0000000..f7e1b5b
--- /dev/null
+++ b/arch/arm/mach-msm/gpio_hw.h
@@ -0,0 +1,187 @@
+/* arch/arm/mach-msm/gpio_hw.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_GPIO_HW_H
+#define __ARCH_ARM_MACH_MSM_GPIO_HW_H
+
+#include <mach/msm_iomap.h>
+
+/* see 80-VA736-2 Rev C pp 695-751
+**
+** These are actually the *shadow* gpio registers, since the
+** real ones (which allow full access) are only available to the
+** ARM9 side of the world.
+**
+** Since the _BASE need to be page-aligned when we're mapping them
+** to virtual addresses, adjust for the additional offset in these
+** macros.
+*/
+
+#define GPIO1_REG(off) (MSM_GPIO1_BASE + 0x800 + (off))
+#define GPIO2_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off))
+
+#if defined(CONFIG_ARCH_MSM7X00A)
+
+/* output value */
+#define GPIO_OUT_0         GPIO1_REG(0x00)  /* gpio  15-0  */
+#define GPIO_OUT_1         GPIO2_REG(0x00)  /* gpio  42-16 */
+#define GPIO_OUT_2         GPIO1_REG(0x04)  /* gpio  67-43 */
+#define GPIO_OUT_3         GPIO1_REG(0x08)  /* gpio  94-68 */
+#define GPIO_OUT_4         GPIO1_REG(0x0C)  /* gpio 106-95 */
+#define GPIO_OUT_5         GPIO1_REG(0x50)  /* gpio 107-121 */
+
+/* same pin map as above, output enable */
+#define GPIO_OE_0          GPIO1_REG(0x10)
+#define GPIO_OE_1          GPIO2_REG(0x08)
+#define GPIO_OE_2          GPIO1_REG(0x14)
+#define GPIO_OE_3          GPIO1_REG(0x18)
+#define GPIO_OE_4          GPIO1_REG(0x1C)
+#define GPIO_OE_5          GPIO1_REG(0x54)
+
+/* same pin map as above, input read */
+#define GPIO_IN_0          GPIO1_REG(0x34)
+#define GPIO_IN_1          GPIO2_REG(0x20)
+#define GPIO_IN_2          GPIO1_REG(0x38)
+#define GPIO_IN_3          GPIO1_REG(0x3C)
+#define GPIO_IN_4          GPIO1_REG(0x40)
+#define GPIO_IN_5          GPIO1_REG(0x44)
+
+/* same pin map as above, 1=edge 0=level interrup */
+#define GPIO_INT_EDGE_0    GPIO1_REG(0x60)
+#define GPIO_INT_EDGE_1    GPIO2_REG(0x50)
+#define GPIO_INT_EDGE_2    GPIO1_REG(0x64)
+#define GPIO_INT_EDGE_3    GPIO1_REG(0x68)
+#define GPIO_INT_EDGE_4    GPIO1_REG(0x6C)
+#define GPIO_INT_EDGE_5    GPIO1_REG(0xC0)
+
+/* same pin map as above, 1=positive 0=negative */
+#define GPIO_INT_POS_0     GPIO1_REG(0x70)
+#define GPIO_INT_POS_1     GPIO2_REG(0x58)
+#define GPIO_INT_POS_2     GPIO1_REG(0x74)
+#define GPIO_INT_POS_3     GPIO1_REG(0x78)
+#define GPIO_INT_POS_4     GPIO1_REG(0x7C)
+#define GPIO_INT_POS_5     GPIO1_REG(0xBC)
+
+/* same pin map as above, interrupt enable */
+#define GPIO_INT_EN_0      GPIO1_REG(0x80)
+#define GPIO_INT_EN_1      GPIO2_REG(0x60)
+#define GPIO_INT_EN_2      GPIO1_REG(0x84)
+#define GPIO_INT_EN_3      GPIO1_REG(0x88)
+#define GPIO_INT_EN_4      GPIO1_REG(0x8C)
+#define GPIO_INT_EN_5      GPIO1_REG(0xB8)
+
+/* same pin map as above, write 1 to clear interrupt */
+#define GPIO_INT_CLEAR_0   GPIO1_REG(0x90)
+#define GPIO_INT_CLEAR_1   GPIO2_REG(0x68)
+#define GPIO_INT_CLEAR_2   GPIO1_REG(0x94)
+#define GPIO_INT_CLEAR_3   GPIO1_REG(0x98)
+#define GPIO_INT_CLEAR_4   GPIO1_REG(0x9C)
+#define GPIO_INT_CLEAR_5   GPIO1_REG(0xB4)
+
+/* same pin map as above, 1=interrupt pending */
+#define GPIO_INT_STATUS_0  GPIO1_REG(0xA0)
+#define GPIO_INT_STATUS_1  GPIO2_REG(0x70)
+#define GPIO_INT_STATUS_2  GPIO1_REG(0xA4)
+#define GPIO_INT_STATUS_3  GPIO1_REG(0xA8)
+#define GPIO_INT_STATUS_4  GPIO1_REG(0xAC)
+#define GPIO_INT_STATUS_5  GPIO1_REG(0xB0)
+
+#endif
+
+#if defined(CONFIG_ARCH_QSD8X50)
+/* output value */
+#define GPIO_OUT_0         GPIO1_REG(0x00)  /* gpio  15-0   */
+#define GPIO_OUT_1         GPIO2_REG(0x00)  /* gpio  42-16  */
+#define GPIO_OUT_2         GPIO1_REG(0x04)  /* gpio  67-43  */
+#define GPIO_OUT_3         GPIO1_REG(0x08)  /* gpio  94-68  */
+#define GPIO_OUT_4         GPIO1_REG(0x0C)  /* gpio 103-95  */
+#define GPIO_OUT_5         GPIO1_REG(0x10)  /* gpio 121-104 */
+#define GPIO_OUT_6         GPIO1_REG(0x14)  /* gpio 152-122 */
+#define GPIO_OUT_7         GPIO1_REG(0x18)  /* gpio 164-153 */
+
+/* same pin map as above, output enable */
+#define GPIO_OE_0          GPIO1_REG(0x20)
+#define GPIO_OE_1          GPIO2_REG(0x08)
+#define GPIO_OE_2          GPIO1_REG(0x24)
+#define GPIO_OE_3          GPIO1_REG(0x28)
+#define GPIO_OE_4          GPIO1_REG(0x2C)
+#define GPIO_OE_5          GPIO1_REG(0x30)
+#define GPIO_OE_6          GPIO1_REG(0x34)
+#define GPIO_OE_7          GPIO1_REG(0x38)
+
+/* same pin map as above, input read */
+#define GPIO_IN_0          GPIO1_REG(0x50)
+#define GPIO_IN_1          GPIO2_REG(0x20)
+#define GPIO_IN_2          GPIO1_REG(0x54)
+#define GPIO_IN_3          GPIO1_REG(0x58)
+#define GPIO_IN_4          GPIO1_REG(0x5C)
+#define GPIO_IN_5          GPIO1_REG(0x60)
+#define GPIO_IN_6          GPIO1_REG(0x64)
+#define GPIO_IN_7          GPIO1_REG(0x68)
+
+/* same pin map as above, 1=edge 0=level interrup */
+#define GPIO_INT_EDGE_0    GPIO1_REG(0x70)
+#define GPIO_INT_EDGE_1    GPIO2_REG(0x50)
+#define GPIO_INT_EDGE_2    GPIO1_REG(0x74)
+#define GPIO_INT_EDGE_3    GPIO1_REG(0x78)
+#define GPIO_INT_EDGE_4    GPIO1_REG(0x7C)
+#define GPIO_INT_EDGE_5    GPIO1_REG(0x80)
+#define GPIO_INT_EDGE_6    GPIO1_REG(0x84)
+#define GPIO_INT_EDGE_7    GPIO1_REG(0x88)
+
+/* same pin map as above, 1=positive 0=negative */
+#define GPIO_INT_POS_0     GPIO1_REG(0x90)
+#define GPIO_INT_POS_1     GPIO2_REG(0x58)
+#define GPIO_INT_POS_2     GPIO1_REG(0x94)
+#define GPIO_INT_POS_3     GPIO1_REG(0x98)
+#define GPIO_INT_POS_4     GPIO1_REG(0x9C)
+#define GPIO_INT_POS_5     GPIO1_REG(0xA0)
+#define GPIO_INT_POS_6     GPIO1_REG(0xA4)
+#define GPIO_INT_POS_7     GPIO1_REG(0xA8)
+
+/* same pin map as above, interrupt enable */
+#define GPIO_INT_EN_0      GPIO1_REG(0xB0)
+#define GPIO_INT_EN_1      GPIO2_REG(0x60)
+#define GPIO_INT_EN_2      GPIO1_REG(0xB4)
+#define GPIO_INT_EN_3      GPIO1_REG(0xB8)
+#define GPIO_INT_EN_4      GPIO1_REG(0xBC)
+#define GPIO_INT_EN_5      GPIO1_REG(0xC0)
+#define GPIO_INT_EN_6      GPIO1_REG(0xC4)
+#define GPIO_INT_EN_7      GPIO1_REG(0xC8)
+
+/* same pin map as above, write 1 to clear interrupt */
+#define GPIO_INT_CLEAR_0   GPIO1_REG(0xD0)
+#define GPIO_INT_CLEAR_1   GPIO2_REG(0x68)
+#define GPIO_INT_CLEAR_2   GPIO1_REG(0xD4)
+#define GPIO_INT_CLEAR_3   GPIO1_REG(0xD8)
+#define GPIO_INT_CLEAR_4   GPIO1_REG(0xDC)
+#define GPIO_INT_CLEAR_5   GPIO1_REG(0xE0)
+#define GPIO_INT_CLEAR_6   GPIO1_REG(0xE4)
+#define GPIO_INT_CLEAR_7   GPIO1_REG(0xE8)
+
+/* same pin map as above, 1=interrupt pending */
+#define GPIO_INT_STATUS_0  GPIO1_REG(0xF0)
+#define GPIO_INT_STATUS_1  GPIO2_REG(0x70)
+#define GPIO_INT_STATUS_2  GPIO1_REG(0xF4)
+#define GPIO_INT_STATUS_3  GPIO1_REG(0xF8)
+#define GPIO_INT_STATUS_4  GPIO1_REG(0xFC)
+#define GPIO_INT_STATUS_5  GPIO1_REG(0x100)
+#define GPIO_INT_STATUS_6  GPIO1_REG(0x104)
+#define GPIO_INT_STATUS_7  GPIO1_REG(0x108)
+
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h
new file mode 100644
index 0000000..784e6f5
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/gpio.h
@@ -0,0 +1,43 @@
+/* linux/include/asm-arm/arch-msm/gpio.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_GPIO_H
+#define __ASM_ARCH_MSM_GPIO_H
+
+#include <linux/interrupt.h>
+#include <asm-generic/gpio.h>
+
+static inline int gpio_get_value(unsigned gpio)
+{
+	return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+	__gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned gpio)
+{
+	return __gpio_cansleep(gpio);
+}
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+	return __gpio_to_irq(gpio);
+}
+
+#endif
-- 
1.6.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 2/4] arm: msm: GPIO support for HTC Dream
  2010-03-30 23:11 ` Daniel Walker
@ 2010-03-30 23:11   ` Daniel Walker
  -1 siblings, 0 replies; 22+ messages in thread
From: Daniel Walker @ 2010-03-30 23:11 UTC (permalink / raw)
  To: linux-arm-kernel; +Cc: linux-arm-msm, Pavel Machek, Daniel Walker

From: Pavel Machek <pavel@ucw.cz>

Add GPIO support for HTC Dream.

Signed-off-by: Pavel Machek <pavel@ucw.cz>
[dwalker@codeaurora.org: renamed to trout]
Signed-off-by: Daniel Walker <dwalker@codeaurora.org>
---
 arch/arm/mach-msm/Makefile           |    2 +-
 arch/arm/mach-msm/board-trout-gpio.c |  112 ++++++++++++++++++++++++
 arch/arm/mach-msm/board-trout.h      |  157 ++++++++++++++++++++++++++++++++++
 3 files changed, 270 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/mach-msm/board-trout-gpio.c

diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 47d47cb..fb9ab2d 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -9,5 +9,5 @@ obj-y += gpio.o
 obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o
 obj-$(CONFIG_MSM_SMD) += last_radio_log.o
 
-obj-$(CONFIG_MACH_TROUT) += board-trout.o
+obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o
 obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o
diff --git a/arch/arm/mach-msm/board-trout-gpio.c b/arch/arm/mach-msm/board-trout-gpio.c
new file mode 100644
index 0000000..6e6bc76
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout-gpio.c
@@ -0,0 +1,112 @@
+/*
+ * linux/arch/arm/mach-msm/gpio.c
+ *
+ * Copyright (C) 2005 HP Labs
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2009 Pavel Machek <pavel@ucw.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+
+#include "board-trout.h"
+
+struct msm_gpio_chip {
+	struct gpio_chip	chip;
+	void __iomem		*reg;	/* Base of register bank */
+	u8			shadow;
+};
+
+#define to_msm_gpio_chip(c) container_of(c, struct msm_gpio_chip, chip)
+
+static int msm_gpiolib_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct msm_gpio_chip *msm_gpio = to_msm_gpio_chip(chip);
+	unsigned mask = 1 << offset;
+
+	return !! (readb(msm_gpio->reg) & mask);
+}
+
+static void msm_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val)
+{
+	struct msm_gpio_chip *msm_gpio = to_msm_gpio_chip(chip);
+	unsigned mask = 1 << offset;
+
+	if (val)
+		msm_gpio->shadow |= mask;
+	else
+		msm_gpio->shadow &= ~mask;
+
+	writeb(msm_gpio->shadow, msm_gpio->reg);
+}
+
+static int msm_gpiolib_direction_input(struct gpio_chip *chip,
+					unsigned offset)
+{
+	msm_gpiolib_set(chip, offset, 0);
+	return 0;
+}
+
+static int msm_gpiolib_direction_output(struct gpio_chip *chip,
+					 unsigned offset, int val)
+{
+	msm_gpiolib_set(chip, offset, val);
+	return 0;
+}
+
+#define TROUT_GPIO_BANK(name, reg_num, base_gpio, shadow_val)		\
+	{								\
+		.chip = {						\
+			.label		  = name,			\
+			.direction_input  = msm_gpiolib_direction_input,\
+			.direction_output = msm_gpiolib_direction_output, \
+			.get		  = msm_gpiolib_get,		\
+			.set		  = msm_gpiolib_set,		\
+			.base		  = base_gpio,			\
+			.ngpio		  = 8,				\
+		},							\
+		.reg = (void *) reg_num + TROUT_CPLD_BASE,		\
+		.shadow = shadow_val,					\
+	}
+
+static struct msm_gpio_chip msm_gpio_banks[] = {
+#if defined(CONFIG_MSM_DEBUG_UART1)
+        /* H2W pins <-> UART1 */
+        TROUT_GPIO_BANK("MISC2", 0x00,   TROUT_GPIO_MISC2_BASE, 0x40),
+#else
+	/* H2W pins <-> UART3, Bluetooth <-> UART1 */
+        TROUT_GPIO_BANK("MISC2", 0x00,   TROUT_GPIO_MISC2_BASE, 0x80),
+#endif
+	/* I2C pull */
+        TROUT_GPIO_BANK("MISC3", 0x02,   TROUT_GPIO_MISC3_BASE, 0x04),
+        TROUT_GPIO_BANK("MISC4", 0x04,   TROUT_GPIO_MISC4_BASE, 0),
+	/* mmdi 32k en */
+        TROUT_GPIO_BANK("MISC5", 0x06,   TROUT_GPIO_MISC5_BASE, 0x04),
+        TROUT_GPIO_BANK("INT2", 0x08,    TROUT_GPIO_INT2_BASE,  0),
+        TROUT_GPIO_BANK("MISC1", 0x0a,   TROUT_GPIO_MISC1_BASE, 0),
+        TROUT_GPIO_BANK("VIRTUAL", 0x12, TROUT_GPIO_VIRTUAL_BASE, 0),
+};
+
+/*
+ * Called from the processor-specific init to enable GPIO pin support.
+ */
+int __init trout_init_gpio(void)
+{
+        int i;
+
+        for (i = 0; i < ARRAY_SIZE(msm_gpio_banks); i++)
+                gpiochip_add(&msm_gpio_banks[i].chip);
+
+	return 0;
+}
+
+postcore_initcall(trout_init_gpio);
+
diff --git a/arch/arm/mach-msm/board-trout.h b/arch/arm/mach-msm/board-trout.h
index 4f345a5..308c4df 100644
--- a/arch/arm/mach-msm/board-trout.h
+++ b/arch/arm/mach-msm/board-trout.h
@@ -1,5 +1,162 @@
+/* linux/arch/arm/mach-msm/board-trout.h
+** Author: Brian Swetland <swetland@google.com>
+*/
+#ifndef __ARCH_ARM_MACH_MSM_BOARD_TROUT_H
+#define __ARCH_ARM_MACH_MSM_BOARD_TROUT_H
+
+#include <mach/board.h>
+
+#define MSM_SMI_BASE		0x00000000
+#define MSM_SMI_SIZE		0x00800000
+
+#define MSM_EBI_BASE		0x10000000
+#define MSM_EBI_SIZE		0x06e00000
+
+#define MSM_PMEM_GPU0_BASE	0x00000000
+#define MSM_PMEM_GPU0_SIZE	0x00700000
+
+#define MSM_PMEM_MDP_BASE	0x02000000
+#define MSM_PMEM_MDP_SIZE	0x00800000
+
+#define MSM_PMEM_ADSP_BASE      0x02800000
+#define MSM_PMEM_ADSP_SIZE	0x00800000
+
+#define MSM_PMEM_CAMERA_BASE	0x03000000
+#define MSM_PMEM_CAMERA_SIZE	0x00800000
+
+#define MSM_FB_BASE		0x03800000
+#define MSM_FB_SIZE		0x00100000
+
+#define MSM_LINUX_BASE		MSM_EBI_BASE
+#define MSM_LINUX_SIZE		0x06500000
+
+#define MSM_PMEM_GPU1_SIZE	0x800000
+#define MSM_PMEM_GPU1_BASE	MSM_RAM_CONSOLE_BASE - MSM_PMEM_GPU1_SIZE
+
+#define MSM_RAM_CONSOLE_BASE	MSM_EBI_BASE + 0x6d00000
+#define MSM_RAM_CONSOLE_SIZE	128 * SZ_1K
+
+#if (MSM_FB_BASE + MSM_FB_SIZE) >= (MSM_PMEM_GPU1_BASE)
+#error invalid memory map
+#endif
+
+#define DECLARE_MSM_IOMAP
+#include <mach/msm_iomap.h>
+
+#define TROUT_4_BALL_UP_0     1
+#define TROUT_4_BALL_LEFT_0   18
+#define TROUT_4_BALL_DOWN_0   57
+#define TROUT_4_BALL_RIGHT_0  91
+
+#define TROUT_5_BALL_UP_0     94
+#define TROUT_5_BALL_LEFT_0   18
+#define TROUT_5_BALL_DOWN_0   90
+#define TROUT_5_BALL_RIGHT_0  19
+
+#define TROUT_POWER_KEY     20
+
+#define TROUT_4_TP_LS_EN    19
+#define TROUT_5_TP_LS_EN    1
 
 #define TROUT_CPLD_BASE   0xE8100000
 #define TROUT_CPLD_START  0x98000000
 #define TROUT_CPLD_SIZE   SZ_4K
 
+#define TROUT_GPIO_CABLE_IN1		(83)
+#define TROUT_GPIO_CABLE_IN2		(49)
+
+#define TROUT_GPIO_START (128)
+
+#define TROUT_GPIO_INT_MASK0_REG            (0x0c)
+#define TROUT_GPIO_INT_STAT0_REG            (0x0e)
+#define TROUT_GPIO_INT_MASK1_REG            (0x14)
+#define TROUT_GPIO_INT_STAT1_REG            (0x10)
+
+#define TROUT_GPIO_HAPTIC_PWM               (28)
+#define TROUT_GPIO_PS_HOLD                  (25)
+
+#define TROUT_GPIO_MISC2_BASE               (TROUT_GPIO_START + 0x00)
+#define TROUT_GPIO_MISC3_BASE               (TROUT_GPIO_START + 0x08)
+#define TROUT_GPIO_MISC4_BASE               (TROUT_GPIO_START + 0x10)
+#define TROUT_GPIO_MISC5_BASE               (TROUT_GPIO_START + 0x18)
+#define TROUT_GPIO_INT2_BASE                (TROUT_GPIO_START + 0x20)
+#define TROUT_GPIO_MISC1_BASE               (TROUT_GPIO_START + 0x28)
+#define TROUT_GPIO_VIRTUAL_BASE             (TROUT_GPIO_START + 0x30)
+#define TROUT_GPIO_INT5_BASE                (TROUT_GPIO_START + 0x48)
+
+#define TROUT_GPIO_CHARGER_EN               (TROUT_GPIO_MISC2_BASE + 0)
+#define TROUT_GPIO_ISET                     (TROUT_GPIO_MISC2_BASE + 1)
+#define TROUT_GPIO_H2W_DAT_DIR              (TROUT_GPIO_MISC2_BASE + 2)
+#define TROUT_GPIO_H2W_CLK_DIR              (TROUT_GPIO_MISC2_BASE + 3)
+#define TROUT_GPIO_H2W_DAT_GPO              (TROUT_GPIO_MISC2_BASE + 4)
+#define TROUT_GPIO_H2W_CLK_GPO              (TROUT_GPIO_MISC2_BASE + 5)
+#define TROUT_GPIO_H2W_SEL0                 (TROUT_GPIO_MISC2_BASE + 6)
+#define TROUT_GPIO_H2W_SEL1                 (TROUT_GPIO_MISC2_BASE + 7)
+
+#define TROUT_GPIO_SPOTLIGHT_EN             (TROUT_GPIO_MISC3_BASE + 0)
+#define TROUT_GPIO_FLASH_EN                 (TROUT_GPIO_MISC3_BASE + 1)
+#define TROUT_GPIO_I2C_PULL                 (TROUT_GPIO_MISC3_BASE + 2)
+#define TROUT_GPIO_TP_I2C_PULL              (TROUT_GPIO_MISC3_BASE + 3)
+#define TROUT_GPIO_TP_EN                    (TROUT_GPIO_MISC3_BASE + 4)
+#define TROUT_GPIO_JOG_EN                   (TROUT_GPIO_MISC3_BASE + 5)
+#define TROUT_GPIO_UI_LED_EN                (TROUT_GPIO_MISC3_BASE + 6)
+#define TROUT_GPIO_QTKEY_LED_EN             (TROUT_GPIO_MISC3_BASE + 7)
+
+#define TROUT_GPIO_VCM_PWDN                 (TROUT_GPIO_MISC4_BASE + 0)
+#define TROUT_GPIO_USB_H2W_SW               (TROUT_GPIO_MISC4_BASE + 1)
+#define TROUT_GPIO_COMPASS_RST_N            (TROUT_GPIO_MISC4_BASE + 2)
+#define TROUT_GPIO_HAPTIC_EN_UP             (TROUT_GPIO_MISC4_BASE + 3)
+#define TROUT_GPIO_HAPTIC_EN_MAIN           (TROUT_GPIO_MISC4_BASE + 4)
+#define TROUT_GPIO_USB_PHY_RST_N            (TROUT_GPIO_MISC4_BASE + 5)
+#define TROUT_GPIO_WIFI_PA_RESETX           (TROUT_GPIO_MISC4_BASE + 6)
+#define TROUT_GPIO_WIFI_EN                  (TROUT_GPIO_MISC4_BASE + 7)
+
+#define TROUT_GPIO_BT_32K_EN                (TROUT_GPIO_MISC5_BASE + 0)
+#define TROUT_GPIO_MAC_32K_EN               (TROUT_GPIO_MISC5_BASE + 1)
+#define TROUT_GPIO_MDDI_32K_EN              (TROUT_GPIO_MISC5_BASE + 2)
+#define TROUT_GPIO_COMPASS_32K_EN           (TROUT_GPIO_MISC5_BASE + 3)
+
+#define TROUT_GPIO_NAVI_ACT_N               (TROUT_GPIO_INT2_BASE + 0)
+#define TROUT_GPIO_COMPASS_IRQ              (TROUT_GPIO_INT2_BASE + 1)
+#define TROUT_GPIO_SLIDING_DET              (TROUT_GPIO_INT2_BASE + 2)
+#define TROUT_GPIO_AUD_HSMIC_DET_N          (TROUT_GPIO_INT2_BASE + 3)
+#define TROUT_GPIO_SD_DOOR_N                (TROUT_GPIO_INT2_BASE + 4)
+#define TROUT_GPIO_CAM_BTN_STEP1_N          (TROUT_GPIO_INT2_BASE + 5)
+#define TROUT_GPIO_CAM_BTN_STEP2_N          (TROUT_GPIO_INT2_BASE + 6)
+#define TROUT_GPIO_TP_ATT_N                 (TROUT_GPIO_INT2_BASE + 7)
+#define TROUT_GPIO_BANK0_FIRST_INT_SOURCE   (TROUT_GPIO_NAVI_ACT_N)
+#define TROUT_GPIO_BANK0_LAST_INT_SOURCE    (TROUT_GPIO_TP_ATT_N)
+
+#define TROUT_GPIO_H2W_DAT_GPI              (TROUT_GPIO_MISC1_BASE + 0)
+#define TROUT_GPIO_H2W_CLK_GPI              (TROUT_GPIO_MISC1_BASE + 1)
+#define TROUT_GPIO_CPLD128_VER_0            (TROUT_GPIO_MISC1_BASE + 4)
+#define TROUT_GPIO_CPLD128_VER_1            (TROUT_GPIO_MISC1_BASE + 5)
+#define TROUT_GPIO_CPLD128_VER_2            (TROUT_GPIO_MISC1_BASE + 6)
+#define TROUT_GPIO_CPLD128_VER_3            (TROUT_GPIO_MISC1_BASE + 7)
+
+#define TROUT_GPIO_SDMC_CD_N                (TROUT_GPIO_VIRTUAL_BASE + 0)
+#define TROUT_GPIO_END                      (TROUT_GPIO_SDMC_CD_N)
+#define TROUT_GPIO_BANK1_FIRST_INT_SOURCE   (TROUT_GPIO_SDMC_CD_N)
+#define TROUT_GPIO_BANK1_LAST_INT_SOURCE    (TROUT_GPIO_SDMC_CD_N)
+
+#define TROUT_GPIO_VIRTUAL_TO_REAL_OFFSET \
+	(TROUT_GPIO_INT5_BASE - TROUT_GPIO_VIRTUAL_BASE)
+
+#define TROUT_INT_START (NR_MSM_IRQS + NR_GPIO_IRQS)
+#define TROUT_INT_BANK0_COUNT (8)
+#define TROUT_INT_BANK1_START (TROUT_INT_START + TROUT_INT_BANK0_COUNT)
+#define TROUT_INT_BANK1_COUNT (1)
+#define TROUT_INT_END (TROUT_INT_START + TROUT_INT_BANK0_COUNT + \
+			TROUT_INT_BANK1_COUNT - 1)
+#define TROUT_GPIO_TO_INT(n) (((n) <= TROUT_GPIO_BANK0_LAST_INT_SOURCE) ? \
+	(TROUT_INT_START - TROUT_GPIO_BANK0_FIRST_INT_SOURCE + (n)) : \
+	(TROUT_INT_BANK1_START - TROUT_GPIO_BANK1_FIRST_INT_SOURCE + (n)))
+
+#define TROUT_INT_TO_BANK(n) ((n - TROUT_INT_START) / TROUT_INT_BANK0_COUNT)
+#define TROUT_INT_TO_MASK(n) (1U << ((n - TROUT_INT_START) & 7))
+#define TROUT_BANK_TO_MASK_REG(bank) \
+	(bank ? TROUT_GPIO_INT_MASK1_REG : TROUT_GPIO_INT_MASK0_REG)
+#define TROUT_BANK_TO_STAT_REG(bank) \
+	(bank ? TROUT_GPIO_INT_STAT1_REG : TROUT_GPIO_INT_STAT0_REG)
+
+#endif /* GUARD */
-- 
1.6.2.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 2/4] arm: msm: GPIO support for HTC Dream
@ 2010-03-30 23:11   ` Daniel Walker
  0 siblings, 0 replies; 22+ messages in thread
From: Daniel Walker @ 2010-03-30 23:11 UTC (permalink / raw)
  To: linux-arm-kernel

From: Pavel Machek <pavel@ucw.cz>

Add GPIO support for HTC Dream.

Signed-off-by: Pavel Machek <pavel@ucw.cz>
[dwalker at codeaurora.org: renamed to trout]
Signed-off-by: Daniel Walker <dwalker@codeaurora.org>
---
 arch/arm/mach-msm/Makefile           |    2 +-
 arch/arm/mach-msm/board-trout-gpio.c |  112 ++++++++++++++++++++++++
 arch/arm/mach-msm/board-trout.h      |  157 ++++++++++++++++++++++++++++++++++
 3 files changed, 270 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/mach-msm/board-trout-gpio.c

diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 47d47cb..fb9ab2d 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -9,5 +9,5 @@ obj-y += gpio.o
 obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o
 obj-$(CONFIG_MSM_SMD) += last_radio_log.o
 
-obj-$(CONFIG_MACH_TROUT) += board-trout.o
+obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o
 obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o
diff --git a/arch/arm/mach-msm/board-trout-gpio.c b/arch/arm/mach-msm/board-trout-gpio.c
new file mode 100644
index 0000000..6e6bc76
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout-gpio.c
@@ -0,0 +1,112 @@
+/*
+ * linux/arch/arm/mach-msm/gpio.c
+ *
+ * Copyright (C) 2005 HP Labs
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2009 Pavel Machek <pavel@ucw.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+
+#include "board-trout.h"
+
+struct msm_gpio_chip {
+	struct gpio_chip	chip;
+	void __iomem		*reg;	/* Base of register bank */
+	u8			shadow;
+};
+
+#define to_msm_gpio_chip(c) container_of(c, struct msm_gpio_chip, chip)
+
+static int msm_gpiolib_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct msm_gpio_chip *msm_gpio = to_msm_gpio_chip(chip);
+	unsigned mask = 1 << offset;
+
+	return !! (readb(msm_gpio->reg) & mask);
+}
+
+static void msm_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val)
+{
+	struct msm_gpio_chip *msm_gpio = to_msm_gpio_chip(chip);
+	unsigned mask = 1 << offset;
+
+	if (val)
+		msm_gpio->shadow |= mask;
+	else
+		msm_gpio->shadow &= ~mask;
+
+	writeb(msm_gpio->shadow, msm_gpio->reg);
+}
+
+static int msm_gpiolib_direction_input(struct gpio_chip *chip,
+					unsigned offset)
+{
+	msm_gpiolib_set(chip, offset, 0);
+	return 0;
+}
+
+static int msm_gpiolib_direction_output(struct gpio_chip *chip,
+					 unsigned offset, int val)
+{
+	msm_gpiolib_set(chip, offset, val);
+	return 0;
+}
+
+#define TROUT_GPIO_BANK(name, reg_num, base_gpio, shadow_val)		\
+	{								\
+		.chip = {						\
+			.label		  = name,			\
+			.direction_input  = msm_gpiolib_direction_input,\
+			.direction_output = msm_gpiolib_direction_output, \
+			.get		  = msm_gpiolib_get,		\
+			.set		  = msm_gpiolib_set,		\
+			.base		  = base_gpio,			\
+			.ngpio		  = 8,				\
+		},							\
+		.reg = (void *) reg_num + TROUT_CPLD_BASE,		\
+		.shadow = shadow_val,					\
+	}
+
+static struct msm_gpio_chip msm_gpio_banks[] = {
+#if defined(CONFIG_MSM_DEBUG_UART1)
+        /* H2W pins <-> UART1 */
+        TROUT_GPIO_BANK("MISC2", 0x00,   TROUT_GPIO_MISC2_BASE, 0x40),
+#else
+	/* H2W pins <-> UART3, Bluetooth <-> UART1 */
+        TROUT_GPIO_BANK("MISC2", 0x00,   TROUT_GPIO_MISC2_BASE, 0x80),
+#endif
+	/* I2C pull */
+        TROUT_GPIO_BANK("MISC3", 0x02,   TROUT_GPIO_MISC3_BASE, 0x04),
+        TROUT_GPIO_BANK("MISC4", 0x04,   TROUT_GPIO_MISC4_BASE, 0),
+	/* mmdi 32k en */
+        TROUT_GPIO_BANK("MISC5", 0x06,   TROUT_GPIO_MISC5_BASE, 0x04),
+        TROUT_GPIO_BANK("INT2", 0x08,    TROUT_GPIO_INT2_BASE,  0),
+        TROUT_GPIO_BANK("MISC1", 0x0a,   TROUT_GPIO_MISC1_BASE, 0),
+        TROUT_GPIO_BANK("VIRTUAL", 0x12, TROUT_GPIO_VIRTUAL_BASE, 0),
+};
+
+/*
+ * Called from the processor-specific init to enable GPIO pin support.
+ */
+int __init trout_init_gpio(void)
+{
+        int i;
+
+        for (i = 0; i < ARRAY_SIZE(msm_gpio_banks); i++)
+                gpiochip_add(&msm_gpio_banks[i].chip);
+
+	return 0;
+}
+
+postcore_initcall(trout_init_gpio);
+
diff --git a/arch/arm/mach-msm/board-trout.h b/arch/arm/mach-msm/board-trout.h
index 4f345a5..308c4df 100644
--- a/arch/arm/mach-msm/board-trout.h
+++ b/arch/arm/mach-msm/board-trout.h
@@ -1,5 +1,162 @@
+/* linux/arch/arm/mach-msm/board-trout.h
+** Author: Brian Swetland <swetland@google.com>
+*/
+#ifndef __ARCH_ARM_MACH_MSM_BOARD_TROUT_H
+#define __ARCH_ARM_MACH_MSM_BOARD_TROUT_H
+
+#include <mach/board.h>
+
+#define MSM_SMI_BASE		0x00000000
+#define MSM_SMI_SIZE		0x00800000
+
+#define MSM_EBI_BASE		0x10000000
+#define MSM_EBI_SIZE		0x06e00000
+
+#define MSM_PMEM_GPU0_BASE	0x00000000
+#define MSM_PMEM_GPU0_SIZE	0x00700000
+
+#define MSM_PMEM_MDP_BASE	0x02000000
+#define MSM_PMEM_MDP_SIZE	0x00800000
+
+#define MSM_PMEM_ADSP_BASE      0x02800000
+#define MSM_PMEM_ADSP_SIZE	0x00800000
+
+#define MSM_PMEM_CAMERA_BASE	0x03000000
+#define MSM_PMEM_CAMERA_SIZE	0x00800000
+
+#define MSM_FB_BASE		0x03800000
+#define MSM_FB_SIZE		0x00100000
+
+#define MSM_LINUX_BASE		MSM_EBI_BASE
+#define MSM_LINUX_SIZE		0x06500000
+
+#define MSM_PMEM_GPU1_SIZE	0x800000
+#define MSM_PMEM_GPU1_BASE	MSM_RAM_CONSOLE_BASE - MSM_PMEM_GPU1_SIZE
+
+#define MSM_RAM_CONSOLE_BASE	MSM_EBI_BASE + 0x6d00000
+#define MSM_RAM_CONSOLE_SIZE	128 * SZ_1K
+
+#if (MSM_FB_BASE + MSM_FB_SIZE) >= (MSM_PMEM_GPU1_BASE)
+#error invalid memory map
+#endif
+
+#define DECLARE_MSM_IOMAP
+#include <mach/msm_iomap.h>
+
+#define TROUT_4_BALL_UP_0     1
+#define TROUT_4_BALL_LEFT_0   18
+#define TROUT_4_BALL_DOWN_0   57
+#define TROUT_4_BALL_RIGHT_0  91
+
+#define TROUT_5_BALL_UP_0     94
+#define TROUT_5_BALL_LEFT_0   18
+#define TROUT_5_BALL_DOWN_0   90
+#define TROUT_5_BALL_RIGHT_0  19
+
+#define TROUT_POWER_KEY     20
+
+#define TROUT_4_TP_LS_EN    19
+#define TROUT_5_TP_LS_EN    1
 
 #define TROUT_CPLD_BASE   0xE8100000
 #define TROUT_CPLD_START  0x98000000
 #define TROUT_CPLD_SIZE   SZ_4K
 
+#define TROUT_GPIO_CABLE_IN1		(83)
+#define TROUT_GPIO_CABLE_IN2		(49)
+
+#define TROUT_GPIO_START (128)
+
+#define TROUT_GPIO_INT_MASK0_REG            (0x0c)
+#define TROUT_GPIO_INT_STAT0_REG            (0x0e)
+#define TROUT_GPIO_INT_MASK1_REG            (0x14)
+#define TROUT_GPIO_INT_STAT1_REG            (0x10)
+
+#define TROUT_GPIO_HAPTIC_PWM               (28)
+#define TROUT_GPIO_PS_HOLD                  (25)
+
+#define TROUT_GPIO_MISC2_BASE               (TROUT_GPIO_START + 0x00)
+#define TROUT_GPIO_MISC3_BASE               (TROUT_GPIO_START + 0x08)
+#define TROUT_GPIO_MISC4_BASE               (TROUT_GPIO_START + 0x10)
+#define TROUT_GPIO_MISC5_BASE               (TROUT_GPIO_START + 0x18)
+#define TROUT_GPIO_INT2_BASE                (TROUT_GPIO_START + 0x20)
+#define TROUT_GPIO_MISC1_BASE               (TROUT_GPIO_START + 0x28)
+#define TROUT_GPIO_VIRTUAL_BASE             (TROUT_GPIO_START + 0x30)
+#define TROUT_GPIO_INT5_BASE                (TROUT_GPIO_START + 0x48)
+
+#define TROUT_GPIO_CHARGER_EN               (TROUT_GPIO_MISC2_BASE + 0)
+#define TROUT_GPIO_ISET                     (TROUT_GPIO_MISC2_BASE + 1)
+#define TROUT_GPIO_H2W_DAT_DIR              (TROUT_GPIO_MISC2_BASE + 2)
+#define TROUT_GPIO_H2W_CLK_DIR              (TROUT_GPIO_MISC2_BASE + 3)
+#define TROUT_GPIO_H2W_DAT_GPO              (TROUT_GPIO_MISC2_BASE + 4)
+#define TROUT_GPIO_H2W_CLK_GPO              (TROUT_GPIO_MISC2_BASE + 5)
+#define TROUT_GPIO_H2W_SEL0                 (TROUT_GPIO_MISC2_BASE + 6)
+#define TROUT_GPIO_H2W_SEL1                 (TROUT_GPIO_MISC2_BASE + 7)
+
+#define TROUT_GPIO_SPOTLIGHT_EN             (TROUT_GPIO_MISC3_BASE + 0)
+#define TROUT_GPIO_FLASH_EN                 (TROUT_GPIO_MISC3_BASE + 1)
+#define TROUT_GPIO_I2C_PULL                 (TROUT_GPIO_MISC3_BASE + 2)
+#define TROUT_GPIO_TP_I2C_PULL              (TROUT_GPIO_MISC3_BASE + 3)
+#define TROUT_GPIO_TP_EN                    (TROUT_GPIO_MISC3_BASE + 4)
+#define TROUT_GPIO_JOG_EN                   (TROUT_GPIO_MISC3_BASE + 5)
+#define TROUT_GPIO_UI_LED_EN                (TROUT_GPIO_MISC3_BASE + 6)
+#define TROUT_GPIO_QTKEY_LED_EN             (TROUT_GPIO_MISC3_BASE + 7)
+
+#define TROUT_GPIO_VCM_PWDN                 (TROUT_GPIO_MISC4_BASE + 0)
+#define TROUT_GPIO_USB_H2W_SW               (TROUT_GPIO_MISC4_BASE + 1)
+#define TROUT_GPIO_COMPASS_RST_N            (TROUT_GPIO_MISC4_BASE + 2)
+#define TROUT_GPIO_HAPTIC_EN_UP             (TROUT_GPIO_MISC4_BASE + 3)
+#define TROUT_GPIO_HAPTIC_EN_MAIN           (TROUT_GPIO_MISC4_BASE + 4)
+#define TROUT_GPIO_USB_PHY_RST_N            (TROUT_GPIO_MISC4_BASE + 5)
+#define TROUT_GPIO_WIFI_PA_RESETX           (TROUT_GPIO_MISC4_BASE + 6)
+#define TROUT_GPIO_WIFI_EN                  (TROUT_GPIO_MISC4_BASE + 7)
+
+#define TROUT_GPIO_BT_32K_EN                (TROUT_GPIO_MISC5_BASE + 0)
+#define TROUT_GPIO_MAC_32K_EN               (TROUT_GPIO_MISC5_BASE + 1)
+#define TROUT_GPIO_MDDI_32K_EN              (TROUT_GPIO_MISC5_BASE + 2)
+#define TROUT_GPIO_COMPASS_32K_EN           (TROUT_GPIO_MISC5_BASE + 3)
+
+#define TROUT_GPIO_NAVI_ACT_N               (TROUT_GPIO_INT2_BASE + 0)
+#define TROUT_GPIO_COMPASS_IRQ              (TROUT_GPIO_INT2_BASE + 1)
+#define TROUT_GPIO_SLIDING_DET              (TROUT_GPIO_INT2_BASE + 2)
+#define TROUT_GPIO_AUD_HSMIC_DET_N          (TROUT_GPIO_INT2_BASE + 3)
+#define TROUT_GPIO_SD_DOOR_N                (TROUT_GPIO_INT2_BASE + 4)
+#define TROUT_GPIO_CAM_BTN_STEP1_N          (TROUT_GPIO_INT2_BASE + 5)
+#define TROUT_GPIO_CAM_BTN_STEP2_N          (TROUT_GPIO_INT2_BASE + 6)
+#define TROUT_GPIO_TP_ATT_N                 (TROUT_GPIO_INT2_BASE + 7)
+#define TROUT_GPIO_BANK0_FIRST_INT_SOURCE   (TROUT_GPIO_NAVI_ACT_N)
+#define TROUT_GPIO_BANK0_LAST_INT_SOURCE    (TROUT_GPIO_TP_ATT_N)
+
+#define TROUT_GPIO_H2W_DAT_GPI              (TROUT_GPIO_MISC1_BASE + 0)
+#define TROUT_GPIO_H2W_CLK_GPI              (TROUT_GPIO_MISC1_BASE + 1)
+#define TROUT_GPIO_CPLD128_VER_0            (TROUT_GPIO_MISC1_BASE + 4)
+#define TROUT_GPIO_CPLD128_VER_1            (TROUT_GPIO_MISC1_BASE + 5)
+#define TROUT_GPIO_CPLD128_VER_2            (TROUT_GPIO_MISC1_BASE + 6)
+#define TROUT_GPIO_CPLD128_VER_3            (TROUT_GPIO_MISC1_BASE + 7)
+
+#define TROUT_GPIO_SDMC_CD_N                (TROUT_GPIO_VIRTUAL_BASE + 0)
+#define TROUT_GPIO_END                      (TROUT_GPIO_SDMC_CD_N)
+#define TROUT_GPIO_BANK1_FIRST_INT_SOURCE   (TROUT_GPIO_SDMC_CD_N)
+#define TROUT_GPIO_BANK1_LAST_INT_SOURCE    (TROUT_GPIO_SDMC_CD_N)
+
+#define TROUT_GPIO_VIRTUAL_TO_REAL_OFFSET \
+	(TROUT_GPIO_INT5_BASE - TROUT_GPIO_VIRTUAL_BASE)
+
+#define TROUT_INT_START (NR_MSM_IRQS + NR_GPIO_IRQS)
+#define TROUT_INT_BANK0_COUNT (8)
+#define TROUT_INT_BANK1_START (TROUT_INT_START + TROUT_INT_BANK0_COUNT)
+#define TROUT_INT_BANK1_COUNT (1)
+#define TROUT_INT_END (TROUT_INT_START + TROUT_INT_BANK0_COUNT + \
+			TROUT_INT_BANK1_COUNT - 1)
+#define TROUT_GPIO_TO_INT(n) (((n) <= TROUT_GPIO_BANK0_LAST_INT_SOURCE) ? \
+	(TROUT_INT_START - TROUT_GPIO_BANK0_FIRST_INT_SOURCE + (n)) : \
+	(TROUT_INT_BANK1_START - TROUT_GPIO_BANK1_FIRST_INT_SOURCE + (n)))
+
+#define TROUT_INT_TO_BANK(n) ((n - TROUT_INT_START) / TROUT_INT_BANK0_COUNT)
+#define TROUT_INT_TO_MASK(n) (1U << ((n - TROUT_INT_START) & 7))
+#define TROUT_BANK_TO_MASK_REG(bank) \
+	(bank ? TROUT_GPIO_INT_MASK1_REG : TROUT_GPIO_INT_MASK0_REG)
+#define TROUT_BANK_TO_STAT_REG(bank) \
+	(bank ? TROUT_GPIO_INT_STAT1_REG : TROUT_GPIO_INT_STAT0_REG)
+
+#endif /* GUARD */
-- 
1.6.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 3/4] arm: msm: trout: add trout specific gpio interrupts
  2010-03-30 23:11   ` Daniel Walker
@ 2010-03-30 23:11     ` Daniel Walker
  -1 siblings, 0 replies; 22+ messages in thread
From: Daniel Walker @ 2010-03-30 23:11 UTC (permalink / raw)
  To: linux-arm-kernel; +Cc: linux-arm-msm, Daniel Walker

From: Daniel Walker <c_dwalke@quicinc.com>

This adds the interrupt layer onto the initial trout gpio
changes.

There changes were adapted from the Google driver which lists
Arve Hjønnevåg <arve@android.com> as the author.

Signed-off-by: Daniel Walker <c_dwalke@quicinc.com>
---
 arch/arm/mach-msm/board-trout-gpio.c |  114 ++++++++++++++++++++++++++++++++++
 1 files changed, 114 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-msm/board-trout-gpio.c b/arch/arm/mach-msm/board-trout-gpio.c
index 6e6bc76..99965b2 100644
--- a/arch/arm/mach-msm/board-trout-gpio.c
+++ b/arch/arm/mach-msm/board-trout-gpio.c
@@ -19,6 +19,15 @@
 
 #include "board-trout.h"
 
+static uint8_t trout_int_mask[2] = {
+	[0] = 0xff, /* mask all interrupts */
+	[1] = 0xff,
+};
+static uint8_t trout_sleep_int_mask[] = {
+	[0] = 0xff,
+	[1] = 0xff,
+};
+
 struct msm_gpio_chip {
 	struct gpio_chip	chip;
 	void __iomem		*reg;	/* Base of register bank */
@@ -95,16 +104,121 @@ static struct msm_gpio_chip msm_gpio_banks[] = {
         TROUT_GPIO_BANK("VIRTUAL", 0x12, TROUT_GPIO_VIRTUAL_BASE, 0),
 };
 
+static void trout_gpio_irq_ack(unsigned int irq)
+{
+	int bank = TROUT_INT_TO_BANK(irq);
+	uint8_t mask = TROUT_INT_TO_MASK(irq);
+	int reg = TROUT_BANK_TO_STAT_REG(bank);
+	/*printk(KERN_INFO "trout_gpio_irq_ack irq %d\n", irq);*/
+	writeb(mask, TROUT_CPLD_BASE + reg);
+}
+
+static void trout_gpio_irq_mask(unsigned int irq)
+{
+	unsigned long flags;
+	uint8_t reg_val;
+	int bank = TROUT_INT_TO_BANK(irq);
+	uint8_t mask = TROUT_INT_TO_MASK(irq);
+	int reg = TROUT_BANK_TO_MASK_REG(bank);
+
+	local_irq_save(flags);
+	reg_val = trout_int_mask[bank] |= mask;
+	/*printk(KERN_INFO "trout_gpio_irq_mask irq %d => %d:%02x\n",
+	       irq, bank, reg_val);*/
+	writeb(reg_val, TROUT_CPLD_BASE + reg);
+	local_irq_restore(flags);
+}
+
+static void trout_gpio_irq_unmask(unsigned int irq)
+{
+	unsigned long flags;
+	uint8_t reg_val;
+	int bank = TROUT_INT_TO_BANK(irq);
+	uint8_t mask = TROUT_INT_TO_MASK(irq);
+	int reg = TROUT_BANK_TO_MASK_REG(bank);
+
+	local_irq_save(flags);
+	reg_val = trout_int_mask[bank] &= ~mask;
+	/*printk(KERN_INFO "trout_gpio_irq_unmask irq %d => %d:%02x\n",
+	       irq, bank, reg_val);*/
+	writeb(reg_val, TROUT_CPLD_BASE + reg);
+	local_irq_restore(flags);
+}
+
+int trout_gpio_irq_set_wake(unsigned int irq, unsigned int on)
+{
+	unsigned long flags;
+	int bank = TROUT_INT_TO_BANK(irq);
+	uint8_t mask = TROUT_INT_TO_MASK(irq);
+
+	local_irq_save(flags);
+	if(on)
+		trout_sleep_int_mask[bank] &= ~mask;
+	else
+		trout_sleep_int_mask[bank] |= mask;
+	local_irq_restore(flags);
+	return 0;
+}
+
+static void trout_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	int j, m;
+	unsigned v;
+	int bank;
+	int stat_reg;
+	int int_base = TROUT_INT_START;
+	uint8_t int_mask;
+
+	for (bank = 0; bank < 2; bank++) {
+		stat_reg = TROUT_BANK_TO_STAT_REG(bank);
+		v = readb(TROUT_CPLD_BASE + stat_reg);
+		int_mask = trout_int_mask[bank];
+		if (v & int_mask) {
+			writeb(v & int_mask, TROUT_CPLD_BASE + stat_reg);
+			printk(KERN_ERR "trout_gpio_irq_handler: got masked "
+			       "interrupt: %d:%02x\n", bank, v & int_mask);
+		}
+		v &= ~int_mask;
+		while (v) {
+			m = v & -v;
+			j = fls(m) - 1;
+			/*printk(KERN_INFO "msm_gpio_irq_handler %d:%02x %02x b"
+			       "it %d irq %d\n", bank, v, m, j, int_base + j);*/
+			v &= ~m;
+			generic_handle_irq(int_base + j);
+		}
+		int_base += TROUT_INT_BANK0_COUNT;
+	}
+	desc->chip->ack(irq);
+}
+
+static struct irq_chip trout_gpio_irq_chip = {
+	.name      = "troutgpio",
+	.ack       = trout_gpio_irq_ack,
+	.mask      = trout_gpio_irq_mask,
+	.unmask    = trout_gpio_irq_unmask,
+	.set_wake  = trout_gpio_irq_set_wake,
+};
+
 /*
  * Called from the processor-specific init to enable GPIO pin support.
  */
 int __init trout_init_gpio(void)
 {
         int i;
+	for(i = TROUT_INT_START; i <= TROUT_INT_END; i++) {
+		set_irq_chip(i, &trout_gpio_irq_chip);
+		set_irq_handler(i, handle_edge_irq);
+		set_irq_flags(i, IRQF_VALID);
+	}
 
         for (i = 0; i < ARRAY_SIZE(msm_gpio_banks); i++)
                 gpiochip_add(&msm_gpio_banks[i].chip);
 
+	set_irq_type(MSM_GPIO_TO_INT(17), IRQF_TRIGGER_HIGH);
+	set_irq_chained_handler(MSM_GPIO_TO_INT(17), trout_gpio_irq_handler);
+	set_irq_wake(MSM_GPIO_TO_INT(17), 1);
+
 	return 0;
 }
 
-- 
1.6.2.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 3/4] arm: msm: trout: add trout specific gpio interrupts
@ 2010-03-30 23:11     ` Daniel Walker
  0 siblings, 0 replies; 22+ messages in thread
From: Daniel Walker @ 2010-03-30 23:11 UTC (permalink / raw)
  To: linux-arm-kernel

From: Daniel Walker <c_dwalke@quicinc.com>

This adds the interrupt layer onto the initial trout gpio
changes.

There changes were adapted from the Google driver which lists
Arve Hj?nnev?g <arve@android.com> as the author.

Signed-off-by: Daniel Walker <c_dwalke@quicinc.com>
---
 arch/arm/mach-msm/board-trout-gpio.c |  114 ++++++++++++++++++++++++++++++++++
 1 files changed, 114 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-msm/board-trout-gpio.c b/arch/arm/mach-msm/board-trout-gpio.c
index 6e6bc76..99965b2 100644
--- a/arch/arm/mach-msm/board-trout-gpio.c
+++ b/arch/arm/mach-msm/board-trout-gpio.c
@@ -19,6 +19,15 @@
 
 #include "board-trout.h"
 
+static uint8_t trout_int_mask[2] = {
+	[0] = 0xff, /* mask all interrupts */
+	[1] = 0xff,
+};
+static uint8_t trout_sleep_int_mask[] = {
+	[0] = 0xff,
+	[1] = 0xff,
+};
+
 struct msm_gpio_chip {
 	struct gpio_chip	chip;
 	void __iomem		*reg;	/* Base of register bank */
@@ -95,16 +104,121 @@ static struct msm_gpio_chip msm_gpio_banks[] = {
         TROUT_GPIO_BANK("VIRTUAL", 0x12, TROUT_GPIO_VIRTUAL_BASE, 0),
 };
 
+static void trout_gpio_irq_ack(unsigned int irq)
+{
+	int bank = TROUT_INT_TO_BANK(irq);
+	uint8_t mask = TROUT_INT_TO_MASK(irq);
+	int reg = TROUT_BANK_TO_STAT_REG(bank);
+	/*printk(KERN_INFO "trout_gpio_irq_ack irq %d\n", irq);*/
+	writeb(mask, TROUT_CPLD_BASE + reg);
+}
+
+static void trout_gpio_irq_mask(unsigned int irq)
+{
+	unsigned long flags;
+	uint8_t reg_val;
+	int bank = TROUT_INT_TO_BANK(irq);
+	uint8_t mask = TROUT_INT_TO_MASK(irq);
+	int reg = TROUT_BANK_TO_MASK_REG(bank);
+
+	local_irq_save(flags);
+	reg_val = trout_int_mask[bank] |= mask;
+	/*printk(KERN_INFO "trout_gpio_irq_mask irq %d => %d:%02x\n",
+	       irq, bank, reg_val);*/
+	writeb(reg_val, TROUT_CPLD_BASE + reg);
+	local_irq_restore(flags);
+}
+
+static void trout_gpio_irq_unmask(unsigned int irq)
+{
+	unsigned long flags;
+	uint8_t reg_val;
+	int bank = TROUT_INT_TO_BANK(irq);
+	uint8_t mask = TROUT_INT_TO_MASK(irq);
+	int reg = TROUT_BANK_TO_MASK_REG(bank);
+
+	local_irq_save(flags);
+	reg_val = trout_int_mask[bank] &= ~mask;
+	/*printk(KERN_INFO "trout_gpio_irq_unmask irq %d => %d:%02x\n",
+	       irq, bank, reg_val);*/
+	writeb(reg_val, TROUT_CPLD_BASE + reg);
+	local_irq_restore(flags);
+}
+
+int trout_gpio_irq_set_wake(unsigned int irq, unsigned int on)
+{
+	unsigned long flags;
+	int bank = TROUT_INT_TO_BANK(irq);
+	uint8_t mask = TROUT_INT_TO_MASK(irq);
+
+	local_irq_save(flags);
+	if(on)
+		trout_sleep_int_mask[bank] &= ~mask;
+	else
+		trout_sleep_int_mask[bank] |= mask;
+	local_irq_restore(flags);
+	return 0;
+}
+
+static void trout_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	int j, m;
+	unsigned v;
+	int bank;
+	int stat_reg;
+	int int_base = TROUT_INT_START;
+	uint8_t int_mask;
+
+	for (bank = 0; bank < 2; bank++) {
+		stat_reg = TROUT_BANK_TO_STAT_REG(bank);
+		v = readb(TROUT_CPLD_BASE + stat_reg);
+		int_mask = trout_int_mask[bank];
+		if (v & int_mask) {
+			writeb(v & int_mask, TROUT_CPLD_BASE + stat_reg);
+			printk(KERN_ERR "trout_gpio_irq_handler: got masked "
+			       "interrupt: %d:%02x\n", bank, v & int_mask);
+		}
+		v &= ~int_mask;
+		while (v) {
+			m = v & -v;
+			j = fls(m) - 1;
+			/*printk(KERN_INFO "msm_gpio_irq_handler %d:%02x %02x b"
+			       "it %d irq %d\n", bank, v, m, j, int_base + j);*/
+			v &= ~m;
+			generic_handle_irq(int_base + j);
+		}
+		int_base += TROUT_INT_BANK0_COUNT;
+	}
+	desc->chip->ack(irq);
+}
+
+static struct irq_chip trout_gpio_irq_chip = {
+	.name      = "troutgpio",
+	.ack       = trout_gpio_irq_ack,
+	.mask      = trout_gpio_irq_mask,
+	.unmask    = trout_gpio_irq_unmask,
+	.set_wake  = trout_gpio_irq_set_wake,
+};
+
 /*
  * Called from the processor-specific init to enable GPIO pin support.
  */
 int __init trout_init_gpio(void)
 {
         int i;
+	for(i = TROUT_INT_START; i <= TROUT_INT_END; i++) {
+		set_irq_chip(i, &trout_gpio_irq_chip);
+		set_irq_handler(i, handle_edge_irq);
+		set_irq_flags(i, IRQF_VALID);
+	}
 
         for (i = 0; i < ARRAY_SIZE(msm_gpio_banks); i++)
                 gpiochip_add(&msm_gpio_banks[i].chip);
 
+	set_irq_type(MSM_GPIO_TO_INT(17), IRQF_TRIGGER_HIGH);
+	set_irq_chained_handler(MSM_GPIO_TO_INT(17), trout_gpio_irq_handler);
+	set_irq_wake(MSM_GPIO_TO_INT(17), 1);
+
 	return 0;
 }
 
-- 
1.6.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 4/4] arm: msm: trout add mmc support
  2010-03-30 23:11     ` Daniel Walker
@ 2010-03-30 23:11       ` Daniel Walker
  -1 siblings, 0 replies; 22+ messages in thread
From: Daniel Walker @ 2010-03-30 23:11 UTC (permalink / raw)
  To: linux-arm-kernel; +Cc: linux-arm-msm, Daniel Walker

This adds the platform data for MMC on trout.

Signed-off-by: Daniel Walker <dwalker@codeaurora.org>
---
 arch/arm/mach-msm/Makefile          |    2 +-
 arch/arm/mach-msm/board-trout-mmc.c |  189 +++++++++++++++++++++++++++++++++++
 arch/arm/mach-msm/board-trout.c     |   11 ++
 3 files changed, 201 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/mach-msm/board-trout-mmc.c

diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index fb9ab2d..cde59dc 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -9,5 +9,5 @@ obj-y += gpio.o
 obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o
 obj-$(CONFIG_MSM_SMD) += last_radio_log.o
 
-obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o
+obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o board-trout-mmc.o
 obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o
diff --git a/arch/arm/mach-msm/board-trout-mmc.c b/arch/arm/mach-msm/board-trout-mmc.c
new file mode 100644
index 0000000..7a773f8
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout-mmc.c
@@ -0,0 +1,189 @@
+/* linux/arch/arm/mach-msm/board-trout-mmc.c
+** Author: Brian Swetland <swetland@google.com>
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/err.h>
+#include <linux/debugfs.h>
+
+#include <asm/gpio.h>
+#include <asm/io.h>
+
+#include <mach/vreg.h>
+
+#include <mach/mmc.h>
+
+#include "devices.h"
+
+#include "board-trout.h"
+
+#include "proc_comm.h"
+
+#define DEBUG_SDSLOT_VDD 1
+
+extern int msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat,
+			unsigned int stat_irq, unsigned long stat_irq_flags);
+
+/* ---- COMMON ---- */
+static void config_gpio_table(uint32_t *table, int len)
+{
+	int n;
+	unsigned id;
+	for(n = 0; n < len; n++) {
+		id = table[n];
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+	}
+}
+
+/* ---- SDCARD ---- */
+
+static uint32_t sdcard_on_gpio_table[] = {
+	PCOM_GPIO_CFG(62, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */
+	PCOM_GPIO_CFG(63, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */
+	PCOM_GPIO_CFG(64, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT3 */
+	PCOM_GPIO_CFG(65, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT2 */
+	PCOM_GPIO_CFG(66, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(67, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */
+};
+
+static uint32_t sdcard_off_gpio_table[] = {
+	PCOM_GPIO_CFG(62, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */
+	PCOM_GPIO_CFG(63, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */
+	PCOM_GPIO_CFG(64, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */
+	PCOM_GPIO_CFG(65, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */
+	PCOM_GPIO_CFG(66, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(67, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */
+};
+
+static uint opt_disable_sdcard;
+
+static int __init trout_disablesdcard_setup(char *str)
+{
+	int cal = simple_strtol(str, NULL, 0);
+	
+	opt_disable_sdcard = cal;
+	return 1;
+}
+
+__setup("board_trout.disable_sdcard=", trout_disablesdcard_setup);
+
+static struct vreg *vreg_sdslot;	/* SD slot power */
+
+struct mmc_vdd_xlat {
+	int mask;
+	int level;
+};
+
+static struct mmc_vdd_xlat mmc_vdd_table[] = {
+	{ MMC_VDD_165_195,	1800 },
+	{ MMC_VDD_20_21,	2050 },
+	{ MMC_VDD_21_22,	2150 },
+	{ MMC_VDD_22_23,	2250 },
+	{ MMC_VDD_23_24,	2350 },
+	{ MMC_VDD_24_25,	2450 },
+	{ MMC_VDD_25_26,	2550 },
+	{ MMC_VDD_26_27,	2650 },
+	{ MMC_VDD_27_28,	2750 },
+	{ MMC_VDD_28_29,	2850 },
+	{ MMC_VDD_29_30,	2950 },
+};
+
+static unsigned int sdslot_vdd = 0xffffffff;
+static unsigned int sdslot_vreg_enabled;
+
+static uint32_t trout_sdslot_switchvdd(struct device *dev, unsigned int vdd)
+{
+	int i, rc;
+
+	BUG_ON(!vreg_sdslot);
+
+	if (vdd == sdslot_vdd)
+		return 0;
+
+	sdslot_vdd = vdd;
+
+	if (vdd == 0) {
+#if DEBUG_SDSLOT_VDD
+		printk("%s: Disabling SD slot power\n", __func__);
+#endif
+		config_gpio_table(sdcard_off_gpio_table,
+				  ARRAY_SIZE(sdcard_off_gpio_table));
+		vreg_disable(vreg_sdslot);
+		sdslot_vreg_enabled = 0;
+		return 0;
+	}
+
+	if (!sdslot_vreg_enabled) {
+		rc = vreg_enable(vreg_sdslot);
+		if (rc) {
+			printk(KERN_ERR "%s: Error enabling vreg (%d)\n",
+			       __func__, rc);
+		}
+		config_gpio_table(sdcard_on_gpio_table,
+				  ARRAY_SIZE(sdcard_on_gpio_table));
+		sdslot_vreg_enabled = 1;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(mmc_vdd_table); i++) {
+		if (mmc_vdd_table[i].mask == (1 << vdd)) {
+#if DEBUG_SDSLOT_VDD
+			printk("%s: Setting level to %u\n",
+			        __func__, mmc_vdd_table[i].level);
+#endif
+			rc = vreg_set_level(vreg_sdslot,
+					    mmc_vdd_table[i].level);
+			if (rc) {
+				printk(KERN_ERR
+				       "%s: Error setting vreg level (%d)\n",
+				       __func__, rc);
+			}
+			return 0;
+		}
+	}
+
+	printk(KERN_ERR "%s: Invalid VDD %d specified\n", __func__, vdd);
+	return 0;
+}
+
+static unsigned int trout_sdslot_status(struct device *dev)
+{
+	unsigned int status;
+
+	status = (unsigned int) gpio_get_value(TROUT_GPIO_SDMC_CD_N);
+	return (!status);
+}
+
+#define TROUT_MMC_VDD	MMC_VDD_165_195 | MMC_VDD_20_21 | MMC_VDD_21_22 \
+			| MMC_VDD_22_23 | MMC_VDD_23_24 | MMC_VDD_24_25 \
+			| MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 \
+			| MMC_VDD_28_29 | MMC_VDD_29_30
+
+static struct mmc_platform_data trout_sdslot_data = {
+	.ocr_mask	= TROUT_MMC_VDD,
+	.status		= trout_sdslot_status,
+	.translate_vdd	= trout_sdslot_switchvdd,
+};
+
+int __init trout_init_mmc(unsigned int sys_rev)
+{
+	sdslot_vreg_enabled = 0;
+
+	vreg_sdslot = vreg_get(0, "gp6");
+	if (IS_ERR(vreg_sdslot))
+		return PTR_ERR(vreg_sdslot);
+
+	set_irq_wake(TROUT_GPIO_TO_INT(TROUT_GPIO_SDMC_CD_N), 1);
+
+	if (!opt_disable_sdcard)
+		msm_add_sdcc(2, &trout_sdslot_data,
+			     TROUT_GPIO_TO_INT(TROUT_GPIO_SDMC_CD_N), 0);
+	else
+		printk(KERN_INFO "trout: SD-Card interface disabled\n");
+	return 0;
+}
+
diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c
index 9793ff4..49d550e 100644
--- a/arch/arm/mach-msm/board-trout.c
+++ b/arch/arm/mach-msm/board-trout.c
@@ -30,6 +30,8 @@
 #include "devices.h"
 #include "board-trout.h"
 
+extern int trout_init_mmc(unsigned int);
+
 static struct platform_device *devices[] __initdata = {
 	&msm_device_uart3,
 	&msm_device_smd,
@@ -56,7 +58,16 @@ static void __init trout_fixup(struct machine_desc *desc, struct tag *tags,
 
 static void __init trout_init(void)
 {
+	int rc;
+
 	platform_add_devices(devices, ARRAY_SIZE(devices));
+
+#ifdef CONFIG_MMC
+        rc = trout_init_mmc(system_rev);
+        if (rc)
+                printk(KERN_CRIT "%s: MMC init failure (%d)\n", __func__, rc);
+#endif
+
 }
 
 static struct map_desc trout_io_desc[] __initdata = {
-- 
1.6.2.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 4/4] arm: msm: trout add mmc support
@ 2010-03-30 23:11       ` Daniel Walker
  0 siblings, 0 replies; 22+ messages in thread
From: Daniel Walker @ 2010-03-30 23:11 UTC (permalink / raw)
  To: linux-arm-kernel

This adds the platform data for MMC on trout.

Signed-off-by: Daniel Walker <dwalker@codeaurora.org>
---
 arch/arm/mach-msm/Makefile          |    2 +-
 arch/arm/mach-msm/board-trout-mmc.c |  189 +++++++++++++++++++++++++++++++++++
 arch/arm/mach-msm/board-trout.c     |   11 ++
 3 files changed, 201 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/mach-msm/board-trout-mmc.c

diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index fb9ab2d..cde59dc 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -9,5 +9,5 @@ obj-y += gpio.o
 obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o
 obj-$(CONFIG_MSM_SMD) += last_radio_log.o
 
-obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o
+obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o board-trout-mmc.o
 obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o
diff --git a/arch/arm/mach-msm/board-trout-mmc.c b/arch/arm/mach-msm/board-trout-mmc.c
new file mode 100644
index 0000000..7a773f8
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout-mmc.c
@@ -0,0 +1,189 @@
+/* linux/arch/arm/mach-msm/board-trout-mmc.c
+** Author: Brian Swetland <swetland@google.com>
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/err.h>
+#include <linux/debugfs.h>
+
+#include <asm/gpio.h>
+#include <asm/io.h>
+
+#include <mach/vreg.h>
+
+#include <mach/mmc.h>
+
+#include "devices.h"
+
+#include "board-trout.h"
+
+#include "proc_comm.h"
+
+#define DEBUG_SDSLOT_VDD 1
+
+extern int msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat,
+			unsigned int stat_irq, unsigned long stat_irq_flags);
+
+/* ---- COMMON ---- */
+static void config_gpio_table(uint32_t *table, int len)
+{
+	int n;
+	unsigned id;
+	for(n = 0; n < len; n++) {
+		id = table[n];
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+	}
+}
+
+/* ---- SDCARD ---- */
+
+static uint32_t sdcard_on_gpio_table[] = {
+	PCOM_GPIO_CFG(62, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */
+	PCOM_GPIO_CFG(63, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */
+	PCOM_GPIO_CFG(64, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT3 */
+	PCOM_GPIO_CFG(65, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT2 */
+	PCOM_GPIO_CFG(66, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(67, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */
+};
+
+static uint32_t sdcard_off_gpio_table[] = {
+	PCOM_GPIO_CFG(62, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */
+	PCOM_GPIO_CFG(63, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */
+	PCOM_GPIO_CFG(64, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */
+	PCOM_GPIO_CFG(65, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */
+	PCOM_GPIO_CFG(66, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(67, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */
+};
+
+static uint opt_disable_sdcard;
+
+static int __init trout_disablesdcard_setup(char *str)
+{
+	int cal = simple_strtol(str, NULL, 0);
+	
+	opt_disable_sdcard = cal;
+	return 1;
+}
+
+__setup("board_trout.disable_sdcard=", trout_disablesdcard_setup);
+
+static struct vreg *vreg_sdslot;	/* SD slot power */
+
+struct mmc_vdd_xlat {
+	int mask;
+	int level;
+};
+
+static struct mmc_vdd_xlat mmc_vdd_table[] = {
+	{ MMC_VDD_165_195,	1800 },
+	{ MMC_VDD_20_21,	2050 },
+	{ MMC_VDD_21_22,	2150 },
+	{ MMC_VDD_22_23,	2250 },
+	{ MMC_VDD_23_24,	2350 },
+	{ MMC_VDD_24_25,	2450 },
+	{ MMC_VDD_25_26,	2550 },
+	{ MMC_VDD_26_27,	2650 },
+	{ MMC_VDD_27_28,	2750 },
+	{ MMC_VDD_28_29,	2850 },
+	{ MMC_VDD_29_30,	2950 },
+};
+
+static unsigned int sdslot_vdd = 0xffffffff;
+static unsigned int sdslot_vreg_enabled;
+
+static uint32_t trout_sdslot_switchvdd(struct device *dev, unsigned int vdd)
+{
+	int i, rc;
+
+	BUG_ON(!vreg_sdslot);
+
+	if (vdd == sdslot_vdd)
+		return 0;
+
+	sdslot_vdd = vdd;
+
+	if (vdd == 0) {
+#if DEBUG_SDSLOT_VDD
+		printk("%s: Disabling SD slot power\n", __func__);
+#endif
+		config_gpio_table(sdcard_off_gpio_table,
+				  ARRAY_SIZE(sdcard_off_gpio_table));
+		vreg_disable(vreg_sdslot);
+		sdslot_vreg_enabled = 0;
+		return 0;
+	}
+
+	if (!sdslot_vreg_enabled) {
+		rc = vreg_enable(vreg_sdslot);
+		if (rc) {
+			printk(KERN_ERR "%s: Error enabling vreg (%d)\n",
+			       __func__, rc);
+		}
+		config_gpio_table(sdcard_on_gpio_table,
+				  ARRAY_SIZE(sdcard_on_gpio_table));
+		sdslot_vreg_enabled = 1;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(mmc_vdd_table); i++) {
+		if (mmc_vdd_table[i].mask == (1 << vdd)) {
+#if DEBUG_SDSLOT_VDD
+			printk("%s: Setting level to %u\n",
+			        __func__, mmc_vdd_table[i].level);
+#endif
+			rc = vreg_set_level(vreg_sdslot,
+					    mmc_vdd_table[i].level);
+			if (rc) {
+				printk(KERN_ERR
+				       "%s: Error setting vreg level (%d)\n",
+				       __func__, rc);
+			}
+			return 0;
+		}
+	}
+
+	printk(KERN_ERR "%s: Invalid VDD %d specified\n", __func__, vdd);
+	return 0;
+}
+
+static unsigned int trout_sdslot_status(struct device *dev)
+{
+	unsigned int status;
+
+	status = (unsigned int) gpio_get_value(TROUT_GPIO_SDMC_CD_N);
+	return (!status);
+}
+
+#define TROUT_MMC_VDD	MMC_VDD_165_195 | MMC_VDD_20_21 | MMC_VDD_21_22 \
+			| MMC_VDD_22_23 | MMC_VDD_23_24 | MMC_VDD_24_25 \
+			| MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 \
+			| MMC_VDD_28_29 | MMC_VDD_29_30
+
+static struct mmc_platform_data trout_sdslot_data = {
+	.ocr_mask	= TROUT_MMC_VDD,
+	.status		= trout_sdslot_status,
+	.translate_vdd	= trout_sdslot_switchvdd,
+};
+
+int __init trout_init_mmc(unsigned int sys_rev)
+{
+	sdslot_vreg_enabled = 0;
+
+	vreg_sdslot = vreg_get(0, "gp6");
+	if (IS_ERR(vreg_sdslot))
+		return PTR_ERR(vreg_sdslot);
+
+	set_irq_wake(TROUT_GPIO_TO_INT(TROUT_GPIO_SDMC_CD_N), 1);
+
+	if (!opt_disable_sdcard)
+		msm_add_sdcc(2, &trout_sdslot_data,
+			     TROUT_GPIO_TO_INT(TROUT_GPIO_SDMC_CD_N), 0);
+	else
+		printk(KERN_INFO "trout: SD-Card interface disabled\n");
+	return 0;
+}
+
diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c
index 9793ff4..49d550e 100644
--- a/arch/arm/mach-msm/board-trout.c
+++ b/arch/arm/mach-msm/board-trout.c
@@ -30,6 +30,8 @@
 #include "devices.h"
 #include "board-trout.h"
 
+extern int trout_init_mmc(unsigned int);
+
 static struct platform_device *devices[] __initdata = {
 	&msm_device_uart3,
 	&msm_device_smd,
@@ -56,7 +58,16 @@ static void __init trout_fixup(struct machine_desc *desc, struct tag *tags,
 
 static void __init trout_init(void)
 {
+	int rc;
+
 	platform_add_devices(devices, ARRAY_SIZE(devices));
+
+#ifdef CONFIG_MMC
+        rc = trout_init_mmc(system_rev);
+        if (rc)
+                printk(KERN_CRIT "%s: MMC init failure (%d)\n", __func__, rc);
+#endif
+
 }
 
 static struct map_desc trout_io_desc[] __initdata = {
-- 
1.6.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* RE: [PATCH 1/4] arm: msm: gpio support
  2010-03-30 23:11 ` Daniel Walker
@ 2010-03-30 23:58   ` H Hartley Sweeten
  -1 siblings, 0 replies; 22+ messages in thread
From: H Hartley Sweeten @ 2010-03-30 23:58 UTC (permalink / raw)
  To: Daniel Walker, linux-arm-kernel; +Cc: linux-arm-msm, Daniel Walker

On Tuesday, March 30, 2010 4:12 PM, Daniel Walker wrote:
> From: Daniel Walker <c_dwalke@quicinc.com>
>
> This adds basic gpio support in MSM using gpiolib, as well as gpio
> interrupt support.
>
> Signed-off-by: Daniel Walker <c_dwalke@quicinc.com>
> ---
>  arch/arm/Kconfig                      |    1 +
>  arch/arm/mach-msm/Makefile            |    1 +
>  arch/arm/mach-msm/gpio.c              |  428 +++++++++++++++++++++++++++++++++
>  arch/arm/mach-msm/gpio_hw.h           |  187 ++++++++++++++
>  arch/arm/mach-msm/include/mach/gpio.h |   43 ++++
>  5 files changed, 660 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/mach-msm/gpio.c
>  create mode 100644 arch/arm/mach-msm/gpio_hw.h
>  create mode 100644 arch/arm/mach-msm/include/mach/gpio.h
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index cadfe2e..5e29092 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -601,6 +601,7 @@ config ARCH_MSM
>       select CPU_V6
>       select GENERIC_TIME
>       select GENERIC_CLOCKEVENTS
> +     select ARCH_REQUIRE_GPIOLIB
>       help
>         Support for Qualcomm MSM7K based systems.  This runs on the ARM11
>         apps processor of the MSM7K and depends on a shared memory
> diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
> index 147339c..47d47cb 100644
> --- a/arch/arm/mach-msm/Makefile
> +++ b/arch/arm/mach-msm/Makefile
> @@ -4,6 +4,7 @@ obj-y += proc_comm.o
>  obj-y += vreg.o
>  obj-y += acpuclock-arm11.o
>  obj-y += clock.o clock-7x01a.o
> +obj-y += gpio.o
>
>  obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o
>  obj-$(CONFIG_MSM_SMD) += last_radio_log.o
> diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c
> new file mode 100644
> index 0000000..5b95885
> --- /dev/null
> +++ b/arch/arm/mach-msm/gpio.c
> @@ -0,0 +1,428 @@
> +/* linux/arch/arm/mach-msm/gpio.c
> + *
> + * Copyright (C) 2007 Google, Inc.
> + * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +
> +#include <asm/io.h>

#include <linux/io.h>

> +#include <asm/irq.h>

This one is not needed.

> +#include <linux/irq.h>

This includes the <asm/irq.h> for you.

> +#include <linux/module.h>
> +#include <linux/gpio.h>
> +#include "gpio_hw.h"
> +
> +#include "smd_private.h"
> +
> +static int msm_gpio_debug_mask;
> +module_param_named(debug_mask, msm_gpio_debug_mask, int,
> +                S_IRUGO | S_IWUSR | S_IWGRP);
> +
> +#define MSM_GPIO_BROKEN_INT_CLEAR 1
> +
> +/* private gpio_configure flags */
> +#define MSM_GPIOF_ENABLE_INTERRUPT      0x10000000
> +#define MSM_GPIOF_DISABLE_INTERRUPT     0x20000000
> +#define MSM_GPIOF_ENABLE_WAKE           0x40000000
> +#define MSM_GPIOF_DISABLE_WAKE          0x80000000
> +
> +static int gpio_chip_to_irq(struct gpio_chip *chip, unsigned offset);
> +static void gpio_chip_set(struct gpio_chip *chip, unsigned offset, int value);
> +static int gpio_chip_get(struct gpio_chip *chip, unsigned offset);
> +static int gpio_chip_direction_input(struct gpio_chip *chip, unsigned offset);
> +static int gpio_chip_direction_output(struct gpio_chip *chip, unsigned offset,
> +                                   int value);

Can the code be re-ordered to eliminate the prototypes?

> +
> +struct msm_gpio_regs {
> +     void __iomem *out;
> +     void __iomem *in;
> +     void __iomem *int_status;
> +     void __iomem *int_clear;
> +     void __iomem *int_en;
> +     void __iomem *int_edge;
> +     void __iomem *int_pos;
> +     void __iomem *oe;
> +};
> +
> +struct msm_gpio_chip {
> +     struct gpio_chip        chip;
> +     struct msm_gpio_regs    regs;
> +     spinlock_t              lock;
> +#if MSM_GPIO_BROKEN_INT_CLEAR
> +     unsigned                int_status_copy;
> +#endif
> +     unsigned int            both_edge_detect;
> +     unsigned int            int_enable[2]; /* 0: awake, 1: sleep */
> +};
> +
> +#define MSM_GPIO_BANK(name, reg_num, start, end)                     \
> +     {                                                               \
> +             .regs = {                                               \
> +                     .out =         GPIO_OUT_ ## reg_num,            \
> +                     .in =          GPIO_IN_ ## reg_num ,            \
> +                     .int_status =  GPIO_INT_STATUS_ ## reg_num,     \
> +                     .int_clear =   GPIO_INT_CLEAR_ ## reg_num,      \
> +                     .int_en =      GPIO_INT_EN_ ## reg_num,         \
> +                     .int_edge =    GPIO_INT_EDGE_ ## reg_num,       \
> +                     .int_pos =     GPIO_INT_POS_ ## reg_num,        \
> +                     .oe =          GPIO_OE_ ## reg_num,             \
> +             },                                                      \
> +             .chip = {                                               \
> +                     .label = name,                                  \
> +                     .ngpio = end - start + 1,                       \
> +                     .direction_input = gpio_chip_direction_input,   \
> +                     .direction_output = gpio_chip_direction_output, \
> +                     .get = gpio_chip_get,                           \
> +                     .set = gpio_chip_set,                           \
> +                     .to_irq = gpio_chip_to_irq,                     \
> +                     .base = start,                                  \
> +             }                                                       \
> +     }
> +
> +struct msm_gpio_chip msm_gpio_chips[] = {
> +     MSM_GPIO_BANK("bank0", 0, 0, 15),
> +     MSM_GPIO_BANK("bank1", 1, 16, 42),
> +     MSM_GPIO_BANK("bank2", 2, 43, 67),
> +     MSM_GPIO_BANK("bank3", 3, 68, 94),
> +#if defined(CONFIG_ARCH_QSD8X50)
> +     MSM_GPIO_BANK("bank4", 4, 95, 103),
> +     MSM_GPIO_BANK("bank5", 5, 104, 121),
> +     MSM_GPIO_BANK("bank6", 6, 122, 152),
> +     MSM_GPIO_BANK("bank7", 7, 153, 164),
> +#else
> +     MSM_GPIO_BANK("bank4", 4, 95, 106),
> +     MSM_GPIO_BANK("bank5", 5, 107, 121),
> +#endif
> +};
> +
> +#define to_msm_gpio_chip(c) container_of(c, struct msm_gpio_chip, chip)
> +
> +static int gpio_chip_direction_input(struct gpio_chip *chip, unsigned offset)
> +{
> +     struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
> +     unsigned long irq_flags;
> +     unsigned b = 1U << (offset);

The () around offset are not needed.

> +     unsigned v;
> +
> +     spin_lock_irqsave(&old_chip->lock, irq_flags);
> +     b = 1U << (offset);

Not needed.  You already did it above.

> +
> +     v = readl(old_chip->regs.oe);
> +     writel(v & (~b), old_chip->regs.oe);

Again, the () around ~b are not needed.  There are a number of these in this file.

> +
> +     spin_unlock_irqrestore(&old_chip->lock, irq_flags);
> +
> +     return 0;
> +}
> +
> +static int gpio_chip_get(struct gpio_chip *chip, unsigned offset)
> +{
> +     struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
> +     unsigned long irq_flags;
> +     int ret = -ENOTSUPP;
> +     unsigned b;
> +
> +     spin_lock_irqsave(&old_chip->lock, irq_flags);
> +     b = 1U << (offset);
> +
> +     ret = (readl(old_chip->regs.in)) & b ? 1 : 0;
> +
> +     spin_unlock_irqrestore(&old_chip->lock, irq_flags);
> +     return ret;
> +}
> +
> +static inline int
> +msm_gpio_write(struct msm_gpio_chip *chip, unsigned n, unsigned on)
> +{
> +     unsigned b = 1U << n;
> +     unsigned v;
> +
> +     v = readl(chip->regs.out);
> +     if (on)
> +             writel(v | b, chip->regs.out);
> +     else
> +             writel(v & (~b), chip->regs.out);
> +
> +     return 0;
> +}
> +
> +static int
> +gpio_chip_direction_output(struct gpio_chip *chip, unsigned offset, int value)
> +{
> +     struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
> +     unsigned long irq_flags;
> +     unsigned v;
> +
> +     spin_lock_irqsave(&old_chip->lock, irq_flags);
> +
> +     msm_gpio_write(old_chip, offset, value);
> +
> +     v = readl(old_chip->regs.oe);
> +     writel(v | offset, old_chip->regs.oe);
> +
> +     spin_unlock_irqrestore(&old_chip->lock, irq_flags);
> +
> +     return 0;
> +}
> +
> +static void gpio_chip_set(struct gpio_chip *chip, unsigned offset, int value)
> +{
> +     struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
> +     unsigned long irq_flags;
> +
> +     spin_lock_irqsave(&old_chip->lock, irq_flags);
> +
> +     msm_gpio_write(old_chip, offset, value);
> +
> +     spin_unlock_irqrestore(&old_chip->lock, irq_flags);
> +}
> +
> +static int gpio_chip_to_irq(struct gpio_chip *chip, unsigned offset)
> +{
> +     struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
> +     unsigned long irq_flags;
> +     int ret;
> +
> +     spin_lock_irqsave(&old_chip->lock, irq_flags);
> +     ret = MSM_GPIO_TO_INT(offset);
> +     spin_unlock_irqrestore(&old_chip->lock, irq_flags);
> +
> +     return ret;
> +}
> +
> +
> +static void msm_gpio_update_both_edge_detect(struct msm_gpio_chip *msm_chip)
> +{
> +     int loop_limit = 100;
> +     unsigned pol, val, val2, intstat;
> +     do {
> +             val = readl(msm_chip->regs.in);
> +             pol = readl(msm_chip->regs.int_pos);
> +             pol = (pol & ~msm_chip->both_edge_detect) |
> +                   (~val & msm_chip->both_edge_detect);
> +
> +             writel(pol, msm_chip->regs.int_pos);
> +
> +             intstat = readl(msm_chip->regs.int_status);
> +             val2 = readl(msm_chip->regs.in);
> +
> +             if (((val ^ val2) & msm_chip->both_edge_detect & ~intstat) == 0)
> +                     return;
> +     } while (loop_limit-- > 0);
> +     printk(KERN_ERR "msm_gpio_update_both_edge_detect, failed to reach stable state %x != %x\n", val, val2);
> +}
> +
> +static void msm_gpio_irq_ack(unsigned int irq)
> +{
> +     unsigned long irq_flags;
> +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> +     unsigned b;
> +
> +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> +
> +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);

Urk... That's a bit confusing...

You might want to make this a macro or an inline function with some kind
of comment.

> +
> +#if MSM_GPIO_BROKEN_INT_CLEAR
> +     /* Save interrupts that already triggered before we loose them. */
> +     /* Any interrupt that triggers between the read of int_status */
> +     /* and the write to int_clear will still be lost though. */
> +     msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
> +     msm_chip->int_status_copy &= ~b;
> +#endif
> +     writel(b, msm_chip->regs.int_clear);
> +
> +     msm_gpio_update_both_edge_detect(msm_chip);
> +     spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
> +}
> +
> +static void msm_gpio_irq_mask(unsigned int irq)
> +{
> +     unsigned long irq_flags;
> +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> +     unsigned b, v;
> +
> +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> +
> +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> +
> +     v = readl(msm_chip->regs.int_edge);
> +     /* level triggered interrupts are also latched */
> +     if (!(v & b)) {
> +
> +     #if MSM_GPIO_BROKEN_INT_CLEAR

Align the #if/#endif to the first column.

> +             /* Save interrupts that already triggered before we loose
> +              * them. Any interrupt that triggers between the read of
> +              * int_status and the write to int_clear will still be
> +              * lost though.
> +              */
> +             msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
> +             msm_chip->int_status_copy &= ~b;
> +     #endif
> +             writel(b, msm_chip->regs.int_clear);
> +             msm_gpio_update_both_edge_detect(msm_chip);
> +     }
> +
> +     msm_chip->int_enable[0] &= ~b;
> +     writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
> +
> +     spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
> +}
> +
> +static void msm_gpio_irq_unmask(unsigned int irq)
> +{
> +     unsigned long irq_flags;
> +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> +     unsigned b, v;
> +
> +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> +
> +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> +
> +     v = readl(msm_chip->regs.int_edge);
> +     /* level triggered interrupts are also latched */
> +     if (!(v & b)) {
> +
> +     #if MSM_GPIO_BROKEN_INT_CLEAR
> +             /* Save interrupts that already triggered before we loose
> +              * them. Any interrupt that triggers between the read of
> +              * int_status and the write to int_clear will still be
> +              * lost though.
> +              */
> +             msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
> +             msm_chip->int_status_copy &= ~b;
> +     #endif
> +             writel(b, msm_chip->regs.int_clear);
> +             msm_gpio_update_both_edge_detect(msm_chip);
> +     }
> +
> +     msm_chip->int_enable[0] |= b;
> +     writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
> +
> +     spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
> +}
> +
> +static int msm_gpio_irq_set_wake(unsigned int irq, unsigned int on)
> +{
> +     unsigned long irq_flags;
> +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> +     unsigned b;
> +
> +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> +
> +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> +
> +     if (on)
> +             msm_chip->int_enable[1] |= b;
> +     else
> +             msm_chip->int_enable[1] &= ~b;
> +
> +     spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
> +
> +     return 0;
> +}
> +
> +
> +static int msm_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
> +{
> +     unsigned long irq_flags;
> +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> +     unsigned b, v;
> +
> +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> +
> +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> +
> +     v = readl(msm_chip->regs.int_edge);
> +     if (flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) {
> +             writel(v | b, msm_chip->regs.int_edge);
> +             irq_desc[MSM_GPIO_TO_INT(irq - FIRST_GPIO_IRQ)].handle_irq = handle_edge_irq;
> +     } else {
> +             writel(v & (~b), msm_chip->regs.int_edge);
> +             irq_desc[MSM_GPIO_TO_INT(irq - FIRST_GPIO_IRQ)].handle_irq = handle_level_irq;
> +     }
> +     if ((flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) ==
> +                      (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) {
> +             msm_chip->both_edge_detect |= b;
> +             msm_gpio_update_both_edge_detect(msm_chip);
> +     } else {
> +             msm_chip->both_edge_detect &= ~b;
> +             v = readl(msm_chip->regs.int_pos);
> +             if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
> +                     writel(v | b, msm_chip->regs.int_pos);
> +             else
> +                     writel(v & (~b), msm_chip->regs.int_pos);
> +
> +     }
> +     spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
> +     return 0;
> +}
> +
> +static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
> +{
> +     int i, j, m;
> +     unsigned v;
> +
> +     for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
> +             struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i];
> +             v = readl(msm_chip->regs.int_status);
> +             v &= msm_chip->int_enable[0];
> +             while (v) {
> +                     m = v & -v;
> +                     j = fls(m) - 1;
> +                     v &= ~m;
> +                     generic_handle_irq(FIRST_GPIO_IRQ + msm_chip->chip.base + j);
> +             }
> +     }
> +     desc->chip->ack(irq);
> +}
> +
> +static struct irq_chip msm_gpio_irq_chip = {
> +     .name      = "msmgpio",
> +     .ack       = msm_gpio_irq_ack,
> +     .mask      = msm_gpio_irq_mask,
> +     .unmask    = msm_gpio_irq_unmask,
> +     .set_wake  = msm_gpio_irq_set_wake,
> +     .set_type  = msm_gpio_irq_set_type,
> +};
> +
> +static int __init msm_init_gpio(void)
> +{
> +     int i, j = 0;
> +     for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
> +             if (i - FIRST_GPIO_IRQ > msm_gpio_chips[j].chip.ngpio - 1)
> +                     j++;
> +             set_irq_chip_data(i, &msm_gpio_chips[j]);
> +             set_irq_chip(i, &msm_gpio_irq_chip);
> +             set_irq_handler(i, handle_edge_irq);
> +             set_irq_flags(i, IRQF_VALID);
> +     }
> +
> +     for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
> +             writel(0, msm_gpio_chips[i].regs.int_en);
> +             spin_lock_init(&msm_gpio_chips[i].lock);
> +             gpiochip_add(&msm_gpio_chips[i].chip);
> +     }
> +
> +     set_irq_chained_handler(INT_GPIO_GROUP1, msm_gpio_irq_handler);
> +     set_irq_chained_handler(INT_GPIO_GROUP2, msm_gpio_irq_handler);
> +     set_irq_wake(INT_GPIO_GROUP1, 1);
> +     set_irq_wake(INT_GPIO_GROUP2, 2);
> +
> +     return 0;
> +}
> +
> +postcore_initcall(msm_init_gpio);
> diff --git a/arch/arm/mach-msm/gpio_hw.h b/arch/arm/mach-msm/gpio_hw.h
> new file mode 100644
> index 0000000..f7e1b5b
> --- /dev/null
> +++ b/arch/arm/mach-msm/gpio_hw.h
> @@ -0,0 +1,187 @@
> +/* arch/arm/mach-msm/gpio_hw.h
> + *
> + * Copyright (C) 2007 Google, Inc.
> + * Author: Brian Swetland <swetland@google.com>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef __ARCH_ARM_MACH_MSM_GPIO_HW_H
> +#define __ARCH_ARM_MACH_MSM_GPIO_HW_H
> +
> +#include <mach/msm_iomap.h>
> +
> +/* see 80-VA736-2 Rev C pp 695-751
> +**
> +** These are actually the *shadow* gpio registers, since the
> +** real ones (which allow full access) are only available to the
> +** ARM9 side of the world.
> +**
> +** Since the _BASE need to be page-aligned when we're mapping them
> +** to virtual addresses, adjust for the additional offset in these
> +** macros.
> +*/
> +

All the #define'd names in this file are pretty generic.  You should
probably add a prefix (MSM_ ?) to all of them.

Also, you should use tabs instead of spaces between the #define <name><tabs><something>

> +#define GPIO1_REG(off) (MSM_GPIO1_BASE + 0x800 + (off))
> +#define GPIO2_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off))
> +
> +#if defined(CONFIG_ARCH_MSM7X00A)
> +
> +/* output value */
> +#define GPIO_OUT_0         GPIO1_REG(0x00)  /* gpio  15-0  */
> +#define GPIO_OUT_1         GPIO2_REG(0x00)  /* gpio  42-16 */
> +#define GPIO_OUT_2         GPIO1_REG(0x04)  /* gpio  67-43 */
> +#define GPIO_OUT_3         GPIO1_REG(0x08)  /* gpio  94-68 */
> +#define GPIO_OUT_4         GPIO1_REG(0x0C)  /* gpio 106-95 */
> +#define GPIO_OUT_5         GPIO1_REG(0x50)  /* gpio 107-121 */
> +
> +/* same pin map as above, output enable */
> +#define GPIO_OE_0          GPIO1_REG(0x10)
> +#define GPIO_OE_1          GPIO2_REG(0x08)
> +#define GPIO_OE_2          GPIO1_REG(0x14)
> +#define GPIO_OE_3          GPIO1_REG(0x18)
> +#define GPIO_OE_4          GPIO1_REG(0x1C)
> +#define GPIO_OE_5          GPIO1_REG(0x54)
> +
> +/* same pin map as above, input read */
> +#define GPIO_IN_0          GPIO1_REG(0x34)
> +#define GPIO_IN_1          GPIO2_REG(0x20)
> +#define GPIO_IN_2          GPIO1_REG(0x38)
> +#define GPIO_IN_3          GPIO1_REG(0x3C)
> +#define GPIO_IN_4          GPIO1_REG(0x40)
> +#define GPIO_IN_5          GPIO1_REG(0x44)
> +
> +/* same pin map as above, 1=edge 0=level interrup */
> +#define GPIO_INT_EDGE_0    GPIO1_REG(0x60)
> +#define GPIO_INT_EDGE_1    GPIO2_REG(0x50)
> +#define GPIO_INT_EDGE_2    GPIO1_REG(0x64)
> +#define GPIO_INT_EDGE_3    GPIO1_REG(0x68)
> +#define GPIO_INT_EDGE_4    GPIO1_REG(0x6C)
> +#define GPIO_INT_EDGE_5    GPIO1_REG(0xC0)
> +
> +/* same pin map as above, 1=positive 0=negative */
> +#define GPIO_INT_POS_0     GPIO1_REG(0x70)
> +#define GPIO_INT_POS_1     GPIO2_REG(0x58)
> +#define GPIO_INT_POS_2     GPIO1_REG(0x74)
> +#define GPIO_INT_POS_3     GPIO1_REG(0x78)
> +#define GPIO_INT_POS_4     GPIO1_REG(0x7C)
> +#define GPIO_INT_POS_5     GPIO1_REG(0xBC)
> +
> +/* same pin map as above, interrupt enable */
> +#define GPIO_INT_EN_0      GPIO1_REG(0x80)
> +#define GPIO_INT_EN_1      GPIO2_REG(0x60)
> +#define GPIO_INT_EN_2      GPIO1_REG(0x84)
> +#define GPIO_INT_EN_3      GPIO1_REG(0x88)
> +#define GPIO_INT_EN_4      GPIO1_REG(0x8C)
> +#define GPIO_INT_EN_5      GPIO1_REG(0xB8)
> +
> +/* same pin map as above, write 1 to clear interrupt */
> +#define GPIO_INT_CLEAR_0   GPIO1_REG(0x90)
> +#define GPIO_INT_CLEAR_1   GPIO2_REG(0x68)
> +#define GPIO_INT_CLEAR_2   GPIO1_REG(0x94)
> +#define GPIO_INT_CLEAR_3   GPIO1_REG(0x98)
> +#define GPIO_INT_CLEAR_4   GPIO1_REG(0x9C)
> +#define GPIO_INT_CLEAR_5   GPIO1_REG(0xB4)
> +
> +/* same pin map as above, 1=interrupt pending */
> +#define GPIO_INT_STATUS_0  GPIO1_REG(0xA0)
> +#define GPIO_INT_STATUS_1  GPIO2_REG(0x70)
> +#define GPIO_INT_STATUS_2  GPIO1_REG(0xA4)
> +#define GPIO_INT_STATUS_3  GPIO1_REG(0xA8)
> +#define GPIO_INT_STATUS_4  GPIO1_REG(0xAC)
> +#define GPIO_INT_STATUS_5  GPIO1_REG(0xB0)
> +
> +#endif
> +
> +#if defined(CONFIG_ARCH_QSD8X50)
> +/* output value */
> +#define GPIO_OUT_0         GPIO1_REG(0x00)  /* gpio  15-0   */
> +#define GPIO_OUT_1         GPIO2_REG(0x00)  /* gpio  42-16  */
> +#define GPIO_OUT_2         GPIO1_REG(0x04)  /* gpio  67-43  */
> +#define GPIO_OUT_3         GPIO1_REG(0x08)  /* gpio  94-68  */
> +#define GPIO_OUT_4         GPIO1_REG(0x0C)  /* gpio 103-95  */
> +#define GPIO_OUT_5         GPIO1_REG(0x10)  /* gpio 121-104 */
> +#define GPIO_OUT_6         GPIO1_REG(0x14)  /* gpio 152-122 */
> +#define GPIO_OUT_7         GPIO1_REG(0x18)  /* gpio 164-153 */
> +
> +/* same pin map as above, output enable */
> +#define GPIO_OE_0          GPIO1_REG(0x20)
> +#define GPIO_OE_1          GPIO2_REG(0x08)
> +#define GPIO_OE_2          GPIO1_REG(0x24)
> +#define GPIO_OE_3          GPIO1_REG(0x28)
> +#define GPIO_OE_4          GPIO1_REG(0x2C)
> +#define GPIO_OE_5          GPIO1_REG(0x30)
> +#define GPIO_OE_6          GPIO1_REG(0x34)
> +#define GPIO_OE_7          GPIO1_REG(0x38)
> +
> +/* same pin map as above, input read */
> +#define GPIO_IN_0          GPIO1_REG(0x50)
> +#define GPIO_IN_1          GPIO2_REG(0x20)
> +#define GPIO_IN_2          GPIO1_REG(0x54)
> +#define GPIO_IN_3          GPIO1_REG(0x58)
> +#define GPIO_IN_4          GPIO1_REG(0x5C)
> +#define GPIO_IN_5          GPIO1_REG(0x60)
> +#define GPIO_IN_6          GPIO1_REG(0x64)
> +#define GPIO_IN_7          GPIO1_REG(0x68)
> +
> +/* same pin map as above, 1=edge 0=level interrup */
> +#define GPIO_INT_EDGE_0    GPIO1_REG(0x70)
> +#define GPIO_INT_EDGE_1    GPIO2_REG(0x50)
> +#define GPIO_INT_EDGE_2    GPIO1_REG(0x74)
> +#define GPIO_INT_EDGE_3    GPIO1_REG(0x78)
> +#define GPIO_INT_EDGE_4    GPIO1_REG(0x7C)
> +#define GPIO_INT_EDGE_5    GPIO1_REG(0x80)
> +#define GPIO_INT_EDGE_6    GPIO1_REG(0x84)
> +#define GPIO_INT_EDGE_7    GPIO1_REG(0x88)
> +
> +/* same pin map as above, 1=positive 0=negative */
> +#define GPIO_INT_POS_0     GPIO1_REG(0x90)
> +#define GPIO_INT_POS_1     GPIO2_REG(0x58)
> +#define GPIO_INT_POS_2     GPIO1_REG(0x94)
> +#define GPIO_INT_POS_3     GPIO1_REG(0x98)
> +#define GPIO_INT_POS_4     GPIO1_REG(0x9C)
> +#define GPIO_INT_POS_5     GPIO1_REG(0xA0)
> +#define GPIO_INT_POS_6     GPIO1_REG(0xA4)
> +#define GPIO_INT_POS_7     GPIO1_REG(0xA8)
> +
> +/* same pin map as above, interrupt enable */
> +#define GPIO_INT_EN_0      GPIO1_REG(0xB0)
> +#define GPIO_INT_EN_1      GPIO2_REG(0x60)
> +#define GPIO_INT_EN_2      GPIO1_REG(0xB4)
> +#define GPIO_INT_EN_3      GPIO1_REG(0xB8)
> +#define GPIO_INT_EN_4      GPIO1_REG(0xBC)
> +#define GPIO_INT_EN_5      GPIO1_REG(0xC0)
> +#define GPIO_INT_EN_6      GPIO1_REG(0xC4)
> +#define GPIO_INT_EN_7      GPIO1_REG(0xC8)
> +
> +/* same pin map as above, write 1 to clear interrupt */
> +#define GPIO_INT_CLEAR_0   GPIO1_REG(0xD0)
> +#define GPIO_INT_CLEAR_1   GPIO2_REG(0x68)
> +#define GPIO_INT_CLEAR_2   GPIO1_REG(0xD4)
> +#define GPIO_INT_CLEAR_3   GPIO1_REG(0xD8)
> +#define GPIO_INT_CLEAR_4   GPIO1_REG(0xDC)
> +#define GPIO_INT_CLEAR_5   GPIO1_REG(0xE0)
> +#define GPIO_INT_CLEAR_6   GPIO1_REG(0xE4)
> +#define GPIO_INT_CLEAR_7   GPIO1_REG(0xE8)
> +
> +/* same pin map as above, 1=interrupt pending */
> +#define GPIO_INT_STATUS_0  GPIO1_REG(0xF0)
> +#define GPIO_INT_STATUS_1  GPIO2_REG(0x70)
> +#define GPIO_INT_STATUS_2  GPIO1_REG(0xF4)
> +#define GPIO_INT_STATUS_3  GPIO1_REG(0xF8)
> +#define GPIO_INT_STATUS_4  GPIO1_REG(0xFC)
> +#define GPIO_INT_STATUS_5  GPIO1_REG(0x100)
> +#define GPIO_INT_STATUS_6  GPIO1_REG(0x104)
> +#define GPIO_INT_STATUS_7  GPIO1_REG(0x108)
> +
> +#endif
> +
> +#endif
> diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h
> new file mode 100644
> index 0000000..784e6f5
> --- /dev/null
> +++ b/arch/arm/mach-msm/include/mach/gpio.h
> @@ -0,0 +1,43 @@
> +/* linux/include/asm-arm/arch-msm/gpio.h
> + *
> + * Copyright (C) 2007 Google, Inc.
> + * Author: Mike Lockwood <lockwood@android.com>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef __ASM_ARCH_MSM_GPIO_H
> +#define __ASM_ARCH_MSM_GPIO_H
> +
> +#include <linux/interrupt.h>

Why is this included?

> +#include <asm-generic/gpio.h>
> +
> +static inline int gpio_get_value(unsigned gpio)
> +{
> +     return __gpio_get_value(gpio);
> +}
> +
> +static inline void gpio_set_value(unsigned gpio, int value)
> +{
> +     __gpio_set_value(gpio, value);
> +}
> +
> +static inline int gpio_cansleep(unsigned gpio)
> +{
> +     return __gpio_cansleep(gpio);
> +}
> +
> +static inline int gpio_to_irq(unsigned gpio)
> +{
> +     return __gpio_to_irq(gpio);
> +}
> +

These could all just be:

#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

> +#endif

Regards,
Hartley

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH 1/4] arm: msm: gpio support
@ 2010-03-30 23:58   ` H Hartley Sweeten
  0 siblings, 0 replies; 22+ messages in thread
From: H Hartley Sweeten @ 2010-03-30 23:58 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday, March 30, 2010 4:12 PM, Daniel Walker wrote:
> From: Daniel Walker <c_dwalke@quicinc.com>
>
> This adds basic gpio support in MSM using gpiolib, as well as gpio
> interrupt support.
>
> Signed-off-by: Daniel Walker <c_dwalke@quicinc.com>
> ---
>  arch/arm/Kconfig                      |    1 +
>  arch/arm/mach-msm/Makefile            |    1 +
>  arch/arm/mach-msm/gpio.c              |  428 +++++++++++++++++++++++++++++++++
>  arch/arm/mach-msm/gpio_hw.h           |  187 ++++++++++++++
>  arch/arm/mach-msm/include/mach/gpio.h |   43 ++++
>  5 files changed, 660 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/mach-msm/gpio.c
>  create mode 100644 arch/arm/mach-msm/gpio_hw.h
>  create mode 100644 arch/arm/mach-msm/include/mach/gpio.h
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index cadfe2e..5e29092 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -601,6 +601,7 @@ config ARCH_MSM
>       select CPU_V6
>       select GENERIC_TIME
>       select GENERIC_CLOCKEVENTS
> +     select ARCH_REQUIRE_GPIOLIB
>       help
>         Support for Qualcomm MSM7K based systems.  This runs on the ARM11
>         apps processor of the MSM7K and depends on a shared memory
> diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
> index 147339c..47d47cb 100644
> --- a/arch/arm/mach-msm/Makefile
> +++ b/arch/arm/mach-msm/Makefile
> @@ -4,6 +4,7 @@ obj-y += proc_comm.o
>  obj-y += vreg.o
>  obj-y += acpuclock-arm11.o
>  obj-y += clock.o clock-7x01a.o
> +obj-y += gpio.o
>
>  obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o
>  obj-$(CONFIG_MSM_SMD) += last_radio_log.o
> diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c
> new file mode 100644
> index 0000000..5b95885
> --- /dev/null
> +++ b/arch/arm/mach-msm/gpio.c
> @@ -0,0 +1,428 @@
> +/* linux/arch/arm/mach-msm/gpio.c
> + *
> + * Copyright (C) 2007 Google, Inc.
> + * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +
> +#include <asm/io.h>

#include <linux/io.h>

> +#include <asm/irq.h>

This one is not needed.

> +#include <linux/irq.h>

This includes the <asm/irq.h> for you.

> +#include <linux/module.h>
> +#include <linux/gpio.h>
> +#include "gpio_hw.h"
> +
> +#include "smd_private.h"
> +
> +static int msm_gpio_debug_mask;
> +module_param_named(debug_mask, msm_gpio_debug_mask, int,
> +                S_IRUGO | S_IWUSR | S_IWGRP);
> +
> +#define MSM_GPIO_BROKEN_INT_CLEAR 1
> +
> +/* private gpio_configure flags */
> +#define MSM_GPIOF_ENABLE_INTERRUPT      0x10000000
> +#define MSM_GPIOF_DISABLE_INTERRUPT     0x20000000
> +#define MSM_GPIOF_ENABLE_WAKE           0x40000000
> +#define MSM_GPIOF_DISABLE_WAKE          0x80000000
> +
> +static int gpio_chip_to_irq(struct gpio_chip *chip, unsigned offset);
> +static void gpio_chip_set(struct gpio_chip *chip, unsigned offset, int value);
> +static int gpio_chip_get(struct gpio_chip *chip, unsigned offset);
> +static int gpio_chip_direction_input(struct gpio_chip *chip, unsigned offset);
> +static int gpio_chip_direction_output(struct gpio_chip *chip, unsigned offset,
> +                                   int value);

Can the code be re-ordered to eliminate the prototypes?

> +
> +struct msm_gpio_regs {
> +     void __iomem *out;
> +     void __iomem *in;
> +     void __iomem *int_status;
> +     void __iomem *int_clear;
> +     void __iomem *int_en;
> +     void __iomem *int_edge;
> +     void __iomem *int_pos;
> +     void __iomem *oe;
> +};
> +
> +struct msm_gpio_chip {
> +     struct gpio_chip        chip;
> +     struct msm_gpio_regs    regs;
> +     spinlock_t              lock;
> +#if MSM_GPIO_BROKEN_INT_CLEAR
> +     unsigned                int_status_copy;
> +#endif
> +     unsigned int            both_edge_detect;
> +     unsigned int            int_enable[2]; /* 0: awake, 1: sleep */
> +};
> +
> +#define MSM_GPIO_BANK(name, reg_num, start, end)                     \
> +     {                                                               \
> +             .regs = {                                               \
> +                     .out =         GPIO_OUT_ ## reg_num,            \
> +                     .in =          GPIO_IN_ ## reg_num ,            \
> +                     .int_status =  GPIO_INT_STATUS_ ## reg_num,     \
> +                     .int_clear =   GPIO_INT_CLEAR_ ## reg_num,      \
> +                     .int_en =      GPIO_INT_EN_ ## reg_num,         \
> +                     .int_edge =    GPIO_INT_EDGE_ ## reg_num,       \
> +                     .int_pos =     GPIO_INT_POS_ ## reg_num,        \
> +                     .oe =          GPIO_OE_ ## reg_num,             \
> +             },                                                      \
> +             .chip = {                                               \
> +                     .label = name,                                  \
> +                     .ngpio = end - start + 1,                       \
> +                     .direction_input = gpio_chip_direction_input,   \
> +                     .direction_output = gpio_chip_direction_output, \
> +                     .get = gpio_chip_get,                           \
> +                     .set = gpio_chip_set,                           \
> +                     .to_irq = gpio_chip_to_irq,                     \
> +                     .base = start,                                  \
> +             }                                                       \
> +     }
> +
> +struct msm_gpio_chip msm_gpio_chips[] = {
> +     MSM_GPIO_BANK("bank0", 0, 0, 15),
> +     MSM_GPIO_BANK("bank1", 1, 16, 42),
> +     MSM_GPIO_BANK("bank2", 2, 43, 67),
> +     MSM_GPIO_BANK("bank3", 3, 68, 94),
> +#if defined(CONFIG_ARCH_QSD8X50)
> +     MSM_GPIO_BANK("bank4", 4, 95, 103),
> +     MSM_GPIO_BANK("bank5", 5, 104, 121),
> +     MSM_GPIO_BANK("bank6", 6, 122, 152),
> +     MSM_GPIO_BANK("bank7", 7, 153, 164),
> +#else
> +     MSM_GPIO_BANK("bank4", 4, 95, 106),
> +     MSM_GPIO_BANK("bank5", 5, 107, 121),
> +#endif
> +};
> +
> +#define to_msm_gpio_chip(c) container_of(c, struct msm_gpio_chip, chip)
> +
> +static int gpio_chip_direction_input(struct gpio_chip *chip, unsigned offset)
> +{
> +     struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
> +     unsigned long irq_flags;
> +     unsigned b = 1U << (offset);

The () around offset are not needed.

> +     unsigned v;
> +
> +     spin_lock_irqsave(&old_chip->lock, irq_flags);
> +     b = 1U << (offset);

Not needed.  You already did it above.

> +
> +     v = readl(old_chip->regs.oe);
> +     writel(v & (~b), old_chip->regs.oe);

Again, the () around ~b are not needed.  There are a number of these in this file.

> +
> +     spin_unlock_irqrestore(&old_chip->lock, irq_flags);
> +
> +     return 0;
> +}
> +
> +static int gpio_chip_get(struct gpio_chip *chip, unsigned offset)
> +{
> +     struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
> +     unsigned long irq_flags;
> +     int ret = -ENOTSUPP;
> +     unsigned b;
> +
> +     spin_lock_irqsave(&old_chip->lock, irq_flags);
> +     b = 1U << (offset);
> +
> +     ret = (readl(old_chip->regs.in)) & b ? 1 : 0;
> +
> +     spin_unlock_irqrestore(&old_chip->lock, irq_flags);
> +     return ret;
> +}
> +
> +static inline int
> +msm_gpio_write(struct msm_gpio_chip *chip, unsigned n, unsigned on)
> +{
> +     unsigned b = 1U << n;
> +     unsigned v;
> +
> +     v = readl(chip->regs.out);
> +     if (on)
> +             writel(v | b, chip->regs.out);
> +     else
> +             writel(v & (~b), chip->regs.out);
> +
> +     return 0;
> +}
> +
> +static int
> +gpio_chip_direction_output(struct gpio_chip *chip, unsigned offset, int value)
> +{
> +     struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
> +     unsigned long irq_flags;
> +     unsigned v;
> +
> +     spin_lock_irqsave(&old_chip->lock, irq_flags);
> +
> +     msm_gpio_write(old_chip, offset, value);
> +
> +     v = readl(old_chip->regs.oe);
> +     writel(v | offset, old_chip->regs.oe);
> +
> +     spin_unlock_irqrestore(&old_chip->lock, irq_flags);
> +
> +     return 0;
> +}
> +
> +static void gpio_chip_set(struct gpio_chip *chip, unsigned offset, int value)
> +{
> +     struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
> +     unsigned long irq_flags;
> +
> +     spin_lock_irqsave(&old_chip->lock, irq_flags);
> +
> +     msm_gpio_write(old_chip, offset, value);
> +
> +     spin_unlock_irqrestore(&old_chip->lock, irq_flags);
> +}
> +
> +static int gpio_chip_to_irq(struct gpio_chip *chip, unsigned offset)
> +{
> +     struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
> +     unsigned long irq_flags;
> +     int ret;
> +
> +     spin_lock_irqsave(&old_chip->lock, irq_flags);
> +     ret = MSM_GPIO_TO_INT(offset);
> +     spin_unlock_irqrestore(&old_chip->lock, irq_flags);
> +
> +     return ret;
> +}
> +
> +
> +static void msm_gpio_update_both_edge_detect(struct msm_gpio_chip *msm_chip)
> +{
> +     int loop_limit = 100;
> +     unsigned pol, val, val2, intstat;
> +     do {
> +             val = readl(msm_chip->regs.in);
> +             pol = readl(msm_chip->regs.int_pos);
> +             pol = (pol & ~msm_chip->both_edge_detect) |
> +                   (~val & msm_chip->both_edge_detect);
> +
> +             writel(pol, msm_chip->regs.int_pos);
> +
> +             intstat = readl(msm_chip->regs.int_status);
> +             val2 = readl(msm_chip->regs.in);
> +
> +             if (((val ^ val2) & msm_chip->both_edge_detect & ~intstat) == 0)
> +                     return;
> +     } while (loop_limit-- > 0);
> +     printk(KERN_ERR "msm_gpio_update_both_edge_detect, failed to reach stable state %x != %x\n", val, val2);
> +}
> +
> +static void msm_gpio_irq_ack(unsigned int irq)
> +{
> +     unsigned long irq_flags;
> +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> +     unsigned b;
> +
> +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> +
> +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);

Urk... That's a bit confusing...

You might want to make this a macro or an inline function with some kind
of comment.

> +
> +#if MSM_GPIO_BROKEN_INT_CLEAR
> +     /* Save interrupts that already triggered before we loose them. */
> +     /* Any interrupt that triggers between the read of int_status */
> +     /* and the write to int_clear will still be lost though. */
> +     msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
> +     msm_chip->int_status_copy &= ~b;
> +#endif
> +     writel(b, msm_chip->regs.int_clear);
> +
> +     msm_gpio_update_both_edge_detect(msm_chip);
> +     spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
> +}
> +
> +static void msm_gpio_irq_mask(unsigned int irq)
> +{
> +     unsigned long irq_flags;
> +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> +     unsigned b, v;
> +
> +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> +
> +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> +
> +     v = readl(msm_chip->regs.int_edge);
> +     /* level triggered interrupts are also latched */
> +     if (!(v & b)) {
> +
> +     #if MSM_GPIO_BROKEN_INT_CLEAR

Align the #if/#endif to the first column.

> +             /* Save interrupts that already triggered before we loose
> +              * them. Any interrupt that triggers between the read of
> +              * int_status and the write to int_clear will still be
> +              * lost though.
> +              */
> +             msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
> +             msm_chip->int_status_copy &= ~b;
> +     #endif
> +             writel(b, msm_chip->regs.int_clear);
> +             msm_gpio_update_both_edge_detect(msm_chip);
> +     }
> +
> +     msm_chip->int_enable[0] &= ~b;
> +     writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
> +
> +     spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
> +}
> +
> +static void msm_gpio_irq_unmask(unsigned int irq)
> +{
> +     unsigned long irq_flags;
> +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> +     unsigned b, v;
> +
> +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> +
> +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> +
> +     v = readl(msm_chip->regs.int_edge);
> +     /* level triggered interrupts are also latched */
> +     if (!(v & b)) {
> +
> +     #if MSM_GPIO_BROKEN_INT_CLEAR
> +             /* Save interrupts that already triggered before we loose
> +              * them. Any interrupt that triggers between the read of
> +              * int_status and the write to int_clear will still be
> +              * lost though.
> +              */
> +             msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
> +             msm_chip->int_status_copy &= ~b;
> +     #endif
> +             writel(b, msm_chip->regs.int_clear);
> +             msm_gpio_update_both_edge_detect(msm_chip);
> +     }
> +
> +     msm_chip->int_enable[0] |= b;
> +     writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
> +
> +     spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
> +}
> +
> +static int msm_gpio_irq_set_wake(unsigned int irq, unsigned int on)
> +{
> +     unsigned long irq_flags;
> +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> +     unsigned b;
> +
> +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> +
> +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> +
> +     if (on)
> +             msm_chip->int_enable[1] |= b;
> +     else
> +             msm_chip->int_enable[1] &= ~b;
> +
> +     spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
> +
> +     return 0;
> +}
> +
> +
> +static int msm_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
> +{
> +     unsigned long irq_flags;
> +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> +     unsigned b, v;
> +
> +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> +
> +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> +
> +     v = readl(msm_chip->regs.int_edge);
> +     if (flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) {
> +             writel(v | b, msm_chip->regs.int_edge);
> +             irq_desc[MSM_GPIO_TO_INT(irq - FIRST_GPIO_IRQ)].handle_irq = handle_edge_irq;
> +     } else {
> +             writel(v & (~b), msm_chip->regs.int_edge);
> +             irq_desc[MSM_GPIO_TO_INT(irq - FIRST_GPIO_IRQ)].handle_irq = handle_level_irq;
> +     }
> +     if ((flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) ==
> +                      (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) {
> +             msm_chip->both_edge_detect |= b;
> +             msm_gpio_update_both_edge_detect(msm_chip);
> +     } else {
> +             msm_chip->both_edge_detect &= ~b;
> +             v = readl(msm_chip->regs.int_pos);
> +             if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
> +                     writel(v | b, msm_chip->regs.int_pos);
> +             else
> +                     writel(v & (~b), msm_chip->regs.int_pos);
> +
> +     }
> +     spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
> +     return 0;
> +}
> +
> +static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
> +{
> +     int i, j, m;
> +     unsigned v;
> +
> +     for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
> +             struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i];
> +             v = readl(msm_chip->regs.int_status);
> +             v &= msm_chip->int_enable[0];
> +             while (v) {
> +                     m = v & -v;
> +                     j = fls(m) - 1;
> +                     v &= ~m;
> +                     generic_handle_irq(FIRST_GPIO_IRQ + msm_chip->chip.base + j);
> +             }
> +     }
> +     desc->chip->ack(irq);
> +}
> +
> +static struct irq_chip msm_gpio_irq_chip = {
> +     .name      = "msmgpio",
> +     .ack       = msm_gpio_irq_ack,
> +     .mask      = msm_gpio_irq_mask,
> +     .unmask    = msm_gpio_irq_unmask,
> +     .set_wake  = msm_gpio_irq_set_wake,
> +     .set_type  = msm_gpio_irq_set_type,
> +};
> +
> +static int __init msm_init_gpio(void)
> +{
> +     int i, j = 0;
> +     for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
> +             if (i - FIRST_GPIO_IRQ > msm_gpio_chips[j].chip.ngpio - 1)
> +                     j++;
> +             set_irq_chip_data(i, &msm_gpio_chips[j]);
> +             set_irq_chip(i, &msm_gpio_irq_chip);
> +             set_irq_handler(i, handle_edge_irq);
> +             set_irq_flags(i, IRQF_VALID);
> +     }
> +
> +     for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
> +             writel(0, msm_gpio_chips[i].regs.int_en);
> +             spin_lock_init(&msm_gpio_chips[i].lock);
> +             gpiochip_add(&msm_gpio_chips[i].chip);
> +     }
> +
> +     set_irq_chained_handler(INT_GPIO_GROUP1, msm_gpio_irq_handler);
> +     set_irq_chained_handler(INT_GPIO_GROUP2, msm_gpio_irq_handler);
> +     set_irq_wake(INT_GPIO_GROUP1, 1);
> +     set_irq_wake(INT_GPIO_GROUP2, 2);
> +
> +     return 0;
> +}
> +
> +postcore_initcall(msm_init_gpio);
> diff --git a/arch/arm/mach-msm/gpio_hw.h b/arch/arm/mach-msm/gpio_hw.h
> new file mode 100644
> index 0000000..f7e1b5b
> --- /dev/null
> +++ b/arch/arm/mach-msm/gpio_hw.h
> @@ -0,0 +1,187 @@
> +/* arch/arm/mach-msm/gpio_hw.h
> + *
> + * Copyright (C) 2007 Google, Inc.
> + * Author: Brian Swetland <swetland@google.com>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef __ARCH_ARM_MACH_MSM_GPIO_HW_H
> +#define __ARCH_ARM_MACH_MSM_GPIO_HW_H
> +
> +#include <mach/msm_iomap.h>
> +
> +/* see 80-VA736-2 Rev C pp 695-751
> +**
> +** These are actually the *shadow* gpio registers, since the
> +** real ones (which allow full access) are only available to the
> +** ARM9 side of the world.
> +**
> +** Since the _BASE need to be page-aligned when we're mapping them
> +** to virtual addresses, adjust for the additional offset in these
> +** macros.
> +*/
> +

All the #define'd names in this file are pretty generic.  You should
probably add a prefix (MSM_ ?) to all of them.

Also, you should use tabs instead of spaces between the #define <name><tabs><something>

> +#define GPIO1_REG(off) (MSM_GPIO1_BASE + 0x800 + (off))
> +#define GPIO2_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off))
> +
> +#if defined(CONFIG_ARCH_MSM7X00A)
> +
> +/* output value */
> +#define GPIO_OUT_0         GPIO1_REG(0x00)  /* gpio  15-0  */
> +#define GPIO_OUT_1         GPIO2_REG(0x00)  /* gpio  42-16 */
> +#define GPIO_OUT_2         GPIO1_REG(0x04)  /* gpio  67-43 */
> +#define GPIO_OUT_3         GPIO1_REG(0x08)  /* gpio  94-68 */
> +#define GPIO_OUT_4         GPIO1_REG(0x0C)  /* gpio 106-95 */
> +#define GPIO_OUT_5         GPIO1_REG(0x50)  /* gpio 107-121 */
> +
> +/* same pin map as above, output enable */
> +#define GPIO_OE_0          GPIO1_REG(0x10)
> +#define GPIO_OE_1          GPIO2_REG(0x08)
> +#define GPIO_OE_2          GPIO1_REG(0x14)
> +#define GPIO_OE_3          GPIO1_REG(0x18)
> +#define GPIO_OE_4          GPIO1_REG(0x1C)
> +#define GPIO_OE_5          GPIO1_REG(0x54)
> +
> +/* same pin map as above, input read */
> +#define GPIO_IN_0          GPIO1_REG(0x34)
> +#define GPIO_IN_1          GPIO2_REG(0x20)
> +#define GPIO_IN_2          GPIO1_REG(0x38)
> +#define GPIO_IN_3          GPIO1_REG(0x3C)
> +#define GPIO_IN_4          GPIO1_REG(0x40)
> +#define GPIO_IN_5          GPIO1_REG(0x44)
> +
> +/* same pin map as above, 1=edge 0=level interrup */
> +#define GPIO_INT_EDGE_0    GPIO1_REG(0x60)
> +#define GPIO_INT_EDGE_1    GPIO2_REG(0x50)
> +#define GPIO_INT_EDGE_2    GPIO1_REG(0x64)
> +#define GPIO_INT_EDGE_3    GPIO1_REG(0x68)
> +#define GPIO_INT_EDGE_4    GPIO1_REG(0x6C)
> +#define GPIO_INT_EDGE_5    GPIO1_REG(0xC0)
> +
> +/* same pin map as above, 1=positive 0=negative */
> +#define GPIO_INT_POS_0     GPIO1_REG(0x70)
> +#define GPIO_INT_POS_1     GPIO2_REG(0x58)
> +#define GPIO_INT_POS_2     GPIO1_REG(0x74)
> +#define GPIO_INT_POS_3     GPIO1_REG(0x78)
> +#define GPIO_INT_POS_4     GPIO1_REG(0x7C)
> +#define GPIO_INT_POS_5     GPIO1_REG(0xBC)
> +
> +/* same pin map as above, interrupt enable */
> +#define GPIO_INT_EN_0      GPIO1_REG(0x80)
> +#define GPIO_INT_EN_1      GPIO2_REG(0x60)
> +#define GPIO_INT_EN_2      GPIO1_REG(0x84)
> +#define GPIO_INT_EN_3      GPIO1_REG(0x88)
> +#define GPIO_INT_EN_4      GPIO1_REG(0x8C)
> +#define GPIO_INT_EN_5      GPIO1_REG(0xB8)
> +
> +/* same pin map as above, write 1 to clear interrupt */
> +#define GPIO_INT_CLEAR_0   GPIO1_REG(0x90)
> +#define GPIO_INT_CLEAR_1   GPIO2_REG(0x68)
> +#define GPIO_INT_CLEAR_2   GPIO1_REG(0x94)
> +#define GPIO_INT_CLEAR_3   GPIO1_REG(0x98)
> +#define GPIO_INT_CLEAR_4   GPIO1_REG(0x9C)
> +#define GPIO_INT_CLEAR_5   GPIO1_REG(0xB4)
> +
> +/* same pin map as above, 1=interrupt pending */
> +#define GPIO_INT_STATUS_0  GPIO1_REG(0xA0)
> +#define GPIO_INT_STATUS_1  GPIO2_REG(0x70)
> +#define GPIO_INT_STATUS_2  GPIO1_REG(0xA4)
> +#define GPIO_INT_STATUS_3  GPIO1_REG(0xA8)
> +#define GPIO_INT_STATUS_4  GPIO1_REG(0xAC)
> +#define GPIO_INT_STATUS_5  GPIO1_REG(0xB0)
> +
> +#endif
> +
> +#if defined(CONFIG_ARCH_QSD8X50)
> +/* output value */
> +#define GPIO_OUT_0         GPIO1_REG(0x00)  /* gpio  15-0   */
> +#define GPIO_OUT_1         GPIO2_REG(0x00)  /* gpio  42-16  */
> +#define GPIO_OUT_2         GPIO1_REG(0x04)  /* gpio  67-43  */
> +#define GPIO_OUT_3         GPIO1_REG(0x08)  /* gpio  94-68  */
> +#define GPIO_OUT_4         GPIO1_REG(0x0C)  /* gpio 103-95  */
> +#define GPIO_OUT_5         GPIO1_REG(0x10)  /* gpio 121-104 */
> +#define GPIO_OUT_6         GPIO1_REG(0x14)  /* gpio 152-122 */
> +#define GPIO_OUT_7         GPIO1_REG(0x18)  /* gpio 164-153 */
> +
> +/* same pin map as above, output enable */
> +#define GPIO_OE_0          GPIO1_REG(0x20)
> +#define GPIO_OE_1          GPIO2_REG(0x08)
> +#define GPIO_OE_2          GPIO1_REG(0x24)
> +#define GPIO_OE_3          GPIO1_REG(0x28)
> +#define GPIO_OE_4          GPIO1_REG(0x2C)
> +#define GPIO_OE_5          GPIO1_REG(0x30)
> +#define GPIO_OE_6          GPIO1_REG(0x34)
> +#define GPIO_OE_7          GPIO1_REG(0x38)
> +
> +/* same pin map as above, input read */
> +#define GPIO_IN_0          GPIO1_REG(0x50)
> +#define GPIO_IN_1          GPIO2_REG(0x20)
> +#define GPIO_IN_2          GPIO1_REG(0x54)
> +#define GPIO_IN_3          GPIO1_REG(0x58)
> +#define GPIO_IN_4          GPIO1_REG(0x5C)
> +#define GPIO_IN_5          GPIO1_REG(0x60)
> +#define GPIO_IN_6          GPIO1_REG(0x64)
> +#define GPIO_IN_7          GPIO1_REG(0x68)
> +
> +/* same pin map as above, 1=edge 0=level interrup */
> +#define GPIO_INT_EDGE_0    GPIO1_REG(0x70)
> +#define GPIO_INT_EDGE_1    GPIO2_REG(0x50)
> +#define GPIO_INT_EDGE_2    GPIO1_REG(0x74)
> +#define GPIO_INT_EDGE_3    GPIO1_REG(0x78)
> +#define GPIO_INT_EDGE_4    GPIO1_REG(0x7C)
> +#define GPIO_INT_EDGE_5    GPIO1_REG(0x80)
> +#define GPIO_INT_EDGE_6    GPIO1_REG(0x84)
> +#define GPIO_INT_EDGE_7    GPIO1_REG(0x88)
> +
> +/* same pin map as above, 1=positive 0=negative */
> +#define GPIO_INT_POS_0     GPIO1_REG(0x90)
> +#define GPIO_INT_POS_1     GPIO2_REG(0x58)
> +#define GPIO_INT_POS_2     GPIO1_REG(0x94)
> +#define GPIO_INT_POS_3     GPIO1_REG(0x98)
> +#define GPIO_INT_POS_4     GPIO1_REG(0x9C)
> +#define GPIO_INT_POS_5     GPIO1_REG(0xA0)
> +#define GPIO_INT_POS_6     GPIO1_REG(0xA4)
> +#define GPIO_INT_POS_7     GPIO1_REG(0xA8)
> +
> +/* same pin map as above, interrupt enable */
> +#define GPIO_INT_EN_0      GPIO1_REG(0xB0)
> +#define GPIO_INT_EN_1      GPIO2_REG(0x60)
> +#define GPIO_INT_EN_2      GPIO1_REG(0xB4)
> +#define GPIO_INT_EN_3      GPIO1_REG(0xB8)
> +#define GPIO_INT_EN_4      GPIO1_REG(0xBC)
> +#define GPIO_INT_EN_5      GPIO1_REG(0xC0)
> +#define GPIO_INT_EN_6      GPIO1_REG(0xC4)
> +#define GPIO_INT_EN_7      GPIO1_REG(0xC8)
> +
> +/* same pin map as above, write 1 to clear interrupt */
> +#define GPIO_INT_CLEAR_0   GPIO1_REG(0xD0)
> +#define GPIO_INT_CLEAR_1   GPIO2_REG(0x68)
> +#define GPIO_INT_CLEAR_2   GPIO1_REG(0xD4)
> +#define GPIO_INT_CLEAR_3   GPIO1_REG(0xD8)
> +#define GPIO_INT_CLEAR_4   GPIO1_REG(0xDC)
> +#define GPIO_INT_CLEAR_5   GPIO1_REG(0xE0)
> +#define GPIO_INT_CLEAR_6   GPIO1_REG(0xE4)
> +#define GPIO_INT_CLEAR_7   GPIO1_REG(0xE8)
> +
> +/* same pin map as above, 1=interrupt pending */
> +#define GPIO_INT_STATUS_0  GPIO1_REG(0xF0)
> +#define GPIO_INT_STATUS_1  GPIO2_REG(0x70)
> +#define GPIO_INT_STATUS_2  GPIO1_REG(0xF4)
> +#define GPIO_INT_STATUS_3  GPIO1_REG(0xF8)
> +#define GPIO_INT_STATUS_4  GPIO1_REG(0xFC)
> +#define GPIO_INT_STATUS_5  GPIO1_REG(0x100)
> +#define GPIO_INT_STATUS_6  GPIO1_REG(0x104)
> +#define GPIO_INT_STATUS_7  GPIO1_REG(0x108)
> +
> +#endif
> +
> +#endif
> diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h
> new file mode 100644
> index 0000000..784e6f5
> --- /dev/null
> +++ b/arch/arm/mach-msm/include/mach/gpio.h
> @@ -0,0 +1,43 @@
> +/* linux/include/asm-arm/arch-msm/gpio.h
> + *
> + * Copyright (C) 2007 Google, Inc.
> + * Author: Mike Lockwood <lockwood@android.com>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef __ASM_ARCH_MSM_GPIO_H
> +#define __ASM_ARCH_MSM_GPIO_H
> +
> +#include <linux/interrupt.h>

Why is this included?

> +#include <asm-generic/gpio.h>
> +
> +static inline int gpio_get_value(unsigned gpio)
> +{
> +     return __gpio_get_value(gpio);
> +}
> +
> +static inline void gpio_set_value(unsigned gpio, int value)
> +{
> +     __gpio_set_value(gpio, value);
> +}
> +
> +static inline int gpio_cansleep(unsigned gpio)
> +{
> +     return __gpio_cansleep(gpio);
> +}
> +
> +static inline int gpio_to_irq(unsigned gpio)
> +{
> +     return __gpio_to_irq(gpio);
> +}
> +

These could all just be:

#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

> +#endif

Regards,
Hartley

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 1/4] arm: msm: gpio support
  2010-03-30 23:58   ` H Hartley Sweeten
@ 2010-03-31  1:14     ` Arve Hjønnevåg
  -1 siblings, 0 replies; 22+ messages in thread
From: Arve Hjønnevåg @ 2010-03-31  1:14 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: Daniel Walker, linux-arm-kernel, linux-arm-msm, Daniel Walker

On Tue, Mar 30, 2010 at 4:58 PM, H Hartley Sweeten
<hartleys@visionengravers.com> wrote:
> On Tuesday, March 30, 2010 4:12 PM, Daniel Walker wrote:
>> From: Daniel Walker <c_dwalke@quicinc.com>
...
>> +
>> +static void msm_gpio_irq_ack(unsigned int irq)
>> +{
>> +     unsigned long irq_flags;
>> +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
>> +     unsigned b;
>> +
>> +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
>> +
>> +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
>
> Urk... That's a bit confusing...
>
> You might want to make this a macro or an inline function with some kind
> of comment.
>

On a related note, why did you inline msm_gpio_clear_detect_status? It
is used from two other functions.

>> +
>> +#if MSM_GPIO_BROKEN_INT_CLEAR
>> +     /* Save interrupts that already triggered before we loose them. */
>> +     /* Any interrupt that triggers between the read of int_status */
>> +     /* and the write to int_clear will still be lost though. */
>> +     msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
>> +     msm_chip->int_status_copy &= ~b;
>> +#endif
>> +     writel(b, msm_chip->regs.int_clear);
>> +
>> +     msm_gpio_update_both_edge_detect(msm_chip);
>> +     spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
>> +}
>> +
...

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH 1/4] arm: msm: gpio support
@ 2010-03-31  1:14     ` Arve Hjønnevåg
  0 siblings, 0 replies; 22+ messages in thread
From: Arve Hjønnevåg @ 2010-03-31  1:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Mar 30, 2010 at 4:58 PM, H Hartley Sweeten
<hartleys@visionengravers.com> wrote:
> On Tuesday, March 30, 2010 4:12 PM, Daniel Walker wrote:
>> From: Daniel Walker <c_dwalke@quicinc.com>
...
>> +
>> +static void msm_gpio_irq_ack(unsigned int irq)
>> +{
>> + ? ? unsigned long irq_flags;
>> + ? ? struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
>> + ? ? unsigned b;
>> +
>> + ? ? spin_lock_irqsave(&msm_chip->lock, irq_flags);
>> +
>> + ? ? b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
>
> Urk... That's a bit confusing...
>
> You might want to make this a macro or an inline function with some kind
> of comment.
>

On a related note, why did you inline msm_gpio_clear_detect_status? It
is used from two other functions.

>> +
>> +#if MSM_GPIO_BROKEN_INT_CLEAR
>> + ? ? /* Save interrupts that already triggered before we loose them. */
>> + ? ? /* Any interrupt that triggers between the read of int_status */
>> + ? ? /* and the write to int_clear will still be lost though. */
>> + ? ? msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
>> + ? ? msm_chip->int_status_copy &= ~b;
>> +#endif
>> + ? ? writel(b, msm_chip->regs.int_clear);
>> +
>> + ? ? msm_gpio_update_both_edge_detect(msm_chip);
>> + ? ? spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
>> +}
>> +
...

-- 
Arve Hj?nnev?g

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 1/4] arm: msm: gpio support
  2010-03-31  1:14     ` Arve Hjønnevåg
@ 2010-03-31 14:03       ` Daniel Walker
  -1 siblings, 0 replies; 22+ messages in thread
From: Daniel Walker @ 2010-03-31 14:03 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: H Hartley Sweeten, linux-arm-kernel, linux-arm-msm

On Tue, 2010-03-30 at 18:14 -0700, Arve Hjønnevåg wrote:
> On Tue, Mar 30, 2010 at 4:58 PM, H Hartley Sweeten
> <hartleys@visionengravers.com> wrote:
> > On Tuesday, March 30, 2010 4:12 PM, Daniel Walker wrote:
> >> From: Daniel Walker <c_dwalke@quicinc.com>
> ...
> >> +
> >> +static void msm_gpio_irq_ack(unsigned int irq)
> >> +{
> >> +     unsigned long irq_flags;
> >> +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> >> +     unsigned b;
> >> +
> >> +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> >> +
> >> +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> >
> > Urk... That's a bit confusing...
> >
> > You might want to make this a macro or an inline function with some kind
> > of comment.
> >
> 
> On a related note, why did you inline msm_gpio_clear_detect_status? It
> is used from two other functions.
> 

You mean other places in the Android tree?

Daniel


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH 1/4] arm: msm: gpio support
@ 2010-03-31 14:03       ` Daniel Walker
  0 siblings, 0 replies; 22+ messages in thread
From: Daniel Walker @ 2010-03-31 14:03 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 2010-03-30 at 18:14 -0700, Arve Hj?nnev?g wrote:
> On Tue, Mar 30, 2010 at 4:58 PM, H Hartley Sweeten
> <hartleys@visionengravers.com> wrote:
> > On Tuesday, March 30, 2010 4:12 PM, Daniel Walker wrote:
> >> From: Daniel Walker <c_dwalke@quicinc.com>
> ...
> >> +
> >> +static void msm_gpio_irq_ack(unsigned int irq)
> >> +{
> >> +     unsigned long irq_flags;
> >> +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> >> +     unsigned b;
> >> +
> >> +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> >> +
> >> +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> >
> > Urk... That's a bit confusing...
> >
> > You might want to make this a macro or an inline function with some kind
> > of comment.
> >
> 
> On a related note, why did you inline msm_gpio_clear_detect_status? It
> is used from two other functions.
> 

You mean other places in the Android tree?

Daniel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* RE: [PATCH 1/4] arm: msm: gpio support
  2010-03-30 23:58   ` H Hartley Sweeten
@ 2010-03-31 14:12     ` Daniel Walker
  -1 siblings, 0 replies; 22+ messages in thread
From: Daniel Walker @ 2010-03-31 14:12 UTC (permalink / raw)
  To: H Hartley Sweeten; +Cc: linux-arm-kernel, linux-arm-msm

On Tue, 2010-03-30 at 18:58 -0500, H Hartley Sweeten wrote:
> On Tuesday, March 30, 2010 4:12 PM, Daniel Walker wrote:
> > From: Daniel Walker <c_dwalke@quicinc.com>
> >
> > This adds basic gpio support in MSM using gpiolib, as well as gpio
> > interrupt support.
> >
> > Signed-off-by: Daniel Walker <c_dwalke@quicinc.com>
> > ---
> >  arch/arm/Kconfig                      |    1 +
> >  arch/arm/mach-msm/Makefile            |    1 +
> >  arch/arm/mach-msm/gpio.c              |  428 +++++++++++++++++++++++++++++++++
> >  arch/arm/mach-msm/gpio_hw.h           |  187 ++++++++++++++
> >  arch/arm/mach-msm/include/mach/gpio.h |   43 ++++
> >  5 files changed, 660 insertions(+), 0 deletions(-)
> >  create mode 100644 arch/arm/mach-msm/gpio.c
> >  create mode 100644 arch/arm/mach-msm/gpio_hw.h
> >  create mode 100644 arch/arm/mach-msm/include/mach/gpio.h
> >
> > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> > index cadfe2e..5e29092 100644
> > --- a/arch/arm/Kconfig
> > +++ b/arch/arm/Kconfig
> > @@ -601,6 +601,7 @@ config ARCH_MSM
> >       select CPU_V6
> >       select GENERIC_TIME
> >       select GENERIC_CLOCKEVENTS
> > +     select ARCH_REQUIRE_GPIOLIB
> >       help
> >         Support for Qualcomm MSM7K based systems.  This runs on the ARM11
> >         apps processor of the MSM7K and depends on a shared memory
> > diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
> > index 147339c..47d47cb 100644
> > --- a/arch/arm/mach-msm/Makefile
> > +++ b/arch/arm/mach-msm/Makefile
> > @@ -4,6 +4,7 @@ obj-y += proc_comm.o
> >  obj-y += vreg.o
> >  obj-y += acpuclock-arm11.o
> >  obj-y += clock.o clock-7x01a.o
> > +obj-y += gpio.o
> >
> >  obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o
> >  obj-$(CONFIG_MSM_SMD) += last_radio_log.o
> > diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c
> > new file mode 100644
> > index 0000000..5b95885
> > --- /dev/null
> > +++ b/arch/arm/mach-msm/gpio.c
> > @@ -0,0 +1,428 @@
> > +/* linux/arch/arm/mach-msm/gpio.c
> > + *
> > + * Copyright (C) 2007 Google, Inc.
> > + * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
> > + *
> > + * This software is licensed under the terms of the GNU General Public
> > + * License version 2, as published by the Free Software Foundation, and
> > + * may be copied, distributed, and modified under those terms.
> > + *
> > + * 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/kernel.h>
> > +#include <linux/errno.h>
> > +#include <linux/slab.h>
> > +#include <linux/spinlock.h>
> > +
> > +#include <asm/io.h>
> 
> #include <linux/io.h>
> 
> > +#include <asm/irq.h>
> 
> This one is not needed.
> 
> > +#include <linux/irq.h>
> 
> This includes the <asm/irq.h> for you.
> 
> > +#include <linux/module.h>
> > +#include <linux/gpio.h>
> > +#include "gpio_hw.h"
> > +
> > +#include "smd_private.h"
> > +
> > +static int msm_gpio_debug_mask;
> > +module_param_named(debug_mask, msm_gpio_debug_mask, int,
> > +                S_IRUGO | S_IWUSR | S_IWGRP);
> > +
> > +#define MSM_GPIO_BROKEN_INT_CLEAR 1
> > +
> > +/* private gpio_configure flags */
> > +#define MSM_GPIOF_ENABLE_INTERRUPT      0x10000000
> > +#define MSM_GPIOF_DISABLE_INTERRUPT     0x20000000
> > +#define MSM_GPIOF_ENABLE_WAKE           0x40000000
> > +#define MSM_GPIOF_DISABLE_WAKE          0x80000000
> > +
> > +static int gpio_chip_to_irq(struct gpio_chip *chip, unsigned offset);
> > +static void gpio_chip_set(struct gpio_chip *chip, unsigned offset, int value);
> > +static int gpio_chip_get(struct gpio_chip *chip, unsigned offset);
> > +static int gpio_chip_direction_input(struct gpio_chip *chip, unsigned offset);
> > +static int gpio_chip_direction_output(struct gpio_chip *chip, unsigned offset,
> > +                                   int value);
> 
> Can the code be re-ordered to eliminate the prototypes?

Yeah, I'm sure I can work that out.

> > +
> > +struct msm_gpio_regs {
> > +     void __iomem *out;
> > +     void __iomem *in;
> > +     void __iomem *int_status;
> > +     void __iomem *int_clear;
> > +     void __iomem *int_en;
> > +     void __iomem *int_edge;
> > +     void __iomem *int_pos;
> > +     void __iomem *oe;
> > +};
> > +
> > +struct msm_gpio_chip {
> > +     struct gpio_chip        chip;
> > +     struct msm_gpio_regs    regs;
> > +     spinlock_t              lock;
> > +#if MSM_GPIO_BROKEN_INT_CLEAR
> > +     unsigned                int_status_copy;
> > +#endif
> > +     unsigned int            both_edge_detect;
> > +     unsigned int            int_enable[2]; /* 0: awake, 1: sleep */
> > +};
> > +
> > +#define MSM_GPIO_BANK(name, reg_num, start, end)                     \
> > +     {                                                               \
> > +             .regs = {                                               \
> > +                     .out =         GPIO_OUT_ ## reg_num,            \
> > +                     .in =          GPIO_IN_ ## reg_num ,            \
> > +                     .int_status =  GPIO_INT_STATUS_ ## reg_num,     \
> > +                     .int_clear =   GPIO_INT_CLEAR_ ## reg_num,      \
> > +                     .int_en =      GPIO_INT_EN_ ## reg_num,         \
> > +                     .int_edge =    GPIO_INT_EDGE_ ## reg_num,       \
> > +                     .int_pos =     GPIO_INT_POS_ ## reg_num,        \
> > +                     .oe =          GPIO_OE_ ## reg_num,             \
> > +             },                                                      \
> > +             .chip = {                                               \
> > +                     .label = name,                                  \
> > +                     .ngpio = end - start + 1,                       \
> > +                     .direction_input = gpio_chip_direction_input,   \
> > +                     .direction_output = gpio_chip_direction_output, \
> > +                     .get = gpio_chip_get,                           \
> > +                     .set = gpio_chip_set,                           \
> > +                     .to_irq = gpio_chip_to_irq,                     \
> > +                     .base = start,                                  \
> > +             }                                                       \
> > +     }
> > +
> > +struct msm_gpio_chip msm_gpio_chips[] = {
> > +     MSM_GPIO_BANK("bank0", 0, 0, 15),
> > +     MSM_GPIO_BANK("bank1", 1, 16, 42),
> > +     MSM_GPIO_BANK("bank2", 2, 43, 67),
> > +     MSM_GPIO_BANK("bank3", 3, 68, 94),
> > +#if defined(CONFIG_ARCH_QSD8X50)
> > +     MSM_GPIO_BANK("bank4", 4, 95, 103),
> > +     MSM_GPIO_BANK("bank5", 5, 104, 121),
> > +     MSM_GPIO_BANK("bank6", 6, 122, 152),
> > +     MSM_GPIO_BANK("bank7", 7, 153, 164),
> > +#else
> > +     MSM_GPIO_BANK("bank4", 4, 95, 106),
> > +     MSM_GPIO_BANK("bank5", 5, 107, 121),
> > +#endif
> > +};
> > +
> > +#define to_msm_gpio_chip(c) container_of(c, struct msm_gpio_chip, chip)
> > +
> > +static int gpio_chip_direction_input(struct gpio_chip *chip, unsigned offset)
> > +{
> > +     struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
> > +     unsigned long irq_flags;
> > +     unsigned b = 1U << (offset);
> 
> The () around offset are not needed.
> 
> > +     unsigned v;
> > +
> > +     spin_lock_irqsave(&old_chip->lock, irq_flags);
> > +     b = 1U << (offset);
> 
> Not needed.  You already did it above.
> 
> > +
> > +     v = readl(old_chip->regs.oe);
> > +     writel(v & (~b), old_chip->regs.oe);
> 
> Again, the () around ~b are not needed.  There are a number of these in this file.

Ok ..

> > +
> > +     spin_unlock_irqrestore(&old_chip->lock, irq_flags);
> > +
> > +     return 0;
> > +}
> > +
> > +static int gpio_chip_get(struct gpio_chip *chip, unsigned offset)
> > +{
> > +     struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
> > +     unsigned long irq_flags;
> > +     int ret = -ENOTSUPP;
> > +     unsigned b;
> > +
> > +     spin_lock_irqsave(&old_chip->lock, irq_flags);
> > +     b = 1U << (offset);
> > +
> > +     ret = (readl(old_chip->regs.in)) & b ? 1 : 0;
> > +
> > +     spin_unlock_irqrestore(&old_chip->lock, irq_flags);
> > +     return ret;
> > +}
> > +
> > +static inline int
> > +msm_gpio_write(struct msm_gpio_chip *chip, unsigned n, unsigned on)
> > +{
> > +     unsigned b = 1U << n;
> > +     unsigned v;
> > +
> > +     v = readl(chip->regs.out);
> > +     if (on)
> > +             writel(v | b, chip->regs.out);
> > +     else
> > +             writel(v & (~b), chip->regs.out);
> > +
> > +     return 0;
> > +}
> > +
> > +static int
> > +gpio_chip_direction_output(struct gpio_chip *chip, unsigned offset, int value)
> > +{
> > +     struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
> > +     unsigned long irq_flags;
> > +     unsigned v;
> > +
> > +     spin_lock_irqsave(&old_chip->lock, irq_flags);
> > +
> > +     msm_gpio_write(old_chip, offset, value);
> > +
> > +     v = readl(old_chip->regs.oe);
> > +     writel(v | offset, old_chip->regs.oe);
> > +
> > +     spin_unlock_irqrestore(&old_chip->lock, irq_flags);
> > +
> > +     return 0;
> > +}
> > +
> > +static void gpio_chip_set(struct gpio_chip *chip, unsigned offset, int value)
> > +{
> > +     struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
> > +     unsigned long irq_flags;
> > +
> > +     spin_lock_irqsave(&old_chip->lock, irq_flags);
> > +
> > +     msm_gpio_write(old_chip, offset, value);
> > +
> > +     spin_unlock_irqrestore(&old_chip->lock, irq_flags);
> > +}
> > +
> > +static int gpio_chip_to_irq(struct gpio_chip *chip, unsigned offset)
> > +{
> > +     struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
> > +     unsigned long irq_flags;
> > +     int ret;
> > +
> > +     spin_lock_irqsave(&old_chip->lock, irq_flags);
> > +     ret = MSM_GPIO_TO_INT(offset);
> > +     spin_unlock_irqrestore(&old_chip->lock, irq_flags);
> > +
> > +     return ret;
> > +}
> > +
> > +
> > +static void msm_gpio_update_both_edge_detect(struct msm_gpio_chip *msm_chip)
> > +{
> > +     int loop_limit = 100;
> > +     unsigned pol, val, val2, intstat;
> > +     do {
> > +             val = readl(msm_chip->regs.in);
> > +             pol = readl(msm_chip->regs.int_pos);
> > +             pol = (pol & ~msm_chip->both_edge_detect) |
> > +                   (~val & msm_chip->both_edge_detect);
> > +
> > +             writel(pol, msm_chip->regs.int_pos);
> > +
> > +             intstat = readl(msm_chip->regs.int_status);
> > +             val2 = readl(msm_chip->regs.in);
> > +
> > +             if (((val ^ val2) & msm_chip->both_edge_detect & ~intstat) == 0)
> > +                     return;
> > +     } while (loop_limit-- > 0);
> > +     printk(KERN_ERR "msm_gpio_update_both_edge_detect, failed to reach stable state %x != %x\n", val, val2);
> > +}
> > +
> > +static void msm_gpio_irq_ack(unsigned int irq)
> > +{
> > +     unsigned long irq_flags;
> > +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> > +     unsigned b;
> > +
> > +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> > +
> > +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> 
> Urk... That's a bit confusing...
> 
> You might want to make this a macro or an inline function with some kind
> of comment.

Ok ..

> > +
> > +#if MSM_GPIO_BROKEN_INT_CLEAR
> > +     /* Save interrupts that already triggered before we loose them. */
> > +     /* Any interrupt that triggers between the read of int_status */
> > +     /* and the write to int_clear will still be lost though. */
> > +     msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
> > +     msm_chip->int_status_copy &= ~b;
> > +#endif
> > +     writel(b, msm_chip->regs.int_clear);
> > +
> > +     msm_gpio_update_both_edge_detect(msm_chip);
> > +     spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
> > +}
> > +
> > +static void msm_gpio_irq_mask(unsigned int irq)
> > +{
> > +     unsigned long irq_flags;
> > +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> > +     unsigned b, v;
> > +
> > +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> > +
> > +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> > +
> > +     v = readl(msm_chip->regs.int_edge);
> > +     /* level triggered interrupts are also latched */
> > +     if (!(v & b)) {
> > +
> > +     #if MSM_GPIO_BROKEN_INT_CLEAR
> 
> Align the #if/#endif to the first column.

Yeah .

> > +             /* Save interrupts that already triggered before we loose
> > +              * them. Any interrupt that triggers between the read of
> > +              * int_status and the write to int_clear will still be
> > +              * lost though.
> > +              */
> > +             msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
> > +             msm_chip->int_status_copy &= ~b;
> > +     #endif
> > +             writel(b, msm_chip->regs.int_clear);
> > +             msm_gpio_update_both_edge_detect(msm_chip);
> > +     }
> > +
> > +     msm_chip->int_enable[0] &= ~b;
> > +     writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
> > +
> > +     spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
> > +}
> > +
> > +static void msm_gpio_irq_unmask(unsigned int irq)
> > +{
> > +     unsigned long irq_flags;
> > +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> > +     unsigned b, v;
> > +
> > +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> > +
> > +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> > +
> > +     v = readl(msm_chip->regs.int_edge);
> > +     /* level triggered interrupts are also latched */
> > +     if (!(v & b)) {
> > +
> > +     #if MSM_GPIO_BROKEN_INT_CLEAR
> > +             /* Save interrupts that already triggered before we loose
> > +              * them. Any interrupt that triggers between the read of
> > +              * int_status and the write to int_clear will still be
> > +              * lost though.
> > +              */
> > +             msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
> > +             msm_chip->int_status_copy &= ~b;
> > +     #endif
> > +             writel(b, msm_chip->regs.int_clear);
> > +             msm_gpio_update_both_edge_detect(msm_chip);
> > +     }
> > +
> > +     msm_chip->int_enable[0] |= b;
> > +     writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
> > +
> > +     spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
> > +}
> > +
> > +static int msm_gpio_irq_set_wake(unsigned int irq, unsigned int on)
> > +{
> > +     unsigned long irq_flags;
> > +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> > +     unsigned b;
> > +
> > +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> > +
> > +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> > +
> > +     if (on)
> > +             msm_chip->int_enable[1] |= b;
> > +     else
> > +             msm_chip->int_enable[1] &= ~b;
> > +
> > +     spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
> > +
> > +     return 0;
> > +}
> > +
> > +
> > +static int msm_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
> > +{
> > +     unsigned long irq_flags;
> > +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> > +     unsigned b, v;
> > +
> > +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> > +
> > +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> > +
> > +     v = readl(msm_chip->regs.int_edge);
> > +     if (flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) {
> > +             writel(v | b, msm_chip->regs.int_edge);
> > +             irq_desc[MSM_GPIO_TO_INT(irq - FIRST_GPIO_IRQ)].handle_irq = handle_edge_irq;
> > +     } else {
> > +             writel(v & (~b), msm_chip->regs.int_edge);
> > +             irq_desc[MSM_GPIO_TO_INT(irq - FIRST_GPIO_IRQ)].handle_irq = handle_level_irq;
> > +     }
> > +     if ((flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) ==
> > +                      (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) {
> > +             msm_chip->both_edge_detect |= b;
> > +             msm_gpio_update_both_edge_detect(msm_chip);
> > +     } else {
> > +             msm_chip->both_edge_detect &= ~b;
> > +             v = readl(msm_chip->regs.int_pos);
> > +             if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
> > +                     writel(v | b, msm_chip->regs.int_pos);
> > +             else
> > +                     writel(v & (~b), msm_chip->regs.int_pos);
> > +
> > +     }
> > +     spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
> > +     return 0;
> > +}
> > +
> > +static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
> > +{
> > +     int i, j, m;
> > +     unsigned v;
> > +
> > +     for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
> > +             struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i];
> > +             v = readl(msm_chip->regs.int_status);
> > +             v &= msm_chip->int_enable[0];
> > +             while (v) {
> > +                     m = v & -v;
> > +                     j = fls(m) - 1;
> > +                     v &= ~m;
> > +                     generic_handle_irq(FIRST_GPIO_IRQ + msm_chip->chip.base + j);
> > +             }
> > +     }
> > +     desc->chip->ack(irq);
> > +}
> > +
> > +static struct irq_chip msm_gpio_irq_chip = {
> > +     .name      = "msmgpio",
> > +     .ack       = msm_gpio_irq_ack,
> > +     .mask      = msm_gpio_irq_mask,
> > +     .unmask    = msm_gpio_irq_unmask,
> > +     .set_wake  = msm_gpio_irq_set_wake,
> > +     .set_type  = msm_gpio_irq_set_type,
> > +};
> > +
> > +static int __init msm_init_gpio(void)
> > +{
> > +     int i, j = 0;
> > +     for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
> > +             if (i - FIRST_GPIO_IRQ > msm_gpio_chips[j].chip.ngpio - 1)
> > +                     j++;
> > +             set_irq_chip_data(i, &msm_gpio_chips[j]);
> > +             set_irq_chip(i, &msm_gpio_irq_chip);
> > +             set_irq_handler(i, handle_edge_irq);
> > +             set_irq_flags(i, IRQF_VALID);
> > +     }
> > +
> > +     for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
> > +             writel(0, msm_gpio_chips[i].regs.int_en);
> > +             spin_lock_init(&msm_gpio_chips[i].lock);
> > +             gpiochip_add(&msm_gpio_chips[i].chip);
> > +     }
> > +
> > +     set_irq_chained_handler(INT_GPIO_GROUP1, msm_gpio_irq_handler);
> > +     set_irq_chained_handler(INT_GPIO_GROUP2, msm_gpio_irq_handler);
> > +     set_irq_wake(INT_GPIO_GROUP1, 1);
> > +     set_irq_wake(INT_GPIO_GROUP2, 2);
> > +
> > +     return 0;
> > +}
> > +
> > +postcore_initcall(msm_init_gpio);
> > diff --git a/arch/arm/mach-msm/gpio_hw.h b/arch/arm/mach-msm/gpio_hw.h
> > new file mode 100644
> > index 0000000..f7e1b5b
> > --- /dev/null
> > +++ b/arch/arm/mach-msm/gpio_hw.h
> > @@ -0,0 +1,187 @@
> > +/* arch/arm/mach-msm/gpio_hw.h
> > + *
> > + * Copyright (C) 2007 Google, Inc.
> > + * Author: Brian Swetland <swetland@google.com>
> > + *
> > + * This software is licensed under the terms of the GNU General Public
> > + * License version 2, as published by the Free Software Foundation, and
> > + * may be copied, distributed, and modified under those terms.
> > + *
> > + * 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.
> > + *
> > + */
> > +
> > +#ifndef __ARCH_ARM_MACH_MSM_GPIO_HW_H
> > +#define __ARCH_ARM_MACH_MSM_GPIO_HW_H
> > +
> > +#include <mach/msm_iomap.h>
> > +
> > +/* see 80-VA736-2 Rev C pp 695-751
> > +**
> > +** These are actually the *shadow* gpio registers, since the
> > +** real ones (which allow full access) are only available to the
> > +** ARM9 side of the world.
> > +**
> > +** Since the _BASE need to be page-aligned when we're mapping them
> > +** to virtual addresses, adjust for the additional offset in these
> > +** macros.
> > +*/
> > +
> 
> All the #define'd names in this file are pretty generic.  You should
> probably add a prefix (MSM_ ?) to all of them.
> 
> Also, you should use tabs instead of spaces between the #define <name><tabs><something>

No problem ..

> > +#define GPIO1_REG(off) (MSM_GPIO1_BASE + 0x800 + (off))
> > +#define GPIO2_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off))
> > +
> > +#if defined(CONFIG_ARCH_MSM7X00A)
> > +
> > +/* output value */
> > +#define GPIO_OUT_0         GPIO1_REG(0x00)  /* gpio  15-0  */
> > +#define GPIO_OUT_1         GPIO2_REG(0x00)  /* gpio  42-16 */
> > +#define GPIO_OUT_2         GPIO1_REG(0x04)  /* gpio  67-43 */
> > +#define GPIO_OUT_3         GPIO1_REG(0x08)  /* gpio  94-68 */
> > +#define GPIO_OUT_4         GPIO1_REG(0x0C)  /* gpio 106-95 */
> > +#define GPIO_OUT_5         GPIO1_REG(0x50)  /* gpio 107-121 */
> > +
> > +/* same pin map as above, output enable */
> > +#define GPIO_OE_0          GPIO1_REG(0x10)
> > +#define GPIO_OE_1          GPIO2_REG(0x08)
> > +#define GPIO_OE_2          GPIO1_REG(0x14)
> > +#define GPIO_OE_3          GPIO1_REG(0x18)
> > +#define GPIO_OE_4          GPIO1_REG(0x1C)
> > +#define GPIO_OE_5          GPIO1_REG(0x54)
> > +
> > +/* same pin map as above, input read */
> > +#define GPIO_IN_0          GPIO1_REG(0x34)
> > +#define GPIO_IN_1          GPIO2_REG(0x20)
> > +#define GPIO_IN_2          GPIO1_REG(0x38)
> > +#define GPIO_IN_3          GPIO1_REG(0x3C)
> > +#define GPIO_IN_4          GPIO1_REG(0x40)
> > +#define GPIO_IN_5          GPIO1_REG(0x44)
> > +
> > +/* same pin map as above, 1=edge 0=level interrup */
> > +#define GPIO_INT_EDGE_0    GPIO1_REG(0x60)
> > +#define GPIO_INT_EDGE_1    GPIO2_REG(0x50)
> > +#define GPIO_INT_EDGE_2    GPIO1_REG(0x64)
> > +#define GPIO_INT_EDGE_3    GPIO1_REG(0x68)
> > +#define GPIO_INT_EDGE_4    GPIO1_REG(0x6C)
> > +#define GPIO_INT_EDGE_5    GPIO1_REG(0xC0)
> > +
> > +/* same pin map as above, 1=positive 0=negative */
> > +#define GPIO_INT_POS_0     GPIO1_REG(0x70)
> > +#define GPIO_INT_POS_1     GPIO2_REG(0x58)
> > +#define GPIO_INT_POS_2     GPIO1_REG(0x74)
> > +#define GPIO_INT_POS_3     GPIO1_REG(0x78)
> > +#define GPIO_INT_POS_4     GPIO1_REG(0x7C)
> > +#define GPIO_INT_POS_5     GPIO1_REG(0xBC)
> > +
> > +/* same pin map as above, interrupt enable */
> > +#define GPIO_INT_EN_0      GPIO1_REG(0x80)
> > +#define GPIO_INT_EN_1      GPIO2_REG(0x60)
> > +#define GPIO_INT_EN_2      GPIO1_REG(0x84)
> > +#define GPIO_INT_EN_3      GPIO1_REG(0x88)
> > +#define GPIO_INT_EN_4      GPIO1_REG(0x8C)
> > +#define GPIO_INT_EN_5      GPIO1_REG(0xB8)
> > +
> > +/* same pin map as above, write 1 to clear interrupt */
> > +#define GPIO_INT_CLEAR_0   GPIO1_REG(0x90)
> > +#define GPIO_INT_CLEAR_1   GPIO2_REG(0x68)
> > +#define GPIO_INT_CLEAR_2   GPIO1_REG(0x94)
> > +#define GPIO_INT_CLEAR_3   GPIO1_REG(0x98)
> > +#define GPIO_INT_CLEAR_4   GPIO1_REG(0x9C)
> > +#define GPIO_INT_CLEAR_5   GPIO1_REG(0xB4)
> > +
> > +/* same pin map as above, 1=interrupt pending */
> > +#define GPIO_INT_STATUS_0  GPIO1_REG(0xA0)
> > +#define GPIO_INT_STATUS_1  GPIO2_REG(0x70)
> > +#define GPIO_INT_STATUS_2  GPIO1_REG(0xA4)
> > +#define GPIO_INT_STATUS_3  GPIO1_REG(0xA8)
> > +#define GPIO_INT_STATUS_4  GPIO1_REG(0xAC)
> > +#define GPIO_INT_STATUS_5  GPIO1_REG(0xB0)
> > +
> > +#endif
> > +
> > +#if defined(CONFIG_ARCH_QSD8X50)
> > +/* output value */
> > +#define GPIO_OUT_0         GPIO1_REG(0x00)  /* gpio  15-0   */
> > +#define GPIO_OUT_1         GPIO2_REG(0x00)  /* gpio  42-16  */
> > +#define GPIO_OUT_2         GPIO1_REG(0x04)  /* gpio  67-43  */
> > +#define GPIO_OUT_3         GPIO1_REG(0x08)  /* gpio  94-68  */
> > +#define GPIO_OUT_4         GPIO1_REG(0x0C)  /* gpio 103-95  */
> > +#define GPIO_OUT_5         GPIO1_REG(0x10)  /* gpio 121-104 */
> > +#define GPIO_OUT_6         GPIO1_REG(0x14)  /* gpio 152-122 */
> > +#define GPIO_OUT_7         GPIO1_REG(0x18)  /* gpio 164-153 */
> > +
> > +/* same pin map as above, output enable */
> > +#define GPIO_OE_0          GPIO1_REG(0x20)
> > +#define GPIO_OE_1          GPIO2_REG(0x08)
> > +#define GPIO_OE_2          GPIO1_REG(0x24)
> > +#define GPIO_OE_3          GPIO1_REG(0x28)
> > +#define GPIO_OE_4          GPIO1_REG(0x2C)
> > +#define GPIO_OE_5          GPIO1_REG(0x30)
> > +#define GPIO_OE_6          GPIO1_REG(0x34)
> > +#define GPIO_OE_7          GPIO1_REG(0x38)
> > +
> > +/* same pin map as above, input read */
> > +#define GPIO_IN_0          GPIO1_REG(0x50)
> > +#define GPIO_IN_1          GPIO2_REG(0x20)
> > +#define GPIO_IN_2          GPIO1_REG(0x54)
> > +#define GPIO_IN_3          GPIO1_REG(0x58)
> > +#define GPIO_IN_4          GPIO1_REG(0x5C)
> > +#define GPIO_IN_5          GPIO1_REG(0x60)
> > +#define GPIO_IN_6          GPIO1_REG(0x64)
> > +#define GPIO_IN_7          GPIO1_REG(0x68)
> > +
> > +/* same pin map as above, 1=edge 0=level interrup */
> > +#define GPIO_INT_EDGE_0    GPIO1_REG(0x70)
> > +#define GPIO_INT_EDGE_1    GPIO2_REG(0x50)
> > +#define GPIO_INT_EDGE_2    GPIO1_REG(0x74)
> > +#define GPIO_INT_EDGE_3    GPIO1_REG(0x78)
> > +#define GPIO_INT_EDGE_4    GPIO1_REG(0x7C)
> > +#define GPIO_INT_EDGE_5    GPIO1_REG(0x80)
> > +#define GPIO_INT_EDGE_6    GPIO1_REG(0x84)
> > +#define GPIO_INT_EDGE_7    GPIO1_REG(0x88)
> > +
> > +/* same pin map as above, 1=positive 0=negative */
> > +#define GPIO_INT_POS_0     GPIO1_REG(0x90)
> > +#define GPIO_INT_POS_1     GPIO2_REG(0x58)
> > +#define GPIO_INT_POS_2     GPIO1_REG(0x94)
> > +#define GPIO_INT_POS_3     GPIO1_REG(0x98)
> > +#define GPIO_INT_POS_4     GPIO1_REG(0x9C)
> > +#define GPIO_INT_POS_5     GPIO1_REG(0xA0)
> > +#define GPIO_INT_POS_6     GPIO1_REG(0xA4)
> > +#define GPIO_INT_POS_7     GPIO1_REG(0xA8)
> > +
> > +/* same pin map as above, interrupt enable */
> > +#define GPIO_INT_EN_0      GPIO1_REG(0xB0)
> > +#define GPIO_INT_EN_1      GPIO2_REG(0x60)
> > +#define GPIO_INT_EN_2      GPIO1_REG(0xB4)
> > +#define GPIO_INT_EN_3      GPIO1_REG(0xB8)
> > +#define GPIO_INT_EN_4      GPIO1_REG(0xBC)
> > +#define GPIO_INT_EN_5      GPIO1_REG(0xC0)
> > +#define GPIO_INT_EN_6      GPIO1_REG(0xC4)
> > +#define GPIO_INT_EN_7      GPIO1_REG(0xC8)
> > +
> > +/* same pin map as above, write 1 to clear interrupt */
> > +#define GPIO_INT_CLEAR_0   GPIO1_REG(0xD0)
> > +#define GPIO_INT_CLEAR_1   GPIO2_REG(0x68)
> > +#define GPIO_INT_CLEAR_2   GPIO1_REG(0xD4)
> > +#define GPIO_INT_CLEAR_3   GPIO1_REG(0xD8)
> > +#define GPIO_INT_CLEAR_4   GPIO1_REG(0xDC)
> > +#define GPIO_INT_CLEAR_5   GPIO1_REG(0xE0)
> > +#define GPIO_INT_CLEAR_6   GPIO1_REG(0xE4)
> > +#define GPIO_INT_CLEAR_7   GPIO1_REG(0xE8)
> > +
> > +/* same pin map as above, 1=interrupt pending */
> > +#define GPIO_INT_STATUS_0  GPIO1_REG(0xF0)
> > +#define GPIO_INT_STATUS_1  GPIO2_REG(0x70)
> > +#define GPIO_INT_STATUS_2  GPIO1_REG(0xF4)
> > +#define GPIO_INT_STATUS_3  GPIO1_REG(0xF8)
> > +#define GPIO_INT_STATUS_4  GPIO1_REG(0xFC)
> > +#define GPIO_INT_STATUS_5  GPIO1_REG(0x100)
> > +#define GPIO_INT_STATUS_6  GPIO1_REG(0x104)
> > +#define GPIO_INT_STATUS_7  GPIO1_REG(0x108)
> > +
> > +#endif
> > +
> > +#endif
> > diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h
> > new file mode 100644
> > index 0000000..784e6f5
> > --- /dev/null
> > +++ b/arch/arm/mach-msm/include/mach/gpio.h
> > @@ -0,0 +1,43 @@
> > +/* linux/include/asm-arm/arch-msm/gpio.h
> > + *
> > + * Copyright (C) 2007 Google, Inc.
> > + * Author: Mike Lockwood <lockwood@android.com>
> > + *
> > + * This software is licensed under the terms of the GNU General Public
> > + * License version 2, as published by the Free Software Foundation, and
> > + * may be copied, distributed, and modified under those terms.
> > + *
> > + * 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.
> > + *
> > + */
> > +
> > +#ifndef __ASM_ARCH_MSM_GPIO_H
> > +#define __ASM_ARCH_MSM_GPIO_H
> > +
> > +#include <linux/interrupt.h>
> 
> Why is this included?

Have to ask Mike Lockwood I guess, but I try removing it.

> > +#include <asm-generic/gpio.h>
> > +
> > +static inline int gpio_get_value(unsigned gpio)
> > +{
> > +     return __gpio_get_value(gpio);
> > +}
> > +
> > +static inline void gpio_set_value(unsigned gpio, int value)
> > +{
> > +     __gpio_set_value(gpio, value);
> > +}
> > +
> > +static inline int gpio_cansleep(unsigned gpio)
> > +{
> > +     return __gpio_cansleep(gpio);
> > +}
> > +
> > +static inline int gpio_to_irq(unsigned gpio)
> > +{
> > +     return __gpio_to_irq(gpio);
> > +}
> > +
> 
> These could all just be:
> 
> #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


Much cleaner .. I'll do that. 

Thanks for all the good comments.

Daniel


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH 1/4] arm: msm: gpio support
@ 2010-03-31 14:12     ` Daniel Walker
  0 siblings, 0 replies; 22+ messages in thread
From: Daniel Walker @ 2010-03-31 14:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 2010-03-30 at 18:58 -0500, H Hartley Sweeten wrote:
> On Tuesday, March 30, 2010 4:12 PM, Daniel Walker wrote:
> > From: Daniel Walker <c_dwalke@quicinc.com>
> >
> > This adds basic gpio support in MSM using gpiolib, as well as gpio
> > interrupt support.
> >
> > Signed-off-by: Daniel Walker <c_dwalke@quicinc.com>
> > ---
> >  arch/arm/Kconfig                      |    1 +
> >  arch/arm/mach-msm/Makefile            |    1 +
> >  arch/arm/mach-msm/gpio.c              |  428 +++++++++++++++++++++++++++++++++
> >  arch/arm/mach-msm/gpio_hw.h           |  187 ++++++++++++++
> >  arch/arm/mach-msm/include/mach/gpio.h |   43 ++++
> >  5 files changed, 660 insertions(+), 0 deletions(-)
> >  create mode 100644 arch/arm/mach-msm/gpio.c
> >  create mode 100644 arch/arm/mach-msm/gpio_hw.h
> >  create mode 100644 arch/arm/mach-msm/include/mach/gpio.h
> >
> > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> > index cadfe2e..5e29092 100644
> > --- a/arch/arm/Kconfig
> > +++ b/arch/arm/Kconfig
> > @@ -601,6 +601,7 @@ config ARCH_MSM
> >       select CPU_V6
> >       select GENERIC_TIME
> >       select GENERIC_CLOCKEVENTS
> > +     select ARCH_REQUIRE_GPIOLIB
> >       help
> >         Support for Qualcomm MSM7K based systems.  This runs on the ARM11
> >         apps processor of the MSM7K and depends on a shared memory
> > diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
> > index 147339c..47d47cb 100644
> > --- a/arch/arm/mach-msm/Makefile
> > +++ b/arch/arm/mach-msm/Makefile
> > @@ -4,6 +4,7 @@ obj-y += proc_comm.o
> >  obj-y += vreg.o
> >  obj-y += acpuclock-arm11.o
> >  obj-y += clock.o clock-7x01a.o
> > +obj-y += gpio.o
> >
> >  obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o
> >  obj-$(CONFIG_MSM_SMD) += last_radio_log.o
> > diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c
> > new file mode 100644
> > index 0000000..5b95885
> > --- /dev/null
> > +++ b/arch/arm/mach-msm/gpio.c
> > @@ -0,0 +1,428 @@
> > +/* linux/arch/arm/mach-msm/gpio.c
> > + *
> > + * Copyright (C) 2007 Google, Inc.
> > + * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
> > + *
> > + * This software is licensed under the terms of the GNU General Public
> > + * License version 2, as published by the Free Software Foundation, and
> > + * may be copied, distributed, and modified under those terms.
> > + *
> > + * 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/kernel.h>
> > +#include <linux/errno.h>
> > +#include <linux/slab.h>
> > +#include <linux/spinlock.h>
> > +
> > +#include <asm/io.h>
> 
> #include <linux/io.h>
> 
> > +#include <asm/irq.h>
> 
> This one is not needed.
> 
> > +#include <linux/irq.h>
> 
> This includes the <asm/irq.h> for you.
> 
> > +#include <linux/module.h>
> > +#include <linux/gpio.h>
> > +#include "gpio_hw.h"
> > +
> > +#include "smd_private.h"
> > +
> > +static int msm_gpio_debug_mask;
> > +module_param_named(debug_mask, msm_gpio_debug_mask, int,
> > +                S_IRUGO | S_IWUSR | S_IWGRP);
> > +
> > +#define MSM_GPIO_BROKEN_INT_CLEAR 1
> > +
> > +/* private gpio_configure flags */
> > +#define MSM_GPIOF_ENABLE_INTERRUPT      0x10000000
> > +#define MSM_GPIOF_DISABLE_INTERRUPT     0x20000000
> > +#define MSM_GPIOF_ENABLE_WAKE           0x40000000
> > +#define MSM_GPIOF_DISABLE_WAKE          0x80000000
> > +
> > +static int gpio_chip_to_irq(struct gpio_chip *chip, unsigned offset);
> > +static void gpio_chip_set(struct gpio_chip *chip, unsigned offset, int value);
> > +static int gpio_chip_get(struct gpio_chip *chip, unsigned offset);
> > +static int gpio_chip_direction_input(struct gpio_chip *chip, unsigned offset);
> > +static int gpio_chip_direction_output(struct gpio_chip *chip, unsigned offset,
> > +                                   int value);
> 
> Can the code be re-ordered to eliminate the prototypes?

Yeah, I'm sure I can work that out.

> > +
> > +struct msm_gpio_regs {
> > +     void __iomem *out;
> > +     void __iomem *in;
> > +     void __iomem *int_status;
> > +     void __iomem *int_clear;
> > +     void __iomem *int_en;
> > +     void __iomem *int_edge;
> > +     void __iomem *int_pos;
> > +     void __iomem *oe;
> > +};
> > +
> > +struct msm_gpio_chip {
> > +     struct gpio_chip        chip;
> > +     struct msm_gpio_regs    regs;
> > +     spinlock_t              lock;
> > +#if MSM_GPIO_BROKEN_INT_CLEAR
> > +     unsigned                int_status_copy;
> > +#endif
> > +     unsigned int            both_edge_detect;
> > +     unsigned int            int_enable[2]; /* 0: awake, 1: sleep */
> > +};
> > +
> > +#define MSM_GPIO_BANK(name, reg_num, start, end)                     \
> > +     {                                                               \
> > +             .regs = {                                               \
> > +                     .out =         GPIO_OUT_ ## reg_num,            \
> > +                     .in =          GPIO_IN_ ## reg_num ,            \
> > +                     .int_status =  GPIO_INT_STATUS_ ## reg_num,     \
> > +                     .int_clear =   GPIO_INT_CLEAR_ ## reg_num,      \
> > +                     .int_en =      GPIO_INT_EN_ ## reg_num,         \
> > +                     .int_edge =    GPIO_INT_EDGE_ ## reg_num,       \
> > +                     .int_pos =     GPIO_INT_POS_ ## reg_num,        \
> > +                     .oe =          GPIO_OE_ ## reg_num,             \
> > +             },                                                      \
> > +             .chip = {                                               \
> > +                     .label = name,                                  \
> > +                     .ngpio = end - start + 1,                       \
> > +                     .direction_input = gpio_chip_direction_input,   \
> > +                     .direction_output = gpio_chip_direction_output, \
> > +                     .get = gpio_chip_get,                           \
> > +                     .set = gpio_chip_set,                           \
> > +                     .to_irq = gpio_chip_to_irq,                     \
> > +                     .base = start,                                  \
> > +             }                                                       \
> > +     }
> > +
> > +struct msm_gpio_chip msm_gpio_chips[] = {
> > +     MSM_GPIO_BANK("bank0", 0, 0, 15),
> > +     MSM_GPIO_BANK("bank1", 1, 16, 42),
> > +     MSM_GPIO_BANK("bank2", 2, 43, 67),
> > +     MSM_GPIO_BANK("bank3", 3, 68, 94),
> > +#if defined(CONFIG_ARCH_QSD8X50)
> > +     MSM_GPIO_BANK("bank4", 4, 95, 103),
> > +     MSM_GPIO_BANK("bank5", 5, 104, 121),
> > +     MSM_GPIO_BANK("bank6", 6, 122, 152),
> > +     MSM_GPIO_BANK("bank7", 7, 153, 164),
> > +#else
> > +     MSM_GPIO_BANK("bank4", 4, 95, 106),
> > +     MSM_GPIO_BANK("bank5", 5, 107, 121),
> > +#endif
> > +};
> > +
> > +#define to_msm_gpio_chip(c) container_of(c, struct msm_gpio_chip, chip)
> > +
> > +static int gpio_chip_direction_input(struct gpio_chip *chip, unsigned offset)
> > +{
> > +     struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
> > +     unsigned long irq_flags;
> > +     unsigned b = 1U << (offset);
> 
> The () around offset are not needed.
> 
> > +     unsigned v;
> > +
> > +     spin_lock_irqsave(&old_chip->lock, irq_flags);
> > +     b = 1U << (offset);
> 
> Not needed.  You already did it above.
> 
> > +
> > +     v = readl(old_chip->regs.oe);
> > +     writel(v & (~b), old_chip->regs.oe);
> 
> Again, the () around ~b are not needed.  There are a number of these in this file.

Ok ..

> > +
> > +     spin_unlock_irqrestore(&old_chip->lock, irq_flags);
> > +
> > +     return 0;
> > +}
> > +
> > +static int gpio_chip_get(struct gpio_chip *chip, unsigned offset)
> > +{
> > +     struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
> > +     unsigned long irq_flags;
> > +     int ret = -ENOTSUPP;
> > +     unsigned b;
> > +
> > +     spin_lock_irqsave(&old_chip->lock, irq_flags);
> > +     b = 1U << (offset);
> > +
> > +     ret = (readl(old_chip->regs.in)) & b ? 1 : 0;
> > +
> > +     spin_unlock_irqrestore(&old_chip->lock, irq_flags);
> > +     return ret;
> > +}
> > +
> > +static inline int
> > +msm_gpio_write(struct msm_gpio_chip *chip, unsigned n, unsigned on)
> > +{
> > +     unsigned b = 1U << n;
> > +     unsigned v;
> > +
> > +     v = readl(chip->regs.out);
> > +     if (on)
> > +             writel(v | b, chip->regs.out);
> > +     else
> > +             writel(v & (~b), chip->regs.out);
> > +
> > +     return 0;
> > +}
> > +
> > +static int
> > +gpio_chip_direction_output(struct gpio_chip *chip, unsigned offset, int value)
> > +{
> > +     struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
> > +     unsigned long irq_flags;
> > +     unsigned v;
> > +
> > +     spin_lock_irqsave(&old_chip->lock, irq_flags);
> > +
> > +     msm_gpio_write(old_chip, offset, value);
> > +
> > +     v = readl(old_chip->regs.oe);
> > +     writel(v | offset, old_chip->regs.oe);
> > +
> > +     spin_unlock_irqrestore(&old_chip->lock, irq_flags);
> > +
> > +     return 0;
> > +}
> > +
> > +static void gpio_chip_set(struct gpio_chip *chip, unsigned offset, int value)
> > +{
> > +     struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
> > +     unsigned long irq_flags;
> > +
> > +     spin_lock_irqsave(&old_chip->lock, irq_flags);
> > +
> > +     msm_gpio_write(old_chip, offset, value);
> > +
> > +     spin_unlock_irqrestore(&old_chip->lock, irq_flags);
> > +}
> > +
> > +static int gpio_chip_to_irq(struct gpio_chip *chip, unsigned offset)
> > +{
> > +     struct msm_gpio_chip *old_chip = to_msm_gpio_chip(chip);
> > +     unsigned long irq_flags;
> > +     int ret;
> > +
> > +     spin_lock_irqsave(&old_chip->lock, irq_flags);
> > +     ret = MSM_GPIO_TO_INT(offset);
> > +     spin_unlock_irqrestore(&old_chip->lock, irq_flags);
> > +
> > +     return ret;
> > +}
> > +
> > +
> > +static void msm_gpio_update_both_edge_detect(struct msm_gpio_chip *msm_chip)
> > +{
> > +     int loop_limit = 100;
> > +     unsigned pol, val, val2, intstat;
> > +     do {
> > +             val = readl(msm_chip->regs.in);
> > +             pol = readl(msm_chip->regs.int_pos);
> > +             pol = (pol & ~msm_chip->both_edge_detect) |
> > +                   (~val & msm_chip->both_edge_detect);
> > +
> > +             writel(pol, msm_chip->regs.int_pos);
> > +
> > +             intstat = readl(msm_chip->regs.int_status);
> > +             val2 = readl(msm_chip->regs.in);
> > +
> > +             if (((val ^ val2) & msm_chip->both_edge_detect & ~intstat) == 0)
> > +                     return;
> > +     } while (loop_limit-- > 0);
> > +     printk(KERN_ERR "msm_gpio_update_both_edge_detect, failed to reach stable state %x != %x\n", val, val2);
> > +}
> > +
> > +static void msm_gpio_irq_ack(unsigned int irq)
> > +{
> > +     unsigned long irq_flags;
> > +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> > +     unsigned b;
> > +
> > +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> > +
> > +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> 
> Urk... That's a bit confusing...
> 
> You might want to make this a macro or an inline function with some kind
> of comment.

Ok ..

> > +
> > +#if MSM_GPIO_BROKEN_INT_CLEAR
> > +     /* Save interrupts that already triggered before we loose them. */
> > +     /* Any interrupt that triggers between the read of int_status */
> > +     /* and the write to int_clear will still be lost though. */
> > +     msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
> > +     msm_chip->int_status_copy &= ~b;
> > +#endif
> > +     writel(b, msm_chip->regs.int_clear);
> > +
> > +     msm_gpio_update_both_edge_detect(msm_chip);
> > +     spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
> > +}
> > +
> > +static void msm_gpio_irq_mask(unsigned int irq)
> > +{
> > +     unsigned long irq_flags;
> > +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> > +     unsigned b, v;
> > +
> > +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> > +
> > +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> > +
> > +     v = readl(msm_chip->regs.int_edge);
> > +     /* level triggered interrupts are also latched */
> > +     if (!(v & b)) {
> > +
> > +     #if MSM_GPIO_BROKEN_INT_CLEAR
> 
> Align the #if/#endif to the first column.

Yeah .

> > +             /* Save interrupts that already triggered before we loose
> > +              * them. Any interrupt that triggers between the read of
> > +              * int_status and the write to int_clear will still be
> > +              * lost though.
> > +              */
> > +             msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
> > +             msm_chip->int_status_copy &= ~b;
> > +     #endif
> > +             writel(b, msm_chip->regs.int_clear);
> > +             msm_gpio_update_both_edge_detect(msm_chip);
> > +     }
> > +
> > +     msm_chip->int_enable[0] &= ~b;
> > +     writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
> > +
> > +     spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
> > +}
> > +
> > +static void msm_gpio_irq_unmask(unsigned int irq)
> > +{
> > +     unsigned long irq_flags;
> > +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> > +     unsigned b, v;
> > +
> > +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> > +
> > +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> > +
> > +     v = readl(msm_chip->regs.int_edge);
> > +     /* level triggered interrupts are also latched */
> > +     if (!(v & b)) {
> > +
> > +     #if MSM_GPIO_BROKEN_INT_CLEAR
> > +             /* Save interrupts that already triggered before we loose
> > +              * them. Any interrupt that triggers between the read of
> > +              * int_status and the write to int_clear will still be
> > +              * lost though.
> > +              */
> > +             msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
> > +             msm_chip->int_status_copy &= ~b;
> > +     #endif
> > +             writel(b, msm_chip->regs.int_clear);
> > +             msm_gpio_update_both_edge_detect(msm_chip);
> > +     }
> > +
> > +     msm_chip->int_enable[0] |= b;
> > +     writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
> > +
> > +     spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
> > +}
> > +
> > +static int msm_gpio_irq_set_wake(unsigned int irq, unsigned int on)
> > +{
> > +     unsigned long irq_flags;
> > +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> > +     unsigned b;
> > +
> > +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> > +
> > +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> > +
> > +     if (on)
> > +             msm_chip->int_enable[1] |= b;
> > +     else
> > +             msm_chip->int_enable[1] &= ~b;
> > +
> > +     spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
> > +
> > +     return 0;
> > +}
> > +
> > +
> > +static int msm_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
> > +{
> > +     unsigned long irq_flags;
> > +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> > +     unsigned b, v;
> > +
> > +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> > +
> > +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> > +
> > +     v = readl(msm_chip->regs.int_edge);
> > +     if (flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) {
> > +             writel(v | b, msm_chip->regs.int_edge);
> > +             irq_desc[MSM_GPIO_TO_INT(irq - FIRST_GPIO_IRQ)].handle_irq = handle_edge_irq;
> > +     } else {
> > +             writel(v & (~b), msm_chip->regs.int_edge);
> > +             irq_desc[MSM_GPIO_TO_INT(irq - FIRST_GPIO_IRQ)].handle_irq = handle_level_irq;
> > +     }
> > +     if ((flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) ==
> > +                      (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) {
> > +             msm_chip->both_edge_detect |= b;
> > +             msm_gpio_update_both_edge_detect(msm_chip);
> > +     } else {
> > +             msm_chip->both_edge_detect &= ~b;
> > +             v = readl(msm_chip->regs.int_pos);
> > +             if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
> > +                     writel(v | b, msm_chip->regs.int_pos);
> > +             else
> > +                     writel(v & (~b), msm_chip->regs.int_pos);
> > +
> > +     }
> > +     spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
> > +     return 0;
> > +}
> > +
> > +static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
> > +{
> > +     int i, j, m;
> > +     unsigned v;
> > +
> > +     for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
> > +             struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i];
> > +             v = readl(msm_chip->regs.int_status);
> > +             v &= msm_chip->int_enable[0];
> > +             while (v) {
> > +                     m = v & -v;
> > +                     j = fls(m) - 1;
> > +                     v &= ~m;
> > +                     generic_handle_irq(FIRST_GPIO_IRQ + msm_chip->chip.base + j);
> > +             }
> > +     }
> > +     desc->chip->ack(irq);
> > +}
> > +
> > +static struct irq_chip msm_gpio_irq_chip = {
> > +     .name      = "msmgpio",
> > +     .ack       = msm_gpio_irq_ack,
> > +     .mask      = msm_gpio_irq_mask,
> > +     .unmask    = msm_gpio_irq_unmask,
> > +     .set_wake  = msm_gpio_irq_set_wake,
> > +     .set_type  = msm_gpio_irq_set_type,
> > +};
> > +
> > +static int __init msm_init_gpio(void)
> > +{
> > +     int i, j = 0;
> > +     for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
> > +             if (i - FIRST_GPIO_IRQ > msm_gpio_chips[j].chip.ngpio - 1)
> > +                     j++;
> > +             set_irq_chip_data(i, &msm_gpio_chips[j]);
> > +             set_irq_chip(i, &msm_gpio_irq_chip);
> > +             set_irq_handler(i, handle_edge_irq);
> > +             set_irq_flags(i, IRQF_VALID);
> > +     }
> > +
> > +     for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
> > +             writel(0, msm_gpio_chips[i].regs.int_en);
> > +             spin_lock_init(&msm_gpio_chips[i].lock);
> > +             gpiochip_add(&msm_gpio_chips[i].chip);
> > +     }
> > +
> > +     set_irq_chained_handler(INT_GPIO_GROUP1, msm_gpio_irq_handler);
> > +     set_irq_chained_handler(INT_GPIO_GROUP2, msm_gpio_irq_handler);
> > +     set_irq_wake(INT_GPIO_GROUP1, 1);
> > +     set_irq_wake(INT_GPIO_GROUP2, 2);
> > +
> > +     return 0;
> > +}
> > +
> > +postcore_initcall(msm_init_gpio);
> > diff --git a/arch/arm/mach-msm/gpio_hw.h b/arch/arm/mach-msm/gpio_hw.h
> > new file mode 100644
> > index 0000000..f7e1b5b
> > --- /dev/null
> > +++ b/arch/arm/mach-msm/gpio_hw.h
> > @@ -0,0 +1,187 @@
> > +/* arch/arm/mach-msm/gpio_hw.h
> > + *
> > + * Copyright (C) 2007 Google, Inc.
> > + * Author: Brian Swetland <swetland@google.com>
> > + *
> > + * This software is licensed under the terms of the GNU General Public
> > + * License version 2, as published by the Free Software Foundation, and
> > + * may be copied, distributed, and modified under those terms.
> > + *
> > + * 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.
> > + *
> > + */
> > +
> > +#ifndef __ARCH_ARM_MACH_MSM_GPIO_HW_H
> > +#define __ARCH_ARM_MACH_MSM_GPIO_HW_H
> > +
> > +#include <mach/msm_iomap.h>
> > +
> > +/* see 80-VA736-2 Rev C pp 695-751
> > +**
> > +** These are actually the *shadow* gpio registers, since the
> > +** real ones (which allow full access) are only available to the
> > +** ARM9 side of the world.
> > +**
> > +** Since the _BASE need to be page-aligned when we're mapping them
> > +** to virtual addresses, adjust for the additional offset in these
> > +** macros.
> > +*/
> > +
> 
> All the #define'd names in this file are pretty generic.  You should
> probably add a prefix (MSM_ ?) to all of them.
> 
> Also, you should use tabs instead of spaces between the #define <name><tabs><something>

No problem ..

> > +#define GPIO1_REG(off) (MSM_GPIO1_BASE + 0x800 + (off))
> > +#define GPIO2_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off))
> > +
> > +#if defined(CONFIG_ARCH_MSM7X00A)
> > +
> > +/* output value */
> > +#define GPIO_OUT_0         GPIO1_REG(0x00)  /* gpio  15-0  */
> > +#define GPIO_OUT_1         GPIO2_REG(0x00)  /* gpio  42-16 */
> > +#define GPIO_OUT_2         GPIO1_REG(0x04)  /* gpio  67-43 */
> > +#define GPIO_OUT_3         GPIO1_REG(0x08)  /* gpio  94-68 */
> > +#define GPIO_OUT_4         GPIO1_REG(0x0C)  /* gpio 106-95 */
> > +#define GPIO_OUT_5         GPIO1_REG(0x50)  /* gpio 107-121 */
> > +
> > +/* same pin map as above, output enable */
> > +#define GPIO_OE_0          GPIO1_REG(0x10)
> > +#define GPIO_OE_1          GPIO2_REG(0x08)
> > +#define GPIO_OE_2          GPIO1_REG(0x14)
> > +#define GPIO_OE_3          GPIO1_REG(0x18)
> > +#define GPIO_OE_4          GPIO1_REG(0x1C)
> > +#define GPIO_OE_5          GPIO1_REG(0x54)
> > +
> > +/* same pin map as above, input read */
> > +#define GPIO_IN_0          GPIO1_REG(0x34)
> > +#define GPIO_IN_1          GPIO2_REG(0x20)
> > +#define GPIO_IN_2          GPIO1_REG(0x38)
> > +#define GPIO_IN_3          GPIO1_REG(0x3C)
> > +#define GPIO_IN_4          GPIO1_REG(0x40)
> > +#define GPIO_IN_5          GPIO1_REG(0x44)
> > +
> > +/* same pin map as above, 1=edge 0=level interrup */
> > +#define GPIO_INT_EDGE_0    GPIO1_REG(0x60)
> > +#define GPIO_INT_EDGE_1    GPIO2_REG(0x50)
> > +#define GPIO_INT_EDGE_2    GPIO1_REG(0x64)
> > +#define GPIO_INT_EDGE_3    GPIO1_REG(0x68)
> > +#define GPIO_INT_EDGE_4    GPIO1_REG(0x6C)
> > +#define GPIO_INT_EDGE_5    GPIO1_REG(0xC0)
> > +
> > +/* same pin map as above, 1=positive 0=negative */
> > +#define GPIO_INT_POS_0     GPIO1_REG(0x70)
> > +#define GPIO_INT_POS_1     GPIO2_REG(0x58)
> > +#define GPIO_INT_POS_2     GPIO1_REG(0x74)
> > +#define GPIO_INT_POS_3     GPIO1_REG(0x78)
> > +#define GPIO_INT_POS_4     GPIO1_REG(0x7C)
> > +#define GPIO_INT_POS_5     GPIO1_REG(0xBC)
> > +
> > +/* same pin map as above, interrupt enable */
> > +#define GPIO_INT_EN_0      GPIO1_REG(0x80)
> > +#define GPIO_INT_EN_1      GPIO2_REG(0x60)
> > +#define GPIO_INT_EN_2      GPIO1_REG(0x84)
> > +#define GPIO_INT_EN_3      GPIO1_REG(0x88)
> > +#define GPIO_INT_EN_4      GPIO1_REG(0x8C)
> > +#define GPIO_INT_EN_5      GPIO1_REG(0xB8)
> > +
> > +/* same pin map as above, write 1 to clear interrupt */
> > +#define GPIO_INT_CLEAR_0   GPIO1_REG(0x90)
> > +#define GPIO_INT_CLEAR_1   GPIO2_REG(0x68)
> > +#define GPIO_INT_CLEAR_2   GPIO1_REG(0x94)
> > +#define GPIO_INT_CLEAR_3   GPIO1_REG(0x98)
> > +#define GPIO_INT_CLEAR_4   GPIO1_REG(0x9C)
> > +#define GPIO_INT_CLEAR_5   GPIO1_REG(0xB4)
> > +
> > +/* same pin map as above, 1=interrupt pending */
> > +#define GPIO_INT_STATUS_0  GPIO1_REG(0xA0)
> > +#define GPIO_INT_STATUS_1  GPIO2_REG(0x70)
> > +#define GPIO_INT_STATUS_2  GPIO1_REG(0xA4)
> > +#define GPIO_INT_STATUS_3  GPIO1_REG(0xA8)
> > +#define GPIO_INT_STATUS_4  GPIO1_REG(0xAC)
> > +#define GPIO_INT_STATUS_5  GPIO1_REG(0xB0)
> > +
> > +#endif
> > +
> > +#if defined(CONFIG_ARCH_QSD8X50)
> > +/* output value */
> > +#define GPIO_OUT_0         GPIO1_REG(0x00)  /* gpio  15-0   */
> > +#define GPIO_OUT_1         GPIO2_REG(0x00)  /* gpio  42-16  */
> > +#define GPIO_OUT_2         GPIO1_REG(0x04)  /* gpio  67-43  */
> > +#define GPIO_OUT_3         GPIO1_REG(0x08)  /* gpio  94-68  */
> > +#define GPIO_OUT_4         GPIO1_REG(0x0C)  /* gpio 103-95  */
> > +#define GPIO_OUT_5         GPIO1_REG(0x10)  /* gpio 121-104 */
> > +#define GPIO_OUT_6         GPIO1_REG(0x14)  /* gpio 152-122 */
> > +#define GPIO_OUT_7         GPIO1_REG(0x18)  /* gpio 164-153 */
> > +
> > +/* same pin map as above, output enable */
> > +#define GPIO_OE_0          GPIO1_REG(0x20)
> > +#define GPIO_OE_1          GPIO2_REG(0x08)
> > +#define GPIO_OE_2          GPIO1_REG(0x24)
> > +#define GPIO_OE_3          GPIO1_REG(0x28)
> > +#define GPIO_OE_4          GPIO1_REG(0x2C)
> > +#define GPIO_OE_5          GPIO1_REG(0x30)
> > +#define GPIO_OE_6          GPIO1_REG(0x34)
> > +#define GPIO_OE_7          GPIO1_REG(0x38)
> > +
> > +/* same pin map as above, input read */
> > +#define GPIO_IN_0          GPIO1_REG(0x50)
> > +#define GPIO_IN_1          GPIO2_REG(0x20)
> > +#define GPIO_IN_2          GPIO1_REG(0x54)
> > +#define GPIO_IN_3          GPIO1_REG(0x58)
> > +#define GPIO_IN_4          GPIO1_REG(0x5C)
> > +#define GPIO_IN_5          GPIO1_REG(0x60)
> > +#define GPIO_IN_6          GPIO1_REG(0x64)
> > +#define GPIO_IN_7          GPIO1_REG(0x68)
> > +
> > +/* same pin map as above, 1=edge 0=level interrup */
> > +#define GPIO_INT_EDGE_0    GPIO1_REG(0x70)
> > +#define GPIO_INT_EDGE_1    GPIO2_REG(0x50)
> > +#define GPIO_INT_EDGE_2    GPIO1_REG(0x74)
> > +#define GPIO_INT_EDGE_3    GPIO1_REG(0x78)
> > +#define GPIO_INT_EDGE_4    GPIO1_REG(0x7C)
> > +#define GPIO_INT_EDGE_5    GPIO1_REG(0x80)
> > +#define GPIO_INT_EDGE_6    GPIO1_REG(0x84)
> > +#define GPIO_INT_EDGE_7    GPIO1_REG(0x88)
> > +
> > +/* same pin map as above, 1=positive 0=negative */
> > +#define GPIO_INT_POS_0     GPIO1_REG(0x90)
> > +#define GPIO_INT_POS_1     GPIO2_REG(0x58)
> > +#define GPIO_INT_POS_2     GPIO1_REG(0x94)
> > +#define GPIO_INT_POS_3     GPIO1_REG(0x98)
> > +#define GPIO_INT_POS_4     GPIO1_REG(0x9C)
> > +#define GPIO_INT_POS_5     GPIO1_REG(0xA0)
> > +#define GPIO_INT_POS_6     GPIO1_REG(0xA4)
> > +#define GPIO_INT_POS_7     GPIO1_REG(0xA8)
> > +
> > +/* same pin map as above, interrupt enable */
> > +#define GPIO_INT_EN_0      GPIO1_REG(0xB0)
> > +#define GPIO_INT_EN_1      GPIO2_REG(0x60)
> > +#define GPIO_INT_EN_2      GPIO1_REG(0xB4)
> > +#define GPIO_INT_EN_3      GPIO1_REG(0xB8)
> > +#define GPIO_INT_EN_4      GPIO1_REG(0xBC)
> > +#define GPIO_INT_EN_5      GPIO1_REG(0xC0)
> > +#define GPIO_INT_EN_6      GPIO1_REG(0xC4)
> > +#define GPIO_INT_EN_7      GPIO1_REG(0xC8)
> > +
> > +/* same pin map as above, write 1 to clear interrupt */
> > +#define GPIO_INT_CLEAR_0   GPIO1_REG(0xD0)
> > +#define GPIO_INT_CLEAR_1   GPIO2_REG(0x68)
> > +#define GPIO_INT_CLEAR_2   GPIO1_REG(0xD4)
> > +#define GPIO_INT_CLEAR_3   GPIO1_REG(0xD8)
> > +#define GPIO_INT_CLEAR_4   GPIO1_REG(0xDC)
> > +#define GPIO_INT_CLEAR_5   GPIO1_REG(0xE0)
> > +#define GPIO_INT_CLEAR_6   GPIO1_REG(0xE4)
> > +#define GPIO_INT_CLEAR_7   GPIO1_REG(0xE8)
> > +
> > +/* same pin map as above, 1=interrupt pending */
> > +#define GPIO_INT_STATUS_0  GPIO1_REG(0xF0)
> > +#define GPIO_INT_STATUS_1  GPIO2_REG(0x70)
> > +#define GPIO_INT_STATUS_2  GPIO1_REG(0xF4)
> > +#define GPIO_INT_STATUS_3  GPIO1_REG(0xF8)
> > +#define GPIO_INT_STATUS_4  GPIO1_REG(0xFC)
> > +#define GPIO_INT_STATUS_5  GPIO1_REG(0x100)
> > +#define GPIO_INT_STATUS_6  GPIO1_REG(0x104)
> > +#define GPIO_INT_STATUS_7  GPIO1_REG(0x108)
> > +
> > +#endif
> > +
> > +#endif
> > diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h
> > new file mode 100644
> > index 0000000..784e6f5
> > --- /dev/null
> > +++ b/arch/arm/mach-msm/include/mach/gpio.h
> > @@ -0,0 +1,43 @@
> > +/* linux/include/asm-arm/arch-msm/gpio.h
> > + *
> > + * Copyright (C) 2007 Google, Inc.
> > + * Author: Mike Lockwood <lockwood@android.com>
> > + *
> > + * This software is licensed under the terms of the GNU General Public
> > + * License version 2, as published by the Free Software Foundation, and
> > + * may be copied, distributed, and modified under those terms.
> > + *
> > + * 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.
> > + *
> > + */
> > +
> > +#ifndef __ASM_ARCH_MSM_GPIO_H
> > +#define __ASM_ARCH_MSM_GPIO_H
> > +
> > +#include <linux/interrupt.h>
> 
> Why is this included?

Have to ask Mike Lockwood I guess, but I try removing it.

> > +#include <asm-generic/gpio.h>
> > +
> > +static inline int gpio_get_value(unsigned gpio)
> > +{
> > +     return __gpio_get_value(gpio);
> > +}
> > +
> > +static inline void gpio_set_value(unsigned gpio, int value)
> > +{
> > +     __gpio_set_value(gpio, value);
> > +}
> > +
> > +static inline int gpio_cansleep(unsigned gpio)
> > +{
> > +     return __gpio_cansleep(gpio);
> > +}
> > +
> > +static inline int gpio_to_irq(unsigned gpio)
> > +{
> > +     return __gpio_to_irq(gpio);
> > +}
> > +
> 
> These could all just be:
> 
> #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


Much cleaner .. I'll do that. 

Thanks for all the good comments.

Daniel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 1/4] arm: msm: gpio support
  2010-03-31 14:03       ` Daniel Walker
@ 2010-03-31 21:21         ` Arve Hjønnevåg
  -1 siblings, 0 replies; 22+ messages in thread
From: Arve Hjønnevåg @ 2010-03-31 21:21 UTC (permalink / raw)
  To: Daniel Walker; +Cc: H Hartley Sweeten, linux-arm-kernel, linux-arm-msm

2010/3/31 Daniel Walker <dwalker@codeaurora.org>:
> On Tue, 2010-03-30 at 18:14 -0700, Arve Hjønnevåg wrote:
>> On Tue, Mar 30, 2010 at 4:58 PM, H Hartley Sweeten
>> <hartleys@visionengravers.com> wrote:
>> > On Tuesday, March 30, 2010 4:12 PM, Daniel Walker wrote:
>> >> From: Daniel Walker <c_dwalke@quicinc.com>
>> ...
>> >> +
>> >> +static void msm_gpio_irq_ack(unsigned int irq)
>> >> +{
>> >> +     unsigned long irq_flags;
>> >> +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
>> >> +     unsigned b;
>> >> +
>> >> +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
>> >> +
>> >> +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
>> >
>> > Urk... That's a bit confusing...
>> >
>> > You might want to make this a macro or an inline function with some kind
>> > of comment.
>> >
>>
>> On a related note, why did you inline msm_gpio_clear_detect_status? It
>> is used from two other functions.
>>
>
> You mean other places in the Android tree?

No, you copied it three times in this file.

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH 1/4] arm: msm: gpio support
@ 2010-03-31 21:21         ` Arve Hjønnevåg
  0 siblings, 0 replies; 22+ messages in thread
From: Arve Hjønnevåg @ 2010-03-31 21:21 UTC (permalink / raw)
  To: linux-arm-kernel

2010/3/31 Daniel Walker <dwalker@codeaurora.org>:
> On Tue, 2010-03-30 at 18:14 -0700, Arve Hj?nnev?g wrote:
>> On Tue, Mar 30, 2010 at 4:58 PM, H Hartley Sweeten
>> <hartleys@visionengravers.com> wrote:
>> > On Tuesday, March 30, 2010 4:12 PM, Daniel Walker wrote:
>> >> From: Daniel Walker <c_dwalke@quicinc.com>
>> ...
>> >> +
>> >> +static void msm_gpio_irq_ack(unsigned int irq)
>> >> +{
>> >> + ? ? unsigned long irq_flags;
>> >> + ? ? struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
>> >> + ? ? unsigned b;
>> >> +
>> >> + ? ? spin_lock_irqsave(&msm_chip->lock, irq_flags);
>> >> +
>> >> + ? ? b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
>> >
>> > Urk... That's a bit confusing...
>> >
>> > You might want to make this a macro or an inline function with some kind
>> > of comment.
>> >
>>
>> On a related note, why did you inline msm_gpio_clear_detect_status? It
>> is used from two other functions.
>>
>
> You mean other places in the Android tree?

No, you copied it three times in this file.

-- 
Arve Hj?nnev?g

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 1/4] arm: msm: gpio support
  2010-03-31 21:21         ` Arve Hjønnevåg
@ 2010-03-31 22:53           ` Daniel Walker
  -1 siblings, 0 replies; 22+ messages in thread
From: Daniel Walker @ 2010-03-31 22:53 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: H Hartley Sweeten, linux-arm-kernel, linux-arm-msm

On Wed, 2010-03-31 at 14:21 -0700, Arve Hjønnevåg wrote:
> 2010/3/31 Daniel Walker <dwalker@codeaurora.org>:
> > On Tue, 2010-03-30 at 18:14 -0700, Arve Hjønnevåg wrote:
> >> On Tue, Mar 30, 2010 at 4:58 PM, H Hartley Sweeten
> >> <hartleys@visionengravers.com> wrote:
> >> > On Tuesday, March 30, 2010 4:12 PM, Daniel Walker wrote:
> >> >> From: Daniel Walker <c_dwalke@quicinc.com>
> >> ...
> >> >> +
> >> >> +static void msm_gpio_irq_ack(unsigned int irq)
> >> >> +{
> >> >> +     unsigned long irq_flags;
> >> >> +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> >> >> +     unsigned b;
> >> >> +
> >> >> +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> >> >> +
> >> >> +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> >> >
> >> > Urk... That's a bit confusing...
> >> >
> >> > You might want to make this a macro or an inline function with some kind
> >> > of comment.
> >> >
> >>
> >> On a related note, why did you inline msm_gpio_clear_detect_status? It
> >> is used from two other functions.
> >>
> >
> > You mean other places in the Android tree?
> 
> No, you copied it three times in this file.

Oh, well it was part of the API elimination , but it's helpful when
doing clean up to have stuff all unrolled so optimization possibilities
present themselves more easily .. You think I should convert it into an
inline?

Daniel


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH 1/4] arm: msm: gpio support
@ 2010-03-31 22:53           ` Daniel Walker
  0 siblings, 0 replies; 22+ messages in thread
From: Daniel Walker @ 2010-03-31 22:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 2010-03-31 at 14:21 -0700, Arve Hj?nnev?g wrote:
> 2010/3/31 Daniel Walker <dwalker@codeaurora.org>:
> > On Tue, 2010-03-30 at 18:14 -0700, Arve Hj?nnev?g wrote:
> >> On Tue, Mar 30, 2010 at 4:58 PM, H Hartley Sweeten
> >> <hartleys@visionengravers.com> wrote:
> >> > On Tuesday, March 30, 2010 4:12 PM, Daniel Walker wrote:
> >> >> From: Daniel Walker <c_dwalke@quicinc.com>
> >> ...
> >> >> +
> >> >> +static void msm_gpio_irq_ack(unsigned int irq)
> >> >> +{
> >> >> +     unsigned long irq_flags;
> >> >> +     struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
> >> >> +     unsigned b;
> >> >> +
> >> >> +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> >> >> +
> >> >> +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> >> >
> >> > Urk... That's a bit confusing...
> >> >
> >> > You might want to make this a macro or an inline function with some kind
> >> > of comment.
> >> >
> >>
> >> On a related note, why did you inline msm_gpio_clear_detect_status? It
> >> is used from two other functions.
> >>
> >
> > You mean other places in the Android tree?
> 
> No, you copied it three times in this file.

Oh, well it was part of the API elimination , but it's helpful when
doing clean up to have stuff all unrolled so optimization possibilities
present themselves more easily .. You think I should convert it into an
inline?

Daniel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 1/4] arm: msm: gpio support
  2010-03-31 22:53           ` Daniel Walker
@ 2010-04-06 13:32             ` Pavel Machek
  -1 siblings, 0 replies; 22+ messages in thread
From: Pavel Machek @ 2010-04-06 13:32 UTC (permalink / raw)
  To: Daniel Walker
  Cc: Arve Hj?nnev?g, linux-arm-msm, H Hartley Sweeten, linux-arm-kernel

> > >> >> +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> > >> >> +
> > >> >> +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> > >> >
> > >> > Urk... That's a bit confusing...
> > >> >
> > >> > You might want to make this a macro or an inline function with some kind
> > >> > of comment.
> > >> >
> > >>
> > >> On a related note, why did you inline msm_gpio_clear_detect_status? It
> > >> is used from two other functions.
> > >>
> > >
> > > You mean other places in the Android tree?
> > 
> > No, you copied it three times in this file.
> 
> Oh, well it was part of the API elimination , but it's helpful when
> doing clean up to have stuff all unrolled so optimization possibilities
> present themselves more easily .. You think I should convert it into an
> inline?

I guess so. Premature optimalization is sqrt(all evil).

Really, leave that to compiler.
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH 1/4] arm: msm: gpio support
@ 2010-04-06 13:32             ` Pavel Machek
  0 siblings, 0 replies; 22+ messages in thread
From: Pavel Machek @ 2010-04-06 13:32 UTC (permalink / raw)
  To: linux-arm-kernel

> > >> >> +     spin_lock_irqsave(&msm_chip->lock, irq_flags);
> > >> >> +
> > >> >> +     b = 1U << (irq - FIRST_GPIO_IRQ - msm_chip->chip.base);
> > >> >
> > >> > Urk... That's a bit confusing...
> > >> >
> > >> > You might want to make this a macro or an inline function with some kind
> > >> > of comment.
> > >> >
> > >>
> > >> On a related note, why did you inline msm_gpio_clear_detect_status? It
> > >> is used from two other functions.
> > >>
> > >
> > > You mean other places in the Android tree?
> > 
> > No, you copied it three times in this file.
> 
> Oh, well it was part of the API elimination , but it's helpful when
> doing clean up to have stuff all unrolled so optimization possibilities
> present themselves more easily .. You think I should convert it into an
> inline?

I guess so. Premature optimalization is sqrt(all evil).

Really, leave that to compiler.
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2010-04-06 13:32 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-03-30 23:11 [PATCH 1/4] arm: msm: gpio support Daniel Walker
2010-03-30 23:11 ` Daniel Walker
2010-03-30 23:11 ` [PATCH 2/4] arm: msm: GPIO support for HTC Dream Daniel Walker
2010-03-30 23:11   ` Daniel Walker
2010-03-30 23:11   ` [PATCH 3/4] arm: msm: trout: add trout specific gpio interrupts Daniel Walker
2010-03-30 23:11     ` Daniel Walker
2010-03-30 23:11     ` [PATCH 4/4] arm: msm: trout add mmc support Daniel Walker
2010-03-30 23:11       ` Daniel Walker
2010-03-30 23:58 ` [PATCH 1/4] arm: msm: gpio support H Hartley Sweeten
2010-03-30 23:58   ` H Hartley Sweeten
2010-03-31  1:14   ` Arve Hjønnevåg
2010-03-31  1:14     ` Arve Hjønnevåg
2010-03-31 14:03     ` Daniel Walker
2010-03-31 14:03       ` Daniel Walker
2010-03-31 21:21       ` Arve Hjønnevåg
2010-03-31 21:21         ` Arve Hjønnevåg
2010-03-31 22:53         ` Daniel Walker
2010-03-31 22:53           ` Daniel Walker
2010-04-06 13:32           ` Pavel Machek
2010-04-06 13:32             ` Pavel Machek
2010-03-31 14:12   ` Daniel Walker
2010-03-31 14:12     ` Daniel Walker

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.