1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * ALSA driver for ICEnsemble ICE1712 (Envy24) 4 * 5 * Lowlevel functions for Hoontech STDSP24 6 * 7 * Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz> 8 */ 9 10 #include <linux/delay.h> 11 #include <linux/interrupt.h> 12 #include <linux/init.h> 13 #include <linux/slab.h> 14 #include <linux/mutex.h> 15 16 #include <sound/core.h> 17 18 #include "ice1712.h" 19 #include "hoontech.h" 20 21 /* Hoontech-specific setting */ 22 struct hoontech_spec { 23 unsigned char boxbits[4]; 24 unsigned int config; 25 unsigned short boxconfig[4]; 26 }; 27 28 static void snd_ice1712_stdsp24_gpio_write(struct snd_ice1712 *ice, unsigned char byte) 29 { 30 byte |= ICE1712_STDSP24_CLOCK_BIT; 31 udelay(100); 32 snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, byte); 33 byte &= ~ICE1712_STDSP24_CLOCK_BIT; 34 udelay(100); 35 snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, byte); 36 byte |= ICE1712_STDSP24_CLOCK_BIT; 37 udelay(100); 38 snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, byte); 39 } 40 41 static void snd_ice1712_stdsp24_darear(struct snd_ice1712 *ice, int activate) 42 { 43 struct hoontech_spec *spec = ice->spec; 44 mutex_lock(&ice->gpio_mutex); 45 ICE1712_STDSP24_0_DAREAR(spec->boxbits, activate); 46 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[0]); 47 mutex_unlock(&ice->gpio_mutex); 48 } 49 50 static void snd_ice1712_stdsp24_mute(struct snd_ice1712 *ice, int activate) 51 { 52 struct hoontech_spec *spec = ice->spec; 53 mutex_lock(&ice->gpio_mutex); 54 ICE1712_STDSP24_3_MUTE(spec->boxbits, activate); 55 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]); 56 mutex_unlock(&ice->gpio_mutex); 57 } 58 59 static void snd_ice1712_stdsp24_insel(struct snd_ice1712 *ice, int activate) 60 { 61 struct hoontech_spec *spec = ice->spec; 62 mutex_lock(&ice->gpio_mutex); 63 ICE1712_STDSP24_3_INSEL(spec->boxbits, activate); 64 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]); 65 mutex_unlock(&ice->gpio_mutex); 66 } 67 68 static void snd_ice1712_stdsp24_box_channel(struct snd_ice1712 *ice, int box, int chn, int activate) 69 { 70 struct hoontech_spec *spec = ice->spec; 71 72 mutex_lock(&ice->gpio_mutex); 73 74 /* select box */ 75 ICE1712_STDSP24_0_BOX(spec->boxbits, box); 76 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[0]); 77 78 /* prepare for write */ 79 if (chn == 3) 80 ICE1712_STDSP24_2_CHN4(spec->boxbits, 0); 81 ICE1712_STDSP24_2_MIDI1(spec->boxbits, activate); 82 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); 83 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]); 84 85 ICE1712_STDSP24_1_CHN1(spec->boxbits, 1); 86 ICE1712_STDSP24_1_CHN2(spec->boxbits, 1); 87 ICE1712_STDSP24_1_CHN3(spec->boxbits, 1); 88 ICE1712_STDSP24_2_CHN4(spec->boxbits, 1); 89 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[1]); 90 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); 91 udelay(100); 92 if (chn == 3) { 93 ICE1712_STDSP24_2_CHN4(spec->boxbits, 0); 94 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); 95 } else { 96 switch (chn) { 97 case 0: ICE1712_STDSP24_1_CHN1(spec->boxbits, 0); break; 98 case 1: ICE1712_STDSP24_1_CHN2(spec->boxbits, 0); break; 99 case 2: ICE1712_STDSP24_1_CHN3(spec->boxbits, 0); break; 100 } 101 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[1]); 102 } 103 udelay(100); 104 ICE1712_STDSP24_1_CHN1(spec->boxbits, 1); 105 ICE1712_STDSP24_1_CHN2(spec->boxbits, 1); 106 ICE1712_STDSP24_1_CHN3(spec->boxbits, 1); 107 ICE1712_STDSP24_2_CHN4(spec->boxbits, 1); 108 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[1]); 109 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); 110 udelay(100); 111 112 ICE1712_STDSP24_2_MIDI1(spec->boxbits, 0); 113 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); 114 115 mutex_unlock(&ice->gpio_mutex); 116 } 117 118 static void snd_ice1712_stdsp24_box_midi(struct snd_ice1712 *ice, int box, int master) 119 { 120 struct hoontech_spec *spec = ice->spec; 121 122 mutex_lock(&ice->gpio_mutex); 123 124 /* select box */ 125 ICE1712_STDSP24_0_BOX(spec->boxbits, box); 126 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[0]); 127 128 ICE1712_STDSP24_2_MIDIIN(spec->boxbits, 1); 129 ICE1712_STDSP24_2_MIDI1(spec->boxbits, master); 130 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); 131 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]); 132 133 udelay(100); 134 135 ICE1712_STDSP24_2_MIDIIN(spec->boxbits, 0); 136 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); 137 138 mdelay(10); 139 140 ICE1712_STDSP24_2_MIDIIN(spec->boxbits, 1); 141 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); 142 143 mutex_unlock(&ice->gpio_mutex); 144 } 145 146 static void snd_ice1712_stdsp24_midi2(struct snd_ice1712 *ice, int activate) 147 { 148 struct hoontech_spec *spec = ice->spec; 149 mutex_lock(&ice->gpio_mutex); 150 ICE1712_STDSP24_3_MIDI2(spec->boxbits, activate); 151 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]); 152 mutex_unlock(&ice->gpio_mutex); 153 } 154 155 static int hoontech_init(struct snd_ice1712 *ice, bool staudio) 156 { 157 struct hoontech_spec *spec; 158 int box, chn; 159 160 ice->num_total_dacs = 8; 161 ice->num_total_adcs = 8; 162 163 spec = kzalloc(sizeof(*spec), GFP_KERNEL); 164 if (!spec) 165 return -ENOMEM; 166 ice->spec = spec; 167 168 ICE1712_STDSP24_SET_ADDR(spec->boxbits, 0); 169 ICE1712_STDSP24_CLOCK(spec->boxbits, 0, 1); 170 ICE1712_STDSP24_0_BOX(spec->boxbits, 0); 171 ICE1712_STDSP24_0_DAREAR(spec->boxbits, 0); 172 173 ICE1712_STDSP24_SET_ADDR(spec->boxbits, 1); 174 ICE1712_STDSP24_CLOCK(spec->boxbits, 1, 1); 175 ICE1712_STDSP24_1_CHN1(spec->boxbits, 1); 176 ICE1712_STDSP24_1_CHN2(spec->boxbits, 1); 177 ICE1712_STDSP24_1_CHN3(spec->boxbits, 1); 178 179 ICE1712_STDSP24_SET_ADDR(spec->boxbits, 2); 180 ICE1712_STDSP24_CLOCK(spec->boxbits, 2, 1); 181 ICE1712_STDSP24_2_CHN4(spec->boxbits, 1); 182 ICE1712_STDSP24_2_MIDIIN(spec->boxbits, 1); 183 ICE1712_STDSP24_2_MIDI1(spec->boxbits, 0); 184 185 ICE1712_STDSP24_SET_ADDR(spec->boxbits, 3); 186 ICE1712_STDSP24_CLOCK(spec->boxbits, 3, 1); 187 ICE1712_STDSP24_3_MIDI2(spec->boxbits, 0); 188 ICE1712_STDSP24_3_MUTE(spec->boxbits, 1); 189 ICE1712_STDSP24_3_INSEL(spec->boxbits, 0); 190 191 /* let's go - activate only functions in first box */ 192 if (staudio) 193 spec->config = ICE1712_STDSP24_MUTE; 194 else 195 spec->config = 0; 196 /* ICE1712_STDSP24_MUTE | 197 ICE1712_STDSP24_INSEL | 198 ICE1712_STDSP24_DAREAR; */ 199 /* These boxconfigs have caused problems in the past. 200 * The code is not optimal, but should now enable a working config to 201 * be achieved. 202 * ** MIDI IN can only be configured on one box ** 203 * ICE1712_STDSP24_BOX_MIDI1 needs to be set for that box. 204 * Tests on a ADAC2000 box suggest the box config flags do not 205 * work as would be expected, and the inputs are crossed. 206 * Setting ICE1712_STDSP24_BOX_MIDI1 and ICE1712_STDSP24_BOX_MIDI2 207 * on the same box connects MIDI-In to both 401 uarts; both outputs 208 * are then active on all boxes. 209 * The default config here sets up everything on the first box. 210 * Alan Horstmann 5.2.2008 211 */ 212 spec->boxconfig[0] = ICE1712_STDSP24_BOX_CHN1 | 213 ICE1712_STDSP24_BOX_CHN2 | 214 ICE1712_STDSP24_BOX_CHN3 | 215 ICE1712_STDSP24_BOX_CHN4 | 216 ICE1712_STDSP24_BOX_MIDI1 | 217 ICE1712_STDSP24_BOX_MIDI2; 218 if (staudio) { 219 spec->boxconfig[1] = 220 spec->boxconfig[2] = 221 spec->boxconfig[3] = spec->boxconfig[0]; 222 } else { 223 spec->boxconfig[1] = 224 spec->boxconfig[2] = 225 spec->boxconfig[3] = 0; 226 } 227 228 snd_ice1712_stdsp24_darear(ice, 229 (spec->config & ICE1712_STDSP24_DAREAR) ? 1 : 0); 230 snd_ice1712_stdsp24_mute(ice, 231 (spec->config & ICE1712_STDSP24_MUTE) ? 1 : 0); 232 snd_ice1712_stdsp24_insel(ice, 233 (spec->config & ICE1712_STDSP24_INSEL) ? 1 : 0); 234 for (box = 0; box < 4; box++) { 235 if (spec->boxconfig[box] & ICE1712_STDSP24_BOX_MIDI2) 236 snd_ice1712_stdsp24_midi2(ice, 1); 237 for (chn = 0; chn < 4; chn++) 238 snd_ice1712_stdsp24_box_channel(ice, box, chn, 239 (spec->boxconfig[box] & (1 << chn)) ? 1 : 0); 240 if (spec->boxconfig[box] & ICE1712_STDSP24_BOX_MIDI1) 241 snd_ice1712_stdsp24_box_midi(ice, box, 1); 242 } 243 244 return 0; 245 } 246 247 static int snd_ice1712_hoontech_init(struct snd_ice1712 *ice) 248 { 249 return hoontech_init(ice, false); 250 } 251 252 static int snd_ice1712_staudio_init(struct snd_ice1712 *ice) 253 { 254 return hoontech_init(ice, true); 255 } 256 257 /* 258 * AK4524 access 259 */ 260 261 /* start callback for STDSP24 with modified hardware */ 262 static void stdsp24_ak4524_lock(struct snd_akm4xxx *ak, int chip) 263 { 264 struct snd_ice1712 *ice = ak->private_data[0]; 265 unsigned char tmp; 266 snd_ice1712_save_gpio_status(ice); 267 tmp = ICE1712_STDSP24_SERIAL_DATA | 268 ICE1712_STDSP24_SERIAL_CLOCK | 269 ICE1712_STDSP24_AK4524_CS; 270 snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, 271 ice->gpio.direction | tmp); 272 snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~tmp); 273 } 274 275 static int snd_ice1712_value_init(struct snd_ice1712 *ice) 276 { 277 /* Hoontech STDSP24 with modified hardware */ 278 static const struct snd_akm4xxx akm_stdsp24_mv = { 279 .num_adcs = 2, 280 .num_dacs = 2, 281 .type = SND_AK4524, 282 .ops = { 283 .lock = stdsp24_ak4524_lock 284 } 285 }; 286 287 static const struct snd_ak4xxx_private akm_stdsp24_mv_priv = { 288 .caddr = 2, 289 .cif = 1, /* CIF high */ 290 .data_mask = ICE1712_STDSP24_SERIAL_DATA, 291 .clk_mask = ICE1712_STDSP24_SERIAL_CLOCK, 292 .cs_mask = ICE1712_STDSP24_AK4524_CS, 293 .cs_addr = ICE1712_STDSP24_AK4524_CS, 294 .cs_none = 0, 295 .add_flags = 0, 296 }; 297 298 int err; 299 struct snd_akm4xxx *ak; 300 301 /* set the analog DACs */ 302 ice->num_total_dacs = 2; 303 304 /* set the analog ADCs */ 305 ice->num_total_adcs = 2; 306 307 /* analog section */ 308 ak = ice->akm = kmalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); 309 if (! ak) 310 return -ENOMEM; 311 ice->akm_codecs = 1; 312 313 err = snd_ice1712_akm4xxx_init(ak, &akm_stdsp24_mv, &akm_stdsp24_mv_priv, ice); 314 if (err < 0) 315 return err; 316 317 /* ak4524 controls */ 318 return snd_ice1712_akm4xxx_build_controls(ice); 319 } 320 321 static int snd_ice1712_ez8_init(struct snd_ice1712 *ice) 322 { 323 ice->gpio.write_mask = ice->eeprom.gpiomask; 324 ice->gpio.direction = ice->eeprom.gpiodir; 325 snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ice->eeprom.gpiomask); 326 snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, ice->eeprom.gpiodir); 327 snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, ice->eeprom.gpiostate); 328 return 0; 329 } 330 331 332 /* entry point */ 333 struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] = { 334 { 335 .subvendor = ICE1712_SUBDEVICE_STDSP24, 336 .name = "Hoontech SoundTrack Audio DSP24", 337 .model = "dsp24", 338 .chip_init = snd_ice1712_hoontech_init, 339 .mpu401_1_name = "MIDI-1 Hoontech/STA DSP24", 340 .mpu401_2_name = "MIDI-2 Hoontech/STA DSP24", 341 }, 342 { 343 .subvendor = ICE1712_SUBDEVICE_STDSP24_VALUE, /* a dummy id */ 344 .name = "Hoontech SoundTrack Audio DSP24 Value", 345 .model = "dsp24_value", 346 .chip_init = snd_ice1712_value_init, 347 }, 348 { 349 .subvendor = ICE1712_SUBDEVICE_STDSP24_MEDIA7_1, 350 .name = "Hoontech STA DSP24 Media 7.1", 351 .model = "dsp24_71", 352 .chip_init = snd_ice1712_hoontech_init, 353 }, 354 { 355 .subvendor = ICE1712_SUBDEVICE_EVENT_EZ8, /* a dummy id */ 356 .name = "Event Electronics EZ8", 357 .model = "ez8", 358 .chip_init = snd_ice1712_ez8_init, 359 }, 360 { 361 /* STAudio ADCIII has the same SSID as Hoontech StA DSP24, 362 * thus identified only via the explicit model option 363 */ 364 .subvendor = ICE1712_SUBDEVICE_STAUDIO_ADCIII, /* a dummy id */ 365 .name = "STAudio ADCIII", 366 .model = "staudio", 367 .chip_init = snd_ice1712_staudio_init, 368 }, 369 { } /* terminator */ 370 }; 371