11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
24d10da13SDan Murphy /*
34d10da13SDan Murphy * DRV2665 haptics driver family
44d10da13SDan Murphy *
54d10da13SDan Murphy * Author: Dan Murphy <dmurphy@ti.com>
64d10da13SDan Murphy *
74d10da13SDan Murphy * Copyright: (C) 2015 Texas Instruments, Inc.
84d10da13SDan Murphy */
94d10da13SDan Murphy
104d10da13SDan Murphy #include <linux/i2c.h>
114d10da13SDan Murphy #include <linux/input.h>
124d10da13SDan Murphy #include <linux/module.h>
134d10da13SDan Murphy #include <linux/regmap.h>
144d10da13SDan Murphy #include <linux/slab.h>
154d10da13SDan Murphy #include <linux/delay.h>
164d10da13SDan Murphy #include <linux/regulator/consumer.h>
174d10da13SDan Murphy
184d10da13SDan Murphy /* Contol registers */
194d10da13SDan Murphy #define DRV2665_STATUS 0x00
204d10da13SDan Murphy #define DRV2665_CTRL_1 0x01
214d10da13SDan Murphy #define DRV2665_CTRL_2 0x02
224d10da13SDan Murphy #define DRV2665_FIFO 0x0b
234d10da13SDan Murphy
244d10da13SDan Murphy /* Status Register */
254d10da13SDan Murphy #define DRV2665_FIFO_FULL BIT(0)
264d10da13SDan Murphy #define DRV2665_FIFO_EMPTY BIT(1)
274d10da13SDan Murphy
284d10da13SDan Murphy /* Control 1 Register */
294d10da13SDan Murphy #define DRV2665_25_VPP_GAIN 0x00
304d10da13SDan Murphy #define DRV2665_50_VPP_GAIN 0x01
314d10da13SDan Murphy #define DRV2665_75_VPP_GAIN 0x02
324d10da13SDan Murphy #define DRV2665_100_VPP_GAIN 0x03
334d10da13SDan Murphy #define DRV2665_DIGITAL_IN 0xfc
344d10da13SDan Murphy #define DRV2665_ANALOG_IN BIT(2)
354d10da13SDan Murphy
364d10da13SDan Murphy /* Control 2 Register */
374d10da13SDan Murphy #define DRV2665_BOOST_EN BIT(1)
384d10da13SDan Murphy #define DRV2665_STANDBY BIT(6)
394d10da13SDan Murphy #define DRV2665_DEV_RST BIT(7)
404d10da13SDan Murphy #define DRV2665_5_MS_IDLE_TOUT 0x00
414d10da13SDan Murphy #define DRV2665_10_MS_IDLE_TOUT 0x04
424d10da13SDan Murphy #define DRV2665_15_MS_IDLE_TOUT 0x08
434d10da13SDan Murphy #define DRV2665_20_MS_IDLE_TOUT 0x0c
444d10da13SDan Murphy
454d10da13SDan Murphy /**
464d10da13SDan Murphy * struct drv2665_data -
476e9c6fcbSLee Jones * @input_dev: Pointer to the input device
486e9c6fcbSLee Jones * @client: Pointer to the I2C client
496e9c6fcbSLee Jones * @regmap: Register map of the device
506e9c6fcbSLee Jones * @work: Work item used to off load the enable/disable of the vibration
516e9c6fcbSLee Jones * @regulator: Pointer to the regulator for the IC
524d10da13SDan Murphy */
534d10da13SDan Murphy struct drv2665_data {
544d10da13SDan Murphy struct input_dev *input_dev;
554d10da13SDan Murphy struct i2c_client *client;
564d10da13SDan Murphy struct regmap *regmap;
574d10da13SDan Murphy struct work_struct work;
584d10da13SDan Murphy struct regulator *regulator;
594d10da13SDan Murphy };
604d10da13SDan Murphy
614d10da13SDan Murphy /* 8kHz Sine wave to stream to the FIFO */
624d10da13SDan Murphy static const u8 drv2665_sine_wave_form[] = {
634d10da13SDan Murphy 0x00, 0x10, 0x20, 0x2e, 0x3c, 0x48, 0x53, 0x5b, 0x61, 0x65, 0x66,
644d10da13SDan Murphy 0x65, 0x61, 0x5b, 0x53, 0x48, 0x3c, 0x2e, 0x20, 0x10,
654d10da13SDan Murphy 0x00, 0xf0, 0xe0, 0xd2, 0xc4, 0xb8, 0xad, 0xa5, 0x9f, 0x9b, 0x9a,
664d10da13SDan Murphy 0x9b, 0x9f, 0xa5, 0xad, 0xb8, 0xc4, 0xd2, 0xe0, 0xf0, 0x00,
674d10da13SDan Murphy };
684d10da13SDan Murphy
69ec0843faSAxel Lin static const struct reg_default drv2665_reg_defs[] = {
704d10da13SDan Murphy { DRV2665_STATUS, 0x02 },
714d10da13SDan Murphy { DRV2665_CTRL_1, 0x28 },
724d10da13SDan Murphy { DRV2665_CTRL_2, 0x40 },
734d10da13SDan Murphy { DRV2665_FIFO, 0x00 },
744d10da13SDan Murphy };
754d10da13SDan Murphy
drv2665_worker(struct work_struct * work)764d10da13SDan Murphy static void drv2665_worker(struct work_struct *work)
774d10da13SDan Murphy {
784d10da13SDan Murphy struct drv2665_data *haptics =
794d10da13SDan Murphy container_of(work, struct drv2665_data, work);
804d10da13SDan Murphy unsigned int read_buf;
814d10da13SDan Murphy int error;
824d10da13SDan Murphy
834d10da13SDan Murphy error = regmap_read(haptics->regmap, DRV2665_STATUS, &read_buf);
844d10da13SDan Murphy if (error) {
854d10da13SDan Murphy dev_err(&haptics->client->dev,
864d10da13SDan Murphy "Failed to read status: %d\n", error);
874d10da13SDan Murphy return;
884d10da13SDan Murphy }
894d10da13SDan Murphy
904d10da13SDan Murphy if (read_buf & DRV2665_FIFO_EMPTY) {
914d10da13SDan Murphy error = regmap_bulk_write(haptics->regmap,
924d10da13SDan Murphy DRV2665_FIFO,
934d10da13SDan Murphy drv2665_sine_wave_form,
944d10da13SDan Murphy ARRAY_SIZE(drv2665_sine_wave_form));
954d10da13SDan Murphy if (error) {
964d10da13SDan Murphy dev_err(&haptics->client->dev,
974d10da13SDan Murphy "Failed to write FIFO: %d\n", error);
984d10da13SDan Murphy return;
994d10da13SDan Murphy }
1004d10da13SDan Murphy }
1014d10da13SDan Murphy }
1024d10da13SDan Murphy
drv2665_haptics_play(struct input_dev * input,void * data,struct ff_effect * effect)1034d10da13SDan Murphy static int drv2665_haptics_play(struct input_dev *input, void *data,
1044d10da13SDan Murphy struct ff_effect *effect)
1054d10da13SDan Murphy {
1064d10da13SDan Murphy struct drv2665_data *haptics = input_get_drvdata(input);
1074d10da13SDan Murphy
1084d10da13SDan Murphy schedule_work(&haptics->work);
1094d10da13SDan Murphy
1104d10da13SDan Murphy return 0;
1114d10da13SDan Murphy }
1124d10da13SDan Murphy
drv2665_close(struct input_dev * input)1134d10da13SDan Murphy static void drv2665_close(struct input_dev *input)
1144d10da13SDan Murphy {
1154d10da13SDan Murphy struct drv2665_data *haptics = input_get_drvdata(input);
1164d10da13SDan Murphy int error;
1174d10da13SDan Murphy
1184d10da13SDan Murphy cancel_work_sync(&haptics->work);
1194d10da13SDan Murphy
120037b3af6SFlorian Vaussard error = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
121037b3af6SFlorian Vaussard DRV2665_STANDBY, DRV2665_STANDBY);
1224d10da13SDan Murphy if (error)
1234d10da13SDan Murphy dev_err(&haptics->client->dev,
1244d10da13SDan Murphy "Failed to enter standby mode: %d\n", error);
1254d10da13SDan Murphy }
1264d10da13SDan Murphy
1278019ff6cSNariman Poushin static const struct reg_sequence drv2665_init_regs[] = {
1284d10da13SDan Murphy { DRV2665_CTRL_2, 0 | DRV2665_10_MS_IDLE_TOUT },
1294d10da13SDan Murphy { DRV2665_CTRL_1, DRV2665_25_VPP_GAIN },
1304d10da13SDan Murphy };
1314d10da13SDan Murphy
drv2665_init(struct drv2665_data * haptics)1324d10da13SDan Murphy static int drv2665_init(struct drv2665_data *haptics)
1334d10da13SDan Murphy {
1344d10da13SDan Murphy int error;
1354d10da13SDan Murphy
1364d10da13SDan Murphy error = regmap_register_patch(haptics->regmap,
1374d10da13SDan Murphy drv2665_init_regs,
1384d10da13SDan Murphy ARRAY_SIZE(drv2665_init_regs));
1394d10da13SDan Murphy if (error) {
1404d10da13SDan Murphy dev_err(&haptics->client->dev,
1414d10da13SDan Murphy "Failed to write init registers: %d\n",
1424d10da13SDan Murphy error);
1434d10da13SDan Murphy return error;
1444d10da13SDan Murphy }
1454d10da13SDan Murphy
1464d10da13SDan Murphy return 0;
1474d10da13SDan Murphy }
1484d10da13SDan Murphy
1494d10da13SDan Murphy static const struct regmap_config drv2665_regmap_config = {
1504d10da13SDan Murphy .reg_bits = 8,
1514d10da13SDan Murphy .val_bits = 8,
1524d10da13SDan Murphy
1534d10da13SDan Murphy .max_register = DRV2665_FIFO,
1544d10da13SDan Murphy .reg_defaults = drv2665_reg_defs,
1554d10da13SDan Murphy .num_reg_defaults = ARRAY_SIZE(drv2665_reg_defs),
1564d10da13SDan Murphy .cache_type = REGCACHE_NONE,
1574d10da13SDan Murphy };
1584d10da13SDan Murphy
drv2665_probe(struct i2c_client * client)159110c0a46SUwe Kleine-König static int drv2665_probe(struct i2c_client *client)
1604d10da13SDan Murphy {
1614d10da13SDan Murphy struct drv2665_data *haptics;
1624d10da13SDan Murphy int error;
1634d10da13SDan Murphy
1644d10da13SDan Murphy haptics = devm_kzalloc(&client->dev, sizeof(*haptics), GFP_KERNEL);
1654d10da13SDan Murphy if (!haptics)
1664d10da13SDan Murphy return -ENOMEM;
1674d10da13SDan Murphy
1684d10da13SDan Murphy haptics->regulator = devm_regulator_get(&client->dev, "vbat");
1694d10da13SDan Murphy if (IS_ERR(haptics->regulator)) {
1704d10da13SDan Murphy error = PTR_ERR(haptics->regulator);
1714d10da13SDan Murphy dev_err(&client->dev,
1724d10da13SDan Murphy "unable to get regulator, error: %d\n", error);
1734d10da13SDan Murphy return error;
1744d10da13SDan Murphy }
1754d10da13SDan Murphy
1764d10da13SDan Murphy haptics->input_dev = devm_input_allocate_device(&client->dev);
1774d10da13SDan Murphy if (!haptics->input_dev) {
1784d10da13SDan Murphy dev_err(&client->dev, "Failed to allocate input device\n");
1794d10da13SDan Murphy return -ENOMEM;
1804d10da13SDan Murphy }
1814d10da13SDan Murphy
1824d10da13SDan Murphy haptics->input_dev->name = "drv2665:haptics";
1834d10da13SDan Murphy haptics->input_dev->dev.parent = client->dev.parent;
1844d10da13SDan Murphy haptics->input_dev->close = drv2665_close;
1854d10da13SDan Murphy input_set_drvdata(haptics->input_dev, haptics);
1864d10da13SDan Murphy input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE);
1874d10da13SDan Murphy
1884d10da13SDan Murphy error = input_ff_create_memless(haptics->input_dev, NULL,
1894d10da13SDan Murphy drv2665_haptics_play);
1904d10da13SDan Murphy if (error) {
1914d10da13SDan Murphy dev_err(&client->dev, "input_ff_create() failed: %d\n",
1924d10da13SDan Murphy error);
1934d10da13SDan Murphy return error;
1944d10da13SDan Murphy }
1954d10da13SDan Murphy
1964d10da13SDan Murphy INIT_WORK(&haptics->work, drv2665_worker);
1974d10da13SDan Murphy
1984d10da13SDan Murphy haptics->client = client;
1994d10da13SDan Murphy i2c_set_clientdata(client, haptics);
2004d10da13SDan Murphy
2014d10da13SDan Murphy haptics->regmap = devm_regmap_init_i2c(client, &drv2665_regmap_config);
2024d10da13SDan Murphy if (IS_ERR(haptics->regmap)) {
2034d10da13SDan Murphy error = PTR_ERR(haptics->regmap);
2044d10da13SDan Murphy dev_err(&client->dev, "Failed to allocate register map: %d\n",
2054d10da13SDan Murphy error);
2064d10da13SDan Murphy return error;
2074d10da13SDan Murphy }
2084d10da13SDan Murphy
2094d10da13SDan Murphy error = drv2665_init(haptics);
2104d10da13SDan Murphy if (error) {
2114d10da13SDan Murphy dev_err(&client->dev, "Device init failed: %d\n", error);
2124d10da13SDan Murphy return error;
2134d10da13SDan Murphy }
2144d10da13SDan Murphy
2154d10da13SDan Murphy error = input_register_device(haptics->input_dev);
2164d10da13SDan Murphy if (error) {
2174d10da13SDan Murphy dev_err(&client->dev, "couldn't register input device: %d\n",
2184d10da13SDan Murphy error);
2194d10da13SDan Murphy return error;
2204d10da13SDan Murphy }
2214d10da13SDan Murphy
2224d10da13SDan Murphy return 0;
2234d10da13SDan Murphy }
2244d10da13SDan Murphy
drv2665_suspend(struct device * dev)225c7cd0194SJonathan Cameron static int drv2665_suspend(struct device *dev)
2264d10da13SDan Murphy {
2274d10da13SDan Murphy struct drv2665_data *haptics = dev_get_drvdata(dev);
2284d10da13SDan Murphy int ret = 0;
2294d10da13SDan Murphy
2304d10da13SDan Murphy mutex_lock(&haptics->input_dev->mutex);
2314d10da13SDan Murphy
232d69f0a43SAndrzej Pietrasiewicz if (input_device_enabled(haptics->input_dev)) {
2334d10da13SDan Murphy ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
234037b3af6SFlorian Vaussard DRV2665_STANDBY, DRV2665_STANDBY);
2354d10da13SDan Murphy if (ret) {
2364d10da13SDan Murphy dev_err(dev, "Failed to set standby mode\n");
2374d10da13SDan Murphy regulator_disable(haptics->regulator);
2384d10da13SDan Murphy goto out;
2394d10da13SDan Murphy }
2404d10da13SDan Murphy
2414d10da13SDan Murphy ret = regulator_disable(haptics->regulator);
2424d10da13SDan Murphy if (ret) {
2434d10da13SDan Murphy dev_err(dev, "Failed to disable regulator\n");
2444d10da13SDan Murphy regmap_update_bits(haptics->regmap,
2454d10da13SDan Murphy DRV2665_CTRL_2,
2464d10da13SDan Murphy DRV2665_STANDBY, 0);
2474d10da13SDan Murphy }
2484d10da13SDan Murphy }
2494d10da13SDan Murphy out:
2504d10da13SDan Murphy mutex_unlock(&haptics->input_dev->mutex);
2514d10da13SDan Murphy return ret;
2524d10da13SDan Murphy }
2534d10da13SDan Murphy
drv2665_resume(struct device * dev)254c7cd0194SJonathan Cameron static int drv2665_resume(struct device *dev)
2554d10da13SDan Murphy {
2564d10da13SDan Murphy struct drv2665_data *haptics = dev_get_drvdata(dev);
2574d10da13SDan Murphy int ret = 0;
2584d10da13SDan Murphy
2594d10da13SDan Murphy mutex_lock(&haptics->input_dev->mutex);
2604d10da13SDan Murphy
261d69f0a43SAndrzej Pietrasiewicz if (input_device_enabled(haptics->input_dev)) {
2624d10da13SDan Murphy ret = regulator_enable(haptics->regulator);
2634d10da13SDan Murphy if (ret) {
2644d10da13SDan Murphy dev_err(dev, "Failed to enable regulator\n");
2654d10da13SDan Murphy goto out;
2664d10da13SDan Murphy }
2674d10da13SDan Murphy
2684d10da13SDan Murphy ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
2694d10da13SDan Murphy DRV2665_STANDBY, 0);
2704d10da13SDan Murphy if (ret) {
2714d10da13SDan Murphy dev_err(dev, "Failed to unset standby mode\n");
2724d10da13SDan Murphy regulator_disable(haptics->regulator);
2734d10da13SDan Murphy goto out;
2744d10da13SDan Murphy }
2754d10da13SDan Murphy
2764d10da13SDan Murphy }
2774d10da13SDan Murphy
2784d10da13SDan Murphy out:
2794d10da13SDan Murphy mutex_unlock(&haptics->input_dev->mutex);
2804d10da13SDan Murphy return ret;
2814d10da13SDan Murphy }
2824d10da13SDan Murphy
283c7cd0194SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(drv2665_pm_ops, drv2665_suspend, drv2665_resume);
2844d10da13SDan Murphy
2854d10da13SDan Murphy static const struct i2c_device_id drv2665_id[] = {
2864d10da13SDan Murphy { "drv2665", 0 },
2874d10da13SDan Murphy { }
2884d10da13SDan Murphy };
2894d10da13SDan Murphy MODULE_DEVICE_TABLE(i2c, drv2665_id);
2904d10da13SDan Murphy
2914d10da13SDan Murphy #ifdef CONFIG_OF
2924d10da13SDan Murphy static const struct of_device_id drv2665_of_match[] = {
2934d10da13SDan Murphy { .compatible = "ti,drv2665", },
2944d10da13SDan Murphy { }
2954d10da13SDan Murphy };
2964d10da13SDan Murphy MODULE_DEVICE_TABLE(of, drv2665_of_match);
2974d10da13SDan Murphy #endif
2984d10da13SDan Murphy
2994d10da13SDan Murphy static struct i2c_driver drv2665_driver = {
300*d8bde56dSUwe Kleine-König .probe = drv2665_probe,
3014d10da13SDan Murphy .driver = {
3024d10da13SDan Murphy .name = "drv2665-haptics",
3034d10da13SDan Murphy .of_match_table = of_match_ptr(drv2665_of_match),
304c7cd0194SJonathan Cameron .pm = pm_sleep_ptr(&drv2665_pm_ops),
3054d10da13SDan Murphy },
3064d10da13SDan Murphy .id_table = drv2665_id,
3074d10da13SDan Murphy };
3084d10da13SDan Murphy module_i2c_driver(drv2665_driver);
3094d10da13SDan Murphy
3104d10da13SDan Murphy MODULE_DESCRIPTION("TI DRV2665 haptics driver");
3114d10da13SDan Murphy MODULE_LICENSE("GPL");
3124d10da13SDan Murphy MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
313