blob: 375440c5afb9df1f24fa5a2fe3fac31e00112629 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* arch/arm/mach-msm/board-sapphire-gpio.c
2 * Copyright (C) 2007-2009 HTC Corporation.
3 * Author: Thomas Tsai <thomas_tsai@htc.com>
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13*/
14
15#include <linux/kernel.h>
16#include <linux/errno.h>
17#include <linux/irq.h>
18#include <linux/pm.h>
19#include <linux/sysdev.h>
20
21#include <linux/io.h>
22#include <linux/gpio.h>
23#include <asm/mach-types.h>
24
25#include "gpio_chip.h"
26#include "board-sapphire.h"
27
28#ifdef DEBUG_SAPPHIRE_GPIO
29#define DBG(fmt, arg...) printk(KERN_INFO "%s: " fmt "\n", __func__, ## arg)
30#else
31#define DBG(fmt, arg...) do {} while (0)
32#endif
33
34#define SAPPHIRE_CPLD_INT_STATUS (SAPPHIRE_CPLD_BASE + 0x0E)
35#define SAPPHIRE_CPLD_INT_LEVEL (SAPPHIRE_CPLD_BASE + 0x08)
36#define SAPPHIRE_CPLD_INT_MASK (SAPPHIRE_CPLD_BASE + 0x0C)
37
38/*CPLD misc reg offset*/
39static const int _g_CPLD_MISCn_Offset[] = { 0x0A, /*misc1 reg*/
40 0x00, /*misc2 reg*/
41 0x02, /*misc3 reg*/
42 0x04, /*misc4 reg*/
43 0x06}; /*misc5 reg*/
44/*CPLD INT Bank*/
45/*BANK0: int1 status, int2 level, int3 mask*/
46static const int _g_INT_BANK_Offset[][3] = {{0x0E, 0x08, 0x0C} };
47
48static uint8_t sapphire_cpld_initdata[4] = {
49 [0] = 0x80, /* for serial debug UART3, low current misc2*/
50 [1] = 0x34, /* jog & tp enable, I2C pull misc3*/
51 [3] = 0x04, /* mmdi 32k en misc5*/
52};
53
54/*save current working int mask, so the value can be restored after resume.
55Sapphire has only bank0.*/
56static uint8_t sapphire_int_mask[] = {
57 [0] = 0xfb, /* enable all interrupts, bit 2 is not used */
58};
59
60/*Sleep have to prepare the wake up source in advance.
61default to disable all wakeup sources when suspend.*/
62static uint8_t sapphire_sleep_int_mask[] = {
63 [0] = 0x00, /* bit2 is not used */
64};
65
66static int sapphire_suspended;
67
68static int sapphire_gpio_read(struct gpio_chip *chip, unsigned n)
69{
70 if (n < SAPPHIRE_GPIO_INT_B0_BASE) /*MISCn*/
71 return !!(readb(CPLD_GPIO_REG(n)) & CPLD_GPIO_BIT_POS_MASK(n));
72 else if (n <= SAPPHIRE_GPIO_END) /*gpio n is INT pin*/
73 return !!(readb(CPLD_INT_LEVEL_REG_G(n)) &
74 CPLD_GPIO_BIT_POS_MASK(n));
75 return 0;
76}
77
78/*CPLD Write only register :MISC2, MISC3, MISC4, MISC5 => reg=0,2,4,6
79Reading from write-only registers is undefined, so the writing value
80should be kept in shadow for later usage.*/
81int sapphire_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on)
82{
83 unsigned long flags;
84 uint8_t reg_val;
85 if (n > SAPPHIRE_GPIO_END)
86 return -1;
87
88 local_irq_save(flags);
89 reg_val = readb(CPLD_GPIO_REG(n));
90 if (on)
91 reg_val |= CPLD_GPIO_BIT_POS_MASK(n);
92 else
93 reg_val &= ~CPLD_GPIO_BIT_POS_MASK(n);
94 writeb(reg_val, CPLD_GPIO_REG(n));
95
96 DBG("gpio=%d, l=0x%x\r\n", n, readb(SAPPHIRE_CPLD_INT_LEVEL));
97
98 local_irq_restore(flags);
99
100 return 0;
101}
102
103static int sapphire_gpio_configure(struct gpio_chip *chip, unsigned int gpio,
104 unsigned long flags)
105{
106 if (flags & (GPIOF_OUTPUT_LOW | GPIOF_OUTPUT_HIGH))
107 sapphire_gpio_write(chip, gpio, flags & GPIOF_OUTPUT_HIGH);
108
109 DBG("gpio=%d, l=0x%x\r\n", gpio, readb(SAPPHIRE_CPLD_INT_LEVEL));
110
111 return 0;
112}
113
114static int sapphire_gpio_get_irq_num(struct gpio_chip *chip, unsigned int gpio,
115 unsigned int *irqp, unsigned long *irqnumflagsp)
116{
117 DBG("gpio=%d, l=0x%x\r\n", gpio, readb(SAPPHIRE_CPLD_INT_LEVEL));
118 DBG("SAPPHIRE_GPIO_INT_B0_BASE=%d, SAPPHIRE_GPIO_LAST_INT=%d\r\n",
119 SAPPHIRE_GPIO_INT_B0_BASE, SAPPHIRE_GPIO_LAST_INT);
120 if ((gpio < SAPPHIRE_GPIO_INT_B0_BASE) ||
121 (gpio > SAPPHIRE_GPIO_LAST_INT))
122 return -ENOENT;
123 *irqp = SAPPHIRE_GPIO_TO_INT(gpio);
124 DBG("*irqp=%d\r\n", *irqp);
125 if (irqnumflagsp)
126 *irqnumflagsp = 0;
127 return 0;
128}
129
130/*write 1 to clear INT status bit.*/
131static void sapphire_gpio_irq_ack(unsigned int irq)
132{
133 /*write 1 to clear*/
134 writeb(SAPPHIRE_INT_BIT_MASK(irq), CPLD_INT_STATUS_REG(irq));
135}
136
137/*unmask/enable the INT
138static void sapphire_gpio_irq_unmask(unsigned int irq)*/
139static void sapphire_gpio_irq_enable(unsigned int irq)
140{
141 unsigned long flags;
142 uint8_t reg_val;
143
144 local_irq_save(flags); /*disabling all interrupts*/
145
146 reg_val = readb(CPLD_INT_MASK_REG(irq)) | SAPPHIRE_INT_BIT_MASK(irq);
147 DBG("(irq=%d,0x%x, 0x%x)\r\n", irq, CPLD_INT_MASK_REG(irq),
148 SAPPHIRE_INT_BIT_MASK(irq));
149 DBG("sapphire_suspended=%d\r\n", sapphire_suspended);
150 /*printk(KERN_INFO "sapphire_gpio_irq_mask irq %d => %d:%02x\n",
151 irq, bank, reg_val);*/
152 if (!sapphire_suspended)
153 writeb(reg_val, CPLD_INT_MASK_REG(irq));
154
155 reg_val = readb(CPLD_INT_MASK_REG(irq));
156 DBG("reg_val= 0x%x\r\n", reg_val);
157 DBG("l=0x%x\r\n", readb(SAPPHIRE_CPLD_INT_LEVEL));
158
159 local_irq_restore(flags); /*restore the interrupts*/
160}
161
162/*mask/disable INT
163static void sapphire_gpio_irq_mask(unsigned int irq)*/
164static void sapphire_gpio_irq_disable(unsigned int irq)
165{
166 unsigned long flags;
167 uint8_t reg_val;
168
169 local_irq_save(flags);
170 reg_val = readb(CPLD_INT_MASK_REG(irq)) & ~SAPPHIRE_INT_BIT_MASK(irq);
171 /*CPLD INT MASK is r/w now.*/
172
173 /*printk(KERN_INFO "sapphire_gpio_irq_unmask irq %d => %d:%02x\n",
174 irq, bank, reg_val);*/
175 DBG("(%d,0x%x, 0x%x, 0x%x)\r\n", irq, reg_val, CPLD_INT_MASK_REG(irq),
176 SAPPHIRE_INT_BIT_MASK(irq));
177 DBG("sapphire_suspended=%d\r\n", sapphire_suspended);
178 if (!sapphire_suspended)
179 writeb(reg_val, CPLD_INT_MASK_REG(irq));
180
181 reg_val = readb(CPLD_INT_MASK_REG(irq));
182 DBG("reg_val= 0x%x\r\n", reg_val);
183 DBG("l=0x%x\r\n", readb(SAPPHIRE_CPLD_INT_LEVEL));
184
185 local_irq_restore(flags);
186}
187
188/*preparing enable/disable wake source before sleep*/
189int sapphire_gpio_irq_set_wake(unsigned int irq, unsigned int on)
190{
191 unsigned long flags;
192 uint8_t mask = SAPPHIRE_INT_BIT_MASK(irq);
193
194 local_irq_save(flags);
195
196 if (on) /*wake on -> mask the bit*/
197 sapphire_sleep_int_mask[CPLD_INT_TO_BANK(irq)] |= mask;
198 else /*no wake -> unmask the bit*/
199 sapphire_sleep_int_mask[CPLD_INT_TO_BANK(irq)] &= ~mask;
200 local_irq_restore(flags);
201 return 0;
202}
203
204/*Sapphire has only one INT Bank.*/
205static void sapphire_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
206{
207 int j;
208 unsigned v;
209 int int_base = SAPPHIRE_INT_START;
210
211 v = readb(SAPPHIRE_CPLD_INT_STATUS); /*INT1 status reg, BANK0*/
212
213 for (j = 0; j < 8 ; j++) { /*8 bit per bank*/
214 if (v & (1U << j)) { /*got the INT Bit*/
215 DBG("generic_handle_irq j=0x%x\r\n", j);
216 generic_handle_irq(int_base + j);
217 }
218 }
219
220 desc->chip->ack(irq); /*clear CPLD INT in SOC side.*/
221 DBG("irq=%d, l=0x%x\r\n", irq, readb(SAPPHIRE_CPLD_INT_LEVEL));
222}
223
224/*Save current working sources before sleep, so we can restore it after
225 * resume.*/
226static int sapphire_sysdev_suspend(struct sys_device *dev, pm_message_t state)
227{
228 sapphire_suspended = 1;
229 /*save current masking*/
230 sapphire_int_mask[0] = readb(SAPPHIRE_CPLD_BASE +
231 SAPPHIRE_GPIO_INT_B0_MASK_REG);
232
233 /*set waking source before sleep.*/
234 writeb(sapphire_sleep_int_mask[0],
235 SAPPHIRE_CPLD_BASE + SAPPHIRE_GPIO_INT_B0_MASK_REG);
236
237 return 0;
238}
239
240/*All the registers will be kept till a power loss...*/
241int sapphire_sysdev_resume(struct sys_device *dev)
242{
243 /*restore the working mask saved before sleep*/
244 writeb(sapphire_int_mask[0], SAPPHIRE_CPLD_BASE +
245 SAPPHIRE_GPIO_INT_B0_MASK_REG);
246 sapphire_suspended = 0;
247 return 0;
248}
249
250/**
251 * linux/irq.h :: struct irq_chip
252 * @enable: enable the interrupt (defaults to chip->unmask if NULL)
253 * @disable: disable the interrupt (defaults to chip->mask if NULL)
254 * @ack: start of a new interrupt
255 * @mask: mask an interrupt source
256 * @mask_ack: ack and mask an interrupt source
257 * @unmask: unmask an interrupt source
258 */
259static struct irq_chip sapphire_gpio_irq_chip = {
260 .name = "sapphiregpio",
261 .ack = sapphire_gpio_irq_ack,
262 .mask = sapphire_gpio_irq_disable, /*sapphire_gpio_irq_mask,*/
263 .unmask = sapphire_gpio_irq_enable, /*sapphire_gpio_irq_unmask,*/
264 .set_wake = sapphire_gpio_irq_set_wake,
265 /*.set_type = sapphire_gpio_irq_set_type,*/
266};
267
268/*Thomas:For CPLD*/
269static struct gpio_chip sapphire_gpio_chip = {
270 .start = SAPPHIRE_GPIO_START,
271 .end = SAPPHIRE_GPIO_END,
272 .configure = sapphire_gpio_configure,
273 .get_irq_num = sapphire_gpio_get_irq_num,
274 .read = sapphire_gpio_read,
275 .write = sapphire_gpio_write,
276/* .read_detect_status = sapphire_gpio_read_detect_status,
277 .clear_detect_status = sapphire_gpio_clear_detect_status */
278};
279
280struct sysdev_class sapphire_sysdev_class = {
281 .name = "sapphiregpio_irq",
282 .suspend = sapphire_sysdev_suspend,
283 .resume = sapphire_sysdev_resume,
284};
285
286static struct sys_device sapphire_irq_device = {
287 .cls = &sapphire_sysdev_class,
288};
289
290int sapphire_init_gpio(void)
291{
292 int i;
293 if (!machine_is_sapphire())
294 return 0;
295
296 DBG("%d,%d\r\n", SAPPHIRE_INT_START, SAPPHIRE_INT_END);
297 DBG("NR_MSM_IRQS=%d, NR_GPIO_IRQS=%d\r\n", NR_MSM_IRQS, NR_GPIO_IRQS);
298 for (i = SAPPHIRE_INT_START; i <= SAPPHIRE_INT_END; i++) {
299 set_irq_chip(i, &sapphire_gpio_irq_chip);
300 set_irq_handler(i, handle_edge_irq);
301 set_irq_flags(i, IRQF_VALID);
302 }
303
304 register_gpio_chip(&sapphire_gpio_chip);
305
306 /*setup CPLD INT connecting to SOC's gpio 17 */
307 set_irq_type(MSM_GPIO_TO_INT(17), IRQF_TRIGGER_HIGH);
308 set_irq_chained_handler(MSM_GPIO_TO_INT(17), sapphire_gpio_irq_handler);
309 set_irq_wake(MSM_GPIO_TO_INT(17), 1);
310
311 if (sysdev_class_register(&sapphire_sysdev_class) == 0)
312 sysdev_register(&sapphire_irq_device);
313
314 return 0;
315}
316
317int sapphire_init_cpld(unsigned int sys_rev)
318{
319 int i;
320
321 for (i = 0; i < ARRAY_SIZE(sapphire_cpld_initdata); i++)
322 writeb(sapphire_cpld_initdata[i], SAPPHIRE_CPLD_BASE + i * 2);
323 return 0;
324}
325
326postcore_initcall(sapphire_init_gpio);