[ALSA] oxygen: optimize snd_pcm_hardware structures
[safe/jmp/linux-2.6] / sound / pci / oxygen / oxygen_io.c
1 /*
2  * C-Media CMI8788 driver - helper functions
3  *
4  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
5  *
6  *
7  *  This driver is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License, version 2.
9  *
10  *  This driver is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this driver; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18  */
19
20 #include <linux/delay.h>
21 #include <linux/sched.h>
22 #include <sound/core.h>
23 #include <asm/io.h>
24 #include "oxygen.h"
25
26 u8 oxygen_read8(struct oxygen *chip, unsigned int reg)
27 {
28         return inb(chip->addr + reg);
29 }
30 EXPORT_SYMBOL(oxygen_read8);
31
32 u16 oxygen_read16(struct oxygen *chip, unsigned int reg)
33 {
34         return inw(chip->addr + reg);
35 }
36 EXPORT_SYMBOL(oxygen_read16);
37
38 u32 oxygen_read32(struct oxygen *chip, unsigned int reg)
39 {
40         return inl(chip->addr + reg);
41 }
42 EXPORT_SYMBOL(oxygen_read32);
43
44 void oxygen_write8(struct oxygen *chip, unsigned int reg, u8 value)
45 {
46         outb(value, chip->addr + reg);
47 }
48 EXPORT_SYMBOL(oxygen_write8);
49
50 void oxygen_write16(struct oxygen *chip, unsigned int reg, u16 value)
51 {
52         outw(value, chip->addr + reg);
53 }
54 EXPORT_SYMBOL(oxygen_write16);
55
56 void oxygen_write32(struct oxygen *chip, unsigned int reg, u32 value)
57 {
58         outl(value, chip->addr + reg);
59 }
60 EXPORT_SYMBOL(oxygen_write32);
61
62 void oxygen_write8_masked(struct oxygen *chip, unsigned int reg,
63                           u8 value, u8 mask)
64 {
65         u8 tmp = inb(chip->addr + reg);
66         outb((tmp & ~mask) | (value & mask), chip->addr + reg);
67 }
68 EXPORT_SYMBOL(oxygen_write8_masked);
69
70 void oxygen_write16_masked(struct oxygen *chip, unsigned int reg,
71                            u16 value, u16 mask)
72 {
73         u16 tmp = inw(chip->addr + reg);
74         outw((tmp & ~mask) | (value & mask), chip->addr + reg);
75 }
76 EXPORT_SYMBOL(oxygen_write16_masked);
77
78 void oxygen_write32_masked(struct oxygen *chip, unsigned int reg,
79                            u32 value, u32 mask)
80 {
81         u32 tmp = inl(chip->addr + reg);
82         outl((tmp & ~mask) | (value & mask), chip->addr + reg);
83 }
84 EXPORT_SYMBOL(oxygen_write32_masked);
85
86 static int oxygen_ac97_wait(struct oxygen *chip, unsigned int mask)
87 {
88         unsigned long timeout = jiffies + msecs_to_jiffies(1);
89         do {
90                 udelay(5);
91                 cond_resched();
92                 if (oxygen_read8(chip, OXYGEN_AC97_INTERRUPT_STATUS) & mask)
93                         return 0;
94         } while (time_after_eq(timeout, jiffies));
95         return -EIO;
96 }
97
98 /*
99  * About 10% of AC'97 register reads or writes fail to complete, but even those
100  * where the controller indicates completion aren't guaranteed to have actually
101  * happened.
102  *
103  * It's hard to assign blame to either the controller or the codec because both
104  * were made by C-Media ...
105  */
106
107 void oxygen_write_ac97(struct oxygen *chip, unsigned int codec,
108                        unsigned int index, u16 data)
109 {
110         unsigned int count, succeeded;
111         u32 reg;
112
113         reg = data;
114         reg |= index << OXYGEN_AC97_REG_ADDR_SHIFT;
115         reg |= OXYGEN_AC97_REG_DIR_WRITE;
116         reg |= codec << OXYGEN_AC97_REG_CODEC_SHIFT;
117         succeeded = 0;
118         for (count = 5; count > 0; --count) {
119                 udelay(5);
120                 oxygen_write32(chip, OXYGEN_AC97_REGS, reg);
121                 /* require two "completed" writes, just to be sure */
122                 if (oxygen_ac97_wait(chip, OXYGEN_AC97_INT_WRITE_DONE) >= 0 &&
123                     ++succeeded >= 2)
124                         return;
125         }
126         snd_printk(KERN_ERR "AC'97 write timeout\n");
127 }
128 EXPORT_SYMBOL(oxygen_write_ac97);
129
130 u16 oxygen_read_ac97(struct oxygen *chip, unsigned int codec,
131                      unsigned int index)
132 {
133         unsigned int count;
134         unsigned int last_read = UINT_MAX;
135         u32 reg;
136
137         reg = index << OXYGEN_AC97_REG_ADDR_SHIFT;
138         reg |= OXYGEN_AC97_REG_DIR_READ;
139         reg |= codec << OXYGEN_AC97_REG_CODEC_SHIFT;
140         for (count = 5; count > 0; --count) {
141                 udelay(5);
142                 oxygen_write32(chip, OXYGEN_AC97_REGS, reg);
143                 udelay(10);
144                 if (oxygen_ac97_wait(chip, OXYGEN_AC97_INT_READ_DONE) >= 0) {
145                         u16 value = oxygen_read16(chip, OXYGEN_AC97_REGS);
146                         /* we require two consecutive reads of the same value */
147                         if (value == last_read)
148                                 return value;
149                         last_read = value;
150                         /*
151                          * Invert the register value bits to make sure that two
152                          * consecutive unsuccessful reads do not return the same
153                          * value.
154                          */
155                         reg ^= 0xffff;
156                 }
157         }
158         snd_printk(KERN_ERR "AC'97 read timeout on codec %u\n", codec);
159         return 0;
160 }
161 EXPORT_SYMBOL(oxygen_read_ac97);
162
163 void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec,
164                               unsigned int index, u16 data, u16 mask)
165 {
166         u16 value = oxygen_read_ac97(chip, codec, index);
167         value &= ~mask;
168         value |= data & mask;
169         oxygen_write_ac97(chip, codec, index, value);
170 }
171 EXPORT_SYMBOL(oxygen_write_ac97_masked);
172
173 void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data)
174 {
175         unsigned int count;
176
177         /* should not need more than 7.68 us (24 * 320 ns) */
178         count = 10;
179         while ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) & OXYGEN_SPI_BUSY)
180                && count > 0) {
181                 udelay(1);
182                 --count;
183         }
184
185         spin_lock_irq(&chip->reg_lock);
186         oxygen_write8(chip, OXYGEN_SPI_DATA1, data);
187         oxygen_write8(chip, OXYGEN_SPI_DATA2, data >> 8);
188         if (control & OXYGEN_SPI_DATA_LENGTH_3)
189                 oxygen_write8(chip, OXYGEN_SPI_DATA3, data >> 16);
190         oxygen_write8(chip, OXYGEN_SPI_CONTROL, control);
191         spin_unlock_irq(&chip->reg_lock);
192 }
193 EXPORT_SYMBOL(oxygen_write_spi);