diff options
| author | Robin Gong <b38343@freescale.com> | 2014-04-02 04:55:31 -0400 |
|---|---|---|
| committer | Nitin Garg <nitin.garg@freescale.com> | 2014-04-16 09:58:15 -0400 |
| commit | 8cf20b3a736feeb814c0d32e15fdb9ee575ddbd3 (patch) | |
| tree | f406e952e1ccae44e1103170d3c1a7823f0c193f /drivers/input | |
| parent | 6a824e342dfeca4ff3a8648569408878c7d2a52c (diff) | |
ENGR00306653-2 input: keyboad: snvs_pwrkey: add snvs power key driver
add snvs power key driver since ic team has fix some issues of SNVS on i.mx6sx
Signed-off-by: Robin Gong <b38343@freescale.com>
Diffstat (limited to 'drivers/input')
| -rw-r--r-- | drivers/input/keyboard/Kconfig | 7 | ||||
| -rw-r--r-- | drivers/input/keyboard/Makefile | 1 | ||||
| -rw-r--r-- | drivers/input/keyboard/snvs_pwrkey.c | 221 |
3 files changed, 229 insertions, 0 deletions
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 292f3240e67b..c834583539f9 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
| @@ -388,6 +388,13 @@ config KEYBOARD_MPR121 | |||
| 388 | To compile this driver as a module, choose M here: the | 388 | To compile this driver as a module, choose M here: the |
| 389 | module will be called mpr121_touchkey. | 389 | module will be called mpr121_touchkey. |
| 390 | 390 | ||
| 391 | config KEYBOARD_SNVS_PWRKEY | ||
| 392 | tristate "IMX6SX SNVS Power Key Driver" | ||
| 393 | depends on SOC_IMX6SX | ||
| 394 | help | ||
| 395 | This is the snvs powerkey driver for the Freescale i.MX6SX application | ||
| 396 | processors. | ||
| 397 | |||
| 391 | config KEYBOARD_IMX | 398 | config KEYBOARD_IMX |
| 392 | tristate "IMX keypad support" | 399 | tristate "IMX keypad support" |
| 393 | depends on ARCH_MXC | 400 | depends on ARCH_MXC |
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 0c43e8cf8d0e..7b5379ffbc55 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile | |||
| @@ -46,6 +46,7 @@ obj-$(CONFIG_KEYBOARD_QT1070) += qt1070.o | |||
| 46 | obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o | 46 | obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o |
| 47 | obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o | 47 | obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o |
| 48 | obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o | 48 | obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o |
| 49 | obj-$(CONFIG_KEYBOARD_SNVS_PWRKEY) += snvs_pwrkey.o | ||
| 49 | obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o | 50 | obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o |
| 50 | obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o | 51 | obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o |
| 51 | obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o | 52 | obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o |
diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c new file mode 100644 index 000000000000..f00c21290afd --- /dev/null +++ b/drivers/input/keyboard/snvs_pwrkey.c | |||
| @@ -0,0 +1,221 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved. | ||
| 3 | * | ||
| 4 | * The code contained herein is licensed under the GNU General Public | ||
| 5 | * License. You may obtain a copy of the GNU General Public License | ||
| 6 | * Version 2 or later at the following locations: | ||
| 7 | * | ||
| 8 | * http://www.opensource.org/licenses/gpl-license.html | ||
| 9 | * http://www.gnu.org/copyleft/gpl.html | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/device.h> | ||
| 13 | #include <linux/err.h> | ||
| 14 | #include <linux/init.h> | ||
| 15 | #include <linux/input.h> | ||
| 16 | #include <linux/interrupt.h> | ||
| 17 | #include <linux/io.h> | ||
| 18 | #include <linux/jiffies.h> | ||
| 19 | #include <linux/kernel.h> | ||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/of.h> | ||
| 22 | #include <linux/of_address.h> | ||
| 23 | #include <linux/platform_device.h> | ||
| 24 | |||
| 25 | #define SNVS_LPSR_REG 0x4C /* LP Status Register */ | ||
| 26 | #define SNVS_LPCR_REG 0x38 /* LP Control Register */ | ||
| 27 | #define SNVS_HPSR_REG 0x14 | ||
| 28 | #define SNVS_HPSR_BTN (0x1 << 6) | ||
| 29 | #define SNVS_LPSR_SPO (0x1 << 18) | ||
| 30 | #define SNVS_LPCR_DEP_EN (0x1 << 5) | ||
| 31 | |||
| 32 | struct pwrkey_drv_data { | ||
| 33 | void __iomem *ioaddr; | ||
| 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(unsigned long data) | ||
| 43 | { | ||
| 44 | struct pwrkey_drv_data *pdata = (struct pwrkey_drv_data *) data; | ||
| 45 | struct input_dev *input = pdata->input; | ||
| 46 | void __iomem *ioaddr = pdata->ioaddr; | ||
| 47 | u32 state; | ||
| 48 | |||
| 49 | state = ((readl_relaxed(ioaddr + SNVS_HPSR_REG) & SNVS_HPSR_BTN) ? | ||
| 50 | 1 : 0); | ||
| 51 | |||
| 52 | /* only report new event if status changed */ | ||
| 53 | if (state ^ pdata->keystate) { | ||
| 54 | pdata->keystate = state; | ||
| 55 | input_event(input, EV_KEY, pdata->keycode, state); | ||
| 56 | input_sync(input); | ||
| 57 | } | ||
| 58 | |||
| 59 | /* repeat check if pressed long */ | ||
| 60 | if (state) { | ||
| 61 | mod_timer(&pdata->check_timer, | ||
| 62 | jiffies + msecs_to_jiffies(60)); | ||
| 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 | void __iomem *ioaddr = pdata->ioaddr; | ||
| 71 | u32 lp_status; | ||
| 72 | |||
| 73 | lp_status = readl_relaxed(ioaddr + SNVS_LPSR_REG); | ||
| 74 | if (lp_status & SNVS_LPSR_SPO) | ||
| 75 | mod_timer(&pdata->check_timer, jiffies + msecs_to_jiffies(2)); | ||
| 76 | |||
| 77 | /* clear SPO status */ | ||
| 78 | writel_relaxed(lp_status, ioaddr + SNVS_LPSR_REG); | ||
| 79 | |||
| 80 | return IRQ_HANDLED; | ||
| 81 | } | ||
| 82 | |||
| 83 | static int imx_snvs_pwrkey_probe(struct platform_device *pdev) | ||
| 84 | { | ||
| 85 | struct pwrkey_drv_data *pdata = NULL; | ||
| 86 | struct input_dev *input = NULL; | ||
| 87 | struct device_node *np; | ||
| 88 | void __iomem *ioaddr; | ||
| 89 | u32 lp_cr; | ||
| 90 | int ret = 0; | ||
| 91 | |||
| 92 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | ||
| 93 | if (!pdata) | ||
| 94 | return -ENOMEM; | ||
| 95 | |||
| 96 | /* Get SNVS register Page */ | ||
| 97 | np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-snvs-pwrkey"); | ||
| 98 | if (!np) | ||
| 99 | return -ENODEV; | ||
| 100 | pdata->ioaddr = of_iomap(np, 0); | ||
| 101 | if (IS_ERR(pdata->ioaddr)) | ||
| 102 | return PTR_ERR(pdata->ioaddr); | ||
| 103 | |||
| 104 | if (of_property_read_u32(np, "fsl,keycode", &pdata->keycode)) { | ||
| 105 | pdata->keycode = KEY_POWER; | ||
| 106 | dev_warn(&pdev->dev, "KEY_POWER without setting in dts\n"); | ||
| 107 | } | ||
| 108 | |||
| 109 | pdata->wakeup = !!of_get_property(np, "fsl,wakeup", NULL); | ||
| 110 | |||
| 111 | ioaddr = pdata->ioaddr; | ||
| 112 | pdata->irq = platform_get_irq(pdev, 0); | ||
| 113 | if (pdata->irq < 0) { | ||
| 114 | dev_err(&pdev->dev, "no irq defined in platform data\n"); | ||
| 115 | return -EINVAL; | ||
| 116 | } | ||
| 117 | |||
| 118 | ioaddr = pdata->ioaddr; | ||
| 119 | lp_cr = readl_relaxed(ioaddr + SNVS_LPCR_REG); | ||
| 120 | lp_cr |= SNVS_LPCR_DEP_EN, | ||
| 121 | writel_relaxed(lp_cr, ioaddr + SNVS_LPCR_REG); | ||
| 122 | |||
| 123 | setup_timer(&pdata->check_timer, | ||
| 124 | imx_imx_snvs_check_for_events, (unsigned long) pdata); | ||
| 125 | |||
| 126 | if (pdata->irq >= 0) { | ||
| 127 | ret = devm_request_irq(&pdev->dev, pdata->irq, | ||
| 128 | imx_snvs_pwrkey_interrupt, | ||
| 129 | IRQF_TRIGGER_HIGH, pdev->name, pdev); | ||
| 130 | if (ret) { | ||
| 131 | dev_err(&pdev->dev, "interrupt not available.\n"); | ||
| 132 | return ret; | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 | input = devm_input_allocate_device(&pdev->dev); | ||
| 137 | if (!input) { | ||
| 138 | dev_err(&pdev->dev, "failed to allocate the input device\n"); | ||
| 139 | return -ENOMEM; | ||
| 140 | } | ||
| 141 | |||
| 142 | input->name = pdev->name; | ||
| 143 | input->phys = "snvs-pwrkey/input0"; | ||
| 144 | input->id.bustype = BUS_HOST; | ||
| 145 | input->evbit[0] = BIT_MASK(EV_KEY); | ||
| 146 | |||
| 147 | input_set_capability(input, EV_KEY, pdata->keycode); | ||
| 148 | |||
| 149 | ret = input_register_device(input); | ||
| 150 | if (ret < 0) { | ||
| 151 | dev_err(&pdev->dev, "failed to register input device\n"); | ||
| 152 | input_free_device(input); | ||
| 153 | return ret; | ||
| 154 | } | ||
| 155 | |||
| 156 | pdata->input = input; | ||
| 157 | platform_set_drvdata(pdev, pdata); | ||
| 158 | |||
| 159 | device_init_wakeup(&pdev->dev, pdata->wakeup); | ||
| 160 | |||
| 161 | dev_info(&pdev->dev, "i.MX snvs powerkey probed\n"); | ||
| 162 | |||
| 163 | return 0; | ||
| 164 | } | ||
| 165 | |||
| 166 | static int imx_snvs_pwrkey_remove(struct platform_device *pdev) | ||
| 167 | { | ||
| 168 | struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev); | ||
| 169 | |||
| 170 | input_unregister_device(pdata->input); | ||
