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

Commit b56fa687 authored by Andy Shevchenko's avatar Andy Shevchenko Committed by Takashi Iwai
Browse files

ALSA: fm801: detect FM-only card earlier



If user does not supply tea575x_tuner parameter the driver tries to detect the
tuner type. The failed codec initialization is considered as FM-only card
present, however the driver still registers an IRQ handler for it.

Move codec detection earlier to set tea575x_tuner parameter before check.

Here the following functions are introduced
 reset_coded()                       resets AC97 codec
 snd_fm801_chip_multichannel_init()  initializes cards with multichannel support

Fixes: 5618955c (ALSA: fm801: move to pcim_* and devm_* functions)
Signed-off-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent dbec6719
Loading
Loading
Loading
Loading
+39 −30
Original line number Diff line number Diff line
@@ -1098,27 +1098,21 @@ static int wait_for_codec(struct fm801 *chip, unsigned int codec_id,
	return -EIO;
}

static int snd_fm801_chip_init(struct fm801 *chip, int resume)
static int reset_codec(struct fm801 *chip)
{
	unsigned short cmdw;

	if (chip->tea575x_tuner & TUNER_ONLY)
		goto __ac97_ok;

	/* codec cold reset + AC'97 warm reset */
	fm801_writew(chip, CODEC_CTRL, (1 << 5) | (1 << 6));
	fm801_readw(chip, CODEC_CTRL); /* flush posting data */
	udelay(100);
	fm801_writew(chip, CODEC_CTRL, 0);

	if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0)
		if (!resume) {
			dev_info(chip->card->dev,
				 "Primary AC'97 codec not found, assume SF64-PCR (tuner-only)\n");
			chip->tea575x_tuner = 3 | TUNER_ONLY;
			goto __ac97_ok;
	return wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750));
}

static void snd_fm801_chip_multichannel_init(struct fm801 *chip)
{
	unsigned short cmdw;

	if (chip->multichannel) {
		if (chip->secondary_addr) {
			wait_for_codec(chip, chip->secondary_addr,
@@ -1144,8 +1138,11 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume)
		/* cause timeout problems */
		wait_for_codec(chip, 0, AC97_VENDOR_ID1, msecs_to_jiffies(750));
	}
}

      __ac97_ok:
static void snd_fm801_chip_init(struct fm801 *chip)
{
	unsigned short cmdw;

	/* init volume */
	fm801_writew(chip, PCM_VOL, 0x0808);
@@ -1166,11 +1163,8 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume)
	/* interrupt clear */
	fm801_writew(chip, IRQ_STATUS,
		     FM801_IRQ_PLAYBACK | FM801_IRQ_CAPTURE | FM801_IRQ_MPU);

	return 0;
}


static int snd_fm801_free(struct fm801 *chip)
{
	unsigned short cmdw;
@@ -1227,7 +1221,23 @@ static int snd_fm801_create(struct snd_card *card,
	if ((err = pci_request_regions(pci, "FM801")) < 0)
		return err;
	chip->port = pci_resource_start(pci, 0);
	if ((tea575x_tuner & TUNER_ONLY) == 0) {

	if (pci->revision >= 0xb1)	/* FM801-AU */
		chip->multichannel = 1;

	if (!(chip->tea575x_tuner & TUNER_ONLY)) {
		if (reset_codec(chip) < 0) {
			dev_info(chip->card->dev,
				 "Primary AC'97 codec not found, assume SF64-PCR (tuner-only)\n");
			chip->tea575x_tuner = 3 | TUNER_ONLY;
		} else {
			snd_fm801_chip_multichannel_init(chip);
		}
	}

	snd_fm801_chip_init(chip);

	if ((chip->tea575x_tuner & TUNER_ONLY) == 0) {
		if (devm_request_irq(&pci->dev, pci->irq, snd_fm801_interrupt,
				IRQF_SHARED, KBUILD_MODNAME, chip)) {
			dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
@@ -1238,13 +1248,6 @@ static int snd_fm801_create(struct snd_card *card,
		pci_set_master(pci);
	}

	if (pci->revision >= 0xb1)	/* FM801-AU */
		chip->multichannel = 1;

	snd_fm801_chip_init(chip, 0);
	/* init might set tuner access method */
	tea575x_tuner = chip->tea575x_tuner;

	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
		snd_fm801_free(chip);
		return err;
@@ -1261,15 +1264,15 @@ static int snd_fm801_create(struct snd_card *card,
	chip->tea.private_data = chip;
	chip->tea.ops = &snd_fm801_tea_ops;
	sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci));
	if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 &&
	    (tea575x_tuner & TUNER_TYPE_MASK) < 4) {
	if ((chip->tea575x_tuner & TUNER_TYPE_MASK) > 0 &&
	    (chip->tea575x_tuner & TUNER_TYPE_MASK) < 4) {
		if (snd_tea575x_init(&chip->tea, THIS_MODULE)) {
			dev_err(card->dev, "TEA575x radio not found\n");
			snd_fm801_free(chip);
			return -ENODEV;
		}
	} else if ((tea575x_tuner & TUNER_TYPE_MASK) == 0) {
		unsigned int tuner_only = tea575x_tuner & TUNER_ONLY;
	} else if ((chip->tea575x_tuner & TUNER_TYPE_MASK) == 0) {
		unsigned int tuner_only = chip->tea575x_tuner & TUNER_ONLY;

		/* autodetect tuner connection */
		for (tea575x_tuner = 1; tea575x_tuner <= 3; tea575x_tuner++) {
@@ -1405,7 +1408,13 @@ static int snd_fm801_resume(struct device *dev)
	struct fm801 *chip = card->private_data;
	int i;

	snd_fm801_chip_init(chip, 1);
	if (chip->tea575x_tuner & TUNER_ONLY) {
		snd_fm801_chip_init(chip);
	} else {
		reset_codec(chip);
		snd_fm801_chip_multichannel_init(chip);
		snd_fm801_chip_init(chip);
	}
	snd_ac97_resume(chip->ac97);
	snd_ac97_resume(chip->ac97_sec);
	for (i = 0; i < ARRAY_SIZE(saved_regs); i++)