Commit 6b844f06 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

Merge branch 'topic/emu10k1-fix' into for-next



Pull emu10k1 fixes from Oswald Buddenhagen

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parents 078c95fe 1aa41272
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -1692,8 +1692,8 @@ struct snd_emu1010 {
	unsigned int clock_fallback;
	unsigned int optical_in; /* 0:SPDIF, 1:ADAT */
	unsigned int optical_out; /* 0:SPDIF, 1:ADAT */
	struct work_struct firmware_work;
	struct work_struct clock_work;
	struct work_struct work;
	struct mutex lock;
};

struct snd_emu10k1 {
@@ -1842,12 +1842,16 @@ unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, unsigned int reg,
void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data);
int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, unsigned int data);
int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, u32 reg, u32 value);
static inline void snd_emu1010_fpga_lock(struct snd_emu10k1 *emu) { mutex_lock(&emu->emu1010.lock); };
static inline void snd_emu1010_fpga_unlock(struct snd_emu10k1 *emu) { mutex_unlock(&emu->emu1010.lock); };
void snd_emu1010_fpga_write_lock(struct snd_emu10k1 *emu, u32 reg, u32 value);
void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value);
void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value);
void snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 *emu, u32 dst, u32 src);
u32 snd_emu1010_fpga_link_dst_src_read(struct snd_emu10k1 *emu, u32 dst);
int snd_emu1010_get_raw_rate(struct snd_emu10k1 *emu, u8 src);
void snd_emu1010_update_clock(struct snd_emu10k1 *emu);
void snd_emu1010_load_firmware_entry(struct snd_emu10k1 *emu, int dock, const struct firmware *fw_entry);
unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc);
void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb);
void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb);
+1 −1
Original line number Diff line number Diff line
@@ -428,7 +428,7 @@ static int cvt_ump_midi2_to_midi1(struct snd_seq_client *dest,
	midi1->note.group = midi2->note.group;
	midi1->note.status = midi2->note.status;
	midi1->note.channel = midi2->note.channel;
	switch (midi2->note.status << 4) {
	switch (midi2->note.status) {
	case UMP_MSG_STATUS_NOTE_ON:
	case UMP_MSG_STATUS_NOTE_OFF:
		midi1->note.note = midi2->note.note;
+1 −2
Original line number Diff line number Diff line
@@ -189,8 +189,7 @@ static int snd_emu10k1_suspend(struct device *dev)

	emu->suspend = 1;

	cancel_work_sync(&emu->emu1010.firmware_work);
	cancel_work_sync(&emu->emu1010.clock_work);
	cancel_work_sync(&emu->emu1010.work);

	snd_ac97_suspend(emu->ac97);

+91 −134
Original line number Diff line number Diff line
@@ -652,52 +652,6 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 *emu)
	return 0;
}

static int snd_emu1010_load_firmware_entry(struct snd_emu10k1 *emu,
				     const struct firmware *fw_entry)
{
	int n, i;
	u16 reg;
	u8 value;
	__always_unused u16 write_post;

	if (!fw_entry)
		return -EIO;

	/* The FPGA is a Xilinx Spartan IIE XC2S50E */
	/* On E-MU 0404b it is a Xilinx Spartan III XC3S50 */
	/* GPIO7 -> FPGA PGMN
	 * GPIO6 -> FPGA CCLK
	 * GPIO5 -> FPGA DIN
	 * FPGA CONFIG OFF -> FPGA PGMN
	 */
	spin_lock_irq(&emu->emu_lock);
	outw(0x00, emu->port + A_GPIO); /* Set PGMN low for 100uS. */
	write_post = inw(emu->port + A_GPIO);
	udelay(100);
	outw(0x80, emu->port + A_GPIO); /* Leave bit 7 set during netlist setup. */
	write_post = inw(emu->port + A_GPIO);
	udelay(100); /* Allow FPGA memory to clean */
	for (n = 0; n < fw_entry->size; n++) {
		value = fw_entry->data[n];
		for (i = 0; i < 8; i++) {
			reg = 0x80;
			if (value & 0x1)
				reg = reg | 0x20;
			value = value >> 1;
			outw(reg, emu->port + A_GPIO);
			write_post = inw(emu->port + A_GPIO);
			outw(reg | 0x40, emu->port + A_GPIO);
			write_post = inw(emu->port + A_GPIO);
		}
	}
	/* After programming, set GPIO bit 4 high again. */
	outw(0x10, emu->port + A_GPIO);
	write_post = inw(emu->port + A_GPIO);
	spin_unlock_irq(&emu->emu_lock);

	return 0;
}

/* firmware file names, per model, init-fw and dock-fw (optional) */
static const char * const firmware_names[5][2] = {
	[EMU_MODEL_EMU1010] = {
@@ -729,72 +683,68 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, int dock,
			return err;
	}

	return snd_emu1010_load_firmware_entry(emu, *fw);
	snd_emu1010_load_firmware_entry(emu, dock, *fw);
	return 0;
}

static void emu1010_firmware_work(struct work_struct *work)
static void snd_emu1010_load_dock_firmware(struct snd_emu10k1 *emu)
{
	struct snd_emu10k1 *emu;
	u32 tmp, tmp2, reg;
	u32 tmp, tmp2;
	int err;

	emu = container_of(work, struct snd_emu10k1,
			   emu1010.firmware_work);
	if (emu->card->shutdown)
		return;
#ifdef CONFIG_PM_SLEEP
	if (emu->suspend)
		return;
#endif
	snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg); /* OPTIONS: Which cards are attached to the EMU */
	if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) {
		/* Audio Dock attached */
		/* Return to Audio Dock programming mode */
		dev_info(emu->card->dev,
			 "emu1010: Loading Audio Dock Firmware\n");
		snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG,
				       EMU_HANA_FPGA_CONFIG_AUDIODOCK);
	// The docking events clearly arrive prematurely - while the
	// Dock's FPGA seems to be successfully programmed, the Dock
	// fails to initialize subsequently if we don't give it some
	// time to "warm up" here.
	msleep(200);

	dev_info(emu->card->dev, "emu1010: Loading Audio Dock Firmware\n");
	err = snd_emu1010_load_firmware(emu, 1, &emu->dock_fw);
	if (err < 0)
		return;
	snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0);

	snd_emu1010_fpga_read(emu, EMU_HANA_ID, &tmp);
		dev_info(emu->card->dev,
			 "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", tmp);
	dev_dbg(emu->card->dev, "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", tmp);
	if ((tmp & 0x1f) != 0x15) {
		/* FPGA failed to be programmed */
			dev_info(emu->card->dev,
				 "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n",
		dev_err(emu->card->dev,
			"emu1010: Loading Audio Dock Firmware failed, reg = 0x%x\n",
			tmp);
		return;
	}
		dev_info(emu->card->dev,
			 "emu1010: Audio Dock Firmware loaded\n");
	dev_info(emu->card->dev, "emu1010: Audio Dock Firmware loaded\n");

	snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp);
	snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2);
	dev_info(emu->card->dev, "Audio Dock ver: %u.%u\n", tmp, tmp2);
		/* Sync clocking between 1010 and Dock */
		/* Allow DLL to settle */

	/* Allow DLL to settle, to sync clocking between 1010 and Dock */
	msleep(10);
}

