Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4a4bc53b authored by Clemens Ladisch's avatar Clemens Ladisch Committed by Jaroslav Kysela
Browse files

[ALSA] oxygen: add PM support



Add suspend/resume support.

Signed-off-by: default avatarClemens Ladisch <clemens@ladisch.de>
Signed-off-by: default avatarJaroslav Kysela <perex@perex.cz>
parent 92215f3a
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -146,6 +146,7 @@ static const struct oxygen_model model_hifier = {
	.init = hifier_init,
	.control_filter = hifier_control_filter,
	.cleanup = hifier_cleanup,
	.resume = hifier_registers_init,
	.set_dac_params = set_ak4396_params,
	.set_adc_params = set_cs5340_params,
	.update_dac_volume = update_ak4396_volume,
@@ -186,6 +187,10 @@ static struct pci_driver hifier_driver = {
	.id_table = hifier_ids,
	.probe = hifier_probe,
	.remove = __devexit_p(oxygen_pci_remove),
#ifdef CONFIG_PM
	.suspend = oxygen_pci_suspend,
	.resume = oxygen_pci_resume,
#endif
};

static int __init alsa_card_hifier_init(void)
+12 −0
Original line number Diff line number Diff line
@@ -192,6 +192,12 @@ static void generic_cleanup(struct oxygen *chip)
{
}

static void generic_resume(struct oxygen *chip)
{
	ak4396_registers_init(chip);
	wm8785_registers_init(chip);
}

static void set_ak4396_params(struct oxygen *chip,
			      struct snd_pcm_hw_params *params)
{
@@ -278,6 +284,7 @@ static const struct oxygen_model model_generic = {
	.owner = THIS_MODULE,
	.init = generic_init,
	.cleanup = generic_cleanup,
	.resume = generic_resume,
	.set_dac_params = set_ak4396_params,
	.set_adc_params = set_wm8785_params,
	.update_dac_volume = update_ak4396_volume,
@@ -305,6 +312,7 @@ static const struct oxygen_model model_meridian = {
	.owner = THIS_MODULE,
	.init = meridian_init,
	.cleanup = generic_cleanup,
	.resume = ak4396_registers_init,
	.set_dac_params = set_ak4396_params,
	.set_adc_params = set_ak5385_params,
	.update_dac_volume = update_ak4396_volume,
@@ -353,6 +361,10 @@ static struct pci_driver oxygen_driver = {
	.id_table = oxygen_ids,
	.probe = generic_oxygen_probe,
	.remove = __devexit_p(oxygen_pci_remove),
#ifdef CONFIG_PM
	.suspend = oxygen_pci_suspend,
	.resume = oxygen_pci_resume,
#endif
};

static int __init alsa_card_oxygen_init(void)
+6 −0
Original line number Diff line number Diff line
@@ -97,6 +97,8 @@ struct oxygen_model {
	int (*control_filter)(struct snd_kcontrol_new *template);
	int (*mixer_init)(struct oxygen *chip);
	void (*cleanup)(struct oxygen *chip);
	void (*suspend)(struct oxygen *chip);
	void (*resume)(struct oxygen *chip);
	void (*pcm_hardware_filter)(unsigned int channel,
				    struct snd_pcm_hardware *hardware);
	void (*set_dac_params)(struct oxygen *chip,
@@ -125,6 +127,10 @@ struct oxygen_model {
int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
		     const struct oxygen_model *model);
void oxygen_pci_remove(struct pci_dev *pci);
#ifdef CONFIG_PM
int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state);
int oxygen_pci_resume(struct pci_dev *pci);
#endif

/* oxygen_mixer.c */

+100 −0
Original line number Diff line number Diff line
@@ -314,6 +314,10 @@ static void oxygen_init(struct oxygen *chip)
				    OXYGEN_SPDIF_LOCK_MASK |
				    OXYGEN_SPDIF_RATE_MASK);
	oxygen_write32(chip, OXYGEN_SPDIF_OUTPUT_BITS, chip->spdif_bits);
	oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
		       OXYGEN_2WIRE_LENGTH_8 |
		       OXYGEN_2WIRE_INTERRUPT_MASK |
		       OXYGEN_2WIRE_SPEED_STANDARD);
	oxygen_clear_bits8(chip, OXYGEN_MPU401_CONTROL, OXYGEN_MPU401_LOOPBACK);
	oxygen_write8(chip, OXYGEN_GPI_INTERRUPT_MASK, 0);
	oxygen_write16(chip, OXYGEN_GPIO_INTERRUPT_MASK, 0);
@@ -534,3 +538,99 @@ void oxygen_pci_remove(struct pci_dev *pci)
	pci_set_drvdata(pci, NULL);
}
EXPORT_SYMBOL(oxygen_pci_remove);

#ifdef CONFIG_PM
int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state)
{
	struct snd_card *card = pci_get_drvdata(pci);
	struct oxygen *chip = card->private_data;
	unsigned int i, saved_interrupt_mask;

	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);

	for (i = 0; i < PCM_COUNT; ++i)
		if (chip->streams[i])
			snd_pcm_suspend(chip->streams[i]);

	if (chip->model->suspend)
		chip->model->suspend(chip);

	spin_lock_irq(&chip->reg_lock);
	saved_interrupt_mask = chip->interrupt_mask;
	chip->interrupt_mask = 0;
	oxygen_write16(chip, OXYGEN_DMA_STATUS, 0);
	oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0);
	spin_unlock_irq(&chip->reg_lock);

	synchronize_irq(chip->irq);
	flush_scheduled_work();
	chip->interrupt_mask = saved_interrupt_mask;

	pci_disable_device(pci);
	pci_save_state(pci);
	pci_set_power_state(pci, pci_choose_state(pci, state));
	return 0;
}
EXPORT_SYMBOL(oxygen_pci_suspend);

