Skip to contentSkip to conversation

arm: msm: gpio support

PATCH New Daniel Walker 4 participants 11 messages Mar 30, 2010 – Apr 6, 2010

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/4 arm: msm: gpio support

From: Daniel Walker <[email protected]>

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

---
 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
arch/arm/Kconfig +1 -0
index cadfe2e..5e29092 100644
@@ -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
arch/arm/mach-msm/Makefile +1 -0
index 147339c..47d47cb 100644
@@ -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
arch/arm/mach-msm/gpio.c new file +428 -0

428 lines not on this page · raw message

arch/arm/mach-msm/gpio_hw.h new file +187 -0

187 lines not on this page · raw message

arch/arm/mach-msm/include/mach/gpio.h new file +43 -0

43 lines not on this page · raw message

Signature · 1 line
1.6.2.3
#2 lore raw

PATCH 3/4 arm: msm: trout: add trout specific gpio interrupts

In reply to Daniel Walker

From: Daniel Walker <[email protected]>

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 <[email protected]> as the author.

---
 arch/arm/mach-msm/board-trout-gpio.c |  114 ++++++++++++++++++++++++++++++++++
 1 files changed, 114 insertions(+), 0 deletions(-)
arch/arm/mach-msm/board-trout-gpio.c +114 -0
index 6e6bc76..99965b2 100644
@@ -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;
 }
 
Signature · 1 line
1.6.2.3
#1 lore raw

PATCH 2/4 arm: msm: GPIO support for HTC Dream

In reply to Daniel Walker

From: Pavel Machek <[email protected]>

Add GPIO support for HTC Dream.

---
 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
arch/arm/mach-msm/Makefile +1 -1
index 47d47cb..fb9ab2d 100644
@@ -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
arch/arm/mach-msm/board-trout-gpio.c new file +112 -0

112 lines not on this page · raw message

arch/arm/mach-msm/board-trout.h +157 -0

162 lines not on this page · raw message

Signature · 1 line
1.6.2.3
#3 lore raw

PATCH 4/4 arm: msm: trout add mmc support

In reply to Daniel Walker

This adds the platform data for MMC on trout.

---
 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
arch/arm/mach-msm/Makefile +1 -1
index fb9ab2d..cde59dc 100644
@@ -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
arch/arm/mach-msm/board-trout-mmc.c new file +189 -0

189 lines not on this page · raw message

arch/arm/mach-msm/board-trout.c +11 -0
index 9793ff4..49d550e 100644
@@ -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 = {
Signature · 1 line
1.6.2.3
#4 lore raw

PATCH 1/4 arm: msm: gpio support

In reply to Daniel Walker
Quoted 59 lines · Daniel Walker

From: Daniel Walker <[email protected]>

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

---
 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
arch/arm/Kconfig +1 -0
index cadfe2e..5e29092 100644
@@ -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
arch/arm/mach-msm/Makefile +1 -0
index 147339c..47d47cb 100644
@@ -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
arch/arm/mach-msm/gpio.c new file +12 -0
new file mode 100644
index 0000000..5b95885
@@ -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

arch/arm/mach-msm/gpio.c line 22

Quoted 10 lines
arch/arm/mach-msm/gpio.c new file +10 -0
+ * 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>

arch/arm/mach-msm/gpio.c line 23

Quoted 1 line
arch/arm/mach-msm/gpio.c new file +1 -0
+#include <asm/irq.h>

This one is not needed.

arch/arm/mach-msm/gpio.c line 24

Quoted 1 line
arch/arm/mach-msm/gpio.c new file +1 -0
+#include <linux/irq.h>

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

Quoted 14 lines
arch/arm/mach-msm/gpio.c new file +14 -0
+#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

arch/arm/mach-msm/gpio.c line 48

Quoted 10 lines
arch/arm/mach-msm/gpio.c new file +10 -0
+#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?

Quoted 60 lines
arch/arm/mach-msm/gpio.c new file +60 -0
+
+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),

arch/arm/mach-msm/gpio.c line 118

Quoted 10 lines
arch/arm/mach-msm/gpio.c new file +10 -0
+#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.

arch/arm/mach-msm/gpio.c line 122

Quoted 4 lines
arch/arm/mach-msm/gpio.c new file +4 -0
+     unsigned v;
+
+     spin_lock_irqsave(&old_chip->lock, irq_flags);
+     b = 1U << (offset);

Not needed. You already did it above.

arch/arm/mach-msm/gpio.c line 125

Quoted 3 lines
arch/arm/mach-msm/gpio.c new file +3 -0
+
+     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.

Quoted 102 lines
arch/arm/mach-msm/gpio.c new file +102 -0
+
+     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);
+}

