~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise

« back to all changes in this revision

Viewing changes to drivers/input/misc/twl6040-vibra.c

  • Committer: Bazaar Package Importer
  • Author(s): Paolo Pisati
  • Date: 2011-06-29 15:23:51 UTC
  • mfrom: (26.1.1 natty-proposed)
  • Revision ID: james.westby@ubuntu.com-20110629152351-xs96tm303d95rpbk
Tags: 3.0.0-1200.2
* Rebased against 3.0.0-6.7
* BSP from TI based on 3.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * twl6040-vibra.c - TWL6040 Vibrator driver
 
3
 *
 
4
 * Author:      Jorge Eduardo Candelaria <jorge.candelaria@ti.com>
 
5
 * Author:      Misael Lopez Cruz <misael.lopez@ti.com>
 
6
 *
 
7
 * Copyright:   (C) 2011 Texas Instruments, Inc.
 
8
 *
 
9
 * Based on twl4030-vibra.c by Henrik Saari <henrik.saari@nokia.com>
 
10
 *                              Felipe Balbi <felipe.balbi@nokia.com>
 
11
 *                              Jari Vanhala <ext-javi.vanhala@nokia.com>
 
12
 *
 
13
 * This program is free software; you can redistribute it and/or modify
 
14
 * it under the terms of the GNU General Public License version 2 as
 
15
 * published by the Free Software Foundation.
 
16
 *
 
17
 * This program is distributed in the hope that it will be useful, but
 
18
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
20
 * General Public License for more details.
 
21
 *
 
22
 * You should have received a copy of the GNU General Public License
 
23
 * along with this program; if not, write to the Free Software
 
24
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 
25
 * 02110-1301 USA
 
26
 *
 
27
 */
 
28
#include <linux/module.h>
 
29
#include <linux/platform_device.h>
 
30
#include <linux/workqueue.h>
 
31
#include <linux/i2c/twl.h>
 
32
#include <linux/mfd/twl6040.h>
 
33
#include <linux/slab.h>
 
34
#include <linux/delay.h>
 
35
#include <linux/regulator/consumer.h>
 
36
 
 
37
#define EFFECT_DIR_180_DEG      0x8000
 
38
 
 
39
/* Recommended modulation index 85% */
 
40
#define TWL6040_VIBRA_MOD       85
 
41
 
 
42
#define TWL6040_NUM_SUPPLIES 2
 
43
 
 
44
struct vibra_info {
 
45
        struct device *dev;
 
46
        struct input_dev *input_dev;
 
47
        struct workqueue_struct *workqueue;
 
48
        struct work_struct play_work;
 
49
        struct mutex mutex;
 
50
 
 
51
        bool enabled;
 
52
        int weak_speed;
 
53
        int strong_speed;
 
54
        int direction;
 
55
 
 
56
        unsigned int vibldrv_res;
 
57
        unsigned int vibrdrv_res;
 
58
        unsigned int viblmotor_res;
 
59
        unsigned int vibrmotor_res;
 
60
 
 
61
        struct regulator_bulk_data supplies[TWL6040_NUM_SUPPLIES];
 
62
 
 
63
        struct twl6040 *twl6040;
 
64
};
 
65
 
 
66
static irqreturn_t twl6040_vib_irq_handler(int irq, void *data)
 
67
{
 
68
        struct vibra_info *info = data;
 
69
        struct twl6040 *twl6040 = info->twl6040;
 
70
        u8 status;
 
71
 
 
72
        status = twl6040_reg_read(twl6040, TWL6040_REG_STATUS);
 
73
        if (status & TWL6040_VIBLOCDET) {
 
74
                dev_warn(info->dev, "Left Vibrator overcurrent detected\n");
 
75
                twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLL,
 
76
                                   TWL6040_VIBENAL);
 
77
        }
 
78
        if (status & TWL6040_VIBROCDET) {
 
79
                dev_warn(info->dev, "Right Vibrator overcurrent detected\n");
 
80
                twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLR,
 
81
                                   TWL6040_VIBENAR);
 
82
        }
 
83
 
 
84
        return IRQ_HANDLED;
 
85
}
 
86
 
 
87
static void twl6040_vibra_enable(struct vibra_info *info)
 
