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 20 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); 21 MODULE_DESCRIPTION("ICEnsemble ICE17xx <-> AK4xxx AD/DA chip interface"); 22 MODULE_LICENSE("GPL"); 23 24 static 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 31 static 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 */ 41 static 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 */ 112 int 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 139 void 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 */ 154 int 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 168 EXPORT_SYMBOL(snd_ice1712_akm4xxx_init); 169 EXPORT_SYMBOL(snd_ice1712_akm4xxx_free); 170 EXPORT_SYMBOL(snd_ice1712_akm4xxx_build_controls); 171
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.