daca.c (6367B)
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 28struct 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 */ 39static 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 */ 54static 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 82static 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 94static 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 */ 113static 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 123static 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 136static 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 164static 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 176static 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 195static 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 218static 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 229static 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 */ 240int 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}