arch/arm/mach-msm/gpio.c line 237

Quoted 10 lines
arch/arm/mach-msm/gpio.c new file +10 -0
+
+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.

Quoted 19 lines
arch/arm/mach-msm/gpio.c new file +19 -0
+
+#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;

arch/arm/mach-msm/gpio.c line 266

Quoted 10 lines
arch/arm/mach-msm/gpio.c new file +10 -0
+
+     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.

Quoted 190 lines
arch/arm/mach-msm/gpio.c new file +162 -0
+             /* 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);
arch/arm/mach-msm/gpio_hw.h new file +22 -0
new file mode 100644
index 0000000..f7e1b5b
@@ -0,0 +1,187 @@
+/* arch/arm/mach-msm/gpio_hw.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <[email protected]>
+ *
+ * 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

arch/arm/mach-msm/gpio_hw.h line 32

Quoted 10 lines
arch/arm/mach-msm/gpio_hw.h new file +10 -0
+**
+** 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>

Quoted 171 lines
arch/arm/mach-msm/gpio_hw.h new file +155 -0
+#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
arch/arm/mach-msm/include/mach/gpio.h new file +10 -0
new file mode 100644
index 0000000..784e6f5
@@ -0,0 +1,43 @@
+/* linux/include/asm-arm/arch-msm/gpio.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Mike Lockwood <[email protected]>
+ *
+ * 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,

arch/arm/mach-msm/include/mach/gpio.h line 20

Quoted 10 lines
arch/arm/mach-msm/include/mach/gpio.h new file +10 -0
+ * 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?

Quoted 12 lines
arch/arm/mach-msm/include/mach/gpio.h new file +12 -0
+#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);
+}
+

arch/arm/mach-msm/include/mach/gpio.h line 42

Quoted 10 lines
arch/arm/mach-msm/include/mach/gpio.h new file +10 -0
+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

arch/arm/mach-msm/include/mach/gpio.h line 43

Quoted 1 line
arch/arm/mach-msm/include/mach/gpio.h new file +1 -0
+#endif

Regards,
Hartley

#5 lore raw

PATCH 1/4 arm: msm: gpio support

Quoted 2 lines · H Hartley Sweeten
Quoted 1 line · Daniel Walker

From: Daniel Walker <[email protected]>

...

Quoted 13 lines

arch/arm/mach-msm/gpio.c

Quoted 10 lines
arch/arm/mach-msm/gpio.c new file +10 -0
+
+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...

Quoted 3 lines

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.

Quoted 14 lines
Quoted 14 lines
(quoted diff) +14 -0
+
+#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);
+}
+

...

Signature · 1 line
Arve Hj?nnev?g
#6 lore raw

PATCH 1/4 arm: msm: gpio support

Quoted 18 lines · Arve Hj?nnev?g
Quoted 2 lines · H Hartley Sweeten
Quoted 1 line · Daniel Walker

From: Daniel Walker <[email protected]>

...

Quoted 13 lines

arch/arm/mach-msm/gpio.c line 237

Quoted 10 lines
arch/arm/mach-msm/gpio.c new file +10 -0
+
+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...

Quoted 7 lines
Quoted 3 lines

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

#10 lore raw

PATCH 1/4 arm: msm: gpio support

In reply to H Hartley Sweeten
Quoted 99 lines · H Hartley Sweeten
Quoted 59 lines · Daniel Walker

From: Daniel Walker <[email protected]>

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

---
 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
arch/arm/Kconfig +1 -0
index cadfe2e..5e29092 100644
@@ -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
arch/arm/mach-msm/Makefile +1 -0
index 147339c..47d47cb 100644
@@ -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
arch/arm/mach-msm/gpio.c new file +12 -0
new file mode 100644
index 0000000..5b95885
@@ -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

arch/arm/mach-msm/gpio.c line 22

Quoted 10 lines
arch/arm/mach-msm/gpio.c new file +10 -0
+ * 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>

arch/arm/mach-msm/gpio.c line 23

Quoted 1 line
arch/arm/mach-msm/gpio.c new file +1 -0
+#include <asm/irq.h>

This one is not needed.

arch/arm/mach-msm/gpio.c line 24

Quoted 1 line
arch/arm/mach-msm/gpio.c new file +1 -0
+#include <linux/irq.h>

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

Quoted 18 lines
arch/arm/mach-msm/gpio.c new file +18 -0
+#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
+
Quoted 8 lines

arch/arm/mach-msm/gpio.c line 48

Quoted 6 lines
arch/arm/mach-msm/gpio.c new file +6 -0
+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.

Quoted 78 lines
Quoted 60 lines
arch/arm/mach-msm/gpio.c new file +60 -0
+
+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),

arch/arm/mach-msm/gpio.c line 118

Quoted 10 lines
arch/arm/mach-msm/gpio.c new file +10 -0
+#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.

arch/arm/mach-msm/gpio.c line 122

Quoted 4 lines
arch/arm/mach-msm/gpio.c new file +4 -0
+     unsigned v;
+
+     spin_lock_irqsave(&old_chip->lock, irq_flags);
+     b = 1U << (offset);
Quoted 7 lines

Not needed. You already did it above.

arch/arm/mach-msm/gpio.c line 125

Quoted 3 lines
arch/arm/mach-msm/gpio.c new file +3 -0
+
+     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 ..

Quoted 115 lines
Quoted 102 lines
arch/arm/mach-msm/gpio.c new file +102 -0
+
+     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);
+}

arch/arm/mach-msm/gpio.c line 237

Quoted 10 lines
arch/arm/mach-msm/gpio.c new file +10 -0
+
+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...

Quoted 2 lines

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

Ok ..

Quoted 23 lines
Quoted 23 lines
arch/arm/mach-msm/gpio.c new file +23 -0
+
+#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);
Quoted 8 lines

arch/arm/mach-msm/gpio.c line 266

Quoted 6 lines
arch/arm/mach-msm/gpio.c new file +6 -0
+
+     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 .

Quoted 204 lines
Quoted 190 lines
arch/arm/mach-msm/gpio.c new file +162 -0
+             /* 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);
arch/arm/mach-msm/gpio_hw.h new file +22 -0
new file mode 100644
index 0000000..f7e1b5b
@@ -0,0 +1,187 @@
+/* arch/arm/mach-msm/gpio_hw.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <[email protected]>
+ *
+ * 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

arch/arm/mach-msm/gpio_hw.h line 32

Quoted 10 lines
arch/arm/mach-msm/gpio_hw.h new file +10 -0
+**
+** 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.

Quoted 1 line

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

No problem ..

Quoted 175 lines
Quoted 175 lines
arch/arm/mach-msm/gpio_hw.h new file +155 -0
+#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
arch/arm/mach-msm/include/mach/gpio.h new file +14 -0
new file mode 100644
index 0000000..784e6f5
@@ -0,0 +1,43 @@
+/* linux/include/asm-arm/arch-msm/gpio.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Mike Lockwood <[email protected]>
+ *
+ * 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.
+ *
Quoted 8 lines

arch/arm/mach-msm/include/mach/gpio.h line 20

Quoted 6 lines
arch/arm/mach-msm/include/mach/gpio.h new file +6 -0
+ */
+
+#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.

