Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.14 230 lines 5.6 kB view raw
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{ 147 struct pm8xxx_vib *vib; 148 struct input_dev *input_dev; 149 int error; 150 unsigned int val; 151 152 vib = devm_kzalloc(&pdev->dev, sizeof(*vib), GFP_KERNEL); 153 if (!vib) 154 return -ENOMEM; 155 156 vib->regmap = dev_get_regmap(pdev->dev.parent, NULL); 157 if (!vib->regmap) 158 return -ENODEV; 159 160 input_dev = devm_input_allocate_device(&pdev->dev); 161 if (!input_dev) 162 return -ENOMEM; 163 164 INIT_WORK(&vib->work, pm8xxx_work_handler); 165 vib->vib_input_dev = input_dev; 166 167 /* operate in manual mode */ 168 error = regmap_read(vib->regmap, VIB_DRV, &val); 169 if (error < 0) 170 return error; 171 172 val &= ~VIB_DRV_EN_MANUAL_MASK; 173 error = regmap_write(vib->regmap, VIB_DRV, val); 174 if (error < 0) 175 return error; 176 177 vib->reg_vib_drv = val; 178 179 input_dev->name = "pm8xxx_vib_ffmemless"; 180 input_dev->id.version = 1; 181 input_dev->close = pm8xxx_vib_close; 182 input_set_drvdata(input_dev, vib); 183 input_set_capability(vib->vib_input_dev, EV_FF, FF_RUMBLE); 184 185 error = input_ff_create_memless(input_dev, NULL, 186 pm8xxx_vib_play_effect); 187 if (error) { 188 dev_err(&pdev->dev, 189 "couldn't register vibrator as FF device\n"); 190 return error; 191 } 192 193 error = input_register_device(input_dev); 194 if (error) { 195 dev_err(&pdev->dev, "couldn't register input device\n"); 196 return error; 197 } 198 199 platform_set_drvdata(pdev, vib); 200 return 0; 201} 202 203#ifdef CONFIG_PM_SLEEP 204static int pm8xxx_vib_suspend(struct device *dev) 205{ 206 struct pm8xxx_vib *vib = dev_get_drvdata(dev); 207 208 /* Turn off the vibrator */ 209 pm8xxx_vib_set(vib, false); 210 211 return 0; 212} 213#endif 214 215static SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL); 216 217static struct platform_driver pm8xxx_vib_driver = { 218 .probe = pm8xxx_vib_probe, 219 .driver = { 220 .name = "pm8xxx-vib", 221 .owner = THIS_MODULE, 222 .pm = &pm8xxx_vib_pm_ops, 223 }, 224}; 225module_platform_driver(pm8xxx_vib_driver); 226 227MODULE_ALIAS("platform:pm8xxx_vib"); 228MODULE_DESCRIPTION("PMIC8xxx vibrator driver based on ff-memless framework"); 229MODULE_LICENSE("GPL v2"); 230MODULE_AUTHOR("Amy Maloche <amaloche@codeaurora.org>");