diff options
Diffstat (limited to 'sound/soc/codecs/arizona.c')
-rw-r--r-- | sound/soc/codecs/arizona.c | 264 |
1 files changed, 206 insertions, 58 deletions
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index ef62c435848e..ac948a671ea6 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c | |||
@@ -56,14 +56,14 @@ | |||
56 | #define arizona_fll_warn(_fll, fmt, ...) \ | 56 | #define arizona_fll_warn(_fll, fmt, ...) \ |
57 | dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__) | 57 | dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__) |
58 | #define arizona_fll_dbg(_fll, fmt, ...) \ | 58 | #define arizona_fll_dbg(_fll, fmt, ...) \ |
59 | dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__) | 59 | dev_dbg(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__) |
60 | 60 | ||
61 | #define arizona_aif_err(_dai, fmt, ...) \ | 61 | #define arizona_aif_err(_dai, fmt, ...) \ |
62 | dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__) | 62 | dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__) |
63 | #define arizona_aif_warn(_dai, fmt, ...) \ | 63 | #define arizona_aif_warn(_dai, fmt, ...) \ |
64 | dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__) | 64 | dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__) |
65 | #define arizona_aif_dbg(_dai, fmt, ...) \ | 65 | #define arizona_aif_dbg(_dai, fmt, ...) \ |
66 | dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__) | 66 | dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__) |
67 | 67 | ||
68 | const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { | 68 | const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { |
69 | "None", | 69 | "None", |
@@ -141,6 +141,30 @@ const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { | |||
141 | "ASRC1R", | 141 | "ASRC1R", |
142 | "ASRC2L", | 142 | "ASRC2L", |
143 | "ASRC2R", | 143 | "ASRC2R", |
144 | "ISRC1INT1", | ||
145 | "ISRC1INT2", | ||
146 | "ISRC1INT3", | ||
147 | "ISRC1INT4", | ||
148 | "ISRC1DEC1", | ||
149 | "ISRC1DEC2", | ||
150 | "ISRC1DEC3", | ||
151 | "ISRC1DEC4", | ||
152 | "ISRC2INT1", | ||
153 | "ISRC2INT2", | ||
154 | "ISRC2INT3", | ||
155 | "ISRC2INT4", | ||
156 | "ISRC2DEC1", | ||
157 | "ISRC2DEC2", | ||
158 | "ISRC2DEC3", | ||
159 | "ISRC2DEC4", | ||
160 | "ISRC3INT1", | ||
161 | "ISRC3INT2", | ||
162 | "ISRC3INT3", | ||
163 | "ISRC3INT4", | ||
164 | "ISRC3DEC1", | ||
165 | "ISRC3DEC2", | ||
166 | "ISRC3DEC3", | ||
167 | "ISRC3DEC4", | ||
144 | }; | 168 | }; |
145 | EXPORT_SYMBOL_GPL(arizona_mixer_texts); | 169 | EXPORT_SYMBOL_GPL(arizona_mixer_texts); |
146 | 170 | ||
@@ -220,6 +244,30 @@ int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = { | |||
220 | 0x91, | 244 | 0x91, |
221 | 0x92, | 245 | 0x92, |
222 | 0x93, | 246 | 0x93, |
247 | 0xa0, /* ISRC1INT1 */ | ||
248 | 0xa1, | ||
249 | 0xa2, | ||
250 | 0xa3, | ||
251 | 0xa4, /* ISRC1DEC1 */ | ||
252 | 0xa5, | ||
253 | 0xa6, | ||
254 | 0xa7, | ||
255 | 0xa8, /* ISRC2DEC1 */ | ||
256 | 0xa9, | ||
257 | 0xaa, | ||
258 | 0xab, | ||
259 | 0xac, /* ISRC2INT1 */ | ||
260 | 0xad, | ||
261 | 0xae, | ||
262 | 0xaf, | ||
263 | 0xb0, /* ISRC3DEC1 */ | ||
264 | 0xb1, | ||
265 | 0xb2, | ||
266 | 0xb3, | ||
267 | 0xb4, /* ISRC3INT1 */ | ||
268 | 0xb5, | ||
269 | 0xb6, | ||
270 | 0xb7, | ||
223 | }; | 271 | }; |
224 | EXPORT_SYMBOL_GPL(arizona_mixer_values); | 272 | EXPORT_SYMBOL_GPL(arizona_mixer_values); |
225 | 273 | ||
@@ -275,9 +323,35 @@ const struct soc_enum arizona_lhpf4_mode = | |||
275 | arizona_lhpf_mode_text); | 323 | arizona_lhpf_mode_text); |
276 | EXPORT_SYMBOL_GPL(arizona_lhpf4_mode); | 324 | EXPORT_SYMBOL_GPL(arizona_lhpf4_mode); |
277 | 325 | ||
326 | static const char *arizona_ng_hold_text[] = { | ||
327 | "30ms", "120ms", "250ms", "500ms", | ||
328 | }; | ||
329 | |||
330 | const struct soc_enum arizona_ng_hold = | ||
331 | SOC_ENUM_SINGLE(ARIZONA_NOISE_GATE_CONTROL, ARIZONA_NGATE_HOLD_SHIFT, | ||
332 | 4, arizona_ng_hold_text); | ||
333 | EXPORT_SYMBOL_GPL(arizona_ng_hold); | ||
334 | |||
278 | int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, | 335 | int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, |
279 | int event) | 336 | int event) |
280 | { | 337 | { |
338 | unsigned int reg; | ||
339 | |||
340 | if (w->shift % 2) | ||
341 | reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8); | ||
342 | else | ||
343 | reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8); | ||
344 | |||
345 | switch (event) { | ||
346 | case SND_SOC_DAPM_POST_PMU: | ||
347 | snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0); | ||
348 | break; | ||
349 | case SND_SOC_DAPM_PRE_PMD: | ||
350 | snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, | ||
351 | ARIZONA_IN1L_MUTE); | ||
352 | break; | ||
353 | } | ||
354 | |||
281 | return 0; | 355 | return 0; |
282 | } | 356 | } |
283 | EXPORT_SYMBOL_GPL(arizona_in_ev); | 357 | EXPORT_SYMBOL_GPL(arizona_in_ev); |
@@ -417,6 +491,10 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, | |||
417 | case 147456000: | 491 | case 147456000: |
418 | val |= 6 << ARIZONA_SYSCLK_FREQ_SHIFT; | 492 | val |= 6 << ARIZONA_SYSCLK_FREQ_SHIFT; |
419 | break; | 493 | break; |
494 | case 0: | ||
495 | dev_dbg(arizona->dev, "%s cleared\n", name); | ||
496 | *clk = freq; | ||
497 | return 0; | ||
420 | default: | 498 | default: |
421 | return -EINVAL; | 499 | return -EINVAL; |
422 | } | 500 | } |
@@ -635,6 +713,9 @@ static int arizona_startup(struct snd_pcm_substream *substream, | |||
635 | return 0; | 713 | return 0; |
636 | } | 714 | } |
637 | 715 | ||
716 | if (base_rate == 0) | ||
717 | return 0; | ||
718 | |||
638 | if (base_rate % 8000) | 719 | if (base_rate % 8000) |
639 | constraint = &arizona_44k1_constraint; | 720 | constraint = &arizona_44k1_constraint; |
640 | else | 721 | else |
@@ -645,25 +726,81 @@ static int arizona_startup(struct snd_pcm_substream *substream, | |||
645 | constraint); | 726 | constraint); |
646 | } | 727 | } |
647 | 728 | ||
729 | static int arizona_hw_params_rate(struct snd_pcm_substream *substream, | ||
730 | struct snd_pcm_hw_params *params, | ||
731 | struct snd_soc_dai *dai) | ||
732 | { | ||
733 | struct snd_soc_codec *codec = dai->codec; | ||
734 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
735 | struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1]; | ||
736 | int base = dai->driver->base; | ||
737 | int i, sr_val; | ||
738 | |||
739 | /* | ||
740 | * We will need to be more flexible than this in future, | ||
741 | * currently we use a single sample rate for SYSCLK. | ||
742 | */ | ||
743 | for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++) | ||
744 | if (arizona_sr_vals[i] == params_rate(params)) | ||
745 | break; | ||
746 | if (i == ARRAY_SIZE(arizona_sr_vals)) { | ||
747 | arizona_aif_err(dai, "Unsupported sample rate %dHz\n", | ||
748 | params_rate(params)); | ||
749 | return -EINVAL; | ||
750 | } | ||
751 | sr_val = i; | ||
752 | |||
753 | switch (dai_priv->clk) { | ||
754 | case ARIZONA_CLK_SYSCLK: | ||
755 | snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1, | ||
756 | ARIZONA_SAMPLE_RATE_1_MASK, sr_val); | ||
757 | if (base) | ||
758 | snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL, | ||
759 | ARIZONA_AIF1_RATE_MASK, 0); | ||
760 | break; | ||
761 | case ARIZONA_CLK_ASYNCCLK: | ||
762 | snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1, | ||
763 | ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val); | ||
764 | if (base) | ||
765 | snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL, | ||
766 | ARIZONA_AIF1_RATE_MASK, | ||
767 | 8 << ARIZONA_AIF1_RATE_SHIFT); | ||
768 | break; | ||
769 | default: | ||
770 | arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk); | ||
771 | return -EINVAL; | ||
772 | } | ||
773 | |||
774 | return 0; | ||
775 | } | ||
776 | |||
648 | static int arizona_hw_params(struct snd_pcm_substream *substream, | 777 | static int arizona_hw_params(struct snd_pcm_substream *substream, |
649 | struct snd_pcm_hw_params *params, | 778 | struct snd_pcm_hw_params *params, |
650 | struct snd_soc_dai *dai) | 779 | struct snd_soc_dai *dai) |
651 | { | 780 | { |
652 | struct snd_soc_codec *codec = dai->codec; | 781 | struct snd_soc_codec *codec = dai->codec; |
653 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | 782 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); |
654 | struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1]; | 783 | struct arizona *arizona = priv->arizona; |
655 | int base = dai->driver->base; | 784 | int base = dai->driver->base; |
656 | const int *rates; | 785 | const int *rates; |
657 | int i; | 786 | int i, ret; |
658 | int bclk, lrclk, wl, frame, sr_val; | 787 | int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1]; |
788 | int bclk, lrclk, wl, frame, bclk_target; | ||
659 | 789 | ||
660 | if (params_rate(params) % 8000) | 790 | if (params_rate(params) % 8000) |
661 | rates = &arizona_44k1_bclk_rates[0]; | 791 | rates = &arizona_44k1_bclk_rates[0]; |
662 | else | 792 | else |
663 | rates = &arizona_48k_bclk_rates[0]; | 793 | rates = &arizona_48k_bclk_rates[0]; |
664 | 794 | ||
795 | bclk_target = snd_soc_params_to_bclk(params); | ||
796 | if (chan_limit && chan_limit < params_channels(params)) { | ||
797 | arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit); | ||
798 | bclk_target /= params_channels(params); | ||
799 | bclk_target *= chan_limit; | ||
800 | } | ||
801 | |||
665 | for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) { | 802 | for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) { |
666 | if (rates[i] >= snd_soc_params_to_bclk(params) && | 803 | if (rates[i] >= bclk_target && |
667 | rates[i] % params_rate(params) == 0) { | 804 | rates[i] % params_rate(params) == 0) { |
668 | bclk = i; | 805 | bclk = i; |
669 | break; | 806 | break; |
@@ -675,16 +812,6 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, | |||
675 | return -EINVAL; | 812 | return -EINVAL; |
676 | } | 813 | } |
677 | 814 | ||
678 | for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++) | ||
679 | if (arizona_sr_vals[i] == params_rate(params)) | ||
680 | break; | ||
681 | if (i == ARRAY_SIZE(arizona_sr_vals)) { | ||
682 | arizona_aif_err(dai, "Unsupported sample rate %dHz\n", | ||
683 | params_rate(params)); | ||
684 | return -EINVAL; | ||
685 | } | ||
686 | sr_val = i; | ||
687 | |||
688 | lrclk = rates[bclk] / params_rate(params); | 815 | lrclk = rates[bclk] / params_rate(params); |
689 | 816 | ||
690 | arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n", | 817 | arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n", |
@@ -693,28 +820,9 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, | |||
693 | wl = snd_pcm_format_width(params_format(params)); | 820 | wl = snd_pcm_format_width(params_format(params)); |
694 | frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl; | 821 | frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl; |
695 | 822 | ||
696 | /* | 823 | ret = arizona_hw_params_rate(substream, params, dai); |
697 | * We will need to be more flexible than this in future, | 824 | if (ret != 0) |
698 | * currently we use a single sample rate for SYSCLK. | 825 | return ret; |
699 | */ | ||
700 | switch (dai_priv->clk) { | ||
701 | case ARIZONA_CLK_SYSCLK: | ||
702 | snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1, | ||
703 | ARIZONA_SAMPLE_RATE_1_MASK, sr_val); | ||
704 | snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL, | ||
705 | ARIZONA_AIF1_RATE_MASK, 0); | ||
706 | break; | ||
707 | case ARIZONA_CLK_ASYNCCLK: | ||
708 | snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1, | ||
709 | ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val); | ||
710 | snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL, | ||
711 | ARIZONA_AIF1_RATE_MASK, | ||
712 | 8 << ARIZONA_AIF1_RATE_SHIFT); | ||
713 | break; | ||
714 | default: | ||
715 | arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk); | ||
716 | return -EINVAL; | ||
717 | } | ||
718 | 826 | ||
719 | snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL, | 827 | snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL, |
720 | ARIZONA_AIF1_BCLK_FREQ_MASK, bclk); | 828 | ARIZONA_AIF1_BCLK_FREQ_MASK, bclk); |
@@ -789,11 +897,27 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai, | |||
789 | return snd_soc_dapm_sync(&codec->dapm); | 897 | return snd_soc_dapm_sync(&codec->dapm); |
790 | } | 898 | } |
791 | 899 | ||
900 | static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate) | ||
901 | { | ||
902 | struct snd_soc_codec *codec = dai->codec; | ||
903 | int base = dai->driver->base; | ||
904 | unsigned int reg; | ||
905 | |||
906 | if (tristate) | ||
907 | reg = ARIZONA_AIF1_TRI; | ||
908 | else | ||
909 | reg = 0; | ||
910 | |||
911 | return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL, | ||
912 | ARIZONA_AIF1_TRI, reg); | ||
913 | } | ||
914 | |||
792 | const struct snd_soc_dai_ops arizona_dai_ops = { | 915 | const struct snd_soc_dai_ops arizona_dai_ops = { |
793 | .startup = arizona_startup, | 916 | .startup = arizona_startup, |
794 | .set_fmt = arizona_set_fmt, | 917 | .set_fmt = arizona_set_fmt, |
795 | .hw_params = arizona_hw_params, | 918 | .hw_params = arizona_hw_params, |
796 | .set_sysclk = arizona_dai_set_sysclk, | 919 | .set_sysclk = arizona_dai_set_sysclk, |
920 | .set_tristate = arizona_set_tristate, | ||
797 | }; | 921 | }; |
798 | EXPORT_SYMBOL_GPL(arizona_dai_ops); | 922 | EXPORT_SYMBOL_GPL(arizona_dai_ops); |
799 | 923 | ||
@@ -807,17 +931,6 @@ int arizona_init_dai(struct arizona_priv *priv, int id) | |||
807 | } | 931 | } |
808 | EXPORT_SYMBOL_GPL(arizona_init_dai); | 932 | EXPORT_SYMBOL_GPL(arizona_init_dai); |
809 | 933 | ||
810 | static irqreturn_t arizona_fll_lock(int irq, void *data) | ||
811 | { | ||
812 | struct arizona_fll *fll = data; | ||
813 | |||
814 | arizona_fll_dbg(fll, "Lock status changed\n"); | ||
815 | |||
816 | complete(&fll->lock); | ||
817 | |||
818 | return IRQ_HANDLED; | ||
819 | } | ||
820 | |||
821 | static irqreturn_t arizona_fll_clock_ok(int irq, void *data) | 934 | static irqreturn_t arizona_fll_clock_ok(int irq, void *data) |
822 | { | 935 | { |
823 | struct arizona_fll *fll = data; | 936 | struct arizona_fll *fll = data; |
@@ -910,7 +1023,7 @@ static int arizona_calc_fll(struct arizona_fll *fll, | |||
910 | 1023 | ||
911 | cfg->n = target / (ratio * Fref); | 1024 | cfg->n = target / (ratio * Fref); |
912 | 1025 | ||
913 | if (target % Fref) { | 1026 | if (target % (ratio * Fref)) { |
914 | gcd_fll = gcd(target, ratio * Fref); | 1027 | gcd_fll = gcd(target, ratio * Fref); |
915 | arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll); | 1028 | arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll); |
916 | 1029 | ||
@@ -922,6 +1035,15 @@ static int arizona_calc_fll(struct arizona_fll *fll, | |||
922 | cfg->lambda = 0; | 1035 | cfg->lambda = 0; |
923 | } | 1036 | } |
924 | 1037 | ||
1038 | /* Round down to 16bit range with cost of accuracy lost. | ||
1039 | * Denominator must be bigger than numerator so we only | ||
1040 | * take care of it. | ||
1041 | */ | ||
1042 | while (cfg->lambda >= (1 << 16)) { | ||
1043 | cfg->theta >>= 1; | ||
1044 | cfg->lambda >>= 1; | ||
1045 | } | ||
1046 | |||
925 | arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n", | 1047 | arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n", |
926 | cfg->n, cfg->theta, cfg->lambda); | 1048 | cfg->n, cfg->theta, cfg->lambda); |
927 | arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n", | 1049 | arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n", |
@@ -1057,7 +1179,6 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, | |||
1057 | { | 1179 | { |
1058 | int ret; | 1180 | int ret; |
1059 | 1181 | ||
1060 | init_completion(&fll->lock); | ||
1061 | init_completion(&fll->ok); | 1182 | init_completion(&fll->ok); |
1062 | 1183 | ||
1063 | fll->id = id; | 1184 | fll->id = id; |
@@ -1068,13 +1189,6 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, | |||
1068 | snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name), | 1189 | snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name), |
1069 | "FLL%d clock OK", id); | 1190 | "FLL%d clock OK", id); |
1070 | 1191 | ||
1071 | ret = arizona_request_irq(arizona, lock_irq, fll->lock_name, | ||
1072 | arizona_fll_lock, fll); | ||
1073 | if (ret != 0) { | ||
1074 | dev_err(arizona->dev, "Failed to get FLL%d lock IRQ: %d\n", | ||
1075 | id, ret); | ||
1076 | } | ||
1077 | |||
1078 | ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name, | 1192 | ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name, |
1079 | arizona_fll_clock_ok, fll); | 1193 | arizona_fll_clock_ok, fll); |
1080 | if (ret != 0) { | 1194 | if (ret != 0) { |
@@ -1089,6 +1203,40 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, | |||
1089 | } | 1203 | } |
1090 | EXPORT_SYMBOL_GPL(arizona_init_fll); | 1204 | EXPORT_SYMBOL_GPL(arizona_init_fll); |
1091 | 1205 | ||
1206 | /** | ||
1207 | * arizona_set_output_mode - Set the mode of the specified output | ||
1208 | * | ||
1209 | * @codec: Device to configure | ||
1210 | * @output: Output number | ||
1211 | * @diff: True to set the output to differential mode | ||
1212 | * | ||
1213 | * Some systems use external analogue switches to connect more | ||
1214 | * analogue devices to the CODEC than are supported by the device. In | ||
1215 | * some systems this requires changing the switched output from single | ||
1216 | * ended to differential mode dynamically at runtime, an operation | ||
1217 | * supported using this function. | ||
1218 | * | ||
1219 | * Most systems have a single static configuration and should use | ||
1220 | * platform data instead. | ||
1221 | */ | ||
1222 | int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff) | ||
1223 | { | ||
1224 | unsigned int reg, val; | ||
1225 | |||
1226 | if (output < 1 || output > 6) | ||
1227 | return -EINVAL; | ||
1228 | |||
1229 | reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8; | ||
1230 | |||
1231 | if (diff) | ||
1232 | val = ARIZONA_OUT1_MONO; | ||
1233 | else | ||
1234 | val = 0; | ||
1235 | |||
1236 | return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val); | ||
1237 | } | ||
1238 | EXPORT_SYMBOL_GPL(arizona_set_output_mode); | ||
1239 | |||
1092 | MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support"); | 1240 | MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support"); |
1093 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | 1241 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); |
1094 | MODULE_LICENSE("GPL"); | 1242 | MODULE_LICENSE("GPL"); |