#include <linux/mfd/wm831x/irq.h>
#include <linux/delay.h>
-#include <linux/wakelock.h>
+
/*
* Since generic IRQs don't currently support interrupt controllers on
* interrupt driven buses we don't use genirq but instead provide an
* the static irq_data table we use to look up the data for individual
* interrupts, but hopefully won't last too long.
*/
-#define WM831X_IRQ_TYPE IRQF_TRIGGER_LOW
struct wm831x_irq_data {
int primary;
int mask;
};
-struct wm831x_handle_irq
-{
- int irq;
- struct list_head queue;
-};
-
static struct wm831x_irq_data wm831x_irqs[] = {
[WM831X_IRQ_TEMP_THW] = {
.primary = WM831X_TEMP_INT,
struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq);
wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
- //printk("%s:irq=%d\n",__FUNCTION__,irq);
}
static void wm831x_irq_mask(unsigned int irq)
struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq);
wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
- //printk("%s:irq=%d\n",__FUNCTION__,irq);
-}
-
-static void wm831x_irq_disable(unsigned int irq)
-{
- struct wm831x *wm831x = get_irq_chip_data(irq);
- struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq);
-
- wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
- //printk("%s:irq=%d\n",__FUNCTION__,irq);
}
static int wm831x_irq_set_type(unsigned int irq, unsigned int type)
int val;
irq = irq - wm831x->irq_base;
- if (irq < WM831X_IRQ_GPIO_1 || irq > WM831X_IRQ_GPIO_12) {
+
+ if (irq < WM831X_IRQ_GPIO_1 || irq > WM831X_IRQ_GPIO_11) {
/* Ignore internal-only IRQs */
if (irq >= 0 && irq < WM831X_NUM_IRQS)
return 0;
else
return -EINVAL;
}
- //printk("wm831x_irq_set_type:type=%x,irq=%d\n",type,irq);
+
switch (type) {
case IRQ_TYPE_EDGE_BOTH:
val = WM831X_GPN_INT_MODE;
return -EINVAL;
}
- return wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + irq - 1,
+ return wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + irq,
WM831X_GPN_INT_MODE | WM831X_GPN_POL, val);
}
-static int wm831x_irq_set_wake(unsigned irq, unsigned state)
-{
- struct wm831x *wm831x = get_irq_chip_data(irq);
-
- //only wm831x irq
- if ((irq > wm831x->irq_base + WM831X_IRQ_TEMP_THW) &&( irq < wm831x->irq_base + WM831X_NUM_IRQS))
- {
- if(state)
- wm831x_irq_unmask(irq);
- else
- wm831x_irq_mask(irq);
- return 0;
- }
- else
- {
- printk("%s:irq number err!irq=%d\n",__FUNCTION__,irq);
- return -EINVAL;
- }
-
-
-}
-
static struct irq_chip wm831x_irq_chip = {
.name = "wm831x",
.bus_lock = wm831x_irq_lock,
.bus_sync_unlock = wm831x_irq_sync_unlock,
- .disable = wm831x_irq_disable,
.mask = wm831x_irq_mask,
.unmask = wm831x_irq_unmask,
.set_type = wm831x_irq_set_type,
- .set_wake = wm831x_irq_set_wake,
};
-#if WM831X_IRQ_LIST
-static void wm831x_handle_worker(struct work_struct *work)
-{
- struct wm831x *wm831x = container_of(work, struct wm831x, handle_work);
- int irq;
-
- while (1) {
- unsigned long flags;
- struct wm831x_handle_irq *hd = NULL;
-
- spin_lock_irqsave(&wm831x->work_lock, flags);
- if (!list_empty(&wm831x->handle_queue)) {
- hd = list_first_entry(&wm831x->handle_queue, struct wm831x_handle_irq, queue);
- list_del(&hd->queue);
- }
- spin_unlock_irqrestore(&wm831x->work_lock, flags);
-
- if (!hd) // trans_queue empty
- break;
-
- irq = hd->irq; //get wm831x intterupt status
- //printk("%s:irq=%d\n",__FUNCTION__,irq);
-
- /*start to handle wm831x intterupt*/
- handle_nested_irq(wm831x->irq_base + irq);
-
- kfree(hd);
-
- }
-}
-#endif
-/* Main interrupt handling occurs in a workqueue since we need
- * interrupts enabled to interact with the chip. */
-static void wm831x_irq_worker(struct work_struct *work)
+/* The processing of the primary interrupt occurs in a thread so that
+ * we can interact with the device over I2C or SPI. */
+static irqreturn_t wm831x_irq_thread(int irq, void *data)
{
- struct wm831x *wm831x = container_of(work, struct wm831x, irq_work);
+ struct wm831x *wm831x = data;
unsigned int i;
int primary;
int status_regs[WM831X_NUM_IRQ_REGS] = { 0 };
int read[WM831X_NUM_IRQ_REGS] = { 0 };
int *status;
- unsigned long flags;
- struct wm831x_handle_irq *hd;
- int ret;
-
-#if (WM831X_IRQ_TYPE != IRQF_TRIGGER_LOW)
- /*mask wm831x irq at first*/
- ret = wm831x_set_bits(wm831x, WM831X_IRQ_CONFIG,
- WM831X_IRQ_IM_MASK, WM831X_IRQ_IM_EANBLE);
- if (ret < 0) {
- dev_err(wm831x->dev, "Failed to mask irq: %d\n", ret);
- goto out;
- }
-#endif
primary = wm831x_reg_read(wm831x, WM831X_SYSTEM_INTERRUPTS);
if (primary < 0) {
primary);
goto out;
}
-
- mutex_lock(&wm831x->irq_lock);
for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) {
int offset = wm831x_irqs[i].reg - 1;
-
+
if (!(primary & wm831x_irqs[i].primary))
continue;
-
+
status = &status_regs[offset];
/* Hopefully there should only be one register to read
dev_err(wm831x->dev,
"Failed to read IRQ status: %d\n",
*status);
- goto out_lock;
+ goto out;
}
read[offset] = 1;
/* Report it if it isn't masked, or forget the status. */
if ((*status & ~wm831x->irq_masks_cur[offset])
& wm831x_irqs[i].mask)
- {
- #if WM831X_IRQ_LIST
- /*add intterupt handle on list*/
- hd = kzalloc(sizeof(struct wm831x_handle_irq), GFP_KERNEL);
- if (!hd)
- {
- printk("err:%s:ENOMEM\n",__FUNCTION__);
- return ;
- }
-
- if(i == WM831X_IRQ_ON)
- wake_lock(&wm831x->handle_wake); //keep wake while handle WM831X_IRQ_ON
- hd->irq = i;
- spin_lock_irqsave(&wm831x->work_lock, flags);
- list_add_tail(&hd->queue, &wm831x->handle_queue);
- spin_unlock_irqrestore(&wm831x->work_lock, flags);
- queue_work(wm831x->handle_wq, &wm831x->handle_work);
-
- #else
- if(i == WM831X_IRQ_ON)
- wake_lock(&wm831x->handle_wake); //keep wake while handle WM831X_IRQ_ON
handle_nested_irq(wm831x->irq_base + i);
-
- #endif
- }
-
else
*status &= ~wm831x_irqs[i].mask;
}
-
-out_lock:
- mutex_unlock(&wm831x->irq_lock);
-
+
out:
for (i = 0; i < ARRAY_SIZE(status_regs); i++) {
if (status_regs[i])
wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1 + i,
status_regs[i]);
}
-
-#if (WM831X_IRQ_TYPE != IRQF_TRIGGER_LOW)
- ret = wm831x_set_bits(wm831x, WM831X_IRQ_CONFIG,
- WM831X_IRQ_IM_MASK, 0);
- if (ret < 0) {
- dev_err(wm831x->dev, "Failed to open irq: %d\n", ret);
- }
-#endif
-#if (WM831X_IRQ_TYPE == IRQF_TRIGGER_LOW)
- enable_irq(wm831x->irq);
-#endif
- wake_unlock(&wm831x->irq_wake);
-}
-/* The processing of the primary interrupt occurs in a thread so that
- * we can interact with the device over I2C or SPI. */
-static irqreturn_t wm831x_irq_thread(int irq, void *data)
-{
- struct wm831x *wm831x = data;
- int msdelay = 0;
- /* Shut the interrupt to the CPU up and schedule the actual
- * handler; we can't check that the IRQ is asserted. */
-#if (WM831X_IRQ_TYPE == IRQF_TRIGGER_LOW)
- disable_irq_nosync(irq);
-#endif
- wake_lock(&wm831x->irq_wake);
- if(wm831x->flag_suspend)
- {
- spin_lock(&wm831x->flag_lock);
- wm831x->flag_suspend = 0;
- spin_unlock(&wm831x->flag_lock);
- msdelay = 50; //wait for spi/i2c resume
- printk("%s:msdelay=%d\n",__FUNCTION__,msdelay);
- }
- else
- msdelay = 0;
-
- queue_delayed_work(wm831x->irq_wq, &wm831x->irq_work, msecs_to_jiffies(msdelay));
- //printk("%s\n",__FUNCTION__);
return IRQ_HANDLED;
}
{
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
int i, cur_irq, ret;
- printk( "wm831x_irq_init:irq=%d,%d\n",irq,pdata->irq_base);
+
mutex_init(&wm831x->irq_lock);
/* Mask the individual interrupt sources */
return 0;
}
- wm831x->irq_wq = create_singlethread_workqueue("wm831x-irq");
- if (!wm831x->irq_wq) {
- dev_err(wm831x->dev, "Failed to allocate IRQ worker\n");
- return -ESRCH;
- }
-
-
wm831x->irq = irq;
- wm831x->flag_suspend = 0;
wm831x->irq_base = pdata->irq_base;
- INIT_DELAYED_WORK(&wm831x->irq_work, wm831x_irq_worker);
- wake_lock_init(&wm831x->irq_wake, WAKE_LOCK_SUSPEND, "wm831x_irq_wake");
- wake_lock_init(&wm831x->handle_wake, WAKE_LOCK_SUSPEND, "wm831x_handle_wake");
-#if WM831X_IRQ_LIST
- wm831x->handle_wq = create_rt_workqueue("wm831x_handle_wq");
- if (!wm831x->handle_wq) {
- printk("cannot create workqueue\n");
- return -EBUSY;
- }
- INIT_WORK(&wm831x->handle_work, wm831x_handle_worker);
- INIT_LIST_HEAD(&wm831x->handle_queue);
-#endif
-
/* Register them with genirq */
for (cur_irq = wm831x->irq_base;
cur_irq < ARRAY_SIZE(wm831x_irqs) + wm831x->irq_base;
set_irq_noprobe(cur_irq);
#endif
}
-#if (WM831X_IRQ_TYPE == IRQF_TRIGGER_LOW)
- ret = request_threaded_irq(wm831x->irq, wm831x_irq_thread, NULL,
- IRQF_TRIGGER_LOW| IRQF_ONESHOT,//IRQF_TRIGGER_FALLING, //
- "wm831x", wm831x);
-#else
- ret = request_threaded_irq(wm831x->irq, wm831x_irq_thread, NULL,
- IRQF_TRIGGER_FALLING, //IRQF_TRIGGER_LOW| IRQF_ONESHOT,//
+
+ ret = request_threaded_irq(irq, NULL, wm831x_irq_thread,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"wm831x", wm831x);
-#endif
if (ret != 0) {
dev_err(wm831x->dev, "Failed to request IRQ %d: %d\n",
- wm831x->irq, ret);
+ irq, ret);
return ret;
}
- enable_irq_wake(wm831x->irq); // so wm831x irq can wake up system
/* Enable top level interrupts, we mask at secondary level */
wm831x_reg_write(wm831x, WM831X_SYSTEM_INTERRUPTS_MASK, 0);