File Index
Files and directories
Sign in
FILE

ak4xxx.c

File preview with syntax highlighting.

linux-6.19.14/sound/pci/ice1712/ak4xxx.c C
  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);
~/ Read-only file preview.