371 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * ALSA driver for ICEnsemble ICE1712 (Envy24)4 *5 * Lowlevel functions for Hoontech STDSP246 *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 */22struct hoontech_spec {23 unsigned char boxbits[4];24 unsigned int config;25 unsigned short boxconfig[4];26};27 28static 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 41static 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 50static 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 59static 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 68static 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 118static 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 146static 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 155static 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 else195 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 to201 * 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 not205 * work as would be expected, and the inputs are crossed.206 * Setting ICE1712_STDSP24_BOX_MIDI1 and ICE1712_STDSP24_BOX_MIDI2207 * on the same box connects MIDI-In to both 401 uarts; both outputs208 * are then active on all boxes.209 * The default config here sets up everything on the first box.210 * Alan Horstmann 5.2.2008211 */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 247static int snd_ice1712_hoontech_init(struct snd_ice1712 *ice)248{249 return hoontech_init(ice, false);250}251 252static int snd_ice1712_staudio_init(struct snd_ice1712 *ice)253{254 return hoontech_init(ice, true);255}256 257/*258 * AK4524 access259 */260 261/* start callback for STDSP24 with modified hardware */262static 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 275static 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_lock284 }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 321static 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 */333struct 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 option363 */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