1 /* 2 * PMac DACA lowlevel functions 3 * 4 * Copyright (c) by Takashi Iwai <tiwai@suse.de> 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 <sound/driver.h> 23 #include <linux/init.h> 24 #include <linux/i2c.h> 25 #include <linux/i2c-dev.h> 26 #include <linux/kmod.h> 27 #include <linux/slab.h> 28 #include <sound/core.h> 29 #include "pmac.h" 30 31 /* i2c address */ 32 #define DACA_I2C_ADDR 0x4d 33 34 /* registers */ 35 #define DACA_REG_SR 0x01 36 #define DACA_REG_AVOL 0x02 37 #define DACA_REG_GCFG 0x03 38 39 /* maximum volume value */ 40 #define DACA_VOL_MAX 0x38 41 42 43 typedef struct pmac_daca_t { 44 pmac_keywest_t i2c; 45 int left_vol, right_vol; 46 unsigned int deemphasis : 1; 47 unsigned int amp_on : 1; 48 } pmac_daca_t; 49 50 51 /* 52 * initialize / detect DACA 53 */ 54 static int daca_init_client(pmac_keywest_t *i2c) 55 { 56 unsigned short wdata = 0x00; 57 /* SR: no swap, 1bit delay, 32-48kHz */ 58 /* GCFG: power amp inverted, DAC on */ 59 if (i2c_smbus_write_byte_data(i2c->client, DACA_REG_SR, 0x08) < 0 || 60 i2c_smbus_write_byte_data(i2c->client, DACA_REG_GCFG, 0x05) < 0) 61 return -EINVAL; 62 return i2c_smbus_write_block_data(i2c->client, DACA_REG_AVOL, 63 2, (unsigned char*)&wdata); 64 } 65 66 /* 67 * update volume 68 */ 69 static int daca_set_volume(pmac_daca_t *mix) 70 { 71 unsigned char data[2]; 72 73 if (! mix->i2c.client) 74 return -ENODEV; 75 76 if (mix->left_vol > DACA_VOL_MAX) 77 data[0] = DACA_VOL_MAX; 78 else 79 data[0] = mix->left_vol; 80 if (mix->right_vol > DACA_VOL_MAX) 81 data[1] = DACA_VOL_MAX; 82 else 83 data[1] = mix->right_vol; 84 data[1] |= mix->deemphasis ? 0x40 : 0; 85 if (i2c_smbus_write_block_data(mix->i2c.client, DACA_REG_AVOL, 86 2, data) < 0) { 87 snd_printk("failed to set volume \n"); 88 return -EINVAL; 89 } 90 return 0; 91 } 92 93 94 /* deemphasis switch */ 95 static int daca_info_deemphasis(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 96 { 97 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 98 uinfo->count = 1; 99 uinfo->value.integer.min = 0; 100 uinfo->value.integer.max = 1; 101 return 0; 102 } 103 104 static int daca_get_deemphasis(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 105 { 106 pmac_t *chip = snd_kcontrol_chip(kcontrol); 107 pmac_daca_t *mix; 108 if (! (mix = chip->mixer_data)) 109 return -ENODEV; 110 ucontrol->value.integer.value[0] = mix->deemphasis ? 1 : 0; 111 return 0; 112 } 113 114 static int daca_put_deemphasis(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 115 { 116 pmac_t *chip = snd_kcontrol_chip(kcontrol); 117 pmac_daca_t *mix; 118 int change; 119 120 if (! (mix = chip->mixer_data)) 121 return -ENODEV; 122 change = mix->deemphasis != ucontrol->value.integer.value[0]; 123 if (change) { 124 mix->deemphasis = ucontrol->value.integer.value[0]; 125 daca_set_volume(mix); 126 } 127 return change; 128 } 129 130 /* output volume */ 131 static int daca_info_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 132 { 133 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 134 uinfo->count = 2; 135 uinfo->value.integer.min = 0; 136 uinfo->value.integer.max = DACA_VOL_MAX; 137 return 0; 138 } 139 140 static int daca_get_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 141 { 142 pmac_t *chip = snd_kcontrol_chip(kcontrol); 143 pmac_daca_t *mix; 144 if (! (mix = chip->mixer_data)) 145 return -ENODEV; 146 ucontrol->value.integer.value[0] = mix->left_vol; 147 ucontrol->value.integer.value[1] = mix->right_vol; 148 return 0; 149 } 150 151 static int daca_put_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 152 { 153 pmac_t *chip = snd_kcontrol_chip(kcontrol); 154 pmac_daca_t *mix; 155 int change; 156 157 if (! (mix = chip->mixer_data)) 158 return -ENODEV; 159 change = mix->left_vol != ucontrol->value.integer.value[0] || 160 mix->right_vol != ucontrol->value.integer.value[1]; 161 if (change) { 162 mix->left_vol = ucontrol->value.integer.value[0]; 163 mix->right_vol = ucontrol->value.integer.value[1]; 164 daca_set_volume(mix); 165 } 166 return change; 167 } 168 169 /* amplifier switch */ 170 #define daca_info_amp daca_info_deemphasis 171 172 static int daca_get_amp(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 173 { 174 pmac_t *chip = snd_kcontrol_chip(kcontrol); 175 pmac_daca_t *mix; 176 if (! (mix = chip->mixer_data)) 177 return -ENODEV; 178 ucontrol->value.integer.value[0] = mix->amp_on ? 1 : 0; 179 return 0; 180 } 181 182 static int daca_put_amp(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 183 { 184 pmac_t *chip = snd_kcontrol_chip(kcontrol); 185 pmac_daca_t *mix; 186 int change; 187 188 if (! (mix = chip->mixer_data)) 189 return -ENODEV; 190 change = mix->amp_on != ucontrol->value.integer.value[0]; 191 if (change) { 192 mix->amp_on = ucontrol->value.integer.value[0]; 193 i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_GCFG, 194 mix->amp_on ? 0x05 : 0x04); 195 } 196 return change; 197 } 198 199 static snd_kcontrol_new_t daca_mixers[] = { 200 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 201 .name = "Deemphasis Switch", 202 .info = daca_info_deemphasis, 203 .get = daca_get_deemphasis, 204 .put = daca_put_deemphasis 205 }, 206 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 207 .name = "Master Playback Volume", 208 .info = daca_info_volume, 209 .get = daca_get_volume, 210 .put = daca_put_volume 211 }, 212 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 213 .name = "Power Amplifier Switch", 214 .info = daca_info_amp, 215 .get = daca_get_amp, 216 .put = daca_put_amp 217 }, 218 }; 219 220 221 #ifdef CONFIG_PM 222 static void daca_resume(pmac_t *chip) 223 { 224 pmac_daca_t *mix = chip->mixer_data; 225 i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_SR, 0x08); 226 i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_GCFG, 227 mix->amp_on ? 0x05 : 0x04); 228 daca_set_volume(mix); 229 } 230 #endif /* CONFIG_PM */ 231 232 233 static void daca_cleanup(pmac_t *chip) 234 { 235 pmac_daca_t *mix = chip->mixer_data; 236 if (! mix) 237 return; 238 snd_pmac_keywest_cleanup(&mix->i2c); 239 kfree(mix); 240 chip->mixer_data = NULL; 241 } 242 243 /* exported */ 244 int __init snd_pmac_daca_init(pmac_t *chip) 245 { 246 int i, err; 247 pmac_daca_t *mix; 248 249 #ifdef CONFIG_KMOD 250 if (current->fs->root) 251 request_module("i2c-keywest"); 252 #endif /* CONFIG_KMOD */ 253 254 mix = kmalloc(sizeof(*mix), GFP_KERNEL); 255 if (! mix) 256 return -ENOMEM; 257 memset(mix, 0, sizeof(*mix)); 258 chip->mixer_data = mix; 259 chip->mixer_free = daca_cleanup; 260 mix->amp_on = 1; /* default on */ 261 262 mix->i2c.addr = DACA_I2C_ADDR; 263 mix->i2c.init_client = daca_init_client; 264 mix->i2c.name = "DACA"; 265 if ((err = snd_pmac_keywest_init(&mix->i2c)) < 0) 266 return err; 267 268 /* 269 * build mixers 270 */ 271 strcpy(chip->card->mixername, "PowerMac DACA"); 272 273 for (i = 0; i < ARRAY_SIZE(daca_mixers); i++) { 274 if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&daca_mixers[i], chip))) < 0) 275 return err; 276 } 277 278 #ifdef CONFIG_PM 279 chip->resume = daca_resume; 280 #endif 281 282 return 0; 283 } 284