88
{
 
89
        struct twl6040 *twl6040 = info->twl6040;
 
90
        int ret;
 
91
 
 
92
        ret = regulator_bulk_enable(ARRAY_SIZE(info->supplies), info->supplies);
 
93
        if (ret) {
 
94
                dev_err(info->dev, "failed to enable regulators %d\n", ret);
 
95
                return;
 
96
        }
 
97
 
 
98
        twl6040_power(info->twl6040, 1);
 
99
        if (twl6040_get_rev(twl6040) <= TWL6040_REV_ES1_1) {
 
100
                /*
 
101
                 * ERRATA: Disable overcurrent protection for at least
 
102
                 * 3ms when enabling vibrator drivers to avoid false
 
103
                 * overcurrent detection
 
104
                 */
 
105
                twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL,
 
106
                                  TWL6040_VIBENAL | TWL6040_VIBCTRLL);
 
107
                twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR,
 
108
                                  TWL6040_VIBENAR | TWL6040_VIBCTRLR);
 
109
                usleep_range(3000, 3500);
 
110
        }
 
111
 
 
112
        twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL,
 
113
                          TWL6040_VIBENAL);
 
114
        twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR,
 
115
                          TWL6040_VIBENAR);
 
116
 
 
117
        info->enabled = true;
 
118
}
 
119
 
 
120
static void twl6040_vibra_disable(struct vibra_info *info)
 
121
{
 
122
        struct twl6040 *twl6040 = info->twl6040;
 
123
 
 
124
        twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL, 0x00);
 
125
        twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR, 0x00);
 
126
        twl6040_power(info->twl6040, 0);
 
127
 
 
128
        regulator_bulk_disable(ARRAY_SIZE(info->supplies), info->supplies);
 
129
 
 
130
        info->enabled = false;
 
131
}
 
132
 
 
133
static u8 twl6040_vibra_code(int vddvib, int vibdrv_res, int motor_res,
 
134
                             int speed, int direction)
 
135
{
 
136
        int vpk, max_code;
 
137
        u8 vibdat;
 
138
 
 
139
        /* output swing */
 
140
        vpk = (vddvib * motor_res * TWL6040_VIBRA_MOD) /
 
141
                (100 * (vibdrv_res + motor_res));
 
142
 
 
143
        /* 50mV per VIBDAT code step */
 
144
        max_code = vpk / 50;
 
145
        if (max_code > TWL6040_VIBDAT_MAX)
 
146
                max_code = TWL6040_VIBDAT_MAX;
 
147
 
 
148
        /* scale speed to max allowed code */
 
149
        vibdat = (u8)((speed * max_code) / USHRT_MAX);
 
150
 
 
151
        /* 2's complement for direction > 180 degrees */
 
152
        vibdat *= direction;
 
153
 
 
154
        return vibdat;
 
155
}
 
156
 
 
157
static void twl6040_vibra_set_effect(struct vibra_info *info)
 
158
{
 
159
        struct twl6040 *twl6040 = info->twl6040;
 
160
        u8 vibdatl, vibdatr;
 
161
        int volt;
 
162
 
 
163
        /* weak motor */
 
164
        volt = regulator_get_voltage(info->supplies[0].consumer) / 1000;
 
165
        vibdatl = twl6040_vibra_code(volt, info->vibldrv_res,
 
166
                                     info->viblmotor_res,
 
167
                                     info->weak_speed, info->direction);
 
168
 
 
169
        /* strong motor */
 
170
        volt = regulator_get_voltage(info->supplies[1].consumer) / 1000;
 
171
        vibdatr = twl6040_vibra_code(volt, info->vibrdrv_res,
 
172
                                     info->vibrmotor_res,
 
173
                                     info->strong_speed, info->direction);
 
174
 
 
175
        twl6040_reg_write(twl6040, TWL6040_REG_VIBDATL, vibdatl);
 
176
        twl6040_reg_write(twl6040, TWL6040_REG_VIBDATR, vibdatr);
 
177
}
 
178
 
 
179
static void vibra_play_work(struct work_struct *work)
 
180
{
 
181
        struct vibra_info *info = container_of(work,
 
182
                                struct vibra_info, play_work);
 
183
 
 
184
        mutex_lock(&info->mutex);
 
185
 
 
186
        if (info->weak_speed || info->strong_speed) {
 
187
                if (!info->enabled)
 
188
                        twl6040_vibra_enable(info);
 
189
 
 
190
                twl6040_vibra_set_effect(info);
 
191
        } else if (info->enabled)
 
192
                twl6040_vibra_disable(info);
 
193
 
 
194
        mutex_unlock(&info->mutex);
 
195
}
 
196
 
 
197
static int vibra_play(struct input_dev *input, void *data,
 
198
                      struct ff_effect *effect)
 
