diff options
| -rw-r--r-- | sound/soc/fsl/fsl_sai.c | 66 | ||||
| -rw-r--r-- | sound/soc/fsl/fsl_sai.h | 4 | ||||
| -rw-r--r-- | sound/soc/fsl/fsl_utils.c | 131 | ||||
| -rw-r--r-- | sound/soc/fsl/fsl_utils.h | 48 | ||||
| -rw-r--r-- | sound/soc/fsl/fsl_xcvr.c | 64 | ||||
| -rw-r--r-- | sound/soc/fsl/fsl_xcvr.h | 18 |
6 files changed, 331 insertions, 0 deletions
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 148e09e58dfa..bd336d2e4cb3 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -41,6 +41,52 @@ static const struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = { .list = fsl_sai_rates, }; +static const char * const inc_mode[] = { + "On enabled and bitcount increment", "On enabled" +}; + +static SOC_ENUM_SINGLE_DECL(transmit_tstmp_enum, + FSL_SAI_TTCTL, FSL_SAI_xTCTL_TSINC_SHIFT, inc_mode); +static SOC_ENUM_SINGLE_DECL(receive_tstmp_enum, + FSL_SAI_RTCTL, FSL_SAI_xTCTL_TSINC_SHIFT, inc_mode); + +static const struct snd_kcontrol_new fsl_sai_timestamp_ctrls[] = { + FSL_ASOC_SINGLE_EXT("Transmit Timestamp Control Switch", FSL_SAI_TTCTL, + FSL_SAI_xTCTL_TSEN_SHIFT, 1, 0, + fsl_asoc_get_volsw, fsl_asoc_put_volsw), + FSL_ASOC_ENUM_EXT("Transmit Timestamp Increment", transmit_tstmp_enum, + fsl_asoc_get_enum_double, fsl_asoc_put_enum_double), + FSL_ASOC_SINGLE_EXT("Transmit Timestamp Reset Switch", FSL_SAI_TTCTL, + FSL_SAI_xTCTL_RTSC_SHIFT, 1, 0, + fsl_asoc_get_volsw, fsl_asoc_put_volsw), + FSL_ASOC_SINGLE_EXT("Transmit Bit Counter Reset Switch", FSL_SAI_TTCTL, + FSL_SAI_xTCTL_RBC_SHIFT, 1, 0, + fsl_asoc_get_volsw, fsl_asoc_put_volsw), + FSL_ASOC_SINGLE_XR_SX_EXT_RO("Transmit Timestamp Counter", FSL_SAI_TTCTN, + 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx), + FSL_ASOC_SINGLE_XR_SX_EXT_RO("Transmit Bit Counter", FSL_SAI_TBCTN, + 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx), + FSL_ASOC_SINGLE_XR_SX_EXT_RO("Transmit Latched Timestamp Counter", FSL_SAI_TTCAP, + 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx), + FSL_ASOC_SINGLE_EXT("Receive Timestamp Control Switch", FSL_SAI_RTCTL, + FSL_SAI_xTCTL_TSEN_SHIFT, 1, 0, + fsl_asoc_get_volsw, fsl_asoc_put_volsw), + FSL_ASOC_ENUM_EXT("Receive Timestamp Increment", receive_tstmp_enum, + fsl_asoc_get_enum_double, fsl_asoc_put_enum_double), + FSL_ASOC_SINGLE_EXT("Receive Timestamp Reset Switch", FSL_SAI_RTCTL, + FSL_SAI_xTCTL_RTSC_SHIFT, 1, 0, + fsl_asoc_get_volsw, fsl_asoc_put_volsw), + FSL_ASOC_SINGLE_EXT("Receive Bit Counter Reset Switch", FSL_SAI_RTCTL, + FSL_SAI_xTCTL_RBC_SHIFT, 1, 0, + fsl_asoc_get_volsw, fsl_asoc_put_volsw), + FSL_ASOC_SINGLE_XR_SX_EXT_RO("Receive Timestamp Counter", FSL_SAI_RTCTN, + 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx), + FSL_ASOC_SINGLE_XR_SX_EXT_RO("Receive Bit Counter", FSL_SAI_RBCTN, + 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx), + FSL_ASOC_SINGLE_XR_SX_EXT_RO("Receive Latched Timestamp Counter", FSL_SAI_RTCAP, + 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx), +}; + /** * fsl_sai_dir_is_synced - Check if stream is synced by the opposite stream * @@ -1010,6 +1056,17 @@ static int fsl_sai_dai_resume(struct snd_soc_component *component) return 0; } +static int fsl_sai_component_probe(struct snd_soc_component *component) +{ + struct fsl_sai *sai = snd_soc_component_get_drvdata(component); + + if (sai->verid.feature & FSL_SAI_VERID_TSTMP_EN) + snd_soc_add_component_controls(component, fsl_sai_timestamp_ctrls, + ARRAY_SIZE(fsl_sai_timestamp_ctrls)); + + return 0; +} + static struct snd_soc_dai_driver fsl_sai_dai_template[] = { { .name = "sai-tx-rx", @@ -1063,6 +1120,7 @@ static struct snd_soc_dai_driver fsl_sai_dai_template[] = { static const struct snd_soc_component_driver fsl_component = { .name = "fsl-sai", + .probe = fsl_sai_component_probe, .resume = fsl_sai_dai_resume, .legacy_dai_naming = 1, }; @@ -1211,6 +1269,14 @@ static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg) case FSL_SAI_RDR5: case FSL_SAI_RDR6: case FSL_SAI_RDR7: + case FSL_SAI_TTCTN: + case FSL_SAI_RTCTN: + case FSL_SAI_TTCTL: + case FSL_SAI_TBCTN: + case FSL_SAI_TTCAP: + case FSL_SAI_RTCTL: + case FSL_SAI_RBCTN: + case FSL_SAI_RTCAP: return true; default: return false; diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 7605cbaca3d8..af967833b6ed 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -196,9 +196,13 @@ #define FSL_SAI_MDIV_MASK 0xFFFFF /* SAI timestamp and bitcounter */ +#define FSL_SAI_xTCTL_TSEN_SHIFT 0 #define FSL_SAI_xTCTL_TSEN BIT(0) +#define FSL_SAI_xTCTL_TSINC_SHIFT 1 #define FSL_SAI_xTCTL_TSINC BIT(1) +#define FSL_SAI_xTCTL_RTSC_SHIFT 8 #define FSL_SAI_xTCTL_RTSC BIT(8) +#define FSL_SAI_xTCTL_RBC_SHIFT 9 #define FSL_SAI_xTCTL_RBC BIT(9) /* SAI type */ diff --git a/sound/soc/fsl/fsl_utils.c b/sound/soc/fsl/fsl_utils.c index d69a6b9795bf..7651c64bc837 100644 --- a/sound/soc/fsl/fsl_utils.c +++ b/sound/soc/fsl/fsl_utils.c @@ -10,6 +10,7 @@ #include <linux/clk-provider.h> #include <linux/module.h> #include <linux/of_address.h> +#include <linux/pm_runtime.h> #include <sound/soc.h> #include "fsl_utils.h" @@ -197,6 +198,136 @@ void fsl_asoc_constrain_rates(struct snd_pcm_hw_constraint_list *target_constr, } EXPORT_SYMBOL(fsl_asoc_constrain_rates); +/* + * Below functions are used by mixer interface to avoid accessing registers + * which are volatile at pm runtime suspend state (cache_only is enabled). + */ +int fsl_asoc_get_xr_sx(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + int ret = 0; + + ret = pm_runtime_resume_and_get(component->dev); + if (ret) + return ret; + + ret = snd_soc_get_xr_sx(kcontrol, ucontrol); + + pm_runtime_put_autosuspend(component->dev); + + return ret; +} +EXPORT_SYMBOL_GPL(fsl_asoc_get_xr_sx); + +int fsl_asoc_put_xr_sx(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + int ret = 0; + + ret = pm_runtime_resume_and_get(component->dev); + if (ret) + return ret; + + ret = snd_soc_put_xr_sx(kcontrol, ucontrol); + /* + * As this function only used by the SNDRV_CTL_ELEM_ACCESS_VOLATILE + * case. return 0 to avoid control event notification. + */ + if (ret > 0) + ret = 0; + + pm_runtime_put_autosuspend(component->dev); + + return ret; +} +EXPORT_SYMBOL_GPL(fsl_asoc_put_xr_sx); + +int fsl_asoc_get_enum_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + int ret = 0; + + ret = pm_runtime_resume_and_get(component->dev); + if (ret) + return ret; + + ret = snd_soc_get_enum_double(kcontrol, ucontrol); + + pm_runtime_put_autosuspend(component->dev); + + return ret; +} +EXPORT_SYMBOL_GPL(fsl_asoc_get_enum_double); + +int fsl_asoc_put_enum_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + int ret = 0; + + ret = pm_runtime_resume_and_get(component->dev); + if (ret) + return ret; + + ret = snd_soc_put_enum_double(kcontrol, ucontrol); + /* + * As this function only used by the SNDRV_CTL_ELEM_ACCESS_VOLATILE + * case. return 0 to avoid control event notification. + */ + if (ret > 0) + ret = 0; + + pm_runtime_put_autosuspend(component->dev); + + return ret; +} +EXPORT_SYMBOL_GPL(fsl_asoc_put_enum_double); + +int fsl_asoc_get_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + int ret = 0; + + ret = pm_runtime_resume_and_get(component->dev); + if (ret) + return ret; + + ret = snd_soc_get_volsw(kcontrol, ucontrol); + + pm_runtime_put_autosuspend(component->dev); + + return ret; +} +EXPORT_SYMBOL_GPL(fsl_asoc_get_volsw); + +int fsl_asoc_put_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + int ret = 0; + + ret = pm_runtime_resume_and_get(component->dev); + if (ret) + return ret; + + ret = snd_soc_put_volsw(kcontrol, ucontrol); + /* + * As this function only used by the SNDRV_CTL_ELEM_ACCESS_VOLATILE + * case. return 0 to avoid control event notification. + */ + if (ret > 0) + ret = 0; + + pm_runtime_put_autosuspend(component->dev); + + return ret; +} +EXPORT_SYMBOL_GPL(fsl_asoc_put_volsw); + MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); MODULE_DESCRIPTION("Freescale ASoC utility code"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/fsl/fsl_utils.h b/sound/soc/fsl/fsl_utils.h index 21b25a11ecda..1aab0c1cee62 100644 --- a/sound/soc/fsl/fsl_utils.h +++ b/sound/soc/fsl/fsl_utils.h @@ -31,4 +31,52 @@ void fsl_asoc_constrain_rates(struct snd_pcm_hw_constraint_list *target_constr, const struct snd_pcm_hw_constraint_list *original_constr, struct clk *pll8k_clk, struct clk *pll11k_clk, struct clk *ext_clk, int *target_rates); + +/* Similar to SOC_SINGLE_XR_SX, but it is for read only registers. */ +#define FSL_ASOC_SINGLE_XR_SX_EXT_RO(xname, xregbase, xregcount, xnbits, \ + xmin, xmax, xinvert, xhandler_get) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_READ | \ + SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info = snd_soc_info_xr_sx, .get = xhandler_get, \ + .private_value = (unsigned long)&(struct soc_mreg_control) \ + {.regbase = xregbase, .regcount = xregcount, .nbits = xnbits, \ + .invert = xinvert, .min = xmin, .max = xmax} } + +/* Similar to SOC_SINGLE_EXT, but it is for volatile register. */ +#define FSL_ASOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\ + xhandler_get, xhandler_put) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_VOLATILE | \ + SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .info = snd_soc_info_volsw, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = SOC_SINGLE_VALUE(xreg, xshift, 0, xmax, xinvert, 0) } + +#define FSL_ASOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_VOLATILE | \ + SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .info = snd_soc_info_enum_double, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = (unsigned long)&xenum } + +int fsl_asoc_get_xr_sx(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int fsl_asoc_put_xr_sx(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int fsl_asoc_get_enum_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int fsl_asoc_put_enum_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int fsl_asoc_get_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int fsl_asoc_put_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + #endif /* _FSL_UTILS_H */ diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index a268fb81a2f8..de25d9e667ee 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -62,6 +62,58 @@ struct fsl_xcvr { u32 spdif_constr_rates_list[SPDIF_NUM_RATES]; }; +static const char * const inc_mode[] = { + "On enabled and bitcount increment", "On enabled" +}; + +static SOC_ENUM_SINGLE_DECL(transmit_tstmp_enum, + FSL_XCVR_TX_DPTH_CNTR_CTRL, + FSL_XCVR_TX_DPTH_CNTR_CTRL_TSINC_SHIFT, inc_mode); +static SOC_ENUM_SINGLE_DECL(receive_tstmp_enum, + FSL_XCVR_RX_DPTH_CNTR_CTRL, + FSL_XCVR_RX_DPTH_CNTR_CTRL_TSINC_SHIFT, inc_mode); + +static const struct snd_kcontrol_new fsl_xcvr_timestamp_ctrls[] = { + FSL_ASOC_SINGLE_EXT("Transmit Timestamp Control Switch", FSL_XCVR_TX_DPTH_CNTR_CTRL, + FSL_XCVR_TX_DPTH_CNTR_CTRL_TSEN_SHIFT, 1, 0, + fsl_asoc_get_volsw, fsl_asoc_put_volsw), + FSL_ASOC_ENUM_EXT("Transmit Timestamp Increment", transmit_tstmp_enum, + fsl_asoc_get_enum_double, fsl_asoc_put_enum_double), + FSL_ASOC_SINGLE_EXT("Transmit Timestamp Reset Switch", FSL_XCVR_TX_DPTH_CNTR_CTRL, + FSL_XCVR_TX_DPTH_CNTR_CTRL_RTSC_SHIFT, 1, 0, + fsl_asoc_get_volsw, fsl_asoc_put_volsw), + FSL_ASOC_SINGLE_EXT("Transmit Bit Counter Reset Switch", FSL_XCVR_TX_DPTH_CNTR_CTRL, + FSL_XCVR_TX_DPTH_CNTR_CTRL_RBC_SHIFT, 1, 0, + fsl_asoc_get_volsw, fsl_asoc_put_volsw), + FSL_ASOC_SINGLE_XR_SX_EXT_RO("Transmit Timestamp Counter", FSL_XCVR_TX_DPTH_TSCR, + 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx), + FSL_ASOC_SINGLE_XR_SX_EXT_RO("Transmit Bit Counter", FSL_XCVR_TX_DPTH_BCR, + 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx), + FSL_ASOC_SINGLE_XR_SX_EXT_RO("Transmit Bit Count Timestamp", FSL_XCVR_TX_DPTH_BCTR, + 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx), + FSL_ASOC_SINGLE_XR_SX_EXT_RO("Transmit Latched Timestamp Counter", FSL_XCVR_TX_DPTH_BCRR, + 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx), + FSL_ASOC_SINGLE_EXT("Receive Timestamp Control Switch", FSL_XCVR_RX_DPTH_CNTR_CTRL, + FSL_XCVR_RX_DPTH_CNTR_CTRL_TSEN_SHIFT, 1, 0, + fsl_asoc_get_volsw, fsl_asoc_put_volsw), + FSL_ASOC_ENUM_EXT("Receive Timestamp Increment", receive_tstmp_enum, + fsl_asoc_get_enum_double, fsl_asoc_put_enum_double), + FSL_ASOC_SINGLE_EXT("Receive Timestamp Reset Switch", FSL_XCVR_RX_DPTH_CNTR_CTRL, + FSL_XCVR_RX_DPTH_CNTR_CTRL_RTSC_SHIFT, 1, 0, + fsl_asoc_get_volsw, fsl_asoc_put_volsw), + FSL_ASOC_SINGLE_EXT("Receive Bit Counter Reset Switch", FSL_XCVR_RX_DPTH_CNTR_CTRL, + FSL_XCVR_RX_DPTH_CNTR_CTRL_RBC_SHIFT, 1, 0, + fsl_asoc_get_volsw, fsl_asoc_put_volsw), + FSL_ASOC_SINGLE_XR_SX_EXT_RO("Receive Timestamp Counter", FSL_XCVR_RX_DPTH_TSCR, + 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx), + FSL_ASOC_SINGLE_XR_SX_EXT_RO("Receive Bit Counter", FSL_XCVR_RX_DPTH_BCR, + 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx), + FSL_ASOC_SINGLE_XR_SX_EXT_RO("Receive Bit Count Timestamp", FSL_XCVR_RX_DPTH_BCTR, + 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx), + FSL_ASOC_SINGLE_XR_SX_EXT_RO("Receive Latched Timestamp Counter", FSL_XCVR_RX_DPTH_BCRR, + 1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx), +}; + static const struct fsl_xcvr_pll_conf { u8 mfi; /* min=0x18, max=0x38 */ u32 mfn; /* signed int, 2's compl., min=0x3FFF0000, max=0x00010000 */ @@ -1070,8 +1122,20 @@ static struct snd_soc_dai_driver fsl_xcvr_dai = { }, }; +static int fsl_xcvr_component_probe(struct snd_soc_component *component) +{ + struct fsl_xcvr *xcvr = snd_soc_component_get_drvdata(component); + + snd_soc_component_init_regmap(component, xcvr->regmap); + + return 0; +} + static const struct snd_soc_component_driver fsl_xcvr_comp = { .name = "fsl-xcvr-dai", + .probe = fsl_xcvr_component_probe, + .controls = fsl_xcvr_timestamp_ctrls, + .num_controls = ARRAY_SIZE(fsl_xcvr_timestamp_ctrls), .legacy_dai_naming = 1, }; diff --git a/sound/soc/fsl/fsl_xcvr.h b/sound/soc/fsl/fsl_xcvr.h index dade3945cc0c..0cc7945b1d9f 100644 --- a/sound/soc/fsl/fsl_xcvr.h +++ b/sound/soc/fsl/fsl_xcvr.h @@ -233,6 +233,24 @@ #define FSL_XCVR_TX_DPTH_CTRL_CLK_RATIO BIT(29) #define FSL_XCVR_TX_DPTH_CTRL_TM_NO_PRE_BME GENMASK(31, 30) +#define FSL_XCVR_RX_DPTH_CNTR_CTRL_TSEN_SHIFT 0 +#define FSL_XCVR_RX_DPTH_CNTR_CTRL_TSEN BIT(0) +#define FSL_XCVR_RX_DPTH_CNTR_CTRL_TSINC_SHIFT 1 +#define FSL_XCVR_RX_DPTH_CNTR_CTRL_TSINC BIT(1) +#define FSL_XCVR_RX_DPTH_CNTR_CTRL_RBC_SHIFT 8 +#define FSL_XCVR_RX_DPTH_CNTR_CTRL_RBC BIT(8) +#define FSL_XCVR_RX_DPTH_CNTR_CTRL_RTSC_SHIFT 9 +#define FSL_XCVR_RX_DPTH_CNTR_CTRL_RTSC BIT(9) + +#define FSL_XCVR_TX_DPTH_CNTR_CTRL_TSEN_SHIFT 0 +#define FSL_XCVR_TX_DPTH_CNTR_CTRL_TSEN BIT(0) +#define FSL_XCVR_TX_DPTH_CNTR_CTRL_TSINC_SHIFT 1 +#define FSL_XCVR_TX_DPTH_CNTR_CTRL_TSINC BIT(1) +#define FSL_XCVR_TX_DPTH_CNTR_CTRL_RBC_SHIFT 8 +#define FSL_XCVR_TX_DPTH_CNTR_CTRL_RBC BIT(8) +#define FSL_XCVR_TX_DPTH_CNTR_CTRL_RTSC_SHIFT 9 +#define FSL_XCVR_TX_DPTH_CNTR_CTRL_RTSC BIT(9) + #define FSL_XCVR_PHY_AI_CTRL_AI_RESETN BIT(15) #define FSL_XCVR_PHY_AI_CTRL_AI_RWB BIT(31) |
