Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * TM2 touchkey device driver
0004  *
0005  * Copyright 2005 Phil Blundell
0006  * Copyright 2016 Samsung Electronics Co., Ltd.
0007  *
0008  * Author: Beomho Seo <beomho.seo@samsung.com>
0009  * Author: Jaechul Lee <jcsing.lee@samsung.com>
0010  */
0011 
0012 #include <linux/bitops.h>
0013 #include <linux/delay.h>
0014 #include <linux/device.h>
0015 #include <linux/i2c.h>
0016 #include <linux/input.h>
0017 #include <linux/interrupt.h>
0018 #include <linux/irq.h>
0019 #include <linux/leds.h>
0020 #include <linux/module.h>
0021 #include <linux/of.h>
0022 #include <linux/of_device.h>
0023 #include <linux/pm.h>
0024 #include <linux/regulator/consumer.h>
0025 
0026 #define TM2_TOUCHKEY_DEV_NAME       "tm2-touchkey"
0027 
0028 #define ARIES_TOUCHKEY_CMD_LED_ON   0x1
0029 #define ARIES_TOUCHKEY_CMD_LED_OFF  0x2
0030 #define TM2_TOUCHKEY_CMD_LED_ON     0x10
0031 #define TM2_TOUCHKEY_CMD_LED_OFF    0x20
0032 #define TM2_TOUCHKEY_BIT_PRESS_EV   BIT(3)
0033 #define TM2_TOUCHKEY_BIT_KEYCODE    GENMASK(2, 0)
0034 #define TM2_TOUCHKEY_LED_VOLTAGE_MIN    2500000
0035 #define TM2_TOUCHKEY_LED_VOLTAGE_MAX    3300000
0036 
0037 struct touchkey_variant {
0038     u8 keycode_reg;
0039     u8 base_reg;
0040     u8 cmd_led_on;
0041     u8 cmd_led_off;
0042     bool no_reg;
0043     bool fixed_regulator;
0044 };
0045 
0046 struct tm2_touchkey_data {
0047     struct i2c_client *client;
0048     struct input_dev *input_dev;
0049     struct led_classdev led_dev;
0050     struct regulator *vdd;
0051     struct regulator_bulk_data regulators[3];
0052     const struct touchkey_variant *variant;
0053     u32 keycodes[4];
0054     int num_keycodes;
0055 };
0056 
0057 static const struct touchkey_variant tm2_touchkey_variant = {
0058     .keycode_reg = 0x03,
0059     .base_reg = 0x00,
0060     .cmd_led_on = TM2_TOUCHKEY_CMD_LED_ON,
0061     .cmd_led_off = TM2_TOUCHKEY_CMD_LED_OFF,
0062 };
0063 
0064 static const struct touchkey_variant midas_touchkey_variant = {
0065     .keycode_reg = 0x00,
0066     .base_reg = 0x00,
0067     .cmd_led_on = TM2_TOUCHKEY_CMD_LED_ON,
0068     .cmd_led_off = TM2_TOUCHKEY_CMD_LED_OFF,
0069 };
0070 
0071 static struct touchkey_variant aries_touchkey_variant = {
0072     .no_reg = true,
0073     .fixed_regulator = true,
0074     .cmd_led_on = ARIES_TOUCHKEY_CMD_LED_ON,
0075     .cmd_led_off = ARIES_TOUCHKEY_CMD_LED_OFF,
0076 };
0077 
0078 static const struct touchkey_variant tc360_touchkey_variant = {
0079     .keycode_reg = 0x00,
0080     .base_reg = 0x00,
0081     .fixed_regulator = true,
0082     .cmd_led_on = TM2_TOUCHKEY_CMD_LED_ON,
0083     .cmd_led_off = TM2_TOUCHKEY_CMD_LED_OFF,
0084 };
0085 
0086 static int tm2_touchkey_led_brightness_set(struct led_classdev *led_dev,
0087                         enum led_brightness brightness)
0088 {
0089     struct tm2_touchkey_data *touchkey =
0090         container_of(led_dev, struct tm2_touchkey_data, led_dev);
0091     u32 volt;
0092     u8 data;
0093 
0094     if (brightness == LED_OFF) {
0095         volt = TM2_TOUCHKEY_LED_VOLTAGE_MIN;
0096         data = touchkey->variant->cmd_led_off;
0097     } else {
0098         volt = TM2_TOUCHKEY_LED_VOLTAGE_MAX;
0099         data = touchkey->variant->cmd_led_on;
0100     }
0101 
0102     if (!touchkey->variant->fixed_regulator)
0103         regulator_set_voltage(touchkey->vdd, volt, volt);
0104 
0105     return touchkey->variant->no_reg ?
0106         i2c_smbus_write_byte(touchkey->client, data) :
0107         i2c_smbus_write_byte_data(touchkey->client,
0108                       touchkey->variant->base_reg, data);
0109 }
0110 
0111 static int tm2_touchkey_power_enable(struct tm2_touchkey_data *touchkey)
0112 {
0113     int error;
0114 
0115     error = regulator_bulk_enable(ARRAY_SIZE(touchkey->regulators),
0116                       touchkey->regulators);
0117     if (error)
0118         return error;
0119 
0120     /* waiting for device initialization, at least 150ms */
0121     msleep(150);
0122 
0123     return 0;
0124 }
0125 
0126 static void tm2_touchkey_power_disable(void *data)
0127 {
0128     struct tm2_touchkey_data *touchkey = data;
0129 
0130     regulator_bulk_disable(ARRAY_SIZE(touchkey->regulators),
0131                    touchkey->regulators);
0132 }
0133 
0134 static irqreturn_t tm2_touchkey_irq_handler(int irq, void *devid)
0135 {
0136     struct tm2_touchkey_data *touchkey = devid;
0137     int data;
0138     int index;
0139     int i;
0140 
0141     if (touchkey->variant->no_reg)
0142         data = i2c_smbus_read_byte(touchkey->client);
0143     else
0144         data = i2c_smbus_read_byte_data(touchkey->client,
0145                         touchkey->variant->keycode_reg);
0146     if (data < 0) {
0147         dev_err(&touchkey->client->dev,
0148             "failed to read i2c data: %d\n", data);
0149         goto out;
0150     }
0151 
0152     index = (data & TM2_TOUCHKEY_BIT_KEYCODE) - 1;
0153     if (index < 0 || index >= touchkey->num_keycodes) {
0154         dev_warn(&touchkey->client->dev,
0155              "invalid keycode index %d\n", index);
0156         goto out;
0157     }
0158 
0159     input_event(touchkey->input_dev, EV_MSC, MSC_SCAN, index);
0160 
0161     if (data & TM2_TOUCHKEY_BIT_PRESS_EV) {
0162         for (i = 0; i < touchkey->num_keycodes; i++)
0163             input_report_key(touchkey->input_dev,
0164                      touchkey->keycodes[i], 0);
0165     } else {
0166         input_report_key(touchkey->input_dev,
0167                  touchkey->keycodes[index], 1);
0168     }
0169 
0170     input_sync(touchkey->input_dev);
0171 
0172 out:
0173     if (touchkey->variant->fixed_regulator &&
0174                 data & TM2_TOUCHKEY_BIT_PRESS_EV) {
0175         /* touch turns backlight on, so make sure we're in sync */
0176         if (touchkey->led_dev.brightness == LED_OFF)
0177             tm2_touchkey_led_brightness_set(&touchkey->led_dev,
0178                             LED_OFF);
0179     }
0180 
0181     return IRQ_HANDLED;
0182 }
0183 
0184 static int tm2_touchkey_probe(struct i2c_client *client,
0185                   const struct i2c_device_id *id)
0186 {
0187     struct device_node *np = client->dev.of_node;
0188     struct tm2_touchkey_data *touchkey;
0189     int error;
0190     int i;
0191 
0192     if (!i2c_check_functionality(client->adapter,
0193             I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA)) {
0194         dev_err(&client->dev, "incompatible I2C adapter\n");
0195         return -EIO;
0196     }
0197 
0198     touchkey = devm_kzalloc(&client->dev, sizeof(*touchkey), GFP_KERNEL);
0199     if (!touchkey)
0200         return -ENOMEM;
0201 
0202     touchkey->client = client;
0203     i2c_set_clientdata(client, touchkey);
0204 
0205     touchkey->variant = of_device_get_match_data(&client->dev);
0206 
0207     touchkey->regulators[0].supply = "vcc";
0208     touchkey->regulators[1].supply = "vdd";
0209     touchkey->regulators[2].supply = "vddio";
0210     error = devm_regulator_bulk_get(&client->dev,
0211                     ARRAY_SIZE(touchkey->regulators),
0212                     touchkey->regulators);
0213     if (error) {
0214         dev_err(&client->dev, "failed to get regulators: %d\n", error);
0215         return error;
0216     }
0217 
0218     /* Save VDD for easy access */
0219     touchkey->vdd = touchkey->regulators[1].consumer;
0220 
0221     touchkey->num_keycodes = of_property_read_variable_u32_array(np,
0222                     "linux,keycodes", touchkey->keycodes, 0,
0223                     ARRAY_SIZE(touchkey->keycodes));
0224     if (touchkey->num_keycodes <= 0) {
0225         /* default keycodes */
0226         touchkey->keycodes[0] = KEY_PHONE;
0227         touchkey->keycodes[1] = KEY_BACK;
0228         touchkey->num_keycodes = 2;
0229     }
0230 
0231     error = tm2_touchkey_power_enable(touchkey);
0232     if (error) {
0233         dev_err(&client->dev, "failed to power up device: %d\n", error);
0234         return error;
0235     }
0236 
0237     error = devm_add_action_or_reset(&client->dev,
0238                      tm2_touchkey_power_disable, touchkey);
0239     if (error) {
0240         dev_err(&client->dev,
0241             "failed to install poweroff handler: %d\n", error);
0242         return error;
0243     }
0244 
0245     /* input device */
0246     touchkey->input_dev = devm_input_allocate_device(&client->dev);
0247     if (!touchkey->input_dev) {
0248         dev_err(&client->dev, "failed to allocate input device\n");
0249         return -ENOMEM;
0250     }
0251 
0252     touchkey->input_dev->name = TM2_TOUCHKEY_DEV_NAME;
0253     touchkey->input_dev->id.bustype = BUS_I2C;
0254 
0255     touchkey->input_dev->keycode = touchkey->keycodes;
0256     touchkey->input_dev->keycodemax = touchkey->num_keycodes;
0257     touchkey->input_dev->keycodesize = sizeof(touchkey->keycodes[0]);
0258 
0259     input_set_capability(touchkey->input_dev, EV_MSC, MSC_SCAN);
0260     for (i = 0; i < touchkey->num_keycodes; i++)
0261         input_set_capability(touchkey->input_dev, EV_KEY,
0262                      touchkey->keycodes[i]);
0263 
0264     error = input_register_device(touchkey->input_dev);
0265     if (error) {
0266         dev_err(&client->dev,
0267             "failed to register input device: %d\n", error);
0268         return error;
0269     }
0270 
0271     error = devm_request_threaded_irq(&client->dev, client->irq,
0272                       NULL, tm2_touchkey_irq_handler,
0273                       IRQF_ONESHOT,
0274                       TM2_TOUCHKEY_DEV_NAME, touchkey);
0275     if (error) {
0276         dev_err(&client->dev,
0277             "failed to request threaded irq: %d\n", error);
0278         return error;
0279     }
0280 
0281     /* led device */
0282     touchkey->led_dev.name = TM2_TOUCHKEY_DEV_NAME;
0283     touchkey->led_dev.brightness = LED_ON;
0284     touchkey->led_dev.max_brightness = LED_ON;
0285     touchkey->led_dev.brightness_set_blocking =
0286                     tm2_touchkey_led_brightness_set;
0287 
0288     error = devm_led_classdev_register(&client->dev, &touchkey->led_dev);
0289     if (error) {
0290         dev_err(&client->dev,
0291             "failed to register touchkey led: %d\n", error);
0292         return error;
0293     }
0294 
0295     if (touchkey->variant->fixed_regulator)
0296         tm2_touchkey_led_brightness_set(&touchkey->led_dev, LED_ON);
0297 
0298     return 0;
0299 }
0300 
0301 static int __maybe_unused tm2_touchkey_suspend(struct device *dev)
0302 {
0303     struct i2c_client *client = to_i2c_client(dev);
0304     struct tm2_touchkey_data *touchkey = i2c_get_clientdata(client);
0305 
0306     disable_irq(client->irq);
0307     tm2_touchkey_power_disable(touchkey);
0308 
0309     return 0;
0310 }
0311 
0312 static int __maybe_unused tm2_touchkey_resume(struct device *dev)
0313 {
0314     struct i2c_client *client = to_i2c_client(dev);
0315     struct tm2_touchkey_data *touchkey = i2c_get_clientdata(client);
0316     int ret;
0317 
0318     enable_irq(client->irq);
0319 
0320     ret = tm2_touchkey_power_enable(touchkey);
0321     if (ret)
0322         dev_err(dev, "failed to enable power: %d\n", ret);
0323 
0324     return ret;
0325 }
0326 
0327 static SIMPLE_DEV_PM_OPS(tm2_touchkey_pm_ops,
0328              tm2_touchkey_suspend, tm2_touchkey_resume);
0329 
0330 static const struct i2c_device_id tm2_touchkey_id_table[] = {
0331     { TM2_TOUCHKEY_DEV_NAME, 0 },
0332     { },
0333 };
0334 MODULE_DEVICE_TABLE(i2c, tm2_touchkey_id_table);
0335 
0336 static const struct of_device_id tm2_touchkey_of_match[] = {
0337     {
0338         .compatible = "cypress,tm2-touchkey",
0339         .data = &tm2_touchkey_variant,
0340     }, {
0341         .compatible = "cypress,midas-touchkey",
0342         .data = &midas_touchkey_variant,
0343     }, {
0344         .compatible = "cypress,aries-touchkey",
0345         .data = &aries_touchkey_variant,
0346     }, {
0347         .compatible = "coreriver,tc360-touchkey",
0348         .data = &tc360_touchkey_variant,
0349     },
0350     { },
0351 };
0352 MODULE_DEVICE_TABLE(of, tm2_touchkey_of_match);
0353 
0354 static struct i2c_driver tm2_touchkey_driver = {
0355     .driver = {
0356         .name = TM2_TOUCHKEY_DEV_NAME,
0357         .pm = &tm2_touchkey_pm_ops,
0358         .of_match_table = of_match_ptr(tm2_touchkey_of_match),
0359     },
0360     .probe = tm2_touchkey_probe,
0361     .id_table = tm2_touchkey_id_table,
0362 };
0363 module_i2c_driver(tm2_touchkey_driver);
0364 
0365 MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>");
0366 MODULE_AUTHOR("Jaechul Lee <jcsing.lee@samsung.com>");
0367 MODULE_DESCRIPTION("Samsung touchkey driver");
0368 MODULE_LICENSE("GPL v2");