linux/sound/pci/ice1712/ak4xxx.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *   ALSA driver for ICEnsemble ICE1712 (Envy24)
   4 *
   5 *   AK4524 / AK4528 / AK4529 / AK4355 / AK4381 interface
   6 *
   7 *      Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz>
   8 */      
   9
  10#include <linux/io.h>
  11#include <linux/delay.h>
  12#include <linux/interrupt.h>
  13#include <linux/slab.h>
  14#include <linux/init.h>
  15#include <linux/module.h>
  16#include <sound/core.h>
  17#include <sound/initval.h>
  18#include "ice1712.h"
  19
  20MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
  21MODULE_DESCRIPTION("ICEnsemble ICE17xx <-> AK4xxx AD/DA chip interface");
  22MODULE_LICENSE("GPL");
  23
  24static void snd_ice1712_akm4xxx_lock(struct snd_akm4xxx *ak, int chip)
  25{
  26        struct snd_ice1712 *ice = ak->private_data[0];
  27
  28        snd_ice1712_save_gpio_status(ice);
  29}
  30
  31static void snd_ice1712_akm4xxx_unlock(struct snd_akm4xxx *ak, int chip)
  32{
  33        struct snd_ice1712 *ice = ak->private_data[0];
  34
  35        snd_ice1712_restore_gpio_status(ice);
  36}
  37
  38/*
  39 * write AK4xxx register
  40 */
  41static void snd_ice1712_akm4xxx_write(struct snd_akm4xxx *ak, int chip,
  42                                      unsigned char addr, unsigned char data)
  43{
  44        unsigned int tmp;
  45        int idx;
  46        unsigned int addrdata;
  47        struct snd_ak4xxx_private *priv = (void *)ak->private_value[0];
  48        struct snd_ice1712 *ice = ak->private_data[0];
  49
  50        if (snd_BUG_ON(chip < 0 || chip >= 4))
  51                return;
  52
  53        tmp = snd_ice1712_gpio_read(ice);
  54        tmp |= priv->add_flags;
  55        tmp &= ~priv->mask_flags;
  56        if (priv->cs_mask == priv->cs_addr) {
  57                if (priv->cif) {
  58                        tmp |= priv->cs_mask; /* start without chip select */
  59                }  else {
  60                        tmp &= ~priv->cs_mask; /* chip select low */
  61                        snd_ice1712_gpio_write(ice, tmp);
  62                        udelay(1);
  63                }
  64        } else {
  65                /* doesn't handle cf=1 yet */
  66                tmp &= ~priv->cs_mask;
  67                tmp |= priv->cs_addr;
  68                snd_ice1712_gpio_write(ice, tmp);
  69                udelay(1);
  70        }
  71
  72        /* build I2C address + data byte */
  73        addrdata = (priv->caddr << 6) | 0x20 | (addr & 0x1f);
  74        addrdata = (addrdata << 8) | data;
  75        for (idx = 15; idx >= 0; idx--) {
  76                /* drop clock */
  77                tmp &= ~priv->clk_mask;
  78                snd_ice1712_gpio_write(ice, tmp);
  79                udelay(1);
  80                /* set data */
  81                if (addrdata & (1 << idx))
  82                        tmp |= priv->data_mask;
  83                else
  84                        tmp &= ~priv->data_mask;
  85                snd_ice1712_gpio_write(ice, tmp);
  86                udelay(1);
  87                /* raise clock */
  88                tmp |= priv->clk_mask;
  89                snd_ice1712_gpio_write(ice, tmp);
  90                udelay(1);
  91        }
  92
  93        if (priv->cs_mask == priv->cs_addr) {
  94                if (priv->cif) {
  95                        /* assert a cs pulse to trigger */
  96                        tmp &= ~priv->cs_mask;
  97                        snd_ice1712_gpio_write(ice, tmp);
  98                        udelay(1);
  99                }
 100                tmp |= priv->cs_mask; /* chip select high to trigger */
 101        } else {
 102                tmp &= ~priv->cs_mask;
 103                tmp |= priv->cs_none; /* deselect address */
 104        }
 105        snd_ice1712_gpio_write(ice, tmp);
 106        udelay(1);
 107}
 108
 109/*
 110 * initialize the struct snd_akm4xxx record with the template
 111 */
 112int snd_ice1712_akm4xxx_init(struct snd_akm4xxx *ak, const struct snd_akm4xxx *temp,
 113                             const struct snd_ak4xxx_private *_priv, struct snd_ice1712 *ice)
 114{
 115        struct snd_ak4xxx_private *priv;
 116
 117        if (_priv != NULL) {
 118                priv = kmalloc(sizeof(*priv), GFP_KERNEL);
 119                if (priv == NULL)
 120                        return -ENOMEM;
 121                *priv = *_priv;
 122        } else {
 123                priv = NULL;
 124        }
 125        *ak = *temp;
 126        ak->card = ice->card;
 127        ak->private_value[0] = (unsigned long)priv;
 128        ak->private_data[0] = ice;
 129        if (ak->ops.lock == NULL)
 130                ak->ops.lock = snd_ice1712_akm4xxx_lock;
 131        if (ak->ops.unlock == NULL)
 132                ak->ops.unlock = snd_ice1712_akm4xxx_unlock;
 133        if (ak->ops.write == NULL)
 134                ak->ops.write = snd_ice1712_akm4xxx_write;
 135        snd_akm4xxx_init(ak);
 136        return 0;
 137}
 138
 139void snd_ice1712_akm4xxx_free(struct snd_ice1712 *ice)
 140{
 141        unsigned int akidx;
 142        if (ice->akm == NULL)
 143                return;
 144        for (akidx = 0; akidx < ice->akm_codecs; akidx++) {
 145                struct snd_akm4xxx *ak = &ice->akm[akidx];
 146                kfree((void*)ak->private_value[0]);
 147        }
 148        kfree(ice->akm);
 149}
 150
 151/*
 152 * build AK4xxx controls
 153 */
 154int snd_ice1712_akm4xxx_build_controls(struct snd_ice1712 *ice)
 155{
 156        unsigned int akidx;
 157        int err;
 158
 159        for (akidx = 0; akidx < ice->akm_codecs; akidx++) {
 160                struct snd_akm4xxx *ak = &ice->akm[akidx];
 161                err = snd_akm4xxx_build_controls(ak);
 162                if (err < 0)
 163                        return err;
 164        }
 165        return 0;
 166}
 167
 168EXPORT_SYMBOL(snd_ice1712_akm4xxx_init);
 169EXPORT_SYMBOL(snd_ice1712_akm4xxx_free);
 170EXPORT_SYMBOL(snd_ice1712_akm4xxx_build_controls);
 171