* [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.