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