cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

max8997_haptic.c (9840B)


      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 int max8997_haptic_set_duty_cycle(struct max8997_haptic *chip)
     57{
     58	int ret = 0;
     59
     60	if (chip->mode == MAX8997_EXTERNAL_MODE) {
     61		unsigned int duty = chip->pwm_period * chip->level / 100;
     62		ret = pwm_config(chip->pwm, duty, chip->pwm_period);
     63	} else {
     64		u8 duty_index = 0;
     65
     66		duty_index = DIV_ROUND_UP(chip->level * 64, 100);
     67
     68		switch (chip->internal_mode_pattern) {
     69		case 0:
     70			max8997_write_reg(chip->client,
     71				MAX8997_HAPTIC_REG_SIGPWMDC1, duty_index);
     72			break;
     73		case 1:
     74			max8997_write_reg(chip->client,
     75				MAX8997_HAPTIC_REG_SIGPWMDC2, duty_index);
     76			break;
     77		case 2:
     78			max8997_write_reg(chip->client,
     79				MAX8997_HAPTIC_REG_SIGPWMDC3, duty_index);
     80			break;
     81		case 3:
     82			max8997_write_reg(chip->client,
     83				MAX8997_HAPTIC_REG_SIGPWMDC4, duty_index);
     84			break;
     85		default:
     86			break;
     87		}
     88	}
     89	return ret;
     90}
     91
     92static void max8997_haptic_configure(struct max8997_haptic *chip)
     93{
     94	u8 value;
     95
     96	value = chip->type << MAX8997_MOTOR_TYPE_SHIFT |
     97		chip->enabled << MAX8997_ENABLE_SHIFT |
     98		chip->mode << MAX8997_MODE_SHIFT | chip->pwm_divisor;
     99	max8997_write_reg(chip->client, MAX8997_HAPTIC_REG_CONF2, value);
    100
    101	if (chip->mode == MAX8997_INTERNAL_MODE && chip->enabled) {
    102		value = chip->internal_mode_pattern << MAX8997_CYCLE_SHIFT |
    103			chip->internal_mode_pattern << MAX8997_SIG_PERIOD_SHIFT |
    104			chip->internal_mode_pattern << MAX8997_SIG_DUTY_SHIFT |
    105			chip->internal_mode_pattern << MAX8997_PWM_DUTY_SHIFT;
    106		max8997_write_reg(chip->client,
    107			MAX8997_HAPTIC_REG_DRVCONF, value);
    108
    109		switch (chip->internal_mode_pattern) {
    110		case 0:
    111			value = chip->pattern_cycle << 4;
    112			max8997_write_reg(chip->client,
    113				MAX8997_HAPTIC_REG_CYCLECONF1, value);
    114			value = chip->pattern_signal_period;
    115			max8997_write_reg(chip->client,
    116				MAX8997_HAPTIC_REG_SIGCONF1, value);
    117			break;
    118
    119		case 1:
    120			value = chip->pattern_cycle;
    121			max8997_write_reg(chip->client,
    122				MAX8997_HAPTIC_REG_CYCLECONF1, value);
    123			value = chip->pattern_signal_period;
    124			max8997_write_reg(chip->client,
    125				MAX8997_HAPTIC_REG_SIGCONF2, value);
    126			break;
    127
    128		case 2:
    129			value = chip->pattern_cycle << 4;
    130			max8997_write_reg(chip->client,
    131				MAX8997_HAPTIC_REG_CYCLECONF2, value);
    132			value = chip->pattern_signal_period;
    133			max8997_write_reg(chip->client,
    134				MAX8997_HAPTIC_REG_SIGCONF3, value);
    135			break;
    136
    137		case 3:
    138			value = chip->pattern_cycle;
    139			max8997_write_reg(chip->client,
    140				MAX8997_HAPTIC_REG_CYCLECONF2, value);
    141			value = chip->pattern_signal_period;
    142			max8997_write_reg(chip->client,
    143				MAX8997_HAPTIC_REG_SIGCONF4, value);
    144			break;
    145
    146		default:
    147			break;
    148		}
    149	}
    150}
    151
    152static void max8997_haptic_enable(struct max8997_haptic *chip)
    153{
    154	int error;
    155
    156	mutex_lock(&chip->mutex);
    157
    158	error = max8997_haptic_set_duty_cycle(chip);
    159	if (error) {
    160		dev_err(chip->dev, "set_pwm_cycle failed, error: %d\n", error);
    161		goto out;
    162	}
    163
    164	if (!chip->enabled) {
    165		error = regulator_enable(chip->regulator);
    166		if (error) {
    167			dev_err(chip->dev, "Failed to enable regulator\n");
    168			goto out;
    169		}
    170		max8997_haptic_configure(chip);
    171		if (chip->mode == MAX8997_EXTERNAL_MODE) {
    172			error = pwm_enable(chip->pwm);
    173			if (error) {
    174				dev_err(chip->dev, "Failed to enable PWM\n");
    175				regulator_disable(chip->regulator);
    176				goto out;
    177			}
    178		}
    179		chip->enabled = true;
    180	}
    181
    182out:
    183	mutex_unlock(&chip->mutex);
    184}
    185
    186static void max8997_haptic_disable(struct max8997_haptic *chip)
    187{
    188	mutex_lock(&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	mutex_unlock(&chip->mutex);
    199}
    200
    201static void max8997_haptic_play_effect_work(struct work_struct *work)
    202{
    203	struct max8997_haptic *chip =
    204			container_of(work, struct max8997_haptic, work);
    205
    206	if (chip->level)
    207		max8997_haptic_enable(chip);
    208	else
    209		max8997_haptic_disable(chip);
    210}
    211
    212static int max8997_haptic_play_effect(struct input_dev *dev, void *data,
    213				  struct ff_effect *effect)
    214{
    215	struct max8997_haptic *chip = input_get_drvdata(dev);
    216
    217	chip->level = effect->u.rumble.strong_magnitude;
    218	if (!chip->level)
    219		chip->level = effect->u.rumble.weak_magnitude;
    220
    221	schedule_work(&chip->work);
    222
    223	return 0;
    224}
    225
    226static void max8997_haptic_close(struct input_dev *dev)
    227{
    228	struct max8997_haptic *chip = input_get_drvdata(dev);
    229
    230	cancel_work_sync(&chip->work);
    231	max8997_haptic_disable(chip);
    232}
    233
    234static int max8997_haptic_probe(struct platform_device *pdev)
    235{
    236	struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
    237	const struct max8997_platform_data *pdata =
    238					dev_get_platdata(iodev->dev);
    239	const struct max8997_haptic_platform_data *haptic_pdata = NULL;
    240	struct max8997_haptic *chip;
    241	struct input_dev *input_dev;
    242	int error;
    243
    244	if (pdata)
    245		haptic_pdata = pdata->haptic_pdata;
    246
    247	if (!haptic_pdata) {
    248		dev_err(&pdev->dev, "no haptic platform data\n");
    249		return -EINVAL;
    250	}
    251
    252	chip = kzalloc(sizeof(struct max8997_haptic), GFP_KERNEL);
    253	input_dev = input_allocate_device();
    254	if (!chip || !input_dev) {
    255		dev_err(&pdev->dev, "unable to allocate memory\n");
    256		error = -ENOMEM;
    257		goto err_free_mem;
    258	}
    259
    260	INIT_WORK(&chip->work, max8997_haptic_play_effect_work);
    261	mutex_init(&chip->mutex);
    262
    263	chip->client = iodev->haptic;
    264	chip->dev = &pdev->dev;
    265	chip->input_dev = input_dev;
    266	chip->pwm_period = haptic_pdata->pwm_period;
    267	chip->type = haptic_pdata->type;
    268	chip->mode = haptic_pdata->mode;
    269	chip->pwm_divisor = haptic_pdata->pwm_divisor;
    270
    271	switch (chip->mode) {
    272	case MAX8997_INTERNAL_MODE:
    273		chip->internal_mode_pattern =
    274				haptic_pdata->internal_mode_pattern;
    275		chip->pattern_cycle = haptic_pdata->pattern_cycle;
    276		chip->pattern_signal_period =
    277				haptic_pdata->pattern_signal_period;
    278		break;
    279
    280	case MAX8997_EXTERNAL_MODE:
    281		chip->pwm = pwm_request(haptic_pdata->pwm_channel_id,
    282					"max8997-haptic");
    283		if (IS_ERR(chip->pwm)) {
    284			error = PTR_ERR(chip->pwm);
    285			dev_err(&pdev->dev,
    286				"unable to request PWM for haptic, error: %d\n",
    287				error);
    288			goto err_free_mem;
    289		}
    290
    291		/*
    292		 * FIXME: pwm_apply_args() should be removed when switching to
    293		 * the atomic PWM API.
    294		 */
    295		pwm_apply_args(chip->pwm);
    296		break;
    297
    298	default:
    299		dev_err(&pdev->dev,
    300			"Invalid chip mode specified (%d)\n", chip->mode);
    301		error = -EINVAL;
    302		goto err_free_mem;
    303	}
    304
    305	chip->regulator = regulator_get(&pdev->dev, "inmotor");
    306	if (IS_ERR(chip->regulator)) {
    307		error = PTR_ERR(chip->regulator);
    308		dev_err(&pdev->dev,
    309			"unable to get regulator, error: %d\n",
    310			error);
    311		goto err_free_pwm;
    312	}
    313
    314	input_dev->name = "max8997-haptic";
    315	input_dev->id.version = 1;
    316	input_dev->dev.parent = &pdev->dev;
    317	input_dev->close = max8997_haptic_close;
    318	input_set_drvdata(input_dev, chip);
    319	input_set_capability(input_dev, EV_FF, FF_RUMBLE);
    320
    321	error = input_ff_create_memless(input_dev, NULL,
    322				max8997_haptic_play_effect);
    323	if (error) {
    324		dev_err(&pdev->dev,
    325			"unable to create FF device, error: %d\n",
    326			error);
    327		goto err_put_regulator;
    328	}
    329
    330	error = input_register_device(input_dev);
    331	if (error) {
    332		dev_err(&pdev->dev,
    333			"unable to register input device, error: %d\n",
    334			error);
    335		goto err_destroy_ff;
    336	}
    337
    338	platform_set_drvdata(pdev, chip);
    339	return 0;
    340
    341err_destroy_ff:
    342	input_ff_destroy(input_dev);
    343err_put_regulator:
    344	regulator_put(chip->regulator);
    345err_free_pwm:
    346	if (chip->mode == MAX8997_EXTERNAL_MODE)
    347		pwm_free(chip->pwm);
    348err_free_mem:
    349	input_free_device(input_dev);
    350	kfree(chip);
    351
    352	return error;
    353}
    354
    355static int max8997_haptic_remove(struct platform_device *pdev)
    356{
    357	struct max8997_haptic *chip = platform_get_drvdata(pdev);
    358
    359	input_unregister_device(chip->input_dev);
    360	regulator_put(chip->regulator);
    361
    362	if (chip->mode == MAX8997_EXTERNAL_MODE)
    363		pwm_free(chip->pwm);
    364
    365	kfree(chip);
    366
    367	return 0;
    368}
    369
    370static int __maybe_unused max8997_haptic_suspend(struct device *dev)
    371{
    372	struct platform_device *pdev = to_platform_device(dev);
    373	struct max8997_haptic *chip = platform_get_drvdata(pdev);
    374
    375	max8997_haptic_disable(chip);
    376
    377	return 0;
    378}
    379
    380static SIMPLE_DEV_PM_OPS(max8997_haptic_pm_ops, max8997_haptic_suspend, NULL);
    381
    382static const struct platform_device_id max8997_haptic_id[] = {
    383	{ "max8997-haptic", 0 },
    384	{ },
    385};
    386MODULE_DEVICE_TABLE(platform, max8997_haptic_id);
    387
    388static struct platform_driver max8997_haptic_driver = {
    389	.driver	= {
    390		.name	= "max8997-haptic",
    391		.pm	= &max8997_haptic_pm_ops,
    392	},
    393	.probe		= max8997_haptic_probe,
    394	.remove		= max8997_haptic_remove,
    395	.id_table	= max8997_haptic_id,
    396};
    397module_platform_driver(max8997_haptic_driver);
    398
    399MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
    400MODULE_DESCRIPTION("max8997_haptic driver");
    401MODULE_LICENSE("GPL");