18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 48c2ecf20Sopenharmony_ci * Routines for control of MPU-401 in UART mode 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Modified for the Aureal Vortex based Soundcards 78c2ecf20Sopenharmony_ci * by Manuel Jander (mjande@embedded.cl). 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/time.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <sound/core.h> 138c2ecf20Sopenharmony_ci#include <sound/mpu401.h> 148c2ecf20Sopenharmony_ci#include "au88x0.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/* Check for mpu401 mmio support. */ 178c2ecf20Sopenharmony_ci/* MPU401 legacy support is only provided as a emergency fallback * 188c2ecf20Sopenharmony_ci * for older versions of ALSA. Its usage is strongly discouraged. */ 198c2ecf20Sopenharmony_ci#ifndef MPU401_HW_AUREAL 208c2ecf20Sopenharmony_ci#define VORTEX_MPU401_LEGACY 218c2ecf20Sopenharmony_ci#endif 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* Vortex MPU401 defines. */ 248c2ecf20Sopenharmony_ci#define MIDI_CLOCK_DIV 0x61 258c2ecf20Sopenharmony_ci/* Standart MPU401 defines. */ 268c2ecf20Sopenharmony_ci#define MPU401_RESET 0xff 278c2ecf20Sopenharmony_ci#define MPU401_ENTER_UART 0x3f 288c2ecf20Sopenharmony_ci#define MPU401_ACK 0xfe 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic int snd_vortex_midi(vortex_t *vortex) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci struct snd_rawmidi *rmidi; 338c2ecf20Sopenharmony_ci int temp, mode; 348c2ecf20Sopenharmony_ci struct snd_mpu401 *mpu; 358c2ecf20Sopenharmony_ci unsigned long port; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#ifdef VORTEX_MPU401_LEGACY 388c2ecf20Sopenharmony_ci /* EnableHardCodedMPU401Port() */ 398c2ecf20Sopenharmony_ci /* Enable Legacy MIDI Interface port. */ 408c2ecf20Sopenharmony_ci port = (0x03 << 5); /* FIXME: static address. 0x330 */ 418c2ecf20Sopenharmony_ci temp = 428c2ecf20Sopenharmony_ci (hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_PORT) | 438c2ecf20Sopenharmony_ci CTRL_MIDI_EN | port; 448c2ecf20Sopenharmony_ci hwwrite(vortex->mmio, VORTEX_CTRL, temp); 458c2ecf20Sopenharmony_ci#else 468c2ecf20Sopenharmony_ci /* Disable Legacy MIDI Interface port. */ 478c2ecf20Sopenharmony_ci temp = 488c2ecf20Sopenharmony_ci (hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_PORT) & 498c2ecf20Sopenharmony_ci ~CTRL_MIDI_EN; 508c2ecf20Sopenharmony_ci hwwrite(vortex->mmio, VORTEX_CTRL, temp); 518c2ecf20Sopenharmony_ci#endif 528c2ecf20Sopenharmony_ci /* Mpu401UartInit() */ 538c2ecf20Sopenharmony_ci mode = 1; 548c2ecf20Sopenharmony_ci temp = hwread(vortex->mmio, VORTEX_CTRL2) & 0xffff00cf; 558c2ecf20Sopenharmony_ci temp |= (MIDI_CLOCK_DIV << 8) | ((mode >> 24) & 0xff) << 4; 568c2ecf20Sopenharmony_ci hwwrite(vortex->mmio, VORTEX_CTRL2, temp); 578c2ecf20Sopenharmony_ci hwwrite(vortex->mmio, VORTEX_MIDI_CMD, MPU401_RESET); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci /* Check if anything is OK. */ 608c2ecf20Sopenharmony_ci temp = hwread(vortex->mmio, VORTEX_MIDI_DATA); 618c2ecf20Sopenharmony_ci if (temp != MPU401_ACK /*0xfe */ ) { 628c2ecf20Sopenharmony_ci dev_err(vortex->card->dev, "midi port doesn't acknowledge!\n"); 638c2ecf20Sopenharmony_ci return -ENODEV; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci /* Enable MPU401 interrupts. */ 668c2ecf20Sopenharmony_ci hwwrite(vortex->mmio, VORTEX_IRQ_CTRL, 678c2ecf20Sopenharmony_ci hwread(vortex->mmio, VORTEX_IRQ_CTRL) | IRQ_MIDI); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* Create MPU401 instance. */ 708c2ecf20Sopenharmony_ci#ifdef VORTEX_MPU401_LEGACY 718c2ecf20Sopenharmony_ci if ((temp = 728c2ecf20Sopenharmony_ci snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_MPU401, 0x330, 738c2ecf20Sopenharmony_ci MPU401_INFO_IRQ_HOOK, -1, &rmidi)) != 0) { 748c2ecf20Sopenharmony_ci hwwrite(vortex->mmio, VORTEX_CTRL, 758c2ecf20Sopenharmony_ci (hwread(vortex->mmio, VORTEX_CTRL) & 768c2ecf20Sopenharmony_ci ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN); 778c2ecf20Sopenharmony_ci return temp; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci#else 808c2ecf20Sopenharmony_ci port = (unsigned long)(vortex->mmio + VORTEX_MIDI_DATA); 818c2ecf20Sopenharmony_ci if ((temp = 828c2ecf20Sopenharmony_ci snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_AUREAL, port, 838c2ecf20Sopenharmony_ci MPU401_INFO_INTEGRATED | MPU401_INFO_MMIO | 848c2ecf20Sopenharmony_ci MPU401_INFO_IRQ_HOOK, -1, &rmidi)) != 0) { 858c2ecf20Sopenharmony_ci hwwrite(vortex->mmio, VORTEX_CTRL, 868c2ecf20Sopenharmony_ci (hwread(vortex->mmio, VORTEX_CTRL) & 878c2ecf20Sopenharmony_ci ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN); 888c2ecf20Sopenharmony_ci return temp; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci mpu = rmidi->private_data; 918c2ecf20Sopenharmony_ci mpu->cport = (unsigned long)(vortex->mmio + VORTEX_MIDI_CMD); 928c2ecf20Sopenharmony_ci#endif 938c2ecf20Sopenharmony_ci /* Overwrite MIDI name */ 948c2ecf20Sopenharmony_ci snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI %d", CARD_NAME_SHORT , vortex->card->number); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci vortex->rmidi = rmidi; 978c2ecf20Sopenharmony_ci return 0; 988c2ecf20Sopenharmony_ci} 99