1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * ALSA driver for ICEnsemble ICE1712 (Envy24)
5 * AK4524 / AK4528 / AK4529 / AK4355 / AK4381 interface
7 * Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz>
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>
20 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
21 MODULE_DESCRIPTION("ICEnsemble ICE17xx <-> AK4xxx AD/DA chip interface");
22 MODULE_LICENSE("GPL");
24 static void snd_ice1712_akm4xxx_lock(struct snd_akm4xxx
*ak
, int chip
)
26 struct snd_ice1712
*ice
= ak
->private_data
[0];
28 snd_ice1712_save_gpio_status(ice
);
31 static void snd_ice1712_akm4xxx_unlock(struct snd_akm4xxx
*ak
, int chip
)
33 struct snd_ice1712
*ice
= ak
->private_data
[0];
35 snd_ice1712_restore_gpio_status(ice
);
39 * write AK4xxx register
41 static void snd_ice1712_akm4xxx_write(struct snd_akm4xxx
*ak
, int chip
,
42 unsigned char addr
, unsigned char data
)
46 unsigned int addrdata
;
47 struct snd_ak4xxx_private
*priv
= (void *)ak
->private_value
[0];
48 struct snd_ice1712
*ice
= ak
->private_data
[0];
50 if (snd_BUG_ON(chip
< 0 || chip
>= 4))
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
) {
58 tmp
|= priv
->cs_mask
; /* start without chip select */
60 tmp
&= ~priv
->cs_mask
; /* chip select low */
61 snd_ice1712_gpio_write(ice
, tmp
);
65 /* doesn't handle cf=1 yet */
66 tmp
&= ~priv
->cs_mask
;
68 snd_ice1712_gpio_write(ice
, tmp
);
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
--) {
77 tmp
&= ~priv
->clk_mask
;
78 snd_ice1712_gpio_write(ice
, tmp
);
81 if (addrdata
& (1 << idx
))
82 tmp
|= priv
->data_mask
;
84 tmp
&= ~priv
->data_mask
;
85 snd_ice1712_gpio_write(ice
, tmp
);
88 tmp
|= priv
->clk_mask
;
89 snd_ice1712_gpio_write(ice
, tmp
);
93 if (priv
->cs_mask
== priv
->cs_addr
) {
95 /* assert a cs pulse to trigger */
96 tmp
&= ~priv
->cs_mask
;
97 snd_ice1712_gpio_write(ice
, tmp
);
100 tmp
|= priv
->cs_mask
; /* chip select high to trigger */
102 tmp
&= ~priv
->cs_mask
;
103 tmp
|= priv
->cs_none
; /* deselect address */
105 snd_ice1712_gpio_write(ice
, tmp
);
110 * initialize the struct snd_akm4xxx record with the template
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
)
115 struct snd_ak4xxx_private
*priv
;
118 priv
= kmalloc(sizeof(*priv
), GFP_KERNEL
);
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
);
139 void snd_ice1712_akm4xxx_free(struct snd_ice1712
*ice
)
142 if (ice
->akm
== NULL
)
144 for (akidx
= 0; akidx
< ice
->akm_codecs
; akidx
++) {
145 struct snd_akm4xxx
*ak
= &ice
->akm
[akidx
];
146 kfree((void*)ak
->private_value
[0]);
152 * build AK4xxx controls
154 int snd_ice1712_akm4xxx_build_controls(struct snd_ice1712
*ice
)
159 for (akidx
= 0; akidx
< ice
->akm_codecs
; akidx
++) {
160 struct snd_akm4xxx
*ak
= &ice
->akm
[akidx
];
161 err
= snd_akm4xxx_build_controls(ak
);
168 EXPORT_SYMBOL(snd_ice1712_akm4xxx_init
);
169 EXPORT_SYMBOL(snd_ice1712_akm4xxx_free
);
170 EXPORT_SYMBOL(snd_ice1712_akm4xxx_build_controls
);