==Background==
The fsl_ssi driver was designed for PPC originally and then it has
been updated to support different modes for i.MX Series, including
SDMA, I2S Master mode, AC97 and older i.MXs with FIQ, by different
contributors for different use cases in different coding styles.
Additionally, in order to fix/work-around hardware bugs and design
flaws, the driver made a lot of compromise so now its program flow
looks very complicated and it's getting hard to maintain or update.
So I am going to clean up the driver on both coding style level and
program flow level.
==Introduction==
This series of patches is the second set to clean up fsl_ssi driver
in the program flow level. Any patch here may impact a fundamental
test case like playback or record.
==Verification==
This series of patches require fully tested. I have done such tests
on i.MX6SoloX with WM8962 using imx_v6_v7_defconfig as:
- Playback via I2S Master and Slave mode
- Record via I2S Master and Slave mode
- Simultaneous playback and record via I2S Master and Slave mode
- Background playback with foreground record (starting at different
time) via I2S Master and Slave mode
- Background record with foreground playback (starting at different
time) via I2S Master and Slave mode
* All tests above by hacking offline_config to true in imx51.
Example of uncovered tests: TDM, AC97, PowerPC and FIQ.
Nicolin Chen (15):
ASoC: fsl_ssi: Clean up set_dai_tdm_slot()
ASoC: fsl_ssi: Maintain a mask of active streams
ASoC: fsl_ssi: Rename fsl_ssi_disable_val macro
ASoC: fsl_ssi: Clear FIFO directly in fsl_ssi_config()
ASoC: fsl_ssi: Clean up helper functions of trigger()
ASoC: fsl_ssi: Add DAIFMT define for AC97
ASoC: fsl_ssi: Clean up fsl_ssi_setup_regvals()
ASoC: fsl_ssi: Set xFEN0 and xFEN1 together
ASoC: fsl_ssi: Use snd_soc_init_dma_data instead
ASoC: fsl_ssi: Move one-time configurations to dai_probe()
ASoC: fsl_ssi: Setup AC97 in dai_probe()
ASoC: fsl_ssi: Clean up _fsl_ssi_set_dai_fmt()
ASoC: fsl_ssi: Remove cpu_dai_drv from fsl_ssi structure
ASoC: fsl_ssi: Move DT related code to a separate probe()
ASoC: fsl_ssi: Use ssi->streams instead of reading register
sound/soc/fsl/fsl_ssi.c | 710 ++++++++++++++++++++++++------------------------
1 file changed, 348 insertions(+), 362 deletions(-)
--
2.7.4
This patch replaces the register read with ssi->i2s_net for
simplification. It also removes masking SSIEN from scr value
since it's handled later by regmap_update_bits() to set this
scr value back.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
sound/soc/fsl/fsl_ssi.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
@@ -1051,9 +1051,7 @@ static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,}/* The slot number should be >= 2 if using Network mode or I2S mode */-regmap_read(regs,REG_SSI_SCR,&val);-val&=SSI_SCR_I2S_MODE_MASK|SSI_SCR_NET;-if(val&&slots<2){+if(ssi->i2s_net&&slots<2){dev_err(dai->dev,"slot number should be >= 2 in I2S or NET\n");return-EINVAL;}
@@ -1063,9 +1061,8 @@ static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,regmap_update_bits(regs,REG_SSI_SRCCR,SSI_SxCCR_DC_MASK,SSI_SxCCR_DC(slots));-/* Save SSIEN bit of the SCR register */+/* Save the SCR register value */regmap_read(regs,REG_SSI_SCR,&val);-val&=SSI_SCR_SSIEN;/* Temporarily enable SSI to allow SxMSKs to be configurable */regmap_update_bits(regs,REG_SSI_SCR,SSI_SCR_SSIEN,SSI_SCR_SSIEN);
Since there is a helper function, use it to help readability.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
sound/soc/fsl/fsl_ssi.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
AC97 configures some registers earlier to start a communication
with CODECs, so this patch moves those register settings to the
dai_probe() as well, along with other register configurations.
It also applies _fsl_ssi_set_dai_fmt() to AC97 only since other
formats would be configured via fsl_ssi_set_dai_fmt() directly.
Meanwhile, this patch adds fsl_ssi_dai_ac97_remove() to cleanup
some control bits for AC97.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
sound/soc/fsl/fsl_ssi.c | 27 +++++++++++++++++++++------
1 file changed, 21 insertions(+), 6 deletions(-)
@@ -977,9 +977,6 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,regmap_write(regs,REG_SSI_SRCR,srcr);regmap_write(regs,REG_SSI_SCR,scr);-if((fmt&SND_SOC_DAIFMT_FORMAT_MASK)==SND_SOC_DAIFMT_AC97)-fsl_ssi_setup_ac97(ssi);-return0;}
@@ -1108,6 +1105,26 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)regmap_update_bits(ssi->regs,REG_SSI_SCR,SSI_SCR_TCH_EN,SSI_SCR_TCH_EN);+/* AC97 should start earlier to communicate with CODECs */+if(fsl_ssi_is_ac97(ssi)){+_fsl_ssi_set_dai_fmt(ssi->dev,ssi,ssi->dai_fmt);+fsl_ssi_setup_ac97(ssi);+}++return0;+}++/**+*DisableregisterbitsforAC97+*/+staticintfsl_ssi_dai_ac97_remove(structsnd_soc_dai*dai)+{+structfsl_ssi*ssi=snd_soc_dai_get_drvdata(dai);++regmap_write(ssi->regs,REG_SSI_SCR,0);+regmap_write(ssi->regs,REG_SSI_SACNT,0);+regmap_write(ssi->regs,REG_SSI_SOR,0);+return0;}
The dai_probe() could handle some one-time configurations since
they will not be changed once being configured.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
sound/soc/fsl/fsl_ssi.c | 30 +++++++++++++++++-------------
1 file changed, 17 insertions(+), 13 deletions(-)
@@ -855,7 +855,6 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,{structregmap*regs=ssi->regs;u32strcr=0,stcr,srcr,scr,mask;-u8wm;ssi->dai_fmt=fmt;
@@ -864,8 +863,6 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,return-EINVAL;}-fsl_ssi_setup_regvals(ssi);-regmap_read(regs,REG_SSI_SCR,&scr);scr&=~(SSI_SCR_SYN|SSI_SCR_I2S_MODE_MASK);/* Synchronize frame sync clock for TE to avoid data slipping */
@@ -980,16 +977,6 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,regmap_write(regs,REG_SSI_SRCR,srcr);regmap_write(regs,REG_SSI_SCR,scr);-wm=ssi->fifo_watermark;--regmap_write(regs,REG_SSI_SFCSR,-SSI_SFCSR_TFWM0(wm)|SSI_SFCSR_RFWM0(wm)|-SSI_SFCSR_TFWM1(wm)|SSI_SFCSR_RFWM1(wm));--if(ssi->use_dual_fifo)-regmap_update_bits(regs,REG_SSI_SCR,-SSI_SCR_TCH_EN,SSI_SCR_TCH_EN);-if((fmt&SND_SOC_DAIFMT_FORMAT_MASK)==SND_SOC_DAIFMT_AC97)fsl_ssi_setup_ac97(ssi);
@@ -1096,14 +1083,31 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,return0;}+/**+*SetDMAdataandone-timeconfigurations+*/staticintfsl_ssi_dai_probe(structsnd_soc_dai*dai){structfsl_ssi*ssi=snd_soc_dai_get_drvdata(dai);+u32wm=ssi->fifo_watermark;if(ssi->soc->imx&&ssi->use_dma)snd_soc_dai_init_dma_data(dai,&ssi->dma_params_tx,&ssi->dma_params_rx);+/* Initialize regvals */+fsl_ssi_setup_regvals(ssi);++/* Set watermarks */+regmap_write(ssi->regs,REG_SSI_SFCSR,+SSI_SFCSR_TFWM0(wm)|SSI_SFCSR_RFWM0(wm)|+SSI_SFCSR_TFWM1(wm)|SSI_SFCSR_RFWM1(wm));++/* Enable Dual FIFO mode */+if(ssi->use_dual_fifo)+regmap_update_bits(ssi->regs,REG_SSI_SCR,+SSI_SCR_TCH_EN,SSI_SCR_TCH_EN);+return0;}
Since ssi->streams is being updated along with SCR register and
its SSIEN bit, it's simpler to use it instead.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
sound/soc/fsl/fsl_ssi.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
This patch cleans up probe() function by moving all Device Tree
related code into a separate function. It allows the probe() to
be Device Tree independent. This will be very useful for future
integration of imx-ssi driver which has similar functionalities
while exists only because it supports non-DT cases.
This patch also moves symmetric_channels of AC97 from the probe
to the structure snd_soc_dai_driver for simplification.
Additionally, since PowerPC and AC97 use the same pdev pointer
to register a platform device, this patch also unifies related
code.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
sound/soc/fsl/fsl_ssi.c | 204 +++++++++++++++++++++++++-----------------------
1 file changed, 108 insertions(+), 96 deletions(-)
@@ -1266,9 +1273,7 @@ static void make_lowercase(char *s)staticintfsl_ssi_imx_probe(structplatform_device*pdev,structfsl_ssi*ssi,void__iomem*iomem){-structdevice_node*np=pdev->dev.of_node;structdevice*dev=&pdev->dev;-u32dmas[4];intret;/* Backward compatible for a DT without ipg clock name assigned */
@@ -1302,14 +1307,8 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,ssi->dma_params_tx.addr=ssi->ssi_phys+REG_SSI_STX0;ssi->dma_params_rx.addr=ssi->ssi_phys+REG_SSI_SRX0;-/* Set to dual FIFO mode according to the SDMA sciprt */-ret=of_property_read_u32_array(np,"dmas",dmas,4);-if(ssi->use_dma&&!ret&&dmas[2]==IMX_DMATYPE_SSI_DUAL){-ssi->use_dual_fifo=true;-/*-*UseevennumberstoavoidchannelswapduetoSDMA-*scriptdesign-*/+/* Use even numbers to avoid channel swap due to SDMA script design */+if(ssi->use_dual_fifo){ssi->dma_params_tx.maxburst&=~0x1;ssi->dma_params_rx.maxburst&=~0x1;}
@@ -1350,42 +1349,103 @@ static void fsl_ssi_imx_clean(struct platform_device *pdev, struct fsl_ssi *ssi)clk_disable_unprepare(ssi->clk);}-staticintfsl_ssi_probe(structplatform_device*pdev)+staticintfsl_ssi_probe_from_dt(structfsl_ssi*ssi){-structsnd_soc_dai_driver*cpu_dai_drv;-structfsl_ssi*ssi;-intret=0;-structdevice_node*np=pdev->dev.of_node;-structdevice*dev=&pdev->dev;+structdevice*dev=ssi->dev;+structdevice_node*np=dev->of_node;conststructof_device_id*of_id;constchar*p,*sprop;constuint32_t*iprop;-structresource*res;-void__iomem*iomem;-charname[64];-structregmap_configregconfig=fsl_ssi_regconfig;+u32dmas[4];+intret;of_id=of_match_device(fsl_ssi_ids,dev);if(!of_id||!of_id->data)return-EINVAL;-ssi=devm_kzalloc(dev,sizeof(*ssi),GFP_KERNEL);-if(!ssi)-return-ENOMEM;-ssi->soc=of_id->data;-ssi->dev=dev;++ret=of_property_match_string(np,"clock-names","ipg");+/* Get error code if not found */+ssi->has_ipg_clk_name=ret>=0;/* Check if being used in AC97 mode */sprop=of_get_property(np,"fsl,mode",NULL);-if(sprop){-if(!strcmp(sprop,"ac97-slave"))-ssi->dai_fmt=FSLSSI_AC97_DAIFMT;+if(sprop&&!strcmp(sprop,"ac97-slave")){+ssi->dai_fmt=FSLSSI_AC97_DAIFMT;++ret=of_property_read_u32(np,"cell-index",&ssi->card_idx);+if(ret){+dev_err(dev,"failed to get SSI index property\n");+return-EINVAL;+}+strcpy(ssi->card_name,"ac97-codec");}/* Select DMA or FIQ */ssi->use_dma=!of_property_read_bool(np,"fsl,fiq-stream-filter");+/* In synchronous mode, STCK and STFS ports are used by RX as well */+if(!of_find_property(np,"fsl,ssi-asynchronous",NULL))+ssi->synchronous=true;++/* Fetch FIFO depth; Set to 8 for older DT without this property */+iprop=of_get_property(np,"fsl,fifo-depth",NULL);+if(iprop)+ssi->fifo_depth=be32_to_cpup(iprop);+else+ssi->fifo_depth=8;++/* Use dual FIFO mode depending on the support from SDMA script */+ret=of_property_read_u32_array(np,"dmas",dmas,4);+if(ssi->use_dma&&!ret&&dmas[2]==IMX_DMATYPE_SSI_DUAL)+ssi->use_dual_fifo=true;++/*+*Backwardcompatibleforolderbindingsbymanuallytriggeringthe+*machinedriver'sprobe().Use/compatibleproperty,includingthe+*addressofCPUDAIdriverstructure,asthenameofmachinedriver+*+*Ifcard_nameissetbyAC97earlier,bypassheresinceitusesa+*differentnametoregisterthedevice.+*/+if(!ssi->card_name[0]&&of_get_property(np,"codec-handle",NULL)){+sprop=of_get_property(of_find_node_by_path("/"),+"compatible",NULL);+/* Strip "fsl," in the compatible name if applicable */+p=strrchr(sprop,',');+if(p)+sprop=p+1;+snprintf(ssi->card_name,sizeof(ssi->card_name),+"snd-soc-%s",sprop);+make_lowercase(ssi->card_name);+ssi->card_idx=0;+}++return0;+}++staticintfsl_ssi_probe(structplatform_device*pdev)+{+structregmap_configregconfig=fsl_ssi_regconfig;+structsnd_soc_dai_driver*cpu_dai_drv;+structdevice*dev=&pdev->dev;+structfsl_ssi*ssi;+structresource*res;+void__iomem*iomem;+intret=0;++ssi=devm_kzalloc(dev,sizeof(*ssi),GFP_KERNEL);+if(!ssi)+return-ENOMEM;++ssi->dev=dev;++/* Probe from DT */+ret=fsl_ssi_probe_from_dt(ssi);+if(ret)+returnret;+if(fsl_ssi_is_ac97(ssi)){cpu_dai_drv=&fsl_ssi_ac97_dai;fsl_ac97_data=ssi;
@@ -1407,15 +1467,11 @@ static int fsl_ssi_probe(struct platform_device *pdev)REG_SSI_SRMSK/sizeof(uint32_t)+1;}-ret=of_property_match_string(np,"clock-names","ipg");-if(ret<0){-ssi->has_ipg_clk_name=false;-ssi->regs=devm_regmap_init_mmio(dev,iomem,®config);-}else{-ssi->has_ipg_clk_name=true;+if(ssi->has_ipg_clk_name)ssi->regs=devm_regmap_init_mmio_clk(dev,"ipg",iomem,®config);-}+else+ssi->regs=devm_regmap_init_mmio(dev,iomem,®config);if(IS_ERR(ssi->regs)){dev_err(dev,"failed to init register map\n");returnPTR_ERR(ssi->regs);
@@ -1427,24 +1483,13 @@ static int fsl_ssi_probe(struct platform_device *pdev)returnssi->irq;}-/* Set software limitations for synchronous mode */-if(!of_find_property(np,"fsl,ssi-asynchronous",NULL)){-if(!fsl_ssi_is_ac97(ssi)){-cpu_dai_drv->symmetric_rates=1;-cpu_dai_drv->symmetric_samplebits=1;-ssi->synchronous=true;-}-+/* Set software limitations for synchronous mode except AC97 */+if(ssi->synchronous&&!fsl_ssi_is_ac97(ssi)){+cpu_dai_drv->symmetric_rates=1;cpu_dai_drv->symmetric_channels=1;+cpu_dai_drv->symmetric_samplebits=1;}-/* Fetch FIFO depth; Set to 8 for older DT without this property */-iprop=of_get_property(np,"fsl,fifo-depth",NULL);-if(iprop)-ssi->fifo_depth=be32_to_cpup(iprop);-else-ssi->fifo_depth=8;-/**ConfigureTXandRXDMAwatermarks--whentosendaDMArequest*
@@ -1509,47 +1554,14 @@ static int fsl_ssi_probe(struct platform_device *pdev)if(ret)gotoerror_asoc_register;-/* Bypass it if using newer DT bindings of ASoC machine drivers */-if(!of_get_property(np,"codec-handle",NULL))-gotodone;--/*-*Backwardcompatibleforolderbindingsbymanuallytriggeringthe-*machinedriver'sprobe().Use/compatibleproperty,includingthe-*addressofCPUDAIdriverstructure,asthenameofmachinedriver.-*/-sprop=of_get_property(of_find_node_by_path("/"),"compatible",NULL);-/* Sometimes the compatible name has a "fsl," prefix, so we strip it. */-p=strrchr(sprop,',');-if(p)-sprop=p+1;-snprintf(name,sizeof(name),"snd-soc-%s",sprop);-make_lowercase(name);--ssi->pdev=platform_device_register_data(dev,name,0,NULL,0);-if(IS_ERR(ssi->pdev)){-ret=PTR_ERR(ssi->pdev);-dev_err(dev,"failed to register platform: %d\n",ret);-gotoerror_sound_card;-}--done:-if(fsl_ssi_is_ac97(ssi)){-u32ssi_idx;--ret=of_property_read_u32(np,"cell-index",&ssi_idx);-if(ret){-dev_err(dev,"failed to get SSI index property\n");-gotoerror_sound_card;-}--ssi->pdev=platform_device_register_data(NULL,"ac97-codec",-ssi_idx,NULL,0);-if(IS_ERR(ssi->pdev)){-ret=PTR_ERR(ssi->pdev);-dev_err(dev,-"failed to register AC97 codec platform: %d\n",-ret);+/* Register a platform device for older bindings or AC97 */+if(ssi->card_name[0]){+ssi->card_pdev=platform_device_register_data(dev,+ssi->card_name,ssi->card_idx,NULL,0);+if(IS_ERR(ssi->card_pdev)){+ret=PTR_ERR(ssi->card_pdev);+dev_err(dev,"failed to register %s: %d\n",+ssi->card_name,ret);gotoerror_sound_card;}}
@@ -1577,8 +1589,8 @@ static int fsl_ssi_remove(struct platform_device *pdev)fsl_ssi_debugfs_remove(&ssi->dbg_stats);-if(ssi->pdev)-platform_device_unregister(ssi->pdev);+if(ssi->card_pdev)+platform_device_unregister(ssi->card_pdev);if(ssi->soc->imx)fsl_ssi_imx_clean(pdev,ssi);
The cpu_dai_drv is only used for symmetric_rates. So this patch replaces
it with a synchronous boolean flag.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
sound/soc/fsl/fsl_ssi.c | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)
@@ -663,7 +663,6 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,booltx2,tx=substream->stream==SNDRV_PCM_STREAM_PLAYBACK;structfsl_ssi*ssi=snd_soc_dai_get_drvdata(dai);structregmap*regs=ssi->regs;-intsynchronous=ssi->cpu_dai_drv.symmetric_rates,ret;u32pm=999,div2,psr,stccr,mask,afreq,factor,i;unsignedlongclkrate,baudrate,tmprate;unsignedintslots=params_channels(hw_params);
@@ -671,6 +670,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,u64sub,savesub=100000;unsignedintfreq;boolbaudclk_is_used;+intret;/* Override slots and slot_width if being specifically set... */if(ssi->slots)
@@ -749,7 +749,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,mask=SSI_SxCCR_PM_MASK|SSI_SxCCR_DIV2|SSI_SxCCR_PSR;/* STCCR is used for RX in synchronous mode */-tx2=tx||synchronous;+tx2=tx||ssi->synchronous;regmap_update_bits(regs,REG_SSI_SxCCR(tx2),mask,stccr);if(!baudclk_is_used){
@@ -797,7 +797,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,*thatshouldsetseparateconfigurationsforSTCCRandSRCCR*despiterunninginthesynchronousmode.*/-if(enabled&&ssi->cpu_dai_drv.symmetric_rates)+if(enabled&&ssi->synchronous)return0;if(fsl_ssi_is_i2s_master(ssi)){
@@ -829,7 +829,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,}/* In synchronous mode, the SSI uses STCCR for capture */-tx2=tx||ssi->cpu_dai_drv.symmetric_rates;+tx2=tx||ssi->synchronous;regmap_update_bits(regs,REG_SSI_SxCCR(tx2),SSI_SxCCR_WL_MASK,wl);return0;
@@ -954,7 +954,7 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi *ssi, unsigned int fmt)srcr=strcr;/* Set SYN mode and clear RXDIR bit when using SYN or AC97 mode */-if(ssi->cpu_dai_drv.symmetric_rates||fsl_ssi_is_ac97(ssi)){+if(ssi->synchronous||fsl_ssi_is_ac97(ssi)){srcr&=~SSI_SRCR_RXDIR;scr|=SSI_SCR_SYN;}
@@ -1386,14 +1387,12 @@ static int fsl_ssi_probe(struct platform_device *pdev)ssi->use_dma=!of_property_read_bool(np,"fsl,fiq-stream-filter");if(fsl_ssi_is_ac97(ssi)){-memcpy(&ssi->cpu_dai_drv,&fsl_ssi_ac97_dai,-sizeof(fsl_ssi_ac97_dai));+cpu_dai_drv=&fsl_ssi_ac97_dai;fsl_ac97_data=ssi;}else{-memcpy(&ssi->cpu_dai_drv,&fsl_ssi_dai_template,-sizeof(fsl_ssi_dai_template));+cpu_dai_drv=&fsl_ssi_dai_template;}-ssi->cpu_dai_drv.name=dev_name(dev);+cpu_dai_drv->name=dev_name(dev);res=platform_get_resource(pdev,IORESOURCE_MEM,0);iomem=devm_ioremap_resource(dev,res);
@@ -1431,11 +1430,12 @@ static int fsl_ssi_probe(struct platform_device *pdev)/* Set software limitations for synchronous mode */if(!of_find_property(np,"fsl,ssi-asynchronous",NULL)){if(!fsl_ssi_is_ac97(ssi)){-ssi->cpu_dai_drv.symmetric_rates=1;-ssi->cpu_dai_drv.symmetric_samplebits=1;+cpu_dai_drv->symmetric_rates=1;+cpu_dai_drv->symmetric_samplebits=1;+ssi->synchronous=true;}-ssi->cpu_dai_drv.symmetric_channels=1;+cpu_dai_drv->symmetric_channels=1;}/* Fetch FIFO depth; Set to 8 for older DT without this property */
@@ -1490,7 +1490,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)}ret=devm_snd_soc_register_component(dev,&fsl_ssi_component,-&ssi->cpu_dai_drv,1);+cpu_dai_drv,1);if(ret){dev_err(dev,"failed to register DAI: %d\n",ret);gotoerror_asoc_register;
The _fsl_ssi_set_dai_fmt() is a helper function being called from
fsl_ssi_set_dai_fmt() as an ASoC operation and from dai_probe(),
mainly for AC97 format initialization.
This patch cleans the _fsl_ssi_set_dai_fmt() in following ways:
* Removing *dev pointer in the parameters as it's included in the
*ssi pointer of struct fsl_ssi.
* Using regmap_update_bits() instead of regmap_read() and masking
the value manually.
* Removing TXBIT0 configurations since this bit is set to 1 as its
reset value and there is no use case so far to unset it. And it
is safe to remove since regmap_update_bits() won't touch it.
* Moving baudclk check to the switch-case routine to skip the I2S
master check. And moving SxCCR.DC settings after baudclk check.
* Adding format settings for SND_SOC_DAIFMT_AC97 like others.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
sound/soc/fsl/fsl_ssi.c | 70 ++++++++++++++++++++++---------------------------
1 file changed, 31 insertions(+), 39 deletions(-)
@@ -850,42 +850,27 @@ static int fsl_ssi_hw_free(struct snd_pcm_substream *substream,return0;}-staticint_fsl_ssi_set_dai_fmt(structdevice*dev,-structfsl_ssi*ssi,unsignedintfmt)+staticint_fsl_ssi_set_dai_fmt(structfsl_ssi*ssi,unsignedintfmt){-structregmap*regs=ssi->regs;-u32strcr=0,stcr,srcr,scr,mask;+u32strcr=0,scr=0,stcr,srcr,mask;ssi->dai_fmt=fmt;-if(fsl_ssi_is_i2s_master(ssi)&&IS_ERR(ssi->baudclk)){-dev_err(dev,"missing baudclk for master mode\n");-return-EINVAL;-}--regmap_read(regs,REG_SSI_SCR,&scr);-scr&=~(SSI_SCR_SYN|SSI_SCR_I2S_MODE_MASK);/* Synchronize frame sync clock for TE to avoid data slipping */scr|=SSI_SCR_SYNC_TX_FS;-mask=SSI_STCR_TXBIT0|SSI_STCR_TFDIR|SSI_STCR_TXDIR|-SSI_STCR_TSCKP|SSI_STCR_TFSI|SSI_STCR_TFSL|SSI_STCR_TEFS;-regmap_read(regs,REG_SSI_STCR,&stcr);-regmap_read(regs,REG_SSI_SRCR,&srcr);-stcr&=~mask;-srcr&=~mask;-/* Use Network mode as default */ssi->i2s_net=SSI_SCR_NET;switch(fmt&SND_SOC_DAIFMT_FORMAT_MASK){caseSND_SOC_DAIFMT_I2S:-regmap_update_bits(regs,REG_SSI_STCCR,-SSI_SxCCR_DC_MASK,SSI_SxCCR_DC(2));-regmap_update_bits(regs,REG_SSI_SRCCR,-SSI_SxCCR_DC_MASK,SSI_SxCCR_DC(2));switch(fmt&SND_SOC_DAIFMT_MASTER_MASK){caseSND_SOC_DAIFMT_CBM_CFS:caseSND_SOC_DAIFMT_CBS_CFS:+if(IS_ERR(ssi->baudclk)){+dev_err(ssi->dev,+"missing baudclk for master mode\n");+return-EINVAL;+}ssi->i2s_net|=SSI_SCR_I2S_MODE_MASTER;break;caseSND_SOC_DAIFMT_CBM_CFM:
@@ -895,30 +880,34 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,return-EINVAL;}+regmap_update_bits(ssi->regs,REG_SSI_STCCR,+SSI_SxCCR_DC_MASK,SSI_SxCCR_DC(2));+regmap_update_bits(ssi->regs,REG_SSI_SRCCR,+SSI_SxCCR_DC_MASK,SSI_SxCCR_DC(2));+/* Data on rising edge of bclk, frame low, 1clk before data */-strcr|=SSI_STCR_TFSI|SSI_STCR_TSCKP|-SSI_STCR_TXBIT0|SSI_STCR_TEFS;+strcr|=SSI_STCR_TFSI|SSI_STCR_TSCKP|SSI_STCR_TEFS;break;caseSND_SOC_DAIFMT_LEFT_J:/* Data on rising edge of bclk, frame high */-strcr|=SSI_STCR_TXBIT0|SSI_STCR_TSCKP;+strcr|=SSI_STCR_TSCKP;break;caseSND_SOC_DAIFMT_DSP_A:/* Data on rising edge of bclk, frame high, 1clk before data */-strcr|=SSI_STCR_TFSL|SSI_STCR_TSCKP|-SSI_STCR_TXBIT0|SSI_STCR_TEFS;+strcr|=SSI_STCR_TFSL|SSI_STCR_TSCKP|SSI_STCR_TEFS;break;caseSND_SOC_DAIFMT_DSP_B:/* Data on rising edge of bclk, frame high */-strcr|=SSI_STCR_TFSL|SSI_STCR_TSCKP|SSI_STCR_TXBIT0;+strcr|=SSI_STCR_TFSL|SSI_STCR_TSCKP;break;caseSND_SOC_DAIFMT_AC97:/* Data on falling edge of bclk, frame high, 1clk before data */-ssi->i2s_net|=SSI_SCR_I2S_MODE_NORMAL;+strcr|=SSI_STCR_TEFS;break;default:return-EINVAL;}+scr|=ssi->i2s_net;/* DAI clock inversion */
@@ -952,20 +941,17 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,break;caseSND_SOC_DAIFMT_CBM_CFM:/* Input bit or frame sync clocks */-scr&=~SSI_SCR_SYS_CLK_EN;break;caseSND_SOC_DAIFMT_CBM_CFS:/* Input bit clock but output frame sync clock */-strcr&=~SSI_STCR_TXDIR;strcr|=SSI_STCR_TFDIR;-scr&=~SSI_SCR_SYS_CLK_EN;break;default:return-EINVAL;}-stcr|=strcr;-srcr|=strcr;+stcr=strcr;+srcr=strcr;/* Set SYN mode and clear RXDIR bit when using SYN or AC97 mode */if(ssi->cpu_dai_drv.symmetric_rates||fsl_ssi_is_ac97(ssi)){
@@ -973,9 +959,15 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,scr|=SSI_SCR_SYN;}-regmap_write(regs,REG_SSI_STCR,stcr);-regmap_write(regs,REG_SSI_SRCR,srcr);-regmap_write(regs,REG_SSI_SCR,scr);+mask=SSI_STCR_TFDIR|SSI_STCR_TXDIR|SSI_STCR_TSCKP|+SSI_STCR_TFSI|SSI_STCR_TFSL|SSI_STCR_TEFS;++regmap_update_bits(ssi->regs,REG_SSI_STCR,mask,stcr);+regmap_update_bits(ssi->regs,REG_SSI_SRCR,mask,srcr);++mask=SSI_SCR_SYNC_TX_FS|SSI_SCR_I2S_MODE_MASK|+SSI_SCR_SYS_CLK_EN|SSI_SCR_SYN;+regmap_update_bits(ssi->regs,REG_SSI_SCR,mask,scr);return0;}
@@ -991,7 +983,7 @@ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)if(fsl_ssi_is_ac97(ssi))return0;-return_fsl_ssi_set_dai_fmt(dai->dev,ssi,fmt);+return_fsl_ssi_set_dai_fmt(ssi,fmt);}/**
@@ -1107,7 +1099,7 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)/* AC97 should start earlier to communicate with CODECs */if(fsl_ssi_is_ac97(ssi)){-_fsl_ssi_set_dai_fmt(ssi->dev,ssi,ssi->dai_fmt);+_fsl_ssi_set_dai_fmt(ssi,ssi->dai_fmt);fsl_ssi_setup_ac97(ssi);}
It'd be safer to enable both FIFOs for TX or RX at the same time.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
sound/soc/fsl/fsl_ssi.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
This patch cleans fsl_ssi_setup_regvals() by following changes:
1) Moving DBG bits to the first lines.
2) Setting SSIE, RE/TE as default and cleaning it for AC97
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
sound/soc/fsl/fsl_ssi.c | 17 ++++++-----------
1 file changed, 6 insertions(+), 11 deletions(-)
@@ -570,18 +570,16 @@ static void fsl_ssi_setup_regvals(struct fsl_ssi *ssi){structfsl_ssi_regvals*vals=ssi->regvals;-vals[RX].sier=SSI_SIER_RFF0_EN;+vals[RX].sier=SSI_SIER_RFF0_EN|FSLSSI_SIER_DBG_RX_FLAGS;vals[RX].srcr=SSI_SRCR_RFEN0;-vals[RX].scr=0;-vals[TX].sier=SSI_SIER_TFE0_EN;+vals[RX].scr=SSI_SCR_SSIEN|SSI_SCR_RE;+vals[TX].sier=SSI_SIER_TFE0_EN|FSLSSI_SIER_DBG_TX_FLAGS;vals[TX].stcr=SSI_STCR_TFEN0;-vals[TX].scr=0;+vals[TX].scr=SSI_SCR_SSIEN|SSI_SCR_TE;/* AC97 has already enabled SSIEN, RE and TE, so ignore them */-if(!fsl_ssi_is_ac97(ssi)){-vals[RX].scr=SSI_SCR_SSIEN|SSI_SCR_RE;-vals[TX].scr=SSI_SCR_SSIEN|SSI_SCR_TE;-}+if(fsl_ssi_is_ac97(ssi))+vals[RX].scr=vals[TX].scr=0;if(ssi->use_dma){vals[RX].sier|=SSI_SIER_RDMAE;
The _fsl_ssi_set_dai_fmt() bypasses an undefined format for AC97
mode. However, it's not really necessary if AC97 has its complete
format defined.
So this patch adds a DAIFMT macro of complete format including a
clock direction and polarity.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
sound/soc/fsl/fsl_ssi.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
The trigger() calls fsl_ssi_tx_config() and fsl_ssi_rx_config(),
and both of them jump to fsl_ssi_config(). And fsl_ssi_config()
later calls another fsl_ssi_rxtx_config().
However, the whole routine, especially fsl_ssi_config() function,
is too complicated because of the folowing reasons:
1) It has to handle the concern of the opposite stream.
2) It has to handle cases of offline configurations support.
3) It has to handle enable and disable operations while they're
mostly different.
Since the enable and disable routines have more differences than
TX and RX rountines, this patch simplifies these helper functions
with the following changes:
- Changing to two helper functions of enable and disable instead
of TX and RX.
- Removing fsl_ssi_rxtx_config() by separately integrating it to
two newly introduced enable & disable functions.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
sound/soc/fsl/fsl_ssi.c | 254 +++++++++++++++++++++++-------------------------
1 file changed, 119 insertions(+), 135 deletions(-)
@@ -378,31 +378,81 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)}/**-*Enableordisableallrx/txconfigflagsatonce+*SetSCR,SIER,STCRandSRCRregisterswithcachedvaluesinregvals+*+*Notes:+*1)Foroffline_configSoCs,enableallnecessarybitsofbothstreams+*when1ststreamstarts,eveniftheoppositestreamwillnotstart+*2)ItalsoclearsFIFObeforesettingregvals;SORissafetosetonline*/-staticvoidfsl_ssi_rxtx_config(structfsl_ssi*ssi,boolenable)+staticvoidfsl_ssi_config_enable(structfsl_ssi*ssi,booltx){-structregmap*regs=ssi->regs;structfsl_ssi_regvals*vals=ssi->regvals;+u32sier,srcr,stcr;-if(enable){-regmap_update_bits(regs,REG_SSI_SIER,-vals[RX].sier|vals[TX].sier,-vals[RX].sier|vals[TX].sier);-regmap_update_bits(regs,REG_SSI_SRCR,-vals[RX].srcr|vals[TX].srcr,-vals[RX].srcr|vals[TX].srcr);-regmap_update_bits(regs,REG_SSI_STCR,-vals[RX].stcr|vals[TX].stcr,-vals[RX].stcr|vals[TX].stcr);+/* Clear dirty data in the FIFO; It also prevents channel slipping */+regmap_update_bits(ssi->regs,REG_SSI_SOR,+SSI_SOR_xX_CLR(tx),SSI_SOR_xX_CLR(tx));++/*+*Onoffline_configSoCs,SxCRandSIERarealreadyconfiguredwhen+*thepreviousstreamstarted.SoskipallSxCRandSIERsettings+*topreventonlinereconfigurations,thenjumptosetSCRdirectly+*/+if(ssi->soc->offline_config&&ssi->streams)+gotoenable_scr;++if(ssi->soc->offline_config){+/*+*Onlinereconfigurationnotsupported,soenableallbitsfor+*bothstreamsatoncetoavoidnecessityofreconfigurations+*/+srcr=vals[RX].srcr|vals[TX].srcr;+stcr=vals[RX].stcr|vals[TX].stcr;+sier=vals[RX].sier|vals[TX].sier;}else{-regmap_update_bits(regs,REG_SSI_SRCR,-vals[RX].srcr|vals[TX].srcr,0);-regmap_update_bits(regs,REG_SSI_STCR,-vals[RX].stcr|vals[TX].stcr,0);-regmap_update_bits(regs,REG_SSI_SIER,-vals[RX].sier|vals[TX].sier,0);+/* Otherwise, only set bits for the current stream */+srcr=vals[tx].srcr;+stcr=vals[tx].stcr;+sier=vals[tx].sier;}++/* Configure SRCR, STCR and SIER at once */+regmap_update_bits(ssi->regs,REG_SSI_SRCR,srcr,srcr);+regmap_update_bits(ssi->regs,REG_SSI_STCR,stcr,stcr);+regmap_update_bits(ssi->regs,REG_SSI_SIER,sier,sier);++enable_scr:+/*+*StartDMAbeforesettingTEtoavoidFIFOunderrun+*whichmaycauseachannelsliporachannelswap+*+*TODO:FIQcasesmightalsoneedthisupontesting+*/+if(ssi->use_dma&&tx){+inttry=100;+u32sfcsr;++/* Enable SSI first to send TX DMA request */+regmap_update_bits(ssi->regs,REG_SSI_SCR,+SSI_SCR_SSIEN,SSI_SCR_SSIEN);++/* Busy wait until TX FIFO not empty -- DMA working */+do{+regmap_read(ssi->regs,REG_SSI_SFCSR,&sfcsr);+if(SSI_SFCSR_TFCNT0(sfcsr))+break;+}while(--try);++/* FIFO still empty -- something might be wrong */+if(!SSI_SFCSR_TFCNT0(sfcsr))+dev_warn(ssi->dev,"Timeout waiting TX FIFO filling\n");+}+/* Enable all remaining bits in SCR */+regmap_update_bits(ssi->regs,REG_SSI_SCR,vals[tx].scr,vals[tx].scr);++/* Log the enabled stream to the mask */+ssi->streams|=BIT(tx);}/**
@@ -426,65 +476,50 @@ static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable)((vals)&_ssi_xor_shared_bits(vals,avals,aactive))/**-*EnableordisableSSIconfiguration.+*UnsetSCR,SIER,STCRandSRCRregisterswithcachedvaluesinregvals+*+*Notes:+*1)Foroffline_configSoCs,toavoidonlinereconfigurations,disableall+*bitsofbothstreamsatoncewhenthelaststreamisaborttoend+*2)ItalsoclearsFIFOafterunsettingregvals;SORissafetosetonline*/-staticvoidfsl_ssi_config(structfsl_ssi*ssi,boolenable,-structfsl_ssi_regvals*vals)+staticvoidfsl_ssi_config_disable(structfsl_ssi*ssi,booltx){-booltx=&ssi->regvals[TX]==vals;-structregmap*regs=ssi->regs;-structfsl_ssi_regvals*avals;+structfsl_ssi_regvals*avals,*vals=&ssi->regvals[tx];+u32sier,srcr,stcr,scr;boolaactive;/* Check if the opposite stream is active */aactive=ssi->streams&BIT(!tx);-/* Get the opposite direction to keep its values untouched */-if(&ssi->regvals[RX]==vals)-avals=&ssi->regvals[TX];-else-avals=&ssi->regvals[RX];--if(!enable){-/*-*Tokeeptheotherstreamsafe,excludesharedbitsbetween-*bothstreams,andgetsafebitstodisablecurrentstream-*/-u32scr=ssi_excl_shared_bits(vals->scr,avals->scr,aactive);-/* Safely disable SCR register for the stream */-regmap_update_bits(regs,REG_SSI_SCR,scr,0);--/* Log the disabled stream to the mask */-ssi->streams&=~BIT(tx);-}+/* Get regvals of the opposite stream to keep opposite stream safe */+avals=&ssi->regvals[!tx];/*-*Forcaseswhereonlineconfigurationisnotsupported,-*1)Enableallnecessarybitsofbothstreamswhen1ststreamstarts-*eveniftheoppositestreamwillnotstart-*2)Disableallremainingbitsofbothstreamswhenlaststreamends+*Tokeeptheotherstreamsafe,excludesharedbitsbetween+*bothstreams,andgetsafebitstodisablecurrentstream*/-if(ssi->soc->offline_config){-if((enable&&!ssi->streams)||(!enable&&!aactive))-fsl_ssi_rxtx_config(ssi,enable);+scr=ssi_excl_shared_bits(vals->scr,avals->scr,aactive);-gotoconfig_done;-}+/* Disable safe bits of SCR register for the current stream */+regmap_update_bits(ssi->regs,REG_SSI_SCR,scr,0);-/* Online configure single direction while SSI is running */-if(enable){-/* Clear FIFO to prevent dirty data or channel slipping */-regmap_update_bits(ssi->regs,REG_SSI_SOR,-SSI_SOR_xX_CLR(tx),SSI_SOR_xX_CLR(tx));+/* Log the disabled stream to the mask */+ssi->streams&=~BIT(tx);-regmap_update_bits(regs,REG_SSI_SRCR,vals->srcr,vals->srcr);-regmap_update_bits(regs,REG_SSI_STCR,vals->stcr,vals->stcr);-regmap_update_bits(regs,REG_SSI_SIER,vals->sier,vals->sier);-}else{-u32sier;-u32srcr;-u32stcr;+/*+*Onoffline_configSoCs,iftheotherstreamisactive,skip+*SxCRandSIERsettingstopreventonlinereconfigurations+*/+if(ssi->soc->offline_config&&aactive)+gotofifo_clear;+if(ssi->soc->offline_config){+/* Now there is only current stream active, disable all bits */+srcr=vals->srcr|avals->srcr;+stcr=vals->stcr|avals->stcr;+sier=vals->sier|avals->sier;+}else{/**Tokeeptheotherstreamsafe,excludesharedbitsbetween*bothstreams,andgetsafebitstodisablecurrentstream
@@ -492,57 +527,17 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable,sier=ssi_excl_shared_bits(vals->sier,avals->sier,aactive);srcr=ssi_excl_shared_bits(vals->srcr,avals->srcr,aactive);stcr=ssi_excl_shared_bits(vals->stcr,avals->stcr,aactive);--/* Safely disable other control registers for the stream */-regmap_update_bits(regs,REG_SSI_SRCR,srcr,0);-regmap_update_bits(regs,REG_SSI_STCR,stcr,0);-regmap_update_bits(regs,REG_SSI_SIER,sier,0);--/* Clear FIFO to prevent dirty data or channel slipping */-regmap_update_bits(ssi->regs,REG_SSI_SOR,-SSI_SOR_xX_CLR(tx),SSI_SOR_xX_CLR(tx));}-config_done:-/* Enabling of subunits is done after configuration */-if(enable){-/*-*StartDMAbeforesettingTEtoavoidFIFOunderrun-*whichmaycauseachannelsliporachannelswap-*-*TODO:FIQcasesmightalsoneedthisupontesting-*/-if(ssi->use_dma&&(vals->scr&SSI_SCR_TE)){-inti;-intmax_loop=100;--/* Enable SSI first to send TX DMA request */-regmap_update_bits(regs,REG_SSI_SCR,-SSI_SCR_SSIEN,SSI_SCR_SSIEN);--/* Busy wait until TX FIFO not empty -- DMA working */-for(i=0;i<max_loop;i++){-u32sfcsr;-regmap_read(regs,REG_SSI_SFCSR,&sfcsr);-if(SSI_SFCSR_TFCNT0(sfcsr))-break;-}-if(i==max_loop){-dev_err(ssi->dev,-"Timeout waiting TX FIFO filling\n");-}-}-/* Enable all remaining bits */-regmap_update_bits(regs,REG_SSI_SCR,vals->scr,vals->scr);--/* Log the enabled stream to the mask */-ssi->streams|=BIT(tx);-}-}+/* Clear configurations of SRCR, STCR and SIER at once */+regmap_update_bits(ssi->regs,REG_SSI_SRCR,srcr,0);+regmap_update_bits(ssi->regs,REG_SSI_STCR,stcr,0);+regmap_update_bits(ssi->regs,REG_SSI_SIER,sier,0);-staticvoidfsl_ssi_rx_config(structfsl_ssi*ssi,boolenable)-{-fsl_ssi_config(ssi,enable,&ssi->regvals[RX]);+fifo_clear:+/* Clear remaining data in the FIFO */+regmap_update_bits(ssi->regs,REG_SSI_SOR,+SSI_SOR_xX_CLR(tx),SSI_SOR_xX_CLR(tx));}staticvoidfsl_ssi_tx_ac97_saccst_setup(structfsl_ssi*ssi)
The FIFO clear helper function is just one line of code now.
So it could be cleaned up by removing it and calling regmap
directly.
Meanwhile, FIFO clear could be applied to all use cases, not
confined to AC97. So this patch also moves FIFO clear in the
trigger() to fsl_ssi_config() and removes the AC97 check.
Note that SOR register is safe from offline_config HW limit.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
sound/soc/fsl/fsl_ssi.c | 28 +++++++---------------------
1 file changed, 7 insertions(+), 21 deletions(-)
@@ -484,7 +473,9 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable,/* Online configure single direction while SSI is running */if(enable){-fsl_ssi_fifo_clear(ssi,vals->scr&SSI_SCR_RE);+/* Clear FIFO to prevent dirty data or channel slipping */+regmap_update_bits(ssi->regs,REG_SSI_SOR,+SSI_SOR_xX_CLR(tx),SSI_SOR_xX_CLR(tx));regmap_update_bits(regs,REG_SSI_SRCR,vals->srcr,vals->srcr);regmap_update_bits(regs,REG_SSI_STCR,vals->stcr,vals->stcr);
@@ -506,6 +497,10 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable,regmap_update_bits(regs,REG_SSI_SRCR,srcr,0);regmap_update_bits(regs,REG_SSI_STCR,stcr,0);regmap_update_bits(regs,REG_SSI_SIER,sier,0);++/* Clear FIFO to prevent dirty data or channel slipping */+regmap_update_bits(ssi->regs,REG_SSI_SOR,+SSI_SOR_xX_CLR(tx),SSI_SOR_xX_CLR(tx));}config_done:
@@ -1086,7 +1081,6 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,{structsnd_soc_pcm_runtime*rtd=substream->private_data;structfsl_ssi*ssi=snd_soc_dai_get_drvdata(rtd->cpu_dai);-structregmap*regs=ssi->regs;switch(cmd){caseSNDRV_PCM_TRIGGER_START:
@@ -1111,14 +1105,6 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,return-EINVAL;}-/* Clear corresponding FIFO */-if(fsl_ssi_is_ac97(ssi)){-if(substream->stream==SNDRV_PCM_STREAM_PLAYBACK)-regmap_write(regs,REG_SSI_SOR,SSI_SOR_TX_CLR);-else-regmap_write(regs,REG_SSI_SOR,SSI_SOR_RX_CLR);-}-return0;}
The define of fsl_ssi_disable_val is not so clear as it mixes two
steps of calculations together. And those parameter names are also
a bit long to read.
Since it just tries to exclude the shared bits from the regvals of
current stream while the opposite stream is active, it's better to
use something like ssi_excl_shared_bits.
This patch also bisects fsl_ssi_disable_val into two macros of two
corresponding steps and then shortens its parameter names. It also
updates callers in the fsl_ssi_config() accordingly.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
sound/soc/fsl/fsl_ssi.c | 54 ++++++++++++++++++++-----------------------------
1 file changed, 22 insertions(+), 32 deletions(-)
@@ -445,16 +445,10 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable,booltx=&ssi->regvals[TX]==vals;structregmap*regs=ssi->regs;structfsl_ssi_regvals*avals;-intnr_active_streams;-intkeep_active;--nr_active_streams=!!(ssi->streams&BIT(TX))+-!!(ssi->streams&BIT(RX));+boolaactive;-if(nr_active_streams-1>0)-keep_active=1;-else-keep_active=0;+/* Check if the opposite stream is active */+aactive=ssi->streams&BIT(!tx);/* Get the opposite direction to keep its values untouched */if(&ssi->regvals[RX]==vals)
@@ -467,8 +461,7 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable,*Tokeeptheotherstreamsafe,excludesharedbitsbetween*bothstreams,andgetsafebitstodisablecurrentstream*/-u32scr=fsl_ssi_disable_val(vals->scr,avals->scr,-keep_active);+u32scr=ssi_excl_shared_bits(vals->scr,avals->scr,aactive);/* Safely disable SCR register for the stream */regmap_update_bits(regs,REG_SSI_SCR,scr,0);
@@ -505,12 +498,9 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable,*Tokeeptheotherstreamsafe,excludesharedbitsbetween*bothstreams,andgetsafebitstodisablecurrentstream*/-sier=fsl_ssi_disable_val(vals->sier,avals->sier,-keep_active);-srcr=fsl_ssi_disable_val(vals->srcr,avals->srcr,-keep_active);-stcr=fsl_ssi_disable_val(vals->stcr,avals->stcr,-keep_active);+sier=ssi_excl_shared_bits(vals->sier,avals->sier,aactive);+srcr=ssi_excl_shared_bits(vals->srcr,avals->srcr,aactive);+stcr=ssi_excl_shared_bits(vals->stcr,avals->stcr,aactive);/* Safely disable other control registers for the stream */regmap_update_bits(regs,REG_SSI_SRCR,srcr,0);
Checking TE and RE bits in SCR register doesn't work for AC97 mode
which enables SSIEN, TE and RE in the fsl_ssi_setup_ac97() that's
called during probe().
So when running into the trigger(), it will always get the result
of both TE and RE being enabled already, even if actually there is
no active stream.
This patch fixes this issue by adding a variable to log the active
streams manually.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
sound/soc/fsl/fsl_ssi.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
From: Timur Tabi <hidden> Date: 2017-12-19 17:34:46
On 12/19/17 11:00 AM, Nicolin Chen wrote:
This series of patches is the second set to clean up fsl_ssi driver
in the program flow level. Any patch here may impact a fundamental
test case like playback or record.
With Christmas happening over the next two weeks, I don't think I'll be able to review these patches until January.
From: Maciej S. Szmigiero <hidden> Date: 2018-01-01 15:17:36
On 19.12.2017 18:00, Nicolin Chen wrote:
AC97 configures some registers earlier to start a communication
with CODECs, so this patch moves those register settings to the
dai_probe() as well, along with other register configurations.
It also applies _fsl_ssi_set_dai_fmt() to AC97 only since other
formats would be configured via fsl_ssi_set_dai_fmt() directly.
Meanwhile, this patch adds fsl_ssi_dai_ac97_remove() to cleanup
some control bits for AC97.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
This patch breaks AC'97 CODEC probing.
Namely, the fsl_ssi DAI probe callback is only called after the AC'97
CODEC probe callback, so when you move SSI AC'97 startup to its DAI
probe callback it won't be done yet when the CODEC is probed (and this
requires a working AC'97 interface to successfully complete).
Maciej
From: Maciej S. Szmigiero <hidden> Date: 2018-01-01 18:40:04
On 19.12.2017 18:00, Nicolin Chen wrote:
quoted hunk
This patch replaces the register read with ssi->i2s_net for
simplification. It also removes masking SSIEN from scr value
since it's handled later by regmap_update_bits() to set this
scr value back.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
sound/soc/fsl/fsl_ssi.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
@@ -1051,9 +1051,7 @@ static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,}/* The slot number should be >= 2 if using Network mode or I2S mode */-regmap_read(regs,REG_SSI_SCR,&val);-val&=SSI_SCR_I2S_MODE_MASK|SSI_SCR_NET;-if(val&&slots<2){+if(ssi->i2s_net&&slots<2){dev_err(dai->dev,"slot number should be >= 2 in I2S or NET\n");return-EINVAL;}
Are you sure that ssi->i2s_net SSI_SCR_I2S_MODE_MASK | SSI_SCR_NET bits
(also known as SSI_SCR_I2S_NET_MASK) zero or non-zero status is always
consistent with that in the SCR register?
I can see that in fsl_ssi_hw_params() these bits in SCR are zeroed in
a one special case and in the second special case they are hardcoded
to SSI_SCR_I2S_MODE_NORMAL | SSI_SCR_NET, in both cases regardless of
what is currently in ssi->i2s_net.
Maciej
From: Maciej S. Szmigiero <hidden> Date: 2018-01-01 21:29:38
On 19.12.2017 18:00, Nicolin Chen wrote:
quoted hunk
The define of fsl_ssi_disable_val is not so clear as it mixes two
steps of calculations together. And those parameter names are also
a bit long to read.
Since it just tries to exclude the shared bits from the regvals of
current stream while the opposite stream is active, it's better to
use something like ssi_excl_shared_bits.
This patch also bisects fsl_ssi_disable_val into two macros of two
corresponding steps and then shortens its parameter names. It also
updates callers in the fsl_ssi_config() accordingly.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
sound/soc/fsl/fsl_ssi.c | 54 ++++++++++++++++++++-----------------------------
1 file changed, 22 insertions(+), 32 deletions(-)
@@ -445,16 +445,10 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, bool tx = &ssi->regvals[TX] == vals; struct regmap *regs = ssi->regs; struct fsl_ssi_regvals *avals;- int nr_active_streams;- int keep_active;-- nr_active_streams = !!(ssi->streams & BIT(TX)) +- !!(ssi->streams & BIT(RX));+ bool aactive;- if (nr_active_streams - 1 > 0)- keep_active = 1;- else- keep_active = 0;+ /* Check if the opposite stream is active */+ aactive = ssi->streams & BIT(!tx);
I don't think that hardcoding an implicit assumption here that RX == 0,
TX == 1 is a good thing.
If in the future, for any reason, somebody changes values of these macros
this code will silently break.
I would instead change this line into something like
"aactive = ssi->streams & (tx ? BIT(RX) : BIT(TX));" or similar.
Maciej
From: Maciej S. Szmigiero <hidden> Date: 2018-01-01 21:59:42
On 19.12.2017 18:00, Nicolin Chen wrote:
quoted hunk
The trigger() calls fsl_ssi_tx_config() and fsl_ssi_rx_config(),
and both of them jump to fsl_ssi_config(). And fsl_ssi_config()
later calls another fsl_ssi_rxtx_config().
However, the whole routine, especially fsl_ssi_config() function,
is too complicated because of the folowing reasons:
1) It has to handle the concern of the opposite stream.
2) It has to handle cases of offline configurations support.
3) It has to handle enable and disable operations while they're
mostly different.
Since the enable and disable routines have more differences than
TX and RX rountines, this patch simplifies these helper functions
with the following changes:
- Changing to two helper functions of enable and disable instead
of TX and RX.
- Removing fsl_ssi_rxtx_config() by separately integrating it to
two newly introduced enable & disable functions.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
sound/soc/fsl/fsl_ssi.c | 254 +++++++++++++++++++++++-------------------------
1 file changed, 119 insertions(+), 135 deletions(-)
@@ -378,31 +378,81 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)}/**-*Enableordisableallrx/txconfigflagsatonce+*SetSCR,SIER,STCRandSRCRregisterswithcachedvaluesinregvals+*+*Notes:+*1)Foroffline_configSoCs,enableallnecessarybitsofbothstreams+*when1ststreamstarts,eveniftheoppositestreamwillnotstart+*2)ItalsoclearsFIFObeforesettingregvals;SORissafetosetonline*/-staticvoidfsl_ssi_rxtx_config(structfsl_ssi*ssi,boolenable)+staticvoidfsl_ssi_config_enable(structfsl_ssi*ssi,booltx){-structregmap*regs=ssi->regs;structfsl_ssi_regvals*vals=ssi->regvals;+u32sier,srcr,stcr;-if(enable){-regmap_update_bits(regs,REG_SSI_SIER,-vals[RX].sier|vals[TX].sier,-vals[RX].sier|vals[TX].sier);-regmap_update_bits(regs,REG_SSI_SRCR,-vals[RX].srcr|vals[TX].srcr,-vals[RX].srcr|vals[TX].srcr);-regmap_update_bits(regs,REG_SSI_STCR,-vals[RX].stcr|vals[TX].stcr,-vals[RX].stcr|vals[TX].stcr);+/* Clear dirty data in the FIFO; It also prevents channel slipping */+regmap_update_bits(ssi->regs,REG_SSI_SOR,+SSI_SOR_xX_CLR(tx),SSI_SOR_xX_CLR(tx));++/*+*Onoffline_configSoCs,SxCRandSIERarealreadyconfiguredwhen+*thepreviousstreamstarted.SoskipallSxCRandSIERsettings+*topreventonlinereconfigurations,thenjumptosetSCRdirectly+*/+if(ssi->soc->offline_config&&ssi->streams)+gotoenable_scr;++if(ssi->soc->offline_config){+/*+*Onlinereconfigurationnotsupported,soenableallbitsfor+*bothstreamsatoncetoavoidnecessityofreconfigurations+*/+srcr=vals[RX].srcr|vals[TX].srcr;+stcr=vals[RX].stcr|vals[TX].stcr;+sier=vals[RX].sier|vals[TX].sier;}else{-regmap_update_bits(regs,REG_SSI_SRCR,-vals[RX].srcr|vals[TX].srcr,0);-regmap_update_bits(regs,REG_SSI_STCR,-vals[RX].stcr|vals[TX].stcr,0);-regmap_update_bits(regs,REG_SSI_SIER,-vals[RX].sier|vals[TX].sier,0);+/* Otherwise, only set bits for the current stream */+srcr=vals[tx].srcr;+stcr=vals[tx].stcr;+sier=vals[tx].sier;
Implicit assumption here that RX == 0, TX == 1, as in the 03 patch.
quoted hunk
}++ /* Configure SRCR, STCR and SIER at once */+ regmap_update_bits(ssi->regs, REG_SSI_SRCR, srcr, srcr);+ regmap_update_bits(ssi->regs, REG_SSI_STCR, stcr, stcr);+ regmap_update_bits(ssi->regs, REG_SSI_SIER, sier, sier);++enable_scr:+ /*+ * Start DMA before setting TE to avoid FIFO underrun+ * which may cause a channel slip or a channel swap+ *+ * TODO: FIQ cases might also need this upon testing+ */+ if (ssi->use_dma && tx) {+ int try = 100;+ u32 sfcsr;++ /* Enable SSI first to send TX DMA request */+ regmap_update_bits(ssi->regs, REG_SSI_SCR,+ SSI_SCR_SSIEN, SSI_SCR_SSIEN);++ /* Busy wait until TX FIFO not empty -- DMA working */+ do {+ regmap_read(ssi->regs, REG_SSI_SFCSR, &sfcsr);+ if (SSI_SFCSR_TFCNT0(sfcsr))+ break;+ } while (--try);++ /* FIFO still empty -- something might be wrong */+ if (!SSI_SFCSR_TFCNT0(sfcsr))+ dev_warn(ssi->dev, "Timeout waiting TX FIFO filling\n");+ }+ /* Enable all remaining bits in SCR */+ regmap_update_bits(ssi->regs, REG_SSI_SCR, vals[tx].scr, vals[tx].scr);
Ditto.
quoted hunk
++ /* Log the enabled stream to the mask */+ ssi->streams |= BIT(tx);
Ditto.
quoted hunk
}
/**
@@ -426,65 +476,50 @@ static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable) ((vals) & _ssi_xor_shared_bits(vals, avals, aactive)) /**- * Enable or disable SSI configuration.+ * Unset SCR, SIER, STCR and SRCR registers with cached values in regvals+ *+ * Notes:+ * 1) For offline_config SoCs, to avoid online reconfigurations, disable all+ * bits of both streams at once when the last stream is abort to end+ * 2) It also clears FIFO after unsetting regvals; SOR is safe to set online */-static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable,- struct fsl_ssi_regvals *vals)+static void fsl_ssi_config_disable(struct fsl_ssi *ssi, bool tx) {- bool tx = &ssi->regvals[TX] == vals;- struct regmap *regs = ssi->regs;- struct fsl_ssi_regvals *avals;+ struct fsl_ssi_regvals *avals, *vals = &ssi->regvals[tx];
Ditto.
quoted hunk
+ u32 sier, srcr, stcr, scr; bool aactive; /* Check if the opposite stream is active */ aactive = ssi->streams & BIT(!tx);- /* Get the opposite direction to keep its values untouched */- if (&ssi->regvals[RX] == vals)- avals = &ssi->regvals[TX];- else- avals = &ssi->regvals[RX];-- if (!enable) {- /*- * To keep the other stream safe, exclude shared bits between- * both streams, and get safe bits to disable current stream- */- u32 scr = ssi_excl_shared_bits(vals->scr, avals->scr, aactive);- /* Safely disable SCR register for the stream */- regmap_update_bits(regs, REG_SSI_SCR, scr, 0);-- /* Log the disabled stream to the mask */- ssi->streams &= ~BIT(tx);- }+ /* Get regvals of the opposite stream to keep opposite stream safe */+ avals = &ssi->regvals[!tx];
Ditto.
quoted hunk
/*- * For cases where online configuration is not supported,- * 1) Enable all necessary bits of both streams when 1st stream starts- * even if the opposite stream will not start- * 2) Disable all remaining bits of both streams when last stream ends+ * To keep the other stream safe, exclude shared bits between+ * both streams, and get safe bits to disable current stream */- if (ssi->soc->offline_config) {- if ((enable && !ssi->streams) || (!enable && !aactive))- fsl_ssi_rxtx_config(ssi, enable);+ scr = ssi_excl_shared_bits(vals->scr, avals->scr, aactive);- goto config_done;- }+ /* Disable safe bits of SCR register for the current stream */+ regmap_update_bits(ssi->regs, REG_SSI_SCR, scr, 0);- /* Online configure single direction while SSI is running */- if (enable) {- /* Clear FIFO to prevent dirty data or channel slipping */- regmap_update_bits(ssi->regs, REG_SSI_SOR,- SSI_SOR_xX_CLR(tx), SSI_SOR_xX_CLR(tx));+ /* Log the disabled stream to the mask */+ ssi->streams &= ~BIT(tx);
On Tue, Dec 19, 2017 at 9:00 AM, Nicolin Chen [off-list ref] wrote:
==Background==
The fsl_ssi driver was designed for PPC originally and then it has
been updated to support different modes for i.MX Series, including
SDMA, I2S Master mode, AC97 and older i.MXs with FIQ, by different
contributors for different use cases in different coding styles.
Additionally, in order to fix/work-around hardware bugs and design
flaws, the driver made a lot of compromise so now its program flow
looks very complicated and it's getting hard to maintain or update.
So I am going to clean up the driver on both coding style level and
program flow level.
==Introduction==
This series of patches is the second set to clean up fsl_ssi driver
in the program flow level. Any patch here may impact a fundamental
test case like playback or record.
==Verification==
This series of patches require fully tested. I have done such tests
on i.MX6SoloX with WM8962 using imx_v6_v7_defconfig as:
- Playback via I2S Master and Slave mode
- Record via I2S Master and Slave mode
- Simultaneous playback and record via I2S Master and Slave mode
- Background playback with foreground record (starting at different
time) via I2S Master and Slave mode
- Background record with foreground playback (starting at different
time) via I2S Master and Slave mode
* All tests above by hacking offline_config to true in imx51.
Example of uncovered tests: TDM, AC97, PowerPC and FIQ.
Nicolin Chen (15):
ASoC: fsl_ssi: Clean up set_dai_tdm_slot()
ASoC: fsl_ssi: Maintain a mask of active streams
ASoC: fsl_ssi: Rename fsl_ssi_disable_val macro
ASoC: fsl_ssi: Clear FIFO directly in fsl_ssi_config()
ASoC: fsl_ssi: Clean up helper functions of trigger()
ASoC: fsl_ssi: Add DAIFMT define for AC97
ASoC: fsl_ssi: Clean up fsl_ssi_setup_regvals()
ASoC: fsl_ssi: Set xFEN0 and xFEN1 together
ASoC: fsl_ssi: Use snd_soc_init_dma_data instead
ASoC: fsl_ssi: Move one-time configurations to dai_probe()
ASoC: fsl_ssi: Setup AC97 in dai_probe()
ASoC: fsl_ssi: Clean up _fsl_ssi_set_dai_fmt()
ASoC: fsl_ssi: Remove cpu_dai_drv from fsl_ssi structure
ASoC: fsl_ssi: Move DT related code to a separate probe()
ASoC: fsl_ssi: Use ssi->streams instead of reading register
sound/soc/fsl/fsl_ssi.c | 710 ++++++++++++++++++++++++------------------------
1 file changed, 348 insertions(+), 362 deletions(-)
--
2.7.4
tested this patch set on MX6 SSI against broonie for-next (4.15-rc5),
no problems.
Do I send a separate Tested-by for each patch, or just the 00/15 one?
Tested-by: Caleb Crome <redacted>
On Mon, Jan 01, 2018 at 04:17:20PM +0100, Maciej S. Szmigiero wrote:
quoted
AC97 configures some registers earlier to start a communication
with CODECs, so this patch moves those register settings to the
dai_probe() as well, along with other register configurations.
This patch breaks AC'97 CODEC probing.
Namely, the fsl_ssi DAI probe callback is only called after the AC'97
CODEC probe callback, so when you move SSI AC'97 startup to its DAI
probe callback it won't be done yet when the CODEC is probed (and this
requires a working AC'97 interface to successfully complete).
Hmm...What's the dependency here? Why is it required like this?
I am okay to put everything to a separate fsl_ssi_hw_init() and
move it back to the platform probe() though.
On Mon, Jan 01, 2018 at 07:39:52PM +0100, Maciej S. Szmigiero wrote:
quoted
/* The slot number should be >= 2 if using Network mode or I2S mode */- regmap_read(regs, REG_SSI_SCR, &val);- val &= SSI_SCR_I2S_MODE_MASK | SSI_SCR_NET;- if (val && slots < 2) {+ if (ssi->i2s_net && slots < 2) { dev_err(dai->dev, "slot number should be >= 2 in I2S or NET\n"); return -EINVAL; }
Are you sure that ssi->i2s_net SSI_SCR_I2S_MODE_MASK | SSI_SCR_NET bits
(also known as SSI_SCR_I2S_NET_MASK) zero or non-zero status is always
consistent with that in the SCR register?
I can see that in fsl_ssi_hw_params() these bits in SCR are zeroed in
a one special case and in the second special case they are hardcoded
to SSI_SCR_I2S_MODE_NORMAL | SSI_SCR_NET, in both cases regardless of
what is currently in ssi->i2s_net.
You are right. I should update the i2s_net in hw_params() too. Thanks!
+ /* Check if the opposite stream is active */
+ aactive = ssi->streams & BIT(!tx);
I don't think that hardcoding an implicit assumption here that RX == 0,
TX == 1 is a good thing.
If in the future, for any reason, somebody changes values of these macros
this code will silently break.
I would instead change this line into something like
"aactive = ssi->streams & (tx ? BIT(RX) : BIT(TX));" or similar.
You have a point. I could add a "bool dir" to make it clear. Thanks.
On Tue, Jan 02, 2018 at 03:28:11PM -0800, Caleb Crome wrote:
tested this patch set on MX6 SSI against broonie for-next (4.15-rc5),
no problems.
Do I send a separate Tested-by for each patch, or just the 00/15 one?
Tested-by: Caleb Crome <redacted>
I will include your Tested-by to each patch in v2 unless there is
going to be a critical change suggested by the future reviews so
that we need another round of full testing. Thank you.
On Thu, Jan 4, 2018 at 11:48 AM, Nicolin Chen [off-list ref] wrote:
On Tue, Jan 02, 2018 at 03:28:11PM -0800, Caleb Crome wrote:
quoted
tested this patch set on MX6 SSI against broonie for-next (4.15-rc5),
no problems.
Do I send a separate Tested-by for each patch, or just the 00/15 one?
quoted
Tested-by: Caleb Crome <redacted>
I will include your Tested-by to each patch in v2 unless there is
going to be a critical change suggested by the future reviews so
that we need another round of full testing. Thank you
From: Maciej S. Szmigiero <hidden> Date: 2018-01-04 20:39:04
On 04.01.2018 20:07, Nicolin Chen wrote:
On Mon, Jan 01, 2018 at 04:17:20PM +0100, Maciej S. Szmigiero wrote:
quoted
quoted
AC97 configures some registers earlier to start a communication
with CODECs, so this patch moves those register settings to the
dai_probe() as well, along with other register configurations.
quoted
This patch breaks AC'97 CODEC probing.
Namely, the fsl_ssi DAI probe callback is only called after the AC'97
CODEC probe callback, so when you move SSI AC'97 startup to its DAI
probe callback it won't be done yet when the CODEC is probed (and this
requires a working AC'97 interface to successfully complete).
Hmm...What's the dependency here? Why is it required like this?
This patch moves enabling AC'97 communication (done by
fsl_ssi_setup_ac97() ) from SSI _platform device_ probe path to
SSI _DAI_ probe path.
However, it turns out that a SSI _DAI_ probe happens after a AC'97
CODEC probe (that is, ac97_soc_probe() in sound/soc/codecs/ac97.c).
And a AC'97 CODEC probe needs AC'97 communication to be working,
since it has to detect the CODEC model, configure it, etc.
I am okay to put everything to a separate fsl_ssi_hw_init() and
move it back to the platform probe() though.
This could be a solution - I assume that by "everything" in the above
sentence you mean (at least) enabling the AC'97 communication at the
SSI.
Maciej
On Thu, Jan 04, 2018 at 09:38:52PM +0100, Maciej S. Szmigiero wrote:
quoted
Hmm...What's the dependency here? Why is it required like this?
And a AC'97 CODEC probe needs AC'97 communication to be working,
since it has to detect the CODEC model, configure it, etc.
Okay. If the CODEC configurations depend on (or are done via)
the AC link, it has to be in this way then.
quoted
I am okay to put everything to a separate fsl_ssi_hw_init() and
move it back to the platform probe() though.
This could be a solution - I assume that by "everything" in the above
sentence you mean (at least) enabling the AC'97 communication at the
SSI.
All register configurations -- I was trying to move them to dai
probe() so a deferring probe or the platform remove() does not
need to revert these register configurations.
From: Mark Brown <broonie@kernel.org> Date: 2018-02-22 13:16:43
The patch
ASoC: fsl_ssi: Use snd_soc_init_dma_data instead
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
From 40f2563377006b14b94a4f5e9547b8e4498125af Mon Sep 17 00:00:00 2001
From: Nicolin Chen <nicoleotsuka@gmail.com>
Date: Mon, 12 Feb 2018 14:03:19 -0800
Subject: [PATCH] ASoC: fsl_ssi: Use snd_soc_init_dma_data instead
Since there is a helper function, use it to help readability.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
Tested-by: Caleb Crome <redacted>
Tested-by: Maciej S. Szmigiero <redacted>
Reviewed-by: Maciej S. Szmigiero <redacted>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
sound/soc/fsl/fsl_ssi.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
From: Mark Brown <broonie@kernel.org> Date: 2018-02-22 13:16:47
The patch
ASoC: fsl_ssi: Set xFEN0 and xFEN1 together
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
From 702d7965e402a8dcd88e964fd5bba6f5f159d625 Mon Sep 17 00:00:00 2001
From: Nicolin Chen <nicoleotsuka@gmail.com>
Date: Mon, 12 Feb 2018 14:03:18 -0800
Subject: [PATCH] ASoC: fsl_ssi: Set xFEN0 and xFEN1 together
It'd be safer to enable both FIFOs for TX or RX at the same time.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
Tested-by: Caleb Crome <redacted>
Tested-by: Maciej S. Szmigiero <redacted>
Reviewed-by: Maciej S. Szmigiero <redacted>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
sound/soc/fsl/fsl_ssi.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
From: Mark Brown <broonie@kernel.org> Date: 2018-02-22 13:16:50
The patch
ASoC: fsl_ssi: Clean up fsl_ssi_setup_regvals()
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
From 501bc1d70cf5ba8ccd9775ce987c90485034464e Mon Sep 17 00:00:00 2001
From: Nicolin Chen <nicoleotsuka@gmail.com>
Date: Mon, 12 Feb 2018 14:03:17 -0800
Subject: [PATCH] ASoC: fsl_ssi: Clean up fsl_ssi_setup_regvals()
This patch cleans fsl_ssi_setup_regvals() by following changes:
1) Moving DBG bits to the first lines.
2) Setting SSIE, RE/TE as default and cleaning it for AC97
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
Tested-by: Caleb Crome <redacted>
Tested-by: Maciej S. Szmigiero <redacted>
Reviewed-by: Maciej S. Szmigiero <redacted>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
sound/soc/fsl/fsl_ssi.c | 17 ++++++-----------
1 file changed, 6 insertions(+), 11 deletions(-)
@@ -580,18 +580,16 @@ static void fsl_ssi_setup_regvals(struct fsl_ssi *ssi){structfsl_ssi_regvals*vals=ssi->regvals;-vals[RX].sier=SSI_SIER_RFF0_EN;+vals[RX].sier=SSI_SIER_RFF0_EN|FSLSSI_SIER_DBG_RX_FLAGS;vals[RX].srcr=SSI_SRCR_RFEN0;-vals[RX].scr=0;-vals[TX].sier=SSI_SIER_TFE0_EN;+vals[RX].scr=SSI_SCR_SSIEN|SSI_SCR_RE;+vals[TX].sier=SSI_SIER_TFE0_EN|FSLSSI_SIER_DBG_TX_FLAGS;vals[TX].stcr=SSI_STCR_TFEN0;-vals[TX].scr=0;+vals[TX].scr=SSI_SCR_SSIEN|SSI_SCR_TE;/* AC97 has already enabled SSIEN, RE and TE, so ignore them */-if(!fsl_ssi_is_ac97(ssi)){-vals[RX].scr=SSI_SCR_SSIEN|SSI_SCR_RE;-vals[TX].scr=SSI_SCR_SSIEN|SSI_SCR_TE;-}+if(fsl_ssi_is_ac97(ssi))+vals[RX].scr=vals[TX].scr=0;if(ssi->use_dma){vals[RX].sier|=SSI_SIER_RDMAE;
From: Mark Brown <broonie@kernel.org> Date: 2018-02-22 13:16:52
The patch
ASoC: fsl_ssi: Add DAIFMT define for AC97
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
From b6c93f7f60a0d0b61c1fce2872b9d4f7263d6ec2 Mon Sep 17 00:00:00 2001
From: Nicolin Chen <nicoleotsuka@gmail.com>
Date: Mon, 12 Feb 2018 14:03:16 -0800
Subject: [PATCH] ASoC: fsl_ssi: Add DAIFMT define for AC97
The _fsl_ssi_set_dai_fmt() bypasses an undefined format for AC97
mode. However, it's not really necessary if AC97 has its complete
format defined.
So this patch adds a DAIFMT macro of complete format including a
clock direction and polarity.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
Tested-by: Caleb Crome <redacted>
Tested-by: Maciej S. Szmigiero <redacted>
Reviewed-by: Maciej S. Szmigiero <redacted>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
sound/soc/fsl/fsl_ssi.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
From: Mark Brown <broonie@kernel.org> Date: 2018-02-22 13:17:18
The patch
ASoC: fsl_ssi: Clean up set_dai_tdm_slot()
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
From 09947634829ccc5568a80ac02c3395a8b77276c1 Mon Sep 17 00:00:00 2001
From: Nicolin Chen <nicoleotsuka@gmail.com>
Date: Mon, 12 Feb 2018 14:03:11 -0800
Subject: [PATCH] ASoC: fsl_ssi: Clean up set_dai_tdm_slot()
This patch replaces the register read with ssi->i2s_net for
simplification. It also removes masking SSIEN from scr value
since it's handled later by regmap_update_bits() to set this
scr value back.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
Tested-by: Caleb Crome <redacted>
Tested-by: Maciej S. Szmigiero <redacted>
Reviewed-by: Maciej S. Szmigiero <redacted>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
sound/soc/fsl/fsl_ssi.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
@@ -1055,9 +1055,7 @@ static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,}/* The slot number should be >= 2 if using Network mode or I2S mode */-regmap_read(regs,REG_SSI_SCR,&val);-val&=SSI_SCR_I2S_MODE_MASK|SSI_SCR_NET;-if(val&&slots<2){+if(ssi->i2s_net&&slots<2){dev_err(dai->dev,"slot number should be >= 2 in I2S or NET\n");return-EINVAL;}
@@ -1067,9 +1065,8 @@ static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,regmap_update_bits(regs,REG_SSI_SRCCR,SSI_SxCCR_DC_MASK,SSI_SxCCR_DC(slots));-/* Save SSIEN bit of the SCR register */+/* Save the SCR register value */regmap_read(regs,REG_SSI_SCR,&val);-val&=SSI_SCR_SSIEN;/* Temporarily enable SSI to allow SxMSKs to be configurable */regmap_update_bits(regs,REG_SSI_SCR,SSI_SCR_SSIEN,SSI_SCR_SSIEN);