| // SPDX-License-Identifier: GPL-2.0-or-later |
| /* |
| * Copyright (c) by Jaroslav Kysela <perex@perex.cz> |
| * Routines for control of MPU-401 in UART mode |
| * |
| * Modified for the Aureal Vortex based Soundcards |
| * by Manuel Jander (mjande@embedded.cl). |
| */ |
| |
| #include <linux/time.h> |
| #include <linux/init.h> |
| #include <sound/core.h> |
| #include <sound/mpu401.h> |
| #include "au88x0.h" |
| |
| /* Check for mpu401 mmio support. */ |
| /* MPU401 legacy support is only provided as a emergency fallback * |
| * for older versions of ALSA. Its usage is strongly discouraged. */ |
| #ifndef MPU401_HW_AUREAL |
| #define VORTEX_MPU401_LEGACY |
| #endif |
| |
| /* Vortex MPU401 defines. */ |
| #define MIDI_CLOCK_DIV 0x61 |
| /* Standart MPU401 defines. */ |
| #define MPU401_RESET 0xff |
| #define MPU401_ENTER_UART 0x3f |
| #define MPU401_ACK 0xfe |
| |
| static int snd_vortex_midi(vortex_t *vortex) |
| { |
| struct snd_rawmidi *rmidi; |
| int temp, mode; |
| struct snd_mpu401 *mpu; |
| unsigned long port; |
| |
| #ifdef VORTEX_MPU401_LEGACY |
| /* EnableHardCodedMPU401Port() */ |
| /* Enable Legacy MIDI Interface port. */ |
| port = (0x03 << 5); /* FIXME: static address. 0x330 */ |
| temp = |
| (hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_PORT) | |
| CTRL_MIDI_EN | port; |
| hwwrite(vortex->mmio, VORTEX_CTRL, temp); |
| #else |
| /* Disable Legacy MIDI Interface port. */ |
| temp = |
| (hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_PORT) & |
| ~CTRL_MIDI_EN; |
| hwwrite(vortex->mmio, VORTEX_CTRL, temp); |
| #endif |
| /* Mpu401UartInit() */ |
| mode = 1; |
| temp = hwread(vortex->mmio, VORTEX_CTRL2) & 0xffff00cf; |
| temp |= (MIDI_CLOCK_DIV << 8) | ((mode >> 24) & 0xff) << 4; |
| hwwrite(vortex->mmio, VORTEX_CTRL2, temp); |
| hwwrite(vortex->mmio, VORTEX_MIDI_CMD, MPU401_RESET); |
| |
| /* Check if anything is OK. */ |
| temp = hwread(vortex->mmio, VORTEX_MIDI_DATA); |
| if (temp != MPU401_ACK /*0xfe */ ) { |
| dev_err(vortex->card->dev, "midi port doesn't acknowledge!\n"); |
| return -ENODEV; |
| } |
| /* Enable MPU401 interrupts. */ |
| hwwrite(vortex->mmio, VORTEX_IRQ_CTRL, |
| hwread(vortex->mmio, VORTEX_IRQ_CTRL) | IRQ_MIDI); |
| |
| /* Create MPU401 instance. */ |
| #ifdef VORTEX_MPU401_LEGACY |
| temp = snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_MPU401, 0x330, |
| MPU401_INFO_IRQ_HOOK, -1, &rmidi); |
| if (temp) { |
| hwwrite(vortex->mmio, VORTEX_CTRL, |
| (hwread(vortex->mmio, VORTEX_CTRL) & |
| ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN); |
| return temp; |
| } |
| #else |
| port = (unsigned long)(vortex->mmio + VORTEX_MIDI_DATA); |
| temp = snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_AUREAL, port, |
| MPU401_INFO_INTEGRATED | MPU401_INFO_MMIO | |
| MPU401_INFO_IRQ_HOOK, -1, &rmidi); |
| if (temp) { |
| hwwrite(vortex->mmio, VORTEX_CTRL, |
| (hwread(vortex->mmio, VORTEX_CTRL) & |
| ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN); |
| return temp; |
| } |
| mpu = rmidi->private_data; |
| mpu->cport = (unsigned long)(vortex->mmio + VORTEX_MIDI_CMD); |
| #endif |
| /* Overwrite MIDI name */ |
| snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI %d", CARD_NAME_SHORT , vortex->card->number); |
| |
| vortex->rmidi = rmidi; |
| return 0; |
| } |