static void emu1010_dock_event(struct snd_emu10k1 *emu)
{
	u32 reg;

	snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg); /* OPTIONS: Which cards are attached to the EMU */
	if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) {
		/* Audio Dock attached */
		snd_emu1010_load_dock_firmware(emu);
		/* Unmute all. Default is muted after a firmware load */
		snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
	} else if (!(reg & EMU_HANA_OPTION_DOCK_ONLINE)) {
		/* Audio Dock removed */
		dev_info(emu->card->dev, "emu1010: Audio Dock detached\n");
		/* The hardware auto-mutes all, so we unmute again */
		snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
	}
}

static void emu1010_clock_work(struct work_struct *work)
static void emu1010_clock_event(struct snd_emu10k1 *emu)
{
	struct snd_emu10k1 *emu;
	struct snd_ctl_elem_id id;

	emu = container_of(work, struct snd_emu10k1,
			   emu1010.clock_work);
	if (emu->card->shutdown)
		return;
#ifdef CONFIG_PM_SLEEP
	if (emu->suspend)
		return;
#endif

	spin_lock_irq(&emu->reg_lock);
	// This is the only thing that can actually happen.
	emu->emu1010.clock_source = emu->emu1010.clock_fallback;
@@ -805,21 +755,44 @@ static void emu1010_clock_work(struct work_struct *work)
	snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
}

