aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/oxygen
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2008-09-22 03:04:43 -0400
committerClemens Ladisch <clemens@ladisch.de>2008-09-22 03:04:43 -0400
commit397b1dcc449082ce3f720c548da9c59db01cb739 (patch)
treea5295eabb214f913cd931c50b079c81b8086e577 /sound/pci/oxygen
parentdbbbd6744439d95d2b0dc23c5cdca2c477377f76 (diff)
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>
Diffstat (limited to 'sound/pci/oxygen')
-rw-r--r--sound/pci/oxygen/oxygen.h6
-rw-r--r--sound/pci/oxygen/oxygen_io.c21
-rw-r--r--sound/pci/oxygen/oxygen_lib.c32
3 files changed, 57 insertions, 2 deletions
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h
index f82a96290f72..19107c6307e5 100644
--- a/sound/pci/oxygen/oxygen.h
+++ b/sound/pci/oxygen/oxygen.h
@@ -79,6 +79,7 @@ struct oxygen_model {
79 void (*update_dac_volume)(struct oxygen *chip); 79 void (*update_dac_volume)(struct oxygen *chip);
80 void (*update_dac_mute)(struct oxygen *chip); 80 void (*update_dac_mute)(struct oxygen *chip);
81 void (*gpio_changed)(struct oxygen *chip); 81 void (*gpio_changed)(struct oxygen *chip);
82 void (*uart_input)(struct oxygen *chip);
82 void (*ac97_switch)(struct oxygen *chip, 83 void (*ac97_switch)(struct oxygen *chip,
83 unsigned int reg, unsigned int mute); 84 unsigned int reg, unsigned int mute);
84 const unsigned int *dac_tlv; 85 const unsigned int *dac_tlv;
@@ -125,6 +126,8 @@ struct oxygen {
125 __le32 _32[OXYGEN_IO_SIZE / 4]; 126 __le32 _32[OXYGEN_IO_SIZE / 4];
126 } saved_registers; 127 } saved_registers;
127 u16 saved_ac97_registers[2][0x40]; 128 u16 saved_ac97_registers[2][0x40];
129 unsigned int uart_input_count;
130 u8 uart_input[32];
128 struct oxygen_model model; 131 struct oxygen_model model;
129}; 132};
130 133
@@ -174,6 +177,9 @@ void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec,
174void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data); 177void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data);
175void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data); 178void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data);
176 179
180void oxygen_reset_uart(struct oxygen *chip);
181void oxygen_write_uart(struct oxygen *chip, u8 data);
182
177static inline void oxygen_set_bits8(struct oxygen *chip, 183static inline void oxygen_set_bits8(struct oxygen *chip,
178 unsigned int reg, u8 value) 184 unsigned int reg, u8 value)
179{ 185{
diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c
index 83f135f80df4..deba7389aec3 100644
--- a/sound/pci/oxygen/oxygen_io.c
+++ b/sound/pci/oxygen/oxygen_io.c
@@ -20,6 +20,7 @@
20#include <linux/delay.h> 20#include <linux/delay.h>
21#include <linux/sched.h> 21#include <linux/sched.h>
22#include <sound/core.h> 22#include <sound/core.h>
23#include <sound/mpu401.h>
23#include <asm/io.h> 24#include <asm/io.h>
24#include "oxygen.h" 25#include "oxygen.h"
25 26
@@ -232,3 +233,23 @@ void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data)
232 device | OXYGEN_2WIRE_DIR_WRITE); 233 device | OXYGEN_2WIRE_DIR_WRITE);
233} 234}
234EXPORT_SYMBOL(oxygen_write_i2c); 235EXPORT_SYMBOL(oxygen_write_i2c);
236
237static void _write_uart(struct oxygen *chip, unsigned int port, u8 data)
238{
239 if (oxygen_read8(chip, OXYGEN_MPU401 + 1) & MPU401_TX_FULL)
240 msleep(1);
241 oxygen_write8(chip, OXYGEN_MPU401 + port, data);
242}
243
244void oxygen_reset_uart(struct oxygen *chip)
245{
246 _write_uart(chip, 1, MPU401_RESET);
247 _write_uart(chip, 1, MPU401_ENTER_UART);
248}
249EXPORT_SYMBOL(oxygen_reset_uart);
250
251void oxygen_write_uart(struct oxygen *chip, u8 data)
252{
253 _write_uart(chip, 0, data);
254}
255EXPORT_SYMBOL(oxygen_write_uart);
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c
index b1997216b4af..84f481d41efa 100644
--- a/sound/pci/oxygen/oxygen_lib.c
+++ b/sound/pci/oxygen/oxygen_lib.c
@@ -35,6 +35,30 @@ MODULE_DESCRIPTION("C-Media CMI8788 helper library");
35MODULE_LICENSE("GPL v2"); 35MODULE_LICENSE("GPL v2");
36 36
37 37
38static inline int oxygen_uart_input_ready(struct oxygen *chip)
39{
40 return !(oxygen_read8(chip, OXYGEN_MPU401 + 1) & MPU401_RX_EMPTY);
41}
42
43static void oxygen_read_uart(struct oxygen *chip)
44{
45 if (unlikely(!oxygen_uart_input_ready(chip))) {
46 /* no data, but read it anyway to clear the interrupt */
47 oxygen_read8(chip, OXYGEN_MPU401);
48 return;
49 }
50 do {
51 u8 data = oxygen_read8(chip, OXYGEN_MPU401);
52 if (data == MPU401_ACK)
53 continue;
54 if (chip->uart_input_count >= ARRAY_SIZE(chip->uart_input))
55 chip->uart_input_count = 0;
56 chip->uart_input[chip->uart_input_count++] = data;
57 } while (oxygen_uart_input_ready(chip));
58 if (chip->model.uart_input)
59 chip->model.uart_input(chip);
60}
61
38static irqreturn_t oxygen_interrupt(int dummy, void *dev_id) 62static irqreturn_t oxygen_interrupt(int dummy, void *dev_id)
39{ 63{
40 struct oxygen *chip = dev_id; 64 struct oxygen *chip = dev_id;
@@ -87,8 +111,12 @@ static irqreturn_t oxygen_interrupt(int dummy, void *dev_id)
87 if (status & OXYGEN_INT_GPIO) 111 if (status & OXYGEN_INT_GPIO)
88 schedule_work(&chip->gpio_work); 112 schedule_work(&chip->gpio_work);
89 113
90 if ((status & OXYGEN_INT_MIDI) && chip->midi) 114 if (status & OXYGEN_INT_MIDI) {
91 snd_mpu401_uart_interrupt(0, chip->midi->private_data); 115 if (chip->midi)
116 snd_mpu401_uart_interrupt(0, chip->midi->private_data);
117 else
118 oxygen_read_uart(chip);
119 }
92 120
93 if (status & OXYGEN_INT_AC97) 121 if (status & OXYGEN_INT_AC97)
94 wake_up(&chip->ac97_waitqueue); 122 wake_up(&chip->ac97_waitqueue);