temp revert rk change
[firefly-linux-kernel-4.4.55.git] / drivers / mfd / cpcap-irq.c
1 /*
2  * Copyright (C) 2009 - 2010, Motorola, All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
16  * 02111-1307, USA
17  */
18
19 #include <linux/gpio.h>
20 #include <linux/input.h>
21 #include <linux/interrupt.h>
22 #include <linux/irq.h>
23 #include <linux/mutex.h>
24 #include <linux/workqueue.h>
25 #include <linux/wakelock.h>
26
27 #include <linux/spi/cpcap.h>
28 #include <linux/spi/spi.h>
29 #include <linux/debugfs.h>
30 #include <linux/seq_file.h>
31
32 #define NUM_INT_REGS      5
33 #define NUM_INTS_PER_REG  16
34
35 #define CPCAP_INT1_VALID_BITS 0xFFFB
36 #define CPCAP_INT2_VALID_BITS 0xFFFF
37 #define CPCAP_INT3_VALID_BITS 0xFFFF
38 #define CPCAP_INT4_VALID_BITS 0x03FF
39 #define CPCAP_INT5_VALID_BITS 0xFFFF
40
41 struct cpcap_event_handler {
42         void (*func)(enum cpcap_irqs, void *);
43         void *data;
44 };
45
46 struct cpcap_irq_info {
47         uint8_t registered;
48         uint8_t enabled;
49         uint32_t count;
50 };
51
52 struct cpcap_irqdata {
53         struct mutex lock;
54         struct work_struct work;
55         struct workqueue_struct *workqueue;
56         struct cpcap_device *cpcap;
57         struct cpcap_event_handler event_handler[CPCAP_IRQ__NUM];
58         struct cpcap_irq_info irq_info[CPCAP_IRQ__NUM];
59         struct wake_lock wake_lock;
60 };
61
62 #define EVENT_MASK(event) (1 << ((event) % NUM_INTS_PER_REG))
63
64 enum pwrkey_states {
65         PWRKEY_RELEASE, /* Power key released state. */
66         PWRKEY_PRESS,   /* Power key pressed state. */
67         PWRKEY_UNKNOWN, /* Unknown power key state. */
68 };
69
70 static irqreturn_t event_isr(int irq, void *data)
71 {
72         struct cpcap_irqdata *irq_data = data;
73         disable_irq_nosync(irq);
74         wake_lock(&irq_data->wake_lock);
75         queue_work(irq_data->workqueue, &irq_data->work);
76
77         return IRQ_HANDLED;
78 }
79
80 static unsigned short get_int_reg(enum cpcap_irqs event)
81 {
82         unsigned short ret;
83
84         if ((event) >= CPCAP_IRQ_INT5_INDEX)
85                 ret = CPCAP_REG_MI1;
86         else if ((event) >= CPCAP_IRQ_INT4_INDEX)
87                 ret = CPCAP_REG_INT4;
88         else if ((event) >= CPCAP_IRQ_INT3_INDEX)
89                 ret = CPCAP_REG_INT3;
90         else if ((event) >= CPCAP_IRQ_INT2_INDEX)
91                 ret = CPCAP_REG_INT2;
92         else
93                 ret = CPCAP_REG_INT1;
94
95         return ret;
96 }
97
98 static unsigned short get_mask_reg(enum cpcap_irqs event)
99 {
100         unsigned short ret;
101
102         if (event >= CPCAP_IRQ_INT5_INDEX)
103                 ret = CPCAP_REG_MIM1;
104         else if (event >= CPCAP_IRQ_INT4_INDEX)
105                 ret = CPCAP_REG_INTM4;
106         else if (event >= CPCAP_IRQ_INT3_INDEX)
107                 ret = CPCAP_REG_INTM3;
108         else if (event >= CPCAP_IRQ_INT2_INDEX)
109                 ret = CPCAP_REG_INTM2;
110         else
111                 ret = CPCAP_REG_INTM1;
112
113         return ret;
114 }
115
116 static unsigned short get_sense_reg(enum cpcap_irqs event)
117 {
118         unsigned short ret;
119
120         if (event >= CPCAP_IRQ_INT5_INDEX)
121                 ret = CPCAP_REG_MI2;
122         else if (event >= CPCAP_IRQ_INT4_INDEX)
123                 ret = CPCAP_REG_INTS4;
124         else if (event >= CPCAP_IRQ_INT3_INDEX)
125                 ret = CPCAP_REG_INTS3;
126         else if (event >= CPCAP_IRQ_INT2_INDEX)
127                 ret = CPCAP_REG_INTS2;
128         else
129                 ret = CPCAP_REG_INTS1;
130
131         return ret;
132 }
133
134 void cpcap_irq_mask_all(struct cpcap_device *cpcap)
135 {
136         int i;
137
138         static const struct {
139                 unsigned short mask_reg;
140                 unsigned short valid;
141         } int_reg[NUM_INT_REGS] = {
142                 {CPCAP_REG_INTM1, CPCAP_INT1_VALID_BITS},
143                 {CPCAP_REG_INTM2, CPCAP_INT2_VALID_BITS},
144                 {CPCAP_REG_INTM3, CPCAP_INT3_VALID_BITS},
145                 {CPCAP_REG_INTM4, CPCAP_INT4_VALID_BITS},
146                 {CPCAP_REG_MIM1,  CPCAP_INT5_VALID_BITS}
147         };
148
149         for (i = 0; i < NUM_INT_REGS; i++) {
150                 cpcap_regacc_write(cpcap, int_reg[i].mask_reg,
151                                    int_reg[i].valid,
152                                    int_reg[i].valid);
153         }
154 }
155
156 struct pwrkey_data {
157         struct cpcap_device *cpcap;
158         enum pwrkey_states state;
159         struct wake_lock wake_lock;
160 };
161
162 static void pwrkey_handler(enum cpcap_irqs irq, void *data)
163 {
164         struct pwrkey_data *pwrkey_data = data;
165         enum pwrkey_states new_state, last_state = pwrkey_data->state;
166         struct cpcap_device *cpcap = pwrkey_data->cpcap;
167
168         new_state = (enum pwrkey_states) cpcap_irq_sense(cpcap, irq, 0);
169
170
171         if ((new_state < PWRKEY_UNKNOWN) && (new_state != last_state)) {
172                 wake_lock_timeout(&pwrkey_data->wake_lock, 20);
173                 cpcap_broadcast_key_event(cpcap, KEY_END, new_state);
174                 pwrkey_data->state = new_state;
175         } else if ((last_state == PWRKEY_RELEASE) &&
176                    (new_state == PWRKEY_RELEASE)) {
177                 /* Key must have been released before press was handled. Send
178                  * both the press and the release. */
179                 wake_lock_timeout(&pwrkey_data->wake_lock, 20);
180                 cpcap_broadcast_key_event(cpcap, KEY_END, PWRKEY_PRESS);
181                 cpcap_broadcast_key_event(cpcap, KEY_END, PWRKEY_RELEASE);
182         }
183         cpcap_irq_unmask(cpcap, CPCAP_IRQ_ON);
184 }
185
186 static int pwrkey_init(struct cpcap_device *cpcap)
187 {
188         struct pwrkey_data *data = kmalloc(sizeof(struct pwrkey_data),
189                                            GFP_KERNEL);
190         int retval;
191
192         if (!data)
193                 return -ENOMEM;
194         data->cpcap = cpcap;
195         data->state = PWRKEY_RELEASE;
196         retval = cpcap_irq_register(cpcap, CPCAP_IRQ_ON, pwrkey_handler, data);
197         if (retval)
198                 kfree(data);
199         wake_lock_init(&data->wake_lock, WAKE_LOCK_SUSPEND, "pwrkey");
200         return retval;
201 }
202
203 static void pwrkey_remove(struct cpcap_device *cpcap)
204 {
205         struct pwrkey_data *data;
206
207         cpcap_irq_get_data(cpcap, CPCAP_IRQ_ON, (void **)&data);
208         if (!data)
209                 return;
210         cpcap_irq_free(cpcap, CPCAP_IRQ_ON);
211         wake_lock_destroy(&data->wake_lock);
212         kfree(data);
213 }
214
215 static int int_read_and_clear(struct cpcap_device *cpcap,
216                               unsigned short status_reg,
217                               unsigned short mask_reg,
218                               unsigned short valid_mask,
219                               unsigned short *en)
220 {
221         unsigned short ireg_val, mreg_val;
222         int ret;
223         ret = cpcap_regacc_read(cpcap, status_reg, &ireg_val);
224         if (ret)
225                 return ret;
226         ret = cpcap_regacc_read(cpcap, mask_reg, &mreg_val);
227         if (ret)
228                 return ret;
229         *en |= ireg_val & ~mreg_val;
230         *en &= valid_mask;
231         ret = cpcap_regacc_write(cpcap, mask_reg, *en, *en);
232         if (ret)
233                 return ret;
234         ret = cpcap_regacc_write(cpcap, status_reg, *en, *en);
235         if (ret)
236                 return ret;
237         return 0;
238 }
239
240
241 static void irq_work_func(struct work_struct *work)
242 {
243         int retval = 0;
244         unsigned short en_ints[NUM_INT_REGS];
245         int i;
246         struct cpcap_irqdata *data;
247         struct cpcap_device *cpcap;
248         struct spi_device *spi;
249
250         static const struct {
251                 unsigned short status_reg;
252                 unsigned short mask_reg;
253                 unsigned short valid;
254         } int_reg[NUM_INT_REGS] = {
255                 {CPCAP_REG_INT1, CPCAP_REG_INTM1, CPCAP_INT1_VALID_BITS},
256                 {CPCAP_REG_INT2, CPCAP_REG_INTM2, CPCAP_INT2_VALID_BITS},
257                 {CPCAP_REG_INT3, CPCAP_REG_INTM3, CPCAP_INT3_VALID_BITS},
258                 {CPCAP_REG_INT4, CPCAP_REG_INTM4, CPCAP_INT4_VALID_BITS},
259                 {CPCAP_REG_MI1,  CPCAP_REG_MIM1,  CPCAP_INT5_VALID_BITS}
260         };
261
262         for (i = 0; i < NUM_INT_REGS; ++i)
263                 en_ints[i] = 0;
264
265         data = container_of(work, struct cpcap_irqdata, work);
266         cpcap = data->cpcap;
267         spi = cpcap->spi;
268
269         for (i = 0; i < NUM_INT_REGS; ++i) {
270                 retval = int_read_and_clear(cpcap,
271                                             int_reg[i].status_reg,
272                                             int_reg[i].mask_reg,
273                                             int_reg[i].valid,
274                                             &en_ints[i]);
275                 if (retval < 0) {
276                         dev_err(&spi->dev, "Error reading interrupts\n");
277                         break;
278                 }
279         }
280         enable_irq(spi->irq);
281
282         /* lock protects event handlers and data */
283         mutex_lock(&data->lock);
284         for (i = 0; i < NUM_INT_REGS; ++i) {
285                 unsigned char index;
286
287                 while (en_ints[i] > 0) {
288                         struct cpcap_event_handler *event_handler;
289
290                         /* find the first set bit */
291                         index = (unsigned char)(ffs(en_ints[i]) - 1);
292                         if (index >= CPCAP_IRQ__NUM)
293                                 goto error;
294                         /* clear the bit */
295                         en_ints[i] &= ~(1 << index);
296                         /* find the event that occurred */
297                         index += CPCAP_IRQ__START + (i * NUM_INTS_PER_REG);
298                         event_handler = &data->event_handler[index];
299
300                         if (event_handler->func)
301                                 event_handler->func(index, event_handler->data);
302
303                         data->irq_info[index].count++;
304                 }
305         }
306 error:
307         mutex_unlock(&data->lock);
308         wake_unlock(&data->wake_lock);
309 }
310
311 #ifdef CONFIG_DEBUG_FS
312 static int cpcap_dbg_irq_show(struct seq_file *s, void *data)
313 {
314         static const char *irq_name[] = {
315                 [CPCAP_IRQ_HSCLK]                 = "HSCLK",
316                 [CPCAP_IRQ_PRIMAC]                = "PRIMAC",
317                 [CPCAP_IRQ_SECMAC]                = "SECMAC",
318                 [CPCAP_IRQ_LOWBPL]                = "LOWBPL",
319                 [CPCAP_IRQ_SEC2PRI]               = "SEC2PRI",
320                 [CPCAP_IRQ_LOWBPH]                = "LOWBPH",
321                 [CPCAP_IRQ_EOL]                   = "EOL",
322                 [CPCAP_IRQ_TS]                    = "TS",
323                 [CPCAP_IRQ_ADCDONE]               = "ADCDONE",
324                 [CPCAP_IRQ_HS]                    = "HS",
325                 [CPCAP_IRQ_MB2]                   = "MB2",
326                 [CPCAP_IRQ_VBUSOV]                = "VBUSOV",
327                 [CPCAP_IRQ_RVRS_CHRG]             = "RVRS_CHRG",
328                 [CPCAP_IRQ_CHRG_DET]              = "CHRG_DET",
329                 [CPCAP_IRQ_IDFLOAT]               = "IDFLOAT",
330                 [CPCAP_IRQ_IDGND]                 = "IDGND",
331
332                 [CPCAP_IRQ_SE1]                   = "SE1",
333                 [CPCAP_IRQ_SESSEND]               = "SESSEND",
334                 [CPCAP_IRQ_SESSVLD]               = "SESSVLD",
335                 [CPCAP_IRQ_VBUSVLD]               = "VBUSVLD",
336                 [CPCAP_IRQ_CHRG_CURR1]            = "CHRG_CURR1",
337                 [CPCAP_IRQ_CHRG_CURR2]            = "CHRG_CURR2",
338                 [CPCAP_IRQ_RVRS_MODE]             = "RVRS_MODE",
339                 [CPCAP_IRQ_ON]                    = "ON",
340                 [CPCAP_IRQ_ON2]                   = "ON2",
341                 [CPCAP_IRQ_CLK]                   = "CLK",
342                 [CPCAP_IRQ_1HZ]                   = "1HZ",
343                 [CPCAP_IRQ_PTT]                   = "PTT",
344                 [CPCAP_IRQ_SE0CONN]               = "SE0CONN",
345                 [CPCAP_IRQ_CHRG_SE1B]             = "CHRG_SE1B",
346                 [CPCAP_IRQ_UART_ECHO_OVERRUN]     = "UART_ECHO_OVERRUN",
347                 [CPCAP_IRQ_EXTMEMHD]              = "EXTMEMHD",
348
349                 [CPCAP_IRQ_WARM]                  = "WARM",
350                 [CPCAP_IRQ_SYSRSTR]               = "SYSRSTR",
351                 [CPCAP_IRQ_SOFTRST]               = "SOFTRST",
352                 [CPCAP_IRQ_DIEPWRDWN]             = "DIEPWRDWN",
353                 [CPCAP_IRQ_DIETEMPH]              = "DIETEMPH",
354                 [CPCAP_IRQ_PC]                    = "PC",
355                 [CPCAP_IRQ_OFLOWSW]               = "OFLOWSW",
356                 [CPCAP_IRQ_TODA]                  = "TODA",
357                 [CPCAP_IRQ_OPT_SEL_DTCH]          = "OPT_SEL_DTCH",
358                 [CPCAP_IRQ_OPT_SEL_STATE]         = "OPT_SEL_STATE",
359                 [CPCAP_IRQ_ONEWIRE1]              = "ONEWIRE1",
360                 [CPCAP_IRQ_ONEWIRE2]              = "ONEWIRE2",
361                 [CPCAP_IRQ_ONEWIRE3]              = "ONEWIRE3",
362                 [CPCAP_IRQ_UCRESET]               = "UCRESET",
363                 [CPCAP_IRQ_PWRGOOD]               = "PWRGOOD",
364                 [CPCAP_IRQ_USBDPLLCLK]            = "USBDPLLCLK",
365
366                 [CPCAP_IRQ_DPI]                   = "DPI",
367                 [CPCAP_IRQ_DMI]                   = "DMI",
368                 [CPCAP_IRQ_UCBUSY]                = "UCBUSY",
369                 [CPCAP_IRQ_GCAI_CURR1]            = "GCAI_CURR1",
370                 [CPCAP_IRQ_GCAI_CURR2]            = "GCAI_CURR2",
371                 [CPCAP_IRQ_SB_MAX_RETRANSMIT_ERR] = "SB_MAX_RETRANSMIT_ERR",
372                 [CPCAP_IRQ_BATTDETB]              = "BATTDETB",
373                 [CPCAP_IRQ_PRIHALT]               = "PRIHALT",
374                 [CPCAP_IRQ_SECHALT]               = "SECHALT",
375                 [CPCAP_IRQ_CC_CAL]                = "CC_CAL",
376
377                 [CPCAP_IRQ_UC_PRIROMR]            = "UC_PRIROMR",
378                 [CPCAP_IRQ_UC_PRIRAMW]            = "UC_PRIRAMW",
379                 [CPCAP_IRQ_UC_PRIRAMR]            = "UC_PRIRAMR",
380                 [CPCAP_IRQ_UC_USEROFF]            = "UC_USEROFF",
381                 [CPCAP_IRQ_UC_PRIMACRO_4]         = "UC_PRIMACRO_4",
382                 [CPCAP_IRQ_UC_PRIMACRO_5]         = "UC_PRIMACRO_5",
383                 [CPCAP_IRQ_UC_PRIMACRO_6]         = "UC_PRIMACRO_6",
384                 [CPCAP_IRQ_UC_PRIMACRO_7]         = "UC_PRIMACRO_7",
385                 [CPCAP_IRQ_UC_PRIMACRO_8]         = "UC_PRIMACRO_8",
386                 [CPCAP_IRQ_UC_PRIMACRO_9]         = "UC_PRIMACRO_9",
387                 [CPCAP_IRQ_UC_PRIMACRO_10]        = "UC_PRIMACRO_10",
388                 [CPCAP_IRQ_UC_PRIMACRO_11]        = "UC_PRIMACRO_11",
389                 [CPCAP_IRQ_UC_PRIMACRO_12]        = "UC_PRIMACRO_12",
390                 [CPCAP_IRQ_UC_PRIMACRO_13]        = "UC_PRIMACRO_13",
391                 [CPCAP_IRQ_UC_PRIMACRO_14]        = "UC_PRIMACRO_14",
392                 [CPCAP_IRQ_UC_PRIMACRO_15]        = "UC_PRIMACRO_15",
393         };
394         unsigned int i;
395         struct cpcap_irqdata *irqdata = s->private;
396
397         seq_printf(s, "%21s%9s%12s%10s\n",
398                    "CPCAP IRQ", "Enabled", "Registered", "Count");
399
400         for (i = 0; i < CPCAP_IRQ__NUM; i++) {
401                 if ((i <= CPCAP_IRQ_CC_CAL) || (i >= CPCAP_IRQ_UC_PRIROMR)) {
402                         seq_printf(s, "%21s%9d%12d%10d\n",
403                                    irq_name[i],
404                                    irqdata->irq_info[i].enabled,
405                                    irqdata->irq_info[i].registered,
406                                    irqdata->irq_info[i].count);
407                 }
408         }
409         return 0;
410 }
411
412 static int cpcap_dbg_irq_open(struct inode *inode, struct file *file)
413 {
414         return single_open(file, cpcap_dbg_irq_show, inode->i_private);
415 }
416
417 static const struct file_operations debug_fops = {
418         .open    = cpcap_dbg_irq_open,
419         .read    = seq_read,
420         .llseek  = seq_lseek,
421         .release = single_release,
422 };
423 #endif
424
425 int cpcap_irq_init(struct cpcap_device *cpcap)
426 {
427         int retval;
428         struct spi_device *spi = cpcap->spi;
429         struct cpcap_irqdata *data;
430
431         data = kzalloc(sizeof(struct cpcap_irqdata), GFP_KERNEL);
432         if (!data)
433                 return -ENOMEM;
434
435         cpcap_irq_mask_all(cpcap);
436
437         data->workqueue = create_singlethread_workqueue("cpcap_irq");
438         INIT_WORK(&data->work, irq_work_func);
439         mutex_init(&data->lock);
440         wake_lock_init(&data->wake_lock, WAKE_LOCK_SUSPEND, "cpcap-irq");
441         data->cpcap = cpcap;
442
443         retval = request_irq(spi->irq, event_isr, IRQF_DISABLED |
444                              IRQF_TRIGGER_HIGH, "cpcap-irq", data);
445         if (retval) {
446                 printk(KERN_ERR "cpcap_irq: Failed requesting irq.\n");
447                 goto error;
448         }
449
450         enable_irq_wake(spi->irq);
451
452         cpcap->irqdata = data;
453         retval = pwrkey_init(cpcap);
454         if (retval) {
455                 printk(KERN_ERR "cpcap_irq: Failed initializing pwrkey.\n");
456                 goto error;
457         }
458 #ifdef CONFIG_DEBUG_FS
459         (void)debugfs_create_file("cpcap-irq", S_IRUGO, NULL, data,
460                                   &debug_fops);
461 #endif
462         return 0;
463
464 error:
465         free_irq(spi->irq, data);
466         kfree(data);
467         printk(KERN_ERR "cpcap_irq: Error registering cpcap irq.\n");
468         return retval;
469 }
470
471 void cpcap_irq_shutdown(struct cpcap_device *cpcap)
472 {
473         struct spi_device *spi = cpcap->spi;
474         struct cpcap_irqdata *data = cpcap->irqdata;
475
476         pwrkey_remove(cpcap);
477         cancel_work_sync(&data->work);
478         destroy_workqueue(data->workqueue);
479         free_irq(spi->irq, data);
480         kfree(data);
481 }
482
483 int cpcap_irq_register(struct cpcap_device *cpcap,
484                        enum cpcap_irqs irq,
485                        void (*cb_func) (enum cpcap_irqs, void *),
486                        void *data)
487 {
488         struct cpcap_irqdata *irqdata = cpcap->irqdata;
489         int retval = 0;
490
491         if ((irq >= CPCAP_IRQ__NUM) || (!cb_func))
492                 return -EINVAL;
493
494         mutex_lock(&irqdata->lock);
495
496         if (irqdata->event_handler[irq].func == NULL) {
497                 irqdata->irq_info[irq].registered = 1;
498                 cpcap_irq_unmask(cpcap, irq);
499                 irqdata->event_handler[irq].func = cb_func;
500                 irqdata->event_handler[irq].data = data;
501         } else
502                 retval = -EPERM;
503
504         mutex_unlock(&irqdata->lock);
505
506         return retval;
507 }
508 EXPORT_SYMBOL_GPL(cpcap_irq_register);
509
510 int cpcap_irq_free(struct cpcap_device *cpcap, enum cpcap_irqs irq)
511 {
512         struct cpcap_irqdata *data = cpcap->irqdata;
513         int retval;
514
515         if (irq >= CPCAP_IRQ__NUM)
516                 return -EINVAL;
517
518         mutex_lock(&data->lock);
519         retval = cpcap_irq_mask(cpcap, irq);
520         data->event_handler[irq].func = NULL;
521         data->event_handler[irq].data = NULL;
522         data->irq_info[irq].registered = 0;
523         mutex_unlock(&data->lock);
524
525         return retval;
526 }
527 EXPORT_SYMBOL_GPL(cpcap_irq_free);
528
529 int cpcap_irq_get_data(struct cpcap_device *cpcap,
530                         enum cpcap_irqs irq,
531                         void **data)
532 {
533         struct cpcap_irqdata *irqdata = cpcap->irqdata;
534
535         if (irq >= CPCAP_IRQ__NUM)
536                 return -EINVAL;
537
538         mutex_lock(&irqdata->lock);
539         *data = irqdata->event_handler[irq].data;
540         mutex_unlock(&irqdata->lock);
541
542         return 0;
543 }
544 EXPORT_SYMBOL_GPL(cpcap_irq_get_data);
545
546 int cpcap_irq_clear(struct cpcap_device *cpcap,
547                     enum cpcap_irqs irq)
548 {
549         int retval = -EINVAL;
550
551         if ((irq < CPCAP_IRQ__NUM) && (irq != CPCAP_IRQ_SECMAC)) {
552                 retval = cpcap_regacc_write(cpcap,
553                                             get_int_reg(irq),
554                                             EVENT_MASK(irq),
555                                             EVENT_MASK(irq));
556         }
557
558         return retval;
559 }
560 EXPORT_SYMBOL_GPL(cpcap_irq_clear);
561
562 int cpcap_irq_mask(struct cpcap_device *cpcap,
563                    enum cpcap_irqs irq)
564 {
565         struct cpcap_irqdata *data = cpcap->irqdata;
566         int retval = -EINVAL;
567
568         if ((irq < CPCAP_IRQ__NUM) && (irq != CPCAP_IRQ_SECMAC)) {
569                 data->irq_info[irq].enabled = 0;
570                 retval = cpcap_regacc_write(cpcap,
571                                             get_mask_reg(irq),
572                                             EVENT_MASK(irq),
573                                             EVENT_MASK(irq));
574         }
575
576         return retval;
577 }
578 EXPORT_SYMBOL_GPL(cpcap_irq_mask);
579
580 int cpcap_irq_unmask(struct cpcap_device *cpcap,
581                      enum cpcap_irqs irq)
582 {
583         struct cpcap_irqdata *data = cpcap->irqdata;
584         int retval = -EINVAL;
585
586         if ((irq < CPCAP_IRQ__NUM) && (irq != CPCAP_IRQ_SECMAC)) {
587                 data->irq_info[irq].enabled = 1;
588                 retval = cpcap_regacc_write(cpcap,
589                                             get_mask_reg(irq),
590                                             0,
591                                             EVENT_MASK(irq));
592         }
593
594         return retval;
595 }
596 EXPORT_SYMBOL_GPL(cpcap_irq_unmask);
597
598 int cpcap_irq_mask_get(struct cpcap_device *cpcap,
599                        enum cpcap_irqs irq)
600 {
601         struct cpcap_irqdata *data = cpcap->irqdata;
602         int retval = -EINVAL;
603
604         if ((irq < CPCAP_IRQ__NUM) && (irq != CPCAP_IRQ_SECMAC))
605                 return data->irq_info[irq].enabled;
606
607         return retval;
608 }
609 EXPORT_SYMBOL_GPL(cpcap_irq_mask_get);
610
611 int cpcap_irq_sense(struct cpcap_device *cpcap,
612                     enum cpcap_irqs irq,
613                     unsigned char clear)
614 {
615         unsigned short val;
616         int retval;
617
618         if (irq >= CPCAP_IRQ__NUM)
619                 return -EINVAL;
620
621         retval = cpcap_regacc_read(cpcap, get_sense_reg(irq), &val);
622         if (retval)
623                 return retval;
624
625         if (clear)
626                 retval = cpcap_irq_clear(cpcap, irq);
627         if (retval)
628                 return retval;
629
630         return ((val & EVENT_MASK(irq)) != 0) ? 1 : 0;
631 }
632 EXPORT_SYMBOL_GPL(cpcap_irq_sense);
633
634 #ifdef CONFIG_PM
635 int cpcap_irq_suspend(struct cpcap_device *cpcap)
636 {
637         struct spi_device *spi = cpcap->spi;
638         struct cpcap_irqdata *data = cpcap->irqdata;
639
640         disable_irq(spi->irq);
641         flush_work(&data->work);
642         return 0;
643 }
644
645 int cpcap_irq_resume(struct cpcap_device *cpcap)
646 {
647         struct spi_device *spi = cpcap->spi;
648
649         enable_irq(spi->irq);
650         return 0;
651 }
652 #endif