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 45 guard(mutex)(&ice->gpio_mutex); 46 ICE1712_STDSP24_0_DAREAR(spec->boxbits, activate); 47 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[0]); 48 } 49 50 static void snd_ice1712_stdsp24_mute(struct snd_ice1712 *ice, int activate) 51 { 52 struct hoontech_spec *spec = ice->spec; 53 54 guard(mutex)(&ice->gpio_mutex); 55 ICE1712_STDSP24_3_MUTE(spec->boxbits, activate); 56 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]); 57 } 58 59 static void snd_ice1712_stdsp24_insel(struct snd_ice1712 *ice, int activate) 60 { 61 struct hoontech_spec *spec = ice->spec; 62 63 guard(mutex)(&ice->gpio_mutex); 64 ICE1712_STDSP24_3_INSEL(spec->boxbits, activate); 65 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]); 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 guard(mutex)(&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 116 static void snd_ice1712_stdsp24_box_midi(struct snd_ice1712 *ice, int box, int master) 117 { 118 struct hoontech_spec *spec = ice->spec; 119 120 guard(mutex)(&ice->gpio_mutex); 121 122 /* select box */ 123 ICE1712_STDSP24_0_BOX(spec->boxbits, box); 124 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[0]); 125 126 ICE1712_STDSP24_2_MIDIIN(spec->boxbits, 1); 127 ICE1712_STDSP24_2_MIDI1(spec->boxbits, master); 128 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); 129 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]); 130 131 udelay(100); 132 133 ICE1712_STDSP24_2_MIDIIN(spec->boxbits, 0); 134 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); 135 136 mdelay(10); 137 138 ICE1712_STDSP24_2_MIDIIN(spec->boxbits, 1); 139 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); 140 } 141 142 static void snd_ice1712_stdsp24_midi2(struct snd_ice1712 *ice, int activate) 143 { 144 struct hoontech_spec *spec = ice->spec; 145 146 guard(mutex)(&ice->gpio_mutex); 147 ICE1712_STDSP24_3_MIDI2(spec->boxbits, activate); 148 snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]); 149 } 150 151 static int hoontech_init(struct snd_ice1712 *ice, bool staudio) 152 { 153 struct hoontech_spec *spec; 154 int box, chn; 155 156 ice->num_total_dacs = 8; 157 ice->num_total_adcs = 8; 158 159 spec = kzalloc(sizeof(*spec), GFP_KERNEL); 160 if (!spec) 161 return -ENOMEM; 162 ice->spec = spec; 163 164 ICE1712_STDSP24_SET_ADDR(spec->boxbits, 0); 165 ICE1712_STDSP24_CLOCK(spec->boxbits, 0, 1); 166 ICE1712_STDSP24_0_BOX(spec->boxbits, 0); 167 ICE1712_STDSP24_0_DAREAR(spec->boxbits, 0); 168 169 ICE1712_STDSP24_SET_ADDR(spec->boxbits, 1); 170 ICE1712_STDSP24_CLOCK(spec->boxbits, 1, 1); 171 ICE1712_STDSP24_1_CHN1(spec->boxbits, 1); 172 ICE1712_STDSP24_1_CHN2(spec->boxbits, 1); 173 ICE1712_STDSP24_1_CHN3(spec->boxbits, 1); 174 175 ICE1712_STDSP24_SET_ADDR(spec->boxbits, 2); 176 ICE1712_STDSP24_CLOCK(spec->boxbits, 2, 1); 177 ICE1712_STDSP24_2_CHN4(spec->boxbits, 1); 178 ICE1712_STDSP24_2_MIDIIN(spec->boxbits, 1); 179 ICE1712_STDSP24_2_MIDI1(spec->boxbits, 0); 180 181 ICE1712_STDSP24_SET_ADDR(spec->boxbits, 3); 182 ICE1712_STDSP24_CLOCK(spec->boxbits, 3, 1); 183 ICE1712_STDSP24_3_MIDI2(spec->boxbits, 0); 184 ICE1712_STDSP24_3_MUTE(spec->boxbits, 1); 185 ICE1712_STDSP24_3_INSEL(spec->boxbits, 0); 186 187 /* let's go - activate only functions in first box */ 188 if (staudio) 189 spec->config = ICE1712_STDSP24_MUTE; 190 else 191 spec->config = 0; 192 /* ICE1712_STDSP24_MUTE | 193 ICE1712_STDSP24_INSEL | 194 ICE1712_STDSP24_DAREAR; */ 195 /* These boxconfigs have caused problems in the past. 196 * The code is not optimal, but should now enable a working config to 197 * be achieved. 198 * ** MIDI IN can only be configured on one box ** 199 * ICE1712_STDSP24_BOX_MIDI1 needs to be set for that box. 200 * Tests on a ADAC2000 box suggest the box config flags do not 201 * work as would be expected, and the inputs are crossed. 202 * Setting ICE1712_STDSP24_BOX_MIDI1 and ICE1712_STDSP24_BOX_MIDI2 203 * on the same box connects MIDI-In to both 401 uarts; both outputs 204 * are then active on all boxes. 205 * The default config here sets up everything on the first box. 206 * Alan Horstmann 5.2.2008 207 */ 208 spec->boxconfig[0] = ICE1712_STDSP24_BOX_CHN1 | 209 ICE1712_STDSP24_BOX_CHN2 | 210 ICE1712_STDSP24_BOX_CHN3 | 211 ICE1712_STDSP24_BOX_CHN4 | 212 ICE1712_STDSP24_BOX_MIDI1 | 213 ICE1712_STDSP24_BOX_MIDI2; 214 if (staudio) { 215 spec->boxconfig[1] = 216 spec->boxconfig[2] = 217 spec->boxconfig[3] = spec->boxconfig[0]; 218 } else { 219 spec->boxconfig[1] = 220 spec->boxconfig[2] = 221 spec->boxconfig[3] = 0; 222 } 223 224 snd_ice1712_stdsp24_darear(ice, 225 (spec->config & ICE1712_STDSP24_DAREAR) ? 1 : 0); 226 snd_ice1712_stdsp24_mute(ice, 227 (spec->config & ICE1712_STDSP24_MUTE) ? 1 : 0); 228 snd_ice1712_stdsp24_insel(ice, 229 (spec->config & ICE1712_STDSP24_INSEL) ? 1 : 0); 230 for (box = 0; box < 4; box++) { 231 if (spec->boxconfig[box] & ICE1712_STDSP24_BOX_MIDI2) 232 snd_ice1712_stdsp24_midi2(ice, 1); 233 for (chn = 0; chn < 4; chn++) 234 snd_ice1712_stdsp24_box_channel(ice, box, chn, 235 (spec->boxconfig[box] & (1 << chn)) ? 1 : 0); 236 if (spec->boxconfig[box] & ICE1712_STDSP24_BOX_MIDI1) 237 snd_ice1712_stdsp24_box_midi(ice, box, 1); 238 } 239 240 return 0; 241 } 242 243 static int snd_ice1712_hoontech_init(struct snd_ice1712 *ice) 244 { 245 return hoontech_init(ice, false); 246 } 247 248 static int snd_ice1712_staudio_init(struct snd_ice1712 *ice) 249 { 250 return hoontech_init(ice, true); 251 } 252 253 /* 254 * AK4524 access 255 */ 256 257 /* start callback for STDSP24 with modified hardware */ 258 static void stdsp24_ak4524_lock(struct snd_akm4xxx *ak, int chip) 259 { 260 struct snd_ice1712 *ice = ak->private_data[0]; 261 unsigned char tmp; 262 snd_ice1712_save_gpio_status(ice); 263 tmp = ICE1712_STDSP24_SERIAL_DATA | 264 ICE1712_STDSP24_SERIAL_CLOCK | 265 ICE1712_STDSP24_AK4524_CS; 266 snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, 267 ice->gpio.direction | tmp); 268 snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~tmp); 269 } 270 271 static int snd_ice1712_value_init(struct snd_ice1712 *ice) 272 { 273 /* Hoontech STDSP24 with modified hardware */ 274 static const struct snd_akm4xxx akm_stdsp24_mv = { 275 .num_adcs = 2, 276 .num_dacs = 2, 277 .type = SND_AK4524, 278 .ops = { 279 .lock = stdsp24_ak4524_lock 280 } 281 }; 282 283 static const struct snd_ak4xxx_private akm_stdsp24_mv_priv = { 284 .caddr = 2, 285 .cif = 1, /* CIF high */ 286 .data_mask = ICE1712_STDSP24_SERIAL_DATA, 287 .clk_mask = ICE1712_STDSP24_SERIAL_CLOCK, 288 .cs_mask = ICE1712_STDSP24_AK4524_CS, 289 .cs_addr = ICE1712_STDSP24_AK4524_CS, 290 .cs_none = 0, 291 .add_flags = 0, 292 }; 293 294 int err; 295 struct snd_akm4xxx *ak; 296 297 /* set the analog DACs */ 298 ice->num_total_dacs = 2; 299 300 /* set the analog ADCs */ 301 ice->num_total_adcs = 2; 302 303 /* analog section */ 304 ak = ice->akm = kmalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); 305 if (! ak) 306 return -ENOMEM; 307 ice->akm_codecs = 1; 308 309 err = snd_ice1712_akm4xxx_init(ak, &akm_stdsp24_mv, &akm_stdsp24_mv_priv, ice); 310 if (err < 0) 311 return err; 312 313 /* ak4524 controls */ 314 return snd_ice1712_akm4xxx_build_controls(ice); 315 } 316 317 static int snd_ice1712_ez8_init(struct snd_ice1712 *ice) 318 { 319 ice->gpio.write_mask = ice->eeprom.gpiomask; 320 ice->gpio.direction = ice->eeprom.gpiodir; 321 snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ice->eeprom.gpiomask); 322 snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, ice->eeprom.gpiodir); 323 snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, ice->eeprom.gpiostate); 324 return 0; 325 } 326 327 328 /* entry point */ 329 struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] = { 330 { 331 .subvendor = ICE1712_SUBDEVICE_STDSP24, 332 .name = "Hoontech SoundTrack Audio DSP24", 333 .model = "dsp24", 334 .chip_init = snd_ice1712_hoontech_init, 335 .mpu401_1_name = "MIDI-1 Hoontech/STA DSP24", 336 .mpu401_2_name = "MIDI-2 Hoontech/STA DSP24", 337 }, 338 { 339 .subvendor = ICE1712_SUBDEVICE_STDSP24_VALUE, /* a dummy id */ 340 .name = "Hoontech SoundTrack Audio DSP24 Value", 341 .model = "dsp24_value", 342 .chip_init = snd_ice1712_value_init, 343 }, 344 { 345 .subvendor = ICE1712_SUBDEVICE_STDSP24_MEDIA7_1, 346 .name = "Hoontech STA DSP24 Media 7.1", 347 .model = "dsp24_71", 348 .chip_init = snd_ice1712_hoontech_init, 349 }, 350 { 351 .subvendor = ICE1712_SUBDEVICE_EVENT_EZ8, /* a dummy id */ 352 .name = "Event Electronics EZ8", 353 .model = "ez8", 354 .chip_init = snd_ice1712_ez8_init, 355 }, 356 { 357 /* STAudio ADCIII has the same SSID as Hoontech StA DSP24, 358 * thus identified only via the explicit model option 359 */ 360 .subvendor = ICE1712_SUBDEVICE_STAUDIO_ADCIII, /* a dummy id */ 361 .name = "STAudio ADCIII", 362 .model = "staudio", 363 .chip_init = snd_ice1712_staudio_init, 364 }, 365 { } /* terminator */ 366 }; 367