Commit 397b1dcc authored by Clemens Ladisch's avatar Clemens Ladisch

ALSA: oxygen: add UART I/O functions

Add functions to allow model drivers to communicate with external chips
by doing I/O with the not-used-for-MIDI UART.
Signed-off-by: default avatarClemens Ladisch <clemens@ladisch.de>
parent dbbbd674
...@@ -79,6 +79,7 @@ struct oxygen_model { ...@@ -79,6 +79,7 @@ struct oxygen_model {
void (*update_dac_volume)(struct oxygen *chip); void (*update_dac_volume)(struct oxygen *chip);
void (*update_dac_mute)(struct oxygen *chip); void (*update_dac_mute)(struct oxygen *chip);
void (*gpio_changed)(struct oxygen *chip); void (*gpio_changed)(struct oxygen *chip);
void (*uart_input)(struct oxygen *chip);
void (*ac97_switch)(struct oxygen *chip, void (*ac97_switch)(struct oxygen *chip,
unsigned int reg, unsigned int mute); unsigned int reg, unsigned int mute);
const unsigned int *dac_tlv; const unsigned int *dac_tlv;
...@@ -125,6 +126,8 @@ struct oxygen { ...@@ -125,6 +126,8 @@ struct oxygen {
__le32 _32[OXYGEN_IO_SIZE / 4]; __le32 _32[OXYGEN_IO_SIZE / 4];
} saved_registers; } saved_registers;
u16 saved_ac97_registers[2][0x40]; u16 saved_ac97_registers[2][0x40];
unsigned int uart_input_count;
u8 uart_input[32];
struct oxygen_model model; struct oxygen_model model;
}; };
...@@ -174,6 +177,9 @@ void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec, ...@@ -174,6 +177,9 @@ void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec,
void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data); 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_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, static inline void oxygen_set_bits8(struct oxygen *chip,
unsigned int reg, u8 value) unsigned int reg, u8 value)
{ {
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/mpu401.h>
#include <asm/io.h> #include <asm/io.h>
#include "oxygen.h" #include "oxygen.h"
...@@ -232,3 +233,23 @@ void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data) ...@@ -232,3 +233,23 @@ void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data)
device | OXYGEN_2WIRE_DIR_WRITE); device | OXYGEN_2WIRE_DIR_WRITE);
} }
EXPORT_SYMBOL(oxygen_write_i2c); 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);
...@@ -35,6 +35,30 @@ MODULE_DESCRIPTION("C-Media CMI8788 helper library"); ...@@ -35,6 +35,30 @@ MODULE_DESCRIPTION("C-Media CMI8788 helper library");
MODULE_LICENSE("GPL v2"); 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) static irqreturn_t oxygen_interrupt(int dummy, void *dev_id)
{ {
struct oxygen *chip = dev_id; struct oxygen *chip = dev_id;
...@@ -87,8 +111,12 @@ static irqreturn_t oxygen_interrupt(int dummy, void *dev_id) ...@@ -87,8 +111,12 @@ static irqreturn_t oxygen_interrupt(int dummy, void *dev_id)
if (status & OXYGEN_INT_GPIO) if (status & OXYGEN_INT_GPIO)
schedule_work(&chip->gpio_work); schedule_work(&chip->gpio_work);
if ((status & OXYGEN_INT_MIDI) && chip->midi) if (status & OXYGEN_INT_MIDI) {
if (chip->midi)
snd_mpu401_uart_interrupt(0, chip->midi->private_data); snd_mpu401_uart_interrupt(0, chip->midi->private_data);
else
oxygen_read_uart(chip);
}
if (status & OXYGEN_INT_AC97) if (status & OXYGEN_INT_AC97)
wake_up(&chip->ac97_waitqueue); wake_up(&chip->ac97_waitqueue);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment