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> 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> 19#include <linux/regmap.h> 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 37 * @regmap: regmap for register read/write 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 */ 43struct pm8xxx_vib { 44 struct input_dev *vib_input_dev; 45 struct work_struct work; 46 struct regmap *regmap; 47 int speed; 48 int level; 49 bool active; 50 u8 reg_vib_drv; 51}; 52 53/** 54 * pm8xxx_vib_set - handler to start/stop vibration 55 * @vib: pointer to vibrator structure 56 * @on: state to set 57 */ 58static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on) 59{ 60 int rc; 61 unsigned int val = vib->reg_vib_drv; 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 68 rc = regmap_write(vib->regmap, VIB_DRV, val); 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 */ 80static void pm8xxx_work_handler(struct work_struct *work) 81{ 82 struct pm8xxx_vib *vib = container_of(work, struct pm8xxx_vib, work); 83 int rc; 84 unsigned int val; 85 86 rc = regmap_read(vib->regmap, VIB_DRV, &val); 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 */ 113static 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 */ 130static 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 144static int pm8xxx_vib_probe(struct platform_device *pdev) 145{ 146 struct pm8xxx_vib *vib; 147 struct input_dev *input_dev; 148 int error; 149 unsigned int val; 150 151 vib = devm_kzalloc(&pdev->dev, sizeof(*vib), GFP_KERNEL); 152 if (!vib) 153 return -ENOMEM; 154 155 vib->regmap = dev_get_regmap(pdev->dev.parent, NULL); 156 if (!vib->regmap) 157 return -ENODEV; 158 159 input_dev = devm_input_allocate_device(&pdev->dev); 160 if (!input_dev) 161 return -ENOMEM; 162 163 INIT_WORK(&vib->work, pm8xxx_work_handler); 164 vib->vib_input_dev = input_dev; 165 166 /* operate in manual mode */ 167 error = regmap_read(vib->regmap, VIB_DRV, &val); 168 if (error < 0) 169 return error; 170 171 val &= ~VIB_DRV_EN_MANUAL_MASK; 172 error = regmap_write(vib->regmap, VIB_DRV, val); 173 if (error < 0) 174 return error; 175 176 vib->reg_vib_drv = val; 177 178 input_dev->name = "pm8xxx_vib_ffmemless"; 179 input_dev->id.version = 1; 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"); 189 return error; 190 } 191 192 error = input_register_device(input_dev); 193 if (error) { 194 dev_err(&pdev->dev, "couldn't register input device\n"); 195 return error; 196 } 197 198 platform_set_drvdata(pdev, vib); 199 return 0; 200} 201 202static int __maybe_unused pm8xxx_vib_suspend(struct device *dev) 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} 211 212static SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL); 213 214static const struct of_device_id pm8xxx_vib_id_table[] = { 215 { .compatible = "qcom,pm8058-vib" }, 216 { .compatible = "qcom,pm8921-vib" }, 217 { } 218}; 219MODULE_DEVICE_TABLE(of, pm8xxx_vib_id_table); 220 221static struct platform_driver pm8xxx_vib_driver = { 222 .probe = pm8xxx_vib_probe, 223 .driver = { 224 .name = "pm8xxx-vib", 225 .pm = &pm8xxx_vib_pm_ops, 226 .of_match_table = pm8xxx_vib_id_table, 227 }, 228}; 229module_platform_driver(pm8xxx_vib_driver); 230 231MODULE_ALIAS("platform:pm8xxx_vib"); 232MODULE_DESCRIPTION("PMIC8xxx vibrator driver based on ff-memless framework"); 233MODULE_LICENSE("GPL v2"); 234MODULE_AUTHOR("Amy Maloche <amaloche@codeaurora.org>"); 235