static const u32 registers_to_restore[OXYGEN_IO_SIZE / 32] = {
	0xffffffff, 0x00ff077f, 0x00011d08, 0x007f00ff,
	0x00300000, 0x00000fe4, 0x0ff7001f, 0x00000000
};
static const u32 ac97_registers_to_restore[2][0x40 / 32] = {
	{ 0x18284fa2, 0x03060000 },
	{ 0x00007fa6, 0x00200000 }
};

static inline int is_bit_set(const u32 *bitmap, unsigned int bit)
{
	return bitmap[bit / 32] & (1 << (bit & 31));
}

static void oxygen_restore_ac97(struct oxygen *chip, unsigned int codec)
{
	unsigned int i;

	oxygen_write_ac97(chip, codec, AC97_RESET, 0);
	msleep(1);
	for (i = 1; i < 0x40; ++i)
		if (is_bit_set(ac97_registers_to_restore[codec], i))
			oxygen_write_ac97(chip, codec, i * 2,
					  chip->saved_ac97_registers[codec][i]);
}

int oxygen_pci_resume(struct pci_dev *pci)
{
	struct snd_card *card = pci_get_drvdata(pci);
	struct oxygen *chip = card->private_data;
	unsigned int i;

	pci_set_power_state(pci, PCI_D0);
	pci_restore_state(pci);
	if (pci_enable_device(pci) < 0) {
		snd_printk(KERN_ERR "cannot reenable device");
		snd_card_disconnect(card);
		return -EIO;
	}
	pci_set_master(pci);

	oxygen_write16(chip, OXYGEN_DMA_STATUS, 0);
	oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0);
	for (i = 0; i < OXYGEN_IO_SIZE; ++i)
		if (is_bit_set(registers_to_restore, i))
			oxygen_write8(chip, i, chip->saved_registers._8[i]);
	if (chip->has_ac97_0)
		oxygen_restore_ac97(chip, 0);
	if (chip->has_ac97_1)
		oxygen_restore_ac97(chip, 1);

	if (chip->model->resume)
		chip->model->resume(chip);

	oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask);

	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
	return 0;
}
EXPORT_SYMBOL(oxygen_pci_resume);
#endif /* CONFIG_PM */
+1 −0
Original line number Diff line number Diff line
@@ -517,6 +517,7 @@ static int oxygen_trigger(struct snd_pcm_substream *substream, int cmd)
	switch (cmd) {
	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_SUSPEND:
		pausing = 0;
		break;
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
Loading