3232 * @extalclk: esai clock source to derive HCK, SCK and FS
3333 * @fsysclk: system clock source to derive HCK, SCK and FS
3434 * @spbaclk: SPBA clock (optional, depending on SoC design)
35+ * @task: tasklet to handle the reset operation
3536 * @fifo_depth: depth of tx/rx FIFO
3637 * @slot_width: width of each DAI slot
3738 * @slots: number of slots
4243 * @sck_div: if using PSR/PM dividers for SCKx clock
4344 * @slave_mode: if fully using DAI slave mode
4445 * @synchronous: if using tx/rx synchronous mode
46+ * @reset_at_xrun: flags for enable reset operaton
4547 * @name: driver name
4648 */
4749struct fsl_esai {
@@ -53,6 +55,7 @@ struct fsl_esai {
5355 struct clk * extalclk ;
5456 struct clk * fsysclk ;
5557 struct clk * spbaclk ;
58+ struct tasklet_struct task ;
5659 u32 fifo_depth ;
5760 u32 slot_width ;
5861 u32 slots ;
@@ -65,6 +68,7 @@ struct fsl_esai {
6568 bool sck_div [2 ];
6669 bool slave_mode ;
6770 bool synchronous ;
71+ bool reset_at_xrun ;
6872 char name [32 ];
6973};
7074
@@ -73,8 +77,16 @@ static irqreturn_t esai_isr(int irq, void *devid)
7377 struct fsl_esai * esai_priv = (struct fsl_esai * )devid ;
7478 struct platform_device * pdev = esai_priv -> pdev ;
7579 u32 esr ;
80+ u32 saisr ;
7681
7782 regmap_read (esai_priv -> regmap , REG_ESAI_ESR , & esr );
83+ regmap_read (esai_priv -> regmap , REG_ESAI_SAISR , & saisr );
84+
85+ if ((saisr & (ESAI_SAISR_TUE | ESAI_SAISR_ROE )) &&
86+ esai_priv -> reset_at_xrun ) {
87+ dev_dbg (& pdev -> dev , "reset module for xrun\n" );
88+ tasklet_schedule (& esai_priv -> task );
89+ }
7890
7991 if (esr & ESAI_ESR_TINIT_MASK )
8092 dev_dbg (& pdev -> dev , "isr: Transmission Initialized\n" );
@@ -635,10 +647,17 @@ static void fsl_esai_trigger_start(struct fsl_esai *esai_priv, bool tx)
635647 ESAI_xSMB_xS_MASK , ESAI_xSMB_xS (mask ));
636648 regmap_update_bits (esai_priv -> regmap , REG_ESAI_xSMA (tx ),
637649 ESAI_xSMA_xS_MASK , ESAI_xSMA_xS (mask ));
650+
651+ /* Enable Exception interrupt */
652+ regmap_update_bits (esai_priv -> regmap , REG_ESAI_xCR (tx ),
653+ ESAI_xCR_xEIE_MASK , ESAI_xCR_xEIE );
638654}
639655
640656static void fsl_esai_trigger_stop (struct fsl_esai * esai_priv , bool tx )
641657{
658+ regmap_update_bits (esai_priv -> regmap , REG_ESAI_xCR (tx ),
659+ ESAI_xCR_xEIE_MASK , 0 );
660+
642661 regmap_update_bits (esai_priv -> regmap , REG_ESAI_xCR (tx ),
643662 tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK , 0 );
644663 regmap_update_bits (esai_priv -> regmap , REG_ESAI_xSMA (tx ),
@@ -653,6 +672,51 @@ static void fsl_esai_trigger_stop(struct fsl_esai *esai_priv, bool tx)
653672 ESAI_xFCR_xFR , 0 );
654673}
655674
675+ static void fsl_esai_hw_reset (unsigned long arg )
676+ {
677+ struct fsl_esai * esai_priv = (struct fsl_esai * )arg ;
678+ bool tx = true, rx = false, enabled [2 ];
679+ u32 tfcr , rfcr ;
680+
681+ /* Save the registers */
682+ regmap_read (esai_priv -> regmap , REG_ESAI_TFCR , & tfcr );
683+ regmap_read (esai_priv -> regmap , REG_ESAI_RFCR , & rfcr );
684+ enabled [tx ] = tfcr & ESAI_xFCR_xFEN ;
685+ enabled [rx ] = rfcr & ESAI_xFCR_xFEN ;
686+
687+ /* Stop the tx & rx */
688+ fsl_esai_trigger_stop (esai_priv , tx );
689+ fsl_esai_trigger_stop (esai_priv , rx );
690+
691+ /* Reset the esai, and ignore return value */
692+ fsl_esai_hw_init (esai_priv );
693+
694+ /* Enforce ESAI personal resets for both TX and RX */
695+ regmap_update_bits (esai_priv -> regmap , REG_ESAI_TCR ,
696+ ESAI_xCR_xPR_MASK , ESAI_xCR_xPR );
697+ regmap_update_bits (esai_priv -> regmap , REG_ESAI_RCR ,
698+ ESAI_xCR_xPR_MASK , ESAI_xCR_xPR );
699+
700+ /* Restore registers by regcache_sync, and ignore return value */
701+ fsl_esai_register_restore (esai_priv );
702+
703+ /* Remove ESAI personal resets by configuring PCRC and PRRC also */
704+ regmap_update_bits (esai_priv -> regmap , REG_ESAI_TCR ,
705+ ESAI_xCR_xPR_MASK , 0 );
706+ regmap_update_bits (esai_priv -> regmap , REG_ESAI_RCR ,
707+ ESAI_xCR_xPR_MASK , 0 );
708+ regmap_update_bits (esai_priv -> regmap , REG_ESAI_PRRC ,
709+ ESAI_PRRC_PDC_MASK , ESAI_PRRC_PDC (ESAI_GPIO ));
710+ regmap_update_bits (esai_priv -> regmap , REG_ESAI_PCRC ,
711+ ESAI_PCRC_PC_MASK , ESAI_PCRC_PC (ESAI_GPIO ));
712+
713+ /* Restart tx / rx, if they already enabled */
714+ if (enabled [tx ])
715+ fsl_esai_trigger_start (esai_priv , tx );
716+ if (enabled [rx ])
717+ fsl_esai_trigger_start (esai_priv , rx );
718+ }
719+
656720static int fsl_esai_trigger (struct snd_pcm_substream * substream , int cmd ,
657721 struct snd_soc_dai * dai )
658722{
@@ -857,6 +921,10 @@ static int fsl_esai_probe(struct platform_device *pdev)
857921 esai_priv -> pdev = pdev ;
858922 snprintf (esai_priv -> name , sizeof (esai_priv -> name ), "%pOFn" , np );
859923
924+ if (of_device_is_compatible (np , "fsl,vf610-esai" ) ||
925+ of_device_is_compatible (np , "fsl,imx35-esai" ))
926+ esai_priv -> reset_at_xrun = true;
927+
860928 /* Get the addresses and IRQ */
861929 res = platform_get_resource (pdev , IORESOURCE_MEM , 0 );
862930 regs = devm_ioremap_resource (& pdev -> dev , res );
@@ -956,6 +1024,9 @@ static int fsl_esai_probe(struct platform_device *pdev)
9561024 return ret ;
9571025 }
9581026
1027+ tasklet_init (& esai_priv -> task , fsl_esai_hw_reset ,
1028+ (unsigned long )esai_priv );
1029+
9591030 pm_runtime_enable (& pdev -> dev );
9601031
9611032 regcache_cache_only (esai_priv -> regmap , true);
@@ -969,7 +1040,10 @@ static int fsl_esai_probe(struct platform_device *pdev)
9691040
9701041static int fsl_esai_remove (struct platform_device * pdev )
9711042{
1043+ struct fsl_esai * esai_priv = platform_get_drvdata (pdev );
1044+
9721045 pm_runtime_disable (& pdev -> dev );
1046+ tasklet_kill (& esai_priv -> task );
9731047
9741048 return 0 ;
9751049}
0 commit comments