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 <linux/mutex.h> 31 32#include <sound/core.h> 33 34#include "ice1712.h" 35#include "hoontech.h" 36 37 38static void __devinit snd_ice1712_stdsp24_gpio_write(struct snd_ice1712 *ice, unsigned char byte) 39{ 40 byte |= ICE1712_STDSP24_CLOCK_BIT; 41 udelay(100); 42 snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, byte); 43 byte &= ~ICE1712_STDSP24_CLOCK_BIT; 44 udelay(100); 45 snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, byte); 46 byte |= ICE1712_STDSP24_CLOCK_BIT; 47 udelay(100); 48 snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, byte); 49} 50 51static void __devinit snd_ice1712_stdsp24_darear(struct snd_ice1712 *ice, int activate) 52{ 53 mutex_lock(&ice->gpio_mutex); 54 ICE1712_STDSP24_0_DAREAR(ice->spec.hoontech.boxbits, activate); 55 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[0]); 56 mutex_unlock(&ice->gpio_mutex); 57} 58 59static void __devinit snd_ice1712_stdsp24_mute(struct snd_ice1712 *ice, int activate) 60{ 61 mutex_lock(&ice->gpio_mutex); 62 ICE1712_STDSP24_3_MUTE(ice->spec.hoontech.boxbits, activate); 63 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]); 64 mutex_unlock(&ice->gpio_mutex); 65} 66 67static void __devinit snd_ice1712_stdsp24_insel(struct snd_ice1712 *ice, int activate) 68{ 69 mutex_lock(&ice->gpio_mutex); 70 ICE1712_STDSP24_3_INSEL(ice->spec.hoontech.boxbits, activate); 71 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]); 72 mutex_unlock(&ice->gpio_mutex); 73} 74 75static void __devinit snd_ice1712_stdsp24_box_channel(struct snd_ice1712 *ice, int box, int chn, int activate) 76{ 77 mutex_lock(&ice->gpio_mutex); 78 79 /* select box */ 80 ICE1712_STDSP24_0_BOX(ice->spec.hoontech.boxbits, box); 81 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[0]); 82 83 /* prepare for write */ 84 if (chn == 3) 85 ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 0); 86 ICE1712_STDSP24_2_MIDI1(ice->spec.hoontech.boxbits, activate); 87 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); 88 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]); 89 90 ICE1712_STDSP24_1_CHN1(ice->spec.hoontech.boxbits, 1); 91 ICE1712_STDSP24_1_CHN2(ice->spec.hoontech.boxbits, 1); 92 ICE1712_STDSP24_1_CHN3(ice->spec.hoontech.boxbits, 1); 93 ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 1); 94 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[1]); 95 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); 96 udelay(100); 97 if (chn == 3) { 98 ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 0); 99 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); 100 } else { 101 switch (chn) { 102 case 0: ICE1712_STDSP24_1_CHN1(ice->spec.hoontech.boxbits, 0); break; 103 case 1: ICE1712_STDSP24_1_CHN2(ice->spec.hoontech.boxbits, 0); break; 104 case 2: ICE1712_STDSP24_1_CHN3(ice->spec.hoontech.boxbits, 0); break; 105 } 106 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[1]); 107 } 108 udelay(100); 109 ICE1712_STDSP24_1_CHN1(ice->spec.hoontech.boxbits, 1); 110 ICE1712_STDSP24_1_CHN2(ice->spec.hoontech.boxbits, 1); 111 ICE1712_STDSP24_1_CHN3(ice->spec.hoontech.boxbits, 1); 112 ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 1); 113 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[1]); 114 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); 115 udelay(100); 116 117 ICE1712_STDSP24_2_MIDI1(ice->spec.hoontech.boxbits, 0); 118 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); 119 120 mutex_unlock(&ice->gpio_mutex); 121} 122 123static void __devinit snd_ice1712_stdsp24_box_midi(struct snd_ice1712 *ice, int box, int master) 124{ 125 mutex_lock(&ice->gpio_mutex); 126 127 /* select box */ 128 ICE1712_STDSP24_0_BOX(ice->spec.hoontech.boxbits, box); 129 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[0]); 130 131 ICE1712_STDSP24_2_MIDIIN(ice->spec.hoontech.boxbits, 1); 132 ICE1712_STDSP24_2_MIDI1(ice->spec.hoontech.boxbits, master); 133 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); 134 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]); 135 136 udelay(100); 137 138 ICE1712_STDSP24_2_MIDIIN(ice->spec.hoontech.boxbits, 0); 139 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); 140 141 mdelay(10); 142 143 ICE1712_STDSP24_2_MIDIIN(ice->spec.hoontech.boxbits, 1); 144 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); 145 146 mutex_unlock(&ice->gpio_mutex); 147} 148 149static void __devinit snd_ice1712_stdsp24_midi2(struct snd_ice1712 *ice, int activate) 150{ 151 mutex_lock(&ice->gpio_mutex); 152 ICE1712_STDSP24_3_MIDI2(ice->spec.hoontech.boxbits, activate); 153 snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]); 154 mutex_unlock(&ice->gpio_mutex); 155} 156 157static int __devinit snd_ice1712_hoontech_init(struct snd_ice1712 *ice) 158{ 159 int box, chn; 160 161 ice->num_total_dacs = 8; 162 ice->num_total_adcs = 8; 163 164 ice->spec.hoontech.boxbits[0] = 165 ice->spec.hoontech.boxbits[1] = 166 ice->spec.hoontech.boxbits[2] = 167 ice->spec.hoontech.boxbits[3] = 0; /* should be already */ 168 169 ICE1712_STDSP24_SET_ADDR(ice->spec.hoontech.boxbits, 0); 170 ICE1712_STDSP24_CLOCK(ice->spec.hoontech.boxbits, 0, 1); 171 ICE1712_STDSP24_0_BOX(ice->spec.hoontech.boxbits, 0); 172 ICE1712_STDSP24_0_DAREAR(ice->spec.hoontech.boxbits, 0); 173 174 ICE1712_STDSP24_SET_ADDR(ice->spec.hoontech.boxbits, 1); 175 ICE1712_STDSP24_CLOCK(ice->spec.hoontech.boxbits, 1, 1); 176 ICE1712_STDSP24_1_CHN1(ice->spec.hoontech.boxbits, 1); 177 ICE1712_STDSP24_1_CHN2(ice->spec.hoontech.boxbits, 1); 178 ICE1712_STDSP24_1_CHN3(ice->spec.hoontech.boxbits, 1); 179 180 ICE1712_STDSP24_SET_ADDR(ice->spec.hoontech.boxbits, 2); 181 ICE1712_STDSP24_CLOCK(ice->spec.hoontech.boxbits, 2, 1); 182 ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 1); 183 ICE1712_STDSP24_2_MIDIIN(ice->spec.hoontech.boxbits, 1); 184 ICE1712_STDSP24_2_MIDI1(ice->spec.hoontech.boxbits, 0); 185 186 ICE1712_STDSP24_SET_ADDR(ice->spec.hoontech.boxbits, 3); 187 ICE1712_STDSP24_CLOCK(ice->spec.hoontech.boxbits, 3, 1); 188 ICE1712_STDSP24_3_MIDI2(ice->spec.hoontech.boxbits, 0); 189 ICE1712_STDSP24_3_MUTE(ice->spec.hoontech.boxbits, 1); 190 ICE1712_STDSP24_3_INSEL(ice->spec.hoontech.boxbits, 0); 191 192 /* let's go - activate only functions in first box */ 193 ice->spec.hoontech.config = 0; 194 /* ICE1712_STDSP24_MUTE | 195 ICE1712_STDSP24_INSEL | 196 ICE1712_STDSP24_DAREAR; */ 197 ice->spec.hoontech.boxconfig[0] = ICE1712_STDSP24_BOX_CHN1 | 198 ICE1712_STDSP24_BOX_CHN2 | 199 ICE1712_STDSP24_BOX_CHN3 | 200 ICE1712_STDSP24_BOX_CHN4 | 201 ICE1712_STDSP24_BOX_MIDI1 | 202 ICE1712_STDSP24_BOX_MIDI2; 203 ice->spec.hoontech.boxconfig[1] = 204 ice->spec.hoontech.boxconfig[2] = 205 ice->spec.hoontech.boxconfig[3] = 0; 206 snd_ice1712_stdsp24_darear(ice, (ice->spec.hoontech.config & ICE1712_STDSP24_DAREAR) ? 1 : 0); 207 snd_ice1712_stdsp24_mute(ice, (ice->spec.hoontech.config & ICE1712_STDSP24_MUTE) ? 1 : 0); 208 snd_ice1712_stdsp24_insel(ice, (ice->spec.hoontech.config & ICE1712_STDSP24_INSEL) ? 1 : 0); 209 for (box = 0; box < 4; box++) { 210 for (chn = 0; chn < 4; chn++) 211 snd_ice1712_stdsp24_box_channel(ice, box, chn, (ice->spec.hoontech.boxconfig[box] & (1 << chn)) ? 1 : 0); 212 snd_ice1712_stdsp24_box_midi(ice, box, 213 (ice->spec.hoontech.boxconfig[box] & ICE1712_STDSP24_BOX_MIDI1) ? 1 : 0); 214 if (ice->spec.hoontech.boxconfig[box] & ICE1712_STDSP24_BOX_MIDI2) 215 snd_ice1712_stdsp24_midi2(ice, 1); 216 } 217 218 return 0; 219} 220 221/* 222 * AK4524 access 223 */ 224 225/* start callback for STDSP24 with modified hardware */ 226static void stdsp24_ak4524_lock(struct snd_akm4xxx *ak, int chip) 227{ 228 struct snd_ice1712 *ice = ak->private_data[0]; 229 unsigned char tmp; 230 snd_ice1712_save_gpio_status(ice); 231 tmp = ICE1712_STDSP24_SERIAL_DATA | 232 ICE1712_STDSP24_SERIAL_CLOCK | 233 ICE1712_STDSP24_AK4524_CS; 234 snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, 235 ice->gpio.direction | tmp); 236 snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~tmp); 237} 238 239static int __devinit snd_ice1712_value_init(struct snd_ice1712 *ice) 240{ 241 /* Hoontech STDSP24 with modified hardware */ 242 static struct snd_akm4xxx akm_stdsp24_mv __devinitdata = { 243 .num_adcs = 2, 244 .num_dacs = 2, 245 .type = SND_AK4524, 246 .ops = { 247 .lock = stdsp24_ak4524_lock 248 } 249 }; 250 251 static struct snd_ak4xxx_private akm_stdsp24_mv_priv __devinitdata = { 252 .caddr = 2, 253 .cif = 1, /* CIF high */ 254 .data_mask = ICE1712_STDSP24_SERIAL_DATA, 255 .clk_mask = ICE1712_STDSP24_SERIAL_CLOCK, 256 .cs_mask = ICE1712_STDSP24_AK4524_CS, 257 .cs_addr = ICE1712_STDSP24_AK4524_CS, 258 .cs_none = 0, 259 .add_flags = 0, 260 }; 261 262 int err; 263 struct snd_akm4xxx *ak; 264 265 /* set the analog DACs */ 266 ice->num_total_dacs = 2; 267 268 /* set the analog ADCs */ 269 ice->num_total_adcs = 2; 270 271 /* analog section */ 272 ak = ice->akm = kmalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); 273 if (! ak) 274 return -ENOMEM; 275 ice->akm_codecs = 1; 276 277 err = snd_ice1712_akm4xxx_init(ak, &akm_stdsp24_mv, &akm_stdsp24_mv_priv, ice); 278 if (err < 0) 279 return err; 280 281 /* ak4524 controls */ 282 err = snd_ice1712_akm4xxx_build_controls(ice); 283 if (err < 0) 284 return err; 285 286 return 0; 287} 288 289static int __devinit snd_ice1712_ez8_init(struct snd_ice1712 *ice) 290{ 291 ice->gpio.write_mask = ice->eeprom.gpiomask; 292 ice->gpio.direction = ice->eeprom.gpiodir; 293 snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ice->eeprom.gpiomask); 294 snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, ice->eeprom.gpiodir); 295 snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, ice->eeprom.gpiostate); 296 return 0; 297} 298 299 300/* entry point */ 301struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] __devinitdata = { 302 { 303 .subvendor = ICE1712_SUBDEVICE_STDSP24, 304 .name = "Hoontech SoundTrack Audio DSP24", 305 .model = "dsp24", 306 .chip_init = snd_ice1712_hoontech_init, 307 }, 308 { 309 .subvendor = ICE1712_SUBDEVICE_STDSP24_VALUE, /* a dummy id */ 310 .name = "Hoontech SoundTrack Audio DSP24 Value", 311 .model = "dsp24_value", 312 .chip_init = snd_ice1712_value_init, 313 }, 314 { 315 .subvendor = ICE1712_SUBDEVICE_STDSP24_MEDIA7_1, 316 .name = "Hoontech STA DSP24 Media 7.1", 317 .model = "dsp24_71", 318 .chip_init = snd_ice1712_hoontech_init, 319 }, 320 { 321 .subvendor = ICE1712_SUBDEVICE_EVENT_EZ8, /* a dummy id */ 322 .name = "Event Electronics EZ8", 323 .model = "ez8", 324 .chip_init = snd_ice1712_ez8_init, 325 }, 326 { } /* terminator */ 327}; 328