1313#include <linux/module.h>
1414#include <linux/moduleparam.h>
1515#include <linux/of_device.h>
16+ #include <linux/pm_runtime.h>
1617#include <linux/property.h>
1718#include <sound/initval.h>
1819#include <sound/pcm.h>
@@ -187,8 +188,14 @@ static int cs35l41_dsp_preload_ev(struct snd_soc_dapm_widget *w,
187188
188189 switch (event ) {
189190 case SND_SOC_DAPM_PRE_PMU :
191+ if (cs35l41 -> dsp .cs_dsp .booted )
192+ return 0 ;
193+
190194 return wm_adsp_early_event (w , kcontrol , event );
191195 case SND_SOC_DAPM_PRE_PMD :
196+ if (cs35l41 -> dsp .preloaded )
197+ return 0 ;
198+
192199 if (cs35l41 -> dsp .cs_dsp .running ) {
193200 ret = wm_adsp_event (w , kcontrol , event );
194201 if (ret )
@@ -209,6 +216,7 @@ static bool cs35l41_check_cspl_mbox_sts(enum cs35l41_cspl_mbox_cmd cmd,
209216 case CSPL_MBOX_CMD_UNKNOWN_CMD :
210217 return true;
211218 case CSPL_MBOX_CMD_PAUSE :
219+ case CSPL_MBOX_CMD_OUT_OF_HIBERNATE :
212220 return (sts == CSPL_MBOX_STS_PAUSED );
213221 case CSPL_MBOX_CMD_RESUME :
214222 return (sts == CSPL_MBOX_STS_RUNNING );
@@ -230,7 +238,8 @@ static int cs35l41_set_cspl_mbox_cmd(struct cs35l41_private *cs35l41,
230238 // Set mailbox cmd
231239 ret = regmap_write (cs35l41 -> regmap , CS35L41_DSP_VIRT1_MBOX_1 , cmd );
232240 if (ret < 0 ) {
233- dev_err (cs35l41 -> dev , "Failed to write MBOX: %d\n" , ret );
241+ if (cmd != CSPL_MBOX_CMD_OUT_OF_HIBERNATE )
242+ dev_err (cs35l41 -> dev , "Failed to write MBOX: %d\n" , ret );
234243 return ret ;
235244 }
236245
@@ -413,6 +422,8 @@ static irqreturn_t cs35l41_irq(int irq, void *data)
413422 int ret = IRQ_NONE ;
414423 unsigned int i ;
415424
425+ pm_runtime_get_sync (cs35l41 -> dev );
426+
416427 for (i = 0 ; i < ARRAY_SIZE (status ); i ++ ) {
417428 regmap_read (cs35l41 -> regmap ,
418429 CS35L41_IRQ1_STATUS1 + (i * CS35L41_REGSTRIDE ),
@@ -425,7 +436,7 @@ static irqreturn_t cs35l41_irq(int irq, void *data)
425436 /* Check to see if unmasked bits are active */
426437 if (!(status [0 ] & ~masks [0 ]) && !(status [1 ] & ~masks [1 ]) &&
427438 !(status [2 ] & ~masks [2 ]) && !(status [3 ] & ~masks [3 ]))
428- return IRQ_NONE ;
439+ goto done ;
429440
430441 if (status [3 ] & CS35L41_OTP_BOOT_DONE ) {
431442 regmap_update_bits (cs35l41 -> regmap , CS35L41_IRQ1_MASK4 ,
@@ -530,6 +541,10 @@ static irqreturn_t cs35l41_irq(int irq, void *data)
530541 ret = IRQ_HANDLED ;
531542 }
532543
544+ done :
545+ pm_runtime_mark_last_busy (cs35l41 -> dev );
546+ pm_runtime_put_autosuspend (cs35l41 -> dev );
547+
533548 return ret ;
534549}
535550
@@ -1180,6 +1195,7 @@ static int cs35l41_dsp_init(struct cs35l41_private *cs35l41)
11801195 dsp -> cs_dsp .type = WMFW_HALO ;
11811196 dsp -> cs_dsp .rev = 0 ;
11821197 dsp -> fw = 9 ; /* 9 is WM_ADSP_FW_SPK_PROT in wm_adsp.c */
1198+ dsp -> toggle_preload = true;
11831199 dsp -> cs_dsp .dev = cs35l41 -> dev ;
11841200 dsp -> cs_dsp .regmap = cs35l41 -> regmap ;
11851201 dsp -> cs_dsp .base = CS35L41_DSP1_CTRL_BASE ;
@@ -1367,20 +1383,32 @@ int cs35l41_probe(struct cs35l41_private *cs35l41,
13671383 if (ret < 0 )
13681384 goto err ;
13691385
1386+ pm_runtime_set_autosuspend_delay (cs35l41 -> dev , 3000 );
1387+ pm_runtime_use_autosuspend (cs35l41 -> dev );
1388+ pm_runtime_mark_last_busy (cs35l41 -> dev );
1389+ pm_runtime_set_active (cs35l41 -> dev );
1390+ pm_runtime_get_noresume (cs35l41 -> dev );
1391+ pm_runtime_enable (cs35l41 -> dev );
1392+
13701393 ret = devm_snd_soc_register_component (cs35l41 -> dev ,
13711394 & soc_component_dev_cs35l41 ,
13721395 cs35l41_dai , ARRAY_SIZE (cs35l41_dai ));
13731396 if (ret < 0 ) {
13741397 dev_err (cs35l41 -> dev , "Register codec failed: %d\n" , ret );
1375- goto err_dsp ;
1398+ goto err_pm ;
13761399 }
13771400
1401+ pm_runtime_put_autosuspend (cs35l41 -> dev );
1402+
13781403 dev_info (cs35l41 -> dev , "Cirrus Logic CS35L41 (%x), Revision: %02X\n" ,
13791404 regid , reg_revid );
13801405
13811406 return 0 ;
13821407
1383- err_dsp :
1408+ err_pm :
1409+ pm_runtime_disable (cs35l41 -> dev );
1410+ pm_runtime_put_noidle (cs35l41 -> dev );
1411+
13841412 wm_adsp2_remove (& cs35l41 -> dsp );
13851413err :
13861414 regulator_bulk_disable (CS35L41_NUM_SUPPLIES , cs35l41 -> supplies );
@@ -1392,13 +1420,178 @@ EXPORT_SYMBOL_GPL(cs35l41_probe);
13921420
13931421void cs35l41_remove (struct cs35l41_private * cs35l41 )
13941422{
1423+ pm_runtime_get_sync (cs35l41 -> dev );
1424+ pm_runtime_disable (cs35l41 -> dev );
1425+
13951426 regmap_write (cs35l41 -> regmap , CS35L41_IRQ1_MASK1 , 0xFFFFFFFF );
13961427 wm_adsp2_remove (& cs35l41 -> dsp );
1428+
1429+ pm_runtime_put_noidle (cs35l41 -> dev );
1430+
13971431 regulator_bulk_disable (CS35L41_NUM_SUPPLIES , cs35l41 -> supplies );
13981432 gpiod_set_value_cansleep (cs35l41 -> reset_gpio , 0 );
13991433}
14001434EXPORT_SYMBOL_GPL (cs35l41_remove );
14011435
1436+ static int __maybe_unused cs35l41_runtime_suspend (struct device * dev )
1437+ {
1438+ struct cs35l41_private * cs35l41 = dev_get_drvdata (dev );
1439+
1440+ dev_dbg (cs35l41 -> dev , "Runtime suspend\n" );
1441+
1442+ if (!cs35l41 -> dsp .preloaded || !cs35l41 -> dsp .cs_dsp .running )
1443+ return 0 ;
1444+
1445+ dev_dbg (cs35l41 -> dev , "Enter hibernate\n" );
1446+
1447+ regmap_write (cs35l41 -> regmap , CS35L41_WAKESRC_CTL , 0x0088 );
1448+ regmap_write (cs35l41 -> regmap , CS35L41_WAKESRC_CTL , 0x0188 );
1449+
1450+ // Don't wait for ACK since bus activity would wake the device
1451+ regmap_write (cs35l41 -> regmap , CS35L41_DSP_VIRT1_MBOX_1 ,
1452+ CSPL_MBOX_CMD_HIBERNATE );
1453+
1454+ regcache_cache_only (cs35l41 -> regmap , true);
1455+ regcache_mark_dirty (cs35l41 -> regmap );
1456+
1457+ return 0 ;
1458+ }
1459+
1460+ static void cs35l41_wait_for_pwrmgt_sts (struct cs35l41_private * cs35l41 )
1461+ {
1462+ const int pwrmgt_retries = 10 ;
1463+ unsigned int sts ;
1464+ int i , ret ;
1465+
1466+ for (i = 0 ; i < pwrmgt_retries ; i ++ ) {
1467+ ret = regmap_read (cs35l41 -> regmap , CS35L41_PWRMGT_STS , & sts );
1468+ if (ret )
1469+ dev_err (cs35l41 -> dev , "Failed to read PWRMGT_STS: %d\n" , ret );
1470+ else if (!(sts & CS35L41_WR_PEND_STS_MASK ))
1471+ return ;
1472+
1473+ udelay (20 );
1474+ }
1475+
1476+ dev_err (cs35l41 -> dev , "Timed out reading PWRMGT_STS\n" );
1477+ }
1478+
1479+ static int cs35l41_exit_hibernate (struct cs35l41_private * cs35l41 )
1480+ {
1481+ const int wake_retries = 20 ;
1482+ const int sleep_retries = 5 ;
1483+ int ret , i , j ;
1484+
1485+ for (i = 0 ; i < sleep_retries ; i ++ ) {
1486+ dev_dbg (cs35l41 -> dev , "Exit hibernate\n" );
1487+
1488+ for (j = 0 ; j < wake_retries ; j ++ ) {
1489+ ret = cs35l41_set_cspl_mbox_cmd (cs35l41 ,
1490+ CSPL_MBOX_CMD_OUT_OF_HIBERNATE );
1491+ if (!ret )
1492+ break ;
1493+
1494+ usleep_range (100 , 200 );
1495+ }
1496+
1497+ if (j < wake_retries ) {
1498+ dev_dbg (cs35l41 -> dev , "Wake success at cycle: %d\n" , j );
1499+ return 0 ;
1500+ }
1501+
1502+ dev_err (cs35l41 -> dev , "Wake failed, re-enter hibernate: %d\n" , ret );
1503+
1504+ cs35l41_wait_for_pwrmgt_sts (cs35l41 );
1505+ regmap_write (cs35l41 -> regmap , CS35L41_WAKESRC_CTL , 0x0088 );
1506+
1507+ cs35l41_wait_for_pwrmgt_sts (cs35l41 );
1508+ regmap_write (cs35l41 -> regmap , CS35L41_WAKESRC_CTL , 0x0188 );
1509+
1510+ cs35l41_wait_for_pwrmgt_sts (cs35l41 );
1511+ regmap_write (cs35l41 -> regmap , CS35L41_PWRMGT_CTL , 0x3 );
1512+ }
1513+
1514+ dev_err (cs35l41 -> dev , "Timed out waking device\n" );
1515+
1516+ return - ETIMEDOUT ;
1517+ }
1518+
1519+ static int __maybe_unused cs35l41_runtime_resume (struct device * dev )
1520+ {
1521+ struct cs35l41_private * cs35l41 = dev_get_drvdata (dev );
1522+ int ret ;
1523+
1524+ dev_dbg (cs35l41 -> dev , "Runtime resume\n" );
1525+
1526+ if (!cs35l41 -> dsp .preloaded || !cs35l41 -> dsp .cs_dsp .running )
1527+ return 0 ;
1528+
1529+ regcache_cache_only (cs35l41 -> regmap , false);
1530+
1531+ ret = cs35l41_exit_hibernate (cs35l41 );
1532+ if (ret )
1533+ return ret ;
1534+
1535+ /* Test key needs to be unlocked to allow the OTP settings to re-apply */
1536+ cs35l41_test_key_unlock (cs35l41 -> dev , cs35l41 -> regmap );
1537+ ret = regcache_sync (cs35l41 -> regmap );
1538+ cs35l41_test_key_lock (cs35l41 -> dev , cs35l41 -> regmap );
1539+ if (ret ) {
1540+ dev_err (cs35l41 -> dev , "Failed to restore register cache: %d\n" , ret );
1541+ return ret ;
1542+ }
1543+
1544+ return 0 ;
1545+ }
1546+
1547+ static int __maybe_unused cs35l41_sys_suspend (struct device * dev )
1548+ {
1549+ struct cs35l41_private * cs35l41 = dev_get_drvdata (dev );
1550+
1551+ dev_dbg (cs35l41 -> dev , "System suspend, disabling IRQ\n" );
1552+ disable_irq (cs35l41 -> irq );
1553+
1554+ return 0 ;
1555+ }
1556+
1557+ static int __maybe_unused cs35l41_sys_suspend_noirq (struct device * dev )
1558+ {
1559+ struct cs35l41_private * cs35l41 = dev_get_drvdata (dev );
1560+
1561+ dev_dbg (cs35l41 -> dev , "Late system suspend, reenabling IRQ\n" );
1562+ enable_irq (cs35l41 -> irq );
1563+
1564+ return 0 ;
1565+ }
1566+
1567+ static int __maybe_unused cs35l41_sys_resume_noirq (struct device * dev )
1568+ {
1569+ struct cs35l41_private * cs35l41 = dev_get_drvdata (dev );
1570+
1571+ dev_dbg (cs35l41 -> dev , "Early system resume, disabling IRQ\n" );
1572+ disable_irq (cs35l41 -> irq );
1573+
1574+ return 0 ;
1575+ }
1576+
1577+ static int __maybe_unused cs35l41_sys_resume (struct device * dev )
1578+ {
1579+ struct cs35l41_private * cs35l41 = dev_get_drvdata (dev );
1580+
1581+ dev_dbg (cs35l41 -> dev , "System resume, reenabling IRQ\n" );
1582+ enable_irq (cs35l41 -> irq );
1583+
1584+ return 0 ;
1585+ }
1586+
1587+ const struct dev_pm_ops cs35l41_pm_ops = {
1588+ SET_RUNTIME_PM_OPS (cs35l41_runtime_suspend , cs35l41_runtime_resume , NULL )
1589+
1590+ SET_SYSTEM_SLEEP_PM_OPS (cs35l41_sys_suspend , cs35l41_sys_resume )
1591+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS (cs35l41_sys_suspend_noirq , cs35l41_sys_resume_noirq )
1592+ };
1593+ EXPORT_SYMBOL_GPL (cs35l41_pm_ops );
1594+
14021595MODULE_DESCRIPTION ("ASoC CS35L41 driver" );
14031596MODULE_AUTHOR ("David Rhodes, Cirrus Logic Inc, <david.rhodes@cirrus.com>" );
14041597MODULE_LICENSE ("GPL" );
0 commit comments