Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -79,6 +79,7 @@ struct oxygen_model {
	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;
@@ -125,6 +126,8 @@ struct oxygen {
		__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;
};

@@ -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_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)
{
+21 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <linux/delay.h>
#include <linux/sched.h>
#include <sound/core.h>
#include <sound/mpu401.h>
#include <asm/io.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);
}
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);
+30 −2
Original line number Diff line number Diff line
@@ -35,6 +35,30 @@ MODULE_DESCRIPTION("C-Media CMI8788 helper library");
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;
@@ -87,8 +111,12 @@ static irqreturn_t oxygen_interrupt(int dummy, void *dev_id)
	if (status & OXYGEN_INT_GPIO)
		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);
		else
			oxygen_read_uart(chip);
	}

	if (status & OXYGEN_INT_AC97)
		wake_up(&chip->ac97_waitqueue);