diff options
Diffstat (limited to 'sound/soc/codecs/wm9090.c')
-rw-r--r-- | sound/soc/codecs/wm9090.c | 272 |
1 files changed, 144 insertions, 128 deletions
diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index 41ebe0dce772..4b263b6edf13 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 | ||
@@ -447,7 +433,7 @@ static int wm9090_add_controls(struct snd_soc_codec *codec) | |||
447 | 433 | ||
448 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | 434 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
449 | 435 | ||
450 | snd_soc_add_controls(codec, wm9090_controls, | 436 | snd_soc_add_codec_controls(codec, wm9090_controls, |
451 | ARRAY_SIZE(wm9090_controls)); | 437 | ARRAY_SIZE(wm9090_controls)); |
452 | 438 | ||
453 | if (wm9090->pdata.lin1_diff) { | 439 | if (wm9090->pdata.lin1_diff) { |
@@ -456,7 +442,7 @@ static int wm9090_add_controls(struct snd_soc_codec *codec) | |||
456 | } else { | 442 | } else { |
457 | snd_soc_dapm_add_routes(dapm, audio_map_in1_se, | 443 | snd_soc_dapm_add_routes(dapm, audio_map_in1_se, |
458 | ARRAY_SIZE(audio_map_in1_se)); | 444 | ARRAY_SIZE(audio_map_in1_se)); |
459 | snd_soc_add_controls(codec, wm9090_in1_se_controls, | 445 | snd_soc_add_codec_controls(codec, wm9090_in1_se_controls, |
460 | ARRAY_SIZE(wm9090_in1_se_controls)); | 446 | ARRAY_SIZE(wm9090_in1_se_controls)); |
461 | } | 447 | } |
462 | 448 | ||
@@ -466,7 +452,7 @@ static int wm9090_add_controls(struct snd_soc_codec *codec) | |||
466 | } else { | 452 | } else { |
467 | snd_soc_dapm_add_routes(dapm, audio_map_in2_se, | 453 | snd_soc_dapm_add_routes(dapm, audio_map_in2_se, |
468 | ARRAY_SIZE(audio_map_in2_se)); | 454 | ARRAY_SIZE(audio_map_in2_se)); |
469 | snd_soc_add_controls(codec, wm9090_in2_se_controls, | 455 | snd_soc_add_codec_controls(codec, wm9090_in2_se_controls, |
470 | ARRAY_SIZE(wm9090_in2_se_controls)); | 456 | ARRAY_SIZE(wm9090_in2_se_controls)); |
471 | } | 457 | } |
472 | 458 | ||
@@ -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,26 +522,16 @@ 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; |
546 | } | 533 | } |
547 | 534 | ||
548 | ret = snd_soc_read(codec, WM9090_SOFTWARE_RESET); | ||
549 | if (ret < 0) | ||
550 | return ret; | ||
551 | if (ret != wm9090_reg_defaults[WM9090_SOFTWARE_RESET]) { | ||
552 | dev_err(codec->dev, "Device is not a WM9090, ID=%x\n", ret); | ||
553 | return -EINVAL; | ||
554 | } | ||
555 | |||
556 | ret = snd_soc_write(codec, WM9090_SOFTWARE_RESET, 0); | ||
557 | if (ret < 0) | ||
558 | return ret; | ||
559 | |||
560 | /* Configure some defaults; they will be written out when we | 535 | /* Configure some defaults; they will be written out when we |
561 | * bring the bias up. | 536 | * bring the bias up. |
562 | */ | 537 | */ |
@@ -624,16 +599,27 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9090 = { | |||
624 | .suspend = wm9090_suspend, | 599 | .suspend = wm9090_suspend, |
625 | .resume = wm9090_resume, | 600 | .resume = wm9090_resume, |
626 | .set_bias_level = wm9090_set_bias_level, | 601 | .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 | }; | 602 | }; |
632 | 603 | ||
604 | static const struct regmap_config wm9090_regmap = { | ||
605 | .reg_bits = 8, | ||
606 | .val_bits = 16, | ||
607 | |||
608 | .max_register = WM9090_MAX_REGISTER, | ||
609 | .volatile_reg = wm9090_volatile, | ||
610 | .readable_reg = wm9090_readable, | ||
611 | |||
612 | .cache_type = REGCACHE_RBTREE, | ||
613 | .reg_defaults = wm9090_reg_defaults, | ||
614 | .num_reg_defaults = ARRAY_SIZE(wm9090_reg_defaults), | ||
615 | }; | ||
616 | |||
617 | |||
633 | static int wm9090_i2c_probe(struct i2c_client *i2c, | 618 | static int wm9090_i2c_probe(struct i2c_client *i2c, |
634 | const struct i2c_device_id *id) | 619 | const struct i2c_device_id *id) |
635 | { | 620 | { |
636 | struct wm9090_priv *wm9090; | 621 | struct wm9090_priv *wm9090; |
622 | unsigned int reg; | ||
637 | int ret; | 623 | int ret; |
638 | 624 | ||
639 | wm9090 = devm_kzalloc(&i2c->dev, sizeof(*wm9090), GFP_KERNEL); | 625 | wm9090 = devm_kzalloc(&i2c->dev, sizeof(*wm9090), GFP_KERNEL); |
@@ -642,6 +628,26 @@ static int wm9090_i2c_probe(struct i2c_client *i2c, | |||
642 | return -ENOMEM; | 628 | return -ENOMEM; |
643 | } | 629 | } |
644 | 630 | ||
631 | wm9090->regmap = regmap_init_i2c(i2c, &wm9090_regmap); | ||
632 | if (IS_ERR(wm9090->regmap)) { | ||
633 | ret = PTR_ERR(wm9090->regmap); | ||
634 | dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); | ||
635 | return ret; | ||
636 | } | ||
637 | |||
638 | ret = regmap_read(wm9090->regmap, WM9090_SOFTWARE_RESET, ®); | ||
639 | if (ret < 0) | ||
640 | goto err; | ||
641 | if (reg != 0x9093) { | ||
642 | dev_err(&i2c->dev, "Device is not a WM9090, ID=%x\n", reg); | ||
643 | ret = -ENODEV; | ||
644 | goto err; | ||
645 | } | ||
646 | |||
647 | ret = regmap_write(wm9090->regmap, WM9090_SOFTWARE_RESET, 0); | ||
648 | if (ret < 0) | ||
649 | goto err; | ||
650 | |||
645 | if (i2c->dev.platform_data) | 651 | if (i2c->dev.platform_data) |
646 | memcpy(&wm9090->pdata, i2c->dev.platform_data, | 652 | memcpy(&wm9090->pdata, i2c->dev.platform_data, |
647 | sizeof(wm9090->pdata)); | 653 | sizeof(wm9090->pdata)); |
@@ -650,6 +656,15 @@ static int wm9090_i2c_probe(struct i2c_client *i2c, | |||
650 | 656 | ||
651 | ret = snd_soc_register_codec(&i2c->dev, | 657 | ret = snd_soc_register_codec(&i2c->dev, |
652 | &soc_codec_dev_wm9090, NULL, 0); | 658 | &soc_codec_dev_wm9090, NULL, 0); |
659 | if (ret != 0) { | ||
660 | dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); | ||
661 | goto err; | ||
662 | } | ||
663 | |||
664 | return 0; | ||
665 | |||
666 | err: | ||
667 | regmap_exit(wm9090->regmap); | ||
653 | return ret; | 668 | return ret; |
654 | } | 669 | } |
655 | 670 | ||
@@ -658,6 +673,7 @@ static int __devexit wm9090_i2c_remove(struct i2c_client *i2c) | |||
658 | struct wm9090_priv *wm9090 = i2c_get_clientdata(i2c); | 673 | struct wm9090_priv *wm9090 = i2c_get_clientdata(i2c); |
659 | 674 | ||
660 | snd_soc_unregister_codec(&i2c->dev); | 675 | snd_soc_unregister_codec(&i2c->dev); |
676 | regmap_exit(wm9090->regmap); | ||
661 | 677 | ||
662 | return 0; | 678 | return 0; |
663 | } | 679 | } |