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: Clemens Ladisch <clemens@ladisch.de>
This commit is contained in:
@@ -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 {
|
|||||||
__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,
|
|||||||
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 @@
|
|||||||
#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)
|
|||||||
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");
|
|||||||
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)
|
|||||||
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) {
|
||||||
snd_mpu401_uart_interrupt(0, chip->midi->private_data);
|
if (chip->midi)
|
||||||
|
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);
|
||||||
|
Reference in New Issue
Block a user