root/drivers/input/keyboard/snvs_pwrkey.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. imx_imx_snvs_check_for_events
  2. imx_snvs_pwrkey_interrupt
  3. imx_snvs_pwrkey_act
  4. imx_snvs_pwrkey_probe

   1 // SPDX-License-Identifier: GPL-2.0+
   2 //
   3 // Driver for the IMX SNVS ON/OFF Power Key
   4 // Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved.
   5 
   6 #include <linux/device.h>
   7 #include <linux/err.h>
   8 #include <linux/init.h>
   9 #include <linux/input.h>
  10 #include <linux/interrupt.h>
  11 #include <linux/io.h>
  12 #include <linux/jiffies.h>
  13 #include <linux/kernel.h>
  14 #include <linux/module.h>
  15 #include <linux/of.h>
  16 #include <linux/of_address.h>
  17 #include <linux/platform_device.h>
  18 #include <linux/pm_wakeirq.h>
  19 #include <linux/mfd/syscon.h>
  20 #include <linux/regmap.h>
  21 
  22 #define SNVS_LPSR_REG   0x4C    /* LP Status Register */
  23 #define SNVS_LPCR_REG   0x38    /* LP Control Register */
  24 #define SNVS_HPSR_REG   0x14
  25 #define SNVS_HPSR_BTN   BIT(6)
  26 #define SNVS_LPSR_SPO   BIT(18)
  27 #define SNVS_LPCR_DEP_EN BIT(5)
  28 
  29 #define DEBOUNCE_TIME 30
  30 #define REPEAT_INTERVAL 60
  31 
  32 struct pwrkey_drv_data {
  33         struct regmap *snvs;
  34         int irq;
  35         int keycode;
  36         int keystate;  /* 1:pressed */
  37         int wakeup;
  38         struct timer_list check_timer;
  39         struct input_dev *input;
  40 };
  41 
  42 static void imx_imx_snvs_check_for_events(struct timer_list *t)
  43 {
  44         struct pwrkey_drv_data *pdata = from_timer(pdata, t, check_timer);
  45         struct input_dev *input = pdata->input;
  46         u32 state;
  47 
  48         regmap_read(pdata->snvs, SNVS_HPSR_REG, &state);
  49         state = state & SNVS_HPSR_BTN ? 1 : 0;
  50 
  51         /* only report new event if status changed */
  52         if (state ^ pdata->keystate) {
  53                 pdata->keystate = state;
  54                 input_event(input, EV_KEY, pdata->keycode, state);
  55                 input_sync(input);
  56                 pm_relax(pdata->input->dev.parent);
  57         }
  58 
  59         /* repeat check if pressed long */
  60         if (state) {
  61                 mod_timer(&pdata->check_timer,
  62                           jiffies + msecs_to_jiffies(REPEAT_INTERVAL));
  63         }
  64 }
  65 
  66 static irqreturn_t imx_snvs_pwrkey_interrupt(int irq, void *dev_id)
  67 {
  68         struct platform_device *pdev = dev_id;
  69         struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev);
  70         u32 lp_status;
  71 
  72         pm_wakeup_event(pdata->input->dev.parent, 0);
  73 
  74         regmap_read(pdata->snvs, SNVS_LPSR_REG, &lp_status);
  75         if (lp_status & SNVS_LPSR_SPO)
  76                 mod_timer(&pdata->check_timer, jiffies + msecs_to_jiffies(DEBOUNCE_TIME));
  77 
  78         /* clear SPO status */
  79         regmap_write(pdata->snvs, SNVS_LPSR_REG, SNVS_LPSR_SPO);
  80 
  81         return IRQ_HANDLED;
  82 }
  83 
  84 static void imx_snvs_pwrkey_act(void *pdata)
  85 {
  86         struct pwrkey_drv_data *pd = pdata;
  87 
  88         del_timer_sync(&pd->check_timer);
  89 }
  90 
  91 static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
  92 {
  93         struct pwrkey_drv_data *pdata = NULL;
  94         struct input_dev *input = NULL;
  95         struct device_node *np;
  96         int error;
  97 
  98         /* Get SNVS register Page */
  99         np = pdev->dev.of_node;
 100         if (!np)
 101                 return -ENODEV;
 102 
 103         pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 104         if (!pdata)
 105                 return -ENOMEM;
 106 
 107         pdata->snvs = syscon_regmap_lookup_by_phandle(np, "regmap");
 108         if (IS_ERR(pdata->snvs)) {
 109                 dev_err(&pdev->dev, "Can't get snvs syscon\n");
 110                 return PTR_ERR(pdata->snvs);
 111         }
 112 
 113         if (of_property_read_u32(np, "linux,keycode", &pdata->keycode)) {
 114                 pdata->keycode = KEY_POWER;
 115                 dev_warn(&pdev->dev, "KEY_POWER without setting in dts\n");
 116         }
 117 
 118         pdata->wakeup = of_property_read_bool(np, "wakeup-source");
 119 
 120         pdata->irq = platform_get_irq(pdev, 0);
 121         if (pdata->irq < 0)
 122                 return -EINVAL;
 123 
 124         regmap_update_bits(pdata->snvs, SNVS_LPCR_REG, SNVS_LPCR_DEP_EN, SNVS_LPCR_DEP_EN);
 125 
 126         /* clear the unexpected interrupt before driver ready */
 127         regmap_write(pdata->snvs, SNVS_LPSR_REG, SNVS_LPSR_SPO);
 128 
 129         timer_setup(&pdata->check_timer, imx_imx_snvs_check_for_events, 0);
 130 
 131         input = devm_input_allocate_device(&pdev->dev);
 132         if (!input) {
 133                 dev_err(&pdev->dev, "failed to allocate the input device\n");
 134                 return -ENOMEM;
 135         }
 136 
 137         input->name = pdev->name;
 138         input->phys = "snvs-pwrkey/input0";
 139         input->id.bustype = BUS_HOST;
 140 
 141         input_set_capability(input, EV_KEY, pdata->keycode);
 142 
 143         /* input customer action to cancel release timer */
 144         error = devm_add_action(&pdev->dev, imx_snvs_pwrkey_act, pdata);
 145         if (error) {
 146                 dev_err(&pdev->dev, "failed to register remove action\n");
 147                 return error;
 148         }
 149 
 150         pdata->input = input;
 151         platform_set_drvdata(pdev, pdata);
 152 
 153         error = devm_request_irq(&pdev->dev, pdata->irq,
 154                                imx_snvs_pwrkey_interrupt,
 155                                0, pdev->name, pdev);
 156 
 157         if (error) {
 158                 dev_err(&pdev->dev, "interrupt not available.\n");
 159                 return error;
 160         }
 161 
 162         error = input_register_device(input);
 163         if (error < 0) {
 164                 dev_err(&pdev->dev, "failed to register input device\n");
 165                 return error;
 166         }
 167 
 168         device_init_wakeup(&pdev->dev, pdata->wakeup);
 169         error = dev_pm_set_wake_irq(&pdev->dev, pdata->irq);
 170         if (error)
 171                 dev_err(&pdev->dev, "irq wake enable failed.\n");
 172 
 173         return 0;
 174 }
 175 
 176 static const struct of_device_id imx_snvs_pwrkey_ids[] = {
 177         { .compatible = "fsl,sec-v4.0-pwrkey" },
 178         { /* sentinel */ }
 179 };
 180 MODULE_DEVICE_TABLE(of, imx_snvs_pwrkey_ids);
 181 
 182 static struct platform_driver imx_snvs_pwrkey_driver = {
 183         .driver = {
 184                 .name = "snvs_pwrkey",
 185                 .of_match_table = imx_snvs_pwrkey_ids,
 186         },
 187         .probe = imx_snvs_pwrkey_probe,
 188 };
 189 module_platform_driver(imx_snvs_pwrkey_driver);
 190 
 191 MODULE_AUTHOR("Freescale Semiconductor");
 192 MODULE_DESCRIPTION("i.MX snvs power key Driver");
 193 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */