162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 462306a36Sopenharmony_ci * Routines for control of MPU-401 in UART mode 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Modified for the Aureal Vortex based Soundcards 762306a36Sopenharmony_ci * by Manuel Jander (mjande@embedded.cl). 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/time.h> 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <sound/core.h> 1362306a36Sopenharmony_ci#include <sound/mpu401.h> 1462306a36Sopenharmony_ci#include "au88x0.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/* Check for mpu401 mmio support. */ 1762306a36Sopenharmony_ci/* MPU401 legacy support is only provided as a emergency fallback * 1862306a36Sopenharmony_ci * for older versions of ALSA. Its usage is strongly discouraged. */ 1962306a36Sopenharmony_ci#ifndef MPU401_HW_AUREAL 2062306a36Sopenharmony_ci#define VORTEX_MPU401_LEGACY 2162306a36Sopenharmony_ci#endif 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* Vortex MPU401 defines. */ 2462306a36Sopenharmony_ci#define MIDI_CLOCK_DIV 0x61 2562306a36Sopenharmony_ci/* Standart MPU401 defines. */ 2662306a36Sopenharmony_ci#define MPU401_RESET 0xff 2762306a36Sopenharmony_ci#define MPU401_ENTER_UART 0x3f 2862306a36Sopenharmony_ci#define MPU401_ACK 0xfe 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic int snd_vortex_midi(vortex_t *vortex) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci struct snd_rawmidi *rmidi; 3362306a36Sopenharmony_ci int temp, mode; 3462306a36Sopenharmony_ci struct snd_mpu401 *mpu; 3562306a36Sopenharmony_ci unsigned long port; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#ifdef VORTEX_MPU401_LEGACY 3862306a36Sopenharmony_ci /* EnableHardCodedMPU401Port() */ 3962306a36Sopenharmony_ci /* Enable Legacy MIDI Interface port. */ 4062306a36Sopenharmony_ci port = (0x03 << 5); /* FIXME: static address. 0x330 */ 4162306a36Sopenharmony_ci temp = 4262306a36Sopenharmony_ci (hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_PORT) | 4362306a36Sopenharmony_ci CTRL_MIDI_EN | port; 4462306a36Sopenharmony_ci hwwrite(vortex->mmio, VORTEX_CTRL, temp); 4562306a36Sopenharmony_ci#else 4662306a36Sopenharmony_ci /* Disable Legacy MIDI Interface port. */ 4762306a36Sopenharmony_ci temp = 4862306a36Sopenharmony_ci (hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_PORT) & 4962306a36Sopenharmony_ci ~CTRL_MIDI_EN; 5062306a36Sopenharmony_ci hwwrite(vortex->mmio, VORTEX_CTRL, temp); 5162306a36Sopenharmony_ci#endif 5262306a36Sopenharmony_ci /* Mpu401UartInit() */ 5362306a36Sopenharmony_ci mode = 1; 5462306a36Sopenharmony_ci temp = hwread(vortex->mmio, VORTEX_CTRL2) & 0xffff00cf; 5562306a36Sopenharmony_ci temp |= (MIDI_CLOCK_DIV << 8) | ((mode >> 24) & 0xff) << 4; 5662306a36Sopenharmony_ci hwwrite(vortex->mmio, VORTEX_CTRL2, temp); 5762306a36Sopenharmony_ci hwwrite(vortex->mmio, VORTEX_MIDI_CMD, MPU401_RESET); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci /* Check if anything is OK. */ 6062306a36Sopenharmony_ci temp = hwread(vortex->mmio, VORTEX_MIDI_DATA); 6162306a36Sopenharmony_ci if (temp != MPU401_ACK /*0xfe */ ) { 6262306a36Sopenharmony_ci dev_err(vortex->card->dev, "midi port doesn't acknowledge!\n"); 6362306a36Sopenharmony_ci return -ENODEV; 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci /* Enable MPU401 interrupts. */ 6662306a36Sopenharmony_ci hwwrite(vortex->mmio, VORTEX_IRQ_CTRL, 6762306a36Sopenharmony_ci hwread(vortex->mmio, VORTEX_IRQ_CTRL) | IRQ_MIDI); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci /* Create MPU401 instance. */ 7062306a36Sopenharmony_ci#ifdef VORTEX_MPU401_LEGACY 7162306a36Sopenharmony_ci temp = snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_MPU401, 0x330, 7262306a36Sopenharmony_ci MPU401_INFO_IRQ_HOOK, -1, &rmidi); 7362306a36Sopenharmony_ci if (temp) { 7462306a36Sopenharmony_ci hwwrite(vortex->mmio, VORTEX_CTRL, 7562306a36Sopenharmony_ci (hwread(vortex->mmio, VORTEX_CTRL) & 7662306a36Sopenharmony_ci ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN); 7762306a36Sopenharmony_ci return temp; 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci#else 8062306a36Sopenharmony_ci port = (unsigned long)(vortex->mmio + VORTEX_MIDI_DATA); 8162306a36Sopenharmony_ci temp = snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_AUREAL, port, 8262306a36Sopenharmony_ci MPU401_INFO_INTEGRATED | MPU401_INFO_MMIO | 8362306a36Sopenharmony_ci MPU401_INFO_IRQ_HOOK, -1, &rmidi); 8462306a36Sopenharmony_ci if (temp) { 8562306a36Sopenharmony_ci hwwrite(vortex->mmio, VORTEX_CTRL, 8662306a36Sopenharmony_ci (hwread(vortex->mmio, VORTEX_CTRL) & 8762306a36Sopenharmony_ci ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN); 8862306a36Sopenharmony_ci return temp; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci mpu = rmidi->private_data; 9162306a36Sopenharmony_ci mpu->cport = (unsigned long)(vortex->mmio + VORTEX_MIDI_CMD); 9262306a36Sopenharmony_ci#endif 9362306a36Sopenharmony_ci /* Overwrite MIDI name */ 9462306a36Sopenharmony_ci snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI %d", CARD_NAME_SHORT , vortex->card->number); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci vortex->rmidi = rmidi; 9762306a36Sopenharmony_ci return 0; 9862306a36Sopenharmony_ci} 99