11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 21c246225SDan Murphy /* 31c246225SDan Murphy * DRV2667 haptics driver family 41c246225SDan Murphy * 51c246225SDan Murphy * Author: Dan Murphy <dmurphy@ti.com> 61c246225SDan Murphy * 71c246225SDan Murphy * Copyright: (C) 2014 Texas Instruments, Inc. 81c246225SDan Murphy */ 91c246225SDan Murphy 101c246225SDan Murphy #include <linux/i2c.h> 111c246225SDan Murphy #include <linux/input.h> 121c246225SDan Murphy #include <linux/module.h> 131c246225SDan Murphy #include <linux/platform_device.h> 141c246225SDan Murphy #include <linux/regmap.h> 151c246225SDan Murphy #include <linux/slab.h> 161c246225SDan Murphy #include <linux/delay.h> 171c246225SDan Murphy #include <linux/regulator/consumer.h> 181c246225SDan Murphy 191c246225SDan Murphy /* Contol registers */ 201c246225SDan Murphy #define DRV2667_STATUS 0x00 211c246225SDan Murphy #define DRV2667_CTRL_1 0x01 221c246225SDan Murphy #define DRV2667_CTRL_2 0x02 231c246225SDan Murphy /* Waveform sequencer */ 241c246225SDan Murphy #define DRV2667_WV_SEQ_0 0x03 251c246225SDan Murphy #define DRV2667_WV_SEQ_1 0x04 261c246225SDan Murphy #define DRV2667_WV_SEQ_2 0x05 271c246225SDan Murphy #define DRV2667_WV_SEQ_3 0x06 281c246225SDan Murphy #define DRV2667_WV_SEQ_4 0x07 291c246225SDan Murphy #define DRV2667_WV_SEQ_5 0x08 301c246225SDan Murphy #define DRV2667_WV_SEQ_6 0x09 311c246225SDan Murphy #define DRV2667_WV_SEQ_7 0x0A 321c246225SDan Murphy #define DRV2667_FIFO 0x0B 331c246225SDan Murphy #define DRV2667_PAGE 0xFF 341c246225SDan Murphy #define DRV2667_MAX_REG DRV2667_PAGE 351c246225SDan Murphy 361c246225SDan Murphy #define DRV2667_PAGE_0 0x00 371c246225SDan Murphy #define DRV2667_PAGE_1 0x01 381c246225SDan Murphy #define DRV2667_PAGE_2 0x02 391c246225SDan Murphy #define DRV2667_PAGE_3 0x03 401c246225SDan Murphy #define DRV2667_PAGE_4 0x04 411c246225SDan Murphy #define DRV2667_PAGE_5 0x05 421c246225SDan Murphy #define DRV2667_PAGE_6 0x06 431c246225SDan Murphy #define DRV2667_PAGE_7 0x07 441c246225SDan Murphy #define DRV2667_PAGE_8 0x08 451c246225SDan Murphy 461c246225SDan Murphy /* RAM fields */ 471c246225SDan Murphy #define DRV2667_RAM_HDR_SZ 0x0 481c246225SDan Murphy /* RAM Header addresses */ 491c246225SDan Murphy #define DRV2667_RAM_START_HI 0x01 501c246225SDan Murphy #define DRV2667_RAM_START_LO 0x02 511c246225SDan Murphy #define DRV2667_RAM_STOP_HI 0x03 521c246225SDan Murphy #define DRV2667_RAM_STOP_LO 0x04 531c246225SDan Murphy #define DRV2667_RAM_REPEAT_CT 0x05 541c246225SDan Murphy /* RAM data addresses */ 551c246225SDan Murphy #define DRV2667_RAM_AMP 0x06 561c246225SDan Murphy #define DRV2667_RAM_FREQ 0x07 571c246225SDan Murphy #define DRV2667_RAM_DURATION 0x08 581c246225SDan Murphy #define DRV2667_RAM_ENVELOPE 0x09 591c246225SDan Murphy 601c246225SDan Murphy /* Control 1 Register */ 611c246225SDan Murphy #define DRV2667_25_VPP_GAIN 0x00 621c246225SDan Murphy #define DRV2667_50_VPP_GAIN 0x01 631c246225SDan Murphy #define DRV2667_75_VPP_GAIN 0x02 641c246225SDan Murphy #define DRV2667_100_VPP_GAIN 0x03 651c246225SDan Murphy #define DRV2667_DIGITAL_IN 0xfc 661c246225SDan Murphy #define DRV2667_ANALOG_IN (1 << 2) 671c246225SDan Murphy 681c246225SDan Murphy /* Control 2 Register */ 691c246225SDan Murphy #define DRV2667_GO (1 << 0) 701c246225SDan Murphy #define DRV2667_STANDBY (1 << 6) 711c246225SDan Murphy #define DRV2667_DEV_RST (1 << 7) 721c246225SDan Murphy 731c246225SDan Murphy /* RAM Envelope settings */ 741c246225SDan Murphy #define DRV2667_NO_ENV 0x00 751c246225SDan Murphy #define DRV2667_32_MS_ENV 0x01 761c246225SDan Murphy #define DRV2667_64_MS_ENV 0x02 771c246225SDan Murphy #define DRV2667_96_MS_ENV 0x03 781c246225SDan Murphy #define DRV2667_128_MS_ENV 0x04 791c246225SDan Murphy #define DRV2667_160_MS_ENV 0x05 801c246225SDan Murphy #define DRV2667_192_MS_ENV 0x06 811c246225SDan Murphy #define DRV2667_224_MS_ENV 0x07 821c246225SDan Murphy #define DRV2667_256_MS_ENV 0x08 831c246225SDan Murphy #define DRV2667_512_MS_ENV 0x09 841c246225SDan Murphy #define DRV2667_768_MS_ENV 0x0a 851c246225SDan Murphy #define DRV2667_1024_MS_ENV 0x0b 861c246225SDan Murphy #define DRV2667_1280_MS_ENV 0x0c 871c246225SDan Murphy #define DRV2667_1536_MS_ENV 0x0d 881c246225SDan Murphy #define DRV2667_1792_MS_ENV 0x0e 891c246225SDan Murphy #define DRV2667_2048_MS_ENV 0x0f 901c246225SDan Murphy 911c246225SDan Murphy /** 921c246225SDan Murphy * struct drv2667_data - 9317627111SLee Jones * @input_dev: Pointer to the input device 9417627111SLee Jones * @client: Pointer to the I2C client 9517627111SLee Jones * @regmap: Register map of the device 9617627111SLee Jones * @work: Work item used to off load the enable/disable of the vibration 9717627111SLee Jones * @regulator: Pointer to the regulator for the IC 9817627111SLee Jones * @page: Page number 9917627111SLee Jones * @magnitude: Magnitude of the vibration event 10017627111SLee Jones * @frequency: Frequency of the vibration event 1011c246225SDan Murphy **/ 1021c246225SDan Murphy struct drv2667_data { 1031c246225SDan Murphy struct input_dev *input_dev; 1041c246225SDan Murphy struct i2c_client *client; 1051c246225SDan Murphy struct regmap *regmap; 1061c246225SDan Murphy struct work_struct work; 1071c246225SDan Murphy struct regulator *regulator; 1081c246225SDan Murphy u32 page; 1091c246225SDan Murphy u32 magnitude; 1101c246225SDan Murphy u32 frequency; 1111c246225SDan Murphy }; 1121c246225SDan Murphy 113ec0843faSAxel Lin static const struct reg_default drv2667_reg_defs[] = { 1141c246225SDan Murphy { DRV2667_STATUS, 0x02 }, 1151c246225SDan Murphy { DRV2667_CTRL_1, 0x28 }, 1161c246225SDan Murphy { DRV2667_CTRL_2, 0x40 }, 1171c246225SDan Murphy { DRV2667_WV_SEQ_0, 0x00 }, 1181c246225SDan Murphy { DRV2667_WV_SEQ_1, 0x00 }, 1191c246225SDan Murphy { DRV2667_WV_SEQ_2, 0x00 }, 1201c246225SDan Murphy { DRV2667_WV_SEQ_3, 0x00 }, 1211c246225SDan Murphy { DRV2667_WV_SEQ_4, 0x00 }, 1221c246225SDan Murphy { DRV2667_WV_SEQ_5, 0x00 }, 1231c246225SDan Murphy { DRV2667_WV_SEQ_6, 0x00 }, 1241c246225SDan Murphy { DRV2667_WV_SEQ_7, 0x00 }, 1251c246225SDan Murphy { DRV2667_FIFO, 0x00 }, 1261c246225SDan Murphy { DRV2667_PAGE, 0x00 }, 1271c246225SDan Murphy }; 1281c246225SDan Murphy 1291c246225SDan Murphy static int drv2667_set_waveform_freq(struct drv2667_data *haptics) 1301c246225SDan Murphy { 1311c246225SDan Murphy unsigned int read_buf; 1321c246225SDan Murphy int freq; 1331c246225SDan Murphy int error; 1341c246225SDan Murphy 1351c246225SDan Murphy /* Per the data sheet: 1361c246225SDan Murphy * Sinusoid Frequency (Hz) = 7.8125 x Frequency 1371c246225SDan Murphy */ 1381c246225SDan Murphy freq = (haptics->frequency * 1000) / 78125; 1391c246225SDan Murphy if (freq <= 0) { 1401c246225SDan Murphy dev_err(&haptics->client->dev, 1411c246225SDan Murphy "ERROR: Frequency calculated to %i\n", freq); 1421c246225SDan Murphy return -EINVAL; 1431c246225SDan Murphy } 1441c246225SDan Murphy 1451c246225SDan Murphy error = regmap_read(haptics->regmap, DRV2667_PAGE, &read_buf); 1461c246225SDan Murphy if (error) { 1471c246225SDan Murphy dev_err(&haptics->client->dev, 1481c246225SDan Murphy "Failed to read the page number: %d\n", error); 1491c246225SDan Murphy return -EIO; 1501c246225SDan Murphy } 1511c246225SDan Murphy 1521c246225SDan Murphy if (read_buf == DRV2667_PAGE_0 || 1531c246225SDan Murphy haptics->page != read_buf) { 1541c246225SDan Murphy error = regmap_write(haptics->regmap, 1551c246225SDan Murphy DRV2667_PAGE, haptics->page); 1561c246225SDan Murphy if (error) { 1571c246225SDan Murphy dev_err(&haptics->client->dev, 1581c246225SDan Murphy "Failed to set the page: %d\n", error); 1591c246225SDan Murphy return -EIO; 1601c246225SDan Murphy } 1611c246225SDan Murphy } 1621c246225SDan Murphy 1631c246225SDan Murphy error = regmap_write(haptics->regmap, DRV2667_RAM_FREQ, freq); 1641c246225SDan Murphy if (error) 1651c246225SDan Murphy dev_err(&haptics->client->dev, 1661c246225SDan Murphy "Failed to set the frequency: %d\n", error); 1671c246225SDan Murphy 1681c246225SDan Murphy /* Reset back to original page */ 1691c246225SDan Murphy if (read_buf == DRV2667_PAGE_0 || 1701c246225SDan Murphy haptics->page != read_buf) { 1711c246225SDan Murphy error = regmap_write(haptics->regmap, DRV2667_PAGE, read_buf); 1721c246225SDan Murphy if (error) { 1731c246225SDan Murphy dev_err(&haptics->client->dev, 1741c246225SDan Murphy "Failed to set the page: %d\n", error); 1751c246225SDan Murphy return -EIO; 1761c246225SDan Murphy } 1771c246225SDan Murphy } 1781c246225SDan Murphy 1791c246225SDan Murphy return error; 1801c246225SDan Murphy } 1811c246225SDan Murphy 1821c246225SDan Murphy static void drv2667_worker(struct work_struct *work) 1831c246225SDan Murphy { 1841c246225SDan Murphy struct drv2667_data *haptics = container_of(work, struct drv2667_data, work); 1851c246225SDan Murphy int error; 1861c246225SDan Murphy 1871c246225SDan Murphy if (haptics->magnitude) { 1881c246225SDan Murphy error = regmap_write(haptics->regmap, 1891c246225SDan Murphy DRV2667_PAGE, haptics->page); 1901c246225SDan Murphy if (error) { 1911c246225SDan Murphy dev_err(&haptics->client->dev, 1921c246225SDan Murphy "Failed to set the page: %d\n", error); 1931c246225SDan Murphy return; 1941c246225SDan Murphy } 1951c246225SDan Murphy 1961c246225SDan Murphy error = regmap_write(haptics->regmap, DRV2667_RAM_AMP, 1971c246225SDan Murphy haptics->magnitude); 1981c246225SDan Murphy if (error) { 1991c246225SDan Murphy dev_err(&haptics->client->dev, 2001c246225SDan Murphy "Failed to set the amplitude: %d\n", error); 2011c246225SDan Murphy return; 2021c246225SDan Murphy } 2031c246225SDan Murphy 2041c246225SDan Murphy error = regmap_write(haptics->regmap, 2051c246225SDan Murphy DRV2667_PAGE, DRV2667_PAGE_0); 2061c246225SDan Murphy if (error) { 2071c246225SDan Murphy dev_err(&haptics->client->dev, 2081c246225SDan Murphy "Failed to set the page: %d\n", error); 2091c246225SDan Murphy return; 2101c246225SDan Murphy } 2111c246225SDan Murphy 2121c246225SDan Murphy error = regmap_write(haptics->regmap, 2131c246225SDan Murphy DRV2667_CTRL_2, DRV2667_GO); 2141c246225SDan Murphy if (error) { 2151c246225SDan Murphy dev_err(&haptics->client->dev, 2161c246225SDan Murphy "Failed to set the GO bit: %d\n", error); 2171c246225SDan Murphy } 2181c246225SDan Murphy } else { 2191c246225SDan Murphy error = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2, 2201c246225SDan Murphy DRV2667_GO, 0); 2211c246225SDan Murphy if (error) { 2221c246225SDan Murphy dev_err(&haptics->client->dev, 2231c246225SDan Murphy "Failed to unset the GO bit: %d\n", error); 2241c246225SDan Murphy } 2251c246225SDan Murphy } 2261c246225SDan Murphy } 2271c246225SDan Murphy 2281c246225SDan Murphy static int drv2667_haptics_play(struct input_dev *input, void *data, 2291c246225SDan Murphy struct ff_effect *effect) 2301c246225SDan Murphy { 2311c246225SDan Murphy struct drv2667_data *haptics = input_get_drvdata(input); 2321c246225SDan Murphy 2331c246225SDan Murphy if (effect->u.rumble.strong_magnitude > 0) 2341c246225SDan Murphy haptics->magnitude = effect->u.rumble.strong_magnitude; 2351c246225SDan Murphy else if (effect->u.rumble.weak_magnitude > 0) 2361c246225SDan Murphy haptics->magnitude = effect->u.rumble.weak_magnitude; 2371c246225SDan Murphy else 2381c246225SDan Murphy haptics->magnitude = 0; 2391c246225SDan Murphy 2401c246225SDan Murphy schedule_work(&haptics->work); 2411c246225SDan Murphy 2421c246225SDan Murphy return 0; 2431c246225SDan Murphy } 2441c246225SDan Murphy 2451c246225SDan Murphy static void drv2667_close(struct input_dev *input) 2461c246225SDan Murphy { 2471c246225SDan Murphy struct drv2667_data *haptics = input_get_drvdata(input); 2481c246225SDan Murphy int error; 2491c246225SDan Murphy 2501c246225SDan Murphy cancel_work_sync(&haptics->work); 2511c246225SDan Murphy 2521c246225SDan Murphy error = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2, 2536473bbfdSFlorian Vaussard DRV2667_STANDBY, DRV2667_STANDBY); 2541c246225SDan Murphy if (error) 2551c246225SDan Murphy dev_err(&haptics->client->dev, 2561c246225SDan Murphy "Failed to enter standby mode: %d\n", error); 2571c246225SDan Murphy } 2581c246225SDan Murphy 2598019ff6cSNariman Poushin static const struct reg_sequence drv2667_init_regs[] = { 2601c246225SDan Murphy { DRV2667_CTRL_2, 0 }, 2611c246225SDan Murphy { DRV2667_CTRL_1, DRV2667_25_VPP_GAIN }, 2621c246225SDan Murphy { DRV2667_WV_SEQ_0, 1 }, 2631c246225SDan Murphy { DRV2667_WV_SEQ_1, 0 } 2641c246225SDan Murphy }; 2651c246225SDan Murphy 2668019ff6cSNariman Poushin static const struct reg_sequence drv2667_page1_init[] = { 2671c246225SDan Murphy { DRV2667_RAM_HDR_SZ, 0x05 }, 2681c246225SDan Murphy { DRV2667_RAM_START_HI, 0x80 }, 2691c246225SDan Murphy { DRV2667_RAM_START_LO, 0x06 }, 2701c246225SDan Murphy { DRV2667_RAM_STOP_HI, 0x00 }, 2711c246225SDan Murphy { DRV2667_RAM_STOP_LO, 0x09 }, 2721c246225SDan Murphy { DRV2667_RAM_REPEAT_CT, 0 }, 2731c246225SDan Murphy { DRV2667_RAM_DURATION, 0x05 }, 2741c246225SDan Murphy { DRV2667_RAM_ENVELOPE, DRV2667_NO_ENV }, 2751c246225SDan Murphy { DRV2667_RAM_AMP, 0x60 }, 2761c246225SDan Murphy }; 2771c246225SDan Murphy 2781c246225SDan Murphy static int drv2667_init(struct drv2667_data *haptics) 2791c246225SDan Murphy { 2801c246225SDan Murphy int error; 2811c246225SDan Murphy 2821c246225SDan Murphy /* Set default haptic frequency to 195Hz on Page 1*/ 2831c246225SDan Murphy haptics->frequency = 195; 2841c246225SDan Murphy haptics->page = DRV2667_PAGE_1; 2851c246225SDan Murphy 2861c246225SDan Murphy error = regmap_register_patch(haptics->regmap, 2871c246225SDan Murphy drv2667_init_regs, 2881c246225SDan Murphy ARRAY_SIZE(drv2667_init_regs)); 2891c246225SDan Murphy if (error) { 2901c246225SDan Murphy dev_err(&haptics->client->dev, 2911c246225SDan Murphy "Failed to write init registers: %d\n", 2921c246225SDan Murphy error); 2931c246225SDan Murphy return error; 2941c246225SDan Murphy } 2951c246225SDan Murphy 2961c246225SDan Murphy error = regmap_write(haptics->regmap, DRV2667_PAGE, haptics->page); 2971c246225SDan Murphy if (error) { 2981c246225SDan Murphy dev_err(&haptics->client->dev, "Failed to set page: %d\n", 2991c246225SDan Murphy error); 3001c246225SDan Murphy goto error_out; 3011c246225SDan Murphy } 3021c246225SDan Murphy 3031c246225SDan Murphy error = drv2667_set_waveform_freq(haptics); 3041c246225SDan Murphy if (error) 3051c246225SDan Murphy goto error_page; 3061c246225SDan Murphy 3071c246225SDan Murphy error = regmap_register_patch(haptics->regmap, 3081c246225SDan Murphy drv2667_page1_init, 3091c246225SDan Murphy ARRAY_SIZE(drv2667_page1_init)); 3101c246225SDan Murphy if (error) { 3111c246225SDan Murphy dev_err(&haptics->client->dev, 3121c246225SDan Murphy "Failed to write page registers: %d\n", 3131c246225SDan Murphy error); 3141c246225SDan Murphy return error; 3151c246225SDan Murphy } 3161c246225SDan Murphy 3171c246225SDan Murphy error = regmap_write(haptics->regmap, DRV2667_PAGE, DRV2667_PAGE_0); 3181c246225SDan Murphy return error; 3191c246225SDan Murphy 3201c246225SDan Murphy error_page: 3211c246225SDan Murphy regmap_write(haptics->regmap, DRV2667_PAGE, DRV2667_PAGE_0); 3221c246225SDan Murphy error_out: 3231c246225SDan Murphy return error; 3241c246225SDan Murphy } 3251c246225SDan Murphy 3261c246225SDan Murphy static const struct regmap_config drv2667_regmap_config = { 3271c246225SDan Murphy .reg_bits = 8, 3281c246225SDan Murphy .val_bits = 8, 3291c246225SDan Murphy 3301c246225SDan Murphy .max_register = DRV2667_MAX_REG, 3311c246225SDan Murphy .reg_defaults = drv2667_reg_defs, 3321c246225SDan Murphy .num_reg_defaults = ARRAY_SIZE(drv2667_reg_defs), 3331c246225SDan Murphy .cache_type = REGCACHE_NONE, 3341c246225SDan Murphy }; 3351c246225SDan Murphy 336*18dfbd31SUwe Kleine-König static int drv2667_probe(struct i2c_client *client) 3371c246225SDan Murphy { 3381c246225SDan Murphy struct drv2667_data *haptics; 3391c246225SDan Murphy int error; 3401c246225SDan Murphy 3411c246225SDan Murphy haptics = devm_kzalloc(&client->dev, sizeof(*haptics), GFP_KERNEL); 3421c246225SDan Murphy if (!haptics) 3431c246225SDan Murphy return -ENOMEM; 3441c246225SDan Murphy 3451c246225SDan Murphy haptics->regulator = devm_regulator_get(&client->dev, "vbat"); 3461c246225SDan Murphy if (IS_ERR(haptics->regulator)) { 3471c246225SDan Murphy error = PTR_ERR(haptics->regulator); 3481c246225SDan Murphy dev_err(&client->dev, 3491c246225SDan Murphy "unable to get regulator, error: %d\n", error); 3501c246225SDan Murphy return error; 3511c246225SDan Murphy } 3521c246225SDan Murphy 3531c246225SDan Murphy haptics->input_dev = devm_input_allocate_device(&client->dev); 3541c246225SDan Murphy if (!haptics->input_dev) { 3551c246225SDan Murphy dev_err(&client->dev, "Failed to allocate input device\n"); 3561c246225SDan Murphy return -ENOMEM; 3571c246225SDan Murphy } 3581c246225SDan Murphy 3591c246225SDan Murphy haptics->input_dev->name = "drv2667:haptics"; 3601c246225SDan Murphy haptics->input_dev->dev.parent = client->dev.parent; 3611c246225SDan Murphy haptics->input_dev->close = drv2667_close; 3621c246225SDan Murphy input_set_drvdata(haptics->input_dev, haptics); 3631c246225SDan Murphy input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE); 3641c246225SDan Murphy 3651c246225SDan Murphy error = input_ff_create_memless(haptics->input_dev, NULL, 3661c246225SDan Murphy drv2667_haptics_play); 3671c246225SDan Murphy if (error) { 3681c246225SDan Murphy dev_err(&client->dev, "input_ff_create() failed: %d\n", 3691c246225SDan Murphy error); 3701c246225SDan Murphy return error; 3711c246225SDan Murphy } 3721c246225SDan Murphy 3731c246225SDan Murphy INIT_WORK(&haptics->work, drv2667_worker); 3741c246225SDan Murphy 3751c246225SDan Murphy haptics->client = client; 3761c246225SDan Murphy i2c_set_clientdata(client, haptics); 3771c246225SDan Murphy 3781c246225SDan Murphy haptics->regmap = devm_regmap_init_i2c(client, &drv2667_regmap_config); 3791c246225SDan Murphy if (IS_ERR(haptics->regmap)) { 3801c246225SDan Murphy error = PTR_ERR(haptics->regmap); 3811c246225SDan Murphy dev_err(&client->dev, "Failed to allocate register map: %d\n", 3821c246225SDan Murphy error); 3831c246225SDan Murphy return error; 3841c246225SDan Murphy } 3851c246225SDan Murphy 3861c246225SDan Murphy error = drv2667_init(haptics); 3871c246225SDan Murphy if (error) { 3881c246225SDan Murphy dev_err(&client->dev, "Device init failed: %d\n", error); 3891c246225SDan Murphy return error; 3901c246225SDan Murphy } 3911c246225SDan Murphy 3921c246225SDan Murphy error = input_register_device(haptics->input_dev); 3931c246225SDan Murphy if (error) { 3941c246225SDan Murphy dev_err(&client->dev, "couldn't register input device: %d\n", 3951c246225SDan Murphy error); 3961c246225SDan Murphy return error; 3971c246225SDan Murphy } 3981c246225SDan Murphy 3991c246225SDan Murphy return 0; 4001c246225SDan Murphy } 4011c246225SDan Murphy 40297a652a8SJingoo Han static int __maybe_unused drv2667_suspend(struct device *dev) 4031c246225SDan Murphy { 4041c246225SDan Murphy struct drv2667_data *haptics = dev_get_drvdata(dev); 4051c246225SDan Murphy int ret = 0; 4061c246225SDan Murphy 4071c246225SDan Murphy mutex_lock(&haptics->input_dev->mutex); 4081c246225SDan Murphy 409d69f0a43SAndrzej Pietrasiewicz if (input_device_enabled(haptics->input_dev)) { 4101c246225SDan Murphy ret = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2, 4116473bbfdSFlorian Vaussard DRV2667_STANDBY, DRV2667_STANDBY); 4121c246225SDan Murphy if (ret) { 4131c246225SDan Murphy dev_err(dev, "Failed to set standby mode\n"); 4141c246225SDan Murphy regulator_disable(haptics->regulator); 4151c246225SDan Murphy goto out; 4161c246225SDan Murphy } 4171c246225SDan Murphy 4181c246225SDan Murphy ret = regulator_disable(haptics->regulator); 4191c246225SDan Murphy if (ret) { 4201c246225SDan Murphy dev_err(dev, "Failed to disable regulator\n"); 4211c246225SDan Murphy regmap_update_bits(haptics->regmap, 4221c246225SDan Murphy DRV2667_CTRL_2, 4231c246225SDan Murphy DRV2667_STANDBY, 0); 4241c246225SDan Murphy } 4251c246225SDan Murphy } 4261c246225SDan Murphy out: 4271c246225SDan Murphy mutex_unlock(&haptics->input_dev->mutex); 4281c246225SDan Murphy return ret; 4291c246225SDan Murphy } 4301c246225SDan Murphy 43197a652a8SJingoo Han static int __maybe_unused drv2667_resume(struct device *dev) 4321c246225SDan Murphy { 4331c246225SDan Murphy struct drv2667_data *haptics = dev_get_drvdata(dev); 4341c246225SDan Murphy int ret = 0; 4351c246225SDan Murphy 4361c246225SDan Murphy mutex_lock(&haptics->input_dev->mutex); 4371c246225SDan Murphy 438d69f0a43SAndrzej Pietrasiewicz if (input_device_enabled(haptics->input_dev)) { 4391c246225SDan Murphy ret = regulator_enable(haptics->regulator); 4401c246225SDan Murphy if (ret) { 4411c246225SDan Murphy dev_err(dev, "Failed to enable regulator\n"); 4421c246225SDan Murphy goto out; 4431c246225SDan Murphy } 4441c246225SDan Murphy 4451c246225SDan Murphy ret = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2, 4461c246225SDan Murphy DRV2667_STANDBY, 0); 4471c246225SDan Murphy if (ret) { 4481c246225SDan Murphy dev_err(dev, "Failed to unset standby mode\n"); 4491c246225SDan Murphy regulator_disable(haptics->regulator); 4501c246225SDan Murphy goto out; 4511c246225SDan Murphy } 4521c246225SDan Murphy 4531c246225SDan Murphy } 4541c246225SDan Murphy 4551c246225SDan Murphy out: 4561c246225SDan Murphy mutex_unlock(&haptics->input_dev->mutex); 4571c246225SDan Murphy return ret; 4581c246225SDan Murphy } 4591c246225SDan Murphy 4601c246225SDan Murphy static SIMPLE_DEV_PM_OPS(drv2667_pm_ops, drv2667_suspend, drv2667_resume); 4611c246225SDan Murphy 4621c246225SDan Murphy static const struct i2c_device_id drv2667_id[] = { 4631c246225SDan Murphy { "drv2667", 0 }, 4641c246225SDan Murphy { } 4651c246225SDan Murphy }; 4661c246225SDan Murphy MODULE_DEVICE_TABLE(i2c, drv2667_id); 4671c246225SDan Murphy 4681c246225SDan Murphy #ifdef CONFIG_OF 4691c246225SDan Murphy static const struct of_device_id drv2667_of_match[] = { 4701c246225SDan Murphy { .compatible = "ti,drv2667", }, 4711c246225SDan Murphy { } 4721c246225SDan Murphy }; 4731c246225SDan Murphy MODULE_DEVICE_TABLE(of, drv2667_of_match); 4741c246225SDan Murphy #endif 4751c246225SDan Murphy 4761c246225SDan Murphy static struct i2c_driver drv2667_driver = { 477*18dfbd31SUwe Kleine-König .probe_new = drv2667_probe, 4781c246225SDan Murphy .driver = { 4791c246225SDan Murphy .name = "drv2667-haptics", 4801c246225SDan Murphy .of_match_table = of_match_ptr(drv2667_of_match), 4811c246225SDan Murphy .pm = &drv2667_pm_ops, 4821c246225SDan Murphy }, 4831c246225SDan Murphy .id_table = drv2667_id, 4841c246225SDan Murphy }; 4851c246225SDan Murphy module_i2c_driver(drv2667_driver); 4861c246225SDan Murphy 4871c246225SDan Murphy MODULE_DESCRIPTION("TI DRV2667 haptics driver"); 4881c246225SDan Murphy MODULE_LICENSE("GPL"); 4891c246225SDan Murphy MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); 490