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