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