]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/mfd/twl6040-core.c
mfd: twl6040 code cleanup in interrupt initialization part
[mirror_ubuntu-bionic-kernel.git] / drivers / mfd / twl6040-core.c
CommitLineData
f19b2823
MLC
1/*
2 * MFD driver for TWL6040 audio device
3 *
4 * Authors: Misael Lopez Cruz <misael.lopez@ti.com>
5 * Jorge Eduardo Candelaria <jorge.candelaria@ti.com>
6 * Peter Ujfalusi <peter.ujfalusi@ti.com>
7 *
8 * Copyright: (C) 2011 Texas Instruments, Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301 USA
23 *
24 */
25
26#include <linux/module.h>
27#include <linux/types.h>
28#include <linux/slab.h>
29#include <linux/kernel.h>
5af7df6b 30#include <linux/err.h>
f19b2823
MLC
31#include <linux/platform_device.h>
32#include <linux/gpio.h>
33#include <linux/delay.h>
8eaeb939
PU
34#include <linux/i2c.h>
35#include <linux/regmap.h>
36#include <linux/err.h>
f19b2823
MLC
37#include <linux/mfd/core.h>
38#include <linux/mfd/twl6040.h>
5af7df6b 39#include <linux/regulator/consumer.h>
f19b2823 40
31b402e3 41#define VIBRACTRL_MEMBER(reg) ((reg == TWL6040_REG_VIBCTLL) ? 0 : 1)
5af7df6b 42#define TWL6040_NUM_SUPPLIES (2)
31b402e3 43
f19b2823
MLC
44int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg)
45{
46 int ret;
8eaeb939 47 unsigned int val;
f19b2823
MLC
48
49 mutex_lock(&twl6040->io_mutex);
31b402e3
PU
50 /* Vibra control registers from cache */
51 if (unlikely(reg == TWL6040_REG_VIBCTLL ||
52 reg == TWL6040_REG_VIBCTLR)) {
53 val = twl6040->vibra_ctrl_cache[VIBRACTRL_MEMBER(reg)];
54 } else {
8eaeb939 55 ret = regmap_read(twl6040->regmap, reg, &val);
31b402e3
PU
56 if (ret < 0) {
57 mutex_unlock(&twl6040->io_mutex);
58 return ret;
59 }
f19b2823
MLC
60 }
61 mutex_unlock(&twl6040->io_mutex);
62
63 return val;
64}
65EXPORT_SYMBOL(twl6040_reg_read);
66
67int twl6040_reg_write(struct twl6040 *twl6040, unsigned int reg, u8 val)
68{
69 int ret;
70
71 mutex_lock(&twl6040->io_mutex);
8eaeb939 72 ret = regmap_write(twl6040->regmap, reg, val);
31b402e3
PU
73 /* Cache the vibra control registers */
74 if (reg == TWL6040_REG_VIBCTLL || reg == TWL6040_REG_VIBCTLR)
75 twl6040->vibra_ctrl_cache[VIBRACTRL_MEMBER(reg)] = val;
f19b2823
MLC
76 mutex_unlock(&twl6040->io_mutex);
77
78 return ret;
79}
80EXPORT_SYMBOL(twl6040_reg_write);
81
82int twl6040_set_bits(struct twl6040 *twl6040, unsigned int reg, u8 mask)
83{
84 int ret;
f19b2823
MLC
85
86 mutex_lock(&twl6040->io_mutex);
8eaeb939 87 ret = regmap_update_bits(twl6040->regmap, reg, mask, mask);
f19b2823
MLC
88 mutex_unlock(&twl6040->io_mutex);
89 return ret;
90}
91EXPORT_SYMBOL(twl6040_set_bits);
92
93int twl6040_clear_bits(struct twl6040 *twl6040, unsigned int reg, u8 mask)
94{
95 int ret;
f19b2823
MLC
96
97 mutex_lock(&twl6040->io_mutex);
8eaeb939 98 ret = regmap_update_bits(twl6040->regmap, reg, mask, 0);
f19b2823
MLC
99 mutex_unlock(&twl6040->io_mutex);
100 return ret;
101}
102EXPORT_SYMBOL(twl6040_clear_bits);
103
104/* twl6040 codec manual power-up sequence */
105static int twl6040_power_up(struct twl6040 *twl6040)
106{
107 u8 ldoctl, ncpctl, lppllctl;
108 int ret;
109
110 /* enable high-side LDO, reference system and internal oscillator */
111 ldoctl = TWL6040_HSLDOENA | TWL6040_REFENA | TWL6040_OSCENA;
112 ret = twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
113 if (ret)
114 return ret;
115 usleep_range(10000, 10500);
116
117 /* enable negative charge pump */
118 ncpctl = TWL6040_NCPENA;
119 ret = twl6040_reg_write(twl6040, TWL6040_REG_NCPCTL, ncpctl);
120 if (ret)
121 goto ncp_err;
122 usleep_range(1000, 1500);
123
124 /* enable low-side LDO */
125 ldoctl |= TWL6040_LSLDOENA;
126 ret = twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
127 if (ret)
128 goto lsldo_err;
129 usleep_range(1000, 1500);
130
131 /* enable low-power PLL */
132 lppllctl = TWL6040_LPLLENA;
133 ret = twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
134 if (ret)
135 goto lppll_err;
136 usleep_range(5000, 5500);
137
138 /* disable internal oscillator */
139 ldoctl &= ~TWL6040_OSCENA;
140 ret = twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
141 if (ret)
142 goto osc_err;
143
144 return 0;
145
146osc_err:
147 lppllctl &= ~TWL6040_LPLLENA;
148 twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
149lppll_err:
150 ldoctl &= ~TWL6040_LSLDOENA;
151 twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
152lsldo_err:
153 ncpctl &= ~TWL6040_NCPENA;
154 twl6040_reg_write(twl6040, TWL6040_REG_NCPCTL, ncpctl);
155ncp_err:
156 ldoctl &= ~(TWL6040_HSLDOENA | TWL6040_REFENA | TWL6040_OSCENA);
157 twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
158
159 return ret;
160}
161
162/* twl6040 manual power-down sequence */
163static void twl6040_power_down(struct twl6040 *twl6040)
164{
165 u8 ncpctl, ldoctl, lppllctl;
166
167 ncpctl = twl6040_reg_read(twl6040, TWL6040_REG_NCPCTL);
168 ldoctl = twl6040_reg_read(twl6040, TWL6040_REG_LDOCTL);
169 lppllctl = twl6040_reg_read(twl6040, TWL6040_REG_LPPLLCTL);
170
171 /* enable internal oscillator */
172 ldoctl |= TWL6040_OSCENA;
173 twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
174 usleep_range(1000, 1500);
175
176 /* disable low-power PLL */
177 lppllctl &= ~TWL6040_LPLLENA;
178 twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
179
180 /* disable low-side LDO */
181 ldoctl &= ~TWL6040_LSLDOENA;
182 twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
183
184 /* disable negative charge pump */
185 ncpctl &= ~TWL6040_NCPENA;
186 twl6040_reg_write(twl6040, TWL6040_REG_NCPCTL, ncpctl);
187
188 /* disable high-side LDO, reference system and internal oscillator */
189 ldoctl &= ~(TWL6040_HSLDOENA | TWL6040_REFENA | TWL6040_OSCENA);
190 twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
191}
192
193static irqreturn_t twl6040_naudint_handler(int irq, void *data)
194{
195 struct twl6040 *twl6040 = data;
196 u8 intid, status;
197
198 intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID);
199
200 if (intid & TWL6040_READYINT)
201 complete(&twl6040->ready);
202
203 if (intid & TWL6040_THINT) {
204 status = twl6040_reg_read(twl6040, TWL6040_REG_STATUS);
205 if (status & TWL6040_TSHUTDET) {
2d7c957e 206 dev_warn(twl6040->dev,
f19b2823
MLC
207 "Thermal shutdown, powering-off");
208 twl6040_power(twl6040, 0);
209 } else {
2d7c957e 210 dev_warn(twl6040->dev,
f19b2823
MLC
211 "Leaving thermal shutdown, powering-on");
212 twl6040_power(twl6040, 1);
213 }
214 }
215
216 return IRQ_HANDLED;
217}
218
219static int twl6040_power_up_completion(struct twl6040 *twl6040,
220 int naudint)
221{
222 int time_left;
223 u8 intid;
224
225 time_left = wait_for_completion_timeout(&twl6040->ready,
226 msecs_to_jiffies(144));
227 if (!time_left) {
228 intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID);
229 if (!(intid & TWL6040_READYINT)) {
2d7c957e 230 dev_err(twl6040->dev,
f19b2823
MLC
231 "timeout waiting for READYINT\n");
232 return -ETIMEDOUT;
233 }
234 }
235
236 return 0;
237}
238
239int twl6040_power(struct twl6040 *twl6040, int on)
240{
241 int audpwron = twl6040->audpwron;
242 int naudint = twl6040->irq;
243 int ret = 0;
244
245 mutex_lock(&twl6040->mutex);
246
247 if (on) {
248 /* already powered-up */
249 if (twl6040->power_count++)
250 goto out;
251
252 if (gpio_is_valid(audpwron)) {
253 /* use AUDPWRON line */
254 gpio_set_value(audpwron, 1);
255 /* wait for power-up completion */
256 ret = twl6040_power_up_completion(twl6040, naudint);
257 if (ret) {
2d7c957e 258 dev_err(twl6040->dev,
f19b2823
MLC
259 "automatic power-down failed\n");
260 twl6040->power_count = 0;
261 goto out;
262 }
263 } else {
264 /* use manual power-up sequence */
265 ret = twl6040_power_up(twl6040);
266 if (ret) {
2d7c957e 267 dev_err(twl6040->dev,
f19b2823
MLC
268 "manual power-up failed\n");
269 twl6040->power_count = 0;
270 goto out;
271 }
272 }
cfb7a33b
PU
273 /* Default PLL configuration after power up */
274 twl6040->pll = TWL6040_SYSCLK_SEL_LPPLL;
f19b2823 275 twl6040->sysclk = 19200000;
f8447d6c 276 twl6040->mclk = 32768;
f19b2823
MLC
277 } else {
278 /* already powered-down */
279 if (!twl6040->power_count) {
2d7c957e 280 dev_err(twl6040->dev,
f19b2823
MLC
281 "device is already powered-off\n");
282 ret = -EPERM;
283 goto out;
284 }
285
286 if (--twl6040->power_count)
287 goto out;
288
289 if (gpio_is_valid(audpwron)) {
290 /* use AUDPWRON line */
291 gpio_set_value(audpwron, 0);
292
293 /* power-down sequence latency */
294 usleep_range(500, 700);
295 } else {
296 /* use manual power-down sequence */
297 twl6040_power_down(twl6040);
298 }
f19b2823 299 twl6040->sysclk = 0;
f8447d6c 300 twl6040->mclk = 0;
f19b2823
MLC
301 }
302
303out:
304 mutex_unlock(&twl6040->mutex);
305 return ret;
306}
307EXPORT_SYMBOL(twl6040_power);
308
cfb7a33b 309int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
f19b2823
MLC
310 unsigned int freq_in, unsigned int freq_out)
311{
312 u8 hppllctl, lppllctl;
313 int ret = 0;
314
315 mutex_lock(&twl6040->mutex);
316
317 hppllctl = twl6040_reg_read(twl6040, TWL6040_REG_HPPLLCTL);
318 lppllctl = twl6040_reg_read(twl6040, TWL6040_REG_LPPLLCTL);
319
2bd05db7
PU
320 /* Force full reconfiguration when switching between PLL */
321 if (pll_id != twl6040->pll) {
322 twl6040->sysclk = 0;
323 twl6040->mclk = 0;
324 }
325
cfb7a33b
PU
326 switch (pll_id) {
327 case TWL6040_SYSCLK_SEL_LPPLL:
f19b2823 328 /* low-power PLL divider */
2bd05db7
PU
329 /* Change the sysclk configuration only if it has been canged */
330 if (twl6040->sysclk != freq_out) {
331 switch (freq_out) {
332 case 17640000:
333 lppllctl |= TWL6040_LPLLFIN;
334 break;
335 case 19200000:
336 lppllctl &= ~TWL6040_LPLLFIN;
337 break;
338 default:
339 dev_err(twl6040->dev,
340 "freq_out %d not supported\n",
341 freq_out);
342 ret = -EINVAL;
343 goto pll_out;
344 }
345 twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL,
346 lppllctl);
f19b2823 347 }
2bd05db7
PU
348
349 /* The PLL in use has not been change, we can exit */
350 if (twl6040->pll == pll_id)
351 break;
f19b2823
MLC
352
353 switch (freq_in) {
354 case 32768:
355 lppllctl |= TWL6040_LPLLENA;
356 twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL,
357 lppllctl);
358 mdelay(5);
359 lppllctl &= ~TWL6040_HPLLSEL;
360 twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL,
361 lppllctl);
362 hppllctl &= ~TWL6040_HPLLENA;
363 twl6040_reg_write(twl6040, TWL6040_REG_HPPLLCTL,
364 hppllctl);
365 break;
366 default:
2d7c957e 367 dev_err(twl6040->dev,
f19b2823
MLC
368 "freq_in %d not supported\n", freq_in);
369 ret = -EINVAL;
370 goto pll_out;
371 }
f19b2823 372 break;
cfb7a33b 373 case TWL6040_SYSCLK_SEL_HPPLL:
f19b2823
MLC
374 /* high-performance PLL can provide only 19.2 MHz */
375 if (freq_out != 19200000) {
2d7c957e 376 dev_err(twl6040->dev,
f19b2823
MLC
377 "freq_out %d not supported\n", freq_out);
378 ret = -EINVAL;
379 goto pll_out;
380 }
381
2bd05db7
PU
382 if (twl6040->mclk != freq_in) {
383 hppllctl &= ~TWL6040_MCLK_MSK;
384
385 switch (freq_in) {
386 case 12000000:
387 /* PLL enabled, active mode */
388 hppllctl |= TWL6040_MCLK_12000KHZ |
389 TWL6040_HPLLENA;
390 break;
391 case 19200000:
392 /*
393 * PLL disabled
394 * (enable PLL if MCLK jitter quality
395 * doesn't meet specification)
396 */
397 hppllctl |= TWL6040_MCLK_19200KHZ;
398 break;
399 case 26000000:
400 /* PLL enabled, active mode */
401 hppllctl |= TWL6040_MCLK_26000KHZ |
402 TWL6040_HPLLENA;
403 break;
404 case 38400000:
405 /* PLL enabled, active mode */
406 hppllctl |= TWL6040_MCLK_38400KHZ |
407 TWL6040_HPLLENA;
408 break;
409 default:
410 dev_err(twl6040->dev,
411 "freq_in %d not supported\n", freq_in);
412 ret = -EINVAL;
413 goto pll_out;
414 }
f19b2823 415
f19b2823 416 /*
2bd05db7
PU
417 * enable clock slicer to ensure input waveform is
418 * square
f19b2823 419 */
2bd05db7 420 hppllctl |= TWL6040_HPLLSQRENA;
f19b2823 421
2bd05db7
PU
422 twl6040_reg_write(twl6040, TWL6040_REG_HPPLLCTL,
423 hppllctl);
424 usleep_range(500, 700);
425 lppllctl |= TWL6040_HPLLSEL;
426 twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL,
427 lppllctl);
428 lppllctl &= ~TWL6040_LPLLENA;
429 twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL,
430 lppllctl);
431 }
f19b2823
MLC
432 break;
433 default:
2d7c957e 434 dev_err(twl6040->dev, "unknown pll id %d\n", pll_id);
f19b2823
MLC
435 ret = -EINVAL;
436 goto pll_out;
437 }
438
439 twl6040->sysclk = freq_out;
f8447d6c 440 twl6040->mclk = freq_in;
cfb7a33b 441 twl6040->pll = pll_id;
f19b2823
MLC
442
443pll_out:
444 mutex_unlock(&twl6040->mutex);
445 return ret;
446}
447EXPORT_SYMBOL(twl6040_set_pll);
448
cfb7a33b 449int twl6040_get_pll(struct twl6040 *twl6040)
f19b2823 450{
cfb7a33b
PU
451 if (twl6040->power_count)
452 return twl6040->pll;
453 else
454 return -ENODEV;
f19b2823
MLC
455}
456EXPORT_SYMBOL(twl6040_get_pll);
457
458unsigned int twl6040_get_sysclk(struct twl6040 *twl6040)
459{
460 return twl6040->sysclk;
461}
462EXPORT_SYMBOL(twl6040_get_sysclk);
463
70601ec1
PU
464/* Get the combined status of the vibra control register */
465int twl6040_get_vibralr_status(struct twl6040 *twl6040)
466{
467 u8 status;
468
469 status = twl6040->vibra_ctrl_cache[0] | twl6040->vibra_ctrl_cache[1];
470 status &= (TWL6040_VIBENA | TWL6040_VIBSEL);
471
472 return status;
473}
474EXPORT_SYMBOL(twl6040_get_vibralr_status);
475
0f962ae2
PU
476static struct resource twl6040_vibra_rsrc[] = {
477 {
478 .flags = IORESOURCE_IRQ,
479 },
480};
481
482static struct resource twl6040_codec_rsrc[] = {
483 {
484 .flags = IORESOURCE_IRQ,
485 },
486};
487
8eaeb939 488static bool twl6040_readable_reg(struct device *dev, unsigned int reg)
f19b2823 489{
8eaeb939
PU
490 /* Register 0 is not readable */
491 if (!reg)
492 return false;
493 return true;
494}
495
496static struct regmap_config twl6040_regmap_config = {
497 .reg_bits = 8,
498 .val_bits = 8,
499 .max_register = TWL6040_REG_STATUS, /* 0x2e */
500
501 .readable_reg = twl6040_readable_reg,
502};
503
504static int __devinit twl6040_probe(struct i2c_client *client,
505 const struct i2c_device_id *id)
506{
507 struct twl6040_platform_data *pdata = client->dev.platform_data;
f19b2823
MLC
508 struct twl6040 *twl6040;
509 struct mfd_cell *cell = NULL;
510 int ret, children = 0;
511
512 if (!pdata) {
8eaeb939 513 dev_err(&client->dev, "Platform data is missing\n");
f19b2823
MLC
514 return -EINVAL;
515 }
516
d20e1d21 517 /* In order to operate correctly we need valid interrupt config */
8eaeb939
PU
518 if (!client->irq || !pdata->irq_base) {
519 dev_err(&client->dev, "Invalid IRQ configuration\n");
d20e1d21
PU
520 return -EINVAL;
521 }
522
8eaeb939
PU
523 twl6040 = devm_kzalloc(&client->dev, sizeof(struct twl6040),
524 GFP_KERNEL);
525 if (!twl6040) {
526 ret = -ENOMEM;
527 goto err;
528 }
529
bbf6adc1 530 twl6040->regmap = devm_regmap_init_i2c(client, &twl6040_regmap_config);
8eaeb939
PU
531 if (IS_ERR(twl6040->regmap)) {
532 ret = PTR_ERR(twl6040->regmap);
533 goto err;
534 }
f19b2823 535
8eaeb939 536 i2c_set_clientdata(client, twl6040);
f19b2823 537
5af7df6b
PU
538 twl6040->supplies[0].supply = "vio";
539 twl6040->supplies[1].supply = "v2v1";
540 ret = regulator_bulk_get(&client->dev, TWL6040_NUM_SUPPLIES,
541 twl6040->supplies);
542 if (ret != 0) {
543 dev_err(&client->dev, "Failed to get supplies: %d\n", ret);
544 goto regulator_get_err;
545 }
546
547 ret = regulator_bulk_enable(TWL6040_NUM_SUPPLIES, twl6040->supplies);
548 if (ret != 0) {
549 dev_err(&client->dev, "Failed to enable supplies: %d\n", ret);
550 goto power_err;
551 }
552
8eaeb939
PU
553 twl6040->dev = &client->dev;
554 twl6040->irq = client->irq;
f19b2823
MLC
555 twl6040->irq_base = pdata->irq_base;
556
557 mutex_init(&twl6040->mutex);
558 mutex_init(&twl6040->io_mutex);
559 init_completion(&twl6040->ready);
560
561 twl6040->rev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV);
562
77f63e06
PU
563 /* ERRATA: Automatic power-up is not possible in ES1.0 */
564 if (twl6040_get_revid(twl6040) > TWL6040_REV_ES1_0)
565 twl6040->audpwron = pdata->audpwron_gpio;
566 else
567 twl6040->audpwron = -EINVAL;
568
f19b2823 569 if (gpio_is_valid(twl6040->audpwron)) {
b04edb93
AL
570 ret = gpio_request_one(twl6040->audpwron, GPIOF_OUT_INIT_LOW,
571 "audpwron");
f19b2823 572 if (ret)
5af7df6b 573 goto gpio_err;
f19b2823
MLC
574 }
575
d20e1d21
PU
576 /* codec interrupt */
577 ret = twl6040_irq_init(twl6040);
578 if (ret)
5af7df6b 579 goto irq_init_err;
d20e1d21 580
1b7c4725
PU
581 ret = request_threaded_irq(twl6040->irq_base + TWL6040_IRQ_READY,
582 NULL, twl6040_naudint_handler, 0,
583 "twl6040_irq_ready", twl6040);
d20e1d21
PU
584 if (ret) {
585 dev_err(twl6040->dev, "READY IRQ request failed: %d\n",
586 ret);
587 goto irq_err;
f19b2823
MLC
588 }
589
590 /* dual-access registers controlled by I2C only */
591 twl6040_set_bits(twl6040, TWL6040_REG_ACCCTL, TWL6040_I2CSEL);
592
593 if (pdata->codec) {
0f962ae2
PU
594 int irq = twl6040->irq_base + TWL6040_IRQ_PLUG;
595
f19b2823
MLC
596 cell = &twl6040->cells[children];
597 cell->name = "twl6040-codec";
0f962ae2
PU
598 twl6040_codec_rsrc[0].start = irq;
599 twl6040_codec_rsrc[0].end = irq;
600 cell->resources = twl6040_codec_rsrc;
601 cell->num_resources = ARRAY_SIZE(twl6040_codec_rsrc);
6c448637
PU
602 cell->platform_data = pdata->codec;
603 cell->pdata_size = sizeof(*pdata->codec);
f19b2823
MLC
604 children++;
605 }
606
607 if (pdata->vibra) {
0f962ae2
PU
608 int irq = twl6040->irq_base + TWL6040_IRQ_VIB;
609
f19b2823
MLC
610 cell = &twl6040->cells[children];
611 cell->name = "twl6040-vibra";
0f962ae2
PU
612 twl6040_vibra_rsrc[0].start = irq;
613 twl6040_vibra_rsrc[0].end = irq;
614 cell->resources = twl6040_vibra_rsrc;
615 cell->num_resources = ARRAY_SIZE(twl6040_vibra_rsrc);
616
f19b2823
MLC
617 cell->platform_data = pdata->vibra;
618 cell->pdata_size = sizeof(*pdata->vibra);
619 children++;
620 }
621
622 if (children) {
8eaeb939 623 ret = mfd_add_devices(&client->dev, -1, twl6040->cells,
f19b2823
MLC
624 children, NULL, 0);
625 if (ret)
626 goto mfd_err;
627 } else {
8eaeb939 628 dev_err(&client->dev, "No platform data found for children\n");
f19b2823
MLC
629 ret = -ENODEV;
630 goto mfd_err;
631 }
632
633 return 0;
634
635mfd_err:
1b7c4725 636 free_irq(twl6040->irq_base + TWL6040_IRQ_READY, twl6040);
f19b2823 637irq_err:
d20e1d21 638 twl6040_irq_exit(twl6040);
5af7df6b 639irq_init_err:
f19b2823
MLC
640 if (gpio_is_valid(twl6040->audpwron))
641 gpio_free(twl6040->audpwron);
5af7df6b
PU
642gpio_err:
643 regulator_bulk_disable(TWL6040_NUM_SUPPLIES, twl6040->supplies);
644power_err:
645 regulator_bulk_free(TWL6040_NUM_SUPPLIES, twl6040->supplies);
646regulator_get_err:
8eaeb939 647 i2c_set_clientdata(client, NULL);
8eaeb939 648err:
f19b2823
MLC
649 return ret;
650}
651
8eaeb939 652static int __devexit twl6040_remove(struct i2c_client *client)
f19b2823 653{
8eaeb939 654 struct twl6040 *twl6040 = i2c_get_clientdata(client);
f19b2823
MLC
655
656 if (twl6040->power_count)
657 twl6040_power(twl6040, 0);
658
659 if (gpio_is_valid(twl6040->audpwron))
660 gpio_free(twl6040->audpwron);
661
1b7c4725 662 free_irq(twl6040->irq_base + TWL6040_IRQ_READY, twl6040);
d20e1d21 663 twl6040_irq_exit(twl6040);
f19b2823 664
8eaeb939
PU
665 mfd_remove_devices(&client->dev);
666 i2c_set_clientdata(client, NULL);
f19b2823 667
5af7df6b
PU
668 regulator_bulk_disable(TWL6040_NUM_SUPPLIES, twl6040->supplies);
669 regulator_bulk_free(TWL6040_NUM_SUPPLIES, twl6040->supplies);
670
f19b2823
MLC
671 return 0;
672}
673
8eaeb939
PU
674static const struct i2c_device_id twl6040_i2c_id[] = {
675 { "twl6040", 0, },
676 { },
677};
678MODULE_DEVICE_TABLE(i2c, twl6040_i2c_id);
679
680static struct i2c_driver twl6040_driver = {
681 .driver = {
682 .name = "twl6040",
683 .owner = THIS_MODULE,
684 },
f19b2823
MLC
685 .probe = twl6040_probe,
686 .remove = __devexit_p(twl6040_remove),
8eaeb939 687 .id_table = twl6040_i2c_id,
f19b2823
MLC
688};
689
8eaeb939 690module_i2c_driver(twl6040_driver);
f19b2823
MLC
691
692MODULE_DESCRIPTION("TWL6040 MFD");
693MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");
694MODULE_AUTHOR("Jorge Eduardo Candelaria <jorge.candelaria@ti.com>");
695MODULE_LICENSE("GPL");
696MODULE_ALIAS("platform:twl6040");