Skip to content

Commit 0670bc8

Browse files
committed
ASoC: fsl: add bitcount and timestamp controls
Merge series from Shengjiu Wang <shengjiu.wang@nxp.com>: The SAI and XCVR have the timestamp counters and bit counters, which can be used by software to track the progress of the transmitter and receiver. They can also be used to calculate the relative frequency of the bit clock against the bus interface clock.
2 parents 46b87c3 + 7b3f8db commit 0670bc8

6 files changed

Lines changed: 331 additions & 0 deletions

File tree

sound/soc/fsl/fsl_sai.c

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,52 @@ static const struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = {
4141
.list = fsl_sai_rates,
4242
};
4343

44+
static const char * const inc_mode[] = {
45+
"On enabled and bitcount increment", "On enabled"
46+
};
47+
48+
static SOC_ENUM_SINGLE_DECL(transmit_tstmp_enum,
49+
FSL_SAI_TTCTL, FSL_SAI_xTCTL_TSINC_SHIFT, inc_mode);
50+
static SOC_ENUM_SINGLE_DECL(receive_tstmp_enum,
51+
FSL_SAI_RTCTL, FSL_SAI_xTCTL_TSINC_SHIFT, inc_mode);
52+
53+
static const struct snd_kcontrol_new fsl_sai_timestamp_ctrls[] = {
54+
FSL_ASOC_SINGLE_EXT("Transmit Timestamp Control Switch", FSL_SAI_TTCTL,
55+
FSL_SAI_xTCTL_TSEN_SHIFT, 1, 0,
56+
fsl_asoc_get_volsw, fsl_asoc_put_volsw),
57+
FSL_ASOC_ENUM_EXT("Transmit Timestamp Increment", transmit_tstmp_enum,
58+
fsl_asoc_get_enum_double, fsl_asoc_put_enum_double),
59+
FSL_ASOC_SINGLE_EXT("Transmit Timestamp Reset Switch", FSL_SAI_TTCTL,
60+
FSL_SAI_xTCTL_RTSC_SHIFT, 1, 0,
61+
fsl_asoc_get_volsw, fsl_asoc_put_volsw),
62+
FSL_ASOC_SINGLE_EXT("Transmit Bit Counter Reset Switch", FSL_SAI_TTCTL,
63+
FSL_SAI_xTCTL_RBC_SHIFT, 1, 0,
64+
fsl_asoc_get_volsw, fsl_asoc_put_volsw),
65+
FSL_ASOC_SINGLE_XR_SX_EXT_RO("Transmit Timestamp Counter", FSL_SAI_TTCTN,
66+
1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
67+
FSL_ASOC_SINGLE_XR_SX_EXT_RO("Transmit Bit Counter", FSL_SAI_TBCTN,
68+
1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
69+
FSL_ASOC_SINGLE_XR_SX_EXT_RO("Transmit Latched Timestamp Counter", FSL_SAI_TTCAP,
70+
1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
71+
FSL_ASOC_SINGLE_EXT("Receive Timestamp Control Switch", FSL_SAI_RTCTL,
72+
FSL_SAI_xTCTL_TSEN_SHIFT, 1, 0,
73+
fsl_asoc_get_volsw, fsl_asoc_put_volsw),
74+
FSL_ASOC_ENUM_EXT("Receive Timestamp Increment", receive_tstmp_enum,
75+
fsl_asoc_get_enum_double, fsl_asoc_put_enum_double),
76+
FSL_ASOC_SINGLE_EXT("Receive Timestamp Reset Switch", FSL_SAI_RTCTL,
77+
FSL_SAI_xTCTL_RTSC_SHIFT, 1, 0,
78+
fsl_asoc_get_volsw, fsl_asoc_put_volsw),
79+
FSL_ASOC_SINGLE_EXT("Receive Bit Counter Reset Switch", FSL_SAI_RTCTL,
80+
FSL_SAI_xTCTL_RBC_SHIFT, 1, 0,
81+
fsl_asoc_get_volsw, fsl_asoc_put_volsw),
82+
FSL_ASOC_SINGLE_XR_SX_EXT_RO("Receive Timestamp Counter", FSL_SAI_RTCTN,
83+
1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
84+
FSL_ASOC_SINGLE_XR_SX_EXT_RO("Receive Bit Counter", FSL_SAI_RBCTN,
85+
1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
86+
FSL_ASOC_SINGLE_XR_SX_EXT_RO("Receive Latched Timestamp Counter", FSL_SAI_RTCAP,
87+
1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
88+
};
89+
4490
/**
4591
* fsl_sai_dir_is_synced - Check if stream is synced by the opposite stream
4692
*
@@ -1010,6 +1056,17 @@ static int fsl_sai_dai_resume(struct snd_soc_component *component)
10101056
return 0;
10111057
}
10121058

1059+
static int fsl_sai_component_probe(struct snd_soc_component *component)
1060+
{
1061+
struct fsl_sai *sai = snd_soc_component_get_drvdata(component);
1062+
1063+
if (sai->verid.feature & FSL_SAI_VERID_TSTMP_EN)
1064+
snd_soc_add_component_controls(component, fsl_sai_timestamp_ctrls,
1065+
ARRAY_SIZE(fsl_sai_timestamp_ctrls));
1066+
1067+
return 0;
1068+
}
1069+
10131070
static struct snd_soc_dai_driver fsl_sai_dai_template[] = {
10141071
{
10151072
.name = "sai-tx-rx",
@@ -1063,6 +1120,7 @@ static struct snd_soc_dai_driver fsl_sai_dai_template[] = {
10631120

10641121
static const struct snd_soc_component_driver fsl_component = {
10651122
.name = "fsl-sai",
1123+
.probe = fsl_sai_component_probe,
10661124
.resume = fsl_sai_dai_resume,
10671125
.legacy_dai_naming = 1,
10681126
};
@@ -1211,6 +1269,14 @@ static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg)
12111269
case FSL_SAI_RDR5:
12121270
case FSL_SAI_RDR6:
12131271
case FSL_SAI_RDR7:
1272+
case FSL_SAI_TTCTN:
1273+
case FSL_SAI_RTCTN:
1274+
case FSL_SAI_TTCTL:
1275+
case FSL_SAI_TBCTN:
1276+
case FSL_SAI_TTCAP:
1277+
case FSL_SAI_RTCTL:
1278+
case FSL_SAI_RBCTN:
1279+
case FSL_SAI_RTCAP:
12141280
return true;
12151281
default:
12161282
return false;

sound/soc/fsl/fsl_sai.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,13 @@
196196
#define FSL_SAI_MDIV_MASK 0xFFFFF
197197

198198
/* SAI timestamp and bitcounter */
199+
#define FSL_SAI_xTCTL_TSEN_SHIFT 0
199200
#define FSL_SAI_xTCTL_TSEN BIT(0)
201+
#define FSL_SAI_xTCTL_TSINC_SHIFT 1
200202
#define FSL_SAI_xTCTL_TSINC BIT(1)
203+
#define FSL_SAI_xTCTL_RTSC_SHIFT 8
201204
#define FSL_SAI_xTCTL_RTSC BIT(8)
205+
#define FSL_SAI_xTCTL_RBC_SHIFT 9
202206
#define FSL_SAI_xTCTL_RBC BIT(9)
203207

204208
/* SAI type */

sound/soc/fsl/fsl_utils.c

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/clk-provider.h>
1111
#include <linux/module.h>
1212
#include <linux/of_address.h>
13+
#include <linux/pm_runtime.h>
1314
#include <sound/soc.h>
1415

1516
#include "fsl_utils.h"
@@ -197,6 +198,136 @@ void fsl_asoc_constrain_rates(struct snd_pcm_hw_constraint_list *target_constr,
197198
}
198199
EXPORT_SYMBOL(fsl_asoc_constrain_rates);
199200

201+
/*
202+
* Below functions are used by mixer interface to avoid accessing registers
203+
* which are volatile at pm runtime suspend state (cache_only is enabled).
204+
*/
205+
int fsl_asoc_get_xr_sx(struct snd_kcontrol *kcontrol,
206+
struct snd_ctl_elem_value *ucontrol)
207+
{
208+
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
209+
int ret = 0;
210+
211+
ret = pm_runtime_resume_and_get(component->dev);
212+
if (ret)
213+
return ret;
214+
215+
ret = snd_soc_get_xr_sx(kcontrol, ucontrol);
216+
217+
pm_runtime_put_autosuspend(component->dev);
218+
219+
return ret;
220+
}
221+
EXPORT_SYMBOL_GPL(fsl_asoc_get_xr_sx);
222+
223+
int fsl_asoc_put_xr_sx(struct snd_kcontrol *kcontrol,
224+
struct snd_ctl_elem_value *ucontrol)
225+
{
226+
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
227+
int ret = 0;
228+
229+
ret = pm_runtime_resume_and_get(component->dev);
230+
if (ret)
231+
return ret;
232+
233+
ret = snd_soc_put_xr_sx(kcontrol, ucontrol);
234+
/*
235+
* As this function only used by the SNDRV_CTL_ELEM_ACCESS_VOLATILE
236+
* case. return 0 to avoid control event notification.
237+
*/
238+
if (ret > 0)
239+
ret = 0;
240+
241+
pm_runtime_put_autosuspend(component->dev);
242+
243+
return ret;
244+
}
245+
EXPORT_SYMBOL_GPL(fsl_asoc_put_xr_sx);
246+
247+
int fsl_asoc_get_enum_double(struct snd_kcontrol *kcontrol,
248+
struct snd_ctl_elem_value *ucontrol)
249+
{
250+
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
251+
int ret = 0;
252+
253+
ret = pm_runtime_resume_and_get(component->dev);
254+
if (ret)
255+
return ret;
256+
257+
ret = snd_soc_get_enum_double(kcontrol, ucontrol);
258+
259+
pm_runtime_put_autosuspend(component->dev);
260+
261+
return ret;
262+
}
263+
EXPORT_SYMBOL_GPL(fsl_asoc_get_enum_double);
264+
265+
int fsl_asoc_put_enum_double(struct snd_kcontrol *kcontrol,
266+
struct snd_ctl_elem_value *ucontrol)
267+
{
268+
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
269+
int ret = 0;
270+
271+
ret = pm_runtime_resume_and_get(component->dev);
272+
if (ret)
273+
return ret;
274+
275+
ret = snd_soc_put_enum_double(kcontrol, ucontrol);
276+
/*
277+
* As this function only used by the SNDRV_CTL_ELEM_ACCESS_VOLATILE
278+
* case. return 0 to avoid control event notification.
279+
*/
280+
if (ret > 0)
281+
ret = 0;
282+
283+
pm_runtime_put_autosuspend(component->dev);
284+
285+
return ret;
286+
}
287+
EXPORT_SYMBOL_GPL(fsl_asoc_put_enum_double);
288+
289+
int fsl_asoc_get_volsw(struct snd_kcontrol *kcontrol,
290+
struct snd_ctl_elem_value *ucontrol)
291+
{
292+
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
293+
int ret = 0;
294+
295+
ret = pm_runtime_resume_and_get(component->dev);
296+
if (ret)
297+
return ret;
298+
299+
ret = snd_soc_get_volsw(kcontrol, ucontrol);
300+
301+
pm_runtime_put_autosuspend(component->dev);
302+
303+
return ret;
304+
}
305+
EXPORT_SYMBOL_GPL(fsl_asoc_get_volsw);
306+
307+
int fsl_asoc_put_volsw(struct snd_kcontrol *kcontrol,
308+
struct snd_ctl_elem_value *ucontrol)
309+
{
310+
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
311+
int ret = 0;
312+
313+
ret = pm_runtime_resume_and_get(component->dev);
314+
if (ret)
315+
return ret;
316+
317+
ret = snd_soc_put_volsw(kcontrol, ucontrol);
318+
/*
319+
* As this function only used by the SNDRV_CTL_ELEM_ACCESS_VOLATILE
320+
* case. return 0 to avoid control event notification.
321+
*/
322+
if (ret > 0)
323+
ret = 0;
324+
325+
pm_runtime_put_autosuspend(component->dev);
326+
327+
return ret;
328+
}
329+
EXPORT_SYMBOL_GPL(fsl_asoc_put_volsw);
330+
200331
MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
201332
MODULE_DESCRIPTION("Freescale ASoC utility code");
202333
MODULE_LICENSE("GPL v2");

sound/soc/fsl/fsl_utils.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,52 @@ void fsl_asoc_constrain_rates(struct snd_pcm_hw_constraint_list *target_constr,
3131
const struct snd_pcm_hw_constraint_list *original_constr,
3232
struct clk *pll8k_clk, struct clk *pll11k_clk,
3333
struct clk *ext_clk, int *target_rates);
34+
35+
/* Similar to SOC_SINGLE_XR_SX, but it is for read only registers. */
36+
#define FSL_ASOC_SINGLE_XR_SX_EXT_RO(xname, xregbase, xregcount, xnbits, \
37+
xmin, xmax, xinvert, xhandler_get) \
38+
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
39+
.access = SNDRV_CTL_ELEM_ACCESS_READ | \
40+
SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
41+
.info = snd_soc_info_xr_sx, .get = xhandler_get, \
42+
.private_value = (unsigned long)&(struct soc_mreg_control) \
43+
{.regbase = xregbase, .regcount = xregcount, .nbits = xnbits, \
44+
.invert = xinvert, .min = xmin, .max = xmax} }
45+
46+
/* Similar to SOC_SINGLE_EXT, but it is for volatile register. */
47+
#define FSL_ASOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\
48+
xhandler_get, xhandler_put) \
49+
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
50+
.access = SNDRV_CTL_ELEM_ACCESS_VOLATILE | \
51+
SNDRV_CTL_ELEM_ACCESS_READWRITE, \
52+
.info = snd_soc_info_volsw, \
53+
.get = xhandler_get, .put = xhandler_put, \
54+
.private_value = SOC_SINGLE_VALUE(xreg, xshift, 0, xmax, xinvert, 0) }
55+
56+
#define FSL_ASOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \
57+
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
58+
.access = SNDRV_CTL_ELEM_ACCESS_VOLATILE | \
59+
SNDRV_CTL_ELEM_ACCESS_READWRITE, \
60+
.info = snd_soc_info_enum_double, \
61+
.get = xhandler_get, .put = xhandler_put, \
62+
.private_value = (unsigned long)&xenum }
63+
64+
int fsl_asoc_get_xr_sx(struct snd_kcontrol *kcontrol,
65+
struct snd_ctl_elem_value *ucontrol);
66+
67+
int fsl_asoc_put_xr_sx(struct snd_kcontrol *kcontrol,
68+
struct snd_ctl_elem_value *ucontrol);
69+
70+
int fsl_asoc_get_enum_double(struct snd_kcontrol *kcontrol,
71+
struct snd_ctl_elem_value *ucontrol);
72+
73+
int fsl_asoc_put_enum_double(struct snd_kcontrol *kcontrol,
74+
struct snd_ctl_elem_value *ucontrol);
75+
76+
int fsl_asoc_get_volsw(struct snd_kcontrol *kcontrol,
77+
struct snd_ctl_elem_value *ucontrol);
78+
79+
int fsl_asoc_put_volsw(struct snd_kcontrol *kcontrol,
80+
struct snd_ctl_elem_value *ucontrol);
81+
3482
#endif /* _FSL_UTILS_H */

sound/soc/fsl/fsl_xcvr.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,58 @@ struct fsl_xcvr {
6262
u32 spdif_constr_rates_list[SPDIF_NUM_RATES];
6363
};
6464

65+
static const char * const inc_mode[] = {
66+
"On enabled and bitcount increment", "On enabled"
67+
};
68+
69+
static SOC_ENUM_SINGLE_DECL(transmit_tstmp_enum,
70+
FSL_XCVR_TX_DPTH_CNTR_CTRL,
71+
FSL_XCVR_TX_DPTH_CNTR_CTRL_TSINC_SHIFT, inc_mode);
72+
static SOC_ENUM_SINGLE_DECL(receive_tstmp_enum,
73+
FSL_XCVR_RX_DPTH_CNTR_CTRL,
74+
FSL_XCVR_RX_DPTH_CNTR_CTRL_TSINC_SHIFT, inc_mode);
75+
76+
static const struct snd_kcontrol_new fsl_xcvr_timestamp_ctrls[] = {
77+
FSL_ASOC_SINGLE_EXT("Transmit Timestamp Control Switch", FSL_XCVR_TX_DPTH_CNTR_CTRL,
78+
FSL_XCVR_TX_DPTH_CNTR_CTRL_TSEN_SHIFT, 1, 0,
79+
fsl_asoc_get_volsw, fsl_asoc_put_volsw),
80+
FSL_ASOC_ENUM_EXT("Transmit Timestamp Increment", transmit_tstmp_enum,
81+
fsl_asoc_get_enum_double, fsl_asoc_put_enum_double),
82+
FSL_ASOC_SINGLE_EXT("Transmit Timestamp Reset Switch", FSL_XCVR_TX_DPTH_CNTR_CTRL,
83+
FSL_XCVR_TX_DPTH_CNTR_CTRL_RTSC_SHIFT, 1, 0,
84+
fsl_asoc_get_volsw, fsl_asoc_put_volsw),
85+
FSL_ASOC_SINGLE_EXT("Transmit Bit Counter Reset Switch", FSL_XCVR_TX_DPTH_CNTR_CTRL,
86+
FSL_XCVR_TX_DPTH_CNTR_CTRL_RBC_SHIFT, 1, 0,
87+
fsl_asoc_get_volsw, fsl_asoc_put_volsw),
88+
FSL_ASOC_SINGLE_XR_SX_EXT_RO("Transmit Timestamp Counter", FSL_XCVR_TX_DPTH_TSCR,
89+
1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
90+
FSL_ASOC_SINGLE_XR_SX_EXT_RO("Transmit Bit Counter", FSL_XCVR_TX_DPTH_BCR,
91+
1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
92+
FSL_ASOC_SINGLE_XR_SX_EXT_RO("Transmit Bit Count Timestamp", FSL_XCVR_TX_DPTH_BCTR,
93+
1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
94+
FSL_ASOC_SINGLE_XR_SX_EXT_RO("Transmit Latched Timestamp Counter", FSL_XCVR_TX_DPTH_BCRR,
95+
1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
96+
FSL_ASOC_SINGLE_EXT("Receive Timestamp Control Switch", FSL_XCVR_RX_DPTH_CNTR_CTRL,
97+
FSL_XCVR_RX_DPTH_CNTR_CTRL_TSEN_SHIFT, 1, 0,
98+
fsl_asoc_get_volsw, fsl_asoc_put_volsw),
99+
FSL_ASOC_ENUM_EXT("Receive Timestamp Increment", receive_tstmp_enum,
100+
fsl_asoc_get_enum_double, fsl_asoc_put_enum_double),
101+
FSL_ASOC_SINGLE_EXT("Receive Timestamp Reset Switch", FSL_XCVR_RX_DPTH_CNTR_CTRL,
102+
FSL_XCVR_RX_DPTH_CNTR_CTRL_RTSC_SHIFT, 1, 0,
103+
fsl_asoc_get_volsw, fsl_asoc_put_volsw),
104+
FSL_ASOC_SINGLE_EXT("Receive Bit Counter Reset Switch", FSL_XCVR_RX_DPTH_CNTR_CTRL,
105+
FSL_XCVR_RX_DPTH_CNTR_CTRL_RBC_SHIFT, 1, 0,
106+
fsl_asoc_get_volsw, fsl_asoc_put_volsw),
107+
FSL_ASOC_SINGLE_XR_SX_EXT_RO("Receive Timestamp Counter", FSL_XCVR_RX_DPTH_TSCR,
108+
1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
109+
FSL_ASOC_SINGLE_XR_SX_EXT_RO("Receive Bit Counter", FSL_XCVR_RX_DPTH_BCR,
110+
1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
111+
FSL_ASOC_SINGLE_XR_SX_EXT_RO("Receive Bit Count Timestamp", FSL_XCVR_RX_DPTH_BCTR,
112+
1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
113+
FSL_ASOC_SINGLE_XR_SX_EXT_RO("Receive Latched Timestamp Counter", FSL_XCVR_RX_DPTH_BCRR,
114+
1, 32, 0, 0xffffffff, 0, fsl_asoc_get_xr_sx),
115+
};
116+
65117
static const struct fsl_xcvr_pll_conf {
66118
u8 mfi; /* min=0x18, max=0x38 */
67119
u32 mfn; /* signed int, 2's compl., min=0x3FFF0000, max=0x00010000 */
@@ -1070,8 +1122,20 @@ static struct snd_soc_dai_driver fsl_xcvr_dai = {
10701122
},
10711123
};
10721124

1125+
static int fsl_xcvr_component_probe(struct snd_soc_component *component)
1126+
{
1127+
struct fsl_xcvr *xcvr = snd_soc_component_get_drvdata(component);
1128+
1129+
snd_soc_component_init_regmap(component, xcvr->regmap);
1130+
1131+
return 0;
1132+
}
1133+
10731134
static const struct snd_soc_component_driver fsl_xcvr_comp = {
10741135
.name = "fsl-xcvr-dai",
1136+
.probe = fsl_xcvr_component_probe,
1137+
.controls = fsl_xcvr_timestamp_ctrls,
1138+
.num_controls = ARRAY_SIZE(fsl_xcvr_timestamp_ctrls),
10751139
.legacy_dai_naming = 1,
10761140
};
10771141

0 commit comments

Comments
 (0)