summaryrefslogtreecommitdiff
path: root/drivers/input/keyboard
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/keyboard')
-rw-r--r--drivers/input/keyboard/Kconfig17
-rw-r--r--drivers/input/keyboard/Makefile1
-rw-r--r--drivers/input/keyboard/adp5589-keys.c1
-rw-r--r--drivers/input/keyboard/cap11xx.c145
-rw-r--r--drivers/input/keyboard/gpio_keys.c9
-rw-r--r--drivers/input/keyboard/gpio_keys_polled.c5
-rw-r--r--drivers/input/keyboard/imx_keypad.c2
-rw-r--r--drivers/input/keyboard/lm8333.c1
-rw-r--r--drivers/input/keyboard/matrix_keypad.c6
-rw-r--r--drivers/input/keyboard/mcs_touchkey.c1
-rw-r--r--drivers/input/keyboard/mpr121_touchkey.c1
-rw-r--r--drivers/input/keyboard/omap4-keypad.c2
-rw-r--r--drivers/input/keyboard/pmic8xxx-keypad.c10
-rw-r--r--drivers/input/keyboard/qt1070.c1
-rw-r--r--drivers/input/keyboard/qt2160.c1
-rw-r--r--drivers/input/keyboard/samsung-keypad.c6
-rw-r--r--drivers/input/keyboard/snvs_pwrkey.c227
-rw-r--r--drivers/input/keyboard/tc3589x-keypad.c63
-rw-r--r--drivers/input/keyboard/tca8418_keypad.c1
19 files changed, 434 insertions, 66 deletions
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 4cd94fd6c..2e80107ff 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -187,7 +187,7 @@ config KEYBOARD_EP93XX
config KEYBOARD_GPIO
tristate "GPIO Buttons"
- depends on GPIOLIB
+ depends on GPIOLIB || COMPILE_TEST
help
This driver implements support for buttons connected
to GPIO pins of various CPUs (and some other chips).
@@ -253,7 +253,7 @@ config KEYBOARD_TCA8418
config KEYBOARD_MATRIX
tristate "GPIO driven matrix keypad support"
- depends on GPIOLIB
+ depends on GPIOLIB || COMPILE_TEST
select INPUT_MATRIXKMAP
help
Enable support for GPIO driven matrix keypad.
@@ -401,6 +401,17 @@ config KEYBOARD_MPR121
To compile this driver as a module, choose M here: the
module will be called mpr121_touchkey.
+config KEYBOARD_SNVS_PWRKEY
+ tristate "IMX SNVS Power Key Driver"
+ depends on SOC_IMX6SX
+ depends on OF
+ help
+ This is the snvs powerkey driver for the Freescale i.MX application
+ processors that are newer than i.MX6 SX.
+
+ To compile this driver as a module, choose M here; the
+ module will be called snvs_pwrkey.
+
config KEYBOARD_IMX
tristate "IMX keypad support"
depends on ARCH_MXC
@@ -678,7 +689,7 @@ config KEYBOARD_W90P910
config KEYBOARD_CROS_EC
tristate "ChromeOS EC keyboard"
select INPUT_MATRIXKMAP
- depends on CROS_EC_PROTO
+ depends on MFD_CROS_EC
help
Say Y here to enable the matrix keyboard used by ChromeOS devices
and implemented on the ChromeOS EC. You must enable one bus option
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index df28d5553..1d416ddf8 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_KEYBOARD_QT1070) += qt1070.o
obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o
obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o
obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
+obj-$(CONFIG_KEYBOARD_SNVS_PWRKEY) += snvs_pwrkey.o
obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o
obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c
index 6ed83cf8b..4d446d508 100644
--- a/drivers/input/keyboard/adp5589-keys.c
+++ b/drivers/input/keyboard/adp5589-keys.c
@@ -1097,7 +1097,6 @@ MODULE_DEVICE_TABLE(i2c, adp5589_id);
static struct i2c_driver adp5589_driver = {
.driver = {
.name = KBUILD_MODNAME,
- .owner = THIS_MODULE,
.pm = &adp5589_dev_pm_ops,
},
.probe = adp5589_probe,
diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
index f07461a64..378db1000 100644
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/input.h>
+#include <linux/leds.h>
#include <linux/of_irq.h>
#include <linux/regmap.h>
#include <linux/i2c.h>
@@ -47,6 +48,20 @@
#define CAP11XX_REG_CONFIG2 0x44
#define CAP11XX_REG_CONFIG2_ALT_POL BIT(6)
#define CAP11XX_REG_SENSOR_BASE_CNT(X) (0x50 + (X))
+#define CAP11XX_REG_LED_POLARITY 0x73
+#define CAP11XX_REG_LED_OUTPUT_CONTROL 0x74
+
+#define CAP11XX_REG_LED_DUTY_CYCLE_1 0x90
+#define CAP11XX_REG_LED_DUTY_CYCLE_2 0x91
+#define CAP11XX_REG_LED_DUTY_CYCLE_3 0x92
+#define CAP11XX_REG_LED_DUTY_CYCLE_4 0x93
+
+#define CAP11XX_REG_LED_DUTY_MIN_MASK (0x0f)
+#define CAP11XX_REG_LED_DUTY_MIN_MASK_SHIFT (0)
+#define CAP11XX_REG_LED_DUTY_MAX_MASK (0xf0)
+#define CAP11XX_REG_LED_DUTY_MAX_MASK_SHIFT (4)
+#define CAP11XX_REG_LED_DUTY_MAX_VALUE (15)
+
#define CAP11XX_REG_SENSOR_CALIB (0xb1 + (X))
#define CAP11XX_REG_SENSOR_CALIB_LSB1 0xb9
#define CAP11XX_REG_SENSOR_CALIB_LSB2 0xba
@@ -56,10 +71,23 @@
#define CAP11XX_MANUFACTURER_ID 0x5d
+#ifdef CONFIG_LEDS_CLASS
+struct cap11xx_led {
+ struct cap11xx_priv *priv;
+ struct led_classdev cdev;
+ struct work_struct work;
+ u32 reg;
+ enum led_brightness new_brightness;
+};
+#endif
+
struct cap11xx_priv {
struct regmap *regmap;
struct input_dev *idev;
+ struct cap11xx_led *leds;
+ int num_leds;
+
/* config */
u32 keycodes[];
};
@@ -67,6 +95,7 @@ struct cap11xx_priv {
struct cap11xx_hw_model {
u8 product_id;
unsigned int num_channels;
+ unsigned int num_leds;
};
enum {
@@ -76,9 +105,9 @@ enum {
};
static const struct cap11xx_hw_model cap11xx_devices[] = {
- [CAP1106] = { .product_id = 0x55, .num_channels = 6 },
- [CAP1126] = { .product_id = 0x53, .num_channels = 6 },
- [CAP1188] = { .product_id = 0x50, .num_channels = 8 },
+ [CAP1106] = { .product_id = 0x55, .num_channels = 6, .num_leds = 0 },
+ [CAP1126] = { .product_id = 0x53, .num_channels = 6, .num_leds = 2 },
+ [CAP1188] = { .product_id = 0x50, .num_channels = 8, .num_leds = 8 },
};
static const struct reg_default cap11xx_reg_defaults[] = {
@@ -111,6 +140,7 @@ static const struct reg_default cap11xx_reg_defaults[] = {
{ CAP11XX_REG_STANDBY_SENSITIVITY, 0x02 },
{ CAP11XX_REG_STANDBY_THRESH, 0x40 },
{ CAP11XX_REG_CONFIG2, 0x40 },
+ { CAP11XX_REG_LED_POLARITY, 0x00 },
{ CAP11XX_REG_SENSOR_CALIB_LSB1, 0x00 },
{ CAP11XX_REG_SENSOR_CALIB_LSB2, 0x00 },
};
@@ -177,6 +207,12 @@ out:
static int cap11xx_set_sleep(struct cap11xx_priv *priv, bool sleep)
{
+ /*
+ * DLSEEP mode will turn off all LEDS, prevent this
+ */
+ if (IS_ENABLED(CONFIG_LEDS_CLASS) && priv->num_leds)
+ return 0;
+
return regmap_update_bits(priv->regmap, CAP11XX_REG_MAIN_CONTROL,
CAP11XX_REG_MAIN_CONTROL_DLSEEP,
sleep ? CAP11XX_REG_MAIN_CONTROL_DLSEEP : 0);
@@ -196,6 +232,104 @@ static void cap11xx_input_close(struct input_dev *idev)
cap11xx_set_sleep(priv, true);
}
+#ifdef CONFIG_LEDS_CLASS
+static void cap11xx_led_work(struct work_struct *work)
+{
+ struct cap11xx_led *led = container_of(work, struct cap11xx_led, work);
+ struct cap11xx_priv *priv = led->priv;
+ int value = led->new_brightness;
+
+ /*
+ * All LEDs share the same duty cycle as this is a HW limitation.
+ * Brightness levels per LED are either 0 (OFF) and 1 (ON).
+ */
+ regmap_update_bits(priv->regmap, CAP11XX_REG_LED_OUTPUT_CONTROL,
+ BIT(led->reg), value ? BIT(led->reg) : 0);
+}
+
+static void cap11xx_led_set(struct led_classdev *cdev,
+ enum led_brightness value)
+{
+ struct cap11xx_led *led = container_of(cdev, struct cap11xx_led, cdev);
+
+ if (led->new_brightness == value)
+ return;
+
+ led->new_brightness = value;
+ schedule_work(&led->work);
+}
+
+static int cap11xx_init_leds(struct device *dev,
+ struct cap11xx_priv *priv, int num_leds)
+{
+ struct device_node *node = dev->of_node, *child;
+ struct cap11xx_led *led;
+ int cnt = of_get_child_count(node);
+ int error;
+
+ if (!num_leds || !cnt)
+ return 0;
+
+ if (cnt > num_leds)
+ return -EINVAL;
+
+ led = devm_kcalloc(dev, cnt, sizeof(struct cap11xx_led), GFP_KERNEL);
+ if (!led)
+ return -ENOMEM;
+
+ priv->leds = led;
+
+ error = regmap_update_bits(priv->regmap,
+ CAP11XX_REG_LED_OUTPUT_CONTROL, 0xff, 0);
+ if (error)
+ return error;
+
+ error = regmap_update_bits(priv->regmap, CAP11XX_REG_LED_DUTY_CYCLE_4,
+ CAP11XX_REG_LED_DUTY_MAX_MASK,
+ CAP11XX_REG_LED_DUTY_MAX_VALUE <<
+ CAP11XX_REG_LED_DUTY_MAX_MASK_SHIFT);
+ if (error)
+ return error;
+
+ for_each_child_of_node(node, child) {
+ u32 reg;
+
+ led->cdev.name =
+ of_get_property(child, "label", NULL) ? : child->name;
+ led->cdev.default_trigger =
+ of_get_property(child, "linux,default-trigger", NULL);
+ led->cdev.flags = 0;
+ led->cdev.brightness_set = cap11xx_led_set;
+ led->cdev.max_brightness = 1;
+ led->cdev.brightness = LED_OFF;
+
+ error = of_property_read_u32(child, "reg", &reg);
+ if (error != 0 || reg >= num_leds)
+ return -EINVAL;
+
+ led->reg = reg;
+ led->priv = priv;
+
+ INIT_WORK(&led->work, cap11xx_led_work);
+
+ error = devm_led_classdev_register(dev, &led->cdev);
+ if (error)
+ return error;
+
+ priv->num_leds++;
+ led++;
+ }
+
+ return 0;
+}
+#else
+static int cap11xx_init_leds(struct device *dev,
+ struct cap11xx_priv *priv, int num_leds)
+{
+ return 0;
+}
+#endif
+
static int cap11xx_i2c_probe(struct i2c_client *i2c_client,
const struct i2c_device_id *id)
{
@@ -316,6 +450,10 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client,
priv->idev->open = cap11xx_input_open;
priv->idev->close = cap11xx_input_close;
+ error = cap11xx_init_leds(dev, priv, cap->num_leds);
+ if (error)
+ return error;
+
input_set_drvdata(priv->idev, priv);
/*
@@ -361,7 +499,6 @@ MODULE_DEVICE_TABLE(i2c, cap11xx_i2c_ids);
static struct i2c_driver cap11xx_i2c_driver = {
.driver = {
.name = "cap11xx",
- .owner = THIS_MODULE,
.of_match_table = cap11xx_dt_ids,
},
.id_table = cap11xx_i2c_ids,
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index ddf4045de..9d517ca7e 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -239,6 +239,11 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
}
}
+ if (i == ddata->pdata->nbuttons) {
+ error = -EINVAL;
+ goto out;
+ }
+
mutex_lock(&ddata->disable_lock);
for (i = 0; i < ddata->pdata->nbuttons; i++) {
@@ -655,7 +660,9 @@ gpio_keys_get_devtree_pdata(struct device *dev)
if (of_property_read_u32(pp, "linux,input-type", &button->type))
button->type = EV_KEY;
- button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
+ button->wakeup = of_property_read_bool(pp, "wakeup-source") ||
+ /* legacy name */
+ of_property_read_bool(pp, "gpio-key,wakeup");
button->can_disable = !!of_get_property(pp, "linux,can-disable", NULL);
diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c
index c6dc644aa..870cfa6e2 100644
--- a/drivers/input/keyboard/gpio_keys_polled.c
+++ b/drivers/input/keyboard/gpio_keys_polled.c
@@ -152,7 +152,10 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
&button->type))
button->type = EV_KEY;
- button->wakeup = fwnode_property_present(child, "gpio-key,wakeup");
+ button->wakeup =
+ fwnode_property_read_bool(child, "wakeup-source") ||
+ /* legacy name */
+ fwnode_property_read_bool(child, "gpio-key,wakeup");
if (fwnode_property_read_u32(child, "debounce-interval",
&button->debounce_interval))
diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c
index d2ea863d6..2165f3dd3 100644
--- a/drivers/input/keyboard/imx_keypad.c
+++ b/drivers/input/keyboard/imx_keypad.c
@@ -5,8 +5,6 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
- *
- * <<Power management needs to be implemented>>.
*/
#include <linux/clk.h>
diff --git a/drivers/input/keyboard/lm8333.c b/drivers/input/keyboard/lm8333.c
index 0ad422b8a..c717e8f3c 100644
--- a/drivers/input/keyboard/lm8333.c
+++ b/drivers/input/keyboard/lm8333.c
@@ -223,7 +223,6 @@ MODULE_DEVICE_TABLE(i2c, lm8333_id);
static struct i2c_driver lm8333_driver = {
.driver = {
.name = "lm8333",
- .owner = THIS_MODULE,
},
.probe = lm8333_probe,
.remove = lm8333_remove,
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
index b370a59cb..7f12b6579 100644
--- a/drivers/input/keyboard/matrix_keypad.c
+++ b/drivers/input/keyboard/matrix_keypad.c
@@ -425,8 +425,10 @@ matrix_keypad_parse_dt(struct device *dev)
if (of_get_property(np, "linux,no-autorepeat", NULL))
pdata->no_autorepeat = true;
- if (of_get_property(np, "linux,wakeup", NULL))
- pdata->wakeup = true;
+
+ pdata->wakeup = of_property_read_bool(np, "wakeup-source") ||
+ of_property_read_bool(np, "linux,wakeup"); /* legacy */
+
if (of_get_property(np, "gpio-activelow", NULL))
pdata->active_low = true;
diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c
index 375b05ca8..31090d71a 100644
--- a/drivers/input/keyboard/mcs_touchkey.c
+++ b/drivers/input/keyboard/mcs_touchkey.c
@@ -265,7 +265,6 @@ MODULE_DEVICE_TABLE(i2c, mcs_touchkey_id);
static struct i2c_driver mcs_touchkey_driver = {
.driver = {
.name = "mcs_touchkey",
- .owner = THIS_MODULE,
.pm = &mcs_touchkey_pm_ops,
},
.probe = mcs_touchkey_probe,
diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c
index 3aa2ec45b..0fd612dd7 100644
--- a/drivers/input/keyboard/mpr121_touchkey.c
+++ b/drivers/input/keyboard/mpr121_touchkey.c
@@ -305,7 +305,6 @@ MODULE_DEVICE_TABLE(i2c, mpr121_id);
static struct i2c_driver mpr_touchkey_driver = {
.driver = {
.name = "mpr121",
- .owner = THIS_MODULE,
.pm = &mpr121_touchkey_pm_ops,
},
.id_table = mpr121_id,
diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c
index b052afec9..6639b2b85 100644
--- a/drivers/input/keyboard/omap4-keypad.c
+++ b/drivers/input/keyboard/omap4-keypad.c
@@ -266,7 +266,7 @@ static int omap4_keypad_probe(struct platform_device *pdev)
error = omap4_keypad_parse_dt(&pdev->dev, keypad_data);
if (error)
- return error;
+ goto err_free_keypad;
res = request_mem_region(res->start, resource_size(res), pdev->name);
if (!res) {
diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c
index 32580afec..5c68e3f09 100644
--- a/drivers/input/keyboard/pmic8xxx-keypad.c
+++ b/drivers/input/keyboard/pmic8xxx-keypad.c
@@ -507,6 +507,7 @@ static void pmic8xxx_kp_close(struct input_dev *dev)
*/
static int pmic8xxx_kp_probe(struct platform_device *pdev)
{
+ struct device_node *np = pdev->dev.of_node;
unsigned int rows, cols;
bool repeat;
bool wakeup;
@@ -524,10 +525,11 @@ static int pmic8xxx_kp_probe(struct platform_device *pdev)
return -EINVAL;
}
- repeat = !of_property_read_bool(pdev->dev.of_node,
- "linux,input-no-autorepeat");
- wakeup = of_property_read_bool(pdev->dev.of_node,
- "linux,keypad-wakeup");
+ repeat = !of_property_read_bool(np, "linux,input-no-autorepeat");
+
+ wakeup = of_property_read_bool(np, "wakeup-source") ||
+ /* legacy name */
+ of_property_read_bool(np, "linux,keypad-wakeup");
kp = devm_kzalloc(&pdev->dev, sizeof(*kp), GFP_KERNEL);
if (!kp)
diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c
index 52cd6e88a..5a5778729 100644
--- a/drivers/input/keyboard/qt1070.c
+++ b/drivers/input/keyboard/qt1070.c
@@ -277,7 +277,6 @@ MODULE_DEVICE_TABLE(i2c, qt1070_id);
static struct i2c_driver qt1070_driver = {
.driver = {
.name = "qt1070",
- .owner = THIS_MODULE,
.pm = &qt1070_pm_ops,
},
.id_table = qt1070_id,
diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c
index 819b22897..43b86482d 100644
--- a/drivers/input/keyboard/qt2160.c
+++ b/drivers/input/keyboard/qt2160.c
@@ -497,7 +497,6 @@ MODULE_DEVICE_TABLE(i2c, qt2160_idtable);
static struct i2c_driver qt2160_driver = {
.driver = {
.name = "qt2160",
- .owner = THIS_MODULE,
},
.id_table = qt2160_idtable,
diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c
index 43e48dac7..4e319eb9e 100644
--- a/drivers/input/keyboard/samsung-keypad.c
+++ b/drivers/input/keyboard/samsung-keypad.c
@@ -299,8 +299,10 @@ samsung_keypad_parse_dt(struct device *dev)
if (of_get_property(np, "linux,input-no-autorepeat", NULL))
pdata->no_autorepeat = true;
- if (of_get_property(np, "linux,input-wakeup", NULL))
- pdata->wakeup = true;
+ pdata->wakeup = of_property_read_bool(np, "wakeup-source") ||
+ /* legacy name */
+ of_property_read_bool(np, "linux,input-wakeup");
+
return pdata;
}
diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c
new file mode 100644
index 000000000..78fd24ca3
--- /dev/null
+++ b/drivers/input/keyboard/snvs_pwrkey.c
@@ -0,0 +1,227 @@
+/*
+ * Driver for the IMX SNVS ON/OFF Power Key
+ * Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+
+#define SNVS_LPSR_REG 0x4C /* LP Status Register */
+#define SNVS_LPCR_REG 0x38 /* LP Control Register */
+#define SNVS_HPSR_REG 0x14
+#define SNVS_HPSR_BTN BIT(6)
+#define SNVS_LPSR_SPO BIT(18)
+#define SNVS_LPCR_DEP_EN BIT(5)
+
+#define DEBOUNCE_TIME 30
+#define REPEAT_INTERVAL 60
+
+struct pwrkey_drv_data {
+ struct regmap *snvs;
+ int irq;
+ int keycode;
+ int keystate; /* 1:pressed */
+ int wakeup;
+ struct timer_list check_timer;
+ struct input_dev *input;
+};
+
+static void imx_imx_snvs_check_for_events(unsigned long data)
+{
+ struct pwrkey_drv_data *pdata = (struct pwrkey_drv_data *) data;
+ struct input_dev *input = pdata->input;
+ u32 state;
+
+ regmap_read(pdata->snvs, SNVS_HPSR_REG, &state);
+ state = state & SNVS_HPSR_BTN ? 1 : 0;
+
+ /* only report new event if status changed */
+ if (state ^ pdata->keystate) {
+ pdata->keystate = state;
+ input_event(input, EV_KEY, pdata->keycode, state);
+ input_sync(input);
+ pm_relax(pdata->input->dev.parent);
+ }
+
+ /* repeat check if pressed long */
+ if (state) {
+ mod_timer(&pdata->check_timer,
+ jiffies + msecs_to_jiffies(REPEAT_INTERVAL));
+ }
+}
+
+static irqreturn_t imx_snvs_pwrkey_interrupt(int irq, void *dev_id)
+{
+ struct platform_device *pdev = dev_id;
+ struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev);
+ u32 lp_status;
+
+ pm_wakeup_event(pdata->input->dev.parent, 0);
+
+ regmap_read(pdata->snvs, SNVS_LPSR_REG, &lp_status);
+ if (lp_status & SNVS_LPSR_SPO)
+ mod_timer(&pdata->check_timer, jiffies + msecs_to_jiffies(DEBOUNCE_TIME));
+
+ /* clear SPO status */
+ regmap_write(pdata->snvs, SNVS_LPSR_REG, SNVS_LPSR_SPO);
+
+ return IRQ_HANDLED;
+}
+
+static void imx_snvs_pwrkey_act(void *pdata)
+{
+ struct pwrkey_drv_data *pd = pdata;
+
+ del_timer_sync(&pd->check_timer);
+}
+
+static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
+{
+ struct pwrkey_drv_data *pdata = NULL;
+ struct input_dev *input = NULL;
+ struct device_node *np;
+ int error;
+
+ /* Get SNVS register Page */
+ np = pdev->dev.of_node;
+ if (!np)
+ return -ENODEV;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ pdata->snvs = syscon_regmap_lookup_by_phandle(np, "regmap");;
+
+ if (!pdata->snvs) {
+ dev_err(&pdev->dev, "Can't get snvs syscon\n");
+ return -ENODEV;
+ }
+
+ if (of_property_read_u32(np, "linux,keycode", &pdata->keycode)) {
+ pdata->keycode = KEY_POWER;
+ dev_warn(&pdev->dev, "KEY_POWER without setting in dts\n");
+ }
+
+ pdata->wakeup = of_property_read_bool(np, "wakeup-source");
+
+ pdata->irq = platform_get_irq(pdev, 0);
+ if (pdata->irq < 0) {
+ dev_err(&pdev->dev, "no irq defined in platform data\n");
+ return -EINVAL;
+ }
+
+ regmap_update_bits(pdata->snvs, SNVS_LPCR_REG, SNVS_LPCR_DEP_EN, SNVS_LPCR_DEP_EN);
+
+ /* clear the unexpected interrupt before driver ready */
+ regmap_write(pdata->snvs, SNVS_LPSR_REG, SNVS_LPSR_SPO);
+
+ setup_timer(&pdata->check_timer,
+ imx_imx_snvs_check_for_events, (unsigned long) pdata);
+
+ input = devm_input_allocate_device(&pdev->dev);
+ if (!input) {
+ dev_err(&pdev->dev, "failed to allocate the input device\n");
+ return -ENOMEM;
+ }
+
+ input->name = pdev->name;
+ input->phys = "snvs-pwrkey/input0";
+ input->id.bustype = BUS_HOST;
+
+ input_set_capability(input, EV_KEY, pdata->keycode);
+
+ /* input customer action to cancel release timer */
+ error = devm_add_action(&pdev->dev, imx_snvs_pwrkey_act, pdata);
+ if (error) {
+ dev_err(&pdev->dev, "failed to register remove action\n");
+ return error;
+ }
+
+ error = devm_request_irq(&pdev->dev, pdata->irq,
+ imx_snvs_pwrkey_interrupt,
+ 0, pdev->name, pdev);
+
+ if (error) {
+ dev_err(&pdev->dev, "interrupt not available.\n");
+ return error;
+ }
+
+ error = input_register_device(input);
+ if (error < 0) {
+ dev_err(&pdev->dev, "failed to register input device\n");
+ input_free_device(input);
+ return error;
+ }
+
+ pdata->input = input;
+ platform_set_drvdata(pdev, pdata);
+
+ device_init_wakeup(&pdev->dev, pdata->wakeup);
+
+ return 0;
+}
+
+static int imx_snvs_pwrkey_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev);
+
+ if (device_may_wakeup(&pdev->dev))
+ enable_irq_wake(pdata->irq);
+
+ return 0;
+}
+
+static int imx_snvs_pwrkey_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev);
+
+ if (device_may_wakeup(&pdev->dev))
+ disable_irq_wake(pdata->irq);
+
+ return 0;
+}
+
+static const struct of_device_id imx_snvs_pwrkey_ids[] = {
+ { .compatible = "fsl,sec-v4.0-pwrkey" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_snvs_pwrkey_ids);
+
+static SIMPLE_DEV_PM_OPS(imx_snvs_pwrkey_pm_ops, imx_snvs_pwrkey_suspend,
+ imx_snvs_pwrkey_resume);
+
+static struct platform_driver imx_snvs_pwrkey_driver = {
+ .driver = {
+ .name = "snvs_pwrkey",
+ .pm = &imx_snvs_pwrkey_pm_ops,
+ .of_match_table = imx_snvs_pwrkey_ids,
+ },
+ .probe = imx_snvs_pwrkey_probe,
+};
+module_platform_driver(imx_snvs_pwrkey_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor");
+MODULE_DESCRIPTION("i.MX snvs power key Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c
index 31c606a4d..e92dfd888 100644
--- a/drivers/input/keyboard/tc3589x-keypad.c
+++ b/drivers/input/keyboard/tc3589x-keypad.c
@@ -17,6 +17,7 @@
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/mfd/tc3589x.h>
+#include <linux/device.h>
/* Maximum supported keypad matrix row/columns size */
#define TC3589x_MAX_KPROW 8
@@ -352,7 +353,10 @@ tc3589x_keypad_of_probe(struct device *dev)
}
plat->no_autorepeat = of_property_read_bool(np, "linux,no-autorepeat");
- plat->enable_wakeup = of_property_read_bool(np, "linux,wakeup");
+
+ plat->enable_wakeup = of_property_read_bool(np, "wakeup-source") ||
+ /* legacy name */
+ of_property_read_bool(np, "linux,wakeup");
/* The custom delay format is ms/16 */
of_property_read_u32(np, "debounce-delay-ms", &debounce_ms);
@@ -386,12 +390,15 @@ static int tc3589x_keypad_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- keypad = kzalloc(sizeof(struct tc_keypad), GFP_KERNEL);
- input = input_allocate_device();
- if (!keypad || !input) {
- dev_err(&pdev->dev, "failed to allocate keypad memory\n");
- error = -ENOMEM;
- goto err_free_mem;
+ keypad = devm_kzalloc(&pdev->dev, sizeof(struct tc_keypad),
+ GFP_KERNEL);
+ if (!keypad)
+ return -ENOMEM;
+
+ input = devm_input_allocate_device(&pdev->dev);
+ if (!input) {
+ dev_err(&pdev->dev, "failed to allocate input device\n");
+ return -ENOMEM;
}
keypad->board = plat;
@@ -410,7 +417,7 @@ static int tc3589x_keypad_probe(struct platform_device *pdev)
NULL, input);
if (error) {
dev_err(&pdev->dev, "Failed to build keymap\n");
- goto err_free_mem;
+ return error;
}
keypad->keymap = input->keycode;
@@ -421,20 +428,23 @@ static int tc3589x_keypad_probe(struct platform_device *pdev)
input_set_drvdata(input, keypad);
- error = request_threaded_irq(irq, NULL, tc3589x_keypad_irq,
- plat->irqtype | IRQF_ONESHOT,
- "tc3589x-keypad", keypad);
- if (error < 0) {
+ tc3589x_keypad_disable(keypad);
+
+ error = devm_request_threaded_irq(&pdev->dev, irq,
+ NULL, tc3589x_keypad_irq,
+ plat->irqtype | IRQF_ONESHOT,
+ "tc3589x-keypad", keypad);
+ if (error) {
dev_err(&pdev->dev,
"Could not allocate irq %d,error %d\n",
irq, error);
- goto err_free_mem;
+ return error;
}
error = input_register_device(input);
if (error) {
dev_err(&pdev->dev, "Could not register input device\n");
- goto err_free_irq;
+ return error;
}
/* let platform decide if keypad is a wakeup source or not */
@@ -444,30 +454,6 @@ static int tc3589x_keypad_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, keypad);
return 0;
-
-err_free_irq:
- free_irq(irq, keypad);
-err_free_mem:
- input_free_device(input);
- kfree(keypad);
- return error;
-}
-
-static int tc3589x_keypad_remove(struct platform_device *pdev)
-{
- struct tc_keypad *keypad = platform_get_drvdata(pdev);
- int irq = platform_get_irq(pdev, 0);
-
- if (!keypad->keypad_stopped)
- tc3589x_keypad_disable(keypad);
-
- free_irq(irq, keypad);
-
- input_unregister_device(keypad->input);
-
- kfree(keypad);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -518,7 +504,6 @@ static struct platform_driver tc3589x_keypad_driver = {
.pm = &tc3589x_keypad_dev_pm_ops,
},
.probe = tc3589x_keypad_probe,
- .remove = tc3589x_keypad_remove,
};
module_platform_driver(tc3589x_keypad_driver);
diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c
index 4e491c176..900229869 100644
--- a/drivers/input/keyboard/tca8418_keypad.c
+++ b/drivers/input/keyboard/tca8418_keypad.c
@@ -404,7 +404,6 @@ MODULE_ALIAS("i2c:tca8418");
static struct i2c_driver tca8418_keypad_driver = {
.driver = {
.name = TCA8418_NAME,
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(tca8418_dt_ids),
},
.probe = tca8418_keypad_probe,