diff options
Diffstat (limited to 'sound/soc/codecs/rt5670.c')
-rw-r--r-- | sound/soc/codecs/rt5670.c | 138 |
1 files changed, 131 insertions, 7 deletions
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 8a0833de1665..e1a4a45c57e2 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c | |||
@@ -14,10 +14,12 @@ | |||
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
16 | #include <linux/pm.h> | 16 | #include <linux/pm.h> |
17 | #include <linux/pm_runtime.h> | ||
17 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
18 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
19 | #include <linux/acpi.h> | 20 | #include <linux/acpi.h> |
20 | #include <linux/spi/spi.h> | 21 | #include <linux/spi/spi.h> |
22 | #include <linux/dmi.h> | ||
21 | #include <sound/core.h> | 23 | #include <sound/core.h> |
22 | #include <sound/pcm.h> | 24 | #include <sound/pcm.h> |
23 | #include <sound/pcm_params.h> | 25 | #include <sound/pcm_params.h> |
@@ -498,7 +500,7 @@ static const struct snd_kcontrol_new rt5670_snd_controls[] = { | |||
498 | static int set_dmic_clk(struct snd_soc_dapm_widget *w, | 500 | static int set_dmic_clk(struct snd_soc_dapm_widget *w, |
499 | struct snd_kcontrol *kcontrol, int event) | 501 | struct snd_kcontrol *kcontrol, int event) |
500 | { | 502 | { |
501 | struct snd_soc_codec *codec = w->codec; | 503 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
502 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); | 504 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); |
503 | int idx = -EINVAL; | 505 | int idx = -EINVAL; |
504 | 506 | ||
@@ -515,9 +517,10 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w, | |||
515 | static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, | 517 | static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, |
516 | struct snd_soc_dapm_widget *sink) | 518 | struct snd_soc_dapm_widget *sink) |
517 | { | 519 | { |
520 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); | ||
518 | unsigned int val; | 521 | unsigned int val; |
519 | 522 | ||
520 | val = snd_soc_read(source->codec, RT5670_GLB_CLK); | 523 | val = snd_soc_read(codec, RT5670_GLB_CLK); |
521 | val &= RT5670_SCLK_SRC_MASK; | 524 | val &= RT5670_SCLK_SRC_MASK; |
522 | if (val == RT5670_SCLK_SRC_PLL1) | 525 | if (val == RT5670_SCLK_SRC_PLL1) |
523 | return 1; | 526 | return 1; |
@@ -528,6 +531,7 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, | |||
528 | static int is_using_asrc(struct snd_soc_dapm_widget *source, | 531 | static int is_using_asrc(struct snd_soc_dapm_widget *source, |
529 | struct snd_soc_dapm_widget *sink) | 532 | struct snd_soc_dapm_widget *sink) |
530 | { | 533 | { |
534 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); | ||
531 | unsigned int reg, shift, val; | 535 | unsigned int reg, shift, val; |
532 | 536 | ||
533 | switch (source->shift) { | 537 | switch (source->shift) { |
@@ -563,7 +567,7 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source, | |||
563 | return 0; | 567 | return 0; |
564 | } | 568 | } |
565 | 569 | ||
566 | val = (snd_soc_read(source->codec, reg) >> shift) & 0xf; | 570 | val = (snd_soc_read(codec, reg) >> shift) & 0xf; |
567 | switch (val) { | 571 | switch (val) { |
568 | case 1: | 572 | case 1: |
569 | case 2: | 573 | case 2: |
@@ -588,6 +592,89 @@ static int can_use_asrc(struct snd_soc_dapm_widget *source, | |||
588 | return 0; | 592 | return 0; |
589 | } | 593 | } |
590 | 594 | ||
595 | |||
596 | /** | ||
597 | * rt5670_sel_asrc_clk_src - select ASRC clock source for a set of filters | ||
598 | * @codec: SoC audio codec device. | ||
599 | * @filter_mask: mask of filters. | ||
600 | * @clk_src: clock source | ||
601 | * | ||
602 | * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5670 can | ||
603 | * only support standard 32fs or 64fs i2s format, ASRC should be enabled to | ||
604 | * support special i2s clock format such as Intel's 100fs(100 * sampling rate). | ||
605 | * ASRC function will track i2s clock and generate a corresponding system clock | ||
606 | * for codec. This function provides an API to select the clock source for a | ||
607 | * set of filters specified by the mask. And the codec driver will turn on ASRC | ||
608 | * for these filters if ASRC is selected as their clock source. | ||
609 | */ | ||
610 | int rt5670_sel_asrc_clk_src(struct snd_soc_codec *codec, | ||
611 | unsigned int filter_mask, unsigned int clk_src) | ||
612 | { | ||
613 | unsigned int asrc2_mask = 0, asrc2_value = 0; | ||
614 | unsigned int asrc3_mask = 0, asrc3_value = 0; | ||
615 | |||
616 | if (clk_src > RT5670_CLK_SEL_SYS3) | ||
617 | return -EINVAL; | ||
618 | |||
619 | if (filter_mask & RT5670_DA_STEREO_FILTER) { | ||
620 | asrc2_mask |= RT5670_DA_STO_CLK_SEL_MASK; | ||
621 | asrc2_value = (asrc2_value & ~RT5670_DA_STO_CLK_SEL_MASK) | ||
622 | | (clk_src << RT5670_DA_STO_CLK_SEL_SFT); | ||
623 | } | ||
624 | |||
625 | if (filter_mask & RT5670_DA_MONO_L_FILTER) { | ||
626 | asrc2_mask |= RT5670_DA_MONOL_CLK_SEL_MASK; | ||
627 | asrc2_value = (asrc2_value & ~RT5670_DA_MONOL_CLK_SEL_MASK) | ||
628 | | (clk_src << RT5670_DA_MONOL_CLK_SEL_SFT); | ||
629 | } | ||
630 | |||
631 | if (filter_mask & RT5670_DA_MONO_R_FILTER) { | ||
632 | asrc2_mask |= RT5670_DA_MONOR_CLK_SEL_MASK; | ||
633 | asrc2_value = (asrc2_value & ~RT5670_DA_MONOR_CLK_SEL_MASK) | ||
634 | | (clk_src << RT5670_DA_MONOR_CLK_SEL_SFT); | ||
635 | } | ||
636 | |||
637 | if (filter_mask & RT5670_AD_STEREO_FILTER) { | ||
638 | asrc2_mask |= RT5670_AD_STO1_CLK_SEL_MASK; | ||
639 | asrc2_value = (asrc2_value & ~RT5670_AD_STO1_CLK_SEL_MASK) | ||
640 | | (clk_src << RT5670_AD_STO1_CLK_SEL_SFT); | ||
641 | } | ||
642 | |||
643 | if (filter_mask & RT5670_AD_MONO_L_FILTER) { | ||
644 | asrc3_mask |= RT5670_AD_MONOL_CLK_SEL_MASK; | ||
645 | asrc3_value = (asrc3_value & ~RT5670_AD_MONOL_CLK_SEL_MASK) | ||
646 | | (clk_src << RT5670_AD_MONOL_CLK_SEL_SFT); | ||
647 | } | ||
648 | |||
649 | if (filter_mask & RT5670_AD_MONO_R_FILTER) { | ||
650 | asrc3_mask |= RT5670_AD_MONOR_CLK_SEL_MASK; | ||
651 | asrc3_value = (asrc3_value & ~RT5670_AD_MONOR_CLK_SEL_MASK) | ||
652 | | (clk_src << RT5670_AD_MONOR_CLK_SEL_SFT); | ||
653 | } | ||
654 | |||
655 | if (filter_mask & RT5670_UP_RATE_FILTER) { | ||
656 | asrc3_mask |= RT5670_UP_CLK_SEL_MASK; | ||
657 | asrc3_value = (asrc3_value & ~RT5670_UP_CLK_SEL_MASK) | ||
658 | | (clk_src << RT5670_UP_CLK_SEL_SFT); | ||
659 | } | ||
660 | |||
661 | if (filter_mask & RT5670_DOWN_RATE_FILTER) { | ||
662 | asrc3_mask |= RT5670_DOWN_CLK_SEL_MASK; | ||
663 | asrc3_value = (asrc3_value & ~RT5670_DOWN_CLK_SEL_MASK) | ||
664 | | (clk_src << RT5670_DOWN_CLK_SEL_SFT); | ||
665 | } | ||
666 | |||
667 | if (asrc2_mask) | ||
668 | snd_soc_update_bits(codec, RT5670_ASRC_2, | ||
669 | asrc2_mask, asrc2_value); | ||
670 | |||
671 | if (asrc3_mask) | ||
672 | snd_soc_update_bits(codec, RT5670_ASRC_3, | ||
673 | asrc3_mask, asrc3_value); | ||
674 | return 0; | ||
675 | } | ||
676 | EXPORT_SYMBOL_GPL(rt5670_sel_asrc_clk_src); | ||
677 | |||
591 | /* Digital Mixer */ | 678 | /* Digital Mixer */ |
592 | static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = { | 679 | static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = { |
593 | SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER, | 680 | SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER, |
@@ -1146,7 +1233,7 @@ static const struct snd_kcontrol_new rt5670_vad_adc_mux = | |||
1146 | static int rt5670_hp_power_event(struct snd_soc_dapm_widget *w, | 1233 | static int rt5670_hp_power_event(struct snd_soc_dapm_widget *w, |
1147 | struct snd_kcontrol *kcontrol, int event) | 1234 | struct snd_kcontrol *kcontrol, int event) |
1148 | { | 1235 | { |
1149 | struct snd_soc_codec *codec = w->codec; | 1236 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
1150 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); | 1237 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); |
1151 | 1238 | ||
1152 | switch (event) { | 1239 | switch (event) { |
@@ -1182,7 +1269,7 @@ static int rt5670_hp_power_event(struct snd_soc_dapm_widget *w, | |||
1182 | static int rt5670_hp_event(struct snd_soc_dapm_widget *w, | 1269 | static int rt5670_hp_event(struct snd_soc_dapm_widget *w, |
1183 | struct snd_kcontrol *kcontrol, int event) | 1270 | struct snd_kcontrol *kcontrol, int event) |
1184 | { | 1271 | { |
1185 | struct snd_soc_codec *codec = w->codec; | 1272 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
1186 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); | 1273 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); |
1187 | 1274 | ||
1188 | switch (event) { | 1275 | switch (event) { |
@@ -1232,7 +1319,7 @@ static int rt5670_hp_event(struct snd_soc_dapm_widget *w, | |||
1232 | static int rt5670_bst1_event(struct snd_soc_dapm_widget *w, | 1319 | static int rt5670_bst1_event(struct snd_soc_dapm_widget *w, |
1233 | struct snd_kcontrol *kcontrol, int event) | 1320 | struct snd_kcontrol *kcontrol, int event) |
1234 | { | 1321 | { |
1235 | struct snd_soc_codec *codec = w->codec; | 1322 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
1236 | 1323 | ||
1237 | switch (event) { | 1324 | switch (event) { |
1238 | case SND_SOC_DAPM_POST_PMU: | 1325 | case SND_SOC_DAPM_POST_PMU: |
@@ -1255,7 +1342,7 @@ static int rt5670_bst1_event(struct snd_soc_dapm_widget *w, | |||
1255 | static int rt5670_bst2_event(struct snd_soc_dapm_widget *w, | 1342 | static int rt5670_bst2_event(struct snd_soc_dapm_widget *w, |
1256 | struct snd_kcontrol *kcontrol, int event) | 1343 | struct snd_kcontrol *kcontrol, int event) |
1257 | { | 1344 | { |
1258 | struct snd_soc_codec *codec = w->codec; | 1345 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
1259 | 1346 | ||
1260 | switch (event) { | 1347 | switch (event) { |
1261 | case SND_SOC_DAPM_POST_PMU: | 1348 | case SND_SOC_DAPM_POST_PMU: |
@@ -2188,6 +2275,13 @@ static int rt5670_set_dai_sysclk(struct snd_soc_dai *dai, | |||
2188 | if (freq == rt5670->sysclk && clk_id == rt5670->sysclk_src) | 2275 | if (freq == rt5670->sysclk && clk_id == rt5670->sysclk_src) |
2189 | return 0; | 2276 | return 0; |
2190 | 2277 | ||
2278 | if (rt5670->pdata.jd_mode) { | ||
2279 | if (clk_id == RT5670_SCLK_S_PLL1) | ||
2280 | snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1"); | ||
2281 | else | ||
2282 | snd_soc_dapm_disable_pin(&codec->dapm, "PLL1"); | ||
2283 | snd_soc_dapm_sync(&codec->dapm); | ||
2284 | } | ||
2191 | switch (clk_id) { | 2285 | switch (clk_id) { |
2192 | case RT5670_SCLK_S_MCLK: | 2286 | case RT5670_SCLK_S_MCLK: |
2193 | reg_val |= RT5670_SCLK_SRC_MCLK; | 2287 | reg_val |= RT5670_SCLK_SRC_MCLK; |
@@ -2522,6 +2616,7 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5670 = { | |||
2522 | static const struct regmap_config rt5670_regmap = { | 2616 | static const struct regmap_config rt5670_regmap = { |
2523 | .reg_bits = 8, | 2617 | .reg_bits = 8, |
2524 | .val_bits = 16, | 2618 | .val_bits = 16, |
2619 | .use_single_rw = true, | ||
2525 | .max_register = RT5670_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5670_ranges) * | 2620 | .max_register = RT5670_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5670_ranges) * |
2526 | RT5670_PR_SPACING), | 2621 | RT5670_PR_SPACING), |
2527 | .volatile_reg = rt5670_volatile_register, | 2622 | .volatile_reg = rt5670_volatile_register, |
@@ -2549,6 +2644,17 @@ static struct acpi_device_id rt5670_acpi_match[] = { | |||
2549 | MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match); | 2644 | MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match); |
2550 | #endif | 2645 | #endif |
2551 | 2646 | ||
2647 | static const struct dmi_system_id dmi_platform_intel_braswell[] = { | ||
2648 | { | ||
2649 | .ident = "Intel Braswell", | ||
2650 | .matches = { | ||
2651 | DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), | ||
2652 | DMI_MATCH(DMI_BOARD_NAME, "Braswell CRB"), | ||
2653 | }, | ||
2654 | }, | ||
2655 | {} | ||
2656 | }; | ||
2657 | |||
2552 | static int rt5670_i2c_probe(struct i2c_client *i2c, | 2658 | static int rt5670_i2c_probe(struct i2c_client *i2c, |
2553 | const struct i2c_device_id *id) | 2659 | const struct i2c_device_id *id) |
2554 | { | 2660 | { |
@@ -2568,6 +2674,12 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, | |||
2568 | if (pdata) | 2674 | if (pdata) |
2569 | rt5670->pdata = *pdata; | 2675 | rt5670->pdata = *pdata; |
2570 | 2676 | ||
2677 | if (dmi_check_system(dmi_platform_intel_braswell)) { | ||
2678 | rt5670->pdata.dmic_en = true; | ||
2679 | rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P; | ||
2680 | rt5670->pdata.jd_mode = 1; | ||
2681 | } | ||
2682 | |||
2571 | rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap); | 2683 | rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap); |
2572 | if (IS_ERR(rt5670->regmap)) { | 2684 | if (IS_ERR(rt5670->regmap)) { |
2573 | ret = PTR_ERR(rt5670->regmap); | 2685 | ret = PTR_ERR(rt5670->regmap); |
@@ -2609,6 +2721,10 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, | |||
2609 | } | 2721 | } |
2610 | 2722 | ||
2611 | if (rt5670->pdata.jd_mode) { | 2723 | if (rt5670->pdata.jd_mode) { |
2724 | regmap_update_bits(rt5670->regmap, RT5670_GLB_CLK, | ||
2725 | RT5670_SCLK_SRC_MASK, RT5670_SCLK_SRC_RCCLK); | ||
2726 | rt5670->sysclk = 0; | ||
2727 | rt5670->sysclk_src = RT5670_SCLK_S_RCCLK; | ||
2612 | regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG1, | 2728 | regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG1, |
2613 | RT5670_PWR_MB, RT5670_PWR_MB); | 2729 | RT5670_PWR_MB, RT5670_PWR_MB); |
2614 | regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG2, | 2730 | regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG2, |
@@ -2716,18 +2832,26 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, | |||
2716 | 2832 | ||
2717 | } | 2833 | } |
2718 | 2834 | ||
2835 | pm_runtime_enable(&i2c->dev); | ||
2836 | pm_request_idle(&i2c->dev); | ||
2837 | |||
2719 | ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5670, | 2838 | ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5670, |
2720 | rt5670_dai, ARRAY_SIZE(rt5670_dai)); | 2839 | rt5670_dai, ARRAY_SIZE(rt5670_dai)); |
2721 | if (ret < 0) | 2840 | if (ret < 0) |
2722 | goto err; | 2841 | goto err; |
2723 | 2842 | ||
2843 | pm_runtime_put(&i2c->dev); | ||
2844 | |||
2724 | return 0; | 2845 | return 0; |
2725 | err: | 2846 | err: |
2847 | pm_runtime_disable(&i2c->dev); | ||
2848 | |||
2726 | return ret; | 2849 | return ret; |
2727 | } | 2850 | } |
2728 | 2851 | ||
2729 | static int rt5670_i2c_remove(struct i2c_client *i2c) | 2852 | static int rt5670_i2c_remove(struct i2c_client *i2c) |
2730 | { | 2853 | { |
2854 | pm_runtime_disable(&i2c->dev); | ||
2731 | snd_soc_unregister_codec(&i2c->dev); | 2855 | snd_soc_unregister_codec(&i2c->dev); |
2732 | 2856 | ||
2733 | return 0; | 2857 | return 0; |