diff options
| author | Jaewon Kim <jaewon02.kim@samsung.com> | 2014-09-12 02:15:01 -0400 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2014-09-12 02:40:28 -0400 |
| commit | a3b3ca753cdc92c7d5f57404afed3115b3b79cc6 (patch) | |
| tree | de26e862cd43b9c2cb78eb06749145d3726b8e5c /drivers | |
| parent | adff5962fdd2f29bac943bc014ebd529444b2153 (diff) | |
Input: add haptic driver on max77693
This driver to supports the haptic controller on MAX77693 Multifunction
device with PMIC, CHARGER, LED, MUIC, HAPTIC.
This driver supports external pwm and LRA (Linear Resonant Actuator) motor.
User can control the haptic device via force feedback framework.
Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/input/misc/Kconfig | 11 | ||||
| -rw-r--r-- | drivers/input/misc/Makefile | 1 | ||||
| -rw-r--r-- | drivers/input/misc/max77693-haptic.c | 357 |
3 files changed, 369 insertions, 0 deletions
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 36382e5b7703..23297ab6163f 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig | |||
| @@ -144,6 +144,17 @@ config INPUT_M68K_BEEP | |||
| 144 | tristate "M68k Beeper support" | 144 | tristate "M68k Beeper support" |
| 145 | depends on M68K | 145 | depends on M68K |
| 146 | 146 | ||
| 147 | config INPUT_MAX77693_HAPTIC | ||
| 148 | tristate "MAXIM MAX77693 haptic controller support" | ||
| 149 | depends on MFD_MAX77693 && PWM | ||
| 150 | select INPUT_FF_MEMLESS | ||
| 151 | help | ||
| 152 | This option enables support for the haptic controller on | ||
| 153 | MAXIM MAX77693 chip. | ||
| 154 | |||
| 155 | To compile this driver as module, choose M here: the | ||
| 156 | module will be called max77693-haptic. | ||
| 157 | |||
| 147 | config INPUT_MAX8925_ONKEY | 158 | config INPUT_MAX8925_ONKEY |
| 148 | tristate "MAX8925 ONKEY support" | 159 | tristate "MAX8925 ONKEY support" |
| 149 | depends on MFD_MAX8925 | 160 | depends on MFD_MAX8925 |
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index e8b84d2c845f..19c760361f80 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile | |||
| @@ -37,6 +37,7 @@ obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o | |||
| 37 | obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o | 37 | obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o |
| 38 | obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o | 38 | obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o |
| 39 | obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o | 39 | obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o |
| 40 | obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o | ||
| 40 | obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o | 41 | obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o |
| 41 | obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o | 42 | obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o |
| 42 | obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o | 43 | obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o |
diff --git a/drivers/input/misc/max77693-haptic.c b/drivers/input/misc/max77693-haptic.c new file mode 100644 index 000000000000..d605db4d2f39 --- /dev/null +++ b/drivers/input/misc/max77693-haptic.c | |||
| @@ -0,0 +1,357 @@ | |||
| 1 | /* | ||
| 2 | * MAXIM MAX77693 Haptic device driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Samsung Electronics | ||
| 5 | * Jaewon Kim <jaewon02.kim@samsung.com> | ||
| 6 | * | ||
| 7 | * This program is not provided / owned by Maxim Integrated Products. | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License as published by | ||
| 11 | * the Free Software Foundation; either version 2 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/err.h> | ||
| 16 | #include <linux/init.h> | ||
| 17 | #include <linux/i2c.h> | ||
| 18 | #include <linux/regmap.h> | ||
| 19 | #include <linux/input.h> | ||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/platform_device.h> | ||
| 22 | #include <linux/pwm.h> | ||
| 23 | #include <linux/slab.h> | ||
| 24 | #include <linux/workqueue.h> | ||
| 25 | #include <linux/regulator/consumer.h> | ||
| 26 | #include <linux/mfd/max77693.h> | ||
| 27 | #include <linux/mfd/max77693-private.h> | ||
| 28 | |||
| 29 | #define MAX_MAGNITUDE_SHIFT 16 | ||
| 30 | |||
| 31 | enum max77693_haptic_motor_type { | ||
| 32 | MAX77693_HAPTIC_ERM = 0, | ||
| 33 | MAX77693_HAPTIC_LRA, | ||
| 34 | }; | ||
| 35 | |||
| 36 | enum max77693_haptic_pulse_mode { | ||
| 37 | MAX77693_HAPTIC_EXTERNAL_MODE = 0, | ||
| 38 | MAX77693_HAPTIC_INTERNAL_MODE, | ||
| 39 | }; | ||
| 40 | |||
| 41 | enum max77693_haptic_pwm_divisor { | ||
| 42 | MAX77693_HAPTIC_PWM_DIVISOR_32 = 0, | ||
| 43 | MAX77693_HAPTIC_PWM_DIVISOR_64, | ||
| 44 | MAX77693_HAPTIC_PWM_DIVISOR_128, | ||
| 45 | MAX77693_HAPTIC_PWM_DIVISOR_256, | ||
| 46 | }; | ||
| 47 | |||
| 48 | struct max77693_haptic { | ||
| 49 | struct regmap *regmap_pmic; | ||
| 50 | struct regmap *regmap_haptic; | ||
| 51 | struct device *dev; | ||
| 52 | struct input_dev *input_dev; | ||
| 53 | struct pwm_device *pwm_dev; | ||
| 54 | struct regulator *motor_reg; | ||
| 55 | |||
| 56 | bool enabled; | ||
| 57 | bool suspend_state; | ||
| 58 | unsigned int magnitude; | ||
| 59 | unsigned int pwm_duty; | ||
| 60 | enum max77693_haptic_motor_type type; | ||
| 61 | enum max77693_haptic_pulse_mode mode; | ||
| 62 | enum max77693_haptic_pwm_divisor pwm_divisor; | ||
| 63 | |||
| 64 | struct work_struct work; | ||
| 65 | }; | ||
| 66 | |||
| 67 | static int max77693_haptic_set_duty_cycle(struct max77693_haptic *haptic) | ||
| 68 | { | ||
| 69 | int delta = (haptic->pwm_dev->period + haptic->pwm_duty) / 2; | ||
| 70 | int error; | ||
| 71 | |||
| 72 | error = pwm_config(haptic->pwm_dev, delta, haptic->pwm_dev->period); | ||
| 73 | if (error) { | ||
| 74 | dev_err(haptic->dev, "failed to configure pwm: %d\n", error); | ||
| 75 | return error; | ||
| 76 | } | ||
| 77 | |||
| 78 | return 0; | ||
| 79 | } | ||
| 80 | |||
| 81 | static int max77693_haptic_configure(struct max77693_haptic *haptic, | ||
| 82 | bool enable) | ||
| 83 | { | ||
| 84 | unsigned int value; | ||
| 85 | int error; | ||
| 86 | |||
| 87 | value = ((haptic->type << MAX77693_CONFIG2_MODE) | | ||
| 88 | (enable << MAX77693_CONFIG2_MEN) | | ||
| 89 | (haptic->mode << MAX77693_CONFIG2_HTYP) | | ||
| 90 | (haptic->pwm_divisor)); | ||
| 91 | |||
| 92 | error = regmap_write(haptic->regmap_haptic, | ||
| 93 | MAX77693_HAPTIC_REG_CONFIG2, value); | ||
| 94 | if (error) { | ||
| 95 | dev_err(haptic->dev, | ||
| 96 | "failed to update haptic config: %d\n", error); | ||
| 97 | return error; | ||
| 98 | } | ||
| 99 | |||
| 100 | return 0; | ||
| 101 | } | ||
| 102 | |||
| 103 | static int max77693_haptic_lowsys(struct max77693_haptic *haptic, bool enable) | ||
| 104 | { | ||
| 105 | int error; | ||
| 106 | |||
| 107 | error = regmap_update_bits(haptic->regmap_pmic, | ||
| 108 | MAX77693_PMIC_REG_LSCNFG, | ||
| 109 | MAX77693_PMIC_LOW_SYS_MASK, | ||
| 110 | enable << MAX77693_PMIC_LOW_SYS_SHIFT); | ||
| 111 | if (error) { | ||
| 112 | dev_err(haptic->dev, "cannot update pmic regmap: %d\n", error); | ||
| 113 | return error; | ||
| 114 | } | ||
| 115 | |||
| 116 | return 0; | ||
| 117 | } | ||
| 118 | |||
| 119 | static void max77693_haptic_enable(struct max77693_haptic *haptic) | ||
| 120 | { | ||
| 121 | int error; | ||
| 122 | |||
| 123 | if (haptic->enabled) | ||
| 124 | return; | ||
| 125 | |||
| 126 | error = pwm_enable(haptic->pwm_dev); | ||
| 127 | if (error) { | ||
| 128 | dev_err(haptic->dev, | ||
| 129 | "failed to enable haptic pwm device: %d\n", error); | ||
| 130 | return; | ||
| 131 | } | ||
| 132 | |||
| 133 | error = max77693_haptic_lowsys(haptic, true); | ||
| 134 | if (error) | ||
| 135 | goto err_enable_lowsys; | ||
| 136 | |||
| 137 | error = max77693_haptic_configure(haptic, true); | ||
| 138 | if (error) | ||
| 139 | goto err_enable_config; | ||
| 140 | |||
| 141 | haptic->enabled = true; | ||
| 142 | |||
| 143 | return; | ||
| 144 | |||
| 145 | err_enable_config: | ||
| 146 | max77693_haptic_lowsys(haptic, false); | ||
| 147 | err_enable_lowsys: | ||
| 148 | pwm_disable(haptic->pwm_dev); | ||
| 149 | } | ||
| 150 | |||
| 151 | static void max77693_haptic_disable(struct max77693_haptic *haptic) | ||
| 152 | { | ||
| 153 | int error; | ||
| 154 | |||
| 155 | if (haptic->enabled) | ||
| 156 | return; | ||
| 157 | |||
| 158 | error = max77693_haptic_configure(haptic, false); | ||
| 159 | if (error) | ||
| 160 | return; | ||
| 161 | |||
| 162 | error = max77693_haptic_lowsys(haptic, false); | ||
| 163 | if (error) | ||
| 164 | goto err_disable_lowsys; | ||
| 165 | |||
| 166 | pwm_disable(haptic->pwm_dev); | ||
| 167 | |||
