2 * Driver for Sound Core PDAudioCF soundcard
4 * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz>
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.
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.
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
21 #include <linux/delay.h>
22 #include <sound/core.h>
23 #include <sound/info.h>
24 #include "pdaudiocf.h"
25 #include <sound/initval.h>
30 static unsigned char pdacf_ak4117_read(void *private_data
, unsigned char reg
)
32 struct snd_pdacf
*chip
= private_data
;
33 unsigned long timeout
;
37 spin_lock_irqsave(&chip
->ak4117_lock
, flags
);
39 while (pdacf_reg_read(chip
, PDAUDIOCF_REG_SCR
) & PDAUDIOCF_AK_SBP
) {
42 spin_unlock_irqrestore(&chip
->ak4117_lock
, flags
);
43 snd_printk(KERN_ERR
"AK4117 ready timeout (read)\n");
47 pdacf_reg_write(chip
, PDAUDIOCF_REG_AK_IFR
, (u16
)reg
<< 8);
49 while (pdacf_reg_read(chip
, PDAUDIOCF_REG_SCR
) & PDAUDIOCF_AK_SBP
) {
52 spin_unlock_irqrestore(&chip
->ak4117_lock
, flags
);
53 snd_printk(KERN_ERR
"AK4117 read timeout (read2)\n");
57 res
= (unsigned char)pdacf_reg_read(chip
, PDAUDIOCF_REG_AK_IFR
);
58 spin_unlock_irqrestore(&chip
->ak4117_lock
, flags
);
62 static void pdacf_ak4117_write(void *private_data
, unsigned char reg
, unsigned char val
)
64 struct snd_pdacf
*chip
= private_data
;
65 unsigned long timeout
;
68 spin_lock_irqsave(&chip
->ak4117_lock
, flags
);
70 while (inw(chip
->port
+ PDAUDIOCF_REG_SCR
) & PDAUDIOCF_AK_SBP
) {
73 spin_unlock_irqrestore(&chip
->ak4117_lock
, flags
);
74 snd_printk(KERN_ERR
"AK4117 ready timeout (write)\n");
78 outw((u16
)reg
<< 8 | val
| (1<<13), chip
->port
+ PDAUDIOCF_REG_AK_IFR
);
79 spin_unlock_irqrestore(&chip
->ak4117_lock
, flags
);
83 void pdacf_dump(struct snd_pdacf
*chip
)
85 printk("PDAUDIOCF DUMP (0x%lx):\n", chip
->port
);
86 printk("WPD : 0x%x\n", inw(chip
->port
+ PDAUDIOCF_REG_WDP
));
87 printk("RDP : 0x%x\n", inw(chip
->port
+ PDAUDIOCF_REG_RDP
));
88 printk("TCR : 0x%x\n", inw(chip
->port
+ PDAUDIOCF_REG_TCR
));
89 printk("SCR : 0x%x\n", inw(chip
->port
+ PDAUDIOCF_REG_SCR
));
90 printk("ISR : 0x%x\n", inw(chip
->port
+ PDAUDIOCF_REG_ISR
));
91 printk("IER : 0x%x\n", inw(chip
->port
+ PDAUDIOCF_REG_IER
));
92 printk("AK_IFR : 0x%x\n", inw(chip
->port
+ PDAUDIOCF_REG_AK_IFR
));
96 static int pdacf_reset(struct snd_pdacf
*chip
, int powerdown
)
100 val
= pdacf_reg_read(chip
, PDAUDIOCF_REG_SCR
);
101 val
|= PDAUDIOCF_PDN
;
102 val
&= ~PDAUDIOCF_RECORD
; /* for sure */
103 pdacf_reg_write(chip
, PDAUDIOCF_REG_SCR
, val
);
105 val
|= PDAUDIOCF_RST
;
106 pdacf_reg_write(chip
, PDAUDIOCF_REG_SCR
, val
);
108 val
&= ~PDAUDIOCF_RST
;
109 pdacf_reg_write(chip
, PDAUDIOCF_REG_SCR
, val
);
112 val
&= ~PDAUDIOCF_PDN
;
113 pdacf_reg_write(chip
, PDAUDIOCF_REG_SCR
, val
);
119 void pdacf_reinit(struct snd_pdacf
*chip
, int resume
)
121 pdacf_reset(chip
, 0);
123 pdacf_reg_write(chip
, PDAUDIOCF_REG_SCR
, chip
->suspend_reg_scr
);
124 snd_ak4117_reinit(chip
->ak4117
);
125 pdacf_reg_write(chip
, PDAUDIOCF_REG_TCR
, chip
->regmap
[PDAUDIOCF_REG_TCR
>>1]);
126 pdacf_reg_write(chip
, PDAUDIOCF_REG_IER
, chip
->regmap
[PDAUDIOCF_REG_IER
>>1]);
129 static void pdacf_proc_read(struct snd_info_entry
* entry
,
130 struct snd_info_buffer
*buffer
)
132 struct snd_pdacf
*chip
= entry
->private_data
;
135 snd_iprintf(buffer
, "PDAudioCF\n\n");
136 tmp
= pdacf_reg_read(chip
, PDAUDIOCF_REG_SCR
);
137 snd_iprintf(buffer
, "FPGA revision : 0x%x\n", PDAUDIOCF_FPGAREV(tmp
));
141 static void pdacf_proc_init(struct snd_pdacf
*chip
)
143 struct snd_info_entry
*entry
;
145 if (! snd_card_proc_new(chip
->card
, "pdaudiocf", &entry
))
146 snd_info_set_text_ops(entry
, chip
, pdacf_proc_read
);
149 struct snd_pdacf
*snd_pdacf_create(struct snd_card
*card
)
151 struct snd_pdacf
*chip
;
153 chip
= kzalloc(sizeof(*chip
), GFP_KERNEL
);
157 spin_lock_init(&chip
->reg_lock
);
158 spin_lock_init(&chip
->ak4117_lock
);
159 tasklet_init(&chip
->tq
, pdacf_tasklet
, (unsigned long)chip
);
160 card
->private_data
= chip
;
162 pdacf_proc_init(chip
);
166 static void snd_pdacf_ak4117_change(struct ak4117
*ak4117
, unsigned char c0
, unsigned char c1
)
168 struct snd_pdacf
*chip
= ak4117
->change_callback_private
;
172 if (!(c0
& AK4117_UNLCK
))
174 spin_lock_irqsave(&chip
->reg_lock
, flags
);
175 val
= chip
->regmap
[PDAUDIOCF_REG_SCR
>>1];
176 if (ak4117
->rcs0
& AK4117_UNLCK
)
177 val
|= PDAUDIOCF_BLUE_LED_OFF
;
179 val
&= ~PDAUDIOCF_BLUE_LED_OFF
;
180 pdacf_reg_write(chip
, PDAUDIOCF_REG_SCR
, val
);
181 spin_unlock_irqrestore(&chip
->reg_lock
, flags
);
184 int snd_pdacf_ak4117_create(struct snd_pdacf
*chip
)
188 /* design note: if we unmask PLL unlock, parity, valid, audio or auto bit interrupts */
189 /* from AK4117 then INT1 pin from AK4117 will be high all time, because PCMCIA interrupts are */
190 /* egde based and FPGA does logical OR for all interrupt sources, we cannot use these */
191 /* high-rate sources */
192 static unsigned char pgm
[5] = {
193 AK4117_XTL_24_576M
| AK4117_EXCT
, /* AK4117_REG_PWRDN */
194 AK4117_CM_PLL_XTAL
| AK4117_PKCS_128fs
| AK4117_XCKS_128fs
, /* AK4117_REQ_CLOCK */
195 AK4117_EFH_1024LRCLK
| AK4117_DIF_24R
| AK4117_IPS
, /* AK4117_REG_IO */
196 0xff, /* AK4117_REG_INT0_MASK */
197 AK4117_MAUTO
| AK4117_MAUD
| AK4117_MULK
| AK4117_MPAR
| AK4117_MV
, /* AK4117_REG_INT1_MASK */
200 err
= pdacf_reset(chip
, 0);
203 err
= snd_ak4117_create(chip
->card
, pdacf_ak4117_read
, pdacf_ak4117_write
, pgm
, chip
, &chip
->ak4117
);
207 val
= pdacf_reg_read(chip
, PDAUDIOCF_REG_TCR
);
208 #if 1 /* normal operation */
209 val
&= ~(PDAUDIOCF_ELIMAKMBIT
|PDAUDIOCF_TESTDATASEL
);
211 val
|= PDAUDIOCF_ELIMAKMBIT
;
212 val
&= ~PDAUDIOCF_TESTDATASEL
;
214 pdacf_reg_write(chip
, PDAUDIOCF_REG_TCR
, val
);
216 /* setup the FPGA to match AK4117 setup */
217 val
= pdacf_reg_read(chip
, PDAUDIOCF_REG_SCR
);
218 val
&= ~(PDAUDIOCF_CLKDIV0
| PDAUDIOCF_CLKDIV1
); /* use 24.576Mhz clock */
219 val
&= ~(PDAUDIOCF_RED_LED_OFF
|PDAUDIOCF_BLUE_LED_OFF
);
220 val
|= PDAUDIOCF_DATAFMT0
| PDAUDIOCF_DATAFMT1
; /* 24-bit data */
221 pdacf_reg_write(chip
, PDAUDIOCF_REG_SCR
, val
);
223 /* setup LEDs and IRQ */
224 val
= pdacf_reg_read(chip
, PDAUDIOCF_REG_IER
);
225 val
&= ~(PDAUDIOCF_IRQLVLEN0
| PDAUDIOCF_IRQLVLEN1
);
226 val
&= ~(PDAUDIOCF_BLUEDUTY0
| PDAUDIOCF_REDDUTY0
| PDAUDIOCF_REDDUTY1
);
227 val
|= PDAUDIOCF_BLUEDUTY1
| PDAUDIOCF_HALFRATE
;
228 val
|= PDAUDIOCF_IRQOVREN
| PDAUDIOCF_IRQAKMEN
;
229 pdacf_reg_write(chip
, PDAUDIOCF_REG_IER
, val
);
231 chip
->ak4117
->change_callback_private
= chip
;
232 chip
->ak4117
->change_callback
= snd_pdacf_ak4117_change
;
234 /* update LED status */
235 snd_pdacf_ak4117_change(chip
->ak4117
, AK4117_UNLCK
, 0);
240 void snd_pdacf_powerdown(struct snd_pdacf
*chip
)
244 val
= pdacf_reg_read(chip
, PDAUDIOCF_REG_SCR
);
245 chip
->suspend_reg_scr
= val
;
246 val
|= PDAUDIOCF_RED_LED_OFF
| PDAUDIOCF_BLUE_LED_OFF
;
247 pdacf_reg_write(chip
, PDAUDIOCF_REG_SCR
, val
);
248 /* disable interrupts, but use direct write to preserve old register value in chip->regmap */
249 val
= inw(chip
->port
+ PDAUDIOCF_REG_IER
);
250 val
&= ~(PDAUDIOCF_IRQOVREN
|PDAUDIOCF_IRQAKMEN
|PDAUDIOCF_IRQLVLEN0
|PDAUDIOCF_IRQLVLEN1
);
251 outw(val
, chip
->port
+ PDAUDIOCF_REG_IER
);
252 pdacf_reset(chip
, 1);
257 int snd_pdacf_suspend(struct snd_pdacf
*chip
, pm_message_t state
)
261 snd_power_change_state(chip
->card
, SNDRV_CTL_POWER_D3hot
);
262 snd_pcm_suspend_all(chip
->pcm
);
263 /* disable interrupts, but use direct write to preserve old register value in chip->regmap */
264 val
= inw(chip
->port
+ PDAUDIOCF_REG_IER
);
265 val
&= ~(PDAUDIOCF_IRQOVREN
|PDAUDIOCF_IRQAKMEN
|PDAUDIOCF_IRQLVLEN0
|PDAUDIOCF_IRQLVLEN1
);
266 outw(val
, chip
->port
+ PDAUDIOCF_REG_IER
);
267 chip
->chip_status
|= PDAUDIOCF_STAT_IS_SUSPENDED
; /* ignore interrupts from now */
268 snd_pdacf_powerdown(chip
);
272 static inline int check_signal(struct snd_pdacf
*chip
)
274 return (chip
->ak4117
->rcs0
& AK4117_UNLCK
) == 0;
277 int snd_pdacf_resume(struct snd_pdacf
*chip
)
281 pdacf_reinit(chip
, 1);
282 /* wait for AK4117's PLL */
283 while (timeout
-- > 0 &&
284 (snd_ak4117_external_rate(chip
->ak4117
) <= 0 || !check_signal(chip
)))
286 chip
->chip_status
&= ~PDAUDIOCF_STAT_IS_SUSPENDED
;
287 snd_power_change_state(chip
->card
, SNDRV_CTL_POWER_D0
);