Blame view

sound/ppc/daca.c 6.87 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  /*
   * PMac DACA lowlevel functions
   *
   * Copyright (c) by Takashi Iwai <tiwai@suse.de>
   *
   *   This program is free software; you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
   *   the Free Software Foundation; either version 2 of the License, or
   *   (at your option) any later version.
   *
   *   This program is distributed in the hope that it will be useful,
   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *   GNU General Public License for more details.
   *
   *   You should have received a copy of the GNU General Public License
   *   along with this program; if not, write to the Free Software
   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
  #include <linux/init.h>
  #include <linux/i2c.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
  #include <linux/kmod.h>
  #include <linux/slab.h>
  #include <sound/core.h>
  #include "pmac.h"
  
  /* i2c address */
  #define DACA_I2C_ADDR	0x4d
  
  /* registers */
  #define DACA_REG_SR	0x01
  #define DACA_REG_AVOL	0x02
  #define DACA_REG_GCFG	0x03
  
  /* maximum volume value */
  #define DACA_VOL_MAX	0x38
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
37
38
  struct pmac_daca {
  	struct pmac_keywest i2c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
  	int left_vol, right_vol;
  	unsigned int deemphasis : 1;
  	unsigned int amp_on : 1;
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
42
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
46
47
  
  
  /*
   * initialize / detect DACA
   */
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
48
  static int daca_init_client(struct pmac_keywest *i2c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
51
52
53
54
55
56
57
58
59
60
61
62
  {
  	unsigned short wdata = 0x00;
  	/* SR: no swap, 1bit delay, 32-48kHz */
  	/* GCFG: power amp inverted, DAC on */
  	if (i2c_smbus_write_byte_data(i2c->client, DACA_REG_SR, 0x08) < 0 ||
  	    i2c_smbus_write_byte_data(i2c->client, DACA_REG_GCFG, 0x05) < 0)
  		return -EINVAL;
  	return i2c_smbus_write_block_data(i2c->client, DACA_REG_AVOL,
  					  2, (unsigned char*)&wdata);
  }
  
  /*
   * update volume
   */
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
63
  static int daca_set_volume(struct pmac_daca *mix)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
  {
  	unsigned char data[2];
    
  	if (! mix->i2c.client)
  		return -ENODEV;
    
  	if (mix->left_vol > DACA_VOL_MAX)
  		data[0] = DACA_VOL_MAX;
  	else
  		data[0] = mix->left_vol;
  	if (mix->right_vol > DACA_VOL_MAX)
  		data[1] = DACA_VOL_MAX;
  	else
  		data[1] = mix->right_vol;
  	data[1] |= mix->deemphasis ? 0x40 : 0;
  	if (i2c_smbus_write_block_data(mix->i2c.client, DACA_REG_AVOL,
  				       2, data) < 0) {
6da671138   Takashi Iwai   ALSA: powermac - ...
81
82
  		snd_printk(KERN_ERR "failed to set volume 
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
85
86
87
88
89
  		return -EINVAL;
  	}
  	return 0;
  }
  
  
  /* deemphasis switch */
a5ce88909   Takashi Iwai   [ALSA] Clean up w...
90
  #define daca_info_deemphasis		snd_ctl_boolean_mono_info
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91

65b29f503   Takashi Iwai   [ALSA] Remove xxx...
92
93
  static int daca_get_deemphasis(struct snd_kcontrol *kcontrol,
  			       struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
95
96
  	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
  	struct pmac_daca *mix;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
98
99
100
101
  	if (! (mix = chip->mixer_data))
  		return -ENODEV;
  	ucontrol->value.integer.value[0] = mix->deemphasis ? 1 : 0;
  	return 0;
  }
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
102
103
  static int daca_put_deemphasis(struct snd_kcontrol *kcontrol,
  			       struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
105
106
  	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
  	struct pmac_daca *mix;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
109
110
111
112
  	int change;
  
  	if (! (mix = chip->mixer_data))
  		return -ENODEV;
  	change = mix->deemphasis != ucontrol->value.integer.value[0];
  	if (change) {
d4079ac49   Takashi Iwai   [ALSA] powermac -...
113
  		mix->deemphasis = !!ucontrol->value.integer.value[0];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
116
117
118
119
  		daca_set_volume(mix);
  	}
  	return change;
  }
  
  /* output volume */
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
120
121
  static int daca_info_volume(struct snd_kcontrol *kcontrol,
  			    struct snd_ctl_elem_info *uinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
124
125
126
127
128
  {
  	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  	uinfo->count = 2;
  	uinfo->value.integer.min = 0;
  	uinfo->value.integer.max = DACA_VOL_MAX;
  	return 0;
  }
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
129
130
  static int daca_get_volume(struct snd_kcontrol *kcontrol,
  			   struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
132
133
  	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
  	struct pmac_daca *mix;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
136
137
138
139
  	if (! (mix = chip->mixer_data))
  		return -ENODEV;
  	ucontrol->value.integer.value[0] = mix->left_vol;
  	ucontrol->value.integer.value[1] = mix->right_vol;
  	return 0;
  }
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
140
141
  static int daca_put_volume(struct snd_kcontrol *kcontrol,
  			   struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
143
144
  	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
  	struct pmac_daca *mix;
d4079ac49   Takashi Iwai   [ALSA] powermac -...
145
  	unsigned int vol[2];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
148
149
  	int change;
  
  	if (! (mix = chip->mixer_data))
  		return -ENODEV;
d4079ac49   Takashi Iwai   [ALSA] powermac -...
150
151
152
153
154
155
  	vol[0] = ucontrol->value.integer.value[0];
  	vol[1] = ucontrol->value.integer.value[1];
  	if (vol[0] > DACA_VOL_MAX || vol[1] > DACA_VOL_MAX)
  		return -EINVAL;
  	change = mix->left_vol != vol[0] ||
  		mix->right_vol != vol[1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
  	if (change) {
d4079ac49   Takashi Iwai   [ALSA] powermac -...
157
158
  		mix->left_vol = vol[0];
  		mix->right_vol = vol[1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
160
161
162
163
164
165
  		daca_set_volume(mix);
  	}
  	return change;
  }
  
  /* amplifier switch */
  #define daca_info_amp	daca_info_deemphasis
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
166
167
  static int daca_get_amp(struct snd_kcontrol *kcontrol,
  			struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
169
170
  	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
  	struct pmac_daca *mix;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
172
173
174
175
  	if (! (mix = chip->mixer_data))
  		return -ENODEV;
  	ucontrol->value.integer.value[0] = mix->amp_on ? 1 : 0;
  	return 0;
  }
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
176
177
  static int daca_put_amp(struct snd_kcontrol *kcontrol,
  			struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
179
180
  	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
  	struct pmac_daca *mix;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
184
185
186
  	int change;
  
  	if (! (mix = chip->mixer_data))
  		return -ENODEV;
  	change = mix->amp_on != ucontrol->value.integer.value[0];
  	if (change) {
d4079ac49   Takashi Iwai   [ALSA] powermac -...
187
  		mix->amp_on = !!ucontrol->value.integer.value[0];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
190
191
192
  		i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_GCFG,
  					  mix->amp_on ? 0x05 : 0x04);
  	}
  	return change;
  }
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
193
  static struct snd_kcontrol_new daca_mixers[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
  	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  	  .name = "Deemphasis Switch",
  	  .info = daca_info_deemphasis,
  	  .get = daca_get_deemphasis,
  	  .put = daca_put_deemphasis
  	},
  	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  	  .name = "Master Playback Volume",
  	  .info = daca_info_volume,
  	  .get = daca_get_volume,
  	  .put = daca_put_volume
  	},
  	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  	  .name = "Power Amplifier Switch",
  	  .info = daca_info_amp,
  	  .get = daca_get_amp,
  	  .put = daca_put_amp
  	},
  };
8c8709334   Benjamin Herrenschmidt   [PATCH] ppc32: Re...
213
  #ifdef CONFIG_PM
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
214
  static void daca_resume(struct snd_pmac *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
216
  	struct pmac_daca *mix = chip->mixer_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
218
219
220
221
  	i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_SR, 0x08);
  	i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_GCFG,
  				  mix->amp_on ? 0x05 : 0x04);
  	daca_set_volume(mix);
  }
