Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * PMac DACA lowlevel functions
0004  *
0005  * Copyright (c) by Takashi Iwai <tiwai@suse.de>
0006  */
0007 
0008 
0009 #include <linux/init.h>
0010 #include <linux/i2c.h>
0011 #include <linux/kmod.h>
0012 #include <linux/slab.h>
0013 #include <sound/core.h>
0014 #include "pmac.h"
0015 
0016 /* i2c address */
0017 #define DACA_I2C_ADDR   0x4d
0018 
0019 /* registers */
0020 #define DACA_REG_SR 0x01
0021 #define DACA_REG_AVOL   0x02
0022 #define DACA_REG_GCFG   0x03
0023 
0024 /* maximum volume value */
0025 #define DACA_VOL_MAX    0x38
0026 
0027 
0028 struct pmac_daca {
0029     struct pmac_keywest i2c;
0030     int left_vol, right_vol;
0031     unsigned int deemphasis : 1;
0032     unsigned int amp_on : 1;
0033 };
0034 
0035 
0036 /*
0037  * initialize / detect DACA
0038  */
0039 static int daca_init_client(struct pmac_keywest *i2c)
0040 {
0041     unsigned short wdata = 0x00;
0042     /* SR: no swap, 1bit delay, 32-48kHz */
0043     /* GCFG: power amp inverted, DAC on */
0044     if (i2c_smbus_write_byte_data(i2c->client, DACA_REG_SR, 0x08) < 0 ||
0045         i2c_smbus_write_byte_data(i2c->client, DACA_REG_GCFG, 0x05) < 0)
0046         return -EINVAL;
0047     return i2c_smbus_write_block_data(i2c->client, DACA_REG_AVOL,
0048                       2, (unsigned char*)&wdata);
0049 }
0050 
0051 /*
0052  * update volume
0053  */
0054 static int daca_set_volume(struct pmac_daca *mix)
0055 {
0056     unsigned char data[2];
0057   
0058     if (! mix->i2c.client)
0059         return -ENODEV;
0060   
0061     if (mix->left_vol > DACA_VOL_MAX)
0062         data[0] = DACA_VOL_MAX;
0063     else
0064         data[0] = mix->left_vol;
0065     if (mix->right_vol > DACA_VOL_MAX)
0066         data[1] = DACA_VOL_MAX;
0067     else
0068         data[1] = mix->right_vol;
0069     data[1] |= mix->deemphasis ? 0x40 : 0;
0070     if (i2c_smbus_write_block_data(mix->i2c.client, DACA_REG_AVOL,
0071                        2, data) < 0) {
0072         snd_printk(KERN_ERR "failed to set volume \n");
0073         return -EINVAL;
0074     }
0075     return 0;
0076 }
0077 
0078 
0079 /* deemphasis switch */
0080 #define daca_info_deemphasis        snd_ctl_boolean_mono_info
0081 
0082 static int daca_get_deemphasis(struct snd_kcontrol *kcontrol,
0083                    struct snd_ctl_elem_value *ucontrol)
0084 {
0085     struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
0086     struct pmac_daca *mix;
0087     mix = chip->mixer_data;
0088     if (!mix)
0089         return -ENODEV;
0090     ucontrol->value.integer.value[0] = mix->deemphasis ? 1 : 0;
0091     return 0;
0092 }
0093 
0094 static int daca_put_deemphasis(struct snd_kcontrol *kcontrol,
0095                    struct snd_ctl_elem_value *ucontrol)
0096 {
0097     struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
0098     struct pmac_daca *mix;
0099     int change;
0100 
0101     mix = chip->mixer_data;
0102     if (!mix)
0103         return -ENODEV;
0104     change = mix->deemphasis != ucontrol->value.integer.value[0];
0105     if (change) {
0106         mix->deemphasis = !!ucontrol->value.integer.value[0];
0107         daca_set_volume(mix);
0108     }
0109     return change;
0110 }
0111 
0112 /* output volume */
0113 static int daca_info_volume(struct snd_kcontrol *kcontrol,
0114                 struct snd_ctl_elem_info *uinfo)
0115 {
0116     uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
0117     uinfo->count = 2;
0118     uinfo->value.integer.min = 0;
0119     uinfo->value.integer.max = DACA_VOL_MAX;
0120     return 0;
0121 }
0122 
0123 static int daca_get_volume(struct snd_kcontrol *kcontrol,
0124                struct snd_ctl_elem_value *ucontrol)
0125 {
0126     struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
0127     struct pmac_daca *mix;
0128     mix = chip->mixer_data;
0129     if (!mix)
0130         return -ENODEV;
0131     ucontrol->value.integer.value[0] = mix->left_vol;
0132     ucontrol->value.integer.value[1] = mix->right_vol;
0133     return 0;
0134 }
0135 
0136 static int daca_put_volume(struct snd_kcontrol *kcontrol,
0137                struct snd_ctl_elem_value *ucontrol)
0138 {
0139     struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
0140     struct pmac_daca *mix;
0141     unsigned int vol[2];
0142     int change;
0143 
0144     mix = chip->mixer_data;
0145     if (!mix)
0146         return -ENODEV;
0147     vol[0] = ucontrol->value.integer.value[0];
0148     vol[1] = ucontrol->value.integer.value[1];
0149     if (vol[0] > DACA_VOL_MAX || vol[1] > DACA_VOL_MAX)
0150         return -EINVAL;
0151     change = mix->left_vol != vol[0] ||
0152         mix->right_vol != vol[1];
0153     if (change) {
0154         mix->left_vol = vol[0];
0155         mix->right_vol = vol[1];
0156         daca_set_volume(mix);
0157     }
0158     return change;
0159 }
0160 
0161 /* amplifier switch */
0162 #define daca_info_amp   daca_info_deemphasis
0163 
0164 static int daca_get_amp(struct snd_kcontrol *kcontrol,
0165             struct snd_ctl_elem_value *ucontrol)
0166 {
0167     struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
0168     struct pmac_daca *mix;
0169     mix = chip->mixer_data;
0170     if (!mix)
0171         return -ENODEV;
0172     ucontrol->value.integer.value[0] = mix->amp_on ? 1 : 0;
0173     return 0;
0174 }
0175 
0176 static int daca_put_amp(struct snd_kcontrol *kcontrol,
0177             struct snd_ctl_elem_value *ucontrol)
0178 {
0179     struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
0180     struct pmac_daca *mix;
0181     int change;
0182 
0183     mix = chip->mixer_data;
0184     if (!mix)
0185         return -ENODEV;
0186     change = mix->amp_on != ucontrol->value.integer.value[0];
0187     if (change) {
0188         mix->amp_on = !!ucontrol->value.integer.value[0];
0189         i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_GCFG,
0190                       mix->amp_on ? 0x05 : 0x04);
0191     }
0192     return change;
0193 }
0194 
0195 static const struct snd_kcontrol_new daca_mixers[] = {
0196     { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0197       .name = "Deemphasis Switch",
0198       .info = daca_info_deemphasis,
0199       .get = daca_get_deemphasis,
0200       .put = daca_put_deemphasis
0201     },
0202     { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0203       .name = "Master Playback Volume",
0204       .info = daca_info_volume,
0205       .get = daca_get_volume,
0206       .put = daca_put_volume
0207     },
0208     { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0209       .name = "Power Amplifier Switch",
0210       .info = daca_info_amp,
0211       .get = daca_get_amp,
0212       .put = daca_put_amp
0213     },
0214 };
0215 
0216 
0217 #ifdef CONFIG_PM
0218 static void daca_resume(struct snd_pmac *chip)
0219 {
0220     struct pmac_daca *mix = chip->mixer_data;
0221     i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_SR, 0x08);
0222     i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_GCFG,
0223                   mix->amp_on ? 0x05 : 0x04);
0224     daca_set_volume(mix);
0225 }
0226 #endif /* CONFIG_PM */
0227 
0228 
0229 static void daca_cleanup(struct snd_pmac *chip)
0230 {
0231     struct pmac_daca *mix = chip->mixer_data;
0232     if (! mix)
0233         return;
0234     snd_pmac_keywest_cleanup(&mix->i2c);
0235     kfree(mix);
0236     chip->mixer_data = NULL;
0237 }
0238 
0239 /* exported */
0240 int snd_pmac_daca_init(struct snd_pmac *chip)
0241 {
0242     int i, err;
0243     struct pmac_daca *mix;
0244 
0245     request_module("i2c-powermac");
0246 
0247     mix = kzalloc(sizeof(*mix), GFP_KERNEL);
0248     if (! mix)
0249         return -ENOMEM;
0250     chip->mixer_data = mix;
0251     chip->mixer_free = daca_cleanup;
0252     mix->amp_on = 1; /* default on */
0253 
0254     mix->i2c.addr = DACA_I2C_ADDR;
0255     mix->i2c.init_client = daca_init_client;
0256     mix->i2c.name = "DACA";
0257     err = snd_pmac_keywest_init(&mix->i2c);
0258     if (err < 0)
0259         return err;
0260 
0261     /*
0262      * build mixers
0263      */
0264     strcpy(chip->card->mixername, "PowerMac DACA");
0265 
0266     for (i = 0; i < ARRAY_SIZE(daca_mixers); i++) {
0267         err = snd_ctl_add(chip->card, snd_ctl_new1(&daca_mixers[i], chip));
0268         if (err < 0)
0269             return err;
0270     }
0271 
0272 #ifdef CONFIG_PM
0273     chip->resume = daca_resume;
0274 #endif
0275 
0276     return 0;
0277 }