PageRenderTime 53ms CodeModel.GetById 22ms app.highlight 25ms RepoModel.GetById 2ms app.codeStats 0ms

/arch/arm/mach-msm/board-sapphire-gpio.c

https://github.com/AICP/kernel_google_msm
C | 326 lines | 215 code | 55 blank | 56 comment | 19 complexity | 31426d6facc2c3d0382180922aa55863 MD5 | raw file
  1/* 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);