Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/pci/ice1712/ak4xxx.c
29266 views
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 <[email protected]>
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 <[email protected]>");
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
172