Skip to content

Commit e3f4e5b

Browse files
TE-N-ShengjiuWangbroonie
authored andcommitted
ASoC: fsl_sai: Configure dataline/FIFO information from dts property
The SAI has multiple successive FIFO registers, but in some use case the required dataline/FIFOs are not successive, so need get such information from dts property "fsl,dataline" fsl,dataline has 3 values for each configuration: first one means the type: I2S(1) or DSD(2), second one is dataline mask for 'rx', third one is dataline mask for 'tx'. Also set dma peripheral address and TRCE bits according to data lane. Signed-off-by: Shengjiu Wang <[email protected]> Signed-off-by: Viorel Suman <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent 6b878ac commit e3f4e5b

File tree

2 files changed

+174
-4
lines changed

2 files changed

+174
-4
lines changed

sound/soc/fsl/fsl_sai.c

Lines changed: 157 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -487,13 +487,18 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
487487
unsigned int ofs = sai->soc_data->reg_offset;
488488
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
489489
unsigned int channels = params_channels(params);
490+
struct snd_dmaengine_dai_dma_data *dma_params;
491+
struct fsl_sai_dl_cfg *dl_cfg = sai->dl_cfg;
490492
u32 word_width = params_width(params);
493+
int trce_mask = 0, dl_cfg_idx = 0;
494+
int dl_cfg_cnt = sai->dl_cfg_cnt;
495+
u32 dl_type = FSL_SAI_DL_I2S;
491496
u32 val_cr4 = 0, val_cr5 = 0;
492497
u32 slots = (channels == 1) ? 2 : channels;
493498
u32 slot_width = word_width;
494499
int adir = tx ? RX : TX;
495500
u32 pins, bclk;
496-
int ret;
501+
int ret, i;
497502

498503
if (sai->slots)
499504
slots = sai->slots;
@@ -507,8 +512,22 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
507512
* PDM mode, channels are independent
508513
* each channels are on one dataline/FIFO.
509514
*/
510-
if (sai->is_pdm_mode)
515+
if (sai->is_pdm_mode) {
511516
pins = channels;
517+
dl_type = FSL_SAI_DL_PDM;
518+
}
519+
520+
for (i = 0; i < dl_cfg_cnt; i++) {
521+
if (dl_cfg[i].type == dl_type && dl_cfg[i].pins[tx] == pins) {
522+
dl_cfg_idx = i;
523+
break;
524+
}
525+
}
526+
527+
if (hweight8(dl_cfg[dl_cfg_idx].mask[tx]) < pins) {
528+
dev_err(cpu_dai->dev, "channel not supported\n");
529+
return -EINVAL;
530+
}
512531

513532
bclk = params_rate(params) * (sai->bclk_ratio ? sai->bclk_ratio : slots * slot_width);
514533

@@ -571,13 +590,28 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
571590
FSL_SAI_CR5_FBT_MASK, val_cr5);
572591
}
573592

574-
if (sai->soc_data->pins > 1)
593+
if (hweight8(dl_cfg[dl_cfg_idx].mask[tx]) <= 1)
594+
regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
595+
FSL_SAI_CR4_FCOMB_MASK, 0);
596+
else
575597
regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
576598
FSL_SAI_CR4_FCOMB_MASK, FSL_SAI_CR4_FCOMB_SOFT);
577599

600+
dma_params = tx ? &sai->dma_params_tx : &sai->dma_params_rx;
601+
dma_params->addr = sai->res->start + FSL_SAI_xDR0(tx) +
602+
dl_cfg[dl_cfg_idx].start_off[tx] * 0x4;
603+
604+
/* Find a proper tcre setting */
605+
for (i = 0; i < sai->soc_data->pins; i++) {
606+
trce_mask = (1 << (i + 1)) - 1;
607+
if (hweight8(dl_cfg[dl_cfg_idx].mask[tx] & trce_mask) == pins)
608+
break;
609+
}
610+
578611
regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs),
579612
FSL_SAI_CR3_TRCE_MASK,
580-
FSL_SAI_CR3_TRCE((1 << pins) - 1));
613+
FSL_SAI_CR3_TRCE((dl_cfg[dl_cfg_idx].mask[tx] & trce_mask)));
614+
581615
regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
582616
FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK |
583617
FSL_SAI_CR4_CHMOD_MASK,
@@ -1068,6 +1102,118 @@ static int fsl_sai_check_version(struct device *dev)
10681102
return 0;
10691103
}
10701104

