void (*update_dac_volume)(struct oxygen *chip);
void (*update_dac_mute)(struct oxygen *chip);
void (*gpio_changed)(struct oxygen *chip);
+ void (*uart_input)(struct oxygen *chip);
void (*ac97_switch)(struct oxygen *chip,
unsigned int reg, unsigned int mute);
const unsigned int *dac_tlv;
__le32 _32[OXYGEN_IO_SIZE / 4];
} saved_registers;
u16 saved_ac97_registers[2][0x40];
+ unsigned int uart_input_count;
+ u8 uart_input[32];
struct oxygen_model model;
};
void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data);
void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data);
+void oxygen_reset_uart(struct oxygen *chip);
+void oxygen_write_uart(struct oxygen *chip, u8 data);
+
static inline void oxygen_set_bits8(struct oxygen *chip,
unsigned int reg, u8 value)
{
#include <linux/delay.h>
#include <linux/sched.h>
#include <sound/core.h>
+#include <sound/mpu401.h>
#include <asm/io.h>
#include "oxygen.h"
device | OXYGEN_2WIRE_DIR_WRITE);
}
EXPORT_SYMBOL(oxygen_write_i2c);
+
+static void _write_uart(struct oxygen *chip, unsigned int port, u8 data)
+{
+ if (oxygen_read8(chip, OXYGEN_MPU401 + 1) & MPU401_TX_FULL)
+ msleep(1);
+ oxygen_write8(chip, OXYGEN_MPU401 + port, data);
+}
+
+void oxygen_reset_uart(struct oxygen *chip)
+{
+ _write_uart(chip, 1, MPU401_RESET);
+ _write_uart(chip, 1, MPU401_ENTER_UART);
+}
+EXPORT_SYMBOL(oxygen_reset_uart);
+
+void oxygen_write_uart(struct oxygen *chip, u8 data)
+{
+ _write_uart(chip, 0, data);
+}
+EXPORT_SYMBOL(oxygen_write_uart);
MODULE_LICENSE("GPL v2");
+static inline int oxygen_uart_input_ready(struct oxygen *chip)
+{
+ return !(oxygen_read8(chip, OXYGEN_MPU401 + 1) & MPU401_RX_EMPTY);
+}
+
+static void oxygen_read_uart(struct oxygen *chip)
+{
+ if (unlikely(!oxygen_uart_input_ready(chip))) {
+ /* no data, but read it anyway to clear the interrupt */
+ oxygen_read8(chip, OXYGEN_MPU401);
+ return;
+ }
+ do {
+ u8 data = oxygen_read8(chip, OXYGEN_MPU401);
+ if (data == MPU401_ACK)
+ continue;
+ if (chip->uart_input_count >= ARRAY_SIZE(chip->uart_input))
+ chip->uart_input_count = 0;
+ chip->uart_input[chip->uart_input_count++] = data;
+ } while (oxygen_uart_input_ready(chip));
+ if (chip->model.uart_input)
+ chip->model.uart_input(chip);
+}
+
static irqreturn_t oxygen_interrupt(int dummy, void *dev_id)
{
struct oxygen *chip = dev_id;
if (status & OXYGEN_INT_GPIO)
schedule_work(&chip->gpio_work);
- if ((status & OXYGEN_INT_MIDI) && chip->midi)
- snd_mpu401_uart_interrupt(0, chip->midi->private_data);
+ if (status & OXYGEN_INT_MIDI) {
+ if (chip->midi)
+ snd_mpu401_uart_interrupt(0, chip->midi->private_data);
+ else
+ oxygen_read_uart(chip);
+ }
if (status & OXYGEN_INT_AC97)
wake_up(&chip->ac97_waitqueue);