--- v7
+++ v6
@@ -9,15 +9,12 @@
Signed-off-by: Jaechul Lee <jcsing.lee@samsung.com>
Reviewed-by: Javier Martinez Canillas <javier@osg.samsung.com>
Reviewed-by: Andi Shyti <andi.shyti@samsung.com>
-Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>
-Tested-by: Chanwoo Choi <cw00.choi@samsung.com>
Acked-by: Krzysztof Kozlowski <krzk@kernel.org>
-Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/input/keyboard/Kconfig | 11 ++
drivers/input/keyboard/Makefile | 1 +
- drivers/input/keyboard/tm2-touchkey.c | 286 ++++++++++++++++++++++++++++++++++
- 3 files changed, 298 insertions(+)
+ drivers/input/keyboard/tm2-touchkey.c | 287 ++++++++++++++++++++++++++++++++++
+ 3 files changed, 299 insertions(+)
create mode 100644 drivers/input/keyboard/tm2-touchkey.c
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
@@ -56,10 +53,10 @@
obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o
diff --git a/drivers/input/keyboard/tm2-touchkey.c b/drivers/input/keyboard/tm2-touchkey.c
new file mode 100644
-index 0000000..916e2f3
+index 0000000..e927d06
--- /dev/null
+++ b/drivers/input/keyboard/tm2-touchkey.c
-@@ -0,0 +1,286 @@
+@@ -0,0 +1,287 @@
+/*
+ * TM2 touchkey device driver
+ *
@@ -102,19 +99,26 @@
+ TM2_TOUCHKEY_KEY_BACK,
+};
+
++enum {
++ TM2_TOUCHKEY_SUPPLIES_VCC,
++ TM2_TOUCHKEY_SUPPLIES_VDD,
++};
++
+struct tm2_touchkey_data {
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+ struct led_classdev led_dev;
-+ struct regulator *vdd;
+ struct regulator_bulk_data regulators[2];
++
++ u8 keycode_type;
++ u8 pressed;
+};
+
+static void tm2_touchkey_led_brightness_set(struct led_classdev *led_dev,
-+ enum led_brightness brightness)
++ enum led_brightness brightness)
+{
+ struct tm2_touchkey_data *touchkey =
-+ container_of(led_dev, struct tm2_touchkey_data, led_dev);
++ container_of(led_dev, struct tm2_touchkey_data, led_dev);
+ u32 volt;
+ u8 data;
+
@@ -126,19 +130,21 @@
+ data = TM2_TOUCHKEY_CMD_LED_ON;
+ }
+
-+ regulator_set_voltage(touchkey->vdd, volt, volt);
++ regulator_set_voltage(
++ touchkey->regulators[TM2_TOUCHKEY_SUPPLIES_VDD].consumer,
++ volt, volt);
+ i2c_smbus_write_byte_data(touchkey->client,
-+ TM2_TOUCHKEY_BASE_REG, data);
++ TM2_TOUCHKEY_BASE_REG, data);
+}
+
+static int tm2_touchkey_power_enable(struct tm2_touchkey_data *touchkey)
+{
-+ int error;
-+
-+ error = regulator_bulk_enable(ARRAY_SIZE(touchkey->regulators),
-+ touchkey->regulators);
-+ if (error)
-+ return error;
++ int ret = 0;
++
++ ret = regulator_bulk_enable(ARRAY_SIZE(touchkey->regulators),
++ touchkey->regulators);
++ if (ret)
++ return ret;
+
+ /* waiting for device initialization, at least 150ms */
+ msleep(150);
@@ -151,61 +157,60 @@
+ struct tm2_touchkey_data *touchkey = data;
+
+ regulator_bulk_disable(ARRAY_SIZE(touchkey->regulators),
-+ touchkey->regulators);
++ touchkey->regulators);
+}
+
+static irqreturn_t tm2_touchkey_irq_handler(int irq, void *devid)
+{
+ struct tm2_touchkey_data *touchkey = devid;
-+ int data;
-+ int key;
++ u32 data;
+
+ data = i2c_smbus_read_byte_data(touchkey->client,
+ TM2_TOUCHKEY_KEYCODE_REG);
++
+ if (data < 0) {
-+ dev_err(&touchkey->client->dev,
-+ "failed to read i2c data: %d\n", data);
-+ goto out;
-+ }
-+
-+ switch (data & TM2_TOUCHKEY_BIT_KEYCODE) {
-+ case TM2_TOUCHKEY_KEY_MENU:
-+ key = KEY_PHONE;
-+ break;
-+
-+ case TM2_TOUCHKEY_KEY_BACK:
-+ key = KEY_BACK;
-+ break;
-+
-+ default:
-+ dev_warn(&touchkey->client->dev,
-+ "unhandled keycode, data %#02x\n", data);
-+ goto out;
-+ }
-+
-+ if (data & TM2_TOUCHKEY_BIT_PRESS_EV) {
++ dev_err(&touchkey->client->dev, "Failed to read i2c data\n");
++ return IRQ_HANDLED;
++ }
++
++ touchkey->keycode_type = data & TM2_TOUCHKEY_BIT_KEYCODE;
++ touchkey->pressed = !(data & TM2_TOUCHKEY_BIT_PRESS_EV);
++
++ if (touchkey->keycode_type != TM2_TOUCHKEY_KEY_MENU &&
++ touchkey->keycode_type != TM2_TOUCHKEY_KEY_BACK) {
++ dev_warn(&touchkey->client->dev, "Skip unhandled keycode(%d)\n",
++ touchkey->keycode_type);
++ return IRQ_HANDLED;
++ }
++
++ if (!touchkey->pressed) {
+ input_report_key(touchkey->input_dev, KEY_PHONE, 0);
+ input_report_key(touchkey->input_dev, KEY_BACK, 0);
+ } else {
-+ input_report_key(touchkey->input_dev, key, 1);
-+ }
-+
++ if (touchkey->keycode_type == TM2_TOUCHKEY_KEY_MENU)
++ input_report_key(touchkey->input_dev,
++ KEY_PHONE, 1);
++ else
++ input_report_key(touchkey->input_dev,
++ KEY_BACK, 1);
++ }
+ input_sync(touchkey->input_dev);
+
-+out:
+ return IRQ_HANDLED;
+}
+
+static int tm2_touchkey_probe(struct i2c_client *client,
-+ const struct i2c_device_id *id)
++ const struct i2c_device_id *id)
+{
+ struct tm2_touchkey_data *touchkey;
-+ int error;
-+
-+ if (!i2c_check_functionality(client->adapter,
-+ I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA)) {
-+ dev_err(&client->dev, "incompatible I2C adapter\n");
-+ return -EIO;
++ int ret;
++
++ ret = i2c_check_functionality(client->adapter,
++ I2C_FUNC_SMBUS_BYTE |
++ I2C_FUNC_SMBUS_BYTE_DATA);
++ if (!ret) {
++ dev_err(&client->dev, "No I2C functionality found\n");
++ return -ENODEV;
+ }
+
+ touchkey = devm_kzalloc(&client->dev, sizeof(*touchkey), GFP_KERNEL);
@@ -215,63 +220,59 @@
+ touchkey->client = client;
+ i2c_set_clientdata(client, touchkey);
+
-+ touchkey->regulators[0].supply = "vcc";
-+ touchkey->regulators[1].supply = "vdd";
-+ error = devm_regulator_bulk_get(&client->dev,
++ /* regulators */
++ touchkey->regulators[TM2_TOUCHKEY_SUPPLIES_VCC].supply = "vcc";
++ touchkey->regulators[TM2_TOUCHKEY_SUPPLIES_VDD].supply = "vdd";
++ ret = devm_regulator_bulk_get(&client->dev,
+ ARRAY_SIZE(touchkey->regulators),
+ touchkey->regulators);
-+ if (error) {
-+ dev_err(&client->dev, "failed to get regulators: %d\n", error);
-+ return error;
-+ }
-+
-+ /* Save VDD for easy access */
-+ touchkey->vdd = touchkey->regulators[1].consumer;
-+
-+ error = tm2_touchkey_power_enable(touchkey);
-+ if (error) {
-+ dev_err(&client->dev, "failed to power up device: %d\n", error);
-+ return error;
-+ }
-+
-+ error = devm_add_action_or_reset(&client->dev,
-+ tm2_touchkey_power_disable, touchkey);
-+ if (error) {
-+ dev_err(&client->dev,
-+ "failed to install poweroff handler: %d\n", error);
-+ return error;
-+ }
++ if (ret) {
++ dev_err(&client->dev, "Failed to get regulators\n");
++ return ret;
++ }
++
++ /* power */
++ ret = tm2_touchkey_power_enable(touchkey);
++ if (ret) {
++ dev_err(&client->dev, "Failed to enable power\n");
++ return ret;
++ }
++
++ ret = devm_add_action_or_reset(&client->dev,
++ tm2_touchkey_power_disable, touchkey);
++ if (ret)
++ return ret;
+
+ /* input device */
+ touchkey->input_dev = devm_input_allocate_device(&client->dev);
+ if (!touchkey->input_dev) {
-+ dev_err(&client->dev, "failed to allocate input device\n");
++ dev_err(&client->dev, "Failed to alloc input device\n");
+ return -ENOMEM;
+ }
-+
+ touchkey->input_dev->name = TM2_TOUCHKEY_DEV_NAME;
+ touchkey->input_dev->id.bustype = BUS_I2C;
+
++ set_bit(EV_KEY, touchkey->input_dev->evbit);
+ input_set_capability(touchkey->input_dev, EV_KEY, KEY_PHONE);
+ input_set_capability(touchkey->input_dev, EV_KEY, KEY_BACK);
+
+ input_set_drvdata(touchkey->input_dev, touchkey);
+
-+ error = input_register_device(touchkey->input_dev);
-+ if (error) {
-+ dev_err(&client->dev,
-+ "failed to register input device: %d\n", error);
-+ return error;
-+ }
-+
-+ error = devm_request_threaded_irq(&client->dev, client->irq,
-+ NULL, tm2_touchkey_irq_handler,
-+ IRQF_ONESHOT,
-+ TM2_TOUCHKEY_DEV_NAME, touchkey);
-+ if (error) {
-+ dev_err(&client->dev,
-+ "failed to request threaded irq: %d\n", error);
-+ return error;
++ ret = input_register_device(touchkey->input_dev);
++ if (ret) {
++ dev_err(&client->dev, "Failed to register input device\n");
++ return ret;
++ }
++
++ /* irq */
++ ret = devm_request_threaded_irq(&client->dev,
++ client->irq, NULL,
++ tm2_touchkey_irq_handler,
++ IRQF_ONESHOT, TM2_TOUCHKEY_DEV_NAME,
++ touchkey);
++ if (ret) {
++ dev_err(&client->dev, "Failed to request threaded irq\n");
++ return ret;
+ }
+
+ /* led device */
@@ -280,11 +281,10 @@
+ touchkey->led_dev.max_brightness = LED_FULL;
+ touchkey->led_dev.brightness_set = tm2_touchkey_led_brightness_set;
+
-+ error = devm_led_classdev_register(&client->dev, &touchkey->led_dev);
-+ if (error) {
-+ dev_err(&client->dev,
-+ "failed to register touchkey led: %d\n", error);
-+ return error;
++ ret = devm_led_classdev_register(&client->dev, &touchkey->led_dev);
++ if (ret < 0) {
++ dev_err(&client->dev, "Failed to register touchkey led\n");
++ return ret;
+ }
+
+ return 0;
@@ -292,10 +292,9 @@
+
+static int __maybe_unused tm2_touchkey_suspend(struct device *dev)
+{
-+ struct i2c_client *client = to_i2c_client(dev);
-+ struct tm2_touchkey_data *touchkey = i2c_get_clientdata(client);
-+
-+ disable_irq(client->irq);
++ struct tm2_touchkey_data *touchkey = dev_get_drvdata(dev);
++
++ disable_irq(touchkey->client->irq);
+ tm2_touchkey_power_disable(touchkey);
+
+ return 0;
@@ -303,31 +302,29 @@
+
+static int __maybe_unused tm2_touchkey_resume(struct device *dev)
+{
-+ struct i2c_client *client = to_i2c_client(dev);
-+ struct tm2_touchkey_data *touchkey = i2c_get_clientdata(client);
++ struct tm2_touchkey_data *touchkey = dev_get_drvdata(dev);
+ int ret;
+
-+ enable_irq(client->irq);
-+
++ enable_irq(touchkey->client->irq);
+ ret = tm2_touchkey_power_enable(touchkey);
+ if (ret)
-+ dev_err(dev, "failed to enable power: %d\n", ret);
++ dev_err(dev, "Failed to enable power\n");
+
+ return ret;
+}
+
-+static SIMPLE_DEV_PM_OPS(tm2_touchkey_pm_ops,
-+ tm2_touchkey_suspend, tm2_touchkey_resume);
++static SIMPLE_DEV_PM_OPS(tm2_touchkey_pm_ops, tm2_touchkey_suspend,
++ tm2_touchkey_resume);
+
+static const struct i2c_device_id tm2_touchkey_id_table[] = {
-+ { TM2_TOUCHKEY_DEV_NAME, 0 },
-+ { },
++ {TM2_TOUCHKEY_DEV_NAME, 0},
++ {},
+};
+MODULE_DEVICE_TABLE(i2c, tm2_touchkey_id_table);
+
+static const struct of_device_id tm2_touchkey_of_match[] = {
-+ { .compatible = "cypress,tm2-touchkey", },
-+ { },
++ {.compatible = "cypress,tm2-touchkey",},
++ {},
+};
+MODULE_DEVICE_TABLE(of, tm2_touchkey_of_match);
+
@@ -340,6 +337,7 @@
+ .probe = tm2_touchkey_probe,
+ .id_table = tm2_touchkey_id_table,
+};
++
+module_i2c_driver(tm2_touchkey_driver);
+
+MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>");