mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 09:44:51 +01:00
This was done entirely with mindless brute force, using
git grep -l '\<k[vmz]*alloc_objs*(.*, GFP_KERNEL)' |
xargs sed -i 's/\(alloc_objs*(.*\), GFP_KERNEL)/\1)/'
to convert the new alloc_obj() users that had a simple GFP_KERNEL
argument to just drop that argument.
Note that due to the extreme simplicity of the scripting, any slightly
more complex cases spread over multiple lines would not be triggered:
they definitely exist, but this covers the vast bulk of the cases, and
the resulting diff is also then easier to check automatically.
For the same reason the 'flex' versions will be done as a separate
conversion.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
392 lines
9.6 KiB
C
392 lines
9.6 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* MAX8997-haptic controller driver
|
|
*
|
|
* Copyright (C) 2012 Samsung Electronics
|
|
* Donggeun Kim <dg77.kim@samsung.com>
|
|
*
|
|
* This program is not provided / owned by Maxim Integrated Products.
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/err.h>
|
|
#include <linux/pwm.h>
|
|
#include <linux/input.h>
|
|
#include <linux/mfd/max8997-private.h>
|
|
#include <linux/mfd/max8997.h>
|
|
#include <linux/regulator/consumer.h>
|
|
|
|
/* Haptic configuration 2 register */
|
|
#define MAX8997_MOTOR_TYPE_SHIFT 7
|
|
#define MAX8997_ENABLE_SHIFT 6
|
|
#define MAX8997_MODE_SHIFT 5
|
|
|
|
/* Haptic driver configuration register */
|
|
#define MAX8997_CYCLE_SHIFT 6
|
|
#define MAX8997_SIG_PERIOD_SHIFT 4
|
|
#define MAX8997_SIG_DUTY_SHIFT 2
|
|
#define MAX8997_PWM_DUTY_SHIFT 0
|
|
|
|
struct max8997_haptic {
|
|
struct device *dev;
|
|
struct i2c_client *client;
|
|
struct input_dev *input_dev;
|
|
struct regulator *regulator;
|
|
|
|
struct work_struct work;
|
|
struct mutex mutex;
|
|
|
|
bool enabled;
|
|
unsigned int level;
|
|
|
|
struct pwm_device *pwm;
|
|
unsigned int pwm_period;
|
|
enum max8997_haptic_pwm_divisor pwm_divisor;
|
|
|
|
enum max8997_haptic_motor_type type;
|
|
enum max8997_haptic_pulse_mode mode;
|
|
|
|
unsigned int internal_mode_pattern;
|
|
unsigned int pattern_cycle;
|
|
unsigned int pattern_signal_period;
|
|
};
|
|
|
|
static void max8997_haptic_set_internal_duty_cycle(struct max8997_haptic *chip)
|
|
{
|
|
u8 duty_index = DIV_ROUND_UP(chip->level * 64, 100);
|
|
|
|
switch (chip->internal_mode_pattern) {
|
|
case 0:
|
|
max8997_write_reg(chip->client,
|
|
MAX8997_HAPTIC_REG_SIGPWMDC1, duty_index);
|
|
break;
|
|
case 1:
|
|
max8997_write_reg(chip->client,
|
|
MAX8997_HAPTIC_REG_SIGPWMDC2, duty_index);
|
|
break;
|
|
case 2:
|
|
max8997_write_reg(chip->client,
|
|
MAX8997_HAPTIC_REG_SIGPWMDC3, duty_index);
|
|
break;
|
|
case 3:
|
|
max8997_write_reg(chip->client,
|
|
MAX8997_HAPTIC_REG_SIGPWMDC4, duty_index);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void max8997_haptic_configure(struct max8997_haptic *chip)
|
|
{
|
|
u8 value;
|
|
|
|
value = chip->type << MAX8997_MOTOR_TYPE_SHIFT |
|
|
chip->enabled << MAX8997_ENABLE_SHIFT |
|
|
chip->mode << MAX8997_MODE_SHIFT | chip->pwm_divisor;
|
|
max8997_write_reg(chip->client, MAX8997_HAPTIC_REG_CONF2, value);
|
|
|
|
if (chip->mode == MAX8997_INTERNAL_MODE && chip->enabled) {
|
|
value = chip->internal_mode_pattern << MAX8997_CYCLE_SHIFT |
|
|
chip->internal_mode_pattern << MAX8997_SIG_PERIOD_SHIFT |
|
|
chip->internal_mode_pattern << MAX8997_SIG_DUTY_SHIFT |
|
|
chip->internal_mode_pattern << MAX8997_PWM_DUTY_SHIFT;
|
|
max8997_write_reg(chip->client,
|
|
MAX8997_HAPTIC_REG_DRVCONF, value);
|
|
|
|
switch (chip->internal_mode_pattern) {
|
|
case 0:
|
|
value = chip->pattern_cycle << 4;
|
|
max8997_write_reg(chip->client,
|
|
MAX8997_HAPTIC_REG_CYCLECONF1, value);
|
|
value = chip->pattern_signal_period;
|
|
max8997_write_reg(chip->client,
|
|
MAX8997_HAPTIC_REG_SIGCONF1, value);
|
|
break;
|
|
|
|
case 1:
|
|
value = chip->pattern_cycle;
|
|
max8997_write_reg(chip->client,
|
|
MAX8997_HAPTIC_REG_CYCLECONF1, value);
|
|
value = chip->pattern_signal_period;
|
|
max8997_write_reg(chip->client,
|
|
MAX8997_HAPTIC_REG_SIGCONF2, value);
|
|
break;
|
|
|
|
case 2:
|
|
value = chip->pattern_cycle << 4;
|
|
max8997_write_reg(chip->client,
|
|
MAX8997_HAPTIC_REG_CYCLECONF2, value);
|
|
value = chip->pattern_signal_period;
|
|
max8997_write_reg(chip->client,
|
|
MAX8997_HAPTIC_REG_SIGCONF3, value);
|
|
break;
|
|
|
|
case 3:
|
|
value = chip->pattern_cycle;
|
|
max8997_write_reg(chip->client,
|
|
MAX8997_HAPTIC_REG_CYCLECONF2, value);
|
|
value = chip->pattern_signal_period;
|
|
max8997_write_reg(chip->client,
|
|
MAX8997_HAPTIC_REG_SIGCONF4, value);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void max8997_haptic_enable(struct max8997_haptic *chip)
|
|
{
|
|
int error;
|
|
|
|
guard(mutex)(&chip->mutex);
|
|
|
|
if (chip->mode != MAX8997_EXTERNAL_MODE)
|
|
max8997_haptic_set_internal_duty_cycle(chip);
|
|
|
|
if (!chip->enabled) {
|
|
error = regulator_enable(chip->regulator);
|
|
if (error) {
|
|
dev_err(chip->dev, "Failed to enable regulator\n");
|
|
return;
|
|
}
|
|
max8997_haptic_configure(chip);
|
|
}
|
|
|
|
/*
|
|
* It would be more straight forward to configure the external PWM
|
|
* earlier i.e. when the internal duty_cycle is setup in internal mode.
|
|
* But historically this is done only after the regulator was enabled
|
|
* and max8997_haptic_configure() set the enable bit in
|
|
* MAX8997_HAPTIC_REG_CONF2. So better keep it this way.
|
|
*/
|
|
if (chip->mode == MAX8997_EXTERNAL_MODE) {
|
|
struct pwm_state state;
|
|
|
|
pwm_init_state(chip->pwm, &state);
|
|
state.period = chip->pwm_period;
|
|
state.duty_cycle = chip->pwm_period * chip->level / 100;
|
|
state.enabled = true;
|
|
|
|
error = pwm_apply_might_sleep(chip->pwm, &state);
|
|
if (error) {
|
|
dev_err(chip->dev, "Failed to enable PWM\n");
|
|
regulator_disable(chip->regulator);
|
|
return;
|
|
}
|
|
}
|
|
|
|
chip->enabled = true;
|
|
}
|
|
|
|
static void max8997_haptic_disable(struct max8997_haptic *chip)
|
|
{
|
|
guard(mutex)(&chip->mutex);
|
|
|
|
if (chip->enabled) {
|
|
chip->enabled = false;
|
|
max8997_haptic_configure(chip);
|
|
if (chip->mode == MAX8997_EXTERNAL_MODE)
|
|
pwm_disable(chip->pwm);
|
|
regulator_disable(chip->regulator);
|
|
}
|
|
}
|
|
|
|
static void max8997_haptic_play_effect_work(struct work_struct *work)
|
|
{
|
|
struct max8997_haptic *chip =
|
|
container_of(work, struct max8997_haptic, work);
|
|
|
|
if (chip->level)
|
|
max8997_haptic_enable(chip);
|
|
else
|
|
max8997_haptic_disable(chip);
|
|
}
|
|
|
|
static int max8997_haptic_play_effect(struct input_dev *dev, void *data,
|
|
struct ff_effect *effect)
|
|
{
|
|
struct max8997_haptic *chip = input_get_drvdata(dev);
|
|
|
|
chip->level = effect->u.rumble.strong_magnitude;
|
|
if (!chip->level)
|
|
chip->level = effect->u.rumble.weak_magnitude;
|
|
|
|
schedule_work(&chip->work);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void max8997_haptic_close(struct input_dev *dev)
|
|
{
|
|
struct max8997_haptic *chip = input_get_drvdata(dev);
|
|
|
|
cancel_work_sync(&chip->work);
|
|
max8997_haptic_disable(chip);
|
|
}
|
|
|
|
static int max8997_haptic_probe(struct platform_device *pdev)
|
|
{
|
|
struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
|
|
const struct max8997_platform_data *pdata =
|
|
dev_get_platdata(iodev->dev);
|
|
const struct max8997_haptic_platform_data *haptic_pdata = NULL;
|
|
struct max8997_haptic *chip;
|
|
struct input_dev *input_dev;
|
|
int error;
|
|
|
|
if (pdata)
|
|
haptic_pdata = pdata->haptic_pdata;
|
|
|
|
if (!haptic_pdata) {
|
|
dev_err(&pdev->dev, "no haptic platform data\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
chip = kzalloc_obj(*chip);
|
|
input_dev = input_allocate_device();
|
|
if (!chip || !input_dev) {
|
|
dev_err(&pdev->dev, "unable to allocate memory\n");
|
|
error = -ENOMEM;
|
|
goto err_free_mem;
|
|
}
|
|
|
|
INIT_WORK(&chip->work, max8997_haptic_play_effect_work);
|
|
mutex_init(&chip->mutex);
|
|
|
|
chip->client = iodev->haptic;
|
|
chip->dev = &pdev->dev;
|
|
chip->input_dev = input_dev;
|
|
chip->pwm_period = haptic_pdata->pwm_period;
|
|
chip->type = haptic_pdata->type;
|
|
chip->mode = haptic_pdata->mode;
|
|
chip->pwm_divisor = haptic_pdata->pwm_divisor;
|
|
|
|
switch (chip->mode) {
|
|
case MAX8997_INTERNAL_MODE:
|
|
chip->internal_mode_pattern =
|
|
haptic_pdata->internal_mode_pattern;
|
|
chip->pattern_cycle = haptic_pdata->pattern_cycle;
|
|
chip->pattern_signal_period =
|
|
haptic_pdata->pattern_signal_period;
|
|
break;
|
|
|
|
case MAX8997_EXTERNAL_MODE:
|
|
chip->pwm = pwm_get(&pdev->dev, NULL);
|
|
if (IS_ERR(chip->pwm)) {
|
|
error = PTR_ERR(chip->pwm);
|
|
dev_err(&pdev->dev,
|
|
"unable to request PWM for haptic, error: %d\n",
|
|
error);
|
|
goto err_free_mem;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
dev_err(&pdev->dev,
|
|
"Invalid chip mode specified (%d)\n", chip->mode);
|
|
error = -EINVAL;
|
|
goto err_free_mem;
|
|
}
|
|
|
|
chip->regulator = regulator_get(&pdev->dev, "inmotor");
|
|
if (IS_ERR(chip->regulator)) {
|
|
error = PTR_ERR(chip->regulator);
|
|
dev_err(&pdev->dev,
|
|
"unable to get regulator, error: %d\n",
|
|
error);
|
|
goto err_free_pwm;
|
|
}
|
|
|
|
input_dev->name = "max8997-haptic";
|
|
input_dev->id.version = 1;
|
|
input_dev->dev.parent = &pdev->dev;
|
|
input_dev->close = max8997_haptic_close;
|
|
input_set_drvdata(input_dev, chip);
|
|
input_set_capability(input_dev, EV_FF, FF_RUMBLE);
|
|
|
|
error = input_ff_create_memless(input_dev, NULL,
|
|
max8997_haptic_play_effect);
|
|
if (error) {
|
|
dev_err(&pdev->dev,
|
|
"unable to create FF device, error: %d\n",
|
|
error);
|
|
goto err_put_regulator;
|
|
}
|
|
|
|
error = input_register_device(input_dev);
|
|
if (error) {
|
|
dev_err(&pdev->dev,
|
|
"unable to register input device, error: %d\n",
|
|
error);
|
|
goto err_destroy_ff;
|
|
}
|
|
|
|
platform_set_drvdata(pdev, chip);
|
|
return 0;
|
|
|
|
err_destroy_ff:
|
|
input_ff_destroy(input_dev);
|
|
err_put_regulator:
|
|
regulator_put(chip->regulator);
|
|
err_free_pwm:
|
|
if (chip->mode == MAX8997_EXTERNAL_MODE)
|
|
pwm_put(chip->pwm);
|
|
err_free_mem:
|
|
input_free_device(input_dev);
|
|
kfree(chip);
|
|
|
|
return error;
|
|
}
|
|
|
|
static void max8997_haptic_remove(struct platform_device *pdev)
|
|
{
|
|
struct max8997_haptic *chip = platform_get_drvdata(pdev);
|
|
|
|
input_unregister_device(chip->input_dev);
|
|
regulator_put(chip->regulator);
|
|
|
|
if (chip->mode == MAX8997_EXTERNAL_MODE)
|
|
pwm_put(chip->pwm);
|
|
|
|
kfree(chip);
|
|
}
|
|
|
|
static int max8997_haptic_suspend(struct device *dev)
|
|
{
|
|
struct platform_device *pdev = to_platform_device(dev);
|
|
struct max8997_haptic *chip = platform_get_drvdata(pdev);
|
|
|
|
max8997_haptic_disable(chip);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static DEFINE_SIMPLE_DEV_PM_OPS(max8997_haptic_pm_ops,
|
|
max8997_haptic_suspend, NULL);
|
|
|
|
static const struct platform_device_id max8997_haptic_id[] = {
|
|
{ "max8997-haptic", 0 },
|
|
{ },
|
|
};
|
|
MODULE_DEVICE_TABLE(platform, max8997_haptic_id);
|
|
|
|
static struct platform_driver max8997_haptic_driver = {
|
|
.driver = {
|
|
.name = "max8997-haptic",
|
|
.pm = pm_sleep_ptr(&max8997_haptic_pm_ops),
|
|
},
|
|
.probe = max8997_haptic_probe,
|
|
.remove = max8997_haptic_remove,
|
|
.id_table = max8997_haptic_id,
|
|
};
|
|
module_platform_driver(max8997_haptic_driver);
|
|
|
|
MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
|
|
MODULE_DESCRIPTION("max8997_haptic driver");
|
|
MODULE_LICENSE("GPL");
|