1 /* 2 * ALSA driver for ICEnsemble ICE1712 (Envy24) 3 * 4 * Lowlevel functions for Hoontech STDSP24 5 * 6 * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 */ 23 24 #include <sound/driver.h> 25 #include <asm/io.h> 26 #include <linux/delay.h> 27 #include <linux/interrupt.h> 28 #include <linux/init.h> 29 #include <linux/slab.h> 30 #include <sound/core.h> 31 32 #include "ice1712.h" 33 #include "hoontech.h" 34 35 36 static void __devinit snd_ice1712_stdsp24_gpio_write(ice1712_t *ice, unsigned char byte) 37 { 38 byte |= ICE1712_STDSP24_CLOCK_BIT; 39 udelay(100); 40 snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, byte); 41 byte &= ~ICE1712_STDSP24_CLOCK_BIT; 42 udelay(100); 43 snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, byte); 44 byte |= ICE1712_STDSP24_CLOCK_BIT; 45 udelay(100); 46 snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, byte); 47 } 48 49 static void __devinit snd_ice1712_stdsp24_darear(ice1712_t *ice, int activate) 50 { 51 down(&ice->gpio_mutex); 52 ICE1712_STDSP24_0_DAREAR(ice->spec.hoontech.boxbits, activate); 53 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[0]); 54 up(&ice->gpio_mutex); 55 } 56 57 static void __devinit snd_ice1712_stdsp24_mute(ice1712_t *ice, int activate) 58 { 59 down(&ice->gpio_mutex); 60 ICE1712_STDSP24_3_MUTE(ice->spec.hoontech.boxbits, activate); 61 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]); 62 up(&ice->gpio_mutex); 63 } 64 65 static void __devinit snd_ice1712_stdsp24_insel(ice1712_t *ice, int activate) 66 { 67 down(&ice->gpio_mutex); 68 ICE1712_STDSP24_3_INSEL(ice->spec.hoontech.boxbits, activate); 69 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]); 70 up(&ice->gpio_mutex); 71 } 72 73 static void __devinit snd_ice1712_stdsp24_box_channel(ice1712_t *ice, int box, int chn, int activate) 74 { 75 down(&ice->gpio_mutex); 76 77 /* select box */ 78 ICE1712_STDSP24_0_BOX(ice->spec.hoontech.boxbits, box); 79 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[0]); 80 81 /* prepare for write */ 82 if (chn == 3) 83 ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 0); 84 ICE1712_STDSP24_2_MIDI1(ice->spec.hoontech.boxbits, activate); 85 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); 86 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]); 87 88 ICE1712_STDSP24_1_CHN1(ice->spec.hoontech.boxbits, 1); 89 ICE1712_STDSP24_1_CHN2(ice->spec.hoontech.boxbits, 1); 90 ICE1712_STDSP24_1_CHN3(ice->spec.hoontech.boxbits, 1); 91 ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 1); 92 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[1]); 93 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); 94 udelay(100); 95 if (chn == 3) { 96 ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 0); 97 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); 98 } else { 99 switch (chn) { 100 case 0: ICE1712_STDSP24_1_CHN1(ice->spec.hoontech.boxbits, 0); break; 101 case 1: ICE1712_STDSP24_1_CHN2(ice->spec.hoontech.boxbits, 0); break; 102 case 2: ICE1712_STDSP24_1_CHN3(ice->spec.hoontech.boxbits, 0); break; 103 } 104 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[1]); 105 } 106 udelay(100); 107 ICE1712_STDSP24_1_CHN1(ice->spec.hoontech.boxbits, 1); 108 ICE1712_STDSP24_1_CHN2(ice->spec.hoontech.boxbits, 1); 109 ICE1712_STDSP24_1_CHN3(ice->spec.hoontech.boxbits, 1); 110 ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 1); 111 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[1]); 112 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); 113 udelay(100); 114 115 ICE1712_STDSP24_2_MIDI1(ice->spec.hoontech.boxbits, 0); 116 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); 117 118 up(&ice->gpio_mutex); 119 } 120 121 static void __devinit snd_ice1712_stdsp24_box_midi(ice1712_t *ice, int box, int master) 122 { 123 down(&ice->gpio_mutex); 124 125 /* select box */ 126 ICE1712_STDSP24_0_BOX(ice->spec.hoontech.boxbits, box); 127 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[0]); 128 129 ICE1712_STDSP24_2_MIDIIN(ice->spec.hoontech.boxbits, 1); 130 ICE1712_STDSP24_2_MIDI1(ice->spec.hoontech.boxbits, master); 131 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); 132 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]); 133 134 udelay(100); 135 136 ICE1712_STDSP24_2_MIDIIN(ice->spec.hoontech.boxbits, 0); 137 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); 138 139 mdelay(10); 140 141 ICE1712_STDSP24_2_MIDIIN(ice->spec.hoontech.boxbits, 1); 142 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); 143 144 up(&ice->gpio_mutex); 145 } 146 147 static void __devinit snd_ice1712_stdsp24_midi2(ice1712_t *ice, int activate) 148 { 149 down(&ice->gpio_mutex); 150 ICE1712_STDSP24_3_MIDI2(ice->spec.hoontech.boxbits, activate); 151 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]); 152 up(&ice->gpio_mutex); 153 } 154 155 static int __devinit snd_ice1712_hoontech_init(ice1712_t *ice) 156 { 157 int box, chn; 158 159 ice->num_total_dacs = 8; 160 ice->num_total_adcs = 8; 161 162 ice->spec.hoontech.boxbits[0] = 163 ice->spec.hoontech.boxbits[1] = 164 ice->spec.hoontech.boxbits[2] = 165 ice->spec.hoontech.boxbits[3] = 0; /* should be already */ 166 167 ICE1712_STDSP24_SET_ADDR(ice->spec.hoontech.boxbits, 0); 168 ICE1712_STDSP24_CLOCK(ice->spec.hoontech.boxbits, 0, 1); 169 ICE1712_STDSP24_0_BOX(ice->spec.hoontech.boxbits, 0); 170 ICE1712_STDSP24_0_DAREAR(ice->spec.hoontech.boxbits, 0); 171 172 ICE1712_STDSP24_SET_ADDR(ice->spec.hoontech.boxbits, 1); 173 ICE1712_STDSP24_CLOCK(ice->spec.hoontech.boxbits, 1, 1); 174 ICE1712_STDSP24_1_CHN1(ice->spec.hoontech.boxbits, 1); 175 ICE1712_STDSP24_1_CHN2(ice->spec.hoontech.boxbits, 1); 176 ICE1712_STDSP24_1_CHN3(ice->spec.hoontech.boxbits, 1); 177 178 ICE1712_STDSP24_SET_ADDR(ice->spec.hoontech.boxbits, 2); 179 ICE1712_STDSP24_CLOCK(ice->spec.hoontech.boxbits, 2, 1); 180 ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 1); 181 ICE1712_STDSP24_2_MIDIIN(ice->spec.hoontech.boxbits, 1); 182 ICE1712_STDSP24_2_MIDI1(ice->spec.hoontech.boxbits, 0); 183 184 ICE1712_STDSP24_SET_ADDR(ice->spec.hoontech.boxbits, 3); 185 ICE1712_STDSP24_CLOCK(ice->spec.hoontech.boxbits, 3, 1); 186 ICE1712_STDSP24_3_MIDI2(ice->spec.hoontech.boxbits, 0); 187 ICE1712_STDSP24_3_MUTE(ice->spec.hoontech.boxbits, 1); 188 ICE1712_STDSP24_3_INSEL(ice->spec.hoontech.boxbits, 0); 189 190 /* let's go - activate only functions in first box */ 191 ice->spec.hoontech.config = 0; 192 /* ICE1712_STDSP24_MUTE | 193 ICE1712_STDSP24_INSEL | 194 ICE1712_STDSP24_DAREAR; */ 195 ice->spec.hoontech.boxconfig[0] = ICE1712_STDSP24_BOX_CHN1 | 196 ICE1712_STDSP24_BOX_CHN2 | 197 ICE1712_STDSP24_BOX_CHN3 | 198 ICE1712_STDSP24_BOX_CHN4 | 199 ICE1712_STDSP24_BOX_MIDI1 | 200 ICE1712_STDSP24_BOX_MIDI2; 201 ice->spec.hoontech.boxconfig[1] = 202 ice->spec.hoontech.boxconfig[2] = 203 ice->spec.hoontech.boxconfig[3] = 0; 204 snd_ice1712_stdsp24_darear(ice, (ice->spec.hoontech.config & ICE1712_STDSP24_DAREAR) ? 1 : 0); 205 snd_ice1712_stdsp24_mute(ice, (ice->spec.hoontech.config & ICE1712_STDSP24_MUTE) ? 1 : 0); 206 snd_ice1712_stdsp24_insel(ice, (ice->spec.hoontech.config & ICE1712_STDSP24_INSEL) ? 1 : 0); 207 for (box = 0; box < 4; box++) { 208 for (chn = 0; chn < 4; chn++) 209 snd_ice1712_stdsp24_box_channel(ice, box, chn, (ice->spec.hoontech.boxconfig[box] & (1 << chn)) ? 1 : 0); 210 snd_ice1712_stdsp24_box_midi(ice, box, 211 (ice->spec.hoontech.boxconfig[box] & ICE1712_STDSP24_BOX_MIDI1) ? 1 : 0); 212 if (ice->spec.hoontech.boxconfig[box] & ICE1712_STDSP24_BOX_MIDI2) 213 snd_ice1712_stdsp24_midi2(ice, 1); 214 } 215 216 return 0; 217 } 218 219 /* 220 * AK4524 access 221 */ 222 223 /* start callback for STDSP24 with modified hardware */ 224 static void stdsp24_ak4524_lock(akm4xxx_t *ak, int chip) 225 { 226 ice1712_t *ice = ak->private_data[0]; 227 unsigned char tmp; 228 snd_ice1712_save_gpio_status(ice); 229 tmp = ICE1712_STDSP24_SERIAL_DATA | 230 ICE1712_STDSP24_SERIAL_CLOCK | 231 ICE1712_STDSP24_AK4524_CS; 232 snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, 233 ice->gpio.direction | tmp); 234 snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~tmp); 235 } 236 237 static int __devinit snd_ice1712_value_init(ice1712_t *ice) 238 { 239 /* Hoontech STDSP24 with modified hardware */ 240 static akm4xxx_t akm_stdsp24_mv __devinitdata = { 241 .num_adcs = 2, 242 .num_dacs = 2, 243 .type = SND_AK4524, 244 .ops = { 245 .lock = stdsp24_ak4524_lock 246 } 247 }; 248 249 static struct snd_ak4xxx_private akm_stdsp24_mv_priv __devinitdata = { 250 .caddr = 2, 251 .cif = 1, /* CIF high */ 252 .data_mask = ICE1712_STDSP24_SERIAL_DATA, 253 .clk_mask = ICE1712_STDSP24_SERIAL_CLOCK, 254 .cs_mask = ICE1712_STDSP24_AK4524_CS, 255 .cs_addr = ICE1712_STDSP24_AK4524_CS, 256 .cs_none = 0, 257 .add_flags = 0, 258 }; 259 260 int err; 261 akm4xxx_t *ak; 262 263 /* set the analog DACs */ 264 ice->num_total_dacs = 2; 265 266 /* set the analog ADCs */ 267 ice->num_total_adcs = 2; 268 269 /* analog section */ 270 ak = ice->akm = kmalloc(sizeof(akm4xxx_t), GFP_KERNEL); 271 if (! ak) 272 return -ENOMEM; 273 ice->akm_codecs = 1; 274 275 err = snd_ice1712_akm4xxx_init(ak, &akm_stdsp24_mv, &akm_stdsp24_mv_priv, ice); 276 if (err < 0) 277 return err; 278 279 /* ak4524 controls */ 280 err = snd_ice1712_akm4xxx_build_controls(ice); 281 if (err < 0) 282 return err; 283 284 return 0; 285 } 286 287 static int __devinit snd_ice1712_ez8_init(ice1712_t *ice) 288 { 289 ice->gpio.write_mask = ice->eeprom.gpiomask; 290 ice->gpio.direction = ice->eeprom.gpiodir; 291 snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ice->eeprom.gpiomask); 292 snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, ice->eeprom.gpiodir); 293 snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, ice->eeprom.gpiostate); 294 return 0; 295 } 296 297 298 /* entry point */ 299 struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] __devinitdata = { 300 { 301 .subvendor = ICE1712_SUBDEVICE_STDSP24, 302 .name = "Hoontech SoundTrack Audio DSP24", 303 .model = "dsp24", 304 .chip_init = snd_ice1712_hoontech_init, 305 }, 306 { 307 .subvendor = ICE1712_SUBDEVICE_STDSP24_VALUE, /* a dummy id */ 308 .name = "Hoontech SoundTrack Audio DSP24 Value", 309 .model = "dsp24_value", 310 .chip_init = snd_ice1712_value_init, 311 }, 312 { 313 .subvendor = ICE1712_SUBDEVICE_STDSP24_MEDIA7_1, 314 .name = "Hoontech STA DSP24 Media 7.1", 315 .model = "dsp24_71", 316 .chip_init = snd_ice1712_hoontech_init, 317 }, 318 { 319 .subvendor = ICE1712_SUBDEVICE_EVENT_EZ8, /* a dummy id */ 320 .name = "Event Electronics EZ8", 321 .model = "ez8", 322 .chip_init = snd_ice1712_ez8_init, 323 }, 324 { } /* terminator */ 325 }; 326 327