162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * DRV2665 haptics driver family
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author: Dan Murphy <dmurphy@ti.com>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright: (C) 2015 Texas Instruments, Inc.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/i2c.h>
1162306a36Sopenharmony_ci#include <linux/input.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/regmap.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <linux/delay.h>
1662306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/* Contol registers */
1962306a36Sopenharmony_ci#define DRV2665_STATUS	0x00
2062306a36Sopenharmony_ci#define DRV2665_CTRL_1	0x01
2162306a36Sopenharmony_ci#define DRV2665_CTRL_2	0x02
2262306a36Sopenharmony_ci#define DRV2665_FIFO	0x0b
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/* Status Register */
2562306a36Sopenharmony_ci#define DRV2665_FIFO_FULL		BIT(0)
2662306a36Sopenharmony_ci#define DRV2665_FIFO_EMPTY		BIT(1)
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/* Control 1 Register */
2962306a36Sopenharmony_ci#define DRV2665_25_VPP_GAIN		0x00
3062306a36Sopenharmony_ci#define DRV2665_50_VPP_GAIN		0x01
3162306a36Sopenharmony_ci#define DRV2665_75_VPP_GAIN		0x02
3262306a36Sopenharmony_ci#define DRV2665_100_VPP_GAIN		0x03
3362306a36Sopenharmony_ci#define DRV2665_DIGITAL_IN		0xfc
3462306a36Sopenharmony_ci#define DRV2665_ANALOG_IN		BIT(2)
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* Control 2 Register */
3762306a36Sopenharmony_ci#define DRV2665_BOOST_EN		BIT(1)
3862306a36Sopenharmony_ci#define DRV2665_STANDBY			BIT(6)
3962306a36Sopenharmony_ci#define DRV2665_DEV_RST			BIT(7)
4062306a36Sopenharmony_ci#define DRV2665_5_MS_IDLE_TOUT		0x00
4162306a36Sopenharmony_ci#define DRV2665_10_MS_IDLE_TOUT		0x04
4262306a36Sopenharmony_ci#define DRV2665_15_MS_IDLE_TOUT		0x08
4362306a36Sopenharmony_ci#define DRV2665_20_MS_IDLE_TOUT		0x0c
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/**
4662306a36Sopenharmony_ci * struct drv2665_data -
4762306a36Sopenharmony_ci * @input_dev: Pointer to the input device
4862306a36Sopenharmony_ci * @client: Pointer to the I2C client
4962306a36Sopenharmony_ci * @regmap: Register map of the device
5062306a36Sopenharmony_ci * @work: Work item used to off load the enable/disable of the vibration
5162306a36Sopenharmony_ci * @regulator: Pointer to the regulator for the IC
5262306a36Sopenharmony_ci */
5362306a36Sopenharmony_cistruct drv2665_data {
5462306a36Sopenharmony_ci	struct input_dev *input_dev;
5562306a36Sopenharmony_ci	struct i2c_client *client;
5662306a36Sopenharmony_ci	struct regmap *regmap;
5762306a36Sopenharmony_ci	struct work_struct work;
5862306a36Sopenharmony_ci	struct regulator *regulator;
5962306a36Sopenharmony_ci};
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/* 8kHz Sine wave to stream to the FIFO */
6262306a36Sopenharmony_cistatic const u8 drv2665_sine_wave_form[] = {
6362306a36Sopenharmony_ci	0x00, 0x10, 0x20, 0x2e, 0x3c, 0x48, 0x53, 0x5b, 0x61, 0x65, 0x66,
6462306a36Sopenharmony_ci	0x65, 0x61, 0x5b, 0x53, 0x48, 0x3c, 0x2e, 0x20, 0x10,
6562306a36Sopenharmony_ci	0x00, 0xf0, 0xe0, 0xd2, 0xc4, 0xb8, 0xad, 0xa5, 0x9f, 0x9b, 0x9a,
6662306a36Sopenharmony_ci	0x9b, 0x9f, 0xa5, 0xad, 0xb8, 0xc4, 0xd2, 0xe0, 0xf0, 0x00,
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic const struct reg_default drv2665_reg_defs[] = {
7062306a36Sopenharmony_ci	{ DRV2665_STATUS, 0x02 },
7162306a36Sopenharmony_ci	{ DRV2665_CTRL_1, 0x28 },
7262306a36Sopenharmony_ci	{ DRV2665_CTRL_2, 0x40 },
7362306a36Sopenharmony_ci	{ DRV2665_FIFO, 0x00 },
7462306a36Sopenharmony_ci};
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic void drv2665_worker(struct work_struct *work)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	struct drv2665_data *haptics =
7962306a36Sopenharmony_ci				container_of(work, struct drv2665_data, work);
8062306a36Sopenharmony_ci	unsigned int read_buf;
8162306a36Sopenharmony_ci	int error;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	error = regmap_read(haptics->regmap, DRV2665_STATUS, &read_buf);
8462306a36Sopenharmony_ci	if (error) {
8562306a36Sopenharmony_ci		dev_err(&haptics->client->dev,
8662306a36Sopenharmony_ci			"Failed to read status: %d\n", error);
8762306a36Sopenharmony_ci		return;
8862306a36Sopenharmony_ci	}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	if (read_buf & DRV2665_FIFO_EMPTY) {
9162306a36Sopenharmony_ci		error = regmap_bulk_write(haptics->regmap,
9262306a36Sopenharmony_ci					  DRV2665_FIFO,
9362306a36Sopenharmony_ci					  drv2665_sine_wave_form,
9462306a36Sopenharmony_ci					  ARRAY_SIZE(drv2665_sine_wave_form));
9562306a36Sopenharmony_ci		if (error) {
9662306a36Sopenharmony_ci			dev_err(&haptics->client->dev,
9762306a36Sopenharmony_ci				"Failed to write FIFO: %d\n", error);
9862306a36Sopenharmony_ci			return;
9962306a36Sopenharmony_ci		}
10062306a36Sopenharmony_ci	}
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic int drv2665_haptics_play(struct input_dev *input, void *data,
10462306a36Sopenharmony_ci				struct ff_effect *effect)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	struct drv2665_data *haptics = input_get_drvdata(input);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	schedule_work(&haptics->work);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	return 0;
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic void drv2665_close(struct input_dev *input)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	struct drv2665_data *haptics = input_get_drvdata(input);
11662306a36Sopenharmony_ci	int error;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	cancel_work_sync(&haptics->work);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	error = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
12162306a36Sopenharmony_ci				   DRV2665_STANDBY, DRV2665_STANDBY);
12262306a36Sopenharmony_ci	if (error)
12362306a36Sopenharmony_ci		dev_err(&haptics->client->dev,
12462306a36Sopenharmony_ci			"Failed to enter standby mode: %d\n", error);
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic const struct reg_sequence drv2665_init_regs[] = {
12862306a36Sopenharmony_ci	{ DRV2665_CTRL_2, 0 | DRV2665_10_MS_IDLE_TOUT },
12962306a36Sopenharmony_ci	{ DRV2665_CTRL_1, DRV2665_25_VPP_GAIN },
13062306a36Sopenharmony_ci};
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic int drv2665_init(struct drv2665_data *haptics)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	int error;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	error = regmap_register_patch(haptics->regmap,
13762306a36Sopenharmony_ci				      drv2665_init_regs,
13862306a36Sopenharmony_ci				      ARRAY_SIZE(drv2665_init_regs));
13962306a36Sopenharmony_ci	if (error) {
14062306a36Sopenharmony_ci		dev_err(&haptics->client->dev,
14162306a36Sopenharmony_ci			"Failed to write init registers: %d\n",
14262306a36Sopenharmony_ci			error);
14362306a36Sopenharmony_ci		return error;
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	return 0;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic const struct regmap_config drv2665_regmap_config = {
15062306a36Sopenharmony_ci	.reg_bits = 8,
15162306a36Sopenharmony_ci	.val_bits = 8,
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	.max_register = DRV2665_FIFO,
15462306a36Sopenharmony_ci	.reg_defaults = drv2665_reg_defs,
15562306a36Sopenharmony_ci	.num_reg_defaults = ARRAY_SIZE(drv2665_reg_defs),
15662306a36Sopenharmony_ci	.cache_type = REGCACHE_NONE,
15762306a36Sopenharmony_ci};
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistatic int drv2665_probe(struct i2c_client *client)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	struct drv2665_data *haptics;
16262306a36Sopenharmony_ci	int error;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	haptics = devm_kzalloc(&client->dev, sizeof(*haptics), GFP_KERNEL);
16562306a36Sopenharmony_ci	if (!haptics)
16662306a36Sopenharmony_ci		return -ENOMEM;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	haptics->regulator = devm_regulator_get(&client->dev, "vbat");
16962306a36Sopenharmony_ci	if (IS_ERR(haptics->regulator)) {
17062306a36Sopenharmony_ci		error = PTR_ERR(haptics->regulator);
17162306a36Sopenharmony_ci		dev_err(&client->dev,
17262306a36Sopenharmony_ci			"unable to get regulator, error: %d\n", error);
17362306a36Sopenharmony_ci		return error;
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	haptics->input_dev = devm_input_allocate_device(&client->dev);
17762306a36Sopenharmony_ci	if (!haptics->input_dev) {
17862306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to allocate input device\n");
17962306a36Sopenharmony_ci		return -ENOMEM;
18062306a36Sopenharmony_ci	}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	haptics->input_dev->name = "drv2665:haptics";
18362306a36Sopenharmony_ci	haptics->input_dev->dev.parent = client->dev.parent;
18462306a36Sopenharmony_ci	haptics->input_dev->close = drv2665_close;
18562306a36Sopenharmony_ci	input_set_drvdata(haptics->input_dev, haptics);
18662306a36Sopenharmony_ci	input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	error = input_ff_create_memless(haptics->input_dev, NULL,
18962306a36Sopenharmony_ci					drv2665_haptics_play);
19062306a36Sopenharmony_ci	if (error) {
19162306a36Sopenharmony_ci		dev_err(&client->dev, "input_ff_create() failed: %d\n",
19262306a36Sopenharmony_ci			error);
19362306a36Sopenharmony_ci		return error;
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	INIT_WORK(&haptics->work, drv2665_worker);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	haptics->client = client;
19962306a36Sopenharmony_ci	i2c_set_clientdata(client, haptics);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	haptics->regmap = devm_regmap_init_i2c(client, &drv2665_regmap_config);
20262306a36Sopenharmony_ci	if (IS_ERR(haptics->regmap)) {
20362306a36Sopenharmony_ci		error = PTR_ERR(haptics->regmap);
20462306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to allocate register map: %d\n",
20562306a36Sopenharmony_ci			error);
20662306a36Sopenharmony_ci		return error;
20762306a36Sopenharmony_ci	}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	error = drv2665_init(haptics);
21062306a36Sopenharmony_ci	if (error) {
21162306a36Sopenharmony_ci		dev_err(&client->dev, "Device init failed: %d\n", error);
21262306a36Sopenharmony_ci		return error;
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	error = input_register_device(haptics->input_dev);
21662306a36Sopenharmony_ci	if (error) {
21762306a36Sopenharmony_ci		dev_err(&client->dev, "couldn't register input device: %d\n",
21862306a36Sopenharmony_ci			error);
21962306a36Sopenharmony_ci		return error;
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	return 0;
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic int drv2665_suspend(struct device *dev)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	struct drv2665_data *haptics = dev_get_drvdata(dev);
22862306a36Sopenharmony_ci	int ret = 0;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	mutex_lock(&haptics->input_dev->mutex);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	if (input_device_enabled(haptics->input_dev)) {
23362306a36Sopenharmony_ci		ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
23462306a36Sopenharmony_ci					 DRV2665_STANDBY, DRV2665_STANDBY);
23562306a36Sopenharmony_ci		if (ret) {
23662306a36Sopenharmony_ci			dev_err(dev, "Failed to set standby mode\n");
23762306a36Sopenharmony_ci			regulator_disable(haptics->regulator);
23862306a36Sopenharmony_ci			goto out;
23962306a36Sopenharmony_ci		}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci		ret = regulator_disable(haptics->regulator);
24262306a36Sopenharmony_ci		if (ret) {
24362306a36Sopenharmony_ci			dev_err(dev, "Failed to disable regulator\n");
24462306a36Sopenharmony_ci			regmap_update_bits(haptics->regmap,
24562306a36Sopenharmony_ci					   DRV2665_CTRL_2,
24662306a36Sopenharmony_ci					   DRV2665_STANDBY, 0);
24762306a36Sopenharmony_ci		}
24862306a36Sopenharmony_ci	}
24962306a36Sopenharmony_ciout:
25062306a36Sopenharmony_ci	mutex_unlock(&haptics->input_dev->mutex);
25162306a36Sopenharmony_ci	return ret;
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic int drv2665_resume(struct device *dev)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	struct drv2665_data *haptics = dev_get_drvdata(dev);
25762306a36Sopenharmony_ci	int ret = 0;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	mutex_lock(&haptics->input_dev->mutex);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	if (input_device_enabled(haptics->input_dev)) {
26262306a36Sopenharmony_ci		ret = regulator_enable(haptics->regulator);
26362306a36Sopenharmony_ci		if (ret) {
26462306a36Sopenharmony_ci			dev_err(dev, "Failed to enable regulator\n");
26562306a36Sopenharmony_ci			goto out;
26662306a36Sopenharmony_ci		}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci		ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
26962306a36Sopenharmony_ci					 DRV2665_STANDBY, 0);
27062306a36Sopenharmony_ci		if (ret) {
27162306a36Sopenharmony_ci			dev_err(dev, "Failed to unset standby mode\n");
27262306a36Sopenharmony_ci			regulator_disable(haptics->regulator);
27362306a36Sopenharmony_ci			goto out;
27462306a36Sopenharmony_ci		}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ciout:
27962306a36Sopenharmony_ci	mutex_unlock(&haptics->input_dev->mutex);
28062306a36Sopenharmony_ci	return ret;
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(drv2665_pm_ops, drv2665_suspend, drv2665_resume);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic const struct i2c_device_id drv2665_id[] = {
28662306a36Sopenharmony_ci	{ "drv2665", 0 },
28762306a36Sopenharmony_ci	{ }
28862306a36Sopenharmony_ci};
28962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, drv2665_id);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci#ifdef CONFIG_OF
29262306a36Sopenharmony_cistatic const struct of_device_id drv2665_of_match[] = {
29362306a36Sopenharmony_ci	{ .compatible = "ti,drv2665", },
29462306a36Sopenharmony_ci	{ }
29562306a36Sopenharmony_ci};
29662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, drv2665_of_match);
29762306a36Sopenharmony_ci#endif
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic struct i2c_driver drv2665_driver = {
30062306a36Sopenharmony_ci	.probe		= drv2665_probe,
30162306a36Sopenharmony_ci	.driver		= {
30262306a36Sopenharmony_ci		.name	= "drv2665-haptics",
30362306a36Sopenharmony_ci		.of_match_table = of_match_ptr(drv2665_of_match),
30462306a36Sopenharmony_ci		.pm	= pm_sleep_ptr(&drv2665_pm_ops),
30562306a36Sopenharmony_ci	},
30662306a36Sopenharmony_ci	.id_table = drv2665_id,
30762306a36Sopenharmony_ci};
30862306a36Sopenharmony_cimodule_i2c_driver(drv2665_driver);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ciMODULE_DESCRIPTION("TI DRV2665 haptics driver");
31162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
31262306a36Sopenharmony_ciMODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
313