162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * MAXIM MAX77693/MAX77843 Haptic device driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2014,2015 Samsung Electronics 662306a36Sopenharmony_ci * Jaewon Kim <jaewon02.kim@samsung.com> 762306a36Sopenharmony_ci * Krzysztof Kozlowski <krzk@kernel.org> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * This program is not provided / owned by Maxim Integrated Products. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/err.h> 1362306a36Sopenharmony_ci#include <linux/init.h> 1462306a36Sopenharmony_ci#include <linux/i2c.h> 1562306a36Sopenharmony_ci#include <linux/regmap.h> 1662306a36Sopenharmony_ci#include <linux/input.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/platform_device.h> 1962306a36Sopenharmony_ci#include <linux/pwm.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci#include <linux/workqueue.h> 2262306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 2362306a36Sopenharmony_ci#include <linux/mfd/max77693.h> 2462306a36Sopenharmony_ci#include <linux/mfd/max77693-common.h> 2562306a36Sopenharmony_ci#include <linux/mfd/max77693-private.h> 2662306a36Sopenharmony_ci#include <linux/mfd/max77843-private.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define MAX_MAGNITUDE_SHIFT 16 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cienum max77693_haptic_motor_type { 3162306a36Sopenharmony_ci MAX77693_HAPTIC_ERM = 0, 3262306a36Sopenharmony_ci MAX77693_HAPTIC_LRA, 3362306a36Sopenharmony_ci}; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cienum max77693_haptic_pulse_mode { 3662306a36Sopenharmony_ci MAX77693_HAPTIC_EXTERNAL_MODE = 0, 3762306a36Sopenharmony_ci MAX77693_HAPTIC_INTERNAL_MODE, 3862306a36Sopenharmony_ci}; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cienum max77693_haptic_pwm_divisor { 4162306a36Sopenharmony_ci MAX77693_HAPTIC_PWM_DIVISOR_32 = 0, 4262306a36Sopenharmony_ci MAX77693_HAPTIC_PWM_DIVISOR_64, 4362306a36Sopenharmony_ci MAX77693_HAPTIC_PWM_DIVISOR_128, 4462306a36Sopenharmony_ci MAX77693_HAPTIC_PWM_DIVISOR_256, 4562306a36Sopenharmony_ci}; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistruct max77693_haptic { 4862306a36Sopenharmony_ci enum max77693_types dev_type; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci struct regmap *regmap_pmic; 5162306a36Sopenharmony_ci struct regmap *regmap_haptic; 5262306a36Sopenharmony_ci struct device *dev; 5362306a36Sopenharmony_ci struct input_dev *input_dev; 5462306a36Sopenharmony_ci struct pwm_device *pwm_dev; 5562306a36Sopenharmony_ci struct regulator *motor_reg; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci bool enabled; 5862306a36Sopenharmony_ci bool suspend_state; 5962306a36Sopenharmony_ci unsigned int magnitude; 6062306a36Sopenharmony_ci unsigned int pwm_duty; 6162306a36Sopenharmony_ci enum max77693_haptic_motor_type type; 6262306a36Sopenharmony_ci enum max77693_haptic_pulse_mode mode; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci struct work_struct work; 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic int max77693_haptic_set_duty_cycle(struct max77693_haptic *haptic) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci struct pwm_args pargs; 7062306a36Sopenharmony_ci int delta; 7162306a36Sopenharmony_ci int error; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci pwm_get_args(haptic->pwm_dev, &pargs); 7462306a36Sopenharmony_ci delta = (pargs.period + haptic->pwm_duty) / 2; 7562306a36Sopenharmony_ci error = pwm_config(haptic->pwm_dev, delta, pargs.period); 7662306a36Sopenharmony_ci if (error) { 7762306a36Sopenharmony_ci dev_err(haptic->dev, "failed to configure pwm: %d\n", error); 7862306a36Sopenharmony_ci return error; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci return 0; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic int max77843_haptic_bias(struct max77693_haptic *haptic, bool on) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci int error; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (haptic->dev_type != TYPE_MAX77843) 8962306a36Sopenharmony_ci return 0; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci error = regmap_update_bits(haptic->regmap_haptic, 9262306a36Sopenharmony_ci MAX77843_SYS_REG_MAINCTRL1, 9362306a36Sopenharmony_ci MAX77843_MAINCTRL1_BIASEN_MASK, 9462306a36Sopenharmony_ci on << MAINCTRL1_BIASEN_SHIFT); 9562306a36Sopenharmony_ci if (error) { 9662306a36Sopenharmony_ci dev_err(haptic->dev, "failed to %s bias: %d\n", 9762306a36Sopenharmony_ci on ? "enable" : "disable", error); 9862306a36Sopenharmony_ci return error; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci return 0; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic int max77693_haptic_configure(struct max77693_haptic *haptic, 10562306a36Sopenharmony_ci bool enable) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci unsigned int value, config_reg; 10862306a36Sopenharmony_ci int error; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci switch (haptic->dev_type) { 11162306a36Sopenharmony_ci case TYPE_MAX77693: 11262306a36Sopenharmony_ci value = ((haptic->type << MAX77693_CONFIG2_MODE) | 11362306a36Sopenharmony_ci (enable << MAX77693_CONFIG2_MEN) | 11462306a36Sopenharmony_ci (haptic->mode << MAX77693_CONFIG2_HTYP) | 11562306a36Sopenharmony_ci MAX77693_HAPTIC_PWM_DIVISOR_128); 11662306a36Sopenharmony_ci config_reg = MAX77693_HAPTIC_REG_CONFIG2; 11762306a36Sopenharmony_ci break; 11862306a36Sopenharmony_ci case TYPE_MAX77843: 11962306a36Sopenharmony_ci value = (haptic->type << MCONFIG_MODE_SHIFT) | 12062306a36Sopenharmony_ci (enable << MCONFIG_MEN_SHIFT) | 12162306a36Sopenharmony_ci MAX77693_HAPTIC_PWM_DIVISOR_128; 12262306a36Sopenharmony_ci config_reg = MAX77843_HAP_REG_MCONFIG; 12362306a36Sopenharmony_ci break; 12462306a36Sopenharmony_ci default: 12562306a36Sopenharmony_ci return -EINVAL; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci error = regmap_write(haptic->regmap_haptic, 12962306a36Sopenharmony_ci config_reg, value); 13062306a36Sopenharmony_ci if (error) { 13162306a36Sopenharmony_ci dev_err(haptic->dev, 13262306a36Sopenharmony_ci "failed to update haptic config: %d\n", error); 13362306a36Sopenharmony_ci return error; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci return 0; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic int max77693_haptic_lowsys(struct max77693_haptic *haptic, bool enable) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci int error; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (haptic->dev_type != TYPE_MAX77693) 14462306a36Sopenharmony_ci return 0; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci error = regmap_update_bits(haptic->regmap_pmic, 14762306a36Sopenharmony_ci MAX77693_PMIC_REG_LSCNFG, 14862306a36Sopenharmony_ci MAX77693_PMIC_LOW_SYS_MASK, 14962306a36Sopenharmony_ci enable << MAX77693_PMIC_LOW_SYS_SHIFT); 15062306a36Sopenharmony_ci if (error) { 15162306a36Sopenharmony_ci dev_err(haptic->dev, "cannot update pmic regmap: %d\n", error); 15262306a36Sopenharmony_ci return error; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci return 0; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic void max77693_haptic_enable(struct max77693_haptic *haptic) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci int error; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (haptic->enabled) 16362306a36Sopenharmony_ci return; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci error = pwm_enable(haptic->pwm_dev); 16662306a36Sopenharmony_ci if (error) { 16762306a36Sopenharmony_ci dev_err(haptic->dev, 16862306a36Sopenharmony_ci "failed to enable haptic pwm device: %d\n", error); 16962306a36Sopenharmony_ci return; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci error = max77693_haptic_lowsys(haptic, true); 17362306a36Sopenharmony_ci if (error) 17462306a36Sopenharmony_ci goto err_enable_lowsys; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci error = max77693_haptic_configure(haptic, true); 17762306a36Sopenharmony_ci if (error) 17862306a36Sopenharmony_ci goto err_enable_config; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci haptic->enabled = true; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci return; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cierr_enable_config: 18562306a36Sopenharmony_ci max77693_haptic_lowsys(haptic, false); 18662306a36Sopenharmony_cierr_enable_lowsys: 18762306a36Sopenharmony_ci pwm_disable(haptic->pwm_dev); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic void max77693_haptic_disable(struct max77693_haptic *haptic) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci int error; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (!haptic->enabled) 19562306a36Sopenharmony_ci return; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci error = max77693_haptic_configure(haptic, false); 19862306a36Sopenharmony_ci if (error) 19962306a36Sopenharmony_ci return; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci error = max77693_haptic_lowsys(haptic, false); 20262306a36Sopenharmony_ci if (error) 20362306a36Sopenharmony_ci goto err_disable_lowsys; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci pwm_disable(haptic->pwm_dev); 20662306a36Sopenharmony_ci haptic->enabled = false; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci return; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cierr_disable_lowsys: 21162306a36Sopenharmony_ci max77693_haptic_configure(haptic, true); 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic void max77693_haptic_play_work(struct work_struct *work) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci struct max77693_haptic *haptic = 21762306a36Sopenharmony_ci container_of(work, struct max77693_haptic, work); 21862306a36Sopenharmony_ci int error; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci error = max77693_haptic_set_duty_cycle(haptic); 22162306a36Sopenharmony_ci if (error) { 22262306a36Sopenharmony_ci dev_err(haptic->dev, "failed to set duty cycle: %d\n", error); 22362306a36Sopenharmony_ci return; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (haptic->magnitude) 22762306a36Sopenharmony_ci max77693_haptic_enable(haptic); 22862306a36Sopenharmony_ci else 22962306a36Sopenharmony_ci max77693_haptic_disable(haptic); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic int max77693_haptic_play_effect(struct input_dev *dev, void *data, 23362306a36Sopenharmony_ci struct ff_effect *effect) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci struct max77693_haptic *haptic = input_get_drvdata(dev); 23662306a36Sopenharmony_ci struct pwm_args pargs; 23762306a36Sopenharmony_ci u64 period_mag_multi; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci haptic->magnitude = effect->u.rumble.strong_magnitude; 24062306a36Sopenharmony_ci if (!haptic->magnitude) 24162306a36Sopenharmony_ci haptic->magnitude = effect->u.rumble.weak_magnitude; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci /* 24462306a36Sopenharmony_ci * The magnitude comes from force-feedback interface. 24562306a36Sopenharmony_ci * The formula to convert magnitude to pwm_duty as follows: 24662306a36Sopenharmony_ci * - pwm_duty = (magnitude * pwm_period) / MAX_MAGNITUDE(0xFFFF) 24762306a36Sopenharmony_ci */ 24862306a36Sopenharmony_ci pwm_get_args(haptic->pwm_dev, &pargs); 24962306a36Sopenharmony_ci period_mag_multi = (u64)pargs.period * haptic->magnitude; 25062306a36Sopenharmony_ci haptic->pwm_duty = (unsigned int)(period_mag_multi >> 25162306a36Sopenharmony_ci MAX_MAGNITUDE_SHIFT); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci schedule_work(&haptic->work); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci return 0; 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic int max77693_haptic_open(struct input_dev *dev) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci struct max77693_haptic *haptic = input_get_drvdata(dev); 26162306a36Sopenharmony_ci int error; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci error = max77843_haptic_bias(haptic, true); 26462306a36Sopenharmony_ci if (error) 26562306a36Sopenharmony_ci return error; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci error = regulator_enable(haptic->motor_reg); 26862306a36Sopenharmony_ci if (error) { 26962306a36Sopenharmony_ci dev_err(haptic->dev, 27062306a36Sopenharmony_ci "failed to enable regulator: %d\n", error); 27162306a36Sopenharmony_ci return error; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci return 0; 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic void max77693_haptic_close(struct input_dev *dev) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci struct max77693_haptic *haptic = input_get_drvdata(dev); 28062306a36Sopenharmony_ci int error; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci cancel_work_sync(&haptic->work); 28362306a36Sopenharmony_ci max77693_haptic_disable(haptic); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci error = regulator_disable(haptic->motor_reg); 28662306a36Sopenharmony_ci if (error) 28762306a36Sopenharmony_ci dev_err(haptic->dev, 28862306a36Sopenharmony_ci "failed to disable regulator: %d\n", error); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci max77843_haptic_bias(haptic, false); 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic int max77693_haptic_probe(struct platform_device *pdev) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent); 29662306a36Sopenharmony_ci struct max77693_haptic *haptic; 29762306a36Sopenharmony_ci int error; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci haptic = devm_kzalloc(&pdev->dev, sizeof(*haptic), GFP_KERNEL); 30062306a36Sopenharmony_ci if (!haptic) 30162306a36Sopenharmony_ci return -ENOMEM; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci haptic->regmap_pmic = max77693->regmap; 30462306a36Sopenharmony_ci haptic->dev = &pdev->dev; 30562306a36Sopenharmony_ci haptic->type = MAX77693_HAPTIC_LRA; 30662306a36Sopenharmony_ci haptic->mode = MAX77693_HAPTIC_EXTERNAL_MODE; 30762306a36Sopenharmony_ci haptic->suspend_state = false; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* Variant-specific init */ 31062306a36Sopenharmony_ci haptic->dev_type = platform_get_device_id(pdev)->driver_data; 31162306a36Sopenharmony_ci switch (haptic->dev_type) { 31262306a36Sopenharmony_ci case TYPE_MAX77693: 31362306a36Sopenharmony_ci haptic->regmap_haptic = max77693->regmap_haptic; 31462306a36Sopenharmony_ci break; 31562306a36Sopenharmony_ci case TYPE_MAX77843: 31662306a36Sopenharmony_ci haptic->regmap_haptic = max77693->regmap; 31762306a36Sopenharmony_ci break; 31862306a36Sopenharmony_ci default: 31962306a36Sopenharmony_ci dev_err(&pdev->dev, "unsupported device type: %u\n", 32062306a36Sopenharmony_ci haptic->dev_type); 32162306a36Sopenharmony_ci return -EINVAL; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci INIT_WORK(&haptic->work, max77693_haptic_play_work); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci /* Get pwm and regulatot for haptic device */ 32762306a36Sopenharmony_ci haptic->pwm_dev = devm_pwm_get(&pdev->dev, NULL); 32862306a36Sopenharmony_ci if (IS_ERR(haptic->pwm_dev)) { 32962306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to get pwm device\n"); 33062306a36Sopenharmony_ci return PTR_ERR(haptic->pwm_dev); 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* 33462306a36Sopenharmony_ci * FIXME: pwm_apply_args() should be removed when switching to the 33562306a36Sopenharmony_ci * atomic PWM API. 33662306a36Sopenharmony_ci */ 33762306a36Sopenharmony_ci pwm_apply_args(haptic->pwm_dev); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci haptic->motor_reg = devm_regulator_get(&pdev->dev, "haptic"); 34062306a36Sopenharmony_ci if (IS_ERR(haptic->motor_reg)) { 34162306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to get regulator\n"); 34262306a36Sopenharmony_ci return PTR_ERR(haptic->motor_reg); 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* Initialize input device for haptic device */ 34662306a36Sopenharmony_ci haptic->input_dev = devm_input_allocate_device(&pdev->dev); 34762306a36Sopenharmony_ci if (!haptic->input_dev) { 34862306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to allocate input device\n"); 34962306a36Sopenharmony_ci return -ENOMEM; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci haptic->input_dev->name = "max77693-haptic"; 35362306a36Sopenharmony_ci haptic->input_dev->id.version = 1; 35462306a36Sopenharmony_ci haptic->input_dev->dev.parent = &pdev->dev; 35562306a36Sopenharmony_ci haptic->input_dev->open = max77693_haptic_open; 35662306a36Sopenharmony_ci haptic->input_dev->close = max77693_haptic_close; 35762306a36Sopenharmony_ci input_set_drvdata(haptic->input_dev, haptic); 35862306a36Sopenharmony_ci input_set_capability(haptic->input_dev, EV_FF, FF_RUMBLE); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci error = input_ff_create_memless(haptic->input_dev, NULL, 36162306a36Sopenharmony_ci max77693_haptic_play_effect); 36262306a36Sopenharmony_ci if (error) { 36362306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to create force-feedback\n"); 36462306a36Sopenharmony_ci return error; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci error = input_register_device(haptic->input_dev); 36862306a36Sopenharmony_ci if (error) { 36962306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to register input device\n"); 37062306a36Sopenharmony_ci return error; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci platform_set_drvdata(pdev, haptic); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci return 0; 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistatic int max77693_haptic_suspend(struct device *dev) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 38162306a36Sopenharmony_ci struct max77693_haptic *haptic = platform_get_drvdata(pdev); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (haptic->enabled) { 38462306a36Sopenharmony_ci max77693_haptic_disable(haptic); 38562306a36Sopenharmony_ci haptic->suspend_state = true; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci return 0; 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistatic int max77693_haptic_resume(struct device *dev) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 39462306a36Sopenharmony_ci struct max77693_haptic *haptic = platform_get_drvdata(pdev); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (haptic->suspend_state) { 39762306a36Sopenharmony_ci max77693_haptic_enable(haptic); 39862306a36Sopenharmony_ci haptic->suspend_state = false; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci return 0; 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(max77693_haptic_pm_ops, 40562306a36Sopenharmony_ci max77693_haptic_suspend, 40662306a36Sopenharmony_ci max77693_haptic_resume); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic const struct platform_device_id max77693_haptic_id[] = { 40962306a36Sopenharmony_ci { "max77693-haptic", TYPE_MAX77693 }, 41062306a36Sopenharmony_ci { "max77843-haptic", TYPE_MAX77843 }, 41162306a36Sopenharmony_ci {}, 41262306a36Sopenharmony_ci}; 41362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(platform, max77693_haptic_id); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic struct platform_driver max77693_haptic_driver = { 41662306a36Sopenharmony_ci .driver = { 41762306a36Sopenharmony_ci .name = "max77693-haptic", 41862306a36Sopenharmony_ci .pm = pm_sleep_ptr(&max77693_haptic_pm_ops), 41962306a36Sopenharmony_ci }, 42062306a36Sopenharmony_ci .probe = max77693_haptic_probe, 42162306a36Sopenharmony_ci .id_table = max77693_haptic_id, 42262306a36Sopenharmony_ci}; 42362306a36Sopenharmony_cimodule_platform_driver(max77693_haptic_driver); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ciMODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>"); 42662306a36Sopenharmony_ciMODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>"); 42762306a36Sopenharmony_ciMODULE_DESCRIPTION("MAXIM 77693/77843 Haptic driver"); 42862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 429