| .. | .. |
|---|
| 31 | 31 | #define PDM_FILTER_DELAY_MS_MIN (20) |
|---|
| 32 | 32 | #define PDM_FILTER_DELAY_MS_MAX (1000) |
|---|
| 33 | 33 | #define PDM_CLK_SHIFT_PPM_MAX (1000000) /* 1 ppm */ |
|---|
| 34 | | -#define CLK_PPM_MIN (-1000) |
|---|
| 35 | | -#define CLK_PPM_MAX (1000) |
|---|
| 34 | +#define CLK_PPM_MIN (-1000) |
|---|
| 35 | +#define CLK_PPM_MAX (1000) |
|---|
| 36 | + |
|---|
| 37 | +#define QUIRK_ALWAYS_ON BIT(0) |
|---|
| 36 | 38 | |
|---|
| 37 | 39 | enum rk_pdm_version { |
|---|
| 38 | 40 | RK_PDM_RK3229, |
|---|
| .. | .. |
|---|
| 56 | 58 | enum rk_pdm_version version; |
|---|
| 57 | 59 | unsigned int clk_root_rate; |
|---|
| 58 | 60 | unsigned int clk_root_initial_rate; |
|---|
| 61 | + unsigned int quirks; |
|---|
| 59 | 62 | int clk_ppm; |
|---|
| 60 | 63 | bool clk_calibrate; |
|---|
| 61 | 64 | }; |
|---|
| .. | .. |
|---|
| 95 | 98 | { 4, 12000 }, |
|---|
| 96 | 99 | { 4, 11025 }, |
|---|
| 97 | 100 | { 4, 8000 }, |
|---|
| 101 | +}; |
|---|
| 102 | + |
|---|
| 103 | +static const struct pdm_of_quirks { |
|---|
| 104 | + char *quirk; |
|---|
| 105 | + int id; |
|---|
| 106 | +} of_quirks[] = { |
|---|
| 107 | + { |
|---|
| 108 | + .quirk = "rockchip,always-on", |
|---|
| 109 | + .id = QUIRK_ALWAYS_ON, |
|---|
| 110 | + }, |
|---|
| 98 | 111 | }; |
|---|
| 99 | 112 | |
|---|
| 100 | 113 | static unsigned int get_pdm_clk(struct rk_pdm_dev *pdm, unsigned int sr, |
|---|
| .. | .. |
|---|
| 508 | 521 | static int rockchip_pdm_start_delay_get(struct snd_kcontrol *kcontrol, |
|---|
| 509 | 522 | struct snd_ctl_elem_value *ucontrol) |
|---|
| 510 | 523 | { |
|---|
| 511 | | - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); |
|---|
| 512 | | - struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai); |
|---|
| 524 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
|---|
| 525 | + struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component); |
|---|
| 513 | 526 | |
|---|
| 514 | 527 | ucontrol->value.integer.value[0] = pdm->start_delay_ms; |
|---|
| 515 | 528 | |
|---|
| .. | .. |
|---|
| 519 | 532 | static int rockchip_pdm_start_delay_put(struct snd_kcontrol *kcontrol, |
|---|
| 520 | 533 | struct snd_ctl_elem_value *ucontrol) |
|---|
| 521 | 534 | { |
|---|
| 522 | | - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); |
|---|
| 523 | | - struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai); |
|---|
| 535 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
|---|
| 536 | + struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component); |
|---|
| 524 | 537 | |
|---|
| 525 | 538 | if ((ucontrol->value.integer.value[0] < PDM_START_DELAY_MS_MIN) || |
|---|
| 526 | 539 | (ucontrol->value.integer.value[0] > PDM_START_DELAY_MS_MAX)) |
|---|
| .. | .. |
|---|
| 546 | 559 | static int rockchip_pdm_filter_delay_get(struct snd_kcontrol *kcontrol, |
|---|
| 547 | 560 | struct snd_ctl_elem_value *ucontrol) |
|---|
| 548 | 561 | { |
|---|
| 549 | | - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); |
|---|
| 550 | | - struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai); |
|---|
| 562 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
|---|
| 563 | + struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component); |
|---|
| 551 | 564 | |
|---|
| 552 | 565 | ucontrol->value.integer.value[0] = pdm->filter_delay_ms; |
|---|
| 553 | 566 | |
|---|
| .. | .. |
|---|
| 557 | 570 | static int rockchip_pdm_filter_delay_put(struct snd_kcontrol *kcontrol, |
|---|
| 558 | 571 | struct snd_ctl_elem_value *ucontrol) |
|---|
| 559 | 572 | { |
|---|
| 560 | | - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); |
|---|
| 561 | | - struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai); |
|---|
| 573 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
|---|
| 574 | + struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component); |
|---|
| 562 | 575 | |
|---|
| 563 | 576 | if ((ucontrol->value.integer.value[0] < PDM_FILTER_DELAY_MS_MIN) || |
|---|
| 564 | 577 | (ucontrol->value.integer.value[0] > PDM_FILTER_DELAY_MS_MAX)) |
|---|
| .. | .. |
|---|
| 577 | 590 | static SOC_ENUM_SINGLE_DECL(rpath1_enum, PDM_CLK_CTRL, 10, rpaths_text); |
|---|
| 578 | 591 | static SOC_ENUM_SINGLE_DECL(rpath0_enum, PDM_CLK_CTRL, 8, rpaths_text); |
|---|
| 579 | 592 | |
|---|
| 593 | +static const char * const hpf_cutoff_text[] = { |
|---|
| 594 | + "3.79Hz", "60Hz", "243Hz", "493Hz", |
|---|
| 595 | +}; |
|---|
| 596 | + |
|---|
| 597 | +static SOC_ENUM_SINGLE_DECL(hpf_cutoff_enum, PDM_HPF_CTRL, |
|---|
| 598 | + 0, hpf_cutoff_text); |
|---|
| 599 | + |
|---|
| 580 | 600 | static const struct snd_kcontrol_new rockchip_pdm_controls[] = { |
|---|
| 581 | 601 | SOC_ENUM("Receive PATH3 Source Select", rpath3_enum), |
|---|
| 582 | 602 | SOC_ENUM("Receive PATH2 Source Select", rpath2_enum), |
|---|
| 583 | 603 | SOC_ENUM("Receive PATH1 Source Select", rpath1_enum), |
|---|
| 584 | 604 | SOC_ENUM("Receive PATH0 Source Select", rpath0_enum), |
|---|
| 605 | + |
|---|
| 606 | + SOC_ENUM("HPF Cutoff", hpf_cutoff_enum), |
|---|
| 607 | + SOC_SINGLE("HPFL Switch", PDM_HPF_CTRL, 3, 1, 0), |
|---|
| 608 | + SOC_SINGLE("HPFR Switch", PDM_HPF_CTRL, 2, 1, 0), |
|---|
| 585 | 609 | |
|---|
| 586 | 610 | { |
|---|
| 587 | 611 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
|---|
| .. | .. |
|---|
| 616 | 640 | struct snd_ctl_elem_value *ucontrol) |
|---|
| 617 | 641 | |
|---|
| 618 | 642 | { |
|---|
| 619 | | - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); |
|---|
| 620 | | - struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai); |
|---|
| 643 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
|---|
| 644 | + struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component); |
|---|
| 621 | 645 | |
|---|
| 622 | 646 | ucontrol->value.integer.value[0] = pdm->clk_ppm; |
|---|
| 623 | 647 | |
|---|
| .. | .. |
|---|
| 627 | 651 | static int rockchip_pdm_clk_compensation_put(struct snd_kcontrol *kcontrol, |
|---|
| 628 | 652 | struct snd_ctl_elem_value *ucontrol) |
|---|
| 629 | 653 | { |
|---|
| 630 | | - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); |
|---|
| 631 | | - struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai); |
|---|
| 654 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
|---|
| 655 | + struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component); |
|---|
| 632 | 656 | |
|---|
| 633 | 657 | int ppm = ucontrol->value.integer.value[0]; |
|---|
| 634 | 658 | |
|---|
| .. | .. |
|---|
| 946 | 970 | return 0; |
|---|
| 947 | 971 | } |
|---|
| 948 | 972 | |
|---|
| 973 | +static int rockchip_pdm_keep_clk_always_on(struct rk_pdm_dev *pdm) |
|---|
| 974 | +{ |
|---|
| 975 | + pm_runtime_forbid(pdm->dev); |
|---|
| 976 | + |
|---|
| 977 | + dev_info(pdm->dev, "CLK-ALWAYS-ON: samplerate: %d\n", PDM_DEFAULT_RATE); |
|---|
| 978 | + |
|---|
| 979 | + return 0; |
|---|
| 980 | +} |
|---|
| 981 | + |
|---|
| 982 | +static int rockchip_pdm_parse_quirks(struct rk_pdm_dev *pdm) |
|---|
| 983 | +{ |
|---|
| 984 | + int ret = 0, i = 0; |
|---|
| 985 | + |
|---|
| 986 | + for (i = 0; i < ARRAY_SIZE(of_quirks); i++) |
|---|
| 987 | + if (device_property_read_bool(pdm->dev, of_quirks[i].quirk)) |
|---|
| 988 | + pdm->quirks |= of_quirks[i].id; |
|---|
| 989 | + |
|---|
| 990 | + if (pdm->quirks & QUIRK_ALWAYS_ON) |
|---|
| 991 | + ret = rockchip_pdm_keep_clk_always_on(pdm); |
|---|
| 992 | + |
|---|
| 993 | + return ret; |
|---|
| 994 | +} |
|---|
| 995 | + |
|---|
| 949 | 996 | static int rockchip_pdm_probe(struct platform_device *pdev) |
|---|
| 950 | 997 | { |
|---|
| 951 | 998 | struct device_node *node = pdev->dev.of_node; |
|---|
| .. | .. |
|---|
| 1027 | 1074 | if (ret != 0 && ret != -ENOENT) |
|---|
| 1028 | 1075 | goto err_clk; |
|---|
| 1029 | 1076 | |
|---|
| 1077 | + ret = rockchip_pdm_parse_quirks(pdm); |
|---|
| 1078 | + if (ret) |
|---|
| 1079 | + goto err_clk; |
|---|
| 1080 | + |
|---|
| 1030 | 1081 | /* |
|---|
| 1031 | 1082 | * MUST: after pm_runtime_enable step, any register R/W |
|---|
| 1032 | 1083 | * should be wrapped with pm_runtime_get_sync/put. |
|---|