2 * Copyright (C) 2010 ROCKCHIP, Inc.
\r
4 * This software is licensed under the terms of the GNU General Public
\r
5 * License version 2, as published by the Free Software Foundation, and
\r
6 * may be copied, distributed, and modified under those terms.
\r
8 * This program is distributed in the hope that it will be useful,
\r
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
11 * GNU General Public License for more details.
\r
14 /*******************************************************************/
\r
15 /* COPYRIGHT (C) ROCK-CHIPS FUZHOU . ALL RIGHTS RESERVED.*/
\r
16 /*******************************************************************
\r
17 FILE : Soft_interrupt.c
\r
21 ********************************************************************/
\r
22 #include <asm/mach/time.h>
\r
23 #include <linux/clk.h>
\r
24 #include <linux/errno.h>
\r
25 #include <linux/interrupt.h>
\r
26 #include <asm/mach-types.h>
\r
27 #include <linux/irq.h>
\r
28 #include <linux/debugfs.h>
\r
29 #include <linux/seq_file.h>
\r
30 #include <linux/kernel.h>
\r
31 #include <linux/list.h>
\r
32 #include <linux/module.h>
\r
33 #include <linux/io.h>
\r
34 #include <mach/hardware.h>
\r
35 #include <mach/gpio.h>
\r
36 #include <mach/rk2818_iomap.h>
\r
37 #include <mach/iomux.h>
\r
38 #include <linux/device.h>
\r
39 #include <mach/gpio.h>
\r
40 #include <asm/gpio.h>
\r
41 #include <linux/i2c.h>
\r
42 #include <linux/workqueue.h>
\r
43 #include <mach/board.h>
\r
44 #include <linux/delay.h>
\r
45 #include <linux/i2c/tca6424.h>
\r
46 #include <linux/ktime.h>
\r
47 #include "../drivers/gpio/expand_gpio_soft_interrupt.h"
\r
50 #define DBG(x...) printk(KERN_INFO x)
\r
54 #define DBGERR(x...) printk(KERN_INFO x)
\r
57 #define EXTPAND_GPIO_GET_BIT(a,num) (((a)>>(num))&0x01)
\r
58 #define EXTPAND_GPIO_SET_BIT(a,num) ((a)|(0x01<<(num)))
\r
59 #define EXTPAND_GPIO_CLEAR_BIT(a,num) ((a)&(~(0x01<<(num))))
\r
60 #define MIN(x,y) (((x)<(y))?(x):(y))
\r
63 static int expand_gpio_irq_en = -1;
\r
64 static int expand_gpio_irq_ctrflag = 0;
\r
65 static unsigned int expand_gpio_irq_num = 0;
\r
67 static struct workqueue_struct *irqworkqueue;
\r
68 static struct lock_class_key gpio_lock_class;
70 struct expand_gpio_soft_int expand_irq_data;
\r
72 void expand_gpio_irq_ctr_dis(int irq,int ctrflag)
\r
74 expand_gpio_irq_ctrflag=0;
\r
75 if(expand_gpio_irq_en)
\r
77 expand_gpio_irq_en=0;
\r
78 disable_irq_nosync(irq);
\r
79 DBG("***********%s %d***********\n",__FUNCTION__,__LINE__);
\r
83 expand_gpio_irq_ctrflag=-1;
\r
87 void expand_gpio_irq_ctr_en(int irq)
\r
89 if(!expand_gpio_irq_en)
\r
91 DBG("***********%s %d***********\n",__FUNCTION__,__LINE__);
\r
92 expand_gpio_irq_en = -1;
\r
97 static int expand_checkrange(int start,int num,int val)
\r
100 if((val<(start+num))&&(val>=start))
\r
111 static void expand_gpio_irq_enable(unsigned irq)
\r
113 struct irq_desc *desc = irq_to_desc(irq);
\r
114 struct expand_gpio_soft_int *pchip=(struct expand_gpio_soft_int *)desc->chip_data;
\r
115 uint8_t gpioPortNum;
\r
116 uint8_t gpioPortPinNum;
\r
117 uint8_t expandpinnum;
\r
119 if(!expand_checkrange(pchip->gpio_irq_start,pchip->irq_pin_num,irq))
\r
121 expandpinnum = irq - pchip->gpio_irq_start;//irq_to_gpio(irq)
\r
127 gpioPortNum = expandpinnum/(pchip->expand_port_pinnum);
\r
128 gpioPortPinNum= expandpinnum%(pchip->expand_port_pinnum);
\r
130 if((gpioPortNum>=(pchip->expand_port_group))||(gpioPortPinNum>=(pchip->expand_port_pinnum)))
\r
132 //DBG("**%s**\n",__FUNCTION__);
\r
133 pchip->interrupt_en[gpioPortNum]=EXTPAND_GPIO_SET_BIT(pchip->interrupt_en[gpioPortNum],gpioPortPinNum);
\r
135 static void expand_gpio_irq_disable(unsigned irq)
\r
137 struct irq_desc *desc = irq_to_desc(irq);
\r
138 struct expand_gpio_soft_int *pchip=(struct expand_gpio_soft_int *)desc->chip_data;
\r
139 uint8_t gpioPortNum;
\r
140 uint8_t gpioPortPinNum;
\r
141 uint8_t expandpinnum;
\r
143 if(!expand_checkrange(pchip->gpio_irq_start,pchip->irq_pin_num,irq))
\r
145 expandpinnum=irq - pchip->gpio_irq_start;//irq_to_gpio(irq)
\r
151 gpioPortNum = expandpinnum/(pchip->expand_port_pinnum);
\r
152 gpioPortPinNum= expandpinnum%(pchip->expand_port_pinnum);
\r
154 if((gpioPortNum>=(pchip->expand_port_group))||(gpioPortPinNum>=(pchip->expand_port_pinnum)))
\r
156 //DBG("**%s**\n",__FUNCTION__);
\r
157 pchip->interrupt_en[gpioPortNum]=EXTPAND_GPIO_CLEAR_BIT(pchip->interrupt_en[gpioPortNum],gpioPortPinNum);
\r
161 static void expand_gpio_irq_mask(unsigned irq)
\r
163 struct irq_desc *desc = irq_to_desc(irq);
\r
164 struct expand_gpio_soft_int *pchip=(struct expand_gpio_soft_int *)desc->chip_data;
\r
165 uint8_t gpioPortNum;
\r
166 uint8_t gpioPortPinNum;
\r
167 uint8_t expandpinnum;
\r
169 if(!expand_checkrange(pchip->gpio_irq_start,pchip->irq_pin_num,irq))
\r
171 expandpinnum=irq-pchip->gpio_irq_start;//irq_to_gpio(irq)
\r
177 gpioPortNum = expandpinnum/(pchip->expand_port_pinnum);
\r
178 gpioPortPinNum= expandpinnum%(pchip->expand_port_pinnum);
\r
179 if((gpioPortNum>=(pchip->expand_port_group))||(gpioPortPinNum>=(pchip->expand_port_pinnum)))
\r
181 //DBG("**%s**\n",__FUNCTION__);
\r
182 pchip->interrupt_mask[gpioPortNum]=EXTPAND_GPIO_SET_BIT(pchip->interrupt_mask[gpioPortNum],gpioPortPinNum);
\r
185 static void expand_gpio_irq_unmask(unsigned irq)
\r
187 struct irq_desc *desc = irq_to_desc(irq);
\r
188 struct expand_gpio_soft_int *pchip=(struct expand_gpio_soft_int *)desc->chip_data;
\r
189 uint8_t gpioPortNum;
\r
190 uint8_t gpioPortPinNum;
\r
191 uint8_t expandpinnum;
\r
193 if(!expand_checkrange(pchip->gpio_irq_start,pchip->irq_pin_num,irq))
\r
195 expandpinnum=irq-pchip->gpio_irq_start;//irq_to_gpio(irq)
\r
201 gpioPortNum = expandpinnum/(pchip->expand_port_pinnum);
\r
202 gpioPortPinNum= expandpinnum%(pchip->expand_port_pinnum);
\r
203 if((gpioPortNum>=(pchip->expand_port_group))||(gpioPortPinNum>=(pchip->expand_port_pinnum)))
\r
205 //DBG("**%s**\n",__FUNCTION__);
\r
206 pchip->interrupt_mask[gpioPortNum]=EXTPAND_GPIO_CLEAR_BIT(pchip->interrupt_mask[gpioPortNum],gpioPortPinNum);
\r
209 static int expand_gpio_irq_type(unsigned int irq, unsigned int type)
\r
211 struct irq_desc *desc_irq=irq_to_desc(irq);
\r
212 struct expand_gpio_soft_int *pchip=(struct expand_gpio_soft_int *)desc_irq->chip_data;
\r
213 uint8_t gpioPortNum;
\r
214 uint8_t gpioPortPinNum;
\r
215 uint8_t expandpinnum;
\r
216 if(!expand_checkrange(pchip->gpio_irq_start,pchip->irq_pin_num,irq))
\r
218 expandpinnum = irq - pchip->gpio_irq_start;//irq_to_gpio(irq)
\r
225 gpioPortNum = expandpinnum/(pchip->expand_port_pinnum);
\r
226 gpioPortPinNum= expandpinnum%(pchip->expand_port_pinnum);
\r
227 if((gpioPortNum>=(pchip->expand_port_group))||(gpioPortPinNum>=(pchip->expand_port_pinnum)))
\r
229 DBG("**%s %d PortNum=%d,PortPinNum=%d**\n",__FUNCTION__,__LINE__,gpioPortNum,gpioPortPinNum);
\r
231 case IRQ_TYPE_NONE:
\r
232 pchip->inttype_set[gpioPortNum]=EXTPAND_GPIO_CLEAR_BIT(pchip->inttype_set[gpioPortNum],gpioPortPinNum);
\r
233 DBG("**%s IRQ_TYPE_NONE**\n",__FUNCTION__);
\r
235 case IRQ_TYPE_EDGE_RISING:
\r
236 pchip->inttype_set[gpioPortNum]=EXTPAND_GPIO_SET_BIT(pchip->inttype_set[gpioPortNum],gpioPortPinNum);
\r
237 pchip->inttype[gpioPortNum]=EXTPAND_GPIO_SET_BIT(pchip->inttype[gpioPortNum],gpioPortPinNum);
\r
238 pchip->inttype1[gpioPortNum]=EXTPAND_GPIO_CLEAR_BIT(pchip->inttype1[gpioPortNum],gpioPortPinNum);
\r
239 DBG("**%s IRQ_TYPE_EDGE_RISING,inttype=%x,inttype1=%x**\n",__FUNCTION__,pchip->inttype[gpioPortNum],pchip->inttype1[gpioPortNum]);
\r
241 case IRQ_TYPE_EDGE_FALLING:
\r
242 pchip->inttype_set[gpioPortNum]=EXTPAND_GPIO_SET_BIT(pchip->inttype_set[gpioPortNum],gpioPortPinNum);
\r
243 pchip->inttype[gpioPortNum]=EXTPAND_GPIO_CLEAR_BIT(pchip->inttype[gpioPortNum],gpioPortPinNum);
\r
244 pchip->inttype1[gpioPortNum]=EXTPAND_GPIO_CLEAR_BIT(pchip->inttype1[gpioPortNum],gpioPortPinNum);
\r
245 DBG("**%s IRQ_TYPE_EDGE_RISING,inttype=%x,inttype1=%x**\n",__FUNCTION__,pchip->inttype[gpioPortNum],pchip->inttype1[gpioPortNum]);
\r
247 case IRQ_TYPE_EDGE_BOTH:
\r
248 pchip->inttype_set[gpioPortNum]=EXTPAND_GPIO_SET_BIT(pchip->inttype_set[gpioPortNum],gpioPortPinNum);
\r
249 pchip->inttype1[gpioPortNum]=EXTPAND_GPIO_SET_BIT(pchip->inttype1[gpioPortNum],gpioPortPinNum);
\r
250 DBG("**%s IRQ_TYPE_EDGE_RISING,inttype=%x,inttype1=%x**\n",__FUNCTION__,pchip->inttype[gpioPortNum],pchip->inttype1[gpioPortNum]);
\r
252 case IRQ_TYPE_LEVEL_HIGH:
\r
253 pchip->inttype_set[gpioPortNum]=EXTPAND_GPIO_CLEAR_BIT(pchip->inttype_set[gpioPortNum],gpioPortPinNum);
\r
254 DBG("extern gpios does not support IRQ_TYPE_LEVEL_HIGH irq typ");
\r
256 case IRQ_TYPE_LEVEL_LOW:
\r
257 pchip->inttype_set[gpioPortNum]=EXTPAND_GPIO_CLEAR_BIT(pchip->inttype_set[gpioPortNum],gpioPortPinNum);
\r
258 DBG("extern gpios does not support IRQ_TYPE_LEVEL_LOW irq typ");
\r
266 static int expand_gpio_irq_set_wake(unsigned irq, unsigned state)
\r
271 static struct irq_chip expand_gpio_irqchip = {
\r
272 .name = "expand_gpio_expand ",
\r
273 .enable = expand_gpio_irq_enable,
\r
274 .disable = expand_gpio_irq_disable,
\r
275 .mask = expand_gpio_irq_mask,
\r
276 .unmask = expand_gpio_irq_unmask,
\r
277 .set_type = expand_gpio_irq_type,
\r
278 .set_wake = expand_gpio_irq_set_wake,
\r
281 static irqreturn_t expand_gpio_irq_handler(int irq, void * dev_id)
\r
283 struct irq_desc *gpio_irq_desc = irq_to_desc(irq);
\r
284 struct expand_gpio_soft_int *pchip=(struct expand_gpio_soft_int *)gpio_irq_desc->chip_data;
\r
285 u8 oldintputreg[MAX_SUPPORT_PORT_GROUP]={0,0,0,0,0};
\r
286 u8 tempintputreg[MAX_SUPPORT_PORT_GROUP]={0,0,0,0,0};
\r
287 u8 tempallowint=0;
\r
289 u8 intbit[MAX_SUPPORT_PORT_GROUP]={0,0,0,0,0};
\r
294 DBG("******************%s*******************\n",__FUNCTION__);
\r
295 expand_gpio_irq_ctr_dis(pchip->irq_chain,0);
\r
296 memcpy(&oldintputreg[0],&pchip->gvar->reg_input[0],pchip->expand_port_group);
\r
297 if(pchip->irq_data.read_allinputreg(pchip->irq_data.data,&tempintputreg[0]))
\r
299 expand_gpio_irq_ctr_dis(pchip->irq_chain,-1);
\r
300 DBG("**%s[%d] reading reg is error\n",__FUNCTION__,__LINE__);
\r
301 queue_work(irqworkqueue,&pchip->irq_work);
\r
302 return IRQ_HANDLED;
\r
305 memcpy(&pchip->gvar->reg_input[0],&tempintputreg[0],pchip->expand_port_group);
\r
306 //DBG("**has run at %s**,input[0] = %x,input[1] = %x,input[2] = %x\n",__FUNCTION__,pchip->gvar.reg_input[0],pchip->gvar.reg_input[1],pchip->gvar.reg_input[2]);
\r
308 //Handle for different expand_port_group
\r
309 for(i=0,int_en_flag=0;i<MIN(pchip->expand_port_group,MAX_SUPPORT_PORT_GROUP);i++)
\r
311 int_en_flag|=pchip->interrupt_en[i];
\r
316 if(expand_gpio_irq_num<0xFFFFFFFF)
\r
318 expand_gpio_irq_num++;
\r
322 expand_gpio_irq_num=0;
\r
324 DBGERR("there are no pin reg irq\n");
\r
325 expand_gpio_irq_ctr_en(pchip->irq_chain);
\r
326 return IRQ_HANDLED;
\r
329 for(i=0;i<pchip->expand_port_group;i++)
\r
331 tempallowint=pchip->interrupt_en[i]&pchip->gvar->reg_direction[i]&(~pchip->interrupt_mask[i]);// Âú×ãÖжÏÌõ¼þ
\r
332 levelchg=oldintputreg[i]^tempintputreg[i];// ÕÒ³öÇ°ºó״̬²»Ò»ÑùµÄpin
\r
333 tempinttype=~(tempintputreg[i]^pchip->inttype[i]);// ÕÒ³ö´¥·¢×´Ì¬ºÍµ±Ç°pin״̬һÑùµÄpin£¬×¢ÒâÖ»Ö§³Ölow highÁ½ÖÖpin´¥·¢
\r
335 tempinttype=(~pchip->inttype1[i])&tempinttype;// inttype1 ΪÕæµÄλ¶ÔÓ¦µÄtempinttypeλÇåÁ㣬ÒòΪ¸ÃλֻÊÜinttype1¿ØÖÆ
\r
336 tempinttype|=pchip->inttype1[i];//µçƽֻҪÊDZ仯¾Í²úÉúÖжÏ
\r
337 tempinttype&=pchip->inttype_set[i];//ÒѾÉèÖÃÁËtypeÀàÐÍ
\r
339 intbit[i]=tempallowint&levelchg&tempinttype;
\r
340 //DBG(" tempallowint=%x,levelchg=%x,tempinttype=%x,intbit=%d\n",tempallowint,levelchg,tempinttype,intbit[i]);
\r
342 if(expand_gpio_irq_num<0xFFFFFFFF)
\r
344 expand_gpio_irq_num++;
\r
348 expand_gpio_irq_num=0;
\r
350 for(i=0;i<pchip->expand_port_group;i++)
\r
354 for(j=0;j<pchip->expand_port_pinnum;j++)
\r
356 if(EXTPAND_GPIO_GET_BIT(intbit[i],j))
\r
358 irq=pchip->gpio_irq_start+pchip->expand_port_pinnum*i+j;
\r
359 gpio_irq_desc = irq_to_desc(irq);
\r
360 gpio_irq_desc->chip->mask(irq);
\r
361 generic_handle_irq(irq);
\r
362 gpio_irq_desc->chip->unmask(irq);
\r
363 //DBG("expand_i2c_irq_handler port=%d,pin=%d,pinlevel=%d\n",i,j,EXTPAND_GPIO_GET_BIT(tempintputreg[i],j));
\r
368 expand_gpio_irq_ctr_en(pchip->irq_chain);
\r
369 return IRQ_HANDLED;
\r
372 static void irq_call_back_handler(struct work_struct *work)
\r
374 struct expand_gpio_soft_int *pchip = container_of(work, struct expand_gpio_soft_int,irq_work);
\r
375 //printk("irq_call_back_handle\n");
\r
376 expand_gpio_irq_handler(pchip->irq_chain,NULL);
\r
379 void expand_gpio_irq_setup(struct expand_gpio_soft_int *pchip)
\r
381 unsigned int pioc, irq_num;
\r
383 struct irq_desc *desc;
\r
384 irq_num = pchip->gpio_irq_start; //ÖжϺţ¬À©Õ¹ioµÄÖжϺÅÓ¦¸Ã½ô¸úÔÚÄÚ²¿ioÖжϺŵĺóÃæ¡£ÈçrkÄÚ²¿ÖжÏ48¸ö£¬¼ÓÉÏÄÚ²¿gpio 16¸öÐéÄâÖжϣ¬ÕâÀïpinÓ¦¸Ã´Ó48+16¿ªÊ¼
\r
386 DBG("**%s**\n",__FUNCTION__);
\r
387 for (pioc = 0; pioc < pchip->irq_pin_num; pioc++,irq_num++)
\r
389 lockdep_set_class(&irq_desc[irq_num].lock, &gpio_lock_class);
\r
391 * Can use the "simple" and not "edge" handler since it's
\r
392 * shorter, and the AIC handles interrupts sanely.
\r
394 set_irq_chip(irq_num, &expand_gpio_irqchip);
\r
395 set_irq_handler(irq_num, handle_simple_irq);
\r
396 set_irq_chip_data(irq_num,(void *)pchip);
\r
397 desc = irq_to_desc(irq_num);
\r
398 DBG("**%s line=%d,irq_num=%d**\n",__FUNCTION__,__LINE__,irq_num);
\r
399 set_irq_flags(irq_num, IRQF_VALID);
\r
401 ret = gpio_request(pchip->irq_gpiopin,NULL);
\r
404 gpio_free(pchip->irq_gpiopin);
\r
405 DBG("expand_gpio_irq_setup request gpio is err\n");
\r
407 gpio_pull_updown(pchip->irq_gpiopin, pchip->rk_irq_gpio_pull_up_down); //gpio ÐèÒªÀ¸ßirq_to_gpio(pchip->irq_chain)
\r
408 irqworkqueue=create_rt_workqueue("irq workqueue");
\r
409 INIT_WORK(&pchip->irq_work,irq_call_back_handler);
\r
410 set_irq_chip_data(pchip->irq_chain, pchip);
\r
411 if(request_irq(pchip->irq_chain,expand_gpio_irq_handler,pchip->rk_irq_mode, "expand", pchip)!=0)
\r
413 DBG("**%s line=%d is err**\n",__FUNCTION__,__LINE__);
\r
417 int wait_untill_input_reg_flash(void)
\r
419 unsigned int num = 0;
\r
420 unsigned int tempnum = expand_gpio_irq_num;
\r
422 while(expand_gpio_irq_ctrflag&&(expand_gpio_irq_num==tempnum))
\r
432 void expand_irq_init(void *data,struct expand_gpio_global_variable *var,irq_read_inputreg handler)
\r
434 expand_irq_data.irq_data.data = data;
\r
435 expand_irq_data.irq_data.read_allinputreg = handler;
\r
436 expand_irq_data.gvar = var;
\r
437 expand_gpio_irq_setup(&expand_irq_data);
\r