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