File Index
Files and directories
Sign in
FILE

max8997_haptic.c

File preview with syntax highlighting.

linux-6.19.14/drivers/input/misc/max8997_haptic.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * MAX8997-haptic controller driver
  4 *
  5 * Copyright (C) 2012 Samsung Electronics
  6 * Donggeun Kim <dg77.kim@samsung.com>
  7 *
  8 * This program is not provided / owned by Maxim Integrated Products.
  9 */
 10
 11#include <linux/module.h>
 12#include <linux/slab.h>
 13#include <linux/platform_device.h>
 14#include <linux/err.h>
 15#include <linux/pwm.h>
 16#include <linux/input.h>
 17#include <linux/mfd/max8997-private.h>
 18#include <linux/mfd/max8997.h>
 19#include <linux/regulator/consumer.h>
 20
 21/* Haptic configuration 2 register */
 22#define MAX8997_MOTOR_TYPE_SHIFT	7
 23#define MAX8997_ENABLE_SHIFT		6
 24#define MAX8997_MODE_SHIFT		5
 25
 26/* Haptic driver configuration register */
 27#define MAX8997_CYCLE_SHIFT		6
 28#define MAX8997_SIG_PERIOD_SHIFT	4
 29#define MAX8997_SIG_DUTY_SHIFT		2
 30#define MAX8997_PWM_DUTY_SHIFT		0
 31
 32struct max8997_haptic {
 33	struct device *dev;
 34	struct i2c_client *client;
 35	struct input_dev *input_dev;
 36	struct regulator *regulator;
 37
 38	struct work_struct work;
 39	struct mutex mutex;
 40
 41	bool enabled;
 42	unsigned int level;
 43
 44	struct pwm_device *pwm;
 45	unsigned int pwm_period;
 46	enum max8997_haptic_pwm_divisor pwm_divisor;
 47
 48	enum max8997_haptic_motor_type type;
 49	enum max8997_haptic_pulse_mode mode;
 50
 51	unsigned int internal_mode_pattern;
 52	unsigned int pattern_cycle;
 53	unsigned int pattern_signal_period;
 54};
 55
 56static void max8997_haptic_set_internal_duty_cycle(struct max8997_haptic *chip)
 57{
 58	u8 duty_index = DIV_ROUND_UP(chip->level * 64, 100);
 59
 60	switch (chip->internal_mode_pattern) {
 61	case 0:
 62		max8997_write_reg(chip->client,
 63				  MAX8997_HAPTIC_REG_SIGPWMDC1, duty_index);
 64		break;
 65	case 1:
 66		max8997_write_reg(chip->client,
 67				  MAX8997_HAPTIC_REG_SIGPWMDC2, duty_index);
 68		break;
 69	case 2:
 70		max8997_write_reg(chip->client,
 71				  MAX8997_HAPTIC_REG_SIGPWMDC3, duty_index);
 72		break;
 73	case 3:
 74		max8997_write_reg(chip->client,
 75				  MAX8997_HAPTIC_REG_SIGPWMDC4, duty_index);
 76		break;
 77	default:
 78		break;
 79	}
 80}
 81
 82static void max8997_haptic_configure(struct max8997_haptic *chip)
 83{
 84	u8 value;
 85
 86	value = chip->type << MAX8997_MOTOR_TYPE_SHIFT |
 87		chip->enabled << MAX8997_ENABLE_SHIFT |
 88		chip->mode << MAX8997_MODE_SHIFT | chip->pwm_divisor;
 89	max8997_write_reg(chip->client, MAX8997_HAPTIC_REG_CONF2, value);
 90
 91	if (chip->mode == MAX8997_INTERNAL_MODE && chip->enabled) {
 92		value = chip->internal_mode_pattern << MAX8997_CYCLE_SHIFT |
 93			chip->internal_mode_pattern << MAX8997_SIG_PERIOD_SHIFT |
 94			chip->internal_mode_pattern << MAX8997_SIG_DUTY_SHIFT |
 95			chip->internal_mode_pattern << MAX8997_PWM_DUTY_SHIFT;
 96		max8997_write_reg(chip->client,
 97			MAX8997_HAPTIC_REG_DRVCONF, value);
 98
 99		switch (chip->internal_mode_pattern) {
100		case 0:
101			value = chip->pattern_cycle << 4;
102			max8997_write_reg(chip->client,
103				MAX8997_HAPTIC_REG_CYCLECONF1, value);
104			value = chip->pattern_signal_period;
105			max8997_write_reg(chip->client,
106				MAX8997_HAPTIC_REG_SIGCONF1, value);
107			break;
108
109		case 1:
110			value = chip->pattern_cycle;
111			max8997_write_reg(chip->client,
112				MAX8997_HAPTIC_REG_CYCLECONF1, value);
113			value = chip->pattern_signal_period;
114			max8997_write_reg(chip->client,
115				MAX8997_HAPTIC_REG_SIGCONF2, value);
116			break;
117
118		case 2:
119			value = chip->pattern_cycle << 4;
120			max8997_write_reg(chip->client,
121				MAX8997_HAPTIC_REG_CYCLECONF2, value);
122			value = chip->pattern_signal_period;
123			max8997_write_reg(chip->client,
124				MAX8997_HAPTIC_REG_SIGCONF3, value);
125			break;
126
127		case 3:
128			value = chip->pattern_cycle;
129			max8997_write_reg(chip->client,
130				MAX8997_HAPTIC_REG_CYCLECONF2, value);
131			value = chip->pattern_signal_period;
132			max8997_write_reg(chip->client,
133				MAX8997_HAPTIC_REG_SIGCONF4, value);
134			break;
135
136		default:
137			break;
138		}
139	}
140}
141
142static void max8997_haptic_enable(struct max8997_haptic *chip)
143{
144	int error;
145
146	guard(mutex)(&chip->mutex);
147
148	if (chip->mode != MAX8997_EXTERNAL_MODE)
149		max8997_haptic_set_internal_duty_cycle(chip);
150
151	if (!chip->enabled) {
152		error = regulator_enable(chip->regulator);
153		if (error) {
154			dev_err(chip->dev, "Failed to enable regulator\n");
155			return;
156		}
157		max8997_haptic_configure(chip);
158	}
159
160	/*
161	 * It would be more straight forward to configure the external PWM
162	 * earlier i.e. when the internal duty_cycle is setup in internal mode.
163	 * But historically this is done only after the regulator was enabled
164	 * and max8997_haptic_configure() set the enable bit in
165	 * MAX8997_HAPTIC_REG_CONF2. So better keep it this way.
166	 */
167	if (chip->mode == MAX8997_EXTERNAL_MODE) {
168		struct pwm_state state;
169
170		pwm_init_state(chip->pwm, &state);
171		state.period = chip->pwm_period;
172		state.duty_cycle = chip->pwm_period * chip->level / 100;
173		state.enabled = true;
174
175		error = pwm_apply_might_sleep(chip->pwm, &state);
176		if (error) {
177			dev_err(chip->dev, "Failed to enable PWM\n");
178			regulator_disable(chip->regulator);
179			return;
180		}
181	}
182
183	chip->enabled = true;
184}
185
186static void max8997_haptic_disable(struct max8997_haptic *chip)
187{
188	guard(mutex)(&chip->mutex);
189
190	if (chip->enabled) {
191		chip->enabled = false;
192		max8997_haptic_configure(chip);
193		if (chip->mode == MAX8997_EXTERNAL_MODE)
194			pwm_disable(chip->pwm);
195		regulator_disable(chip->regulator);
196	}
197}
198
199static void max8997_haptic_play_effect_work(struct work_struct *work)
200{
201	struct max8997_haptic *chip =
202			container_of(work, struct max8997_haptic, work);
203
204	if (chip->level)
205		max8997_haptic_enable(chip);
206	else
207		max8997_haptic_disable(chip);
208}
209
210static int max8997_haptic_play_effect(struct input_dev *dev, void *data,
211				  struct ff_effect *effect)
212{
213	struct max8997_haptic *chip = input_get_drvdata(dev);
214
215	chip->level = effect->u.rumble.strong_magnitude;
216	if (!chip->level)
217		chip->level = effect->u.rumble.weak_magnitude;
218
219	schedule_work(&chip->work);
220
221	return 0;
222}
223
224static void max8997_haptic_close(struct input_dev *dev)
225{
226	struct max8997_haptic *chip = input_get_drvdata(dev);
227
228	cancel_work_sync(&chip->work);
229	max8997_haptic_disable(chip);
230}
231
232static int max8997_haptic_probe(struct platform_device *pdev)
233{
234	struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
235	const struct max8997_platform_data *pdata =
236					dev_get_platdata(iodev->dev);
237	const struct max8997_haptic_platform_data *haptic_pdata = NULL;
238	struct max8997_haptic *chip;
239	struct input_dev *input_dev;
240	int error;
241
242	if (pdata)
243		haptic_pdata = pdata->haptic_pdata;
244
245	if (!haptic_pdata) {
246		dev_err(&pdev->dev, "no haptic platform data\n");
247		return -EINVAL;
248	}
249
250	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
251	input_dev = input_allocate_device();
252	if (!chip || !input_dev) {
253		dev_err(&pdev->dev, "unable to allocate memory\n");
254		error = -ENOMEM;
255		goto err_free_mem;
256	}
257
258	INIT_WORK(&chip->work, max8997_haptic_play_effect_work);
259	mutex_init(&chip->mutex);
260
261	chip->client = iodev->haptic;
262	chip->dev = &pdev->dev;
263	chip->input_dev = input_dev;
264	chip->pwm_period = haptic_pdata->pwm_period;
265	chip->type = haptic_pdata->type;
266	chip->mode = haptic_pdata->mode;
267	chip->pwm_divisor = haptic_pdata->pwm_divisor;
268
269	switch (chip->mode) {
270	case MAX8997_INTERNAL_MODE:
271		chip->internal_mode_pattern =
272				haptic_pdata->internal_mode_pattern;
273		chip->pattern_cycle = haptic_pdata->pattern_cycle;
274		chip->pattern_signal_period =
275				haptic_pdata->pattern_signal_period;
276		break;
277
278	case MAX8997_EXTERNAL_MODE:
279		chip->pwm = pwm_get(&pdev->dev, NULL);
280		if (IS_ERR(chip->pwm)) {
281			error = PTR_ERR(chip->pwm);
282			dev_err(&pdev->dev,
283				"unable to request PWM for haptic, error: %d\n",
284				error);
285			goto err_free_mem;
286		}
287
288		break;
289
290	default:
291		dev_err(&pdev->dev,
292			"Invalid chip mode specified (%d)\n", chip->mode);
293		error = -EINVAL;
294		goto err_free_mem;
295	}
296
297	chip->regulator = regulator_get(&pdev->dev, "inmotor");
298	if (IS_ERR(chip->regulator)) {
299		error = PTR_ERR(chip->regulator);
300		dev_err(&pdev->dev,
301			"unable to get regulator, error: %d\n",
302			error);
303		goto err_free_pwm;
304	}
305
306	input_dev->name = "max8997-haptic";
307	input_dev->id.version = 1;
308	input_dev->dev.parent = &pdev->dev;
309	input_dev->close = max8997_haptic_close;
310	input_set_drvdata(input_dev, chip);
311	input_set_capability(input_dev, EV_FF, FF_RUMBLE);
312
313	error = input_ff_create_memless(input_dev, NULL,
314				max8997_haptic_play_effect);
315	if (error) {
316		dev_err(&pdev->dev,
317			"unable to create FF device, error: %d\n",
318			error);
319		goto err_put_regulator;
320	}
321
322	error = input_register_device(input_dev);
323	if (error) {
324		dev_err(&pdev->dev,
325			"unable to register input device, error: %d\n",
326			error);
327		goto err_destroy_ff;
328	}
329
330	platform_set_drvdata(pdev, chip);
331	return 0;
332
333err_destroy_ff:
334	input_ff_destroy(input_dev);
335err_put_regulator:
336	regulator_put(chip->regulator);
337err_free_pwm:
338	if (chip->mode == MAX8997_EXTERNAL_MODE)
339		pwm_put(chip->pwm);
340err_free_mem:
341	input_free_device(input_dev);
342	kfree(chip);
343
344	return error;
345}
346
347static void max8997_haptic_remove(struct platform_device *pdev)
348{
349	struct max8997_haptic *chip = platform_get_drvdata(pdev);
350
351	input_unregister_device(chip->input_dev);
352	regulator_put(chip->regulator);
353
354	if (chip->mode == MAX8997_EXTERNAL_MODE)
355		pwm_put(chip->pwm);
356
357	kfree(chip);
358}
359
360static int max8997_haptic_suspend(struct device *dev)
361{
362	struct platform_device *pdev = to_platform_device(dev);
363	struct max8997_haptic *chip = platform_get_drvdata(pdev);
364
365	max8997_haptic_disable(chip);
366
367	return 0;
368}
369
370static DEFINE_SIMPLE_DEV_PM_OPS(max8997_haptic_pm_ops,
371				max8997_haptic_suspend, NULL);
372
373static const struct platform_device_id max8997_haptic_id[] = {
374	{ "max8997-haptic", 0 },
375	{ },
376};
377MODULE_DEVICE_TABLE(platform, max8997_haptic_id);
378
379static struct platform_driver max8997_haptic_driver = {
380	.driver	= {
381		.name	= "max8997-haptic",
382		.pm	= pm_sleep_ptr(&max8997_haptic_pm_ops),
383	},
384	.probe		= max8997_haptic_probe,
385	.remove		= max8997_haptic_remove,
386	.id_table	= max8997_haptic_id,
387};
388module_platform_driver(max8997_haptic_driver);
389
390MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
391MODULE_DESCRIPTION("max8997_haptic driver");
392MODULE_LICENSE("GPL");
~/ Read-only file preview.