linux/drivers/input/misc/sirfsoc-onkey.c
<<
>>
Prefs
   1/*
   2 * Power key driver for SiRF PrimaII
   3 *
   4 * Copyright (c) 2013 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
   5 * company.
   6 *
   7 * Licensed under GPLv2 or later.
   8 */
   9
  10#include <linux/module.h>
  11#include <linux/interrupt.h>
  12#include <linux/delay.h>
  13#include <linux/platform_device.h>
  14#include <linux/input.h>
  15#include <linux/rtc/sirfsoc_rtciobrg.h>
  16#include <linux/of.h>
  17#include <linux/workqueue.h>
  18
  19struct sirfsoc_pwrc_drvdata {
  20        u32                     pwrc_base;
  21        struct input_dev        *input;
  22        struct delayed_work     work;
  23};
  24
  25#define PWRC_ON_KEY_BIT                 (1 << 0)
  26
  27#define PWRC_INT_STATUS                 0xc
  28#define PWRC_INT_MASK                   0x10
  29#define PWRC_PIN_STATUS                 0x14
  30#define PWRC_KEY_DETECT_UP_TIME         20      /* ms*/
  31
  32static int sirfsoc_pwrc_is_on_key_down(struct sirfsoc_pwrc_drvdata *pwrcdrv)
  33{
  34        u32 state = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base +
  35                                                        PWRC_PIN_STATUS);
  36        return !(state & PWRC_ON_KEY_BIT); /* ON_KEY is active low */
  37}
  38
  39static void sirfsoc_pwrc_report_event(struct work_struct *work)
  40{
  41        struct sirfsoc_pwrc_drvdata *pwrcdrv =
  42                container_of(work, struct sirfsoc_pwrc_drvdata, work.work);
  43
  44        if (sirfsoc_pwrc_is_on_key_down(pwrcdrv)) {
  45                schedule_delayed_work(&pwrcdrv->work,
  46                        msecs_to_jiffies(PWRC_KEY_DETECT_UP_TIME));
  47        } else {
  48                input_event(pwrcdrv->input, EV_KEY, KEY_POWER, 0);
  49                input_sync(pwrcdrv->input);
  50        }
  51}
  52
  53static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id)
  54{
  55        struct sirfsoc_pwrc_drvdata *pwrcdrv = dev_id;
  56        u32 int_status;
  57
  58        int_status = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base +
  59                                                        PWRC_INT_STATUS);
  60        sirfsoc_rtc_iobrg_writel(int_status & ~PWRC_ON_KEY_BIT,
  61                                 pwrcdrv->pwrc_base + PWRC_INT_STATUS);
  62
  63        input_event(pwrcdrv->input, EV_KEY, KEY_POWER, 1);
  64        input_sync(pwrcdrv->input);
  65        schedule_delayed_work(&pwrcdrv->work,
  66                              msecs_to_jiffies(PWRC_KEY_DETECT_UP_TIME));
  67
  68        return IRQ_HANDLED;
  69}
  70
  71static void sirfsoc_pwrc_toggle_interrupts(struct sirfsoc_pwrc_drvdata *pwrcdrv,
  72                                           bool enable)
  73{
  74        u32 int_mask;
  75
  76        int_mask = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base + PWRC_INT_MASK);
  77        if (enable)
  78                int_mask |= PWRC_ON_KEY_BIT;
  79        else
  80                int_mask &= ~PWRC_ON_KEY_BIT;
  81        sirfsoc_rtc_iobrg_writel(int_mask, pwrcdrv->pwrc_base + PWRC_INT_MASK);
  82}
  83
  84static int sirfsoc_pwrc_open(struct input_dev *input)
  85{
  86        struct sirfsoc_pwrc_drvdata *pwrcdrv = input_get_drvdata(input);
  87
  88        sirfsoc_pwrc_toggle_interrupts(pwrcdrv, true);
  89
  90        return 0;
  91}
  92
  93static void sirfsoc_pwrc_close(struct input_dev *input)
  94{
  95        struct sirfsoc_pwrc_drvdata *pwrcdrv = input_get_drvdata(input);
  96
  97        sirfsoc_pwrc_toggle_interrupts(pwrcdrv, false);
  98        cancel_delayed_work_sync(&pwrcdrv->work);
  99}
 100
 101static const struct of_device_id sirfsoc_pwrc_of_match[] = {
 102        { .compatible = "sirf,prima2-pwrc" },
 103        {},
 104};
 105MODULE_DEVICE_TABLE(of, sirfsoc_pwrc_of_match);
 106
 107static int sirfsoc_pwrc_probe(struct platform_device *pdev)
 108{
 109        struct device_node *np = pdev->dev.of_node;
 110        struct sirfsoc_pwrc_drvdata *pwrcdrv;
 111        int irq;
 112        int error;
 113
 114        pwrcdrv = devm_kzalloc(&pdev->dev, sizeof(struct sirfsoc_pwrc_drvdata),
 115                               GFP_KERNEL);
 116        if (!pwrcdrv) {
 117                dev_info(&pdev->dev, "Not enough memory for the device data\n");
 118                return -ENOMEM;
 119        }
 120
 121        /*
 122         * We can't use of_iomap because pwrc is not mapped in memory,
 123         * the so-called base address is only offset in rtciobrg
 124         */
 125        error = of_property_read_u32(np, "reg", &pwrcdrv->pwrc_base);
 126        if (error) {
 127                dev_err(&pdev->dev,
 128                        "unable to find base address of pwrc node in dtb\n");
 129                return error;
 130        }
 131
 132        pwrcdrv->input = devm_input_allocate_device(&pdev->dev);
 133        if (!pwrcdrv->input)
 134                return -ENOMEM;
 135
 136        pwrcdrv->input->name = "sirfsoc pwrckey";
 137        pwrcdrv->input->phys = "pwrc/input0";
 138        pwrcdrv->input->evbit[0] = BIT_MASK(EV_KEY);
 139        input_set_capability(pwrcdrv->input, EV_KEY, KEY_POWER);
 140
 141        INIT_DELAYED_WORK(&pwrcdrv->work, sirfsoc_pwrc_report_event);
 142
 143        pwrcdrv->input->open = sirfsoc_pwrc_open;
 144        pwrcdrv->input->close = sirfsoc_pwrc_close;
 145
 146        input_set_drvdata(pwrcdrv->input, pwrcdrv);
 147
 148        /* Make sure the device is quiesced */
 149        sirfsoc_pwrc_toggle_interrupts(pwrcdrv, false);
 150
 151        irq = platform_get_irq(pdev, 0);
 152        error = devm_request_irq(&pdev->dev, irq,
 153                                 sirfsoc_pwrc_isr, 0,
 154                                 "sirfsoc_pwrc_int", pwrcdrv);
 155        if (error) {
 156                dev_err(&pdev->dev, "unable to claim irq %d, error: %d\n",
 157                        irq, error);
 158                return error;
 159        }
 160
 161        error = input_register_device(pwrcdrv->input);
 162        if (error) {
 163                dev_err(&pdev->dev,
 164                        "unable to register input device, error: %d\n",
 165                        error);
 166                return error;
 167        }
 168
 169        dev_set_drvdata(&pdev->dev, pwrcdrv);
 170        device_init_wakeup(&pdev->dev, 1);
 171
 172        return 0;
 173}
 174
 175static int __maybe_unused sirfsoc_pwrc_resume(struct device *dev)
 176{
 177        struct sirfsoc_pwrc_drvdata *pwrcdrv = dev_get_drvdata(dev);
 178        struct input_dev *input = pwrcdrv->input;
 179
 180        /*
 181         * Do not mask pwrc interrupt as we want pwrc work as a wakeup source
 182         * if users touch X_ONKEY_B, see arch/arm/mach-prima2/pm.c
 183         */
 184        mutex_lock(&input->mutex);
 185        if (input->users)
 186                sirfsoc_pwrc_toggle_interrupts(pwrcdrv, true);
 187        mutex_unlock(&input->mutex);
 188
 189        return 0;
 190}
 191
 192static SIMPLE_DEV_PM_OPS(sirfsoc_pwrc_pm_ops, NULL, sirfsoc_pwrc_resume);
 193
 194static struct platform_driver sirfsoc_pwrc_driver = {
 195        .probe          = sirfsoc_pwrc_probe,
 196        .driver         = {
 197                .name   = "sirfsoc-pwrc",
 198                .pm     = &sirfsoc_pwrc_pm_ops,
 199                .of_match_table = sirfsoc_pwrc_of_match,
 200        }
 201};
 202
 203module_platform_driver(sirfsoc_pwrc_driver);
 204
 205MODULE_LICENSE("GPL v2");
 206MODULE_AUTHOR("Binghua Duan <Binghua.Duan@csr.com>, Xianglong Du <Xianglong.Du@csr.com>");
 207MODULE_DESCRIPTION("CSR Prima2 PWRC Driver");
 208MODULE_ALIAS("platform:sirfsoc-pwrc");
 209