diff options
author | Wai Yew CHAY <wychay@ctl.creative.com> | 2009-06-22 08:52:34 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-06-22 08:53:51 -0400 |
commit | 29959a09cc1aabd2d5f4f03afc0305de6bd29248 (patch) | |
tree | e7e4ed3d33995ab9e83ae378bb9d42fce63f8fde /sound/pci/ctxfi/ctatc.c | |
parent | a8f4310be59a2e7fc80fba945bcb32b18f4ad54f (diff) |
ALSA: ctxfi - Add PM support
Added the suspend/resume support to ctxfi driver.
The team tested on the following seems ok:
AMD Athlon 64 3500+ / ASUS A8N-E / 512MB DDR ATI / Radeon X1300
20k1 & 20k2 cards
Signed-off-by: Wai Yew CHAY <wychay@ctl.creative.com>
Singed-off-by: Ryan RICHARDS <ryan_richards@creativelabs.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/ctxfi/ctatc.c')
-rw-r--r-- | sound/pci/ctxfi/ctatc.c | 181 |
1 files changed, 133 insertions, 48 deletions
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index 32e3c26e969e..a49c76647307 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c | |||
@@ -261,13 +261,8 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) | |||
261 | int device = apcm->substream->pcm->device; | 261 | int device = apcm->substream->pcm->device; |
262 | unsigned int pitch; | 262 | unsigned int pitch; |
263 | 263 | ||
264 | if (NULL != apcm->src) { | ||
265 | /* Prepared pcm playback */ | ||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | /* first release old resources */ | 264 | /* first release old resources */ |
270 | atc->pcm_release_resources(atc, apcm); | 265 | atc_pcm_release_resources(atc, apcm); |
271 | 266 | ||
272 | /* Get SRC resource */ | 267 | /* Get SRC resource */ |
273 | desc.multi = apcm->substream->runtime->channels; | 268 | desc.multi = apcm->substream->runtime->channels; |
@@ -661,10 +656,7 @@ static int atc_pcm_capture_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) | |||
661 | unsigned int pitch; | 656 | unsigned int pitch; |
662 | int mix_base = 0, imp_base = 0; | 657 | int mix_base = 0, imp_base = 0; |
663 | 658 | ||
664 | if (NULL != apcm->src) { | 659 | atc_pcm_release_resources(atc, apcm); |
665 | /* Prepared pcm capture */ | ||
666 | return 0; | ||
667 | } | ||
668 | 660 | ||
669 | /* Get needed resources. */ | 661 | /* Get needed resources. */ |
670 | err = atc_pcm_capture_get_resources(atc, apcm); | 662 | err = atc_pcm_capture_get_resources(atc, apcm); |
@@ -867,7 +859,7 @@ spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm) | |||
867 | struct dao *dao = container_of(atc->daios[SPDIFOO], struct dao, daio); | 859 | struct dao *dao = container_of(atc->daios[SPDIFOO], struct dao, daio); |
868 | unsigned int rate = apcm->substream->runtime->rate; | 860 | unsigned int rate = apcm->substream->runtime->rate; |
869 | unsigned int status; | 861 | unsigned int status; |
870 | int err; | 862 | int err = 0; |
871 | unsigned char iec958_con_fs; | 863 | unsigned char iec958_con_fs; |
872 | 864 | ||
873 | switch (rate) { | 865 | switch (rate) { |
@@ -908,8 +900,7 @@ spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) | |||
908 | int err; | 900 | int err; |
909 | int i; | 901 | int i; |
910 | 902 | ||
911 | if (NULL != apcm->src) | 903 | atc_pcm_release_resources(atc, apcm); |
912 | return 0; | ||
913 | 904 | ||
914 | /* Configure SPDIFOO and PLL to passthrough mode; | 905 | /* Configure SPDIFOO and PLL to passthrough mode; |
915 | * determine pll_rate. */ | 906 | * determine pll_rate. */ |
@@ -1116,32 +1107,20 @@ static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state) | |||
1116 | return err; | 1107 | return err; |
1117 | } | 1108 | } |
1118 | 1109 | ||
1119 | static int ct_atc_destroy(struct ct_atc *atc) | 1110 | static int atc_release_resources(struct ct_atc *atc) |
1120 | { | 1111 | { |
1121 | struct daio_mgr *daio_mgr; | 1112 | int i; |
1122 | struct dao *dao; | 1113 | struct daio_mgr *daio_mgr = NULL; |
1123 | struct dai *dai; | 1114 | struct dao *dao = NULL; |
1124 | struct daio *daio; | 1115 | struct dai *dai = NULL; |
1125 | struct sum_mgr *sum_mgr; | 1116 | struct daio *daio = NULL; |
1126 | struct src_mgr *src_mgr; | 1117 | struct sum_mgr *sum_mgr = NULL; |
1127 | struct srcimp_mgr *srcimp_mgr; | 1118 | struct src_mgr *src_mgr = NULL; |
1128 | struct srcimp *srcimp; | 1119 | struct srcimp_mgr *srcimp_mgr = NULL; |
1129 | struct ct_mixer *mixer; | 1120 | struct srcimp *srcimp = NULL; |
1130 | int i = 0; | 1121 | struct ct_mixer *mixer = NULL; |
1131 | 1122 | ||
1132 | if (NULL == atc) | 1123 | /* disconnect internal mixer objects */ |
1133 | return 0; | ||
1134 | |||
1135 | if (atc->timer) { | ||
1136 | ct_timer_free(atc->timer); | ||
1137 | atc->timer = NULL; | ||
1138 | } | ||
1139 | |||
1140 | /* Stop hardware and disable all interrupts */ | ||
1141 | if (NULL != atc->hw) | ||
1142 | ((struct hw *)atc->hw)->card_stop(atc->hw); | ||
1143 | |||
1144 | /* Destroy internal mixer objects */ | ||
1145 | if (NULL != atc->mixer) { | 1124 | if (NULL != atc->mixer) { |
1146 | mixer = atc->mixer; | 1125 | mixer = atc->mixer; |
1147 | mixer->set_input_left(mixer, MIX_LINE_IN, NULL); | 1126 | mixer->set_input_left(mixer, MIX_LINE_IN, NULL); |
@@ -1150,7 +1129,6 @@ static int ct_atc_destroy(struct ct_atc *atc) | |||
1150 | mixer->set_input_right(mixer, MIX_MIC_IN, NULL); | 1129 | mixer->set_input_right(mixer, MIX_MIC_IN, NULL); |
1151 | mixer->set_input_left(mixer, MIX_SPDIF_IN, NULL); | 1130 | mixer->set_input_left(mixer, MIX_SPDIF_IN, NULL); |
1152 | mixer->set_input_right(mixer, MIX_SPDIF_IN, NULL); | 1131 | mixer->set_input_right(mixer, MIX_SPDIF_IN, NULL); |
1153 | ct_mixer_destroy(atc->mixer); | ||
1154 | } | 1132 | } |
1155 | 1133 | ||
1156 | if (NULL != atc->daios) { | 1134 | if (NULL != atc->daios) { |
@@ -1168,6 +1146,7 @@ static int ct_atc_destroy(struct ct_atc *atc) | |||
1168 | daio_mgr->put_daio(daio_mgr, daio); | 1146 | daio_mgr->put_daio(daio_mgr, daio); |
1169 | } | 1147 | } |
1170 | kfree(atc->daios); | 1148 | kfree(atc->daios); |
1149 | atc->daios = NULL; | ||
1171 | } | 1150 | } |
1172 | 1151 | ||
1173 | if (NULL != atc->pcm) { | 1152 | if (NULL != atc->pcm) { |
@@ -1176,6 +1155,7 @@ static int ct_atc_destroy(struct ct_atc *atc) | |||
1176 | sum_mgr->put_sum(sum_mgr, atc->pcm[i]); | 1155 | sum_mgr->put_sum(sum_mgr, atc->pcm[i]); |
1177 | 1156 | ||
1178 | kfree(atc->pcm); | 1157 | kfree(atc->pcm); |
1158 | atc->pcm = NULL; | ||
1179 | } | 1159 | } |
1180 | 1160 | ||
1181 | if (NULL != atc->srcs) { | 1161 | if (NULL != atc->srcs) { |
@@ -1184,6 +1164,7 @@ static int ct_atc_destroy(struct ct_atc *atc) | |||
1184 | src_mgr->put_src(src_mgr, atc->srcs[i]); | 1164 | src_mgr->put_src(src_mgr, atc->srcs[i]); |
1185 | 1165 | ||
1186 | kfree(atc->srcs); | 1166 | kfree(atc->srcs); |
1167 | atc->srcs = NULL; | ||
1187 | } | 1168 | } |
1188 | 1169 | ||
1189 | if (NULL != atc->srcimps) { | 1170 | if (NULL != atc->srcimps) { |
@@ -1194,8 +1175,30 @@ static int ct_atc_destroy(struct ct_atc *atc) | |||
1194 | srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]); | 1175 | srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]); |
1195 | } | 1176 | } |
1196 | kfree(atc->srcimps); | 1177 | kfree(atc->srcimps); |
1178 | atc->srcimps = NULL; | ||
1179 | } | ||
1180 | |||
1181 | return 0; | ||
1182 | } | ||
1183 | |||
1184 | static int ct_atc_destroy(struct ct_atc *atc) | ||
1185 | { | ||
1186 | int i = 0; | ||
1187 | |||
1188 | if (NULL == atc) | ||
1189 | return 0; | ||
1190 | |||
1191 | if (atc->timer) { | ||
1192 | ct_timer_free(atc->timer); | ||
1193 | atc->timer = NULL; | ||
1197 | } | 1194 | } |
1198 | 1195 | ||
1196 | atc_release_resources(atc); | ||
1197 | |||
1198 | /* Destroy internal mixer objects */ | ||
1199 | if (NULL != atc->mixer) | ||
1200 | ct_mixer_destroy(atc->mixer); | ||
1201 | |||
1199 | for (i = 0; i < NUM_RSCTYP; i++) { | 1202 | for (i = 0; i < NUM_RSCTYP; i++) { |
1200 | if ((NULL != rsc_mgr_funcs[i].destroy) && | 1203 | if ((NULL != rsc_mgr_funcs[i].destroy) && |
1201 | (NULL != atc->rsc_mgrs[i])) | 1204 | (NULL != atc->rsc_mgrs[i])) |
@@ -1323,7 +1326,7 @@ static int __devinit atc_create_hw_devs(struct ct_atc *atc) | |||
1323 | return 0; | 1326 | return 0; |
1324 | } | 1327 | } |
1325 | 1328 | ||
1326 | static int __devinit atc_get_resources(struct ct_atc *atc) | 1329 | static int atc_get_resources(struct ct_atc *atc) |
1327 | { | 1330 | { |
1328 | struct daio_desc da_desc = {0}; | 1331 | struct daio_desc da_desc = {0}; |
1329 | struct daio_mgr *daio_mgr; | 1332 | struct daio_mgr *daio_mgr; |
@@ -1420,16 +1423,10 @@ static int __devinit atc_get_resources(struct ct_atc *atc) | |||
1420 | atc->n_pcm++; | 1423 | atc->n_pcm++; |
1421 | } | 1424 | } |
1422 | 1425 | ||
1423 | err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer); | ||
1424 | if (err) { | ||
1425 | printk(KERN_ERR "ctxfi: Failed to create mixer obj!!!\n"); | ||
1426 | return err; | ||
1427 | } | ||
1428 | |||
1429 | return 0; | 1426 | return 0; |
1430 | } | 1427 | } |
1431 | 1428 | ||
1432 | static void __devinit | 1429 | static void |
1433 | atc_connect_dai(struct src_mgr *src_mgr, struct dai *dai, | 1430 | atc_connect_dai(struct src_mgr *src_mgr, struct dai *dai, |
1434 | struct src **srcs, struct srcimp **srcimps) | 1431 | struct src **srcs, struct srcimp **srcimps) |
1435 | { | 1432 | { |
@@ -1468,7 +1465,7 @@ atc_connect_dai(struct src_mgr *src_mgr, struct dai *dai, | |||
1468 | src_mgr->commit_write(src_mgr); /* Synchronously enable SRCs */ | 1465 | src_mgr->commit_write(src_mgr); /* Synchronously enable SRCs */ |
1469 | } | 1466 | } |
1470 | 1467 | ||
1471 | static void __devinit atc_connect_resources(struct ct_atc *atc) | 1468 | static void atc_connect_resources(struct ct_atc *atc) |
1472 | { | 1469 | { |
1473 | struct dai *dai; | 1470 | struct dai *dai; |
1474 | struct dao *dao; | 1471 | struct dao *dao; |
@@ -1514,6 +1511,84 @@ static void __devinit atc_connect_resources(struct ct_atc *atc) | |||
1514 | } | 1511 | } |
1515 | } | 1512 | } |
1516 | 1513 | ||
1514 | #ifdef CONFIG_PM | ||
1515 | static int atc_suspend(struct ct_atc *atc, pm_message_t state) | ||
1516 | { | ||
1517 | int i; | ||
1518 | struct hw *hw = atc->hw; | ||
1519 | |||
1520 | snd_power_change_state(atc->card, SNDRV_CTL_POWER_D3hot); | ||
1521 | |||
1522 | for (i = FRONT; i < NUM_PCMS; i++) { | ||
1523 | if (!atc->pcms[i]) | ||
1524 | continue; | ||
1525 | |||
1526 | snd_pcm_suspend_all(atc->pcms[i]); | ||
1527 | } | ||
1528 | |||
1529 | atc_release_resources(atc); | ||
1530 | |||
1531 | hw->suspend(hw, state); | ||
1532 | |||
1533 | return 0; | ||
1534 | } | ||
1535 | |||
1536 | static int atc_hw_resume(struct ct_atc *atc) | ||
1537 | { | ||
1538 | struct hw *hw = atc->hw; | ||
1539 | struct card_conf info = {0}; | ||
1540 | |||
1541 | /* Re-initialize card hardware. */ | ||
1542 | info.rsr = atc->rsr; | ||
1543 | info.msr = atc->msr; | ||
1544 | info.vm_pgt_phys = atc_get_ptp_phys(atc, 0); | ||
1545 | return hw->resume(hw, &info); | ||
1546 | } | ||
1547 | |||
1548 | static int atc_resources_resume(struct ct_atc *atc) | ||
1549 | { | ||
1550 | struct ct_mixer *mixer; | ||
1551 | int err = 0; | ||
1552 | |||
1553 | /* Get resources */ | ||
1554 | err = atc_get_resources(atc); | ||
1555 | if (err < 0) { | ||
1556 | atc_release_resources(atc); | ||
1557 | return err; | ||
1558 | } | ||
1559 | |||
1560 | /* Build topology */ | ||
1561 | atc_connect_resources(atc); | ||
1562 | |||
1563 | mixer = atc->mixer; | ||
1564 | mixer->resume(mixer); | ||
1565 | |||
1566 | return 0; | ||
1567 | } | ||
1568 | |||
1569 | static int atc_resume(struct ct_atc *atc) | ||
1570 | { | ||
1571 | int err = 0; | ||
1572 | |||
1573 | /* Do hardware resume. */ | ||
1574 | err = atc_hw_resume(atc); | ||
1575 | if (err < 0) { | ||
1576 | printk(KERN_ERR "ctxfi: pci_enable_device failed, " | ||
1577 | "disabling device\n"); | ||
1578 | snd_card_disconnect(atc->card); | ||
1579 | return err; | ||
1580 | } | ||
1581 | |||
1582 | err = atc_resources_resume(atc); | ||
1583 | if (err < 0) | ||
1584 | return err; | ||
1585 | |||
1586 | snd_power_change_state(atc->card, SNDRV_CTL_POWER_D0); | ||
1587 | |||
1588 | return 0; | ||
1589 | } | ||
1590 | #endif | ||
1591 | |||
1517 | static struct ct_atc atc_preset __devinitdata = { | 1592 | static struct ct_atc atc_preset __devinitdata = { |
1518 | .map_audio_buffer = ct_map_audio_buffer, | 1593 | .map_audio_buffer = ct_map_audio_buffer, |
1519 | .unmap_audio_buffer = ct_unmap_audio_buffer, | 1594 | .unmap_audio_buffer = ct_unmap_audio_buffer, |
@@ -1542,6 +1617,10 @@ static struct ct_atc atc_preset __devinitdata = { | |||
1542 | .spdif_out_set_status = atc_spdif_out_set_status, | 1617 | .spdif_out_set_status = atc_spdif_out_set_status, |
1543 | .spdif_out_passthru = atc_spdif_out_passthru, | 1618 | .spdif_out_passthru = atc_spdif_out_passthru, |
1544 | .have_digit_io_switch = atc_have_digit_io_switch, | 1619 | .have_digit_io_switch = atc_have_digit_io_switch, |
1620 | #ifdef CONFIG_PM | ||
1621 | .suspend = atc_suspend, | ||
1622 | .resume = atc_resume, | ||
1623 | #endif | ||
1545 | }; | 1624 | }; |
1546 | 1625 | ||
1547 | /** | 1626 | /** |
@@ -1600,6 +1679,12 @@ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, | |||
1600 | if (err < 0) | 1679 | if (err < 0) |
1601 | goto error1; | 1680 | goto error1; |
1602 | 1681 | ||
1682 | err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer); | ||
1683 | if (err) { | ||
1684 | printk(KERN_ERR "ctxfi: Failed to create mixer obj!!!\n"); | ||
1685 | goto error1; | ||
1686 | } | ||
1687 | |||
1603 | /* Get resources */ | 1688 | /* Get resources */ |
1604 | err = atc_get_resources(atc); | 1689 | err = atc_get_resources(atc); |
1605 | if (err < 0) | 1690 | if (err < 0) |