2 * TM2 touchkey device driver
4 * Copyright 2005 Phil Blundell
5 * Copyright 2016 Samsung Electronics Co., Ltd.
7 * Author: Beomho Seo <beomho.seo@samsung.com>
8 * Author: Jaechul Lee <jcsing.lee@samsung.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
15 #include <linux/bitops.h>
16 #include <linux/delay.h>
17 #include <linux/device.h>
18 #include <linux/i2c.h>
19 #include <linux/input.h>
20 #include <linux/interrupt.h>
21 #include <linux/irq.h>
22 #include <linux/leds.h>
23 #include <linux/module.h>
26 #include <linux/regulator/consumer.h>
28 #define TM2_TOUCHKEY_DEV_NAME "tm2-touchkey"
29 #define TM2_TOUCHKEY_KEYCODE_REG 0x03
30 #define TM2_TOUCHKEY_BASE_REG 0x00
31 #define TM2_TOUCHKEY_CMD_LED_ON 0x10
32 #define TM2_TOUCHKEY_CMD_LED_OFF 0x20
33 #define TM2_TOUCHKEY_BIT_PRESS_EV BIT(3)
34 #define TM2_TOUCHKEY_BIT_KEYCODE GENMASK(2, 0)
35 #define TM2_TOUCHKEY_LED_VOLTAGE_MIN 2500000
36 #define TM2_TOUCHKEY_LED_VOLTAGE_MAX 3300000
39 TM2_TOUCHKEY_KEY_MENU
= 0x1,
40 TM2_TOUCHKEY_KEY_BACK
,
43 struct tm2_touchkey_data
{
44 struct i2c_client
*client
;
45 struct input_dev
*input_dev
;
46 struct led_classdev led_dev
;
47 struct regulator
*vdd
;
48 struct regulator_bulk_data regulators
[2];
51 static void tm2_touchkey_led_brightness_set(struct led_classdev
*led_dev
,
52 enum led_brightness brightness
)
54 struct tm2_touchkey_data
*touchkey
=
55 container_of(led_dev
, struct tm2_touchkey_data
, led_dev
);
59 if (brightness
== LED_OFF
) {
60 volt
= TM2_TOUCHKEY_LED_VOLTAGE_MIN
;
61 data
= TM2_TOUCHKEY_CMD_LED_OFF
;
63 volt
= TM2_TOUCHKEY_LED_VOLTAGE_MAX
;
64 data
= TM2_TOUCHKEY_CMD_LED_ON
;
67 regulator_set_voltage(touchkey
->vdd
, volt
, volt
);
68 i2c_smbus_write_byte_data(touchkey
->client
,
69 TM2_TOUCHKEY_BASE_REG
, data
);
72 static int tm2_touchkey_power_enable(struct tm2_touchkey_data
*touchkey
)
76 error
= regulator_bulk_enable(ARRAY_SIZE(touchkey
->regulators
),
77 touchkey
->regulators
);
81 /* waiting for device initialization, at least 150ms */
87 static void tm2_touchkey_power_disable(void *data
)
89 struct tm2_touchkey_data
*touchkey
= data
;
91 regulator_bulk_disable(ARRAY_SIZE(touchkey
->regulators
),
92 touchkey
->regulators
);
95 static irqreturn_t
tm2_touchkey_irq_handler(int irq
, void *devid
)
97 struct tm2_touchkey_data
*touchkey
= devid
;
101 data
= i2c_smbus_read_byte_data(touchkey
->client
,
102 TM2_TOUCHKEY_KEYCODE_REG
);
104 dev_err(&touchkey
->client
->dev
,
105 "failed to read i2c data: %d\n", data
);
109 switch (data
& TM2_TOUCHKEY_BIT_KEYCODE
) {
110 case TM2_TOUCHKEY_KEY_MENU
:
114 case TM2_TOUCHKEY_KEY_BACK
:
119 dev_warn(&touchkey
->client
->dev
,
120 "unhandled keycode, data %#02x\n", data
);
124 if (data
& TM2_TOUCHKEY_BIT_PRESS_EV
) {
125 input_report_key(touchkey
->input_dev
, KEY_PHONE
, 0);
126 input_report_key(touchkey
->input_dev
, KEY_BACK
, 0);
128 input_report_key(touchkey
->input_dev
, key
, 1);
131 input_sync(touchkey
->input_dev
);
137 static int tm2_touchkey_probe(struct i2c_client
*client
,
138 const struct i2c_device_id
*id
)
140 struct tm2_touchkey_data
*touchkey
;
143 if (!i2c_check_functionality(client
->adapter
,
144 I2C_FUNC_SMBUS_BYTE
| I2C_FUNC_SMBUS_BYTE_DATA
)) {
145 dev_err(&client
->dev
, "incompatible I2C adapter\n");
149 touchkey
= devm_kzalloc(&client
->dev
, sizeof(*touchkey
), GFP_KERNEL
);
153 touchkey
->client
= client
;
154 i2c_set_clientdata(client
, touchkey
);
156 touchkey
->regulators
[0].supply
= "vcc";
157 touchkey
->regulators
[1].supply
= "vdd";
158 error
= devm_regulator_bulk_get(&client
->dev
,
159 ARRAY_SIZE(touchkey
->regulators
),
160 touchkey
->regulators
);
162 dev_err(&client
->dev
, "failed to get regulators: %d\n", error
);
166 /* Save VDD for easy access */
167 touchkey
->vdd
= touchkey
->regulators
[1].consumer
;
169 error
= tm2_touchkey_power_enable(touchkey
);
171 dev_err(&client
->dev
, "failed to power up device: %d\n", error
);
175 error
= devm_add_action_or_reset(&client
->dev
,
176 tm2_touchkey_power_disable
, touchkey
);
178 dev_err(&client
->dev
,
179 "failed to install poweroff handler: %d\n", error
);
184 touchkey
->input_dev
= devm_input_allocate_device(&client
->dev
);
185 if (!touchkey
->input_dev
) {
186 dev_err(&client
->dev
, "failed to allocate input device\n");
190 touchkey
->input_dev
->name
= TM2_TOUCHKEY_DEV_NAME
;
191 touchkey
->input_dev
->id
.bustype
= BUS_I2C
;
193 input_set_capability(touchkey
->input_dev
, EV_KEY
, KEY_PHONE
);
194 input_set_capability(touchkey
->input_dev
, EV_KEY
, KEY_BACK
);
196 error
= input_register_device(touchkey
->input_dev
);
198 dev_err(&client
->dev
,
199 "failed to register input device: %d\n", error
);
203 error
= devm_request_threaded_irq(&client
->dev
, client
->irq
,
204 NULL
, tm2_touchkey_irq_handler
,
206 TM2_TOUCHKEY_DEV_NAME
, touchkey
);
208 dev_err(&client
->dev
,
209 "failed to request threaded irq: %d\n", error
);
214 touchkey
->led_dev
.name
= TM2_TOUCHKEY_DEV_NAME
;
215 touchkey
->led_dev
.brightness
= LED_FULL
;
216 touchkey
->led_dev
.max_brightness
= LED_ON
;
217 touchkey
->led_dev
.brightness_set
= tm2_touchkey_led_brightness_set
;
219 error
= devm_led_classdev_register(&client
->dev
, &touchkey
->led_dev
);
221 dev_err(&client
->dev
,
222 "failed to register touchkey led: %d\n", error
);
229 static int __maybe_unused
tm2_touchkey_suspend(struct device
*dev
)
231 struct i2c_client
*client
= to_i2c_client(dev
);
232 struct tm2_touchkey_data
*touchkey
= i2c_get_clientdata(client
);
234 disable_irq(client
->irq
);
235 tm2_touchkey_power_disable(touchkey
);
240 static int __maybe_unused
tm2_touchkey_resume(struct device
*dev
)
242 struct i2c_client
*client
= to_i2c_client(dev
);
243 struct tm2_touchkey_data
*touchkey
= i2c_get_clientdata(client
);
246 enable_irq(client
->irq
);
248 ret
= tm2_touchkey_power_enable(touchkey
);
250 dev_err(dev
, "failed to enable power: %d\n", ret
);
255 static SIMPLE_DEV_PM_OPS(tm2_touchkey_pm_ops
,
256 tm2_touchkey_suspend
, tm2_touchkey_resume
);
258 static const struct i2c_device_id tm2_touchkey_id_table
[] = {
259 { TM2_TOUCHKEY_DEV_NAME
, 0 },
262 MODULE_DEVICE_TABLE(i2c
, tm2_touchkey_id_table
);
264 static const struct of_device_id tm2_touchkey_of_match
[] = {
265 { .compatible
= "cypress,tm2-touchkey", },
268 MODULE_DEVICE_TABLE(of
, tm2_touchkey_of_match
);
270 static struct i2c_driver tm2_touchkey_driver
= {
272 .name
= TM2_TOUCHKEY_DEV_NAME
,
273 .pm
= &tm2_touchkey_pm_ops
,
274 .of_match_table
= of_match_ptr(tm2_touchkey_of_match
),
276 .probe
= tm2_touchkey_probe
,
277 .id_table
= tm2_touchkey_id_table
,
279 module_i2c_driver(tm2_touchkey_driver
);
281 MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>");
282 MODULE_AUTHOR("Jaechul Lee <jcsing.lee@samsung.com>");
283 MODULE_DESCRIPTION("Samsung touchkey driver");
284 MODULE_LICENSE("GPL v2");