Version:  2.0.40 2.2.26 2.4.37 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4 4.5

Linux/drivers/input/misc/arizona-haptics.c

  1 /*
  2  * Arizona haptics driver
  3  *
  4  * Copyright 2012 Wolfson Microelectronics plc
  5  *
  6  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  7  *
  8  * This program is free software; you can redistribute it and/or modify
  9  * it under the terms of the GNU General Public License version 2 as
 10  * published by the Free Software Foundation.
 11  */
 12 
 13 #include <linux/module.h>
 14 #include <linux/platform_device.h>
 15 #include <linux/input.h>
 16 #include <linux/slab.h>
 17 
 18 #include <sound/soc.h>
 19 #include <sound/soc-dapm.h>
 20 
 21 #include <linux/mfd/arizona/core.h>
 22 #include <linux/mfd/arizona/pdata.h>
 23 #include <linux/mfd/arizona/registers.h>
 24 
 25 struct arizona_haptics {
 26         struct arizona *arizona;
 27         struct input_dev *input_dev;
 28         struct work_struct work;
 29 
 30         struct mutex mutex;
 31         u8 intensity;
 32 };
 33 
 34 static void arizona_haptics_work(struct work_struct *work)
 35 {
 36         struct arizona_haptics *haptics = container_of(work,
 37                                                        struct arizona_haptics,
 38                                                        work);
 39         struct arizona *arizona = haptics->arizona;
 40         int ret;
 41 
 42         if (!haptics->arizona->dapm) {
 43                 dev_err(arizona->dev, "No DAPM context\n");
 44                 return;
 45         }
 46 
 47         if (haptics->intensity) {
 48                 ret = regmap_update_bits(arizona->regmap,
 49                                          ARIZONA_HAPTICS_PHASE_2_INTENSITY,
 50                                          ARIZONA_PHASE2_INTENSITY_MASK,
 51                                          haptics->intensity);
 52                 if (ret != 0) {
 53                         dev_err(arizona->dev, "Failed to set intensity: %d\n",
 54                                 ret);
 55                         return;
 56                 }
 57 
 58                 /* This enable sequence will be a noop if already enabled */
 59                 ret = regmap_update_bits(arizona->regmap,
 60                                          ARIZONA_HAPTICS_CONTROL_1,
 61                                          ARIZONA_HAP_CTRL_MASK,
 62                                          1 << ARIZONA_HAP_CTRL_SHIFT);
 63                 if (ret != 0) {
 64                         dev_err(arizona->dev, "Failed to start haptics: %d\n",
 65                                 ret);
 66                         return;
 67                 }
 68 
 69                 ret = snd_soc_dapm_enable_pin(arizona->dapm, "HAPTICS");
 70                 if (ret != 0) {
 71                         dev_err(arizona->dev, "Failed to start HAPTICS: %d\n",
 72                                 ret);
 73                         return;
 74                 }
 75 
 76                 ret = snd_soc_dapm_sync(arizona->dapm);
 77                 if (ret != 0) {
 78                         dev_err(arizona->dev, "Failed to sync DAPM: %d\n",
 79                                 ret);
 80                         return;
 81                 }
 82         } else {
 83                 /* This disable sequence will be a noop if already enabled */
 84                 ret = snd_soc_dapm_disable_pin(arizona->dapm, "HAPTICS");
 85                 if (ret != 0) {
 86                         dev_err(arizona->dev, "Failed to disable HAPTICS: %d\n",
 87                                 ret);
 88                         return;
 89                 }
 90 
 91                 ret = snd_soc_dapm_sync(arizona->dapm);
 92                 if (ret != 0) {
 93                         dev_err(arizona->dev, "Failed to sync DAPM: %d\n",
 94                                 ret);
 95                         return;
 96                 }
 97 
 98                 ret = regmap_update_bits(arizona->regmap,
 99                                          ARIZONA_HAPTICS_CONTROL_1,
100                                          ARIZONA_HAP_CTRL_MASK, 0);
101                 if (ret != 0) {
102                         dev_err(arizona->dev, "Failed to stop haptics: %d\n",
103                                 ret);
104                         return;
105                 }
106         }
107 }
108 
109 static int arizona_haptics_play(struct input_dev *input, void *data,
110                                 struct ff_effect *effect)
111 {
112         struct arizona_haptics *haptics = input_get_drvdata(input);
113         struct arizona *arizona = haptics->arizona;
114 
115         if (!arizona->dapm) {
116                 dev_err(arizona->dev, "No DAPM context\n");
117                 return -EBUSY;
118         }
119 
120         if (effect->u.rumble.strong_magnitude) {
121                 /* Scale the magnitude into the range the device supports */
122                 if (arizona->pdata.hap_act) {
123                         haptics->intensity =
124                                 effect->u.rumble.strong_magnitude >> 9;
125                         if (effect->direction < 0x8000)
126                                 haptics->intensity += 0x7f;
127                 } else {
128                         haptics->intensity =
129                                 effect->u.rumble.strong_magnitude >> 8;
130                 }
131         } else {
132                 haptics->intensity = 0;
133         }
134 
135         schedule_work(&haptics->work);
136 
137         return 0;
138 }
139 
140 static void arizona_haptics_close(struct input_dev *input)
141 {
142         struct arizona_haptics *haptics = input_get_drvdata(input);
143 
144         cancel_work_sync(&haptics->work);
145 
146         if (haptics->arizona->dapm)
147                 snd_soc_dapm_disable_pin(haptics->arizona->dapm, "HAPTICS");
148 }
149 
150 static int arizona_haptics_probe(struct platform_device *pdev)
151 {
152         struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
153         struct arizona_haptics *haptics;
154         int ret;
155 
156         haptics = devm_kzalloc(&pdev->dev, sizeof(*haptics), GFP_KERNEL);
157         if (!haptics)
158                 return -ENOMEM;
159 
160         haptics->arizona = arizona;
161 
162         ret = regmap_update_bits(arizona->regmap, ARIZONA_HAPTICS_CONTROL_1,
163                                  ARIZONA_HAP_ACT, arizona->pdata.hap_act);
164         if (ret != 0) {
165                 dev_err(arizona->dev, "Failed to set haptics actuator: %d\n",
166                         ret);
167                 return ret;
168         }
169 
170         INIT_WORK(&haptics->work, arizona_haptics_work);
171 
172         haptics->input_dev = devm_input_allocate_device(&pdev->dev);
173         if (!haptics->input_dev) {
174                 dev_err(arizona->dev, "Failed to allocate input device\n");
175                 return -ENOMEM;
176         }
177 
178         input_set_drvdata(haptics->input_dev, haptics);
179 
180         haptics->input_dev->name = "arizona:haptics";
181         haptics->input_dev->dev.parent = pdev->dev.parent;
182         haptics->input_dev->close = arizona_haptics_close;
183         __set_bit(FF_RUMBLE, haptics->input_dev->ffbit);
184 
185         ret = input_ff_create_memless(haptics->input_dev, NULL,
186                                       arizona_haptics_play);
187         if (ret < 0) {
188                 dev_err(arizona->dev, "input_ff_create_memless() failed: %d\n",
189                         ret);
190                 return ret;
191         }
192 
193         ret = input_register_device(haptics->input_dev);
194         if (ret < 0) {
195                 dev_err(arizona->dev, "couldn't register input device: %d\n",
196                         ret);
197                 return ret;
198         }
199 
200         platform_set_drvdata(pdev, haptics);
201 
202         return 0;
203 }
204 
205 static struct platform_driver arizona_haptics_driver = {
206         .probe          = arizona_haptics_probe,
207         .driver         = {
208                 .name   = "arizona-haptics",
209         },
210 };
211 module_platform_driver(arizona_haptics_driver);
212 
213 MODULE_ALIAS("platform:arizona-haptics");
214 MODULE_DESCRIPTION("Arizona haptics driver");
215 MODULE_LICENSE("GPL");
216 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
217 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us