diff options
Diffstat (limited to 'target/linux/layerscape/patches-5.4/801-audio-0059-MLK-20328-1-ASoC-fsl_sai-map-number-of-pins-to-datal.patch')
-rw-r--r-- | target/linux/layerscape/patches-5.4/801-audio-0059-MLK-20328-1-ASoC-fsl_sai-map-number-of-pins-to-datal.patch | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0059-MLK-20328-1-ASoC-fsl_sai-map-number-of-pins-to-datal.patch b/target/linux/layerscape/patches-5.4/801-audio-0059-MLK-20328-1-ASoC-fsl_sai-map-number-of-pins-to-datal.patch new file mode 100644 index 0000000000..4f1bcea90c --- /dev/null +++ b/target/linux/layerscape/patches-5.4/801-audio-0059-MLK-20328-1-ASoC-fsl_sai-map-number-of-pins-to-datal.patch @@ -0,0 +1,373 @@ +From e62741891f6901b5219eacdf60835cac9beb7bae Mon Sep 17 00:00:00 2001 +From: Viorel Suman <viorel.suman@nxp.com> +Date: Wed, 21 Nov 2018 16:09:44 +0200 +Subject: [PATCH] MLK-20328-1: ASoC: fsl_sai: map number of pins to dataline + masks + +The patch enable mapping the number of pins required to play or record +a specific number of channels to a specific dataline mask. + +Three consequent elements in "fsl,dataline" and "fsl,dataline,dsd" defines a +particular mapping, for instance for: fsl,dataline = "0 0xff 0xff 2 0x11 0x11" +there are two mappings defined: + +default (0 pins) "rx" and "tx" dataline masks: 0 0xff 0xff + 2 pins "rx" and "tx" dataline masks: 2 0x11 0x11 + +In case if property is missing, then default value "0 0x1 0x1" is considered. + +Signed-off-by: Viorel Suman <viorel.suman@nxp.com> +--- + sound/soc/fsl/fsl_sai.c | 227 ++++++++++++++++++++++++++++++------------------ + sound/soc/fsl/fsl_sai.h | 16 +++- + 2 files changed, 153 insertions(+), 90 deletions(-) + +--- a/sound/soc/fsl/fsl_sai.c ++++ b/sound/soc/fsl/fsl_sai.c +@@ -621,17 +621,35 @@ static int fsl_sai_hw_params(struct snd_ + u32 slots = (channels == 1) ? 2 : channels; + u32 slot_width = word_width; + u32 pins, bclk; +- int ret; +- int i; +- int trce_mask = 0; ++ int ret, i, trce_mask = 0, dl_cfg_cnt, dl_cfg_idx = 0; ++ struct fsl_sai_dl_cfg *dl_cfg; + + if (sai->slots) + slots = sai->slots; + + pins = DIV_ROUND_UP(channels, slots); + sai->is_dsd = fsl_is_dsd(params); +- if (sai->is_dsd) ++ if (sai->is_dsd) { + pins = channels; ++ dl_cfg = sai->dsd_dl_cfg; ++ dl_cfg_cnt = sai->dsd_dl_cfg_cnt; ++ } else { ++ dl_cfg = sai->pcm_dl_cfg; ++ dl_cfg_cnt = sai->pcm_dl_cfg_cnt; ++ } ++ ++ for (i = 0; i < dl_cfg_cnt; i++) { ++ if (dl_cfg[i].pins == pins) { ++ dl_cfg_idx = i; ++ break; ++ } ++ } ++ ++ if (dl_cfg_idx >= dl_cfg_cnt) { ++ dev_err(cpu_dai->dev, "fsl,dataline%s invalid or not provided.\n", ++ sai->is_dsd ? ",dsd" : ""); ++ return -EINVAL; ++ } + + if (sai->slot_width) + slot_width = sai->slot_width; +@@ -713,7 +731,7 @@ static int fsl_sai_hw_params(struct snd_ + + if (sai->soc->dataline != 0x1) { + +- if (sai->dataline[tx] <= 1 || sai->is_multi_lane) ++ if (dl_cfg[dl_cfg_idx].mask[tx] <= 1 || sai->is_multi_lane) + regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset), + FSL_SAI_CR4_FCOMB_MASK, 0); + else +@@ -724,21 +742,13 @@ static int fsl_sai_hw_params(struct snd_ + if (tx) { + sai->dma_params_tx.maxburst = + FSL_SAI_MAXBURST_TX * pins; +- if (sai->is_dsd) +- sai->dma_params_tx.fifo_num = pins + +- (sai->dataline_off_dsd[tx] << 4); +- else +- sai->dma_params_tx.fifo_num = pins + +- (sai->dataline_off[tx] << 4); ++ sai->dma_params_tx.fifo_num = pins + ++ (dl_cfg[dl_cfg_idx].offset[tx] << 4); + } else { + sai->dma_params_rx.maxburst = + FSL_SAI_MAXBURST_RX * pins; +- if (sai->is_dsd) +- sai->dma_params_rx.fifo_num = pins + +- (sai->dataline_off_dsd[tx] << 4); +- else +- sai->dma_params_rx.fifo_num = pins + +- (sai->dataline_off[tx] << 4); ++ sai->dma_params_rx.fifo_num = pins + ++ (dl_cfg[dl_cfg_idx].offset[tx] << 4); + } + } + +@@ -746,38 +756,22 @@ static int fsl_sai_hw_params(struct snd_ + &sai->dma_params_rx); + } + +- if (sai->is_dsd) { +- if (__sw_hweight8(sai->dataline_dsd[tx] & 0xFF) < pins) { +- dev_err(cpu_dai->dev, "channel not supported\n"); +- return -EINVAL; +- } +- /*find a proper tcre setting*/ +- for (i = 0; i < 8; i++) { +- trce_mask = (1 << (i + 1)) - 1; +- if (__sw_hweight8(sai->dataline_dsd[tx] & trce_mask) == pins) +- break; +- } +- +- regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset), +- FSL_SAI_CR3_TRCE_MASK, +- FSL_SAI_CR3_TRCE((sai->dataline_dsd[tx] & trce_mask))); +- } else { +- if (__sw_hweight8(sai->dataline[tx] & 0xFF) < pins) { +- dev_err(cpu_dai->dev, "channel not supported\n"); +- return -EINVAL; +- } +- /*find a proper tcre setting*/ +- for (i = 0; i < 8; i++) { +- trce_mask = (1 << (i + 1)) - 1; +- if (__sw_hweight8(sai->dataline[tx] & trce_mask) == pins) +- break; +- } ++ if (__sw_hweight8(dl_cfg[dl_cfg_idx].mask[tx] & 0xFF) < pins) { ++ dev_err(cpu_dai->dev, "channel not supported\n"); ++ return -EINVAL; ++ } + +- regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset), +- FSL_SAI_CR3_TRCE_MASK, +- FSL_SAI_CR3_TRCE((sai->dataline[tx] & trce_mask))); ++ /*find a proper tcre setting*/ ++ for (i = 0; i < 8; i++) { ++ trce_mask = (1 << (i + 1)) - 1; ++ if (__sw_hweight8(dl_cfg[dl_cfg_idx].mask[tx] & trce_mask) == pins) ++ break; + } + ++ regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset), ++ FSL_SAI_CR3_TRCE_MASK, ++ FSL_SAI_CR3_TRCE((dl_cfg[dl_cfg_idx].mask[tx] & trce_mask))); ++ + regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset), + FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK | + FSL_SAI_CR4_CHMOD_MASK, +@@ -820,15 +814,32 @@ static int fsl_sai_trigger(struct snd_pc + u32 slots = (channels == 1) ? 2 : channels; + u32 xcsr, count = 100; + u32 pins; +- int i = 0, j = 0, k = 0; ++ int i = 0, j = 0, k = 0, dl_cfg_cnt, dl_cfg_idx = 0; ++ struct fsl_sai_dl_cfg *dl_cfg; + + if (sai->slots) + slots = sai->slots; + + pins = DIV_ROUND_UP(channels, slots); + +- if (sai->is_dsd) ++ if (sai->is_dsd) { + pins = channels; ++ dl_cfg = sai->dsd_dl_cfg; ++ dl_cfg_cnt = sai->dsd_dl_cfg_cnt; ++ } else { ++ dl_cfg = sai->pcm_dl_cfg; ++ dl_cfg_cnt = sai->pcm_dl_cfg_cnt; ++ } ++ ++ for (i = 0; i < dl_cfg_cnt; i++) { ++ if (dl_cfg[i].pins == pins) { ++ dl_cfg_idx = i; ++ break; ++ } ++ } ++ ++ i = 0; ++ + /* + * Asynchronous mode: Clear SYNC for both Tx and Rx. + * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx. +@@ -849,7 +860,7 @@ static int fsl_sai_trigger(struct snd_pc + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + + while (tx && i < channels) { +- if ((sai->is_dsd ? sai->dataline_dsd[tx] : sai->dataline[tx]) & (1 << j)) { ++ if (dl_cfg[dl_cfg_idx].mask[tx] & (1 << j)) { + regmap_write(sai->regmap, FSL_SAI_TDR0 + j * 0x4, 0x0); + i++; + k++; +@@ -1262,6 +1273,77 @@ static const struct of_device_id fsl_sai + }; + MODULE_DEVICE_TABLE(of, fsl_sai_ids); + ++static unsigned int fsl_sai_calc_dl_off(unsigned int* dl_mask) ++{ ++ int fbidx, nbidx, offset; ++ ++ fbidx = find_first_bit((const unsigned long *)dl_mask, 8); ++ nbidx = find_next_bit((const unsigned long *)dl_mask, 8, fbidx+1); ++ offset = nbidx - fbidx - 1; ++ ++ return (offset < 0 || offset >= 7 ? 0 : offset); ++} ++ ++static int fsl_sai_read_dlcfg(struct platform_device *pdev, char *pn, ++ struct fsl_sai_dl_cfg **rcfg, unsigned int soc_dl) ++{ ++ int ret, elems, i, index, num_cfg; ++ struct device_node *np = pdev->dev.of_node; ++ struct fsl_sai_dl_cfg *cfg; ++ u32 rx, tx, pins; ++ ++ *rcfg = NULL; ++ ++ elems = of_property_count_u32_elems(np, pn); ++ ++ /* consider default value "0 0x1 0x1" if property is missing */ ++ if (elems <= 0) ++ elems = 3; ++ ++ if (elems % 3) { ++ dev_err(&pdev->dev, ++ "Number of elements in %s must be divisible to 3.\n", pn); ++ return -EINVAL; ++ } ++ ++ num_cfg = elems / 3; ++ cfg = devm_kzalloc(&pdev->dev, num_cfg * sizeof(*cfg), GFP_KERNEL); ++ if (cfg == NULL) { ++ dev_err(&pdev->dev, "Cannot allocate memory for %s.\n", pn); ++ return -ENOMEM; ++ } ++ ++ for (i = 0, index = 0; i < num_cfg; i++) { ++ ret = of_property_read_u32_index(np, pn, index++, &pins); ++ if (ret) ++ pins = 0; ++ ++ ret = of_property_read_u32_index(np, pn, index++, &rx); ++ if (ret) ++ rx = 1; ++ ++ ret = of_property_read_u32_index(np, pn, index++, &tx); ++ if (ret) ++ tx = 1; ++ ++ if ((rx & ~soc_dl) || (tx & ~soc_dl)) { ++ dev_err(&pdev->dev, ++ "%s: dataline cfg[%d] setting error, mask is 0x%x\n", ++ pn, i, soc_dl); ++ return -EINVAL; ++ } ++ ++ cfg[i].pins = pins; ++ cfg[i].mask[0] = rx; ++ cfg[i].offset[0] = fsl_sai_calc_dl_off(&rx); ++ cfg[i].mask[1] = tx; ++ cfg[i].offset[1] = fsl_sai_calc_dl_off(&tx); ++ } ++ ++ *rcfg = cfg; ++ return num_cfg; ++} ++ + static int fsl_sai_probe(struct platform_device *pdev) + { + struct device_node *np = pdev->dev.of_node; +@@ -1273,7 +1355,6 @@ static int fsl_sai_probe(struct platform + char tmp[8]; + int irq, ret, i; + int index; +- int firstbitidx, nextbitidx, offset; + struct regmap_config fsl_sai_regmap_config = fsl_sai_v2_regmap_config; + unsigned long irqflags = 0; + +@@ -1340,45 +1421,19 @@ static int fsl_sai_probe(struct platform + sai->is_multi_lane = true; + + /*dataline mask for rx and tx*/ +- ret = of_property_read_u32_index(np, "fsl,dataline", 0, &sai->dataline[0]); +- if (ret) +- sai->dataline[0] = 1; +- +- ret = of_property_read_u32_index(np, "fsl,dataline", 1, &sai->dataline[1]); +- if (ret) +- sai->dataline[1] = 1; +- +- if ((sai->dataline[0] & (~sai->soc->dataline)) || sai->dataline[1] & (~sai->soc->dataline)) { +- dev_err(&pdev->dev, "dataline setting error, Mask is 0x%x\n", sai->soc->dataline); +- return -EINVAL; +- } +- +- for (i = 0; i < 2; i++) { +- firstbitidx = find_first_bit((const unsigned long *)&sai->dataline[i], 8); +- nextbitidx = find_next_bit((const unsigned long *)&sai->dataline[i], 8, firstbitidx+1); +- offset = nextbitidx - firstbitidx - 1; +- sai->dataline_off[i] = (offset < 0 || offset >= 7 ? 0 : offset); +- } +- +- ret = of_property_read_u32_index(np, "fsl,dataline,dsd", 0, &sai->dataline_dsd[0]); +- if (ret) +- sai->dataline_dsd[0] = 1; +- +- ret = of_property_read_u32_index(np, "fsl,dataline,dsd", 1, &sai->dataline_dsd[1]); +- if (ret) +- sai->dataline_dsd[1] = 1; ++ ret = fsl_sai_read_dlcfg(pdev, "fsl,dataline", &sai->pcm_dl_cfg, ++ sai->soc->dataline); ++ if (ret < 0) ++ return ret; ++ ++ sai->pcm_dl_cfg_cnt = ret; ++ ++ ret = fsl_sai_read_dlcfg(pdev, "fsl,dataline,dsd", &sai->dsd_dl_cfg, ++ sai->soc->dataline); ++ if (ret < 0) ++ return ret; + +- if ((sai->dataline_dsd[0] & (~sai->soc->dataline)) || sai->dataline_dsd[1] & (~sai->soc->dataline)) { +- dev_err(&pdev->dev, "dataline setting error, Mask is 0x%x\n", sai->soc->dataline); +- return -EINVAL; +- } +- +- for (i = 0; i < 2; i++) { +- firstbitidx = find_first_bit((const unsigned long *)&sai->dataline_dsd[i], 8); +- nextbitidx = find_next_bit((const unsigned long *)&sai->dataline_dsd[i], 8, firstbitidx+1); +- offset = nextbitidx - firstbitidx - 1; +- sai->dataline_off_dsd[i] = (offset < 0 || offset >= 7 ? 0 : offset); +- } ++ sai->dsd_dl_cfg_cnt = ret; + + if ((of_find_property(np, "fsl,i2s-xtor", NULL) != NULL) || + (of_find_property(np, "fsl,txm-rxs", NULL) != NULL)) +--- a/sound/soc/fsl/fsl_sai.h ++++ b/sound/soc/fsl/fsl_sai.h +@@ -234,6 +234,12 @@ struct fsl_sai_param { + u32 dln; /* number of datalines implemented */ + }; + ++struct fsl_sai_dl_cfg { ++ unsigned int pins; ++ unsigned int mask[2]; ++ unsigned int offset[2]; ++}; ++ + struct fsl_sai { + struct platform_device *pdev; + struct regmap *regmap; +@@ -249,10 +255,12 @@ struct fsl_sai { + bool synchronous[2]; + bool is_stream_opened[2]; + bool is_dsd; +- unsigned int dataline[2]; +- unsigned int dataline_dsd[2]; +- unsigned int dataline_off[2]; +- unsigned int dataline_off_dsd[2]; ++ ++ int pcm_dl_cfg_cnt; ++ int dsd_dl_cfg_cnt; ++ struct fsl_sai_dl_cfg *pcm_dl_cfg; ++ struct fsl_sai_dl_cfg *dsd_dl_cfg; ++ + unsigned int masterflag[2]; + + unsigned int mclk_id[2]; |