Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 1 | /* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. |
| 2 | * |
| 3 | * This program is free software; you can redistribute it and/or modify |
| 4 | * it under the terms of the GNU General Public License version 2 and |
| 5 | * only version 2 as published by the Free Software Foundation. |
| 6 | * |
| 7 | * This program is distributed in the hope that it will be useful, |
| 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 10 | * GNU General Public License for more details. |
| 11 | */ |
| 12 | |
| 13 | #include <linux/module.h> |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 14 | #include <linux/kernel.h> |
| 15 | #include <linux/errno.h> |
| 16 | #include <linux/platform_device.h> |
| 17 | #include <linux/input.h> |
| 18 | #include <linux/slab.h> |
Stephen Boyd | 21014b8 | 2013-12-15 03:46:21 -0800 | [diff] [blame] | 19 | #include <linux/regmap.h> |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 20 | |
| 21 | #define VIB_DRV 0x4A |
| 22 | |
| 23 | #define VIB_DRV_SEL_MASK 0xf8 |
| 24 | #define VIB_DRV_SEL_SHIFT 0x03 |
| 25 | #define VIB_DRV_EN_MANUAL_MASK 0xfc |
| 26 | |
| 27 | #define VIB_MAX_LEVEL_mV (3100) |
| 28 | #define VIB_MIN_LEVEL_mV (1200) |
| 29 | #define VIB_MAX_LEVELS (VIB_MAX_LEVEL_mV - VIB_MIN_LEVEL_mV) |
| 30 | |
| 31 | #define MAX_FF_SPEED 0xff |
| 32 | |
| 33 | /** |
| 34 | * struct pm8xxx_vib - structure to hold vibrator data |
| 35 | * @vib_input_dev: input device supporting force feedback |
| 36 | * @work: work structure to set the vibration parameters |
Stephen Boyd | 21014b8 | 2013-12-15 03:46:21 -0800 | [diff] [blame] | 37 | * @regmap: regmap for register read/write |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 38 | * @speed: speed of vibration set from userland |
| 39 | * @active: state of vibrator |
| 40 | * @level: level of vibration to set in the chip |
| 41 | * @reg_vib_drv: VIB_DRV register value |
| 42 | */ |
| 43 | struct pm8xxx_vib { |
| 44 | struct input_dev *vib_input_dev; |
| 45 | struct work_struct work; |
Stephen Boyd | 21014b8 | 2013-12-15 03:46:21 -0800 | [diff] [blame] | 46 | struct regmap *regmap; |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 47 | int speed; |
| 48 | int level; |
| 49 | bool active; |
| 50 | u8 reg_vib_drv; |
| 51 | }; |
| 52 | |
| 53 | /** |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 54 | * pm8xxx_vib_set - handler to start/stop vibration |
| 55 | * @vib: pointer to vibrator structure |
| 56 | * @on: state to set |
| 57 | */ |
| 58 | static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on) |
| 59 | { |
| 60 | int rc; |
Stephen Boyd | 21014b8 | 2013-12-15 03:46:21 -0800 | [diff] [blame] | 61 | unsigned int val = vib->reg_vib_drv; |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 62 | |
| 63 | if (on) |
| 64 | val |= ((vib->level << VIB_DRV_SEL_SHIFT) & VIB_DRV_SEL_MASK); |
| 65 | else |
| 66 | val &= ~VIB_DRV_SEL_MASK; |
| 67 | |
Stephen Boyd | 21014b8 | 2013-12-15 03:46:21 -0800 | [diff] [blame] | 68 | rc = regmap_write(vib->regmap, VIB_DRV, val); |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 69 | if (rc < 0) |
| 70 | return rc; |
| 71 | |
| 72 | vib->reg_vib_drv = val; |
| 73 | return 0; |
| 74 | } |
| 75 | |
| 76 | /** |
| 77 | * pm8xxx_work_handler - worker to set vibration level |
| 78 | * @work: pointer to work_struct |
| 79 | */ |
| 80 | static void pm8xxx_work_handler(struct work_struct *work) |
| 81 | { |
| 82 | struct pm8xxx_vib *vib = container_of(work, struct pm8xxx_vib, work); |
| 83 | int rc; |
Stephen Boyd | 21014b8 | 2013-12-15 03:46:21 -0800 | [diff] [blame] | 84 | unsigned int val; |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 85 | |
Stephen Boyd | 21014b8 | 2013-12-15 03:46:21 -0800 | [diff] [blame] | 86 | rc = regmap_read(vib->regmap, VIB_DRV, &val); |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 87 | if (rc < 0) |
| 88 | return; |
| 89 | |
| 90 | /* |
| 91 | * pmic vibrator supports voltage ranges from 1.2 to 3.1V, so |
| 92 | * scale the level to fit into these ranges. |
| 93 | */ |
| 94 | if (vib->speed) { |
| 95 | vib->active = true; |
| 96 | vib->level = ((VIB_MAX_LEVELS * vib->speed) / MAX_FF_SPEED) + |
| 97 | VIB_MIN_LEVEL_mV; |
| 98 | vib->level /= 100; |
| 99 | } else { |
| 100 | vib->active = false; |
| 101 | vib->level = VIB_MIN_LEVEL_mV / 100; |
| 102 | } |
| 103 | |
| 104 | pm8xxx_vib_set(vib, vib->active); |
| 105 | } |
| 106 | |
| 107 | /** |
| 108 | * pm8xxx_vib_close - callback of input close callback |
| 109 | * @dev: input device pointer |
| 110 | * |
| 111 | * Turns off the vibrator. |
| 112 | */ |
| 113 | static void pm8xxx_vib_close(struct input_dev *dev) |
| 114 | { |
| 115 | struct pm8xxx_vib *vib = input_get_drvdata(dev); |
| 116 | |
| 117 | cancel_work_sync(&vib->work); |
| 118 | if (vib->active) |
| 119 | pm8xxx_vib_set(vib, false); |
| 120 | } |
| 121 | |
| 122 | /** |
| 123 | * pm8xxx_vib_play_effect - function to handle vib effects. |
| 124 | * @dev: input device pointer |
| 125 | * @data: data of effect |
| 126 | * @effect: effect to play |
| 127 | * |
| 128 | * Currently this driver supports only rumble effects. |
| 129 | */ |
| 130 | static int pm8xxx_vib_play_effect(struct input_dev *dev, void *data, |
| 131 | struct ff_effect *effect) |
| 132 | { |
| 133 | struct pm8xxx_vib *vib = input_get_drvdata(dev); |
| 134 | |
| 135 | vib->speed = effect->u.rumble.strong_magnitude >> 8; |
| 136 | if (!vib->speed) |
| 137 | vib->speed = effect->u.rumble.weak_magnitude >> 9; |
| 138 | |
| 139 | schedule_work(&vib->work); |
| 140 | |
| 141 | return 0; |
| 142 | } |
| 143 | |
Bill Pemberton | 5298cc4 | 2012-11-23 21:38:25 -0800 | [diff] [blame] | 144 | static int pm8xxx_vib_probe(struct platform_device *pdev) |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 145 | { |
| 146 | struct pm8xxx_vib *vib; |
| 147 | struct input_dev *input_dev; |
| 148 | int error; |
Stephen Boyd | 21014b8 | 2013-12-15 03:46:21 -0800 | [diff] [blame] | 149 | unsigned int val; |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 150 | |
Stephen Boyd | 12a5a8f | 2013-12-15 03:43:06 -0800 | [diff] [blame] | 151 | vib = devm_kzalloc(&pdev->dev, sizeof(*vib), GFP_KERNEL); |
| 152 | if (!vib) |
| 153 | return -ENOMEM; |
| 154 | |
Stephen Boyd | 21014b8 | 2013-12-15 03:46:21 -0800 | [diff] [blame] | 155 | vib->regmap = dev_get_regmap(pdev->dev.parent, NULL); |
| 156 | if (!vib->regmap) |
| 157 | return -ENODEV; |
| 158 | |
Stephen Boyd | 12a5a8f | 2013-12-15 03:43:06 -0800 | [diff] [blame] | 159 | input_dev = devm_input_allocate_device(&pdev->dev); |
| 160 | if (!input_dev) |
| 161 | return -ENOMEM; |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 162 | |
| 163 | INIT_WORK(&vib->work, pm8xxx_work_handler); |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 164 | vib->vib_input_dev = input_dev; |
| 165 | |
| 166 | /* operate in manual mode */ |
Stephen Boyd | 21014b8 | 2013-12-15 03:46:21 -0800 | [diff] [blame] | 167 | error = regmap_read(vib->regmap, VIB_DRV, &val); |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 168 | if (error < 0) |
Stephen Boyd | 12a5a8f | 2013-12-15 03:43:06 -0800 | [diff] [blame] | 169 | return error; |
| 170 | |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 171 | val &= ~VIB_DRV_EN_MANUAL_MASK; |
Stephen Boyd | 21014b8 | 2013-12-15 03:46:21 -0800 | [diff] [blame] | 172 | error = regmap_write(vib->regmap, VIB_DRV, val); |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 173 | if (error < 0) |
Stephen Boyd | 12a5a8f | 2013-12-15 03:43:06 -0800 | [diff] [blame] | 174 | return error; |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 175 | |
| 176 | vib->reg_vib_drv = val; |
| 177 | |
| 178 | input_dev->name = "pm8xxx_vib_ffmemless"; |
| 179 | input_dev->id.version = 1; |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 180 | input_dev->close = pm8xxx_vib_close; |
| 181 | input_set_drvdata(input_dev, vib); |
| 182 | input_set_capability(vib->vib_input_dev, EV_FF, FF_RUMBLE); |
| 183 | |
| 184 | error = input_ff_create_memless(input_dev, NULL, |
| 185 | pm8xxx_vib_play_effect); |
| 186 | if (error) { |
| 187 | dev_err(&pdev->dev, |
| 188 | "couldn't register vibrator as FF device\n"); |
Stephen Boyd | 12a5a8f | 2013-12-15 03:43:06 -0800 | [diff] [blame] | 189 | return error; |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 190 | } |
| 191 | |
| 192 | error = input_register_device(input_dev); |
| 193 | if (error) { |
| 194 | dev_err(&pdev->dev, "couldn't register input device\n"); |
Stephen Boyd | 12a5a8f | 2013-12-15 03:43:06 -0800 | [diff] [blame] | 195 | return error; |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 196 | } |
| 197 | |
| 198 | platform_set_drvdata(pdev, vib); |
| 199 | return 0; |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 200 | } |
| 201 | |
Jingoo Han | 97a652a | 2014-11-02 00:02:46 -0700 | [diff] [blame] | 202 | static int __maybe_unused pm8xxx_vib_suspend(struct device *dev) |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 203 | { |
| 204 | struct pm8xxx_vib *vib = dev_get_drvdata(dev); |
| 205 | |
| 206 | /* Turn off the vibrator */ |
| 207 | pm8xxx_vib_set(vib, false); |
| 208 | |
| 209 | return 0; |
| 210 | } |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 211 | |
| 212 | static SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL); |
| 213 | |
Stephen Boyd | 877e1f1 | 2014-03-29 12:44:14 -0700 | [diff] [blame] | 214 | static const struct of_device_id pm8xxx_vib_id_table[] = { |
| 215 | { .compatible = "qcom,pm8058-vib" }, |
| 216 | { .compatible = "qcom,pm8921-vib" }, |
| 217 | { } |
| 218 | }; |
| 219 | MODULE_DEVICE_TABLE(of, pm8xxx_vib_id_table); |
| 220 | |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 221 | static struct platform_driver pm8xxx_vib_driver = { |
| 222 | .probe = pm8xxx_vib_probe, |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 223 | .driver = { |
| 224 | .name = "pm8xxx-vib", |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 225 | .pm = &pm8xxx_vib_pm_ops, |
Stephen Boyd | 877e1f1 | 2014-03-29 12:44:14 -0700 | [diff] [blame] | 226 | .of_match_table = pm8xxx_vib_id_table, |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 227 | }, |
| 228 | }; |
JJ Ding | 840a746 | 2011-11-29 11:08:40 -0800 | [diff] [blame] | 229 | module_platform_driver(pm8xxx_vib_driver); |
Amy Maloche | 11205bb | 2011-08-01 23:41:44 -0700 | [diff] [blame] | 230 | |
| 231 | MODULE_ALIAS("platform:pm8xxx_vib"); |
| 232 | MODULE_DESCRIPTION("PMIC8xxx vibrator driver based on ff-memless framework"); |
| 233 | MODULE_LICENSE("GPL v2"); |
| 234 | MODULE_AUTHOR("Amy Maloche <amaloche@codeaurora.org>"); |