18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * MAX8997-haptic controller driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2012 Samsung Electronics
68c2ecf20Sopenharmony_ci * Donggeun Kim <dg77.kim@samsung.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * This program is not provided / owned by Maxim Integrated Products.
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/slab.h>
138c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
148c2ecf20Sopenharmony_ci#include <linux/err.h>
158c2ecf20Sopenharmony_ci#include <linux/pwm.h>
168c2ecf20Sopenharmony_ci#include <linux/input.h>
178c2ecf20Sopenharmony_ci#include <linux/mfd/max8997-private.h>
188c2ecf20Sopenharmony_ci#include <linux/mfd/max8997.h>
198c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/* Haptic configuration 2 register */
228c2ecf20Sopenharmony_ci#define MAX8997_MOTOR_TYPE_SHIFT	7
238c2ecf20Sopenharmony_ci#define MAX8997_ENABLE_SHIFT		6
248c2ecf20Sopenharmony_ci#define MAX8997_MODE_SHIFT		5
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/* Haptic driver configuration register */
278c2ecf20Sopenharmony_ci#define MAX8997_CYCLE_SHIFT		6
288c2ecf20Sopenharmony_ci#define MAX8997_SIG_PERIOD_SHIFT	4
298c2ecf20Sopenharmony_ci#define MAX8997_SIG_DUTY_SHIFT		2
308c2ecf20Sopenharmony_ci#define MAX8997_PWM_DUTY_SHIFT		0
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistruct max8997_haptic {
338c2ecf20Sopenharmony_ci	struct device *dev;
348c2ecf20Sopenharmony_ci	struct i2c_client *client;
358c2ecf20Sopenharmony_ci	struct input_dev *input_dev;
368c2ecf20Sopenharmony_ci	struct regulator *regulator;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	struct work_struct work;
398c2ecf20Sopenharmony_ci	struct mutex mutex;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	bool enabled;
428c2ecf20Sopenharmony_ci	unsigned int level;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	struct pwm_device *pwm;
458c2ecf20Sopenharmony_ci	unsigned int pwm_period;
468c2ecf20Sopenharmony_ci	enum max8997_haptic_pwm_divisor pwm_divisor;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	enum max8997_haptic_motor_type type;
498c2ecf20Sopenharmony_ci	enum max8997_haptic_pulse_mode mode;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	unsigned int internal_mode_pattern;
528c2ecf20Sopenharmony_ci	unsigned int pattern_cycle;
538c2ecf20Sopenharmony_ci	unsigned int pattern_signal_period;
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic int max8997_haptic_set_duty_cycle(struct max8997_haptic *chip)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	int ret = 0;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	if (chip->mode == MAX8997_EXTERNAL_MODE) {
618c2ecf20Sopenharmony_ci		unsigned int duty = chip->pwm_period * chip->level / 100;
628c2ecf20Sopenharmony_ci		ret = pwm_config(chip->pwm, duty, chip->pwm_period);
638c2ecf20Sopenharmony_ci	} else {
648c2ecf20Sopenharmony_ci		int i;
658c2ecf20Sopenharmony_ci		u8 duty_index = 0;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci		for (i = 0; i <= 64; i++) {
688c2ecf20Sopenharmony_ci			if (chip->level <= i * 100 / 64) {
698c2ecf20Sopenharmony_ci				duty_index = i;
708c2ecf20Sopenharmony_ci				break;
718c2ecf20Sopenharmony_ci			}
728c2ecf20Sopenharmony_ci		}
738c2ecf20Sopenharmony_ci		switch (chip->internal_mode_pattern) {
748c2ecf20Sopenharmony_ci		case 0:
758c2ecf20Sopenharmony_ci			max8997_write_reg(chip->client,
768c2ecf20Sopenharmony_ci				MAX8997_HAPTIC_REG_SIGPWMDC1, duty_index);
778c2ecf20Sopenharmony_ci			break;
788c2ecf20Sopenharmony_ci		case 1:
798c2ecf20Sopenharmony_ci			max8997_write_reg(chip->client,
808c2ecf20Sopenharmony_ci				MAX8997_HAPTIC_REG_SIGPWMDC2, duty_index);
818c2ecf20Sopenharmony_ci			break;
828c2ecf20Sopenharmony_ci		case 2:
838c2ecf20Sopenharmony_ci			max8997_write_reg(chip->client,
848c2ecf20Sopenharmony_ci				MAX8997_HAPTIC_REG_SIGPWMDC3, duty_index);
858c2ecf20Sopenharmony_ci			break;
868c2ecf20Sopenharmony_ci		case 3:
878c2ecf20Sopenharmony_ci			max8997_write_reg(chip->client,
888c2ecf20Sopenharmony_ci				MAX8997_HAPTIC_REG_SIGPWMDC4, duty_index);
898c2ecf20Sopenharmony_ci			break;
908c2ecf20Sopenharmony_ci		default:
918c2ecf20Sopenharmony_ci			break;
928c2ecf20Sopenharmony_ci		}
938c2ecf20Sopenharmony_ci	}
948c2ecf20Sopenharmony_ci	return ret;
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cistatic void max8997_haptic_configure(struct max8997_haptic *chip)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	u8 value;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	value = chip->type << MAX8997_MOTOR_TYPE_SHIFT |
1028c2ecf20Sopenharmony_ci		chip->enabled << MAX8997_ENABLE_SHIFT |
1038c2ecf20Sopenharmony_ci		chip->mode << MAX8997_MODE_SHIFT | chip->pwm_divisor;
1048c2ecf20Sopenharmony_ci	max8997_write_reg(chip->client, MAX8997_HAPTIC_REG_CONF2, value);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	if (chip->mode == MAX8997_INTERNAL_MODE && chip->enabled) {
1078c2ecf20Sopenharmony_ci		value = chip->internal_mode_pattern << MAX8997_CYCLE_SHIFT |
1088c2ecf20Sopenharmony_ci			chip->internal_mode_pattern << MAX8997_SIG_PERIOD_SHIFT |
1098c2ecf20Sopenharmony_ci			chip->internal_mode_pattern << MAX8997_SIG_DUTY_SHIFT |
1108c2ecf20Sopenharmony_ci			chip->internal_mode_pattern << MAX8997_PWM_DUTY_SHIFT;
1118c2ecf20Sopenharmony_ci		max8997_write_reg(chip->client,
1128c2ecf20Sopenharmony_ci			MAX8997_HAPTIC_REG_DRVCONF, value);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci		switch (chip->internal_mode_pattern) {
1158c2ecf20Sopenharmony_ci		case 0:
1168c2ecf20Sopenharmony_ci			value = chip->pattern_cycle << 4;
1178c2ecf20Sopenharmony_ci			max8997_write_reg(chip->client,
1188c2ecf20Sopenharmony_ci				MAX8997_HAPTIC_REG_CYCLECONF1, value);
1198c2ecf20Sopenharmony_ci			value = chip->pattern_signal_period;
1208c2ecf20Sopenharmony_ci			max8997_write_reg(chip->client,
1218c2ecf20Sopenharmony_ci				MAX8997_HAPTIC_REG_SIGCONF1, value);
1228c2ecf20Sopenharmony_ci			break;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci		case 1:
1258c2ecf20Sopenharmony_ci			value = chip->pattern_cycle;
1268c2ecf20Sopenharmony_ci			max8997_write_reg(chip->client,
1278c2ecf20Sopenharmony_ci				MAX8997_HAPTIC_REG_CYCLECONF1, value);
1288c2ecf20Sopenharmony_ci			value = chip->pattern_signal_period;
1298c2ecf20Sopenharmony_ci			max8997_write_reg(chip->client,
1308c2ecf20Sopenharmony_ci				MAX8997_HAPTIC_REG_SIGCONF2, value);
1318c2ecf20Sopenharmony_ci			break;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci		case 2:
1348c2ecf20Sopenharmony_ci			value = chip->pattern_cycle << 4;
1358c2ecf20Sopenharmony_ci			max8997_write_reg(chip->client,
1368c2ecf20Sopenharmony_ci				MAX8997_HAPTIC_REG_CYCLECONF2, value);
1378c2ecf20Sopenharmony_ci			value = chip->pattern_signal_period;
1388c2ecf20Sopenharmony_ci			max8997_write_reg(chip->client,
1398c2ecf20Sopenharmony_ci				MAX8997_HAPTIC_REG_SIGCONF3, value);
1408c2ecf20Sopenharmony_ci			break;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci		case 3:
1438c2ecf20Sopenharmony_ci			value = chip->pattern_cycle;
1448c2ecf20Sopenharmony_ci			max8997_write_reg(chip->client,
1458c2ecf20Sopenharmony_ci				MAX8997_HAPTIC_REG_CYCLECONF2, value);
1468c2ecf20Sopenharmony_ci			value = chip->pattern_signal_period;
1478c2ecf20Sopenharmony_ci			max8997_write_reg(chip->client,
1488c2ecf20Sopenharmony_ci				MAX8997_HAPTIC_REG_SIGCONF4, value);
1498c2ecf20Sopenharmony_ci			break;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci		default:
1528c2ecf20Sopenharmony_ci			break;
1538c2ecf20Sopenharmony_ci		}
1548c2ecf20Sopenharmony_ci	}
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic void max8997_haptic_enable(struct max8997_haptic *chip)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	int error;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	mutex_lock(&chip->mutex);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	error = max8997_haptic_set_duty_cycle(chip);
1648c2ecf20Sopenharmony_ci	if (error) {
1658c2ecf20Sopenharmony_ci		dev_err(chip->dev, "set_pwm_cycle failed, error: %d\n", error);
1668c2ecf20Sopenharmony_ci		goto out;
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	if (!chip->enabled) {
1708c2ecf20Sopenharmony_ci		error = regulator_enable(chip->regulator);
1718c2ecf20Sopenharmony_ci		if (error) {
1728c2ecf20Sopenharmony_ci			dev_err(chip->dev, "Failed to enable regulator\n");
1738c2ecf20Sopenharmony_ci			goto out;
1748c2ecf20Sopenharmony_ci		}
1758c2ecf20Sopenharmony_ci		max8997_haptic_configure(chip);
1768c2ecf20Sopenharmony_ci		if (chip->mode == MAX8997_EXTERNAL_MODE) {
1778c2ecf20Sopenharmony_ci			error = pwm_enable(chip->pwm);
1788c2ecf20Sopenharmony_ci			if (error) {
1798c2ecf20Sopenharmony_ci				dev_err(chip->dev, "Failed to enable PWM\n");
1808c2ecf20Sopenharmony_ci				regulator_disable(chip->regulator);
1818c2ecf20Sopenharmony_ci				goto out;
1828c2ecf20Sopenharmony_ci			}
1838c2ecf20Sopenharmony_ci		}
1848c2ecf20Sopenharmony_ci		chip->enabled = true;
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ciout:
1888c2ecf20Sopenharmony_ci	mutex_unlock(&chip->mutex);
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic void max8997_haptic_disable(struct max8997_haptic *chip)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	mutex_lock(&chip->mutex);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	if (chip->enabled) {
1968c2ecf20Sopenharmony_ci		chip->enabled = false;
1978c2ecf20Sopenharmony_ci		max8997_haptic_configure(chip);
1988c2ecf20Sopenharmony_ci		if (chip->mode == MAX8997_EXTERNAL_MODE)
1998c2ecf20Sopenharmony_ci			pwm_disable(chip->pwm);
2008c2ecf20Sopenharmony_ci		regulator_disable(chip->regulator);
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	mutex_unlock(&chip->mutex);
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic void max8997_haptic_play_effect_work(struct work_struct *work)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	struct max8997_haptic *chip =
2098c2ecf20Sopenharmony_ci			container_of(work, struct max8997_haptic, work);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	if (chip->level)
2128c2ecf20Sopenharmony_ci		max8997_haptic_enable(chip);
2138c2ecf20Sopenharmony_ci	else
2148c2ecf20Sopenharmony_ci		max8997_haptic_disable(chip);
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic int max8997_haptic_play_effect(struct input_dev *dev, void *data,
2188c2ecf20Sopenharmony_ci				  struct ff_effect *effect)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	struct max8997_haptic *chip = input_get_drvdata(dev);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	chip->level = effect->u.rumble.strong_magnitude;
2238c2ecf20Sopenharmony_ci	if (!chip->level)
2248c2ecf20Sopenharmony_ci		chip->level = effect->u.rumble.weak_magnitude;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	schedule_work(&chip->work);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	return 0;
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic void max8997_haptic_close(struct input_dev *dev)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	struct max8997_haptic *chip = input_get_drvdata(dev);
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	cancel_work_sync(&chip->work);
2368c2ecf20Sopenharmony_ci	max8997_haptic_disable(chip);
2378c2ecf20Sopenharmony_ci}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_cistatic int max8997_haptic_probe(struct platform_device *pdev)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
2428c2ecf20Sopenharmony_ci	const struct max8997_platform_data *pdata =
2438c2ecf20Sopenharmony_ci					dev_get_platdata(iodev->dev);
2448c2ecf20Sopenharmony_ci	const struct max8997_haptic_platform_data *haptic_pdata = NULL;
2458c2ecf20Sopenharmony_ci	struct max8997_haptic *chip;
2468c2ecf20Sopenharmony_ci	struct input_dev *input_dev;
2478c2ecf20Sopenharmony_ci	int error;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	if (pdata)
2508c2ecf20Sopenharmony_ci		haptic_pdata = pdata->haptic_pdata;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	if (!haptic_pdata) {
2538c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "no haptic platform data\n");
2548c2ecf20Sopenharmony_ci		return -EINVAL;
2558c2ecf20Sopenharmony_ci	}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	chip = kzalloc(sizeof(struct max8997_haptic), GFP_KERNEL);
2588c2ecf20Sopenharmony_ci	input_dev = input_allocate_device();
2598c2ecf20Sopenharmony_ci	if (!chip || !input_dev) {
2608c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "unable to allocate memory\n");
2618c2ecf20Sopenharmony_ci		error = -ENOMEM;
2628c2ecf20Sopenharmony_ci		goto err_free_mem;
2638c2ecf20Sopenharmony_ci	}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	INIT_WORK(&chip->work, max8997_haptic_play_effect_work);
2668c2ecf20Sopenharmony_ci	mutex_init(&chip->mutex);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	chip->client = iodev->haptic;
2698c2ecf20Sopenharmony_ci	chip->dev = &pdev->dev;
2708c2ecf20Sopenharmony_ci	chip->input_dev = input_dev;
2718c2ecf20Sopenharmony_ci	chip->pwm_period = haptic_pdata->pwm_period;
2728c2ecf20Sopenharmony_ci	chip->type = haptic_pdata->type;
2738c2ecf20Sopenharmony_ci	chip->mode = haptic_pdata->mode;
2748c2ecf20Sopenharmony_ci	chip->pwm_divisor = haptic_pdata->pwm_divisor;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	switch (chip->mode) {
2778c2ecf20Sopenharmony_ci	case MAX8997_INTERNAL_MODE:
2788c2ecf20Sopenharmony_ci		chip->internal_mode_pattern =
2798c2ecf20Sopenharmony_ci				haptic_pdata->internal_mode_pattern;
2808c2ecf20Sopenharmony_ci		chip->pattern_cycle = haptic_pdata->pattern_cycle;
2818c2ecf20Sopenharmony_ci		chip->pattern_signal_period =
2828c2ecf20Sopenharmony_ci				haptic_pdata->pattern_signal_period;
2838c2ecf20Sopenharmony_ci		break;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	case MAX8997_EXTERNAL_MODE:
2868c2ecf20Sopenharmony_ci		chip->pwm = pwm_request(haptic_pdata->pwm_channel_id,
2878c2ecf20Sopenharmony_ci					"max8997-haptic");
2888c2ecf20Sopenharmony_ci		if (IS_ERR(chip->pwm)) {
2898c2ecf20Sopenharmony_ci			error = PTR_ERR(chip->pwm);
2908c2ecf20Sopenharmony_ci			dev_err(&pdev->dev,
2918c2ecf20Sopenharmony_ci				"unable to request PWM for haptic, error: %d\n",
2928c2ecf20Sopenharmony_ci				error);
2938c2ecf20Sopenharmony_ci			goto err_free_mem;
2948c2ecf20Sopenharmony_ci		}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci		/*
2978c2ecf20Sopenharmony_ci		 * FIXME: pwm_apply_args() should be removed when switching to
2988c2ecf20Sopenharmony_ci		 * the atomic PWM API.
2998c2ecf20Sopenharmony_ci		 */
3008c2ecf20Sopenharmony_ci		pwm_apply_args(chip->pwm);
3018c2ecf20Sopenharmony_ci		break;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	default:
3048c2ecf20Sopenharmony_ci		dev_err(&pdev->dev,
3058c2ecf20Sopenharmony_ci			"Invalid chip mode specified (%d)\n", chip->mode);
3068c2ecf20Sopenharmony_ci		error = -EINVAL;
3078c2ecf20Sopenharmony_ci		goto err_free_mem;
3088c2ecf20Sopenharmony_ci	}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	chip->regulator = regulator_get(&pdev->dev, "inmotor");
3118c2ecf20Sopenharmony_ci	if (IS_ERR(chip->regulator)) {
3128c2ecf20Sopenharmony_ci		error = PTR_ERR(chip->regulator);
3138c2ecf20Sopenharmony_ci		dev_err(&pdev->dev,
3148c2ecf20Sopenharmony_ci			"unable to get regulator, error: %d\n",
3158c2ecf20Sopenharmony_ci			error);
3168c2ecf20Sopenharmony_ci		goto err_free_pwm;
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	input_dev->name = "max8997-haptic";
3208c2ecf20Sopenharmony_ci	input_dev->id.version = 1;
3218c2ecf20Sopenharmony_ci	input_dev->dev.parent = &pdev->dev;
3228c2ecf20Sopenharmony_ci	input_dev->close = max8997_haptic_close;
3238c2ecf20Sopenharmony_ci	input_set_drvdata(input_dev, chip);
3248c2ecf20Sopenharmony_ci	input_set_capability(input_dev, EV_FF, FF_RUMBLE);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	error = input_ff_create_memless(input_dev, NULL,
3278c2ecf20Sopenharmony_ci				max8997_haptic_play_effect);
3288c2ecf20Sopenharmony_ci	if (error) {
3298c2ecf20Sopenharmony_ci		dev_err(&pdev->dev,
3308c2ecf20Sopenharmony_ci			"unable to create FF device, error: %d\n",
3318c2ecf20Sopenharmony_ci			error);
3328c2ecf20Sopenharmony_ci		goto err_put_regulator;
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	error = input_register_device(input_dev);
3368c2ecf20Sopenharmony_ci	if (error) {
3378c2ecf20Sopenharmony_ci		dev_err(&pdev->dev,
3388c2ecf20Sopenharmony_ci			"unable to register input device, error: %d\n",
3398c2ecf20Sopenharmony_ci			error);
3408c2ecf20Sopenharmony_ci		goto err_destroy_ff;
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, chip);
3448c2ecf20Sopenharmony_ci	return 0;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cierr_destroy_ff:
3478c2ecf20Sopenharmony_ci	input_ff_destroy(input_dev);
3488c2ecf20Sopenharmony_cierr_put_regulator:
3498c2ecf20Sopenharmony_ci	regulator_put(chip->regulator);
3508c2ecf20Sopenharmony_cierr_free_pwm:
3518c2ecf20Sopenharmony_ci	if (chip->mode == MAX8997_EXTERNAL_MODE)
3528c2ecf20Sopenharmony_ci		pwm_free(chip->pwm);
3538c2ecf20Sopenharmony_cierr_free_mem:
3548c2ecf20Sopenharmony_ci	input_free_device(input_dev);
3558c2ecf20Sopenharmony_ci	kfree(chip);
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	return error;
3588c2ecf20Sopenharmony_ci}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_cistatic int max8997_haptic_remove(struct platform_device *pdev)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	struct max8997_haptic *chip = platform_get_drvdata(pdev);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	input_unregister_device(chip->input_dev);
3658c2ecf20Sopenharmony_ci	regulator_put(chip->regulator);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	if (chip->mode == MAX8997_EXTERNAL_MODE)
3688c2ecf20Sopenharmony_ci		pwm_free(chip->pwm);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	kfree(chip);
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	return 0;
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_cistatic int __maybe_unused max8997_haptic_suspend(struct device *dev)
3768c2ecf20Sopenharmony_ci{
3778c2ecf20Sopenharmony_ci	struct platform_device *pdev = to_platform_device(dev);
3788c2ecf20Sopenharmony_ci	struct max8997_haptic *chip = platform_get_drvdata(pdev);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	max8997_haptic_disable(chip);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	return 0;
3838c2ecf20Sopenharmony_ci}
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(max8997_haptic_pm_ops, max8997_haptic_suspend, NULL);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_cistatic const struct platform_device_id max8997_haptic_id[] = {
3888c2ecf20Sopenharmony_ci	{ "max8997-haptic", 0 },
3898c2ecf20Sopenharmony_ci	{ },
3908c2ecf20Sopenharmony_ci};
3918c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(platform, max8997_haptic_id);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_cistatic struct platform_driver max8997_haptic_driver = {
3948c2ecf20Sopenharmony_ci	.driver	= {
3958c2ecf20Sopenharmony_ci		.name	= "max8997-haptic",
3968c2ecf20Sopenharmony_ci		.pm	= &max8997_haptic_pm_ops,
3978c2ecf20Sopenharmony_ci	},
3988c2ecf20Sopenharmony_ci	.probe		= max8997_haptic_probe,
3998c2ecf20Sopenharmony_ci	.remove		= max8997_haptic_remove,
4008c2ecf20Sopenharmony_ci	.id_table	= max8997_haptic_id,
4018c2ecf20Sopenharmony_ci};
4028c2ecf20Sopenharmony_cimodule_platform_driver(max8997_haptic_driver);
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ciMODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
4058c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("max8997_haptic driver");
4068c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
407