/*
* Micco interrupt service routine.
* In the ISR we need to check the Status bits in Micco and according
* to those bits to check which kind of IRQ had happened.
*/
static irqreturn_t micco_irq_handler(int irq, void *dev_id)
{
struct i2c_client *client = dev_id;
struct micco_platform_data *pdata = client->dev.platform_data;
/* clear the irq */
pdata->ack_irq();
schedule_work(&pdata->work);
return IRQ_HANDLED;
}
static void micco_worker(struct work_struct *work)
{
unsigned int event;
u8 val;
event = micco_event_change();
pmic_event_handle(event);
/* We don't put these codes to USB specific code because
* we need handle it even when no USB callback registered.
*/
if (event & PMIC_EVENT_OTGCP_IOVER) {
/* According to Micco spec, when OTGCP_IOVER happen,
* Need clean the USBPCP_EN in MISC. and then set
* it again.
*/
micco_read(MICCO_MISC, &val);
val &= ~MICCO_MISC_USBCP_EN;
micco_write(MICCO_MISC, val);
val |= MICCO_MISC_USBCP_EN;
micco_write(MICCO_MISC, val);
}
}
static unsigned int micco_event_change(void)
{
unsigned int ret = 0;
u8 val, mask;
micco_read(MICCO_EVENT_A, &val);
if (val & MICCO_EA_ONKEY)
ret |= MICCO_EA_ONKEY;
if (val & MICCO_EA_CHDET)
ret |= PMIC_EVENT_CHDET;
if (val & MICCO_EA_REV_IOVER)
ret |= PMIC_EVENT_REV_IOVER;
if (val & MICCO_EA_IOVER)
ret |= PMIC_EVENT_IOVER;
if (val & MICCO_EA_TBAT)
ret |= PMIC_EVENT_TBAT;
if (val & MICCO_EA_VBATMON)
ret |= PMIC_EVENT_VBATMON;
micco_read(MICCO_EVENT_B, &val);
if (val & MICCO_EB_USB_DEV)
ret |= PMIC_EVENT_VBUS;
if (val & (MICCO_EB_VBUS_4P55|MICCO_EB_VBUS_3P8))
ret |= PMIC_EVENT_VBUS;
if (val & MICCO_EB_SESSION_1P8) {
micco_read(MICCO_IRQ_MASK_B, &mask);
if (!(mask & IRQ_MASK_B_SESSION_VALID_1_8))
ret |= PMIC_EVENT_VBUS;
}
if (val & MICCO_EB_OTGCP_IOVER)
ret |= PMIC_EVENT_OTGCP_IOVER;
micco_read(MICCO_EVENT_C, &val);
if (val & MICCO_EC_PEN_DOWN)
ret |= PMIC_EVENT_TOUCH;
micco_read(MICCO_EVENT_D, &val);
if (val & MICCO_ED_HEADSET)
{
ret |= PMIC_EVENT_HSDETECT;
}
if (val & MICCO_ED_HOOKSWITCH)
{
ret |= PMIC_EVENT_HOOKSWITCH;
}
return ret;
}
int pmic_event_handle(unsigned long event)
{
int ret;
unsigned long flags;
struct pmic_callback *pmic_cb;
ret = check_pmic_ops();
if (ret < 0)
return ret;
spin_lock_irqsave(&pxa3xx_pmic_ops->cb_lock, flags);
list_for_each_entry(pmic_cb, &pxa3xx_pmic_ops->list, list) {
spin_unlock_irqrestore(&pxa3xx_pmic_ops->cb_lock, flags);
/* event is bit-wise parameter, need bit AND here as filter */
if ((pmic_cb->event & event) && (pmic_cb->func))
pmic_cb->func(event);
spin_lock_irqsave(&pxa3xx_pmic_ops->cb_lock, flags);
}
spin_unlock_irqrestore(&pxa3xx_pmic_ops->cb_lock, flags);
return 0;
}
EXPORT_SYMBOL(pmic_event_handle);
比如触摸屏的处理,
DA9034注册的时候调用micco_probe函数将DA9034的中断处理函数注册
ret = request_irq(client->irq, micco_irq_handler, IRQF_TRIGGER_FALLING,
"Micco", client);
触摸屏在注册时将触摸屏的事件和触摸屏中断处理程序注册,通过下面语句注册
ret = pmic_callback_register(PMIC_EVENT_TOUCH, micco_ts_interrupt);
当发生触摸屏中断时调用 micco_irq_handler,接着调用micco_worker, event = micco_event_change();
读出产生中断的事件,调用 pmic_event_handle(event);对相应的事件进行处理。
DA9034产生中断后要通过读出事件寄存器的值,才能清除中断,否则中断线不响应后面的中断。