199
{
 
200
        struct vibra_info *info = input_get_drvdata(input);
 
201
        int ret;
 
202
 
 
203
        info->weak_speed = effect->u.rumble.weak_magnitude;
 
204
        info->strong_speed = effect->u.rumble.strong_magnitude;
 
205
        info->direction = effect->direction < EFFECT_DIR_180_DEG ? 1 : -1;
 
206
 
 
207
        ret = queue_work(info->workqueue, &info->play_work);
 
208
        if (!ret) {
 
209
                dev_info(&input->dev, "work is already on queue\n");
 
210
                return ret;
 
211
        }
 
212
 
 
213
        return 0;
 
214
}
 
215
 
 
216
static void twl6040_vibra_close(struct input_dev *input)
 
217
{
 
218
        struct vibra_info *info = input_get_drvdata(input);
 
219
 
 
220
        cancel_work_sync(&info->play_work);
 
221
 
 
222
        mutex_lock(&info->mutex);
 
223
 
 
224
        if (info->enabled)
 
225
                twl6040_vibra_disable(info);
 
226
 
 
227
        mutex_unlock(&info->mutex);
 
228
}
 
229
 
 
230
#if CONFIG_PM_SLEEP
 
231
static int twl6040_vibra_suspend(struct device *dev)
 
232
{
 
233
        struct platform_device *pdev = to_platform_device(dev);
 
234
        struct vibra_info *info = platform_get_drvdata(pdev);
 
235
 
 
236
        mutex_lock(&info->mutex);
 
237
 
 
238
        if (info->enabled)
 
239
                twl6040_vibra_disable(info);
 
240
 
 
241
        mutex_unlock(&info->mutex);
 
242
 
 
243
        return 0;
 
244
}
 
245
 
 
246
#endif
 
247
 
 
248
static SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops, twl6040_vibra_suspend, NULL);
 
249
 
 
250
static int __devinit twl6040_vibra_probe(struct platform_device *pdev)
 
251
{
 
252
        struct twl4030_vibra_data *pdata = pdev->dev.platform_data;
 
253
        struct vibra_info *info;
 
254
        int ret;
 
255
 
 
256
        if (!pdata) {
 
257
                dev_err(&pdev->dev, "platform_data not available\n");
 
258
                return -EINVAL;
 
259
        }
 
260
 
 
261
        info = kzalloc(sizeof(*info), GFP_KERNEL);
 
262
        if (!info) {
 
263
                dev_err(&pdev->dev, "couldn't allocate memory\n");
 
264
                return -ENOMEM;
 
265
        }
 
266
 
 
267
        info->dev = &pdev->dev;
 
268
        info->twl6040 = dev_get_drvdata(pdev->dev.parent);
 
269
        info->vibldrv_res = pdata->vibldrv_res;
 
270
        info->vibrdrv_res = pdata->vibrdrv_res;
 
271
        info->viblmotor_res = pdata->viblmotor_res;
 
272
        info->vibrmotor_res = pdata->vibrmotor_res;
 
273
        if ((!info->vibldrv_res && !info->viblmotor_res) ||
 
274
            (!info->vibrdrv_res && !info->vibrmotor_res)) {
 
275
                dev_err(info->dev, "invalid vibra driver/motor resistance\n");
 
276
                ret = -EINVAL;
 
277
                goto err_kzalloc;
 
278
        }
 
279
 
 
280
        mutex_init(&info->mutex);
 
281
 
 
282
        info->input_dev = input_allocate_device();
 
283
        if (info->input_dev == NULL) {
 
284
                dev_err(info->dev, "couldn't allocate input device\n");
 
285
                ret = -ENOMEM;
 
286
                goto err_kzalloc;
 
287
        }
 
288
 
 
289
        input_set_drvdata(info->input_dev, info);
 
290
 
 
291
        info->input_dev->name = "twl6040:vibrator";
 
292
        info->input_dev->id.version = 1;
 
293
        info->input_dev->dev.parent = pdev->dev.parent;
 
294
        info->input_dev->close = twl6040_vibra_close;
 
295
        __set_bit(FF_RUMBLE, info->input_dev->ffbit);
 
296
 
 
297
        ret = input_ff_create_memless(info->input_dev, NULL, vibra_play);
 
298
        if (ret < 0) {
 
299
                dev_err(info->dev, "couldn't register vibrator to FF\n");
 
300
                goto err_ialloc;
 
301
        }
 
302
 
 
303
        ret = input_register_device(info->input_dev);
 
304
        if (ret < 0) {
 
305
                dev_err(info->dev, "couldn't register input device\n");
 
306
                goto err_iff;
 
307
        }
 
308
 
 
309
        platform_set_drvdata(pdev, info);
 
310
 
 
311
        ret = twl6040_request_irq(info->twl6040, TWL6040_IRQ_VIB,
 
312
                                  twl6040_vib_irq_handler, 0,
 
313
                                  "twl6040_irq_vib", info);
 
314
        if (ret) {
 
315
                dev_err(info->dev, "VIB IRQ request failed: %d\n", ret);
 
316
                goto err_irq;
 
317
        }
 
318
 
 
319
        info->supplies[0].supply = "vddvibl";
 
320
        info->supplies[1].supply = "vddvibr";
 
321
        ret = regulator_bulk_get(info->dev, ARRAY_SIZE(info->supplies),
 
322
                                 info->supplies);
 
323
        if (ret) {
 
324
                dev_err(info->dev, "couldn't get regulators %d\n", ret);
 
325
                goto err_regulator;
 
326
        }
 
327
 
 
328
        if (pdata->vddvibl_uV) {
 
329
                ret = regulator_set_voltage(info->supplies[0].consumer,
 
330
                                            pdata->vddvibl_uV,
 
331
                                            pdata->vddvibl_uV);
 
332
                if (ret) {
 
333
                        dev_err(info->dev, "failed to set VDDVIBL volt %d\n",
 
334
                                ret);
 
335
                        goto err_voltage;
 
336
                }
 
337
        }
 
338
 
 
339
        if (pdata->vddvibr_uV) {
 
340
                ret = regulator_set_voltage(info->supplies[1].consumer,
 
341
                                            pdata->vddvibr_uV,
 
342
                                            pdata->vddvibr_uV);
 
343
                if (ret) {
 
344
                        dev_err(info->dev, "failed to set VDDVIBR volt %d\n",
 
345
                                ret);
 
346
                        goto err_voltage;
 
347
                }
 
348
        }
 
349
 
 
350
        info->workqueue = alloc_workqueue("twl6040-vibra", 0, 0);
 
351
        if (info->workqueue == NULL) {
 
352
                dev_err(info->dev, "couldn't create workqueue\n");
 
353
                ret = -ENOMEM;
 
354
                goto err_voltage;
 
355
        }
 
356
        INIT_WORK(&info->play_work, vibra_play_work);
 
357
 
 
358
        return 0;
 
359
 
 
360
err_voltage:
 
361
        regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies);
 
