Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/ppc/daca.c
10814 views
1
/*
2
* PMac DACA lowlevel functions
3
*
4
* Copyright (c) by Takashi Iwai <[email protected]>
5
*
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
10
*
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
15
*
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
*/
20
21
22
#include <linux/init.h>
23
#include <linux/i2c.h>
24
#include <linux/kmod.h>
25
#include <linux/slab.h>
26
#include <sound/core.h>
27
#include "pmac.h"
28
29
/* i2c address */
30
#define DACA_I2C_ADDR 0x4d
31
32
/* registers */
33
#define DACA_REG_SR 0x01
34
#define DACA_REG_AVOL 0x02
35
#define DACA_REG_GCFG 0x03
36
37
/* maximum volume value */
38
#define DACA_VOL_MAX 0x38
39
40
41
struct pmac_daca {
42
struct pmac_keywest i2c;
43
int left_vol, right_vol;
44
unsigned int deemphasis : 1;
45
unsigned int amp_on : 1;
46
};
47
48
49
/*
50
* initialize / detect DACA
51
*/
52
static int daca_init_client(struct pmac_keywest *i2c)
53
{
54
unsigned short wdata = 0x00;
55
/* SR: no swap, 1bit delay, 32-48kHz */
56
/* GCFG: power amp inverted, DAC on */
57
if (i2c_smbus_write_byte_data(i2c->client, DACA_REG_SR, 0x08) < 0 ||
58
i2c_smbus_write_byte_data(i2c->client, DACA_REG_GCFG, 0x05) < 0)
59
return -EINVAL;
60
return i2c_smbus_write_block_data(i2c->client, DACA_REG_AVOL,
61
2, (unsigned char*)&wdata);
62
}
63
64
/*
65
* update volume
66
*/
67
static int daca_set_volume(struct pmac_daca *mix)
68
{
69
unsigned char data[2];
70
71
if (! mix->i2c.client)
72
return -ENODEV;
73
74
if (mix->left_vol > DACA_VOL_MAX)
75
data[0] = DACA_VOL_MAX;
76
else
77
data[0] = mix->left_vol;
78
if (mix->right_vol > DACA_VOL_MAX)
79
data[1] = DACA_VOL_MAX;
80
else
81
data[1] = mix->right_vol;
82
data[1] |= mix->deemphasis ? 0x40 : 0;
83
if (i2c_smbus_write_block_data(mix->i2c.client, DACA_REG_AVOL,
84
2, data) < 0) {
85
snd_printk(KERN_ERR "failed to set volume \n");
86
return -EINVAL;
87
}
88
return 0;
89
}
90
91
92
/* deemphasis switch */
93
#define daca_info_deemphasis snd_ctl_boolean_mono_info
94
95
static int daca_get_deemphasis(struct snd_kcontrol *kcontrol,
96
struct snd_ctl_elem_value *ucontrol)
97
{
98
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
99
struct pmac_daca *mix;
100
if (! (mix = chip->mixer_data))
101
return -ENODEV;
102
ucontrol->value.integer.value[0] = mix->deemphasis ? 1 : 0;
103
return 0;
104
}
105
106
static int daca_put_deemphasis(struct snd_kcontrol *kcontrol,
107
struct snd_ctl_elem_value *ucontrol)
108
{
109
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
110
struct pmac_daca *mix;
111
int change;
112
113
if (! (mix = chip->mixer_data))
114
return -ENODEV;
115
change = mix->deemphasis != ucontrol->value.integer.value[0];
116
if (change) {
117
mix->deemphasis = !!ucontrol->value.integer.value[0];
118
daca_set_volume(mix);
119
}
120
return change;
121
}
122
123
/* output volume */
124
static int daca_info_volume(struct snd_kcontrol *kcontrol,
125
struct snd_ctl_elem_info *uinfo)
126
{
127
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
128
uinfo->count = 2;
129
uinfo->value.integer.min = 0;
130
uinfo->value.integer.max = DACA_VOL_MAX;
131
return 0;
132
}
133
134
static int daca_get_volume(struct snd_kcontrol *kcontrol,
135
struct snd_ctl_elem_value *ucontrol)
136
{
137
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
138
struct pmac_daca *mix;
139
if (! (mix = chip->mixer_data))
140
return -ENODEV;
141
ucontrol->value.integer.value[0] = mix->left_vol;
142
ucontrol->value.integer.value[1] = mix->right_vol;
143
return 0;
144
}
145
146
static int daca_put_volume(struct snd_kcontrol *kcontrol,
147
struct snd_ctl_elem_value *ucontrol)
148
{
149
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
150
struct pmac_daca *mix;
151
unsigned int vol[2];
152
int change;
153
154
if (! (mix = chip->mixer_data))
155
return -ENODEV;
156
vol[0] = ucontrol->value.integer.value[0];
157
vol[1] = ucontrol->value.integer.value[1];
158
if (vol[0] > DACA_VOL_MAX || vol[1] > DACA_VOL_MAX)
159
return -EINVAL;
160
change = mix->left_vol != vol[0] ||
161
mix->right_vol != vol[1];
162
if (change) {
163
mix->left_vol = vol[0];
164
mix->right_vol = vol[1];
165
daca_set_volume(mix);
166
}
167
return change;
168
}
169
170
/* amplifier switch */
171
#define daca_info_amp daca_info_deemphasis
172
173
static int daca_get_amp(struct snd_kcontrol *kcontrol,
174
struct snd_ctl_elem_value *ucontrol)
175
{
176
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
177
struct pmac_daca *mix;
178
if (! (mix = chip->mixer_data))
179
return -ENODEV;
180
ucontrol->value.integer.value[0] = mix->amp_on ? 1 : 0;
181
return 0;
182
}
183
184
static int daca_put_amp(struct snd_kcontrol *kcontrol,
185
struct snd_ctl_elem_value *ucontrol)
186
{
187
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
188
struct pmac_daca *mix;
189
int change;
190
191
if (! (mix = chip->mixer_data))
192
return -ENODEV;
193
change = mix->amp_on != ucontrol->value.integer.value[0];
194
if (change) {
195
mix->amp_on = !!ucontrol->value.integer.value[0];
196
i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_GCFG,
197
mix->amp_on ? 0x05 : 0x04);
198
}
199
return change;
200
}
201
202
static struct snd_kcontrol_new daca_mixers[] = {
203
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
204
.name = "Deemphasis Switch",
205
.info = daca_info_deemphasis,
206
.get = daca_get_deemphasis,
207
.put = daca_put_deemphasis
208
},
209
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
210
.name = "Master Playback Volume",
211
.info = daca_info_volume,
212
.get = daca_get_volume,
213
.put = daca_put_volume
214
},
215
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
216
.name = "Power Amplifier Switch",
217
.info = daca_info_amp,
218
.get = daca_get_amp,
219
.put = daca_put_amp
220
},
221
};
222
223
224
#ifdef CONFIG_PM
225
static void daca_resume(struct snd_pmac *chip)
226
{
227
struct pmac_daca *mix = chip->mixer_data;
228
i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_SR, 0x08);
229
i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_GCFG,
230
mix->amp_on ? 0x05 : 0x04);
231
daca_set_volume(mix);
232
}
233
#endif /* CONFIG_PM */
234
235
236
static void daca_cleanup(struct snd_pmac *chip)
237
{
238
struct pmac_daca *mix = chip->mixer_data;
239
if (! mix)
240
return;
241
snd_pmac_keywest_cleanup(&mix->i2c);
242
kfree(mix);
243
chip->mixer_data = NULL;
244
}
245
246
/* exported */
247
int __devinit snd_pmac_daca_init(struct snd_pmac *chip)
248
{
249
int i, err;
250
struct pmac_daca *mix;
251
252
request_module("i2c-powermac");
253
254
mix = kzalloc(sizeof(*mix), GFP_KERNEL);
255
if (! mix)
256
return -ENOMEM;
257
chip->mixer_data = mix;
258
chip->mixer_free = daca_cleanup;
259
mix->amp_on = 1; /* default on */
260
261
mix->i2c.addr = DACA_I2C_ADDR;
262
mix->i2c.init_client = daca_init_client;
263
mix->i2c.name = "DACA";
264
if ((err = snd_pmac_keywest_init(&mix->i2c)) < 0)
265
return err;
266
267
/*
268
* build mixers
269
*/
270
strcpy(chip->card->mixername, "PowerMac DACA");
271
272
for (i = 0; i < ARRAY_SIZE(daca_mixers); i++) {
273
if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&daca_mixers[i], chip))) < 0)
274
return err;
275
}
276
277
#ifdef CONFIG_PM
278
chip->resume = daca_resume;
279
#endif
280
281
return 0;
282
}
283
284