Quoted 25 lines
Quoted 12 lines
arch/arm/mach-msm/include/mach/gpio.h new file +12 -0
+#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);
+}
+

arch/arm/mach-msm/include/mach/gpio.h line 42

Quoted 10 lines
arch/arm/mach-msm/include/mach/gpio.h new file +10 -0
+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:

Quoted 4 lines
#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

#7 lore raw

PATCH 1/4 arm: msm: gpio support

In reply to Daniel Walker

2010/3/31 Daniel Walker <[email protected]>:

Quoted 23 lines · Arve Hj?nnev?g
Quoted 22 lines
Quoted 2 lines · H Hartley Sweeten
Quoted 1 line · Daniel Walker

From: Daniel Walker <[email protected]>

...

Quoted 16 lines

arch/arm/mach-msm/gpio.c

Quoted 10 lines
arch/arm/mach-msm/gpio.c new file +10 -0
+
+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.

Quoted 5 lines
Quoted 3 lines

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.

Signature · 1 line
Arve Hj?nnev?g
#8 lore raw

PATCH 1/4 arm: msm: gpio support

Quoted 24 lines · Arve Hj?nnev?g

2010/3/31 Daniel Walker <[email protected]>:

Quoted 23 lines · Arve Hj?nnev?g
Quoted 22 lines
Quoted 2 lines · H Hartley Sweeten
Quoted 1 line · Daniel Walker

From: Daniel Walker <[email protected]>

...

Quoted 16 lines

arch/arm/mach-msm/gpio.c line 237

Quoted 10 lines
arch/arm/mach-msm/gpio.c new file +10 -0
+
+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.

Quoted 7 lines
Quoted 5 lines
Quoted 3 lines

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

#9 lore raw

PATCH 1/4 arm: msm: gpio support

Quoted 14 lines
Quoted 14 lines
Quoted 14 lines
Quoted 13 lines
Quoted 9 lines

arch/arm/mach-msm/gpio.c line 237

Quoted 3 lines
arch/arm/mach-msm/gpio.c new file +3 -0
+     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.

Quoted 8 lines
Quoted 3 lines
Quoted 1 line

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

Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html