362
err_regulator:
 
363
        twl6040_free_irq(info->twl6040, TWL6040_IRQ_VIB, info);
 
364
err_irq:
 
365
        input_unregister_device(info->input_dev);
 
366
        info->input_dev = NULL;
 
367
err_iff:
 
368
        if (info->input_dev)
 
369
                input_ff_destroy(info->input_dev);
 
370
err_ialloc:
 
371
        input_free_device(info->input_dev);
 
372
err_kzalloc:
 
373
        kfree(info);
 
374
        return ret;
 
375
}
 
376
 
 
377
static int __devexit twl6040_vibra_remove(struct platform_device *pdev)
 
378
{
 
379
        struct vibra_info *info = platform_get_drvdata(pdev);
 
380
 
 
381
        input_unregister_device(info->input_dev);
 
382
        twl6040_free_irq(info->twl6040, TWL6040_IRQ_VIB, info);
 
383
        regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies);
 
384
        destroy_workqueue(info->workqueue);
 
385
        kfree(info);
 
386
 
 
387
        return 0;
 
388
}
 
389
 
 
390
static struct platform_driver twl6040_vibra_driver = {
 
391
        .probe          = twl6040_vibra_probe,
 
392
        .remove         = __devexit_p(twl6040_vibra_remove),
 
393
        .driver         = {
 
394
                .name   = "twl6040-vibra",
 
395
                .owner  = THIS_MODULE,
 
396
                .pm     = &twl6040_vibra_pm_ops,
 
397
        },
 
398
};
 
399
 
 
400
static int __init twl6040_vibra_init(void)
 
401
{
 
402
        return platform_driver_register(&twl6040_vibra_driver);
 
403
}
 
404
module_init(twl6040_vibra_init);
 
405
 
 
406
static void __exit twl6040_vibra_exit(void)
 
407
{
 
408
        platform_driver_unregister(&twl6040_vibra_driver);
 
409
}
 
410
module_exit(twl6040_vibra_exit);
 
411
 
 
412
MODULE_ALIAS("platform:twl6040-vibra");
 
413
MODULE_DESCRIPTION("TWL6040 Vibra driver");
 
414
MODULE_LICENSE("GPL");
 
415
MODULE_AUTHOR("Jorge Eduardo Candelaria <jorge.candelaria@ti.com>");
 
416
MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");