Version:  2.0.40 2.2.26 2.4.37 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 4.6 4.7 4.8 4.9 4.10

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         struct snd_soc_component *component =
 41                 snd_soc_dapm_to_component(arizona->dapm);
 42         int ret;
 43 
 44         if (!haptics->arizona->dapm) {
 45                 dev_err(arizona->dev, "No DAPM context\n");
 46                 return;
 47         }
 48 
 49         if (haptics->intensity) {
 50                 ret = regmap_update_bits(arizona->regmap,
 51                                          ARIZONA_HAPTICS_PHASE_2_INTENSITY,
 52                                          ARIZONA_PHASE2_INTENSITY_MASK,
 53                                          haptics->intensity);
 54                 if (ret != 0) {
 55                         dev_err(arizona->dev, "Failed to set intensity: %d\n",
 56                                 ret);
 57                         return;
 58                 }
 59 
 60                 /* This enable sequence will be a noop if already enabled */
 61                 ret = regmap_update_bits(arizona->regmap,
 62                                          ARIZONA_HAPTICS_CONTROL_1,
 63                                          ARIZONA_HAP_CTRL_MASK,
 64                                          1 << ARIZONA_HAP_CTRL_SHIFT);
 65                 if (ret != 0) {
 66                         dev_err(arizona->dev, "Failed to start haptics: %d\n",
 67                                 ret);
 68                         return;
 69                 }
 70 
 71                 ret = snd_soc_component_enable_pin(component, "HAPTICS");
 72                 if (ret != 0) {
 73                         dev_err(arizona->dev, "Failed to start HAPTICS: %d\n",
 74                                 ret);
 75                         return;
 76                 }
 77 
 78                 ret = snd_soc_dapm_sync(arizona->dapm);
 79                 if (ret != 0) {
 80                         dev_err(arizona->dev, "Failed to sync DAPM: %d\n",
 81                                 ret);
 82                         return;
 83                 }
 84         } else {
 85                 /* This disable sequence will be a noop if already enabled */
 86                 ret = snd_soc_component_disable_pin(component, "HAPTICS");
 87                 if (ret != 0) {
 88                         dev_err(arizona->dev, "Failed to disable HAPTICS: %d\n",
 89                                 ret);
 90                         return;
 91                 }
 92 
 93                 ret = snd_soc_dapm_sync(arizona->dapm);
 94                 if (ret != 0) {
 95                         dev_err(arizona->dev, "Failed to sync DAPM: %d\n",
 96                                 ret);
 97                         return;
 98                 }
 99 
100                 ret = regmap_update_bits(arizona->regmap,
101                                          ARIZONA_HAPTICS_CONTROL_1,
102                                          ARIZONA_HAP_CTRL_MASK, 0);
103                 if (ret != 0) {
104                         dev_err(arizona->dev, "Failed to stop haptics: %d\n",
105                                 ret);
106                         return;
107                 }
108         }
109 }
110 
111 static int arizona_haptics_play(struct input_dev *input, void *data,
112                                 struct ff_effect *effect)
113 {
114         struct arizona_haptics *haptics = input_get_drvdata(input);
115         struct arizona *arizona = haptics->arizona;
116 
117         if (!arizona->dapm) {
118                 dev_err(arizona->dev, "No DAPM context\n");
119                 return -EBUSY;
120         }
121 
122         if (effect->u.rumble.strong_magnitude) {
123                 /* Scale the magnitude into the range the device supports */
124                 if (arizona->pdata.hap_act) {
125                         haptics->intensity =
126                                 effect->u.rumble.strong_magnitude >> 9;
127                         if (effect->direction < 0x8000)
128                                 haptics->intensity += 0x7f;
129                 } else {
130                         haptics->intensity =
131                                 effect->u.rumble.strong_magnitude >> 8;
132                 }
133         } else {
134                 haptics->intensity = 0;
135         }
136 
137         schedule_work(&haptics->work);
138 
139         return 0;
140 }
141 
142 static void arizona_haptics_close(struct input_dev *input)
143 {
144         struct arizona_haptics *haptics = input_get_drvdata(input);
145         struct snd_soc_component *component;
146 
147         cancel_work_sync(&haptics->work);
148 
149         if (haptics->arizona->dapm) {
150                 component = snd_soc_dapm_to_component(haptics->arizona->dapm);
151                 snd_soc_component_disable_pin(component, "HAPTICS");
152         }
153 }
154 
155 static int arizona_haptics_probe(struct platform_device *pdev)
156 {
157         struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
158         struct arizona_haptics *haptics;
159         int ret;
160 
161         haptics = devm_kzalloc(&pdev->dev, sizeof(*haptics), GFP_KERNEL);
162         if (!haptics)
163                 return -ENOMEM;
164 
165         haptics->arizona = arizona;
166 
167         ret = regmap_update_bits(arizona->regmap, ARIZONA_HAPTICS_CONTROL_1,
168                                  ARIZONA_HAP_ACT, arizona->pdata.hap_act);
169         if (ret != 0) {
170                 dev_err(arizona->dev, "Failed to set haptics actuator: %d\n",
171                         ret);
172                 return ret;
173         }
174 
175         INIT_WORK(&haptics->work, arizona_haptics_work);
176 
177         haptics->input_dev = devm_input_allocate_device(&pdev->dev);
178         if (!haptics->input_dev) {
179                 dev_err(arizona->dev, "Failed to allocate input device\n");
180                 return -ENOMEM;
181         }
182 
183         input_set_drvdata(haptics->input_dev, haptics);
184 
185         haptics->input_dev->name = "arizona:haptics";
186         haptics->input_dev->close = arizona_haptics_close;
187         __set_bit(FF_RUMBLE, haptics->input_dev->ffbit);
188 
189         ret = input_ff_create_memless(haptics->input_dev, NULL,
190                                       arizona_haptics_play);
191         if (ret < 0) {
192                 dev_err(arizona->dev, "input_ff_create_memless() failed: %d\n",
193                         ret);
194                 return ret;
195         }
196 
197         ret = input_register_device(haptics->input_dev);
198         if (ret < 0) {
199                 dev_err(arizona->dev, "couldn't register input device: %d\n",
200                         ret);
201                 return ret;
202         }
203 
204         platform_set_drvdata(pdev, haptics);
205 
206         return 0;
207 }
208 
209 static struct platform_driver arizona_haptics_driver = {
210         .probe          = arizona_haptics_probe,
211         .driver         = {
212                 .name   = "arizona-haptics",
213         },
214 };
215 module_platform_driver(arizona_haptics_driver);
216 
217 MODULE_ALIAS("platform:arizona-haptics");
218 MODULE_DESCRIPTION("Arizona haptics driver");
219 MODULE_LICENSE("GPL");
220 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
221 

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