Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid
[linux-2.6-microblaze.git] / sound / pci / ice1712 / ak4xxx.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
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);