@@ -53,6 +53,8 @@ struct fsl_xcvr {
5353 struct snd_aes_iec958 rx_iec958 ;
5454 struct snd_aes_iec958 tx_iec958 ;
5555 u8 cap_ds [FSL_XCVR_CAPDS_SIZE ];
56+ struct work_struct work_rst ;
57+ spinlock_t lock ; /* Protect hw_reset and trigger */
5658};
5759
5860static const struct fsl_xcvr_pll_conf {
@@ -663,7 +665,10 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
663665{
664666 struct fsl_xcvr * xcvr = snd_soc_dai_get_drvdata (dai );
665667 bool tx = substream -> stream == SNDRV_PCM_STREAM_PLAYBACK ;
666- int ret ;
668+ unsigned long lock_flags ;
669+ int ret = 0 ;
670+
671+ spin_lock_irqsave (& xcvr -> lock , lock_flags );
667672
668673 switch (cmd ) {
669674 case SNDRV_PCM_TRIGGER_START :
@@ -675,7 +680,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
675680 FSL_XCVR_EXT_CTRL_DPTH_RESET (tx ));
676681 if (ret < 0 ) {
677682 dev_err (dai -> dev , "Failed to set DPATH RESET: %d\n" , ret );
678- return ret ;
683+ goto release_lock ;
679684 }
680685
681686 if (tx ) {
@@ -687,7 +692,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
687692 FSL_XCVR_ISR_CMDC_TX_EN );
688693 if (ret < 0 ) {
689694 dev_err (dai -> dev , "err updating isr %d\n" , ret );
690- return ret ;
695+ goto release_lock ;
691696 }
692697 fallthrough ;
693698 case FSL_XCVR_MODE_SPDIF :
@@ -696,7 +701,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
696701 FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX );
697702 if (ret < 0 ) {
698703 dev_err (dai -> dev , "Failed to start DATA_TX: %d\n" , ret );
699- return ret ;
704+ goto release_lock ;
700705 }
701706 break ;
702707 }
@@ -707,14 +712,14 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
707712 FSL_XCVR_EXT_CTRL_DMA_DIS (tx ), 0 );
708713 if (ret < 0 ) {
709714 dev_err (dai -> dev , "Failed to enable DMA: %d\n" , ret );
710- return ret ;
715+ goto release_lock ;
711716 }
712717
713718 ret = regmap_update_bits (xcvr -> regmap , FSL_XCVR_EXT_IER0 ,
714719 FSL_XCVR_IRQ_EARC_ALL , FSL_XCVR_IRQ_EARC_ALL );
715720 if (ret < 0 ) {
716721 dev_err (dai -> dev , "Error while setting IER0: %d\n" , ret );
717- return ret ;
722+ goto release_lock ;
718723 }
719724
720725 /* clear DPATH RESET */
@@ -723,7 +728,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
723728 0 );
724729 if (ret < 0 ) {
725730 dev_err (dai -> dev , "Failed to clear DPATH RESET: %d\n" , ret );
726- return ret ;
731+ goto release_lock ;
727732 }
728733
729734 break ;
@@ -736,14 +741,14 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
736741 FSL_XCVR_EXT_CTRL_DMA_DIS (tx ));
737742 if (ret < 0 ) {
738743 dev_err (dai -> dev , "Failed to disable DMA: %d\n" , ret );
739- return ret ;
744+ goto release_lock ;
740745 }
741746
742747 ret = regmap_update_bits (xcvr -> regmap , FSL_XCVR_EXT_IER0 ,
743748 FSL_XCVR_IRQ_EARC_ALL , 0 );
744749 if (ret < 0 ) {
745750 dev_err (dai -> dev , "Failed to clear IER0: %d\n" , ret );
746- return ret ;
751+ goto release_lock ;
747752 }
748753
749754 if (tx ) {
@@ -754,7 +759,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
754759 FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX );
755760 if (ret < 0 ) {
756761 dev_err (dai -> dev , "Failed to stop DATA_TX: %d\n" , ret );
757- return ret ;
762+ goto release_lock ;
758763 }
759764 if (xcvr -> soc_data -> spdif_only )
760765 break ;
@@ -768,17 +773,20 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
768773 if (ret < 0 ) {
769774 dev_err (dai -> dev ,
770775 "Err updating ISR %d\n" , ret );
771- return ret ;
776+ goto release_lock ;
772777 }
773778 break ;
774779 }
775780 }
776781 break ;
777782 default :
778- return - EINVAL ;
783+ ret = - EINVAL ;
784+ break ;
779785 }
780786
781- return 0 ;
787+ release_lock :
788+ spin_unlock_irqrestore (& xcvr -> lock , lock_flags );
789+ return ret ;
782790}
783791
784792static int fsl_xcvr_load_firmware (struct fsl_xcvr * xcvr )
@@ -1198,6 +1206,34 @@ static const struct regmap_config fsl_xcvr_regmap_cfg = {
11981206 .cache_type = REGCACHE_FLAT ,
11991207};
12001208
1209+ static void reset_rx_work (struct work_struct * work )
1210+ {
1211+ struct fsl_xcvr * xcvr = container_of (work , struct fsl_xcvr , work_rst );
1212+ struct device * dev = & xcvr -> pdev -> dev ;
1213+ unsigned long lock_flags ;
1214+ u32 ext_ctrl ;
1215+
1216+ dev_dbg (dev , "reset rx path\n" );
1217+ spin_lock_irqsave (& xcvr -> lock , lock_flags );
1218+ regmap_read (xcvr -> regmap , FSL_XCVR_EXT_CTRL , & ext_ctrl );
1219+
1220+ if (!(ext_ctrl & FSL_XCVR_EXT_CTRL_DMA_RD_DIS )) {
1221+ regmap_update_bits (xcvr -> regmap , FSL_XCVR_EXT_CTRL ,
1222+ FSL_XCVR_EXT_CTRL_DMA_RD_DIS ,
1223+ FSL_XCVR_EXT_CTRL_DMA_RD_DIS );
1224+ regmap_update_bits (xcvr -> regmap , FSL_XCVR_EXT_CTRL ,
1225+ FSL_XCVR_EXT_CTRL_RX_DPTH_RESET ,
1226+ FSL_XCVR_EXT_CTRL_RX_DPTH_RESET );
1227+ regmap_update_bits (xcvr -> regmap , FSL_XCVR_EXT_CTRL ,
1228+ FSL_XCVR_EXT_CTRL_DMA_RD_DIS ,
1229+ 0 );
1230+ regmap_update_bits (xcvr -> regmap , FSL_XCVR_EXT_CTRL ,
1231+ FSL_XCVR_EXT_CTRL_RX_DPTH_RESET ,
1232+ 0 );
1233+ }
1234+ spin_unlock_irqrestore (& xcvr -> lock , lock_flags );
1235+ }
1236+
12011237static irqreturn_t irq0_isr (int irq , void * devid )
12021238{
12031239 struct fsl_xcvr * xcvr = (struct fsl_xcvr * )devid ;
@@ -1265,6 +1301,33 @@ static irqreturn_t irq0_isr(int irq, void *devid)
12651301 dev_dbg (dev , "DMA write request\n" );
12661302 isr_clr |= FSL_XCVR_IRQ_DMA_WR_REQ ;
12671303 }
1304+ if (isr & FSL_XCVR_IRQ_CMDC_STATUS_UPD ) {
1305+ dev_dbg (dev , "CMDC status update\n" );
1306+ isr_clr |= FSL_XCVR_IRQ_CMDC_STATUS_UPD ;
1307+ }
1308+ if (isr & FSL_XCVR_IRQ_PREAMBLE_MISMATCH ) {
1309+ dev_dbg (dev , "Preamble mismatch\n" );
1310+ isr_clr |= FSL_XCVR_IRQ_PREAMBLE_MISMATCH ;
1311+ }
1312+ if (isr & FSL_XCVR_IRQ_UNEXP_PRE_REC ) {
1313+ dev_dbg (dev , "Unexpected preamble received\n" );
1314+ isr_clr |= FSL_XCVR_IRQ_UNEXP_PRE_REC ;
1315+ }
1316+ if (isr & FSL_XCVR_IRQ_M_W_PRE_MISMATCH ) {
1317+ dev_dbg (dev , "M/W preamble mismatch\n" );
1318+ isr_clr |= FSL_XCVR_IRQ_M_W_PRE_MISMATCH ;
1319+ }
1320+ if (isr & FSL_XCVR_IRQ_B_PRE_MISMATCH ) {
1321+ dev_dbg (dev , "B preamble mismatch\n" );
1322+ isr_clr |= FSL_XCVR_IRQ_B_PRE_MISMATCH ;
1323+ }
1324+
1325+ if (isr & (FSL_XCVR_IRQ_PREAMBLE_MISMATCH |
1326+ FSL_XCVR_IRQ_UNEXP_PRE_REC |
1327+ FSL_XCVR_IRQ_M_W_PRE_MISMATCH |
1328+ FSL_XCVR_IRQ_B_PRE_MISMATCH )) {
1329+ schedule_work (& xcvr -> work_rst );
1330+ }
12681331
12691332 if (isr_clr ) {
12701333 regmap_write (regmap , FSL_XCVR_EXT_ISR_CLR , isr_clr );
@@ -1411,11 +1474,16 @@ static int fsl_xcvr_probe(struct platform_device *pdev)
14111474 fsl_xcvr_comp .name );
14121475 }
14131476
1477+ INIT_WORK (& xcvr -> work_rst , reset_rx_work );
1478+ spin_lock_init (& xcvr -> lock );
14141479 return ret ;
14151480}
14161481
14171482static void fsl_xcvr_remove (struct platform_device * pdev )
14181483{
1484+ struct fsl_xcvr * xcvr = dev_get_drvdata (& pdev -> dev );
1485+
1486+ cancel_work_sync (& xcvr -> work_rst );
14191487 pm_runtime_disable (& pdev -> dev );
14201488}
14211489
0 commit comments