13
13
#include <linux/module.h>
14
14
#include <linux/moduleparam.h>
15
15
#include <linux/of_device.h>
16
+ #include <linux/pm_runtime.h>
16
17
#include <linux/property.h>
17
18
#include <sound/initval.h>
18
19
#include <sound/pcm.h>
@@ -187,8 +188,14 @@ static int cs35l41_dsp_preload_ev(struct snd_soc_dapm_widget *w,
187
188
188
189
switch (event ) {
189
190
case SND_SOC_DAPM_PRE_PMU :
191
+ if (cs35l41 -> dsp .cs_dsp .booted )
192
+ return 0 ;
193
+
190
194
return wm_adsp_early_event (w , kcontrol , event );
191
195
case SND_SOC_DAPM_PRE_PMD :
196
+ if (cs35l41 -> dsp .preloaded )
197
+ return 0 ;
198
+
192
199
if (cs35l41 -> dsp .cs_dsp .running ) {
193
200
ret = wm_adsp_event (w , kcontrol , event );
194
201
if (ret )
@@ -209,6 +216,7 @@ static bool cs35l41_check_cspl_mbox_sts(enum cs35l41_cspl_mbox_cmd cmd,
209
216
case CSPL_MBOX_CMD_UNKNOWN_CMD :
210
217
return true;
211
218
case CSPL_MBOX_CMD_PAUSE :
219
+ case CSPL_MBOX_CMD_OUT_OF_HIBERNATE :
212
220
return (sts == CSPL_MBOX_STS_PAUSED );
213
221
case CSPL_MBOX_CMD_RESUME :
214
222
return (sts == CSPL_MBOX_STS_RUNNING );
@@ -230,7 +238,8 @@ static int cs35l41_set_cspl_mbox_cmd(struct cs35l41_private *cs35l41,
230
238
// Set mailbox cmd
231
239
ret = regmap_write (cs35l41 -> regmap , CS35L41_DSP_VIRT1_MBOX_1 , cmd );
232
240
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 );
234
243
return ret ;
235
244
}
236
245
@@ -413,6 +422,8 @@ static irqreturn_t cs35l41_irq(int irq, void *data)
413
422
int ret = IRQ_NONE ;
414
423
unsigned int i ;
415
424
425
+ pm_runtime_get_sync (cs35l41 -> dev );
426
+
416
427
for (i = 0 ; i < ARRAY_SIZE (status ); i ++ ) {
417
428
regmap_read (cs35l41 -> regmap ,
418
429
CS35L41_IRQ1_STATUS1 + (i * CS35L41_REGSTRIDE ),
@@ -425,7 +436,7 @@ static irqreturn_t cs35l41_irq(int irq, void *data)
425
436
/* Check to see if unmasked bits are active */
426
437
if (!(status [0 ] & ~masks [0 ]) && !(status [1 ] & ~masks [1 ]) &&
427
438
!(status [2 ] & ~masks [2 ]) && !(status [3 ] & ~masks [3 ]))
428
- return IRQ_NONE ;
439
+ goto done ;
429
440
430
441
if (status [3 ] & CS35L41_OTP_BOOT_DONE ) {
431
442
regmap_update_bits (cs35l41 -> regmap , CS35L41_IRQ1_MASK4 ,
@@ -530,6 +541,10 @@ static irqreturn_t cs35l41_irq(int irq, void *data)
530
541
ret = IRQ_HANDLED ;
531
542
}
532
543
544
+ done :
545
+ pm_runtime_mark_last_busy (cs35l41 -> dev );
546
+ pm_runtime_put_autosuspend (cs35l41 -> dev );
547
+
533
548
return ret ;
534
549
}
535
550
@@ -1180,6 +1195,7 @@ static int cs35l41_dsp_init(struct cs35l41_private *cs35l41)
1180
1195
dsp -> cs_dsp .type = WMFW_HALO ;
1181
1196
dsp -> cs_dsp .rev = 0 ;
1182
1197
dsp -> fw = 9 ; /* 9 is WM_ADSP_FW_SPK_PROT in wm_adsp.c */
1198
+ dsp -> toggle_preload = true;
1183
1199
dsp -> cs_dsp .dev = cs35l41 -> dev ;
1184
1200
dsp -> cs_dsp .regmap = cs35l41 -> regmap ;
1185
1201
dsp -> cs_dsp .base = CS35L41_DSP1_CTRL_BASE ;
@@ -1367,20 +1383,32 @@ int cs35l41_probe(struct cs35l41_private *cs35l41,
1367
1383
if (ret < 0 )
1368
1384
goto err ;
1369
1385
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
+
1370
1393
ret = devm_snd_soc_register_component (cs35l41 -> dev ,
1371
1394
& soc_component_dev_cs35l41 ,
1372
1395
cs35l41_dai , ARRAY_SIZE (cs35l41_dai ));
1373
1396
if (ret < 0 ) {
1374
1397
dev_err (cs35l41 -> dev , "Register codec failed: %d\n" , ret );
1375
- goto err_dsp ;
1398
+ goto err_pm ;
1376
1399
}
1377
1400
1401
+ pm_runtime_put_autosuspend (cs35l41 -> dev );
1402
+
1378
1403
dev_info (cs35l41 -> dev , "Cirrus Logic CS35L41 (%x), Revision: %02X\n" ,
1379
1404
regid , reg_revid );
1380
1405
1381
1406
return 0 ;
1382
1407
1383
- err_dsp :
1408
+ err_pm :
1409
+ pm_runtime_disable (cs35l41 -> dev );
1410
+ pm_runtime_put_noidle (cs35l41 -> dev );
1411
+
1384
1412
wm_adsp2_remove (& cs35l41 -> dsp );
1385
1413
err :
1386
1414
regulator_bulk_disable (CS35L41_NUM_SUPPLIES , cs35l41 -> supplies );
@@ -1392,13 +1420,178 @@ EXPORT_SYMBOL_GPL(cs35l41_probe);
1392
1420
1393
1421
void cs35l41_remove (struct cs35l41_private * cs35l41 )
1394
1422
{
1423
+ pm_runtime_get_sync (cs35l41 -> dev );
1424
+ pm_runtime_disable (cs35l41 -> dev );
1425
+
1395
1426
regmap_write (cs35l41 -> regmap , CS35L41_IRQ1_MASK1 , 0xFFFFFFFF );
1396
1427
wm_adsp2_remove (& cs35l41 -> dsp );
1428
+
1429
+ pm_runtime_put_noidle (cs35l41 -> dev );
1430
+
1397
1431
regulator_bulk_disable (CS35L41_NUM_SUPPLIES , cs35l41 -> supplies );
1398
1432
gpiod_set_value_cansleep (cs35l41 -> reset_gpio , 0 );
1399
1433
}
1400
1434
EXPORT_SYMBOL_GPL (cs35l41_remove );
1401
1435
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
+
1402
1595
MODULE_DESCRIPTION ("ASoC CS35L41 driver" );
1403
1596
MODULE_AUTHOR (
"David Rhodes, Cirrus Logic Inc, <[email protected] >" );
1404
1597
MODULE_LICENSE ("GPL" );
0 commit comments