static void emu1010_interrupt(struct snd_emu10k1 *emu)
static void emu1010_work(struct work_struct *work)
{
	struct snd_emu10k1 *emu;
	u32 sts;

	emu = container_of(work, struct snd_emu10k1, emu1010.work);
	if (emu->card->shutdown)
		return;
#ifdef CONFIG_PM_SLEEP
	if (emu->suspend)
		return;
#endif

	snd_emu1010_fpga_lock(emu);

	snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &sts);
	if (sts & EMU_HANA_IRQ_DOCK_LOST) {
		/* Audio Dock removed */
		dev_info(emu->card->dev, "emu1010: Audio Dock detached\n");
		/* The hardware auto-mutes all, so we unmute again */
		snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
	} else if (sts & EMU_HANA_IRQ_DOCK) {
		schedule_work(&emu->emu1010.firmware_work);
	}

	// The distinction of the IRQ status bits is unreliable,
	// so we dispatch later based on option card status.
	if (sts & (EMU_HANA_IRQ_DOCK | EMU_HANA_IRQ_DOCK_LOST))
		emu1010_dock_event(emu);

	if (sts & EMU_HANA_IRQ_WCLK_CHANGED)
		schedule_work(&emu->emu1010.clock_work);
		emu1010_clock_event(emu);

	snd_emu1010_fpga_unlock(emu);
}

static void emu1010_interrupt(struct snd_emu10k1 *emu)
{
	// We get an interrupt on each GPIO input pin change, but we
	// care only about the ones triggered by the dedicated pin.
	u16 sts = inw(emu->port + A_GPIO);
	u16 bit = emu->card_capabilities->ca0108_chip ? 0x2000 : 0x8000;
	if (!(sts & bit))
		return;

	schedule_work(&emu->emu1010.work);
}

/*
@@ -841,32 +814,13 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
	 * Proper init follows in snd_emu10k1_init(). */
	outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);

	/* Disable 48Volt power to Audio Dock */
	snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0);

	/* ID, should read & 0x7f = 0x55. (Bit 7 is the IRQ bit) */
	snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg);
	dev_dbg(emu->card->dev, "reg1 = 0x%x\n", reg);
	if ((reg & 0x3f) == 0x15) {
		/* FPGA netlist already present so clear it */
		/* Return to programming mode */

		snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_HANA);
	}
	snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg);
	dev_dbg(emu->card->dev, "reg2 = 0x%x\n", reg);
	if ((reg & 0x3f) == 0x15) {
		/* FPGA failed to return to programming mode */
		dev_info(emu->card->dev,
			 "emu1010: FPGA failed to return to programming mode\n");
		return -ENODEV;
	}
	dev_info(emu->card->dev, "emu1010: EMU_HANA_ID = 0x%x\n", reg);
	snd_emu1010_fpga_lock(emu);

	dev_info(emu->card->dev, "emu1010: Loading Hana Firmware\n");
	err = snd_emu1010_load_firmware(emu, 0, &emu->firmware);
	if (err < 0) {
		dev_info(emu->card->dev, "emu1010: Loading Firmware failed\n");
		return err;
		goto fail;
	}

	/* ID, should read & 0x7f = 0x55 when FPGA programmed. */
@@ -876,7 +830,8 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
		dev_info(emu->card->dev,
			 "emu1010: Loading Hana Firmware file failed, reg = 0x%x\n",
			 reg);
		return -ENODEV;
		err = -ENODEV;
		goto fail;
	}

	dev_info(emu->card->dev, "emu1010: Hana Firmware loaded\n");
@@ -889,7 +844,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
	snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg);
	dev_info(emu->card->dev, "emu1010: Card options = 0x%x\n", reg);
	if (reg & EMU_HANA_OPTION_DOCK_OFFLINE)
		schedule_work(&emu->emu1010.firmware_work);
		snd_emu1010_load_dock_firmware(emu);
	if (emu->card_capabilities->no_adat) {
		emu->emu1010.optical_in = 0; /* IN_SPDIF */
		emu->emu1010.optical_out = 0; /* OUT_SPDIF */
@@ -936,7 +891,9 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
	// so it is safe to simply enable the outputs.
	snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);

	return 0;
fail:
	snd_emu1010_fpga_unlock(emu);
	return err;
}
/*
 *  Create the EMU10K1 instance
@@ -958,10 +915,10 @@ static void snd_emu10k1_free(struct snd_card *card)
	}
	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) {
		/* Disable 48Volt power to Audio Dock */
		snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0);
		snd_emu1010_fpga_write_lock(emu, EMU_HANA_DOCK_PWR, 0);
	}
	cancel_work_sync(&emu->emu1010.firmware_work);
	cancel_work_sync(&emu->emu1010.clock_work);
	cancel_work_sync(&emu->emu1010.work);
	mutex_destroy(&emu->emu1010.lock);
	release_firmware(emu->firmware);
	release_firmware(emu->dock_fw);
	snd_util_memhdr_free(emu->memhdr);
