1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> |
4 | * Routines for control of MPU-401 in UART mode |
5 | * |
6 | * Modified for the Aureal Vortex based Soundcards |
7 | * by Manuel Jander (mjande@embedded.cl). |
8 | */ |
9 | |
10 | #include <linux/time.h> |
11 | #include <linux/init.h> |
12 | #include <sound/core.h> |
13 | #include <sound/mpu401.h> |
14 | #include "au88x0.h" |
15 | |
16 | /* Check for mpu401 mmio support. */ |
17 | /* MPU401 legacy support is only provided as a emergency fallback * |
18 | * for older versions of ALSA. Its usage is strongly discouraged. */ |
19 | #ifndef MPU401_HW_AUREAL |
20 | #define VORTEX_MPU401_LEGACY |
21 | #endif |
22 | |
23 | /* Vortex MPU401 defines. */ |
24 | #define MIDI_CLOCK_DIV 0x61 |
25 | /* Standart MPU401 defines. */ |
26 | #define MPU401_RESET 0xff |
27 | #define MPU401_ENTER_UART 0x3f |
28 | #define MPU401_ACK 0xfe |
29 | |
30 | static int snd_vortex_midi(vortex_t *vortex) |
31 | { |
32 | struct snd_rawmidi *rmidi; |
33 | int temp, mode; |
34 | struct snd_mpu401 *mpu; |
35 | unsigned long port; |
36 | |
37 | #ifdef VORTEX_MPU401_LEGACY |
38 | /* EnableHardCodedMPU401Port() */ |
39 | /* Enable Legacy MIDI Interface port. */ |
40 | port = (0x03 << 5); /* FIXME: static address. 0x330 */ |
41 | temp = |
42 | (hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_PORT) | |
43 | CTRL_MIDI_EN | port; |
44 | hwwrite(vortex->mmio, VORTEX_CTRL, temp); |
45 | #else |
46 | /* Disable Legacy MIDI Interface port. */ |
47 | temp = |
48 | (hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_PORT) & |
49 | ~CTRL_MIDI_EN; |
50 | hwwrite(vortex->mmio, VORTEX_CTRL, temp); |
51 | #endif |
52 | /* Mpu401UartInit() */ |
53 | mode = 1; |
54 | temp = hwread(vortex->mmio, VORTEX_CTRL2) & 0xffff00cf; |
55 | temp |= (MIDI_CLOCK_DIV << 8) | ((mode >> 24) & 0xff) << 4; |
56 | hwwrite(vortex->mmio, VORTEX_CTRL2, temp); |
57 | hwwrite(vortex->mmio, VORTEX_MIDI_CMD, MPU401_RESET); |
58 | |
59 | /* Check if anything is OK. */ |
60 | temp = hwread(vortex->mmio, VORTEX_MIDI_DATA); |
61 | if (temp != MPU401_ACK /*0xfe */ ) { |
62 | dev_err(vortex->card->dev, "midi port doesn't acknowledge!\n" ); |
63 | return -ENODEV; |
64 | } |
65 | /* Enable MPU401 interrupts. */ |
66 | hwwrite(vortex->mmio, VORTEX_IRQ_CTRL, |
67 | hwread(vortex->mmio, VORTEX_IRQ_CTRL) | IRQ_MIDI); |
68 | |
69 | /* Create MPU401 instance. */ |
70 | #ifdef VORTEX_MPU401_LEGACY |
71 | temp = snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_MPU401, 0x330, |
72 | MPU401_INFO_IRQ_HOOK, -1, &rmidi); |
73 | if (temp) { |
74 | hwwrite(vortex->mmio, VORTEX_CTRL, |
75 | (hwread(vortex->mmio, VORTEX_CTRL) & |
76 | ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN); |
77 | return temp; |
78 | } |
79 | #else |
80 | port = (unsigned long)(vortex->mmio + VORTEX_MIDI_DATA); |
81 | temp = snd_mpu401_uart_new(card: vortex->card, device: 0, MPU401_HW_AUREAL, port, |
82 | MPU401_INFO_INTEGRATED | MPU401_INFO_MMIO | |
83 | MPU401_INFO_IRQ_HOOK, irq: -1, rrawmidi: &rmidi); |
84 | if (temp) { |
85 | hwwrite(vortex->mmio, VORTEX_CTRL, |
86 | (hwread(vortex->mmio, VORTEX_CTRL) & |
87 | ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN); |
88 | return temp; |
89 | } |
90 | mpu = rmidi->private_data; |
91 | mpu->cport = (unsigned long)(vortex->mmio + VORTEX_MIDI_CMD); |
92 | #endif |
93 | /* Overwrite MIDI name */ |
94 | snprintf(buf: rmidi->name, size: sizeof(rmidi->name), fmt: "%s MIDI %d" , CARD_NAME_SHORT , vortex->card->number); |
95 | |
96 | vortex->rmidi = rmidi; |
97 | return 0; |
98 | } |
99 | |