[ALSA] add CMI8788 driver
[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 <sound/driver.h>
21 #include <linux/delay.h>
22 #include <linux/sched.h>
23 #include <sound/core.h>
24 #include <asm/io.h>
25 #include "oxygen.h"
26
27 u8 oxygen_read8(struct oxygen *chip, unsigned int reg)
28 {
29         return inb(chip->addr + reg);
30 }
31 EXPORT_SYMBOL(oxygen_read8);
32
33 u16 oxygen_read16(struct oxygen *chip, unsigned int reg)
34 {
35         return inw(chip->addr + reg);
36 }
37 EXPORT_SYMBOL(oxygen_read16);
38
39 u32 oxygen_read32(struct oxygen *chip, unsigned int reg)
40 {
41         return inl(chip->addr + reg);
42 }
43 EXPORT_SYMBOL(oxygen_read32);
44
45 void oxygen_write8(struct oxygen *chip, unsigned int reg, u8 value)
46 {
47         outb(value, chip->addr + reg);
48 }
49 EXPORT_SYMBOL(oxygen_write8);
50
51 void oxygen_write16(struct oxygen *chip, unsigned int reg, u16 value)
52 {
53         outw(value, chip->addr + reg);
54 }
55 EXPORT_SYMBOL(oxygen_write16);
56
57 void oxygen_write32(struct oxygen *chip, unsigned int reg, u32 value)
58 {
59         outl(value, chip->addr + reg);
60 }
61 EXPORT_SYMBOL(oxygen_write32);
62
63 void oxygen_write8_masked(struct oxygen *chip, unsigned int reg,
64                           u8 value, u8 mask)
65 {
66         u8 tmp = inb(chip->addr + reg);
67         outb((tmp & ~mask) | (value & mask), chip->addr + reg);
68 }
69 EXPORT_SYMBOL(oxygen_write8_masked);
70
71 void oxygen_write16_masked(struct oxygen *chip, unsigned int reg,
72                            u16 value, u16 mask)
73 {
74         u16 tmp = inw(chip->addr + reg);
75         outw((tmp & ~mask) | (value & mask), chip->addr + reg);
76 }
77 EXPORT_SYMBOL(oxygen_write16_masked);
78
79 void oxygen_write32_masked(struct oxygen *chip, unsigned int reg,
80                            u32 value, u32 mask)
81 {
82         u32 tmp = inl(chip->addr + reg);
83         outl((tmp & ~mask) | (value & mask), chip->addr + reg);
84 }
85 EXPORT_SYMBOL(oxygen_write32_masked);
86
87 static int oxygen_ac97_wait(struct oxygen *chip, unsigned int mask)
88 {
89         unsigned long timeout = jiffies + msecs_to_jiffies(1);
90         do {
91                 udelay(5);
92                 cond_resched();
93                 if (oxygen_read8(chip, OXYGEN_AC97_INTERRUPT_STATUS) & mask)
94                         return 0;
95         } while (time_after_eq(timeout, jiffies));
96         return -EIO;
97 }
98
99 /*
100  * About 10% of AC'97 register reads or writes fail to complete, but even those
101  * where the controller indicates completion aren't guaranteed to have actually
102  * happened.
103  *
104  * It's hard to assign blame to either the controller or the codec because both
105  * were made by C-Media ...
106  */
107
108 void oxygen_write_ac97(struct oxygen *chip, unsigned int codec,
109                        unsigned int index, u16 data)
110 {
111         unsigned int count, succeeded;
112         u32 reg;
113
114         reg = data;
115         reg |= index << OXYGEN_AC97_REG_ADDR_SHIFT;
116         reg |= OXYGEN_AC97_REG_DIR_WRITE;
117         reg |= codec << OXYGEN_AC97_REG_CODEC_SHIFT;
118         succeeded = 0;
119         for (count = 5; count > 0; --count) {
120                 udelay(5);
121                 oxygen_write32(chip, OXYGEN_AC97_REGS, reg);
122                 /* require two "completed" writes, just to be sure */
123                 if (oxygen_ac97_wait(chip, OXYGEN_AC97_WRITE_COMPLETE) >= 0 &&
124                     ++succeeded >= 2)
125                         return;
126         }
127         snd_printk(KERN_ERR "AC'97 write timeout\n");
128 }
129 EXPORT_SYMBOL(oxygen_write_ac97);
130
131 u16 oxygen_read_ac97(struct oxygen *chip, unsigned int codec,
132                      unsigned int index)
133 {
134         unsigned int count;
135         unsigned int last_read = UINT_MAX;
136         u32 reg;
137
138         reg = index << OXYGEN_AC97_REG_ADDR_SHIFT;
139         reg |= OXYGEN_AC97_REG_DIR_READ;
140         reg |= codec << OXYGEN_AC97_REG_CODEC_SHIFT;
141         for (count = 5; count > 0; --count) {
142                 udelay(5);
143                 oxygen_write32(chip, OXYGEN_AC97_REGS, reg);
144                 udelay(10);
145                 if (oxygen_ac97_wait(chip, OXYGEN_AC97_READ_COMPLETE) >= 0) {
146                         u16 value = oxygen_read16(chip, OXYGEN_AC97_REGS);
147                         /* we require two consecutive reads of the same value */
148                         if (value == last_read)
149                                 return value;
150                         last_read = value;
151                         /*
152                          * Invert the register value bits to make sure that two
153                          * consecutive unsuccessful reads do not return the same
154                          * value.
155                          */
156                         reg ^= 0xffff;
157                 }
158         }
159         snd_printk(KERN_ERR "AC'97 read timeout on codec %u\n", codec);
160         return 0;
161 }
162 EXPORT_SYMBOL(oxygen_read_ac97);
163
164 void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec,
165                               unsigned int index, u16 data, u16 mask)
166 {
167         u16 value = oxygen_read_ac97(chip, codec, index);
168         value &= ~mask;
169         value |= data & mask;
170         oxygen_write_ac97(chip, codec, index, value);
171 }
172 EXPORT_SYMBOL(oxygen_write_ac97_masked);
173
174 void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data)
175 {
176         unsigned int count;
177
178         /* should not need more than 3.84 us (24 * 160 ns) */
179         count = 10;
180         while ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) & OXYGEN_SPI_BUSY)
181                && count > 0) {
182                 udelay(1);
183                 --count;
184         }
185
186         spin_lock_irq(&chip->reg_lock);
187         oxygen_write8(chip, OXYGEN_SPI_DATA1, data);
188         oxygen_write8(chip, OXYGEN_SPI_DATA2, data >> 8);
189         if (control & OXYGEN_SPI_DATA_LENGTH_3)
190                 oxygen_write8(chip, OXYGEN_SPI_DATA3, data >> 16);
191         oxygen_write8(chip, OXYGEN_SPI_CONTROL, control);
192         spin_unlock_irq(&chip->reg_lock);
193 }
194 EXPORT_SYMBOL(oxygen_write_spi);