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        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}
 278