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