diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-12-13 08:20:59 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-01-20 08:58:20 -0500 |
commit | ec2c0fec11f072222b63eb160da6be01773bfe65 (patch) | |
tree | 94e8eae4191599ee1539013fc24618807afb8b7e | |
parent | 008f8d4f9955b5f20be06ed99434cc2f8b025e06 (diff) |
ASoC: Convert WM9090 to use regmap directly
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r-- | sound/soc/codecs/wm9090.c | 242 |
1 files changed, 128 insertions, 114 deletions
diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index 41ebe0dce772..4be5551f06a0 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/device.h> | 25 | #include <linux/device.h> |
26 | #include <linux/i2c.h> | 26 | #include <linux/i2c.h> |
27 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
28 | #include <linux/regmap.h> | ||
28 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
29 | #include <sound/initval.h> | 30 | #include <sound/initval.h> |
30 | #include <sound/soc.h> | 31 | #include <sound/soc.h> |
@@ -33,116 +34,51 @@ | |||
33 | 34 | ||
34 | #include "wm9090.h" | 35 | #include "wm9090.h" |
35 | 36 | ||
36 | static const u16 wm9090_reg_defaults[] = { | 37 | static const struct reg_default wm9090_reg_defaults[] = { |
37 | 0x9093, /* R0 - Software Reset */ | 38 | { 1, 0x0006 }, /* R1 - Power Management (1) */ |
38 | 0x0006, /* R1 - Power Management (1) */ | 39 | { 2, 0x6000 }, /* R2 - Power Management (2) */ |
39 | 0x6000, /* R2 - Power Management (2) */ | 40 | { 3, 0x0000 }, /* R3 - Power Management (3) */ |
40 | 0x0000, /* R3 - Power Management (3) */ | 41 | { 6, 0x01C0 }, /* R6 - Clocking 1 */ |
41 | 0x0000, /* R4 */ | 42 | { 22, 0x0003 }, /* R22 - IN1 Line Control */ |
42 | 0x0000, /* R5 */ | 43 | { 23, 0x0003 }, /* R23 - IN2 Line Control */ |
43 | 0x01C0, /* R6 - Clocking 1 */ | 44 | { 24, 0x0083 }, /* R24 - IN1 Line Input A Volume */ |
44 | 0x0000, /* R7 */ | 45 | { 25, 0x0083 }, /* R25 - IN1 Line Input B Volume */ |
45 | 0x0000, /* R8 */ | 46 | { 26, 0x0083 }, /* R26 - IN2 Line Input A Volume */ |
46 | 0x0000, /* R9 */ | 47 | { 27, 0x0083 }, /* R27 - IN2 Line Input B Volume */ |
47 | 0x0000, /* R10 */ | 48 | { 28, 0x002D }, /* R28 - Left Output Volume */ |
48 | 0x0000, /* R11 */ | 49 | { 29, 0x002D }, /* R29 - Right Output Volume */ |
49 | 0x0000, /* R12 */ | 50 | { 34, 0x0100 }, /* R34 - SPKMIXL Attenuation */ |
50 | 0x0000, /* R13 */ | 51 | { 35, 0x0010 }, /* R36 - SPKOUT Mixers */ |
51 | 0x0000, /* R14 */ | 52 | { 37, 0x0140 }, /* R37 - ClassD3 */ |
52 | 0x0000, /* R15 */ | 53 | { 38, 0x0039 }, /* R38 - Speaker Volume Left */ |
53 | 0x0000, /* R16 */ | 54 | { 45, 0x0000 }, /* R45 - Output Mixer1 */ |
54 | 0x0000, /* R17 */ | 55 | { 46, 0x0000 }, /* R46 - Output Mixer2 */ |
55 | 0x0000, /* R18 */ | 56 | { 47, 0x0100 }, /* R47 - Output Mixer3 */ |
56 | 0x0000, /* R19 */ | 57 | { 48, 0x0100 }, /* R48 - Output Mixer4 */ |
57 | 0x0000, /* R20 */ | 58 | { 54, 0x0000 }, /* R54 - Speaker Mixer */ |
58 | 0x0000, /* R21 */ | 59 | { 57, 0x000D }, /* R57 - AntiPOP2 */ |
59 | 0x0003, /* R22 - IN1 Line Control */ | 60 | { 70, 0x0000 }, /* R70 - Write Sequencer 0 */ |
60 | 0x0003, /* R23 - IN2 Line Control */ | 61 | { 71, 0x0000 }, /* R71 - Write Sequencer 1 */ |
61 | 0x0083, /* R24 - IN1 Line Input A Volume */ | 62 | { 72, 0x0000 }, /* R72 - Write Sequencer 2 */ |
62 | 0x0083, /* R25 - IN1 Line Input B Volume */ | 63 | { 73, 0x0000 }, /* R73 - Write Sequencer 3 */ |
63 | 0x0083, /* R26 - IN2 Line Input A Volume */ | 64 | { 74, 0x0000 }, /* R74 - Write Sequencer 4 */ |
64 | 0x0083, /* R27 - IN2 Line Input B Volume */ | 65 | { 75, 0x0000 }, /* R75 - Write Sequencer 5 */ |
65 | 0x002D, /* R28 - Left Output Volume */ | 66 | { 76, 0x1F25 }, /* R76 - Charge Pump 1 */ |
66 | 0x002D, /* R29 - Right Output Volume */ | 67 | { 85, 0x054A }, /* R85 - DC Servo 1 */ |
67 | 0x0000, /* R30 */ | 68 | { 87, 0x0000 }, /* R87 - DC Servo 3 */ |
68 | 0x0000, /* R31 */ | 69 | { 96, 0x0100 }, /* R96 - Analogue HP 0 */ |
69 | 0x0000, /* R32 */ | 70 | { 98, 0x8640 }, /* R98 - AGC Control 0 */ |
70 | 0x0000, /* R33 */ | 71 | { 99, 0xC000 }, /* R99 - AGC Control 1 */ |
71 | 0x0100, /* R34 - SPKMIXL Attenuation */ | 72 | { 100, 0x0200 }, /* R100 - AGC Control 2 */ |
72 | 0x0000, /* R35 */ | ||
73 | 0x0010, /* R36 - SPKOUT Mixers */ | ||
74 | 0x0140, /* R37 - ClassD3 */ | ||
75 | 0x0039, /* R38 - Speaker Volume Left */ | ||
76 | 0x0000, /* R39 */ | ||
77 | 0x0000, /* R40 */ | ||
78 | 0x0000, /* R41 */ | ||
79 | 0x0000, /* R42 */ | ||
80 | 0x0000, /* R43 */ | ||
81 | 0x0000, /* R44 */ | ||
82 | 0x0000, /* R45 - Output Mixer1 */ | ||
83 | 0x0000, /* R46 - Output Mixer2 */ | ||
84 | 0x0100, /* R47 - Output Mixer3 */ | ||
85 | 0x0100, /* R48 - Output Mixer4 */ | ||
86 | 0x0000, /* R49 */ | ||
87 | 0x0000, /* R50 */ | ||
88 | 0x0000, /* R51 */ | ||
89 | 0x0000, /* R52 */ | ||
90 | 0x0000, /* R53 */ | ||
91 | 0x0000, /* R54 - Speaker Mixer */ | ||
92 | 0x0000, /* R55 */ | ||
93 | 0x0000, /* R56 */ | ||
94 | 0x000D, /* R57 - AntiPOP2 */ | ||
95 | 0x0000, /* R58 */ | ||
96 | 0x0000, /* R59 */ | ||
97 | 0x0000, /* R60 */ | ||
98 | 0x0000, /* R61 */ | ||
99 | 0x0000, /* R62 */ | ||
100 | 0x0000, /* R63 */ | ||
101 | 0x0000, /* R64 */ | ||
102 | 0x0000, /* R65 */ | ||
103 | 0x0000, /* R66 */ | ||
104 | 0x0000, /* R67 */ | ||
105 | 0x0000, /* R68 */ | ||
106 | 0x0000, /* R69 */ | ||
107 | 0x0000, /* R70 - Write Sequencer 0 */ | ||
108 | 0x0000, /* R71 - Write Sequencer 1 */ | ||
109 | 0x0000, /* R72 - Write Sequencer 2 */ | ||
110 | 0x0000, /* R73 - Write Sequencer 3 */ | ||
111 | 0x0000, /* R74 - Write Sequencer 4 */ | ||
112 | 0x0000, /* R75 - Write Sequencer 5 */ | ||
113 | 0x1F25, /* R76 - Charge Pump 1 */ | ||
114 | 0x0000, /* R77 */ | ||
115 | 0x0000, /* R78 */ | ||
116 | 0x0000, /* R79 */ | ||
117 | 0x0000, /* R80 */ | ||
118 | 0x0000, /* R81 */ | ||
119 | 0x0000, /* R82 */ | ||
120 | 0x0000, /* R83 */ | ||
121 | 0x0000, /* R84 - DC Servo 0 */ | ||
122 | 0x054A, /* R85 - DC Servo 1 */ | ||
123 | 0x0000, /* R86 */ | ||
124 | 0x0000, /* R87 - DC Servo 3 */ | ||
125 | 0x0000, /* R88 - DC Servo Readback 0 */ | ||
126 | 0x0000, /* R89 - DC Servo Readback 1 */ | ||
127 | 0x0000, /* R90 - DC Servo Readback 2 */ | ||
128 | 0x0000, /* R91 */ | ||
129 | 0x0000, /* R92 */ | ||
130 | 0x0000, /* R93 */ | ||
131 | 0x0000, /* R94 */ | ||
132 | 0x0000, /* R95 */ | ||
133 | 0x0100, /* R96 - Analogue HP 0 */ | ||
134 | 0x0000, /* R97 */ | ||
135 | 0x8640, /* R98 - AGC Control 0 */ | ||
136 | 0xC000, /* R99 - AGC Control 1 */ | ||
137 | 0x0200, /* R100 - AGC Control 2 */ | ||
138 | }; | 73 | }; |
139 | 74 | ||
140 | /* This struct is used to save the context */ | 75 | /* This struct is used to save the context */ |
141 | struct wm9090_priv { | 76 | struct wm9090_priv { |
142 | struct wm9090_platform_data pdata; | 77 | struct wm9090_platform_data pdata; |
78 | struct regmap *regmap; | ||
143 | }; | 79 | }; |
144 | 80 | ||
145 | static int wm9090_volatile(struct snd_soc_codec *codec, unsigned int reg) | 81 | static bool wm9090_volatile(struct device *dev, unsigned int reg) |
146 | { | 82 | { |
147 | switch (reg) { | 83 | switch (reg) { |
148 | case WM9090_SOFTWARE_RESET: | 84 | case WM9090_SOFTWARE_RESET: |
@@ -150,10 +86,60 @@ static int wm9090_volatile(struct snd_soc_codec *codec, unsigned int reg) | |||
150 | case WM9090_DC_SERVO_READBACK_0: | 86 | case WM9090_DC_SERVO_READBACK_0: |
151 | case WM9090_DC_SERVO_READBACK_1: | 87 | case WM9090_DC_SERVO_READBACK_1: |
152 | case WM9090_DC_SERVO_READBACK_2: | 88 | case WM9090_DC_SERVO_READBACK_2: |
153 | return 1; | 89 | return true; |
154 | 90 | ||
155 | default: | 91 | default: |
156 | return 0; | 92 | return false; |
93 | } | ||
94 | } | ||
95 | |||
96 | static bool wm9090_readable(struct device *dev, unsigned int reg) | ||
97 | { | ||
98 | switch (reg) { | ||
99 | case WM9090_SOFTWARE_RESET: | ||
100 | case WM9090_POWER_MANAGEMENT_1: | ||
101 | case WM9090_POWER_MANAGEMENT_2: | ||
102 | case WM9090_POWER_MANAGEMENT_3: | ||
103 | case WM9090_CLOCKING_1: | ||
104 | case WM9090_IN1_LINE_CONTROL: | ||
105 | case WM9090_IN2_LINE_CONTROL: | ||
106 | case WM9090_IN1_LINE_INPUT_A_VOLUME: | ||
107 | case WM9090_IN1_LINE_INPUT_B_VOLUME: | ||
108 | case WM9090_IN2_LINE_INPUT_A_VOLUME: | ||
109 | case WM9090_IN2_LINE_INPUT_B_VOLUME: | ||
110 | case WM9090_LEFT_OUTPUT_VOLUME: | ||
111 | case WM9090_RIGHT_OUTPUT_VOLUME: | ||
112 | case WM9090_SPKMIXL_ATTENUATION: | ||
113 | case WM9090_SPKOUT_MIXERS: | ||
114 | case WM9090_CLASSD3: | ||
115 | case WM9090_SPEAKER_VOLUME_LEFT: | ||
116 | case WM9090_OUTPUT_MIXER1: | ||
117 | case WM9090_OUTPUT_MIXER2: | ||
118 | case WM9090_OUTPUT_MIXER3: | ||
119 | case WM9090_OUTPUT_MIXER4: | ||
120 | case WM9090_SPEAKER_MIXER: | ||
121 | case WM9090_ANTIPOP2: | ||
122 | case WM9090_WRITE_SEQUENCER_0: | ||
123 | case WM9090_WRITE_SEQUENCER_1: | ||
124 | case WM9090_WRITE_SEQUENCER_2: | ||
125 | case WM9090_WRITE_SEQUENCER_3: | ||
126 | case WM9090_WRITE_SEQUENCER_4: | ||
127 | case WM9090_WRITE_SEQUENCER_5: | ||
128 | case WM9090_CHARGE_PUMP_1: | ||
129 | case WM9090_DC_SERVO_0: | ||
130 | case WM9090_DC_SERVO_1: | ||
131 | case WM9090_DC_SERVO_3: | ||
132 | case WM9090_DC_SERVO_READBACK_0: | ||
133 | case WM9090_DC_SERVO_READBACK_1: | ||
134 | case WM9090_DC_SERVO_READBACK_2: | ||
135 | case WM9090_ANALOGUE_HP_0: | ||
136 | case WM9090_AGC_CONTROL_0: | ||
137 | case WM9090_AGC_CONTROL_1: | ||
138 | case WM9090_AGC_CONTROL_2: | ||
139 | return true; | ||
140 | |||
141 | default: | ||
142 | return false; | ||
157 | } | 143 | } |
158 | } | 144 | } |
159 | 145 | ||
@@ -492,8 +478,7 @@ static int wm9090_add_controls(struct snd_soc_codec *codec) | |||
492 | static int wm9090_set_bias_level(struct snd_soc_codec *codec, | 478 | static int wm9090_set_bias_level(struct snd_soc_codec *codec, |
493 | enum snd_soc_bias_level level) | 479 | enum snd_soc_bias_level level) |
494 | { | 480 | { |
495 | u16 *reg_cache = codec->reg_cache; | 481 | struct wm9090_priv *wm9090 = snd_soc_codec_get_drvdata(codec); |
496 | int i, ret; | ||
497 | 482 | ||
498 | switch (level) { | 483 | switch (level) { |
499 | case SND_SOC_BIAS_ON: | 484 | case SND_SOC_BIAS_ON: |
@@ -513,7 +498,7 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec, | |||
513 | case SND_SOC_BIAS_STANDBY: | 498 | case SND_SOC_BIAS_STANDBY: |
514 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 499 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { |
515 | /* Restore the register cache */ | 500 | /* Restore the register cache */ |
516 | snd_soc_cache_sync(codec); | 501 | regcache_sync(wm9090->regmap); |
517 | } | 502 | } |
518 | 503 | ||
519 | /* We keep VMID off during standby since the combination of | 504 | /* We keep VMID off during standby since the combination of |
@@ -537,9 +522,11 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec, | |||
537 | 522 | ||
538 | static int wm9090_probe(struct snd_soc_codec *codec) | 523 | static int wm9090_probe(struct snd_soc_codec *codec) |
539 | { | 524 | { |
525 | struct wm9090_priv *wm9090 = dev_get_drvdata(codec->dev); | ||
540 | int ret; | 526 | int ret; |
541 | 527 | ||
542 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); | 528 | codec->control_data = wm9090->regmap; |
529 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); | ||
543 | if (ret != 0) { | 530 | if (ret != 0) { |
544 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 531 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
545 | return ret; | 532 | return ret; |
@@ -548,7 +535,7 @@ static int wm9090_probe(struct snd_soc_codec *codec) | |||
548 | ret = snd_soc_read(codec, WM9090_SOFTWARE_RESET); | 535 | ret = snd_soc_read(codec, WM9090_SOFTWARE_RESET); |
549 | if (ret < 0) | 536 | if (ret < 0) |
550 | return ret; | 537 | return ret; |
551 | if (ret != wm9090_reg_defaults[WM9090_SOFTWARE_RESET]) { | 538 | if (ret != 0x9093) { |
552 | dev_err(codec->dev, "Device is not a WM9090, ID=%x\n", ret); | 539 | dev_err(codec->dev, "Device is not a WM9090, ID=%x\n", ret); |
553 | return -EINVAL; | 540 | return -EINVAL; |
554 | } | 541 | } |
@@ -624,12 +611,22 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9090 = { | |||
624 | .suspend = wm9090_suspend, | 611 | .suspend = wm9090_suspend, |
625 | .resume = wm9090_resume, | 612 | .resume = wm9090_resume, |
626 | .set_bias_level = wm9090_set_bias_level, | 613 | .set_bias_level = wm9090_set_bias_level, |
627 | .reg_cache_size = (WM9090_MAX_REGISTER + 1), | ||
628 | .reg_word_size = sizeof(u16), | ||
629 | .reg_cache_default = wm9090_reg_defaults, | ||
630 | .volatile_register = wm9090_volatile, | ||
631 | }; | 614 | }; |
632 | 615 | ||
616 | static const struct regmap_config wm9090_regmap = { | ||
617 | .reg_bits = 8, | ||
618 | .val_bits = 16, | ||
619 | |||
620 | .max_register = WM9090_MAX_REGISTER, | ||
621 | .volatile_reg = wm9090_volatile, | ||
622 | .readable_reg = wm9090_readable, | ||
623 | |||
624 | .cache_type = REGCACHE_RBTREE, | ||
625 | .reg_defaults = wm9090_reg_defaults, | ||
626 | .num_reg_defaults = ARRAY_SIZE(wm9090_reg_defaults), | ||
627 | }; | ||
628 | |||
629 | |||
633 | static int wm9090_i2c_probe(struct i2c_client *i2c, | 630 | static int wm9090_i2c_probe(struct i2c_client *i2c, |
634 | const struct i2c_device_id *id) | 631 | const struct i2c_device_id *id) |
635 | { | 632 | { |
@@ -642,6 +639,13 @@ static int wm9090_i2c_probe(struct i2c_client *i2c, | |||
642 | return -ENOMEM; | 639 | return -ENOMEM; |
643 | } | 640 | } |
644 | 641 | ||
642 | wm9090->regmap = regmap_init_i2c(i2c, &wm9090_regmap); | ||
643 | if (IS_ERR(wm9090->regmap)) { | ||
644 | ret = PTR_ERR(wm9090->regmap); | ||
645 | dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); | ||
646 | return ret; | ||
647 | } | ||
648 | |||
645 | if (i2c->dev.platform_data) | 649 | if (i2c->dev.platform_data) |
646 | memcpy(&wm9090->pdata, i2c->dev.platform_data, | 650 | memcpy(&wm9090->pdata, i2c->dev.platform_data, |
647 | sizeof(wm9090->pdata)); | 651 | sizeof(wm9090->pdata)); |
@@ -650,6 +654,15 @@ static int wm9090_i2c_probe(struct i2c_client *i2c, | |||
650 | 654 | ||
651 | ret = snd_soc_register_codec(&i2c->dev, | 655 | ret = snd_soc_register_codec(&i2c->dev, |
652 | &soc_codec_dev_wm9090, NULL, 0); | 656 | &soc_codec_dev_wm9090, NULL, 0); |
657 | if (ret != 0) { | ||
658 | dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); | ||
659 | goto err; | ||
660 | } | ||
661 | |||
662 | return 0; | ||
663 | |||
664 | err: | ||
665 | regmap_exit(wm9090->regmap); | ||
653 | return ret; | 666 | return ret; |
654 | } | 667 | } |
655 | 668 | ||
@@ -658,6 +671,7 @@ static int __devexit wm9090_i2c_remove(struct i2c_client *i2c) | |||
658 | struct wm9090_priv *wm9090 = i2c_get_clientdata(i2c); | 671 | struct wm9090_priv *wm9090 = i2c_get_clientdata(i2c); |
659 | 672 | ||
660 | snd_soc_unregister_codec(&i2c->dev); | 673 | snd_soc_unregister_codec(&i2c->dev); |
674 | regmap_exit(wm9090->regmap); | ||
661 | 675 | ||
662 | return 0; | 676 | return 0; |
663 | } | 677 | } |