Source
x
MODULE_AUTHOR("Binghua Duan <Binghua.Duan@csr.com>, Xianglong Du <Xianglong.Du@csr.com>");
/*
* Power key driver for SiRF PrimaII
*
* Copyright (c) 2013 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
* company.
*
* Licensed under GPLv2 or later.
*/
struct sirfsoc_pwrc_drvdata {
u32 pwrc_base;
struct input_dev *input;
struct delayed_work work;
};
/* ms*/
static int sirfsoc_pwrc_is_on_key_down(struct sirfsoc_pwrc_drvdata *pwrcdrv)
{
u32 state = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base +
PWRC_PIN_STATUS);
return !(state & PWRC_ON_KEY_BIT); /* ON_KEY is active low */
}
static void sirfsoc_pwrc_report_event(struct work_struct *work)
{
struct sirfsoc_pwrc_drvdata *pwrcdrv =
container_of(work, struct sirfsoc_pwrc_drvdata, work.work);
if (sirfsoc_pwrc_is_on_key_down(pwrcdrv)) {
schedule_delayed_work(&pwrcdrv->work,
msecs_to_jiffies(PWRC_KEY_DETECT_UP_TIME));
} else {
input_event(pwrcdrv->input, EV_KEY, KEY_POWER, 0);
input_sync(pwrcdrv->input);
}
}
static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id)
{
struct sirfsoc_pwrc_drvdata *pwrcdrv = dev_id;
u32 int_status;
int_status = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base +
PWRC_INT_STATUS);
sirfsoc_rtc_iobrg_writel(int_status & ~PWRC_ON_KEY_BIT,
pwrcdrv->pwrc_base + PWRC_INT_STATUS);
input_event(pwrcdrv->input, EV_KEY, KEY_POWER, 1);
input_sync(pwrcdrv->input);
schedule_delayed_work(&pwrcdrv->work,
msecs_to_jiffies(PWRC_KEY_DETECT_UP_TIME));
return IRQ_HANDLED;
}
static void sirfsoc_pwrc_toggle_interrupts(struct sirfsoc_pwrc_drvdata *pwrcdrv,
bool enable)
{
u32 int_mask;
int_mask = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base + PWRC_INT_MASK);
if (enable)
int_mask |= PWRC_ON_KEY_BIT;
else
int_mask &= ~PWRC_ON_KEY_BIT;
sirfsoc_rtc_iobrg_writel(int_mask, pwrcdrv->pwrc_base + PWRC_INT_MASK);
}
static int sirfsoc_pwrc_open(struct input_dev *input)
{
struct sirfsoc_pwrc_drvdata *pwrcdrv = input_get_drvdata(input);
sirfsoc_pwrc_toggle_interrupts(pwrcdrv, true);
return 0;
}