linux/sound/ppc/daca.c
<<
>>
Prefs
   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        if (! (mix = chip->mixer_data))
  88                return -ENODEV;
  89        ucontrol->value.integer.value[0] = mix->deemphasis ? 1 : 0;
  90        return 0;
  91}
  92
  93static int daca_put_deemphasis(struct snd_kcontrol *kcontrol,
  94                               struct snd_ctl_elem_value *ucontrol)
  95{
  96        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
  97        struct pmac_daca *mix;
  98        int change;
  99
 100        if (! (mix = chip->mixer_data))
 101                return -ENODEV;
 102        change = mix->deemphasis != ucontrol->value.integer.value[0];
 103        if (change) {
 104                mix->deemphasis = !!ucontrol->value.integer.value[0];
 105                daca_set_volume(mix);
 106        }
 107        return change;
 108}
 109
 110/* output volume */
 111static int daca_info_volume(struct snd_kcontrol *kcontrol,
 112                            struct snd_ctl_elem_info *uinfo)
 113{
 114        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 115        uinfo->count = 2;
 116        uinfo->value.integer.min = 0;
 117        uinfo->value.integer.max = DACA_VOL_MAX;
 118        return 0;
 119}
 120
 121static int daca_get_volume(struct snd_kcontrol *kcontrol,
 122                           struct snd_ctl_elem_value *ucontrol)
 123{
 124        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 125        struct pmac_daca *mix;
 126        if (! (mix = chip->mixer_data))
 127                return -ENODEV;
 128        ucontrol->value.integer.value[0] = mix->left_vol;
 129        ucontrol->value.integer.value[1] = mix->right_vol;
 130        return 0;
 131}
 132
 133static int daca_put_volume(struct snd_kcontrol *kcontrol,
 134                           struct snd_ctl_elem_value *ucontrol)
 135{
 136        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 137        struct pmac_daca *mix;
 138        unsigned int vol[2];
 139        int change;
 140
 141        if (! (mix = chip->mixer_data))
 142                return -ENODEV;
 143        vol[0] = ucontrol->value.integer.value[0];
 144        vol[1] = ucontrol->value.integer.value[1];
 145        if (vol[0] > DACA_VOL_MAX || vol[1] > DACA_VOL_MAX)
 146                return -EINVAL;
 147        change = mix->left_vol != vol[0] ||
 148                mix->right_vol != vol[1];
 149        if (change) {
 150                mix->left_vol = vol[0];
 151                mix->right_vol = vol[1];
 152                daca_set_volume(mix);
 153        }
 154        return change;
 155}
 156
 157/* amplifier switch */
 158#define daca_info_amp   daca_info_deemphasis
 159
 160static int daca_get_amp(struct snd_kcontrol *kcontrol,
 161                        struct snd_ctl_elem_value *ucontrol)
 162{
 163        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 164        struct pmac_daca *mix;
 165        if (! (mix = chip->mixer_data))
 166                return -ENODEV;
 167        ucontrol->value.integer.value[0] = mix->amp_on ? 1 : 0;
 168        return 0;
 169}
 170
 171static int daca_put_amp(struct snd_kcontrol *kcontrol,
 172                        struct snd_ctl_elem_value *ucontrol)
 173{
 174        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 175        struct pmac_daca *mix;
 176        int change;
 177
 178        if (! (mix = chip->mixer_data))
 179                return -ENODEV;
 180        change = mix->amp_on != ucontrol->value.integer.value[0];
 181        if (change) {
 182                mix->amp_on = !!ucontrol->value.integer.value[0];
 183                i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_GCFG,
 184                                          mix->amp_on ? 0x05 : 0x04);
 185        }
 186        return change;
 187}
 188
 189static const struct snd_kcontrol_new daca_mixers[] = {
 190        { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 191          .name = "Deemphasis Switch",
 192          .info = daca_info_deemphasis,
 193          .get = daca_get_deemphasis,
 194          .put = daca_put_deemphasis
 195        },
 196        { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 197          .name = "Master Playback Volume",
 198          .info = daca_info_volume,
 199          .get = daca_get_volume,
 200          .put = daca_put_volume
 201        },
 202        { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 203          .name = "Power Amplifier Switch",
 204          .info = daca_info_amp,
 205          .get = daca_get_amp,
 206          .put = daca_put_amp
 207        },
 208};
 209
 210
 211#ifdef CONFIG_PM
 212static void daca_resume(struct snd_pmac *chip)
 213{
 214        struct pmac_daca *mix = chip->mixer_data;
 215        i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_SR, 0x08);
 216        i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_GCFG,
 217                                  mix->amp_on ? 0x05 : 0x04);
 218        daca_set_volume(mix);
 219}
 220#endif /* CONFIG_PM */
 221
 222
 223static void daca_cleanup(struct snd_pmac *chip)
 224{
 225        struct pmac_daca *mix = chip->mixer_data;
 226        if (! mix)
 227                return;
 228        snd_pmac_keywest_cleanup(&mix->i2c);
 229        kfree(mix);
 230        chip->mixer_data = NULL;
 231}
 232
 233/* exported */
 234int snd_pmac_daca_init(struct snd_pmac *chip)
 235{
 236        int i, err;
 237        struct pmac_daca *mix;
 238
 239        request_module("i2c-powermac");
 240
 241        mix = kzalloc(sizeof(*mix), GFP_KERNEL);
 242        if (! mix)
 243                return -ENOMEM;
 244        chip->mixer_data = mix;
 245        chip->mixer_free = daca_cleanup;
 246        mix->amp_on = 1; /* default on */
 247
 248        mix->i2c.addr = DACA_I2C_ADDR;
 249        mix->i2c.init_client = daca_init_client;
 250        mix->i2c.name = "DACA";
 251        if ((err = snd_pmac_keywest_init(&mix->i2c)) < 0)
 252                return err;
 253
 254        /*
 255         * build mixers
 256         */
 257        strcpy(chip->card->mixername, "PowerMac DACA");
 258
 259        for (i = 0; i < ARRAY_SIZE(daca_mixers); i++) {
 260                if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&daca_mixers[i], chip))) < 0)
 261                        return err;
 262        }
 263
 264#ifdef CONFIG_PM
 265        chip->resume = daca_resume;
 266#endif
 267
 268        return 0;
 269}
 270