diff options
Diffstat (limited to 'sound/pci/emu10k1/io.c')
-rw-r--r-- | sound/pci/emu10k1/io.c | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index 029e7856c43b..116e1c8d9361 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <sound/core.h> | 30 | #include <sound/core.h> |
31 | #include <sound/emu10k1.h> | 31 | #include <sound/emu10k1.h> |
32 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include "p17v.h" | ||
33 | 34 | ||
34 | unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn) | 35 | unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn) |
35 | { | 36 | { |
@@ -167,6 +168,109 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, | |||
167 | return 0; | 168 | return 0; |
168 | } | 169 | } |
169 | 170 | ||
171 | /* The ADC does not support i2c read, so only write is implemented */ | ||
172 | int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, | ||
173 | u32 reg, | ||
174 | u32 value) | ||
175 | { | ||
176 | u32 tmp; | ||
177 | int timeout = 0; | ||
178 | int status; | ||
179 | int retry; | ||
180 | if ((reg > 0x7f) || (value > 0x1ff)) { | ||
181 | snd_printk(KERN_ERR "i2c_write: invalid values.\n"); | ||
182 | return -EINVAL; | ||
183 | } | ||
184 | |||
185 | tmp = reg << 25 | value << 16; | ||
186 | // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value); | ||
187 | /* Not sure what this I2C channel controls. */ | ||
188 | /* snd_emu10k1_ptr_write(emu, P17V_I2C_0, 0, tmp); */ | ||
189 | |||
190 | /* This controls the I2C connected to the WM8775 ADC Codec */ | ||
191 | snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp); | ||
192 | tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */ | ||
193 | |||
194 | for (retry = 0; retry < 10; retry++) { | ||
195 | /* Send the data to i2c */ | ||
196 | //tmp = snd_emu10k1_ptr_read(emu, P17V_I2C_ADDR, 0); | ||
197 | //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK); | ||
198 | tmp = 0; | ||
199 | tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); | ||
200 | snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp); | ||
201 | |||
202 | /* Wait till the transaction ends */ | ||
203 | while (1) { | ||
204 | udelay(10); | ||
205 | status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0); | ||
206 | // snd_printk("I2C:status=0x%x\n", status); | ||
207 | timeout++; | ||
208 | if ((status & I2C_A_ADC_START) == 0) | ||
209 | break; | ||
210 | |||
211 | if (timeout > 1000) { | ||
212 | snd_printk("emu10k1:I2C:timeout status=0x%x\n", status); | ||
213 | break; | ||
214 | } | ||
215 | } | ||
216 | //Read back and see if the transaction is successful | ||
217 | if ((status & I2C_A_ADC_ABORT) == 0) | ||
218 | break; | ||
219 | } | ||
220 | |||
221 | if (retry == 10) { | ||
222 | snd_printk(KERN_ERR "Writing to ADC failed!\n"); | ||
223 | return -EINVAL; | ||
224 | } | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value) | ||
230 | { | ||
231 | if (reg < 0 || reg > 0x3f) | ||
232 | return 1; | ||
233 | reg += 0x40; /* 0x40 upwards are registers. */ | ||
234 | if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */ | ||
235 | return 1; | ||
236 | outl(reg, emu->port + A_IOCFG); | ||
237 | udelay(10); | ||
238 | outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ | ||
239 | udelay(10); | ||
240 | outl(value, emu->port + A_IOCFG); | ||
241 | udelay(10); | ||
242 | outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, int reg, int *value) | ||
248 | { | ||
249 | if (reg < 0 || reg > 0x3f) | ||
250 | return 1; | ||
251 | reg += 0x40; /* 0x40 upwards are registers. */ | ||
252 | outl(reg, emu->port + A_IOCFG); | ||
253 | udelay(10); | ||
254 | outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ | ||
255 | udelay(10); | ||
256 | *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f); | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | /* Each Destination has one and only one Source, | ||
262 | * but one Source can feed any number of Destinations simultaneously. | ||
263 | */ | ||
264 | int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, int dst, int src) | ||
265 | { | ||
266 | snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) ); | ||
267 | snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) ); | ||
268 | snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) ); | ||
269 | snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) ); | ||
270 | |||
271 | return 0; | ||
272 | } | ||
273 | |||
170 | void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb) | 274 | void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb) |
171 | { | 275 | { |
172 | unsigned long flags; | 276 | unsigned long flags; |