18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * DRV2665 haptics driver family 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Dan Murphy <dmurphy@ti.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright: (C) 2015 Texas Instruments, Inc. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/i2c.h> 118c2ecf20Sopenharmony_ci#include <linux/input.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/regmap.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/delay.h> 168c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* Contol registers */ 198c2ecf20Sopenharmony_ci#define DRV2665_STATUS 0x00 208c2ecf20Sopenharmony_ci#define DRV2665_CTRL_1 0x01 218c2ecf20Sopenharmony_ci#define DRV2665_CTRL_2 0x02 228c2ecf20Sopenharmony_ci#define DRV2665_FIFO 0x0b 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* Status Register */ 258c2ecf20Sopenharmony_ci#define DRV2665_FIFO_FULL BIT(0) 268c2ecf20Sopenharmony_ci#define DRV2665_FIFO_EMPTY BIT(1) 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* Control 1 Register */ 298c2ecf20Sopenharmony_ci#define DRV2665_25_VPP_GAIN 0x00 308c2ecf20Sopenharmony_ci#define DRV2665_50_VPP_GAIN 0x01 318c2ecf20Sopenharmony_ci#define DRV2665_75_VPP_GAIN 0x02 328c2ecf20Sopenharmony_ci#define DRV2665_100_VPP_GAIN 0x03 338c2ecf20Sopenharmony_ci#define DRV2665_DIGITAL_IN 0xfc 348c2ecf20Sopenharmony_ci#define DRV2665_ANALOG_IN BIT(2) 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* Control 2 Register */ 378c2ecf20Sopenharmony_ci#define DRV2665_BOOST_EN BIT(1) 388c2ecf20Sopenharmony_ci#define DRV2665_STANDBY BIT(6) 398c2ecf20Sopenharmony_ci#define DRV2665_DEV_RST BIT(7) 408c2ecf20Sopenharmony_ci#define DRV2665_5_MS_IDLE_TOUT 0x00 418c2ecf20Sopenharmony_ci#define DRV2665_10_MS_IDLE_TOUT 0x04 428c2ecf20Sopenharmony_ci#define DRV2665_15_MS_IDLE_TOUT 0x08 438c2ecf20Sopenharmony_ci#define DRV2665_20_MS_IDLE_TOUT 0x0c 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/** 468c2ecf20Sopenharmony_ci * struct drv2665_data - 478c2ecf20Sopenharmony_ci * @input_dev - Pointer to the input device 488c2ecf20Sopenharmony_ci * @client - Pointer to the I2C client 498c2ecf20Sopenharmony_ci * @regmap - Register map of the device 508c2ecf20Sopenharmony_ci * @work - Work item used to off load the enable/disable of the vibration 518c2ecf20Sopenharmony_ci * @regulator - Pointer to the regulator for the IC 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_cistruct drv2665_data { 548c2ecf20Sopenharmony_ci struct input_dev *input_dev; 558c2ecf20Sopenharmony_ci struct i2c_client *client; 568c2ecf20Sopenharmony_ci struct regmap *regmap; 578c2ecf20Sopenharmony_ci struct work_struct work; 588c2ecf20Sopenharmony_ci struct regulator *regulator; 598c2ecf20Sopenharmony_ci}; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* 8kHz Sine wave to stream to the FIFO */ 628c2ecf20Sopenharmony_cistatic const u8 drv2665_sine_wave_form[] = { 638c2ecf20Sopenharmony_ci 0x00, 0x10, 0x20, 0x2e, 0x3c, 0x48, 0x53, 0x5b, 0x61, 0x65, 0x66, 648c2ecf20Sopenharmony_ci 0x65, 0x61, 0x5b, 0x53, 0x48, 0x3c, 0x2e, 0x20, 0x10, 658c2ecf20Sopenharmony_ci 0x00, 0xf0, 0xe0, 0xd2, 0xc4, 0xb8, 0xad, 0xa5, 0x9f, 0x9b, 0x9a, 668c2ecf20Sopenharmony_ci 0x9b, 0x9f, 0xa5, 0xad, 0xb8, 0xc4, 0xd2, 0xe0, 0xf0, 0x00, 678c2ecf20Sopenharmony_ci}; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic const struct reg_default drv2665_reg_defs[] = { 708c2ecf20Sopenharmony_ci { DRV2665_STATUS, 0x02 }, 718c2ecf20Sopenharmony_ci { DRV2665_CTRL_1, 0x28 }, 728c2ecf20Sopenharmony_ci { DRV2665_CTRL_2, 0x40 }, 738c2ecf20Sopenharmony_ci { DRV2665_FIFO, 0x00 }, 748c2ecf20Sopenharmony_ci}; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic void drv2665_worker(struct work_struct *work) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci struct drv2665_data *haptics = 798c2ecf20Sopenharmony_ci container_of(work, struct drv2665_data, work); 808c2ecf20Sopenharmony_ci unsigned int read_buf; 818c2ecf20Sopenharmony_ci int error; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci error = regmap_read(haptics->regmap, DRV2665_STATUS, &read_buf); 848c2ecf20Sopenharmony_ci if (error) { 858c2ecf20Sopenharmony_ci dev_err(&haptics->client->dev, 868c2ecf20Sopenharmony_ci "Failed to read status: %d\n", error); 878c2ecf20Sopenharmony_ci return; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (read_buf & DRV2665_FIFO_EMPTY) { 918c2ecf20Sopenharmony_ci error = regmap_bulk_write(haptics->regmap, 928c2ecf20Sopenharmony_ci DRV2665_FIFO, 938c2ecf20Sopenharmony_ci drv2665_sine_wave_form, 948c2ecf20Sopenharmony_ci ARRAY_SIZE(drv2665_sine_wave_form)); 958c2ecf20Sopenharmony_ci if (error) { 968c2ecf20Sopenharmony_ci dev_err(&haptics->client->dev, 978c2ecf20Sopenharmony_ci "Failed to write FIFO: %d\n", error); 988c2ecf20Sopenharmony_ci return; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic int drv2665_haptics_play(struct input_dev *input, void *data, 1048c2ecf20Sopenharmony_ci struct ff_effect *effect) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci struct drv2665_data *haptics = input_get_drvdata(input); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci schedule_work(&haptics->work); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci return 0; 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic void drv2665_close(struct input_dev *input) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci struct drv2665_data *haptics = input_get_drvdata(input); 1168c2ecf20Sopenharmony_ci int error; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci cancel_work_sync(&haptics->work); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci error = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2, 1218c2ecf20Sopenharmony_ci DRV2665_STANDBY, DRV2665_STANDBY); 1228c2ecf20Sopenharmony_ci if (error) 1238c2ecf20Sopenharmony_ci dev_err(&haptics->client->dev, 1248c2ecf20Sopenharmony_ci "Failed to enter standby mode: %d\n", error); 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic const struct reg_sequence drv2665_init_regs[] = { 1288c2ecf20Sopenharmony_ci { DRV2665_CTRL_2, 0 | DRV2665_10_MS_IDLE_TOUT }, 1298c2ecf20Sopenharmony_ci { DRV2665_CTRL_1, DRV2665_25_VPP_GAIN }, 1308c2ecf20Sopenharmony_ci}; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic int drv2665_init(struct drv2665_data *haptics) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci int error; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci error = regmap_register_patch(haptics->regmap, 1378c2ecf20Sopenharmony_ci drv2665_init_regs, 1388c2ecf20Sopenharmony_ci ARRAY_SIZE(drv2665_init_regs)); 1398c2ecf20Sopenharmony_ci if (error) { 1408c2ecf20Sopenharmony_ci dev_err(&haptics->client->dev, 1418c2ecf20Sopenharmony_ci "Failed to write init registers: %d\n", 1428c2ecf20Sopenharmony_ci error); 1438c2ecf20Sopenharmony_ci return error; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci return 0; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic const struct regmap_config drv2665_regmap_config = { 1508c2ecf20Sopenharmony_ci .reg_bits = 8, 1518c2ecf20Sopenharmony_ci .val_bits = 8, 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci .max_register = DRV2665_FIFO, 1548c2ecf20Sopenharmony_ci .reg_defaults = drv2665_reg_defs, 1558c2ecf20Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(drv2665_reg_defs), 1568c2ecf20Sopenharmony_ci .cache_type = REGCACHE_NONE, 1578c2ecf20Sopenharmony_ci}; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_cistatic int drv2665_probe(struct i2c_client *client, 1608c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci struct drv2665_data *haptics; 1638c2ecf20Sopenharmony_ci int error; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci haptics = devm_kzalloc(&client->dev, sizeof(*haptics), GFP_KERNEL); 1668c2ecf20Sopenharmony_ci if (!haptics) 1678c2ecf20Sopenharmony_ci return -ENOMEM; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci haptics->regulator = devm_regulator_get(&client->dev, "vbat"); 1708c2ecf20Sopenharmony_ci if (IS_ERR(haptics->regulator)) { 1718c2ecf20Sopenharmony_ci error = PTR_ERR(haptics->regulator); 1728c2ecf20Sopenharmony_ci dev_err(&client->dev, 1738c2ecf20Sopenharmony_ci "unable to get regulator, error: %d\n", error); 1748c2ecf20Sopenharmony_ci return error; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci haptics->input_dev = devm_input_allocate_device(&client->dev); 1788c2ecf20Sopenharmony_ci if (!haptics->input_dev) { 1798c2ecf20Sopenharmony_ci dev_err(&client->dev, "Failed to allocate input device\n"); 1808c2ecf20Sopenharmony_ci return -ENOMEM; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci haptics->input_dev->name = "drv2665:haptics"; 1848c2ecf20Sopenharmony_ci haptics->input_dev->dev.parent = client->dev.parent; 1858c2ecf20Sopenharmony_ci haptics->input_dev->close = drv2665_close; 1868c2ecf20Sopenharmony_ci input_set_drvdata(haptics->input_dev, haptics); 1878c2ecf20Sopenharmony_ci input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci error = input_ff_create_memless(haptics->input_dev, NULL, 1908c2ecf20Sopenharmony_ci drv2665_haptics_play); 1918c2ecf20Sopenharmony_ci if (error) { 1928c2ecf20Sopenharmony_ci dev_err(&client->dev, "input_ff_create() failed: %d\n", 1938c2ecf20Sopenharmony_ci error); 1948c2ecf20Sopenharmony_ci return error; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci INIT_WORK(&haptics->work, drv2665_worker); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci haptics->client = client; 2008c2ecf20Sopenharmony_ci i2c_set_clientdata(client, haptics); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci haptics->regmap = devm_regmap_init_i2c(client, &drv2665_regmap_config); 2038c2ecf20Sopenharmony_ci if (IS_ERR(haptics->regmap)) { 2048c2ecf20Sopenharmony_ci error = PTR_ERR(haptics->regmap); 2058c2ecf20Sopenharmony_ci dev_err(&client->dev, "Failed to allocate register map: %d\n", 2068c2ecf20Sopenharmony_ci error); 2078c2ecf20Sopenharmony_ci return error; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci error = drv2665_init(haptics); 2118c2ecf20Sopenharmony_ci if (error) { 2128c2ecf20Sopenharmony_ci dev_err(&client->dev, "Device init failed: %d\n", error); 2138c2ecf20Sopenharmony_ci return error; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci error = input_register_device(haptics->input_dev); 2178c2ecf20Sopenharmony_ci if (error) { 2188c2ecf20Sopenharmony_ci dev_err(&client->dev, "couldn't register input device: %d\n", 2198c2ecf20Sopenharmony_ci error); 2208c2ecf20Sopenharmony_ci return error; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci return 0; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic int __maybe_unused drv2665_suspend(struct device *dev) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct drv2665_data *haptics = dev_get_drvdata(dev); 2298c2ecf20Sopenharmony_ci int ret = 0; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci mutex_lock(&haptics->input_dev->mutex); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci if (haptics->input_dev->users) { 2348c2ecf20Sopenharmony_ci ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2, 2358c2ecf20Sopenharmony_ci DRV2665_STANDBY, DRV2665_STANDBY); 2368c2ecf20Sopenharmony_ci if (ret) { 2378c2ecf20Sopenharmony_ci dev_err(dev, "Failed to set standby mode\n"); 2388c2ecf20Sopenharmony_ci regulator_disable(haptics->regulator); 2398c2ecf20Sopenharmony_ci goto out; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci ret = regulator_disable(haptics->regulator); 2438c2ecf20Sopenharmony_ci if (ret) { 2448c2ecf20Sopenharmony_ci dev_err(dev, "Failed to disable regulator\n"); 2458c2ecf20Sopenharmony_ci regmap_update_bits(haptics->regmap, 2468c2ecf20Sopenharmony_ci DRV2665_CTRL_2, 2478c2ecf20Sopenharmony_ci DRV2665_STANDBY, 0); 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ciout: 2518c2ecf20Sopenharmony_ci mutex_unlock(&haptics->input_dev->mutex); 2528c2ecf20Sopenharmony_ci return ret; 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic int __maybe_unused drv2665_resume(struct device *dev) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci struct drv2665_data *haptics = dev_get_drvdata(dev); 2588c2ecf20Sopenharmony_ci int ret = 0; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci mutex_lock(&haptics->input_dev->mutex); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (haptics->input_dev->users) { 2638c2ecf20Sopenharmony_ci ret = regulator_enable(haptics->regulator); 2648c2ecf20Sopenharmony_ci if (ret) { 2658c2ecf20Sopenharmony_ci dev_err(dev, "Failed to enable regulator\n"); 2668c2ecf20Sopenharmony_ci goto out; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2, 2708c2ecf20Sopenharmony_ci DRV2665_STANDBY, 0); 2718c2ecf20Sopenharmony_ci if (ret) { 2728c2ecf20Sopenharmony_ci dev_err(dev, "Failed to unset standby mode\n"); 2738c2ecf20Sopenharmony_ci regulator_disable(haptics->regulator); 2748c2ecf20Sopenharmony_ci goto out; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ciout: 2808c2ecf20Sopenharmony_ci mutex_unlock(&haptics->input_dev->mutex); 2818c2ecf20Sopenharmony_ci return ret; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(drv2665_pm_ops, drv2665_suspend, drv2665_resume); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic const struct i2c_device_id drv2665_id[] = { 2878c2ecf20Sopenharmony_ci { "drv2665", 0 }, 2888c2ecf20Sopenharmony_ci { } 2898c2ecf20Sopenharmony_ci}; 2908c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, drv2665_id); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 2938c2ecf20Sopenharmony_cistatic const struct of_device_id drv2665_of_match[] = { 2948c2ecf20Sopenharmony_ci { .compatible = "ti,drv2665", }, 2958c2ecf20Sopenharmony_ci { } 2968c2ecf20Sopenharmony_ci}; 2978c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, drv2665_of_match); 2988c2ecf20Sopenharmony_ci#endif 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic struct i2c_driver drv2665_driver = { 3018c2ecf20Sopenharmony_ci .probe = drv2665_probe, 3028c2ecf20Sopenharmony_ci .driver = { 3038c2ecf20Sopenharmony_ci .name = "drv2665-haptics", 3048c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(drv2665_of_match), 3058c2ecf20Sopenharmony_ci .pm = &drv2665_pm_ops, 3068c2ecf20Sopenharmony_ci }, 3078c2ecf20Sopenharmony_ci .id_table = drv2665_id, 3088c2ecf20Sopenharmony_ci}; 3098c2ecf20Sopenharmony_cimodule_i2c_driver(drv2665_driver); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TI DRV2665 haptics driver"); 3128c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 3138c2ecf20Sopenharmony_ciMODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); 314