提交 29959a09 编写于 作者: W Wai Yew CHAY 提交者: Takashi Iwai

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: NWai Yew CHAY <wychay@ctl.creative.com>
Singed-off-by: NRyan RICHARDS <ryan_richards@creativelabs.com>
Signed-off-by: NTakashi Iwai <tiwai@suse.de>
上级 a8f4310b
...@@ -261,13 +261,8 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) ...@@ -261,13 +261,8 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
int device = apcm->substream->pcm->device; int device = apcm->substream->pcm->device;
unsigned int pitch; unsigned int pitch;
if (NULL != apcm->src) {
/* Prepared pcm playback */
return 0;
}
/* first release old resources */ /* first release old resources */
atc->pcm_release_resources(atc, apcm); atc_pcm_release_resources(atc, apcm);
/* Get SRC resource */ /* Get SRC resource */
desc.multi = apcm->substream->runtime->channels; 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,10 +656,7 @@ static int atc_pcm_capture_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
unsigned int pitch; unsigned int pitch;
int mix_base = 0, imp_base = 0; int mix_base = 0, imp_base = 0;
if (NULL != apcm->src) { atc_pcm_release_resources(atc, apcm);
/* Prepared pcm capture */
return 0;
}
/* Get needed resources. */ /* Get needed resources. */
err = atc_pcm_capture_get_resources(atc, apcm); 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,7 +859,7 @@ spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm)
struct dao *dao = container_of(atc->daios[SPDIFOO], struct dao, daio); struct dao *dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
unsigned int rate = apcm->substream->runtime->rate; unsigned int rate = apcm->substream->runtime->rate;
unsigned int status; unsigned int status;
int err; int err = 0;
unsigned char iec958_con_fs; unsigned char iec958_con_fs;
switch (rate) { switch (rate) {
...@@ -908,8 +900,7 @@ spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) ...@@ -908,8 +900,7 @@ spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
int err; int err;
int i; int i;
if (NULL != apcm->src) atc_pcm_release_resources(atc, apcm);
return 0;
/* Configure SPDIFOO and PLL to passthrough mode; /* Configure SPDIFOO and PLL to passthrough mode;
* determine pll_rate. */ * determine pll_rate. */
...@@ -1116,32 +1107,20 @@ static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state) ...@@ -1116,32 +1107,20 @@ static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state)
return err; return err;
} }
static int ct_atc_destroy(struct ct_atc *atc) static int atc_release_resources(struct ct_atc *atc)
{ {
struct daio_mgr *daio_mgr; int i;
struct dao *dao; struct daio_mgr *daio_mgr = NULL;
struct dai *dai; struct dao *dao = NULL;
struct daio *daio; struct dai *dai = NULL;
struct sum_mgr *sum_mgr; struct daio *daio = NULL;
struct src_mgr *src_mgr; struct sum_mgr *sum_mgr = NULL;
struct srcimp_mgr *srcimp_mgr; struct src_mgr *src_mgr = NULL;
struct srcimp *srcimp; struct srcimp_mgr *srcimp_mgr = NULL;
struct ct_mixer *mixer; struct srcimp *srcimp = NULL;
int i = 0; struct ct_mixer *mixer = NULL;
if (NULL == atc) /* disconnect internal mixer objects */
return 0;
if (atc->timer) {
ct_timer_free(atc->timer);
atc->timer = NULL;
}
/* Stop hardware and disable all interrupts */
if (NULL != atc->hw)
((struct hw *)atc->hw)->card_stop(atc->hw);
/* Destroy internal mixer objects */
if (NULL != atc->mixer) { if (NULL != atc->mixer) {
mixer = atc->mixer; mixer = atc->mixer;
mixer->set_input_left(mixer, MIX_LINE_IN, NULL); mixer->set_input_left(mixer, MIX_LINE_IN, NULL);
...@@ -1150,7 +1129,6 @@ static int ct_atc_destroy(struct ct_atc *atc) ...@@ -1150,7 +1129,6 @@ static int ct_atc_destroy(struct ct_atc *atc)
mixer->set_input_right(mixer, MIX_MIC_IN, NULL); mixer->set_input_right(mixer, MIX_MIC_IN, NULL);
mixer->set_input_left(mixer, MIX_SPDIF_IN, NULL); mixer->set_input_left(mixer, MIX_SPDIF_IN, NULL);
mixer->set_input_right(mixer, MIX_SPDIF_IN, NULL); mixer->set_input_right(mixer, MIX_SPDIF_IN, NULL);
ct_mixer_destroy(atc->mixer);
} }
if (NULL != atc->daios) { if (NULL != atc->daios) {
...@@ -1168,6 +1146,7 @@ static int ct_atc_destroy(struct ct_atc *atc) ...@@ -1168,6 +1146,7 @@ static int ct_atc_destroy(struct ct_atc *atc)
daio_mgr->put_daio(daio_mgr, daio); daio_mgr->put_daio(daio_mgr, daio);
} }
kfree(atc->daios); kfree(atc->daios);
atc->daios = NULL;
} }
if (NULL != atc->pcm) { if (NULL != atc->pcm) {
...@@ -1176,6 +1155,7 @@ static int ct_atc_destroy(struct ct_atc *atc) ...@@ -1176,6 +1155,7 @@ static int ct_atc_destroy(struct ct_atc *atc)
sum_mgr->put_sum(sum_mgr, atc->pcm[i]); sum_mgr->put_sum(sum_mgr, atc->pcm[i]);
kfree(atc->pcm); kfree(atc->pcm);
atc->pcm = NULL;
} }
if (NULL != atc->srcs) { if (NULL != atc->srcs) {
...@@ -1184,6 +1164,7 @@ static int ct_atc_destroy(struct ct_atc *atc) ...@@ -1184,6 +1164,7 @@ static int ct_atc_destroy(struct ct_atc *atc)
src_mgr->put_src(src_mgr, atc->srcs[i]); src_mgr->put_src(src_mgr, atc->srcs[i]);
kfree(atc->srcs); kfree(atc->srcs);
atc->srcs = NULL;
} }
if (NULL != atc->srcimps) { if (NULL != atc->srcimps) {
...@@ -1194,8 +1175,30 @@ static int ct_atc_destroy(struct ct_atc *atc) ...@@ -1194,8 +1175,30 @@ static int ct_atc_destroy(struct ct_atc *atc)
srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]); srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]);
} }
kfree(atc->srcimps); kfree(atc->srcimps);
atc->srcimps = NULL;
}
return 0;
}
static int ct_atc_destroy(struct ct_atc *atc)
{
int i = 0;
if (NULL == atc)
return 0;
if (atc->timer) {
ct_timer_free(atc->timer);
atc->timer = NULL;
} }
atc_release_resources(atc);
/* Destroy internal mixer objects */
if (NULL != atc->mixer)
ct_mixer_destroy(atc->mixer);
for (i = 0; i < NUM_RSCTYP; i++) { for (i = 0; i < NUM_RSCTYP; i++) {
if ((NULL != rsc_mgr_funcs[i].destroy) && if ((NULL != rsc_mgr_funcs[i].destroy) &&
(NULL != atc->rsc_mgrs[i])) (NULL != atc->rsc_mgrs[i]))
...@@ -1323,7 +1326,7 @@ static int __devinit atc_create_hw_devs(struct ct_atc *atc) ...@@ -1323,7 +1326,7 @@ static int __devinit atc_create_hw_devs(struct ct_atc *atc)
return 0; return 0;
} }
static int __devinit atc_get_resources(struct ct_atc *atc) static int atc_get_resources(struct ct_atc *atc)
{ {
struct daio_desc da_desc = {0}; struct daio_desc da_desc = {0};
struct daio_mgr *daio_mgr; struct daio_mgr *daio_mgr;
...@@ -1420,16 +1423,10 @@ static int __devinit atc_get_resources(struct ct_atc *atc) ...@@ -1420,16 +1423,10 @@ static int __devinit atc_get_resources(struct ct_atc *atc)
atc->n_pcm++; atc->n_pcm++;
} }
err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer);
if (err) {
printk(KERN_ERR "ctxfi: Failed to create mixer obj!!!\n");
return err;
}
return 0; return 0;
} }
static void __devinit static void
atc_connect_dai(struct src_mgr *src_mgr, struct dai *dai, atc_connect_dai(struct src_mgr *src_mgr, struct dai *dai,
struct src **srcs, struct srcimp **srcimps) struct src **srcs, struct srcimp **srcimps)
{ {
...@@ -1468,7 +1465,7 @@ atc_connect_dai(struct src_mgr *src_mgr, struct dai *dai, ...@@ -1468,7 +1465,7 @@ atc_connect_dai(struct src_mgr *src_mgr, struct dai *dai,
src_mgr->commit_write(src_mgr); /* Synchronously enable SRCs */ src_mgr->commit_write(src_mgr); /* Synchronously enable SRCs */
} }
static void __devinit atc_connect_resources(struct ct_atc *atc) static void atc_connect_resources(struct ct_atc *atc)
{ {
struct dai *dai; struct dai *dai;
struct dao *dao; struct dao *dao;
...@@ -1514,6 +1511,84 @@ static void __devinit atc_connect_resources(struct ct_atc *atc) ...@@ -1514,6 +1511,84 @@ static void __devinit atc_connect_resources(struct ct_atc *atc)
} }
} }
#ifdef CONFIG_PM
static int atc_suspend(struct ct_atc *atc, pm_message_t state)
{
int i;
struct hw *hw = atc->hw;
snd_power_change_state(atc->card, SNDRV_CTL_POWER_D3hot);
for (i = FRONT; i < NUM_PCMS; i++) {
if (!atc->pcms[i])
continue;
snd_pcm_suspend_all(atc->pcms[i]);
}
atc_release_resources(atc);
hw->suspend(hw, state);
return 0;
}
static int atc_hw_resume(struct ct_atc *atc)
{
struct hw *hw = atc->hw;
struct card_conf info = {0};
/* Re-initialize card hardware. */
info.rsr = atc->rsr;
info.msr = atc->msr;
info.vm_pgt_phys = atc_get_ptp_phys(atc, 0);
return hw->resume(hw, &info);
}
static int atc_resources_resume(struct ct_atc *atc)
{
struct ct_mixer *mixer;
int err = 0;
/* Get resources */
err = atc_get_resources(atc);
if (err < 0) {
atc_release_resources(atc);
return err;
}
/* Build topology */
atc_connect_resources(atc);
mixer = atc->mixer;
mixer->resume(mixer);
return 0;
}
static int atc_resume(struct ct_atc *atc)
{
int err = 0;
/* Do hardware resume. */
err = atc_hw_resume(atc);
if (err < 0) {
printk(KERN_ERR "ctxfi: pci_enable_device failed, "
"disabling device\n");
snd_card_disconnect(atc->card);
return err;
}
err = atc_resources_resume(atc);
if (err < 0)
return err;
snd_power_change_state(atc->card, SNDRV_CTL_POWER_D0);
return 0;
}
#endif
static struct ct_atc atc_preset __devinitdata = { static struct ct_atc atc_preset __devinitdata = {
.map_audio_buffer = ct_map_audio_buffer, .map_audio_buffer = ct_map_audio_buffer,
.unmap_audio_buffer = ct_unmap_audio_buffer, .unmap_audio_buffer = ct_unmap_audio_buffer,
...@@ -1542,6 +1617,10 @@ static struct ct_atc atc_preset __devinitdata = { ...@@ -1542,6 +1617,10 @@ static struct ct_atc atc_preset __devinitdata = {
.spdif_out_set_status = atc_spdif_out_set_status, .spdif_out_set_status = atc_spdif_out_set_status,
.spdif_out_passthru = atc_spdif_out_passthru, .spdif_out_passthru = atc_spdif_out_passthru,
.have_digit_io_switch = atc_have_digit_io_switch, .have_digit_io_switch = atc_have_digit_io_switch,
#ifdef CONFIG_PM
.suspend = atc_suspend,
.resume = atc_resume,
#endif
}; };
/** /**
...@@ -1600,6 +1679,12 @@ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, ...@@ -1600,6 +1679,12 @@ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
if (err < 0) if (err < 0)
goto error1; goto error1;
err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer);
if (err) {
printk(KERN_ERR "ctxfi: Failed to create mixer obj!!!\n");
goto error1;
}
/* Get resources */ /* Get resources */
err = atc_get_resources(atc); err = atc_get_resources(atc);
if (err < 0) if (err < 0)
......
...@@ -136,6 +136,13 @@ struct ct_atc { ...@@ -136,6 +136,13 @@ struct ct_atc {
unsigned char n_pcm; unsigned char n_pcm;
struct ct_timer *timer; struct ct_timer *timer;
#ifdef CONFIG_PM
int (*suspend)(struct ct_atc *atc, pm_message_t state);
int (*resume)(struct ct_atc *atc);
#define NUM_PCMS (NUM_CTALSADEVS - 1)
struct snd_pcm *pcms[NUM_PCMS];
#endif
}; };
......
...@@ -64,6 +64,10 @@ struct hw { ...@@ -64,6 +64,10 @@ struct hw {
int (*card_init)(struct hw *hw, struct card_conf *info); int (*card_init)(struct hw *hw, struct card_conf *info);
int (*card_stop)(struct hw *hw); int (*card_stop)(struct hw *hw);
int (*pll_init)(struct hw *hw, unsigned int rsr); int (*pll_init)(struct hw *hw, unsigned int rsr);
#ifdef CONFIG_PM
int (*suspend)(struct hw *hw, pm_message_t state);
int (*resume)(struct hw *hw, struct card_conf *info);
#endif
int (*is_adc_source_selected)(struct hw *hw, enum ADCSRC source); int (*is_adc_source_selected)(struct hw *hw, enum ADCSRC source);
int (*select_adc_source)(struct hw *hw, enum ADCSRC source); int (*select_adc_source)(struct hw *hw, enum ADCSRC source);
int (*have_digit_io_switch)(struct hw *hw); int (*have_digit_io_switch)(struct hw *hw);
......
...@@ -1911,9 +1911,17 @@ static int hw_card_start(struct hw *hw) ...@@ -1911,9 +1911,17 @@ static int hw_card_start(struct hw *hw)
goto error1; goto error1;
} }
err = pci_request_regions(pci, "XFi"); if (!hw->io_base) {
if (err < 0) err = pci_request_regions(pci, "XFi");
goto error1; if (err < 0)
goto error1;
if (hw->model == CTUAA)
hw->io_base = pci_resource_start(pci, 5);
else
hw->io_base = pci_resource_start(pci, 0);
}
/* Switch to X-Fi mode from UAA mode if neeeded */ /* Switch to X-Fi mode from UAA mode if neeeded */
if (hw->model == CTUAA) { if (hw->model == CTUAA) {
...@@ -1921,18 +1929,17 @@ static int hw_card_start(struct hw *hw) ...@@ -1921,18 +1929,17 @@ static int hw_card_start(struct hw *hw)
if (err) if (err)
goto error2; goto error2;
hw->io_base = pci_resource_start(pci, 5);
} else {
hw->io_base = pci_resource_start(pci, 0);
} }
err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED, if (hw->irq < 0) {
"ctxfi", hw); err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED,
if (err < 0) { "ctxfi", hw);
printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq); if (err < 0) {
goto error2; printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq);
goto error2;
}
hw->irq = pci->irq;
} }
hw->irq = pci->irq;
pci_set_master(pci); pci_set_master(pci);
...@@ -1948,6 +1955,15 @@ static int hw_card_start(struct hw *hw) ...@@ -1948,6 +1955,15 @@ static int hw_card_start(struct hw *hw)
static int hw_card_stop(struct hw *hw) static int hw_card_stop(struct hw *hw)
{ {
unsigned int data;
/* disable transport bus master and queueing of request */
hw_write_20kx(hw, TRNCTL, 0x00);
/* disable pll */
data = hw_read_20kx(hw, PLLCTL);
hw_write_20kx(hw, PLLCTL, (data & (~(0x0F<<12))));
/* TODO: Disable interrupt and so on... */ /* TODO: Disable interrupt and so on... */
if (hw->irq >= 0) if (hw->irq >= 0)
synchronize_irq(hw->irq); synchronize_irq(hw->irq);
...@@ -1987,11 +2003,9 @@ static int hw_card_init(struct hw *hw, struct card_conf *info) ...@@ -1987,11 +2003,9 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
struct trn_conf trn_info = {0}; struct trn_conf trn_info = {0};
/* Get PCI io port base address and do Hendrix switch if needed. */ /* Get PCI io port base address and do Hendrix switch if needed. */
if (!hw->io_base) { err = hw_card_start(hw);
err = hw_card_start(hw); if (err)
if (err) return err;
return err;
}
/* PLL init */ /* PLL init */
err = hw_pll_init(hw, info->rsr); err = hw_pll_init(hw, info->rsr);
...@@ -2064,6 +2078,37 @@ static int hw_card_init(struct hw *hw, struct card_conf *info) ...@@ -2064,6 +2078,37 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
return 0; return 0;
} }
#ifdef CONFIG_PM
static int hw_suspend(struct hw *hw, pm_message_t state)
{
struct pci_dev *pci = hw->pci;
hw_card_stop(hw);
if (hw->model == CTUAA) {
/* Switch to UAA config space. */
pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x0);
}
pci_disable_device(pci);
pci_save_state(pci);
pci_set_power_state(pci, pci_choose_state(pci, state));
return 0;
}
static int hw_resume(struct hw *hw, struct card_conf *info)
{
struct pci_dev *pci = hw->pci;
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
/* Re-initialize card hardware. */
return hw_card_init(hw, info);
}
#endif
static u32 hw_read_20kx(struct hw *hw, u32 reg) static u32 hw_read_20kx(struct hw *hw, u32 reg)
{ {
u32 value; u32 value;
...@@ -2128,6 +2173,10 @@ static struct hw ct20k1_preset __devinitdata = { ...@@ -2128,6 +2173,10 @@ static struct hw ct20k1_preset __devinitdata = {
.is_adc_source_selected = hw_is_adc_input_selected, .is_adc_source_selected = hw_is_adc_input_selected,
.select_adc_source = hw_adc_input_select, .select_adc_source = hw_adc_input_select,
.have_digit_io_switch = hw_have_digit_io_switch, .have_digit_io_switch = hw_have_digit_io_switch,
#ifdef CONFIG_PM
.suspend = hw_suspend,
.resume = hw_resume,
#endif
.src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk, .src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk,
.src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk, .src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk,
......
...@@ -1860,16 +1860,18 @@ static int hw_card_start(struct hw *hw) ...@@ -1860,16 +1860,18 @@ static int hw_card_start(struct hw *hw)
goto error1; goto error1;
} }
err = pci_request_regions(pci, "XFi"); if (!hw->io_base) {
if (err < 0) err = pci_request_regions(pci, "XFi");
goto error1; if (err < 0)
goto error1;
hw->io_base = pci_resource_start(hw->pci, 2); hw->io_base = pci_resource_start(hw->pci, 2);
hw->mem_base = (unsigned long)ioremap(hw->io_base, hw->mem_base = (unsigned long)ioremap(hw->io_base,
pci_resource_len(hw->pci, 2)); pci_resource_len(hw->pci, 2));
if (NULL == (void *)hw->mem_base) { if (NULL == (void *)hw->mem_base) {
err = -ENOENT; err = -ENOENT;
goto error2; goto error2;
}
} }
/* Switch to 20k2 mode from UAA mode. */ /* Switch to 20k2 mode from UAA mode. */
...@@ -1901,6 +1903,15 @@ static int hw_card_start(struct hw *hw) ...@@ -1901,6 +1903,15 @@ static int hw_card_start(struct hw *hw)
static int hw_card_stop(struct hw *hw) static int hw_card_stop(struct hw *hw)
{ {
unsigned int data;
/* disable transport bus master and queueing of request */
hw_write_20kx(hw, TRANSPORT_CTL, 0x00);
/* disable pll */
data = hw_read_20kx(hw, PLL_ENB);
hw_write_20kx(hw, PLL_ENB, (data & (~0x07)));
/* TODO: Disable interrupt and so on... */ /* TODO: Disable interrupt and so on... */
return 0; return 0;
} }
...@@ -1939,11 +1950,9 @@ static int hw_card_init(struct hw *hw, struct card_conf *info) ...@@ -1939,11 +1950,9 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
/* Get PCI io port/memory base address and /* Get PCI io port/memory base address and
* do 20kx core switch if needed. */ * do 20kx core switch if needed. */
if (!hw->io_base) { err = hw_card_start(hw);
err = hw_card_start(hw); if (err)
if (err) return err;
return err;
}
/* PLL init */ /* PLL init */
err = hw_pll_init(hw, info->rsr); err = hw_pll_init(hw, info->rsr);
...@@ -2006,6 +2015,32 @@ static int hw_card_init(struct hw *hw, struct card_conf *info) ...@@ -2006,6 +2015,32 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
return 0; return 0;
} }
#ifdef CONFIG_PM
static int hw_suspend(struct hw *hw, pm_message_t state)
{
struct pci_dev *pci = hw->pci;
hw_card_stop(hw);
pci_disable_device(pci);
pci_save_state(pci);
pci_set_power_state(pci, pci_choose_state(pci, state));
return 0;
}
static int hw_resume(struct hw *hw, struct card_conf *info)
{
struct pci_dev *pci = hw->pci;
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
/* Re-initialize card hardware. */
return hw_card_init(hw, info);
}
#endif
static u32 hw_read_20kx(struct hw *hw, u32 reg) static u32 hw_read_20kx(struct hw *hw, u32 reg)
{ {
return readl((void *)(hw->mem_base + reg)); return readl((void *)(hw->mem_base + reg));
...@@ -2025,6 +2060,10 @@ static struct hw ct20k2_preset __devinitdata = { ...@@ -2025,6 +2060,10 @@ static struct hw ct20k2_preset __devinitdata = {
.is_adc_source_selected = hw_is_adc_input_selected, .is_adc_source_selected = hw_is_adc_input_selected,
.select_adc_source = hw_adc_input_select, .select_adc_source = hw_adc_input_select,
.have_digit_io_switch = hw_have_digit_io_switch, .have_digit_io_switch = hw_have_digit_io_switch,
#ifdef CONFIG_PM
.suspend = hw_suspend,
.resume = hw_resume,
#endif
.src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk, .src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk,
.src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk, .src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk,
......
...@@ -462,6 +462,43 @@ do_digit_io_switch(struct ct_atc *atc, int state) ...@@ -462,6 +462,43 @@ do_digit_io_switch(struct ct_atc *atc, int state)
return; return;
} }
static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state)
{
struct ct_mixer *mixer = atc->mixer;
/* Do changes in mixer. */
if ((SWH_CAPTURE_START <= type) && (SWH_CAPTURE_END >= type)) {
if (state) {
ct_mixer_recording_select(mixer,
get_amixer_index(type));
} else {
ct_mixer_recording_unselect(mixer,
get_amixer_index(type));
}
}
/* Do changes out of mixer. */
if (state && (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type))
do_line_mic_switch(atc, type);
else if (MIXER_WAVEF_P_S == type)
atc->line_front_unmute(atc, state);
else if (MIXER_WAVES_P_S == type)
atc->line_surround_unmute(atc, state);
else if (MIXER_WAVEC_P_S == type)
atc->line_clfe_unmute(atc, state);
else if (MIXER_WAVER_P_S == type)
atc->line_rear_unmute(atc, state);
else if (MIXER_LINEIN_P_S == type)
atc->line_in_unmute(atc, state);
else if (MIXER_SPDIFO_P_S == type)
atc->spdif_out_unmute(atc, state);
else if (MIXER_SPDIFI_P_S == type)
atc->spdif_in_unmute(atc, state);
else if (MIXER_DIGITAL_IO_S == type)
do_digit_io_switch(atc, state);
return;
}
static int ct_alsa_mix_switch_info(struct snd_kcontrol *kcontrol, static int ct_alsa_mix_switch_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo) struct snd_ctl_elem_info *uinfo)
{ {
...@@ -498,35 +535,7 @@ static int ct_alsa_mix_switch_put(struct snd_kcontrol *kcontrol, ...@@ -498,35 +535,7 @@ static int ct_alsa_mix_switch_put(struct snd_kcontrol *kcontrol,
return 0; return 0;
set_switch_state(mixer, type, state); set_switch_state(mixer, type, state);
/* Do changes in mixer. */ do_switch(atc, type, state);
if ((SWH_CAPTURE_START <= type) && (SWH_CAPTURE_END >= type)) {
if (state) {
ct_mixer_recording_select(mixer,
get_amixer_index(type));
} else {
ct_mixer_recording_unselect(mixer,
get_amixer_index(type));
}
}
/* Do changes out of mixer. */
if (state && (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type))
do_line_mic_switch(atc, type);
else if (MIXER_WAVEF_P_S == type)
atc->line_front_unmute(atc, state);
else if (MIXER_WAVES_P_S == type)
atc->line_surround_unmute(atc, state);
else if (MIXER_WAVEC_P_S == type)
atc->line_clfe_unmute(atc, state);
else if (MIXER_WAVER_P_S == type)
atc->line_rear_unmute(atc, state);
else if (MIXER_LINEIN_P_S == type)
atc->line_in_unmute(atc, state);
else if (MIXER_SPDIFO_P_S == type)
atc->spdif_out_unmute(atc, state);
else if (MIXER_SPDIFI_P_S == type)
atc->spdif_in_unmute(atc, state);
else if (MIXER_DIGITAL_IO_S == type)
do_digit_io_switch(atc, state);
return 1; return 1;
} }
...@@ -1039,6 +1048,28 @@ mixer_set_input_right(struct ct_mixer *mixer, ...@@ -1039,6 +1048,28 @@ mixer_set_input_right(struct ct_mixer *mixer,
return 0; return 0;
} }
#ifdef CONFIG_PM
static int mixer_resume(struct ct_mixer *mixer)
{
int i, state;
struct amixer *amixer;
/* resume topology and volume gain. */
for (i = 0; i < NUM_CT_AMIXERS*CHN_NUM; i++) {
amixer = mixer->amixers[i];
amixer->ops->commit_write(amixer);
}
/* resume switch state. */
for (i = SWH_MIXER_START; i <= SWH_MIXER_END; i++) {
state = get_switch_state(mixer, i);
do_switch(mixer->atc, i, state);
}
return 0;
}
#endif
int ct_mixer_destroy(struct ct_mixer *mixer) int ct_mixer_destroy(struct ct_mixer *mixer)
{ {
struct sum_mgr *sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM]; struct sum_mgr *sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM];
...@@ -1087,6 +1118,9 @@ int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer) ...@@ -1087,6 +1118,9 @@ int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer)
mixer->get_output_ports = mixer_get_output_ports; mixer->get_output_ports = mixer_get_output_ports;
mixer->set_input_left = mixer_set_input_left; mixer->set_input_left = mixer_set_input_left;
mixer->set_input_right = mixer_set_input_right; mixer->set_input_right = mixer_set_input_right;
#ifdef CONFIG_PM
mixer->resume = mixer_resume;
#endif
/* Allocate chip resources for mixer obj */ /* Allocate chip resources for mixer obj */
err = ct_mixer_get_resources(mixer); err = ct_mixer_get_resources(mixer);
......
...@@ -56,6 +56,9 @@ struct ct_mixer { ...@@ -56,6 +56,9 @@ struct ct_mixer {
enum MIXER_PORT_T type, struct rsc *rsc); enum MIXER_PORT_T type, struct rsc *rsc);
int (*set_input_right)(struct ct_mixer *mixer, int (*set_input_right)(struct ct_mixer *mixer,
enum MIXER_PORT_T type, struct rsc *rsc); enum MIXER_PORT_T type, struct rsc *rsc);
#ifdef CONFIG_PM
int (*resume)(struct ct_mixer *mixer);
#endif
}; };
int ct_alsa_mix_create(struct ct_atc *atc, int ct_alsa_mix_create(struct ct_atc *atc,
......
...@@ -422,5 +422,9 @@ int ct_alsa_pcm_create(struct ct_atc *atc, ...@@ -422,5 +422,9 @@ int ct_alsa_pcm_create(struct ct_atc *atc,
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
snd_dma_pci_data(atc->pci), 128*1024, 128*1024); snd_dma_pci_data(atc->pci), 128*1024, 128*1024);
#ifdef CONFIG_PM
atc->pcms[device] = pcm;
#endif
return 0; return 0;
} }
...@@ -121,11 +121,33 @@ static void __devexit ct_card_remove(struct pci_dev *pci) ...@@ -121,11 +121,33 @@ static void __devexit ct_card_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL); pci_set_drvdata(pci, NULL);
} }
#ifdef CONFIG_PM
static int ct_card_suspend(struct pci_dev *pci, pm_message_t state)
{
struct snd_card *card = pci_get_drvdata(pci);
struct ct_atc *atc = card->private_data;
return atc->suspend(atc, state);
}
static int ct_card_resume(struct pci_dev *pci)
{
struct snd_card *card = pci_get_drvdata(pci);
struct ct_atc *atc = card->private_data;
return atc->resume(atc);
}
#endif
static struct pci_driver ct_driver = { static struct pci_driver ct_driver = {
.name = "SB-XFi", .name = "SB-XFi",
.id_table = ct_pci_dev_ids, .id_table = ct_pci_dev_ids,
.probe = ct_card_probe, .probe = ct_card_probe,
.remove = __devexit_p(ct_card_remove), .remove = __devexit_p(ct_card_remove),
#ifdef CONFIG_PM
.suspend = ct_card_suspend,
.resume = ct_card_resume,
#endif
}; };
static int __init ct_card_init(void) static int __init ct_card_init(void)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
反馈
建议
客服 返回
顶部