linux/sound/pci/ice1712/hoontech.c
<<
>>
Prefs
   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 */
  36struct hoontech_spec {
  37        unsigned char boxbits[4];
  38        unsigned int config;
  39        unsigned short boxconfig[4];
  40};
  41
  42static 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
  55static 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
  64static 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
  73static 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
  82static 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
 132static 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
 160static 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
 169static int snd_ice1712_hoontech_init(struct snd_ice1712 *ice)
 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        spec->config = 0;
 207                            /* ICE1712_STDSP24_MUTE |
 208                               ICE1712_STDSP24_INSEL |
 209                               ICE1712_STDSP24_DAREAR; */
 210        /*  These boxconfigs have caused problems in the past.
 211         *  The code is not optimal, but should now enable a working config to
 212         *  be achieved.
 213         *  ** MIDI IN can only be configured on one box **
 214         *  ICE1712_STDSP24_BOX_MIDI1 needs to be set for that box.
 215         *  Tests on a ADAC2000 box suggest the box config flags do not
 216         *  work as would be expected, and the inputs are crossed.
 217         *  Setting ICE1712_STDSP24_BOX_MIDI1 and ICE1712_STDSP24_BOX_MIDI2
 218         *  on the same box connects MIDI-In to both 401 uarts; both outputs
 219         *  are then active on all boxes.
 220         *  The default config here sets up everything on the first box.
 221         *  Alan Horstmann  5.2.2008
 222         */
 223        spec->boxconfig[0] = ICE1712_STDSP24_BOX_CHN1 |
 224                                     ICE1712_STDSP24_BOX_CHN2 |
 225                                     ICE1712_STDSP24_BOX_CHN3 |
 226                                     ICE1712_STDSP24_BOX_CHN4 |
 227                                     ICE1712_STDSP24_BOX_MIDI1 |
 228                                     ICE1712_STDSP24_BOX_MIDI2;
 229        spec->boxconfig[1] = 
 230        spec->boxconfig[2] = 
 231        spec->boxconfig[3] = 0;
 232        snd_ice1712_stdsp24_darear(ice,
 233                (spec->config & ICE1712_STDSP24_DAREAR) ? 1 : 0);
 234        snd_ice1712_stdsp24_mute(ice,
 235                (spec->config & ICE1712_STDSP24_MUTE) ? 1 : 0);
 236        snd_ice1712_stdsp24_insel(ice,
 237                (spec->config & ICE1712_STDSP24_INSEL) ? 1 : 0);
 238        for (box = 0; box < 4; box++) {
 239                if (spec->boxconfig[box] & ICE1712_STDSP24_BOX_MIDI2)
 240                        snd_ice1712_stdsp24_midi2(ice, 1);
 241                for (chn = 0; chn < 4; chn++)
 242                        snd_ice1712_stdsp24_box_channel(ice, box, chn,
 243                                (spec->boxconfig[box] & (1 << chn)) ? 1 : 0);
 244                if (spec->boxconfig[box] & ICE1712_STDSP24_BOX_MIDI1)
 245                        snd_ice1712_stdsp24_box_midi(ice, box, 1);
 246        }
 247
 248        return 0;
 249}
 250
 251/*
 252 * AK4524 access
 253 */
 254
 255/* start callback for STDSP24 with modified hardware */
 256static void stdsp24_ak4524_lock(struct snd_akm4xxx *ak, int chip)
 257{
 258        struct snd_ice1712 *ice = ak->private_data[0];
 259        unsigned char tmp;
 260        snd_ice1712_save_gpio_status(ice);
 261        tmp =   ICE1712_STDSP24_SERIAL_DATA |
 262                ICE1712_STDSP24_SERIAL_CLOCK |
 263                ICE1712_STDSP24_AK4524_CS;
 264        snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION,
 265                          ice->gpio.direction | tmp);
 266        snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~tmp);
 267}
 268
 269static int snd_ice1712_value_init(struct snd_ice1712 *ice)
 270{
 271        /* Hoontech STDSP24 with modified hardware */
 272        static struct snd_akm4xxx akm_stdsp24_mv = {
 273                .num_adcs = 2,
 274                .num_dacs = 2,
 275                .type = SND_AK4524,
 276                .ops = {
 277                        .lock = stdsp24_ak4524_lock
 278                }
 279        };
 280
 281        static struct snd_ak4xxx_private akm_stdsp24_mv_priv = {
 282                .caddr = 2,
 283                .cif = 1, /* CIF high */
 284                .data_mask = ICE1712_STDSP24_SERIAL_DATA,
 285                .clk_mask = ICE1712_STDSP24_SERIAL_CLOCK,
 286                .cs_mask = ICE1712_STDSP24_AK4524_CS,
 287                .cs_addr = ICE1712_STDSP24_AK4524_CS,
 288                .cs_none = 0,
 289                .add_flags = 0,
 290        };
 291
 292        int err;
 293        struct snd_akm4xxx *ak;
 294
 295        /* set the analog DACs */
 296        ice->num_total_dacs = 2;
 297
 298        /* set the analog ADCs */
 299        ice->num_total_adcs = 2;
 300        
 301        /* analog section */
 302        ak = ice->akm = kmalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
 303        if (! ak)
 304                return -ENOMEM;
 305        ice->akm_codecs = 1;
 306
 307        err = snd_ice1712_akm4xxx_init(ak, &akm_stdsp24_mv, &akm_stdsp24_mv_priv, ice);
 308        if (err < 0)
 309                return err;
 310
 311        /* ak4524 controls */
 312        return snd_ice1712_akm4xxx_build_controls(ice);
 313}
 314
 315static int snd_ice1712_ez8_init(struct snd_ice1712 *ice)
 316{
 317        ice->gpio.write_mask = ice->eeprom.gpiomask;
 318        ice->gpio.direction = ice->eeprom.gpiodir;
 319        snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ice->eeprom.gpiomask);
 320        snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, ice->eeprom.gpiodir);
 321        snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, ice->eeprom.gpiostate);
 322        return 0;
 323}
 324
 325
 326/* entry point */
 327struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] = {
 328        {
 329                .subvendor = ICE1712_SUBDEVICE_STDSP24,
 330                .name = "Hoontech SoundTrack Audio DSP24",
 331                .model = "dsp24",
 332                .chip_init = snd_ice1712_hoontech_init,
 333                .mpu401_1_name = "MIDI-1 Hoontech/STA DSP24",
 334                .mpu401_2_name = "MIDI-2 Hoontech/STA DSP24",
 335        },
 336        {
 337                .subvendor = ICE1712_SUBDEVICE_STDSP24_VALUE,   /* a dummy id */
 338                .name = "Hoontech SoundTrack Audio DSP24 Value",
 339                .model = "dsp24_value",
 340                .chip_init = snd_ice1712_value_init,
 341        },
 342        {
 343                .subvendor = ICE1712_SUBDEVICE_STDSP24_MEDIA7_1,
 344                .name = "Hoontech STA DSP24 Media 7.1",
 345                .model = "dsp24_71",
 346                .chip_init = snd_ice1712_hoontech_init,
 347        },
 348        {
 349                .subvendor = ICE1712_SUBDEVICE_EVENT_EZ8,       /* a dummy id */
 350                .name = "Event Electronics EZ8",
 351                .model = "ez8",
 352                .chip_init = snd_ice1712_ez8_init,
 353        },
 354        { } /* terminator */
 355};
 356