diff options
author | Takashi Iwai <tiwai@suse.de> | 2005-11-17 10:14:49 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2006-01-03 06:28:01 -0500 |
commit | cb60e5f5b2b19284479825cdaa6dd6b7078cf5d2 (patch) | |
tree | 1a2a9674bbe9abc98385b0a5e0015bc250fd9895 /sound/pci/cmipci.c | |
parent | b1e9ed26a9e472548a63a59014708fdae013b7a3 (diff) |
[ALSA] cmipci - Add PM support
Modules: CMIPCI driver
Add PM support to CMIPCI driver.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/cmipci.c')
-rw-r--r-- | sound/pci/cmipci.c | 104 |
1 files changed, 98 insertions, 6 deletions
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index ce156ca5bc6f..c03b0a0a3b27 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c | |||
@@ -269,6 +269,7 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address."); | |||
269 | #define CM_MICGAINZ 0x01 /* mic boost */ | 269 | #define CM_MICGAINZ 0x01 /* mic boost */ |
270 | #define CM_MICGAINZ_SHIFT 0 | 270 | #define CM_MICGAINZ_SHIFT 0 |
271 | 271 | ||
272 | #define CM_REG_MIXER3 0x24 | ||
272 | #define CM_REG_AUX_VOL 0x26 | 273 | #define CM_REG_AUX_VOL 0x26 |
273 | #define CM_VAUXL_MASK 0xf0 | 274 | #define CM_VAUXL_MASK 0xf0 |
274 | #define CM_VAUXR_MASK 0x0f | 275 | #define CM_VAUXR_MASK 0x0f |
@@ -324,6 +325,7 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address."); | |||
324 | #define CM_REG_CH0_FRAME2 0x84 | 325 | #define CM_REG_CH0_FRAME2 0x84 |
325 | #define CM_REG_CH1_FRAME1 0x88 /* 0-15: count of samples at bus master; buffer size */ | 326 | #define CM_REG_CH1_FRAME1 0x88 /* 0-15: count of samples at bus master; buffer size */ |
326 | #define CM_REG_CH1_FRAME2 0x8C /* 16-31: count of samples at codec; fragment size */ | 327 | #define CM_REG_CH1_FRAME2 0x8C /* 16-31: count of samples at codec; fragment size */ |
328 | #define CM_REG_EXT_MISC 0x90 | ||
327 | #define CM_REG_MISC_CTRL_8768 0x92 /* reg. name the same as 0x18 */ | 329 | #define CM_REG_MISC_CTRL_8768 0x92 /* reg. name the same as 0x18 */ |
328 | #define CM_CHB3D8C 0x20 /* 7.1 channels support */ | 330 | #define CM_CHB3D8C 0x20 /* 7.1 channels support */ |
329 | #define CM_SPD32FMT 0x10 /* SPDIF/IN 32k */ | 331 | #define CM_SPD32FMT 0x10 /* SPDIF/IN 32k */ |
@@ -453,6 +455,11 @@ struct cmipci { | |||
453 | #endif | 455 | #endif |
454 | 456 | ||
455 | spinlock_t reg_lock; | 457 | spinlock_t reg_lock; |
458 | |||
459 | #ifdef CONFIG_PM | ||
460 | unsigned int saved_regs[0x20]; | ||
461 | unsigned char saved_mixers[0x20]; | ||
462 | #endif | ||
456 | }; | 463 | }; |
457 | 464 | ||
458 | 465 | ||
@@ -849,10 +856,12 @@ static int snd_cmipci_pcm_trigger(struct cmipci *cm, struct cmipci_pcm *rec, | |||
849 | snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl & ~reset); | 856 | snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl & ~reset); |
850 | break; | 857 | break; |
851 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 858 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
859 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
852 | cm->ctrl |= pause; | 860 | cm->ctrl |= pause; |
853 | snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl); | 861 | snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl); |
854 | break; | 862 | break; |
855 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 863 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
864 | case SNDRV_PCM_TRIGGER_RESUME: | ||
856 | cm->ctrl &= ~pause; | 865 | cm->ctrl &= ~pause; |
857 | snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl); | 866 | snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl); |
858 | break; | 867 | break; |
@@ -1325,7 +1334,7 @@ static struct snd_pcm_hardware snd_cmipci_playback = | |||
1325 | { | 1334 | { |
1326 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 1335 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
1327 | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | | 1336 | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | |
1328 | SNDRV_PCM_INFO_MMAP_VALID), | 1337 | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), |
1329 | .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, | 1338 | .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, |
1330 | .rates = SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_48000, | 1339 | .rates = SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_48000, |
1331 | .rate_min = 5512, | 1340 | .rate_min = 5512, |
@@ -1345,7 +1354,7 @@ static struct snd_pcm_hardware snd_cmipci_capture = | |||
1345 | { | 1354 | { |
1346 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 1355 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
1347 | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | | 1356 | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | |
1348 | SNDRV_PCM_INFO_MMAP_VALID), | 1357 | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), |
1349 | .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, | 1358 | .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, |
1350 | .rates = SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_48000, | 1359 | .rates = SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_48000, |
1351 | .rate_min = 5512, | 1360 | .rate_min = 5512, |
@@ -1365,7 +1374,7 @@ static struct snd_pcm_hardware snd_cmipci_playback2 = | |||
1365 | { | 1374 | { |
1366 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 1375 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
1367 | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | | 1376 | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | |
1368 | SNDRV_PCM_INFO_MMAP_VALID), | 1377 | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), |
1369 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 1378 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
1370 | .rates = SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_48000, | 1379 | .rates = SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_48000, |
1371 | .rate_min = 5512, | 1380 | .rate_min = 5512, |
@@ -1385,7 +1394,7 @@ static struct snd_pcm_hardware snd_cmipci_playback_spdif = | |||
1385 | { | 1394 | { |
1386 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 1395 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
1387 | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | | 1396 | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | |
1388 | SNDRV_PCM_INFO_MMAP_VALID), | 1397 | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), |
1389 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 1398 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
1390 | .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, | 1399 | .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, |
1391 | .rate_min = 44100, | 1400 | .rate_min = 44100, |
@@ -1405,7 +1414,7 @@ static struct snd_pcm_hardware snd_cmipci_playback_iec958_subframe = | |||
1405 | { | 1414 | { |
1406 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 1415 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
1407 | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | | 1416 | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | |
1408 | SNDRV_PCM_INFO_MMAP_VALID), | 1417 | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), |
1409 | .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE, | 1418 | .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE, |
1410 | .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, | 1419 | .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, |
1411 | .rate_min = 44100, | 1420 | .rate_min = 44100, |
@@ -1425,7 +1434,7 @@ static struct snd_pcm_hardware snd_cmipci_capture_spdif = | |||
1425 | { | 1434 | { |
1426 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 1435 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
1427 | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | | 1436 | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | |
1428 | SNDRV_PCM_INFO_MMAP_VALID), | 1437 | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), |
1429 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 1438 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
1430 | .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, | 1439 | .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, |
1431 | .rate_min = 44100, | 1440 | .rate_min = 44100, |
@@ -3038,6 +3047,7 @@ static int __devinit snd_cmipci_probe(struct pci_dev *pci, | |||
3038 | snd_card_free(card); | 3047 | snd_card_free(card); |
3039 | return err; | 3048 | return err; |
3040 | } | 3049 | } |
3050 | card->private_data = cm; | ||
3041 | 3051 | ||
3042 | sprintf(card->shortname, "C-Media PCI %s", card->driver); | 3052 | sprintf(card->shortname, "C-Media PCI %s", card->driver); |
3043 | sprintf(card->longname, "%s (model %d) at 0x%lx, irq %i", | 3053 | sprintf(card->longname, "%s (model %d) at 0x%lx, irq %i", |
@@ -3065,11 +3075,93 @@ static void __devexit snd_cmipci_remove(struct pci_dev *pci) | |||
3065 | } | 3075 | } |
3066 | 3076 | ||
3067 | 3077 | ||
3078 | #ifdef CONFIG_PM | ||
3079 | /* | ||
3080 | * power management | ||
3081 | */ | ||
3082 | static unsigned char saved_regs[] = { | ||
3083 | CM_REG_FUNCTRL1, CM_REG_CHFORMAT, CM_REG_LEGACY_CTRL, CM_REG_MISC_CTRL, | ||
3084 | CM_REG_MIXER0, CM_REG_MIXER1, CM_REG_MIXER2, CM_REG_MIXER3, CM_REG_PLL, | ||
3085 | CM_REG_CH0_FRAME1, CM_REG_CH0_FRAME2, | ||
3086 | CM_REG_CH1_FRAME1, CM_REG_CH1_FRAME2, CM_REG_EXT_MISC, | ||
3087 | CM_REG_INT_STATUS, CM_REG_INT_HLDCLR, CM_REG_FUNCTRL0, | ||
3088 | }; | ||
3089 | |||
3090 | static unsigned char saved_mixers[] = { | ||
3091 | SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1, | ||
3092 | SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1, | ||
3093 | SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1, | ||
3094 | SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1, | ||
3095 | SB_DSP4_LINE_DEV, SB_DSP4_LINE_DEV + 1, | ||
3096 | SB_DSP4_MIC_DEV, SB_DSP4_SPEAKER_DEV, | ||
3097 | CM_REG_EXTENT_IND, SB_DSP4_OUTPUT_SW, | ||
3098 | SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, | ||
3099 | }; | ||
3100 | |||
3101 | static int snd_cmipci_suspend(struct pci_dev *pci, pm_message_t state) | ||
3102 | { | ||
3103 | struct snd_card *card = pci_get_drvdata(pci); | ||
3104 | struct cmipci *cm = card->private_data; | ||
3105 | int i; | ||
3106 | |||
3107 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
3108 | |||
3109 | snd_pcm_suspend_all(cm->pcm); | ||
3110 | snd_pcm_suspend_all(cm->pcm2); | ||
3111 | snd_pcm_suspend_all(cm->pcm_spdif); | ||
3112 | |||
3113 | /* save registers */ | ||
3114 | for (i = 0; i < ARRAY_SIZE(saved_regs); i++) | ||
3115 | cm->saved_regs[i] = snd_cmipci_read(cm, saved_regs[i]); | ||
3116 | for (i = 0; i < ARRAY_SIZE(saved_mixers); i++) | ||
3117 | cm->saved_mixers[i] = snd_cmipci_mixer_read(cm, saved_mixers[i]); | ||
3118 | |||
3119 | /* disable ints */ | ||
3120 | snd_cmipci_write(cm, CM_REG_INT_HLDCLR, 0); | ||
3121 | |||
3122 | pci_set_power_state(pci, PCI_D3hot); | ||
3123 | pci_disable_device(pci); | ||
3124 | pci_save_state(pci); | ||
3125 | return 0; | ||
3126 | } | ||
3127 | |||
3128 | static int snd_cmipci_resume(struct pci_dev *pci) | ||
3129 | { | ||
3130 | struct snd_card *card = pci_get_drvdata(pci); | ||
3131 | struct cmipci *cm = card->private_data; | ||
3132 | int i; | ||
3133 | |||
3134 | pci_restore_state(pci); | ||
3135 | pci_enable_device(pci); | ||
3136 | pci_set_power_state(pci, PCI_D0); | ||
3137 | pci_set_master(pci); | ||
3138 | |||
3139 | /* reset / initialize to a sane state */ | ||
3140 | snd_cmipci_write(cm, CM_REG_INT_HLDCLR, 0); | ||
3141 | snd_cmipci_ch_reset(cm, CM_CH_PLAY); | ||
3142 | snd_cmipci_ch_reset(cm, CM_CH_CAPT); | ||
3143 | snd_cmipci_mixer_write(cm, 0, 0); | ||
3144 | |||
3145 | /* restore registers */ | ||
3146 | for (i = 0; i < ARRAY_SIZE(saved_regs); i++) | ||
3147 | snd_cmipci_write(cm, saved_regs[i], cm->saved_regs[i]); | ||
3148 | for (i = 0; i < ARRAY_SIZE(saved_mixers); i++) | ||
3149 | snd_cmipci_mixer_write(cm, saved_mixers[i], cm->saved_mixers[i]); | ||
3150 | |||
3151 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
3152 | return 0; | ||
3153 | } | ||
3154 | #endif /* CONFIG_PM */ | ||
3155 | |||
3068 | static struct pci_driver driver = { | 3156 | static struct pci_driver driver = { |
3069 | .name = "C-Media PCI", | 3157 | .name = "C-Media PCI", |
3070 | .id_table = snd_cmipci_ids, | 3158 | .id_table = snd_cmipci_ids, |
3071 | .probe = snd_cmipci_probe, | 3159 | .probe = snd_cmipci_probe, |
3072 | .remove = __devexit_p(snd_cmipci_remove), | 3160 | .remove = __devexit_p(snd_cmipci_remove), |
3161 | #ifdef CONFIG_PM | ||
3162 | .suspend = snd_cmipci_suspend, | ||
3163 | .resume = snd_cmipci_resume, | ||
3164 | #endif | ||
3073 | }; | 3165 | }; |
3074 | 3166 | ||
3075 | static int __init alsa_card_cmipci_init(void) | 3167 | static int __init alsa_card_cmipci_init(void) |