From b56fa687e02b27f8bd9d282950a88c2ed23d766b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 21 Dec 2015 19:09:53 +0200 Subject: [PATCH] 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: 5618955c4269 (ALSA: fm801: move to pcim_* and devm_* functions) Signed-off-by: Andy Shevchenko Signed-off-by: Takashi Iwai --- sound/pci/fm801.c | 69 ++++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 63025b8925f5..294fc131aee0 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -1098,26 +1098,20 @@ 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) { @@ -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++) -- 2.20.1