aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/boards/mach-x3proto/gpio.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2010-10-03 13:59:29 -0400
committerPaul Mundt <lethal@linux-sh.org>2010-10-03 13:59:29 -0400
commit550591143eead286f2cd9d124a55d4a99ed024de (patch)
tree5f1edc1b8c8e0829f04a5d24b9083bd5a054c1fb /arch/sh/boards/mach-x3proto/gpio.c
parentd39d0ed196aa1685bb24771e92f78633c66ac9cb (diff)
sh: mach-x3proto: Support for baseboard GPIOs.
This adds trivial support for the GPIOs implemented through the baseboard CPLD, used for driving the button matrix. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/boards/mach-x3proto/gpio.c')
-rw-r--r--arch/sh/boards/mach-x3proto/gpio.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/arch/sh/boards/mach-x3proto/gpio.c b/arch/sh/boards/mach-x3proto/gpio.c
new file mode 100644
index 000000000000..9fcd7ce6aa42
--- /dev/null
+++ b/arch/sh/boards/mach-x3proto/gpio.c
@@ -0,0 +1,135 @@
1/*
2 * arch/sh/boards/mach-x3proto/gpio.c
3 *
4 * Renesas SH-X3 Prototype Baseboard GPIO Support.
5 *
6 * Copyright (C) 2010 Paul Mundt
7 *
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file "COPYING" in the main directory of this archive
10 * for more details.
11 */
12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13
14#include <linux/init.h>
15#include <linux/interrupt.h>
16#include <linux/gpio.h>
17#include <linux/irq.h>
18#include <linux/kernel.h>
19#include <linux/spinlock.h>
20#include <linux/io.h>
21#include <mach/ilsel.h>
22#include <mach/hardware.h>
23
24#define KEYCTLR 0xb81c0000
25#define KEYOUTR 0xb81c0002
26#define KEYDETR 0xb81c0004
27
28static DEFINE_SPINLOCK(x3proto_gpio_lock);
29static unsigned int x3proto_gpio_irq_map[NR_BASEBOARD_GPIOS] = { 0, };
30
31static int x3proto_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
32{
33 unsigned long flags;
34 unsigned int data;
35
36 spin_lock_irqsave(&x3proto_gpio_lock, flags);
37 data = __raw_readw(KEYCTLR);
38 data |= (1 << gpio);
39 __raw_writew(data, KEYCTLR);
40 spin_unlock_irqrestore(&x3proto_gpio_lock, flags);
41
42 return 0;
43}
44
45static int x3proto_gpio_get(struct gpio_chip *chip, unsigned gpio)
46{
47 return !!(__raw_readw(KEYDETR) & (1 << gpio));
48}
49
50static int x3proto_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
51{
52 return x3proto_gpio_irq_map[gpio];
53}
54
55static void x3proto_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
56{
57 struct irq_chip *chip = get_irq_desc_chip(desc);
58 unsigned long mask;
59 int pin;
60
61 chip->mask_ack(irq);
62
63 mask = __raw_readw(KEYDETR);
64
65 for_each_set_bit(pin, &mask, NR_BASEBOARD_GPIOS)
66 generic_handle_irq(x3proto_gpio_to_irq(NULL, pin));
67
68 chip->unmask(irq);
69}
70
71struct gpio_chip x3proto_gpio_chip = {
72 .label = "x3proto-gpio",
73 .direction_input = x3proto_gpio_direction_input,
74 .get = x3proto_gpio_get,
75 .to_irq = x3proto_gpio_to_irq,
76 .base = -1,
77 .ngpio = NR_BASEBOARD_GPIOS,
78};
79
80int __init x3proto_gpio_setup(void)
81{
82 unsigned int ilsel;
83 int ret, i;
84
85 ilsel = ilsel_enable(ILSEL_KEY);
86 if (unlikely(ilsel < 0))
87 return ilsel;
88
89 ret = gpiochip_add(&x3proto_gpio_chip);
90 if (unlikely(ret))
91 goto err_gpio;
92
93 for (i = 0; i < NR_BASEBOARD_GPIOS; i++) {
94 unsigned long flags;
95 unsigned int irq = create_irq();
96
97 if (unlikely(irq < 0)) {
98 ret = -EINVAL;
99 goto err_irq;
100 }
101
102 spin_lock_irqsave(&x3proto_gpio_lock, flags);
103 x3proto_gpio_irq_map[i] = irq;
104 set_irq_chip_and_handler_name(irq, &dummy_irq_chip,
105 handle_simple_irq, "gpio");
106 spin_unlock_irqrestore(&x3proto_gpio_lock, flags);
107 }
108
109 pr_info("registering '%s' support, handling GPIOs %u -> %u, "
110 "bound to IRQ %u\n",
111 x3proto_gpio_chip.label, x3proto_gpio_chip.base,
112 x3proto_gpio_chip.base + x3proto_gpio_chip.ngpio,
113 ilsel);
114
115 set_irq_chained_handler(ilsel, x3proto_gpio_irq_handler);
116 set_irq_wake(ilsel, 1);
117
118 return 0;
119
120err_irq:
121 for (; i >= 0; --i)
122 if (x3proto_gpio_irq_map[i])
123 destroy_irq(x3proto_gpio_irq_map[i]);
124
125 ret = gpiochip_remove(&x3proto_gpio_chip);
126 if (unlikely(ret))
127 pr_err("Failed deregistering GPIO\n");
128
129err_gpio:
130 synchronize_irq(ilsel);
131
132 ilsel_disable(ILSEL_KEY);
133
134 return ret;
135}