1105+
/*
1106+
* Calculate the offset between first two datalines, don't
1107+
* different offset in one case.
1108+
*/
1109+
static unsigned int fsl_sai_calc_dl_off(unsigned long dl_mask)
1110+
{
1111+
int fbidx, nbidx, offset;
1112+
1113+
fbidx = find_first_bit(&dl_mask, FSL_SAI_DL_NUM);
1114+
nbidx = find_next_bit(&dl_mask, FSL_SAI_DL_NUM, fbidx + 1);
1115+
offset = nbidx - fbidx - 1;
1116+
1117+
return (offset < 0 || offset >= (FSL_SAI_DL_NUM - 1) ? 0 : offset);
1118+
}
1119+
1120+
/*
1121+
* read the fsl,dataline property from dts file.
1122+
* It has 3 value for each configuration, first one means the type:
1123+
* I2S(1) or PDM(2), second one is dataline mask for 'rx', third one is
1124+
* dataline mask for 'tx'. for example
1125+
*
1126+
* fsl,dataline = <1 0xff 0xff 2 0xff 0x11>,
1127+
*
1128+
* It means I2S type rx mask is 0xff, tx mask is 0xff, PDM type
1129+
* rx mask is 0xff, tx mask is 0x11 (dataline 1 and 4 enabled).
1130+
*
1131+
*/
1132+
static int fsl_sai_read_dlcfg(struct fsl_sai *sai)
1133+
{
1134+
struct platform_device *pdev = sai->pdev;
1135+
struct device_node *np = pdev->dev.of_node;
1136+
struct device *dev = &pdev->dev;
1137+
int ret, elems, i, index, num_cfg;
1138+
char *propname = "fsl,dataline";
1139+
struct fsl_sai_dl_cfg *cfg;
1140+
unsigned long dl_mask;
1141+
unsigned int soc_dl;
1142+
u32 rx, tx, type;
1143+
1144+
elems = of_property_count_u32_elems(np, propname);
1145+
1146+
if (elems <= 0) {
1147+
elems = 0;
1148+
} else if (elems % 3) {
1149+
dev_err(dev, "Number of elements must be divisible to 3.\n");
1150+
return -EINVAL;
1151+
}
1152+
1153+
num_cfg = elems / 3;
1154+
/* Add one more for default value */
1155+
cfg = devm_kzalloc(&pdev->dev, (num_cfg + 1) * sizeof(*cfg), GFP_KERNEL);
1156+
if (!cfg)
1157+
return -ENOMEM;
1158+
1159+
/* Consider default value "0 0xFF 0xFF" if property is missing */
1160+
soc_dl = BIT(sai->soc_data->pins) - 1;
1161+
cfg[0].type = FSL_SAI_DL_DEFAULT;
1162+
cfg[0].pins[0] = sai->soc_data->pins;
1163+
cfg[0].mask[0] = soc_dl;
1164+
cfg[0].start_off[0] = 0;
1165+
cfg[0].next_off[0] = 0;
1166+
1167+
cfg[0].pins[1] = sai->soc_data->pins;
1168+
cfg[0].mask[1] = soc_dl;
1169+
cfg[0].start_off[1] = 0;
1170+
cfg[0].next_off[1] = 0;
1171+
for (i = 1, index = 0; i < num_cfg + 1; i++) {
1172+
/*
1173+
* type of dataline
1174+
* 0 means default mode
1175+
* 1 means I2S mode
1176+
* 2 means PDM mode
1177+
*/
1178+
ret = of_property_read_u32_index(np, propname, index++, &type);
1179+
if (ret)
1180+
return -EINVAL;
1181+
1182+
ret = of_property_read_u32_index(np, propname, index++, &rx);
1183+
if (ret)
1184+
return -EINVAL;
1185+
1186+
ret = of_property_read_u32_index(np, propname, index++, &tx);
1187+
if (ret)
1188+
return -EINVAL;
1189+
1190+
if ((rx & ~soc_dl) || (tx & ~soc_dl)) {
1191+
dev_err(dev, "dataline cfg[%d] setting error, mask is 0x%x\n", i, soc_dl);
1192+
return -EINVAL;
1193+
}
1194+
1195+
rx = rx & soc_dl;
1196+
tx = tx & soc_dl;
1197+
1198+
cfg[i].type = type;
1199+
cfg[i].pins[0] = hweight8(rx);
1200+
cfg[i].mask[0] = rx;
1201+
dl_mask = rx;
1202+
cfg[i].start_off[0] = find_first_bit(&dl_mask, FSL_SAI_DL_NUM);
1203+
cfg[i].next_off[0] = fsl_sai_calc_dl_off(rx);
1204+
1205+
cfg[i].pins[1] = hweight8(tx);
1206+
cfg[i].mask[1] = tx;
1207+
dl_mask = tx;
1208+
cfg[i].start_off[1] = find_first_bit(&dl_mask, FSL_SAI_DL_NUM);
1209+
cfg[i].next_off[1] = fsl_sai_calc_dl_off(tx);
1210+
}
1211+
1212+
sai->dl_cfg = cfg;
1213+
sai->dl_cfg_cnt = num_cfg + 1;
1214+
return 0;
1215+
}
1216+
10711217
static int fsl_sai_runtime_suspend(struct device *dev);
10721218
static int fsl_sai_runtime_resume(struct device *dev);
10731219