@@ -1540,8 +1497,8 @@ int snd_emu10k1_create(struct snd_card *card,
	emu->irq = -1;
	emu->synth = NULL;
	emu->get_synth_voice = NULL;
	INIT_WORK(&emu->emu1010.firmware_work, emu1010_firmware_work);
	INIT_WORK(&emu->emu1010.clock_work, emu1010_clock_work);
	INIT_WORK(&emu->emu1010.work, emu1010_work);
	mutex_init(&emu->emu1010.lock);
	/* read revision & serial */
	emu->revision = pci->revision;
	pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial);
+13 −5
Original line number Diff line number Diff line
@@ -661,7 +661,9 @@ static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
	change = (emu->emu1010.output_source[channel] != val);
	if (change) {
		emu->emu1010.output_source[channel] = val;
		snd_emu1010_fpga_lock(emu);
		snd_emu1010_output_source_apply(emu, channel, val);
		snd_emu1010_fpga_unlock(emu);
	}
	return change;
}
@@ -705,7 +707,9 @@ static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
	change = (emu->emu1010.input_source[channel] != val);
	if (change) {
		emu->emu1010.input_source[channel] = val;
		snd_emu1010_fpga_lock(emu);
		snd_emu1010_input_source_apply(emu, channel, val);
		snd_emu1010_fpga_unlock(emu);
	}
	return change;
}
@@ -774,7 +778,7 @@ static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ct
		cache = cache & ~mask;
	change = (cache != emu->emu1010.adc_pads);
	if (change) {
		snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
		snd_emu1010_fpga_write_lock(emu, EMU_HANA_ADC_PADS, cache );
	        emu->emu1010.adc_pads = cache;
	}

@@ -832,7 +836,7 @@ static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ct
		cache = cache & ~mask;
	change = (cache != emu->emu1010.dac_pads);
	if (change) {
		snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
		snd_emu1010_fpga_write_lock(emu, EMU_HANA_DAC_PADS, cache );
	        emu->emu1010.dac_pads = cache;
	}

@@ -980,6 +984,7 @@ static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol,
	val = ucontrol->value.enumerated.item[0] ;
	if (val >= emu_ci->num)
		return -EINVAL;
	snd_emu1010_fpga_lock(emu);
	spin_lock_irq(&emu->reg_lock);
	change = (emu->emu1010.clock_source != val);
	if (change) {
@@ -996,6 +1001,7 @@ static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol,
	} else {
		spin_unlock_irq(&emu->reg_lock);
	}
	snd_emu1010_fpga_unlock(emu);
	return change;
}

@@ -1041,7 +1047,7 @@ static int snd_emu1010_clock_fallback_put(struct snd_kcontrol *kcontrol,
	change = (emu->emu1010.clock_fallback != val);
	if (change) {
		emu->emu1010.clock_fallback = val;
		snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 1 - val);
		snd_emu1010_fpga_write_lock(emu, EMU_HANA_DEFCLOCK, 1 - val);
	}
	return change;
}
@@ -1093,7 +1099,7 @@ static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol,
		emu->emu1010.optical_out = val;
		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
		snd_emu1010_fpga_write_lock(emu, EMU_HANA_OPTICAL_TYPE, tmp);
	}
	return change;
}
@@ -1144,7 +1150,7 @@ static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol,
		emu->emu1010.optical_in = val;
		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
		snd_emu1010_fpga_write_lock(emu, EMU_HANA_OPTICAL_TYPE, tmp);
	}
	return change;
}
@@ -2323,7 +2329,9 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
		for (i = 0; i < emu_ri->n_outs; i++)
			emu->emu1010.output_source[i] =
				emu1010_map_source(emu_ri, emu_ri->out_dflts[i]);
		snd_emu1010_fpga_lock(emu);
		snd_emu1010_apply_sources(emu);
		snd_emu1010_fpga_unlock(emu);

		kctl = emu->ctl_clock_source = snd_ctl_new1(&snd_emu1010_clock_source, emu);
		err = snd_ctl_add(card, kctl);
Loading