Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Driver for Sound Core PDAudioCF soundcard | |
3 | * | |
c1017a4c | 4 | * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz> |
1da177e4 LT |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 | */ | |
20 | ||
21 | #include <sound/driver.h> | |
22 | #include <linux/delay.h> | |
23 | #include <sound/core.h> | |
24 | #include <sound/info.h> | |
25 | #include "pdaudiocf.h" | |
26 | #include <sound/initval.h> | |
27 | ||
28 | /* | |
29 | * | |
30 | */ | |
31 | static unsigned char pdacf_ak4117_read(void *private_data, unsigned char reg) | |
32 | { | |
db131548 | 33 | struct snd_pdacf *chip = private_data; |
1da177e4 LT |
34 | unsigned long timeout; |
35 | unsigned long flags; | |
36 | unsigned char res; | |
37 | ||
38 | spin_lock_irqsave(&chip->ak4117_lock, flags); | |
39 | timeout = 1000; | |
40 | while (pdacf_reg_read(chip, PDAUDIOCF_REG_SCR) & PDAUDIOCF_AK_SBP) { | |
41 | udelay(5); | |
42 | if (--timeout == 0) { | |
43 | spin_unlock_irqrestore(&chip->ak4117_lock, flags); | |
44 | snd_printk(KERN_ERR "AK4117 ready timeout (read)\n"); | |
45 | return 0; | |
46 | } | |
47 | } | |
48 | pdacf_reg_write(chip, PDAUDIOCF_REG_AK_IFR, (u16)reg << 8); | |
49 | timeout = 1000; | |
50 | while (pdacf_reg_read(chip, PDAUDIOCF_REG_SCR) & PDAUDIOCF_AK_SBP) { | |
51 | udelay(5); | |
52 | if (--timeout == 0) { | |
53 | spin_unlock_irqrestore(&chip->ak4117_lock, flags); | |
54 | snd_printk(KERN_ERR "AK4117 read timeout (read2)\n"); | |
55 | return 0; | |
56 | } | |
57 | } | |
58 | res = (unsigned char)pdacf_reg_read(chip, PDAUDIOCF_REG_AK_IFR); | |
59 | spin_unlock_irqrestore(&chip->ak4117_lock, flags); | |
60 | return res; | |
61 | } | |
62 | ||
63 | static void pdacf_ak4117_write(void *private_data, unsigned char reg, unsigned char val) | |
64 | { | |
db131548 | 65 | struct snd_pdacf *chip = private_data; |
1da177e4 LT |
66 | unsigned long timeout; |
67 | unsigned long flags; | |
68 | ||
69 | spin_lock_irqsave(&chip->ak4117_lock, flags); | |
70 | timeout = 1000; | |
71 | while (inw(chip->port + PDAUDIOCF_REG_SCR) & PDAUDIOCF_AK_SBP) { | |
72 | udelay(5); | |
73 | if (--timeout == 0) { | |
74 | spin_unlock_irqrestore(&chip->ak4117_lock, flags); | |
75 | snd_printk(KERN_ERR "AK4117 ready timeout (write)\n"); | |
76 | return; | |
77 | } | |
78 | } | |
79 | outw((u16)reg << 8 | val | (1<<13), chip->port + PDAUDIOCF_REG_AK_IFR); | |
80 | spin_unlock_irqrestore(&chip->ak4117_lock, flags); | |
81 | } | |
82 | ||
83 | #if 0 | |
db131548 | 84 | void pdacf_dump(struct snd_pdacf *chip) |
1da177e4 LT |
85 | { |
86 | printk("PDAUDIOCF DUMP (0x%lx):\n", chip->port); | |
87 | printk("WPD : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_WDP)); | |
88 | printk("RDP : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_RDP)); | |
89 | printk("TCR : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_TCR)); | |
90 | printk("SCR : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_SCR)); | |
91 | printk("ISR : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_ISR)); | |
92 | printk("IER : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_IER)); | |
93 | printk("AK_IFR : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_AK_IFR)); | |
94 | } | |
95 | #endif | |
96 | ||
db131548 | 97 | static int pdacf_reset(struct snd_pdacf *chip, int powerdown) |
1da177e4 LT |
98 | { |
99 | u16 val; | |
100 | ||
101 | val = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR); | |
102 | val |= PDAUDIOCF_PDN; | |
103 | val &= ~PDAUDIOCF_RECORD; /* for sure */ | |
104 | pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val); | |
105 | udelay(5); | |
106 | val |= PDAUDIOCF_RST; | |
107 | pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val); | |
108 | udelay(200); | |
109 | val &= ~PDAUDIOCF_RST; | |
110 | pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val); | |
111 | udelay(5); | |
112 | if (!powerdown) { | |
113 | val &= ~PDAUDIOCF_PDN; | |
114 | pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val); | |
115 | udelay(200); | |
116 | } | |
117 | return 0; | |
118 | } | |
119 | ||
db131548 | 120 | void pdacf_reinit(struct snd_pdacf *chip, int resume) |
1da177e4 LT |
121 | { |
122 | pdacf_reset(chip, 0); | |
123 | if (resume) | |
124 | pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, chip->suspend_reg_scr); | |
125 | snd_ak4117_reinit(chip->ak4117); | |
126 | pdacf_reg_write(chip, PDAUDIOCF_REG_TCR, chip->regmap[PDAUDIOCF_REG_TCR>>1]); | |
127 | pdacf_reg_write(chip, PDAUDIOCF_REG_IER, chip->regmap[PDAUDIOCF_REG_IER>>1]); | |
128 | } | |
129 | ||
db131548 TI |
130 | static void pdacf_proc_read(struct snd_info_entry * entry, |
131 | struct snd_info_buffer *buffer) | |
1da177e4 | 132 | { |
db131548 | 133 | struct snd_pdacf *chip = entry->private_data; |
1da177e4 LT |
134 | u16 tmp; |
135 | ||
136 | snd_iprintf(buffer, "PDAudioCF\n\n"); | |
137 | tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR); | |
138 | snd_iprintf(buffer, "FPGA revision : 0x%x\n", PDAUDIOCF_FPGAREV(tmp)); | |
139 | ||
140 | } | |
141 | ||
db131548 | 142 | static void pdacf_proc_init(struct snd_pdacf *chip) |
1da177e4 | 143 | { |
db131548 | 144 | struct snd_info_entry *entry; |
1da177e4 LT |
145 | |
146 | if (! snd_card_proc_new(chip->card, "pdaudiocf", &entry)) | |
bf850204 | 147 | snd_info_set_text_ops(entry, chip, pdacf_proc_read); |
1da177e4 LT |
148 | } |
149 | ||
db131548 | 150 | struct snd_pdacf *snd_pdacf_create(struct snd_card *card) |
1da177e4 | 151 | { |
db131548 | 152 | struct snd_pdacf *chip; |
1da177e4 | 153 | |
561b220a | 154 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); |
1da177e4 LT |
155 | if (chip == NULL) |
156 | return NULL; | |
157 | chip->card = card; | |
158 | spin_lock_init(&chip->reg_lock); | |
159 | spin_lock_init(&chip->ak4117_lock); | |
160 | tasklet_init(&chip->tq, pdacf_tasklet, (unsigned long)chip); | |
161 | card->private_data = chip; | |
162 | ||
163 | pdacf_proc_init(chip); | |
164 | return chip; | |
165 | } | |
166 | ||
db131548 | 167 | static void snd_pdacf_ak4117_change(struct ak4117 *ak4117, unsigned char c0, unsigned char c1) |
1da177e4 | 168 | { |
db131548 | 169 | struct snd_pdacf *chip = ak4117->change_callback_private; |
1da177e4 LT |
170 | unsigned long flags; |
171 | u16 val; | |
172 | ||
173 | if (!(c0 & AK4117_UNLCK)) | |
174 | return; | |
175 | spin_lock_irqsave(&chip->reg_lock, flags); | |
176 | val = chip->regmap[PDAUDIOCF_REG_SCR>>1]; | |
177 | if (ak4117->rcs0 & AK4117_UNLCK) | |
178 | val |= PDAUDIOCF_BLUE_LED_OFF; | |
179 | else | |
180 | val &= ~PDAUDIOCF_BLUE_LED_OFF; | |
181 | pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val); | |
182 | spin_unlock_irqrestore(&chip->reg_lock, flags); | |
183 | } | |
184 | ||
db131548 | 185 | int snd_pdacf_ak4117_create(struct snd_pdacf *chip) |
1da177e4 LT |
186 | { |
187 | int err; | |
188 | u16 val; | |
189 | /* design note: if we unmask PLL unlock, parity, valid, audio or auto bit interrupts */ | |
190 | /* from AK4117 then INT1 pin from AK4117 will be high all time, because PCMCIA interrupts are */ | |
191 | /* egde based and FPGA does logical OR for all interrupt sources, we cannot use these */ | |
192 | /* high-rate sources */ | |
193 | static unsigned char pgm[5] = { | |
194 | AK4117_XTL_24_576M | AK4117_EXCT, /* AK4117_REG_PWRDN */ | |
195 | AK4117_CM_PLL_XTAL | AK4117_PKCS_128fs | AK4117_XCKS_128fs, /* AK4117_REQ_CLOCK */ | |
196 | AK4117_EFH_1024LRCLK | AK4117_DIF_24R | AK4117_IPS, /* AK4117_REG_IO */ | |
197 | 0xff, /* AK4117_REG_INT0_MASK */ | |
198 | AK4117_MAUTO | AK4117_MAUD | AK4117_MULK | AK4117_MPAR | AK4117_MV, /* AK4117_REG_INT1_MASK */ | |
199 | }; | |
200 | ||
201 | err = pdacf_reset(chip, 0); | |
202 | if (err < 0) | |
203 | return err; | |
204 | err = snd_ak4117_create(chip->card, pdacf_ak4117_read, pdacf_ak4117_write, pgm, chip, &chip->ak4117); | |
205 | if (err < 0) | |
206 | return err; | |
207 | ||
208 | val = pdacf_reg_read(chip, PDAUDIOCF_REG_TCR); | |
209 | #if 1 /* normal operation */ | |
210 | val &= ~(PDAUDIOCF_ELIMAKMBIT|PDAUDIOCF_TESTDATASEL); | |
211 | #else /* debug */ | |
212 | val |= PDAUDIOCF_ELIMAKMBIT; | |
213 | val &= ~PDAUDIOCF_TESTDATASEL; | |
214 | #endif | |
215 | pdacf_reg_write(chip, PDAUDIOCF_REG_TCR, val); | |
216 | ||
217 | /* setup the FPGA to match AK4117 setup */ | |
218 | val = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR); | |
219 | val &= ~(PDAUDIOCF_CLKDIV0 | PDAUDIOCF_CLKDIV1); /* use 24.576Mhz clock */ | |
220 | val &= ~(PDAUDIOCF_RED_LED_OFF|PDAUDIOCF_BLUE_LED_OFF); | |
221 | val |= PDAUDIOCF_DATAFMT0 | PDAUDIOCF_DATAFMT1; /* 24-bit data */ | |
222 | pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val); | |
223 | ||
224 | /* setup LEDs and IRQ */ | |
225 | val = pdacf_reg_read(chip, PDAUDIOCF_REG_IER); | |
226 | val &= ~(PDAUDIOCF_IRQLVLEN0 | PDAUDIOCF_IRQLVLEN1); | |
227 | val &= ~(PDAUDIOCF_BLUEDUTY0 | PDAUDIOCF_REDDUTY0 | PDAUDIOCF_REDDUTY1); | |
228 | val |= PDAUDIOCF_BLUEDUTY1 | PDAUDIOCF_HALFRATE; | |
229 | val |= PDAUDIOCF_IRQOVREN | PDAUDIOCF_IRQAKMEN; | |
230 | pdacf_reg_write(chip, PDAUDIOCF_REG_IER, val); | |
231 | ||
232 | chip->ak4117->change_callback_private = chip; | |
233 | chip->ak4117->change_callback = snd_pdacf_ak4117_change; | |
234 | ||
235 | /* update LED status */ | |
236 | snd_pdacf_ak4117_change(chip->ak4117, AK4117_UNLCK, 0); | |
237 | ||
238 | return 0; | |
239 | } | |
240 | ||
db131548 | 241 | void snd_pdacf_powerdown(struct snd_pdacf *chip) |
1da177e4 LT |
242 | { |
243 | u16 val; | |
244 | ||
245 | val = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR); | |
246 | chip->suspend_reg_scr = val; | |
247 | val |= PDAUDIOCF_RED_LED_OFF | PDAUDIOCF_BLUE_LED_OFF; | |
248 | pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val); | |
249 | /* disable interrupts, but use direct write to preserve old register value in chip->regmap */ | |
250 | val = inw(chip->port + PDAUDIOCF_REG_IER); | |
251 | val &= ~(PDAUDIOCF_IRQOVREN|PDAUDIOCF_IRQAKMEN|PDAUDIOCF_IRQLVLEN0|PDAUDIOCF_IRQLVLEN1); | |
252 | outw(val, chip->port + PDAUDIOCF_REG_IER); | |
253 | pdacf_reset(chip, 1); | |
254 | } | |
255 | ||
256 | #ifdef CONFIG_PM | |
257 | ||
e4f163d9 | 258 | int snd_pdacf_suspend(struct snd_pdacf *chip, pm_message_t state) |
1da177e4 | 259 | { |
1da177e4 LT |
260 | u16 val; |
261 | ||
e4f163d9 | 262 | snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); |
1da177e4 LT |
263 | snd_pcm_suspend_all(chip->pcm); |
264 | /* disable interrupts, but use direct write to preserve old register value in chip->regmap */ | |
265 | val = inw(chip->port + PDAUDIOCF_REG_IER); | |
266 | val &= ~(PDAUDIOCF_IRQOVREN|PDAUDIOCF_IRQAKMEN|PDAUDIOCF_IRQLVLEN0|PDAUDIOCF_IRQLVLEN1); | |
267 | outw(val, chip->port + PDAUDIOCF_REG_IER); | |
268 | chip->chip_status |= PDAUDIOCF_STAT_IS_SUSPENDED; /* ignore interrupts from now */ | |
269 | snd_pdacf_powerdown(chip); | |
270 | return 0; | |
271 | } | |
272 | ||
db131548 | 273 | static inline int check_signal(struct snd_pdacf *chip) |
1da177e4 LT |
274 | { |
275 | return (chip->ak4117->rcs0 & AK4117_UNLCK) == 0; | |
276 | } | |
277 | ||
e4f163d9 | 278 | int snd_pdacf_resume(struct snd_pdacf *chip) |
1da177e4 | 279 | { |
1da177e4 LT |
280 | int timeout = 40; |
281 | ||
282 | pdacf_reinit(chip, 1); | |
283 | /* wait for AK4117's PLL */ | |
284 | while (timeout-- > 0 && | |
285 | (snd_ak4117_external_rate(chip->ak4117) <= 0 || !check_signal(chip))) | |
286 | mdelay(1); | |
287 | chip->chip_status &= ~PDAUDIOCF_STAT_IS_SUSPENDED; | |
e4f163d9 | 288 | snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0); |
1da177e4 LT |
289 | return 0; |
290 | } | |
291 | #endif |