8c8709334   Benjamin Herrenschmidt   [PATCH] ppc32: Re...
222
  #endif /* CONFIG_PM */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223

65b29f503   Takashi Iwai   [ALSA] Remove xxx...
224
  static void daca_cleanup(struct snd_pmac *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
226
  	struct pmac_daca *mix = chip->mixer_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
228
229
230
231
232
233
234
  	if (! mix)
  		return;
  	snd_pmac_keywest_cleanup(&mix->i2c);
  	kfree(mix);
  	chip->mixer_data = NULL;
  }
  
  /* exported */
5c9b6e9e6   Stephen Rothwell   ALSA: sound/ppc: ...
235
  int __devinit snd_pmac_daca_init(struct snd_pmac *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
237
  {
  	int i, err;
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
238
  	struct pmac_daca *mix;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239

0d63e4f9e   Jan Blunck   Dont touch fs_str...
240
  	request_module("i2c-powermac");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241

59feddb25   Panagiotis Issaris   [ALSA] Conversion...
242
  	mix = kzalloc(sizeof(*mix), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
244
  	if (! mix)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
  	chip->mixer_data = mix;
  	chip->mixer_free = daca_cleanup;
  	mix->amp_on = 1; /* default on */
  
  	mix->i2c.addr = DACA_I2C_ADDR;
  	mix->i2c.init_client = daca_init_client;
  	mix->i2c.name = "DACA";
  	if ((err = snd_pmac_keywest_init(&mix->i2c)) < 0)
  		return err;
  
  	/*
  	 * build mixers
  	 */
  	strcpy(chip->card->mixername, "PowerMac DACA");
  
  	for (i = 0; i < ARRAY_SIZE(daca_mixers); i++) {
  		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&daca_mixers[i], chip))) < 0)
  			return err;
  	}
8c8709334   Benjamin Herrenschmidt   [PATCH] ppc32: Re...
264
  #ifdef CONFIG_PM
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
266
267
268
269
  	chip->resume = daca_resume;
  #endif
  
  	return 0;
  }