@@ -1134,6 +1280,13 @@ static int fsl_sai_probe(struct platform_device *pdev)
11341280
else
11351281
sai->mclk_clk[0] = sai->bus_clk;
11361282

1283+
/* read dataline mask for rx and tx*/
1284+
ret = fsl_sai_read_dlcfg(sai);
1285+
if (ret < 0) {
1286+
dev_err(dev, "failed to read dlcfg %d\n", ret);
1287+
return ret;
1288+
}
1289+
11371290
irq = platform_get_irq(pdev, 0);
11381291
if (irq < 0)
11391292
return irq;

sound/soc/fsl/fsl_sai.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,13 @@
218218

219219
#define PMQOS_CPU_LATENCY BIT(0)
220220

221+
/* Max number of dataline */
222+
#define FSL_SAI_DL_NUM (8)
223+
/* default dataline type is zero */
224+
#define FSL_SAI_DL_DEFAULT (0)
225+
#define FSL_SAI_DL_I2S BIT(0)
226+
#define FSL_SAI_DL_PDM BIT(1)
227+
221228
struct fsl_sai_soc_data {
222229
bool use_imx_pcm;
223230
bool use_edma;
@@ -253,6 +260,14 @@ struct fsl_sai_param {
253260
u32 dataline;
254261
};
255262

263+
struct fsl_sai_dl_cfg {
264+
unsigned int type;
265+
unsigned int pins[2];
266+
unsigned int mask[2];
267+
unsigned int start_off[2];
268+
unsigned int next_off[2];
269+
};
270+
256271
struct fsl_sai {
257272
struct platform_device *pdev;
258273
struct regmap *regmap;
@@ -265,6 +280,8 @@ struct fsl_sai {
265280
bool is_dsp_mode;
266281
bool is_pdm_mode;
267282
bool synchronous[2];
283+
struct fsl_sai_dl_cfg *dl_cfg;
284+
unsigned int dl_cfg_cnt;
268285

269286
unsigned int mclk_id[2];
270287
unsigned int mclk_streams;

0 commit comments

Comments
 (0)