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