diff options
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/Kconfig | 1 | ||||
-rw-r--r-- | drivers/mfd/wm8994-core.c | 178 |
2 files changed, 34 insertions, 145 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index cfae5c594d24..a67adcbd0fa1 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -490,6 +490,7 @@ config MFD_WM8350_I2C | |||
490 | config MFD_WM8994 | 490 | config MFD_WM8994 |
491 | bool "Support Wolfson Microelectronics WM8994" | 491 | bool "Support Wolfson Microelectronics WM8994" |
492 | select MFD_CORE | 492 | select MFD_CORE |
493 | select REGMAP_I2C | ||
493 | depends on I2C=y && GENERIC_HARDIRQS | 494 | depends on I2C=y && GENERIC_HARDIRQS |
494 | help | 495 | help |
495 | The WM8994 is a highly integrated hi-fi CODEC designed for | 496 | The WM8994 is a highly integrated hi-fi CODEC designed for |
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 96479c9b1728..bfde4e8ec638 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c | |||
@@ -16,9 +16,11 @@ | |||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
19 | #include <linux/err.h> | ||
19 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
20 | #include <linux/mfd/core.h> | 21 | #include <linux/mfd/core.h> |
21 | #include <linux/pm_runtime.h> | 22 | #include <linux/pm_runtime.h> |
23 | #include <linux/regmap.h> | ||
22 | #include <linux/regulator/consumer.h> | 24 | #include <linux/regulator/consumer.h> |
23 | #include <linux/regulator/machine.h> | 25 | #include <linux/regulator/machine.h> |
24 | 26 | ||
@@ -29,22 +31,7 @@ | |||
29 | static int wm8994_read(struct wm8994 *wm8994, unsigned short reg, | 31 | static int wm8994_read(struct wm8994 *wm8994, unsigned short reg, |
30 | int bytes, void *dest) | 32 | int bytes, void *dest) |
31 | { | 33 | { |
32 | int ret, i; | 34 | return regmap_raw_read(wm8994->regmap, reg, dest, bytes); |
33 | u16 *buf = dest; | ||
34 | |||
35 | BUG_ON(bytes % 2); | ||
36 | BUG_ON(bytes <= 0); | ||
37 | |||
38 | ret = wm8994->read_dev(wm8994, reg, bytes, dest); | ||
39 | if (ret < 0) | ||
40 | return ret; | ||
41 | |||
42 | for (i = 0; i < bytes / 2; i++) { | ||
43 | dev_vdbg(wm8994->dev, "Read %04x from R%d(0x%x)\n", | ||
44 | be16_to_cpu(buf[i]), reg + i, reg + i); | ||
45 | } | ||
46 | |||
47 | return 0; | ||
48 | } | 35 | } |
49 | 36 | ||
50 | /** | 37 | /** |
@@ -55,19 +42,15 @@ static int wm8994_read(struct wm8994 *wm8994, unsigned short reg, | |||
55 | */ | 42 | */ |
56 | int wm8994_reg_read(struct wm8994 *wm8994, unsigned short reg) | 43 | int wm8994_reg_read(struct wm8994 *wm8994, unsigned short reg) |
57 | { | 44 | { |
58 | unsigned short val; | 45 | unsigned int val; |
59 | int ret; | 46 | int ret; |
60 | 47 | ||
61 | mutex_lock(&wm8994->io_lock); | 48 | ret = regmap_read(wm8994->regmap, reg, &val); |
62 | |||
63 | ret = wm8994_read(wm8994, reg, 2, &val); | ||
64 | |||
65 | mutex_unlock(&wm8994->io_lock); | ||
66 | 49 | ||
67 | if (ret < 0) | 50 | if (ret < 0) |
68 | return ret; | 51 | return ret; |
69 | else | 52 | else |
70 | return be16_to_cpu(val); | 53 | return val; |
71 | } | 54 | } |
72 | EXPORT_SYMBOL_GPL(wm8994_reg_read); | 55 | EXPORT_SYMBOL_GPL(wm8994_reg_read); |
73 | 56 | ||
@@ -82,33 +65,13 @@ EXPORT_SYMBOL_GPL(wm8994_reg_read); | |||
82 | int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg, | 65 | int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg, |
83 | int count, u16 *buf) | 66 | int count, u16 *buf) |
84 | { | 67 | { |
85 | int ret; | 68 | return regmap_bulk_read(wm8994->regmap, reg, buf, count); |
86 | |||
87 | mutex_lock(&wm8994->io_lock); | ||
88 | |||
89 | ret = wm8994_read(wm8994, reg, count * 2, buf); | ||
90 | |||
91 | mutex_unlock(&wm8994->io_lock); | ||
92 | |||
93 | return ret; | ||
94 | } | 69 | } |
95 | EXPORT_SYMBOL_GPL(wm8994_bulk_read); | ||
96 | 70 | ||
97 | static int wm8994_write(struct wm8994 *wm8994, unsigned short reg, | 71 | static int wm8994_write(struct wm8994 *wm8994, unsigned short reg, |
98 | int bytes, const void *src) | 72 | int bytes, const void *src) |
99 | { | 73 | { |
100 | const u16 *buf = src; | 74 | return regmap_raw_write(wm8994->regmap, reg, src, bytes); |
101 | int i; | ||
102 | |||
103 | BUG_ON(bytes % 2); | ||
104 | BUG_ON(bytes <= 0); | ||
105 | |||
106 | for (i = 0; i < bytes / 2; i++) { | ||
107 | dev_vdbg(wm8994->dev, "Write %04x to R%d(0x%x)\n", | ||
108 | be16_to_cpu(buf[i]), reg + i, reg + i); | ||
109 | } | ||
110 | |||
111 | return wm8994->write_dev(wm8994, reg, bytes, src); | ||
112 | } | 75 | } |
113 | 76 | ||
114 | /** | 77 | /** |
@@ -121,17 +84,7 @@ static int wm8994_write(struct wm8994 *wm8994, unsigned short reg, | |||
121 | int wm8994_reg_write(struct wm8994 *wm8994, unsigned short reg, | 84 | int wm8994_reg_write(struct wm8994 *wm8994, unsigned short reg, |
122 | unsigned short val) | 85 | unsigned short val) |
123 | { | 86 | { |
124 | int ret; | 87 | return regmap_write(wm8994->regmap, reg, val); |
125 | |||
126 | val = cpu_to_be16(val); | ||
127 | |||
128 | mutex_lock(&wm8994->io_lock); | ||
129 | |||
130 | ret = wm8994_write(wm8994, reg, 2, &val); | ||
131 | |||
132 | mutex_unlock(&wm8994->io_lock); | ||
133 | |||
134 | return ret; | ||
135 | } | 88 | } |
136 | EXPORT_SYMBOL_GPL(wm8994_reg_write); | 89 | EXPORT_SYMBOL_GPL(wm8994_reg_write); |
137 | 90 | ||
@@ -146,15 +99,7 @@ EXPORT_SYMBOL_GPL(wm8994_reg_write); | |||
146 | int wm8994_bulk_write(struct wm8994 *wm8994, unsigned short reg, | 99 | int wm8994_bulk_write(struct wm8994 *wm8994, unsigned short reg, |
147 | int count, const u16 *buf) | 100 | int count, const u16 *buf) |
148 | { | 101 | { |
149 | int ret; | 102 | return regmap_raw_write(wm8994->regmap, reg, buf, count * sizeof(u16)); |
150 | |||
151 | mutex_lock(&wm8994->io_lock); | ||
152 | |||
153 | ret = wm8994_write(wm8994, reg, count * 2, buf); | ||
154 | |||
155 | mutex_unlock(&wm8994->io_lock); | ||
156 | |||
157 | return ret; | ||
158 | } | 103 | } |
159 | EXPORT_SYMBOL_GPL(wm8994_bulk_write); | 104 | EXPORT_SYMBOL_GPL(wm8994_bulk_write); |
160 | 105 | ||
@@ -169,28 +114,7 @@ EXPORT_SYMBOL_GPL(wm8994_bulk_write); | |||
169 | int wm8994_set_bits(struct wm8994 *wm8994, unsigned short reg, | 114 | int wm8994_set_bits(struct wm8994 *wm8994, unsigned short reg, |
170 | unsigned short mask, unsigned short val) | 115 | unsigned short mask, unsigned short val) |
171 | { | 116 | { |
172 | int ret; | 117 | return regmap_update_bits(wm8994->regmap, reg, mask, val); |
173 | u16 r; | ||
174 | |||
175 | mutex_lock(&wm8994->io_lock); | ||
176 | |||
177 | ret = wm8994_read(wm8994, reg, 2, &r); | ||
178 | if (ret < 0) | ||
179 | goto out; | ||
180 | |||
181 | r = be16_to_cpu(r); | ||
182 | |||
183 | r &= ~mask; | ||
184 | r |= val; | ||
185 | |||
186 | r = cpu_to_be16(r); | ||
187 | |||
188 | ret = wm8994_write(wm8994, reg, 2, &r); | ||
189 | |||
190 | out: | ||
191 | mutex_unlock(&wm8994->io_lock); | ||
192 | |||
193 | return ret; | ||
194 | } | 118 | } |
195 | EXPORT_SYMBOL_GPL(wm8994_set_bits); | 119 | EXPORT_SYMBOL_GPL(wm8994_set_bits); |
196 | 120 | ||
@@ -378,6 +302,11 @@ static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo) | |||
378 | } | 302 | } |
379 | #endif | 303 | #endif |
380 | 304 | ||
305 | static struct regmap_config wm8994_regmap_config = { | ||
306 | .reg_bits = 16, | ||
307 | .val_bits = 16, | ||
308 | }; | ||
309 | |||
381 | /* | 310 | /* |
382 | * Instantiate the generic non-control parts of the device. | 311 | * Instantiate the generic non-control parts of the device. |
383 | */ | 312 | */ |
@@ -387,7 +316,6 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) | |||
387 | const char *devname; | 316 | const char *devname; |
388 | int ret, i; | 317 | int ret, i; |
389 | 318 | ||
390 | mutex_init(&wm8994->io_lock); | ||
391 | dev_set_drvdata(wm8994->dev, wm8994); | 319 | dev_set_drvdata(wm8994->dev, wm8994); |
392 | 320 | ||
393 | /* Add the on-chip regulators first for bootstrapping */ | 321 | /* Add the on-chip regulators first for bootstrapping */ |
@@ -397,7 +325,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) | |||
397 | NULL, 0); | 325 | NULL, 0); |
398 | if (ret != 0) { | 326 | if (ret != 0) { |
399 | dev_err(wm8994->dev, "Failed to add children: %d\n", ret); | 327 | dev_err(wm8994->dev, "Failed to add children: %d\n", ret); |
400 | goto err; | 328 | goto err_regmap; |
401 | } | 329 | } |
402 | 330 | ||
403 | switch (wm8994->type) { | 331 | switch (wm8994->type) { |
@@ -409,7 +337,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) | |||
409 | break; | 337 | break; |
410 | default: | 338 | default: |
411 | BUG(); | 339 | BUG(); |
412 | goto err; | 340 | goto err_regmap; |
413 | } | 341 | } |
414 | 342 | ||
415 | wm8994->supplies = kzalloc(sizeof(struct regulator_bulk_data) * | 343 | wm8994->supplies = kzalloc(sizeof(struct regulator_bulk_data) * |
@@ -417,7 +345,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) | |||
417 | GFP_KERNEL); | 345 | GFP_KERNEL); |
418 | if (!wm8994->supplies) { | 346 | if (!wm8994->supplies) { |
419 | ret = -ENOMEM; | 347 | ret = -ENOMEM; |
420 | goto err; | 348 | goto err_regmap; |
421 | } | 349 | } |
422 | 350 | ||
423 | switch (wm8994->type) { | 351 | switch (wm8994->type) { |
@@ -431,7 +359,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) | |||
431 | break; | 359 | break; |
432 | default: | 360 | default: |
433 | BUG(); | 361 | BUG(); |
434 | goto err; | 362 | goto err_regmap; |
435 | } | 363 | } |
436 | 364 | ||
437 | ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies, | 365 | ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies, |
@@ -554,7 +482,8 @@ err_get: | |||
554 | regulator_bulk_free(wm8994->num_supplies, wm8994->supplies); | 482 | regulator_bulk_free(wm8994->num_supplies, wm8994->supplies); |
555 | err_supplies: | 483 | err_supplies: |
556 | kfree(wm8994->supplies); | 484 | kfree(wm8994->supplies); |
557 | err: | 485 | err_regmap: |
486 | regmap_exit(wm8994->regmap); | ||
558 | mfd_remove_devices(wm8994->dev); | 487 | mfd_remove_devices(wm8994->dev); |
559 | kfree(wm8994); | 488 | kfree(wm8994); |
560 | return ret; | 489 | return ret; |
@@ -569,62 +498,15 @@ static void wm8994_device_exit(struct wm8994 *wm8994) | |||
569 | wm8994->supplies); | 498 | wm8994->supplies); |
570 | regulator_bulk_free(wm8994->num_supplies, wm8994->supplies); | 499 | regulator_bulk_free(wm8994->num_supplies, wm8994->supplies); |
571 | kfree(wm8994->supplies); | 500 | kfree(wm8994->supplies); |
501 | regmap_exit(wm8994->regmap); | ||
572 | kfree(wm8994); | 502 | kfree(wm8994); |
573 | } | 503 | } |
574 | 504 | ||
575 | static int wm8994_i2c_read_device(struct wm8994 *wm8994, unsigned short reg, | ||
576 | int bytes, void *dest) | ||
577 | { | ||
578 | struct i2c_client *i2c = wm8994->control_data; | ||
579 | int ret; | ||
580 | u16 r = cpu_to_be16(reg); | ||
581 | |||
582 | ret = i2c_master_send(i2c, (unsigned char *)&r, 2); | ||
583 | if (ret < 0) | ||
584 | return ret; | ||
585 | if (ret != 2) | ||
586 | return -EIO; | ||
587 | |||
588 | ret = i2c_master_recv(i2c, dest, bytes); | ||
589 | if (ret < 0) | ||
590 | return ret; | ||
591 | if (ret != bytes) | ||
592 | return -EIO; | ||
593 | return 0; | ||
594 | } | ||
595 | |||
596 | static int wm8994_i2c_write_device(struct wm8994 *wm8994, unsigned short reg, | ||
597 | int bytes, const void *src) | ||
598 | { | ||
599 | struct i2c_client *i2c = wm8994->control_data; | ||
600 | struct i2c_msg xfer[2]; | ||
601 | int ret; | ||
602 | |||
603 | reg = cpu_to_be16(reg); | ||
604 | |||
605 | xfer[0].addr = i2c->addr; | ||
606 | xfer[0].flags = 0; | ||
607 | xfer[0].len = 2; | ||
608 | xfer[0].buf = (char *)® | ||
609 | |||
610 | xfer[1].addr = i2c->addr; | ||
611 | xfer[1].flags = I2C_M_NOSTART; | ||
612 | xfer[1].len = bytes; | ||
613 | xfer[1].buf = (char *)src; | ||
614 | |||
615 | ret = i2c_transfer(i2c->adapter, xfer, 2); | ||
616 | if (ret < 0) | ||
617 | return ret; | ||
618 | if (ret != 2) | ||
619 | return -EIO; | ||
620 | |||
621 | return 0; | ||
622 | } | ||
623 | |||
624 | static int wm8994_i2c_probe(struct i2c_client *i2c, | 505 | static int wm8994_i2c_probe(struct i2c_client *i2c, |
625 | const struct i2c_device_id *id) | 506 | const struct i2c_device_id *id) |
626 | { | 507 | { |
627 | struct wm8994 *wm8994; | 508 | struct wm8994 *wm8994; |
509 | int ret; | ||
628 | 510 | ||
629 | wm8994 = kzalloc(sizeof(struct wm8994), GFP_KERNEL); | 511 | wm8994 = kzalloc(sizeof(struct wm8994), GFP_KERNEL); |
630 | if (wm8994 == NULL) | 512 | if (wm8994 == NULL) |
@@ -632,12 +514,18 @@ static int wm8994_i2c_probe(struct i2c_client *i2c, | |||
632 | 514 | ||
633 | i2c_set_clientdata(i2c, wm8994); | 515 | i2c_set_clientdata(i2c, wm8994); |
634 | wm8994->dev = &i2c->dev; | 516 | wm8994->dev = &i2c->dev; |
635 | wm8994->control_data = i2c; | ||
636 | wm8994->read_dev = wm8994_i2c_read_device; | ||
637 | wm8994->write_dev = wm8994_i2c_write_device; | ||
638 | wm8994->irq = i2c->irq; | 517 | wm8994->irq = i2c->irq; |
639 | wm8994->type = id->driver_data; | 518 | wm8994->type = id->driver_data; |
640 | 519 | ||
520 | wm8994->regmap = regmap_init_i2c(i2c, &wm8994_regmap_config); | ||
521 | if (IS_ERR(wm8994->regmap)) { | ||
522 | ret = PTR_ERR(wm8994->regmap); | ||
523 | dev_err(wm8994->dev, "Failed to allocate register map: %d\n", | ||
524 | ret); | ||
525 | kfree(wm8994); | ||
526 | return ret; | ||
527 | } | ||
528 | |||
641 | return wm8994_device_init(wm8994, i2c->irq); | 529 | return wm8994_device_init(wm8994, i2c->irq); |
642 | } | 530 | } |
643 | 531 | ||