@@ -461,9 +461,12 @@ static void cs35l41_remove_dsp(struct cs35l41_hda *cs35l41)
461461 struct cs_dsp * dsp = & cs35l41 -> cs_dsp ;
462462
463463 cancel_work_sync (& cs35l41 -> fw_load_work );
464+
465+ mutex_lock (& cs35l41 -> fw_mutex );
464466 cs35l41_shutdown_dsp (cs35l41 );
465467 cs_dsp_remove (dsp );
466468 cs35l41 -> halo_initialized = false;
469+ mutex_unlock (& cs35l41 -> fw_mutex );
467470}
468471
469472/* Protection release cycle to get the speaker out of Safe-Mode */
@@ -570,45 +573,148 @@ static int cs35l41_hda_channel_map(struct device *dev, unsigned int tx_num, unsi
570573 rx_slot );
571574}
572575
576+ static void cs35l41_ready_for_reset (struct cs35l41_hda * cs35l41 )
577+ {
578+ mutex_lock (& cs35l41 -> fw_mutex );
579+ if (cs35l41 -> firmware_running ) {
580+
581+ regcache_cache_only (cs35l41 -> regmap , false);
582+
583+ cs35l41_exit_hibernate (cs35l41 -> dev , cs35l41 -> regmap );
584+ cs35l41_shutdown_dsp (cs35l41 );
585+ cs35l41_safe_reset (cs35l41 -> regmap , cs35l41 -> hw_cfg .bst_type );
586+
587+ regcache_cache_only (cs35l41 -> regmap , true);
588+ regcache_mark_dirty (cs35l41 -> regmap );
589+ }
590+ mutex_unlock (& cs35l41 -> fw_mutex );
591+ }
592+
593+ static int cs35l41_system_suspend (struct device * dev )
594+ {
595+ struct cs35l41_hda * cs35l41 = dev_get_drvdata (dev );
596+ int ret ;
597+
598+ dev_dbg (cs35l41 -> dev , "System Suspend\n" );
599+
600+ if (cs35l41 -> hw_cfg .bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH ) {
601+ dev_err (cs35l41 -> dev , "System Suspend not supported\n" );
602+ return - EINVAL ;
603+ }
604+
605+ ret = pm_runtime_force_suspend (dev );
606+ if (ret )
607+ return ret ;
608+
609+ /* Shutdown DSP before system suspend */
610+ cs35l41_ready_for_reset (cs35l41 );
611+
612+ /*
613+ * Reset GPIO may be shared, so cannot reset here.
614+ * However beyond this point, amps may be powered down.
615+ */
616+ return 0 ;
617+ }
618+
619+ static int cs35l41_system_resume (struct device * dev )
620+ {
621+ struct cs35l41_hda * cs35l41 = dev_get_drvdata (dev );
622+ int ret ;
623+
624+ dev_dbg (cs35l41 -> dev , "System Resume\n" );
625+
626+ if (cs35l41 -> hw_cfg .bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH ) {
627+ dev_err (cs35l41 -> dev , "System Resume not supported\n" );
628+ return - EINVAL ;
629+ }
630+
631+ if (cs35l41 -> reset_gpio ) {
632+ usleep_range (2000 , 2100 );
633+ gpiod_set_value_cansleep (cs35l41 -> reset_gpio , 1 );
634+ }
635+
636+ usleep_range (2000 , 2100 );
637+
638+ ret = pm_runtime_force_resume (dev );
639+
640+ mutex_lock (& cs35l41 -> fw_mutex );
641+ if (!ret && cs35l41 -> request_fw_load && !cs35l41 -> fw_request_ongoing ) {
642+ cs35l41 -> fw_request_ongoing = true;
643+ schedule_work (& cs35l41 -> fw_load_work );
644+ }
645+ mutex_unlock (& cs35l41 -> fw_mutex );
646+
647+ return ret ;
648+ }
649+
573650static int cs35l41_runtime_suspend (struct device * dev )
574651{
575652 struct cs35l41_hda * cs35l41 = dev_get_drvdata (dev );
653+ int ret = 0 ;
576654
577- dev_dbg (cs35l41 -> dev , "Suspend\n" );
655+ dev_dbg (cs35l41 -> dev , "Runtime Suspend\n" );
578656
579- if (!cs35l41 -> firmware_running )
657+ if (cs35l41 -> hw_cfg .bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH ) {
658+ dev_dbg (cs35l41 -> dev , "Runtime Suspend not supported\n" );
580659 return 0 ;
660+ }
581661
582- if (cs35l41_enter_hibernate (cs35l41 -> dev , cs35l41 -> regmap , cs35l41 -> hw_cfg .bst_type ) < 0 )
583- return 0 ;
662+ mutex_lock (& cs35l41 -> fw_mutex );
663+
664+ if (cs35l41 -> playback_started ) {
665+ regmap_multi_reg_write (cs35l41 -> regmap , cs35l41_hda_mute ,
666+ ARRAY_SIZE (cs35l41_hda_mute ));
667+ cs35l41_global_enable (cs35l41 -> regmap , cs35l41 -> hw_cfg .bst_type , 0 );
668+ regmap_update_bits (cs35l41 -> regmap , CS35L41_PWR_CTRL2 ,
669+ CS35L41_AMP_EN_MASK , 0 << CS35L41_AMP_EN_SHIFT );
670+ if (cs35l41 -> hw_cfg .bst_type == CS35L41_EXT_BOOST )
671+ regmap_write (cs35l41 -> regmap , CS35L41_GPIO1_CTRL1 , 0x00000001 );
672+ regmap_update_bits (cs35l41 -> regmap , CS35L41_PWR_CTRL2 ,
673+ CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK ,
674+ 0 << CS35L41_VMON_EN_SHIFT | 0 << CS35L41_IMON_EN_SHIFT );
675+ cs35l41 -> playback_started = false;
676+ }
677+
678+ if (cs35l41 -> firmware_running ) {
679+ ret = cs35l41_enter_hibernate (cs35l41 -> dev , cs35l41 -> regmap ,
680+ cs35l41 -> hw_cfg .bst_type );
681+ if (ret )
682+ goto err ;
683+ } else {
684+ cs35l41_safe_reset (cs35l41 -> regmap , cs35l41 -> hw_cfg .bst_type );
685+ }
584686
585687 regcache_cache_only (cs35l41 -> regmap , true);
586688 regcache_mark_dirty (cs35l41 -> regmap );
587689
588- return 0 ;
690+ err :
691+ mutex_unlock (& cs35l41 -> fw_mutex );
692+
693+ return ret ;
589694}
590695
591696static int cs35l41_runtime_resume (struct device * dev )
592697{
593698 struct cs35l41_hda * cs35l41 = dev_get_drvdata (dev );
594- int ret ;
699+ int ret = 0 ;
595700
596- dev_dbg (cs35l41 -> dev , "Resume. \n" );
701+ dev_dbg (cs35l41 -> dev , "Runtime Resume\n" );
597702
598703 if (cs35l41 -> hw_cfg .bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH ) {
599- dev_dbg (cs35l41 -> dev , "System does not support Resume \n" );
704+ dev_dbg (cs35l41 -> dev , "Runtime Resume not supported \n" );
600705 return 0 ;
601706 }
602707
603- if (!cs35l41 -> firmware_running )
604- return 0 ;
708+ mutex_lock (& cs35l41 -> fw_mutex );
605709
606710 regcache_cache_only (cs35l41 -> regmap , false);
607711
608- ret = cs35l41_exit_hibernate (cs35l41 -> dev , cs35l41 -> regmap );
609- if (ret ) {
610- regcache_cache_only (cs35l41 -> regmap , true);
611- return ret ;
712+ if (cs35l41 -> firmware_running ) {
713+ ret = cs35l41_exit_hibernate (cs35l41 -> dev , cs35l41 -> regmap );
714+ if (ret ) {
715+ dev_warn (cs35l41 -> dev , "Unable to exit Hibernate." );
716+ goto err ;
717+ }
612718 }
613719
614720 /* Test key needs to be unlocked to allow the OTP settings to re-apply */
@@ -617,13 +723,16 @@ static int cs35l41_runtime_resume(struct device *dev)
617723 cs35l41_test_key_lock (cs35l41 -> dev , cs35l41 -> regmap );
618724 if (ret ) {
619725 dev_err (cs35l41 -> dev , "Failed to restore register cache: %d\n" , ret );
620- return ret ;
726+ goto err ;
621727 }
622728
623729 if (cs35l41 -> hw_cfg .bst_type == CS35L41_EXT_BOOST )
624730 cs35l41_init_boost (cs35l41 -> dev , cs35l41 -> regmap , & cs35l41 -> hw_cfg );
625731
626- return 0 ;
732+ err :
733+ mutex_unlock (& cs35l41 -> fw_mutex );
734+
735+ return ret ;
627736}
628737
629738static int cs35l41_smart_amp (struct cs35l41_hda * cs35l41 )
@@ -673,8 +782,6 @@ static int cs35l41_smart_amp(struct cs35l41_hda *cs35l41)
673782
674783static void cs35l41_load_firmware (struct cs35l41_hda * cs35l41 , bool load )
675784{
676- pm_runtime_get_sync (cs35l41 -> dev );
677-
678785 if (cs35l41 -> firmware_running && !load ) {
679786 dev_dbg (cs35l41 -> dev , "Unloading Firmware\n" );
680787 cs35l41_shutdown_dsp (cs35l41 );
@@ -684,9 +791,6 @@ static void cs35l41_load_firmware(struct cs35l41_hda *cs35l41, bool load)
684791 } else {
685792 dev_dbg (cs35l41 -> dev , "Unable to Load firmware.\n" );
686793 }
687-
688- pm_runtime_mark_last_busy (cs35l41 -> dev );
689- pm_runtime_put_autosuspend (cs35l41 -> dev );
690794}
691795
692796static int cs35l41_fw_load_ctl_get (struct snd_kcontrol * kcontrol ,
@@ -702,16 +806,21 @@ static void cs35l41_fw_load_work(struct work_struct *work)
702806{
703807 struct cs35l41_hda * cs35l41 = container_of (work , struct cs35l41_hda , fw_load_work );
704808
809+ pm_runtime_get_sync (cs35l41 -> dev );
810+
705811 mutex_lock (& cs35l41 -> fw_mutex );
706812
707813 /* Recheck if playback is ongoing, mutex will block playback during firmware loading */
708814 if (cs35l41 -> playback_started )
709- dev_err (cs35l41 -> dev , "Cannot Load/Unload firmware during Playback\n" );
815+ dev_err (cs35l41 -> dev , "Cannot Load/Unload firmware during Playback. Retrying... \n" );
710816 else
711817 cs35l41_load_firmware (cs35l41 , cs35l41 -> request_fw_load );
712818
713819 cs35l41 -> fw_request_ongoing = false;
714820 mutex_unlock (& cs35l41 -> fw_mutex );
821+
822+ pm_runtime_mark_last_busy (cs35l41 -> dev );
823+ pm_runtime_put_autosuspend (cs35l41 -> dev );
715824}
716825
717826static int cs35l41_fw_load_ctl_put (struct snd_kcontrol * kcontrol ,
@@ -835,6 +944,8 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas
835944
836945 pm_runtime_get_sync (dev );
837946
947+ mutex_lock (& cs35l41 -> fw_mutex );
948+
838949 comps -> dev = dev ;
839950 if (!cs35l41 -> acpi_subsystem_id )
840951 cs35l41 -> acpi_subsystem_id = kasprintf (GFP_KERNEL , "%.8x" ,
@@ -847,10 +958,8 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas
847958 if (firmware_autostart ) {
848959 dev_dbg (cs35l41 -> dev , "Firmware Autostart.\n" );
849960 cs35l41 -> request_fw_load = true;
850- mutex_lock (& cs35l41 -> fw_mutex );
851961 if (cs35l41_smart_amp (cs35l41 ) < 0 )
852962 dev_warn (cs35l41 -> dev , "Cannot Run Firmware, reverting to dsp bypass...\n" );
853- mutex_unlock (& cs35l41 -> fw_mutex );
854963 } else {
855964 dev_dbg (cs35l41 -> dev , "Firmware Autostart is disabled.\n" );
856965 }
@@ -859,6 +968,8 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas
859968
860969 comps -> playback_hook = cs35l41_hda_playback_hook ;
861970
971+ mutex_unlock (& cs35l41 -> fw_mutex );
972+
862973 pm_runtime_mark_last_busy (dev );
863974 pm_runtime_put_autosuspend (dev );
864975
@@ -1426,6 +1537,7 @@ EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, SND_HDA_SCODEC_CS35L41);
14261537
14271538const struct dev_pm_ops cs35l41_hda_pm_ops = {
14281539 RUNTIME_PM_OPS (cs35l41_runtime_suspend , cs35l41_runtime_resume , NULL )
1540+ SYSTEM_SLEEP_PM_OPS (cs35l41_system_suspend , cs35l41_system_resume )
14291541};
14301542EXPORT_SYMBOL_NS_GPL (cs35l41_hda_pm_ops , SND_HDA_SCODEC_CS35L41 );
14311543
0 commit comments