linux/sound/pci/oxygen/xonar_lib.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * helper functions for Asus Xonar cards
   4 *
   5 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
   6 */
   7
   8#include <linux/delay.h>
   9#include <sound/core.h>
  10#include <sound/control.h>
  11#include <sound/pcm.h>
  12#include <sound/pcm_params.h>
  13#include "xonar.h"
  14
  15
  16#define GPIO_CS53x1_M_MASK      0x000c
  17#define GPIO_CS53x1_M_SINGLE    0x0000
  18#define GPIO_CS53x1_M_DOUBLE    0x0004
  19#define GPIO_CS53x1_M_QUAD      0x0008
  20
  21
  22void xonar_enable_output(struct oxygen *chip)
  23{
  24        struct xonar_generic *data = chip->model_data;
  25
  26        oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, data->output_enable_bit);
  27        msleep(data->anti_pop_delay);
  28        oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit);
  29}
  30
  31void xonar_disable_output(struct oxygen *chip)
  32{
  33        struct xonar_generic *data = chip->model_data;
  34
  35        oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit);
  36}
  37
  38static void xonar_ext_power_gpio_changed(struct oxygen *chip)
  39{
  40        struct xonar_generic *data = chip->model_data;
  41        u8 has_power;
  42
  43        has_power = !!(oxygen_read8(chip, data->ext_power_reg)
  44                       & data->ext_power_bit);
  45        if (has_power != data->has_power) {
  46                data->has_power = has_power;
  47                if (has_power) {
  48                        dev_notice(chip->card->dev, "power restored\n");
  49                } else {
  50                        dev_crit(chip->card->dev,
  51                                   "Hey! Don't unplug the power cable!\n");
  52                        /* TODO: stop PCMs */
  53                }
  54        }
  55}
  56
  57void xonar_init_ext_power(struct oxygen *chip)
  58{
  59        struct xonar_generic *data = chip->model_data;
  60
  61        oxygen_set_bits8(chip, data->ext_power_int_reg,
  62                         data->ext_power_bit);
  63        chip->interrupt_mask |= OXYGEN_INT_GPIO;
  64        chip->model.gpio_changed = xonar_ext_power_gpio_changed;
  65        data->has_power = !!(oxygen_read8(chip, data->ext_power_reg)
  66                             & data->ext_power_bit);
  67}
  68
  69void xonar_init_cs53x1(struct oxygen *chip)
  70{
  71        oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CS53x1_M_MASK);
  72        oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
  73                              GPIO_CS53x1_M_SINGLE, GPIO_CS53x1_M_MASK);
  74}
  75
  76void xonar_set_cs53x1_params(struct oxygen *chip,
  77                             struct snd_pcm_hw_params *params)
  78{
  79        unsigned int value;
  80
  81        if (params_rate(params) <= 54000)
  82                value = GPIO_CS53x1_M_SINGLE;
  83        else if (params_rate(params) <= 108000)
  84                value = GPIO_CS53x1_M_DOUBLE;
  85        else
  86                value = GPIO_CS53x1_M_QUAD;
  87        oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
  88                              value, GPIO_CS53x1_M_MASK);
  89}
  90
  91int xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl,
  92                              struct snd_ctl_elem_value *value)
  93{
  94        struct oxygen *chip = ctl->private_data;
  95        u16 bit = ctl->private_value;
  96        bool invert = ctl->private_value & XONAR_GPIO_BIT_INVERT;
  97
  98        value->value.integer.value[0] =
  99                !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit) ^ invert;
 100        return 0;
 101}
 102
 103int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl,
 104                              struct snd_ctl_elem_value *value)
 105{
 106        struct oxygen *chip = ctl->private_data;
 107        u16 bit = ctl->private_value;
 108        bool invert = ctl->private_value & XONAR_GPIO_BIT_INVERT;
 109        u16 old_bits, new_bits;
 110        int changed;
 111
 112        spin_lock_irq(&chip->reg_lock);
 113        old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA);
 114        if (!!value->value.integer.value[0] ^ invert)
 115                new_bits = old_bits | bit;
 116        else
 117                new_bits = old_bits & ~bit;
 118        changed = new_bits != old_bits;
 119        if (changed)
 120                oxygen_write16(chip, OXYGEN_GPIO_DATA, new_bits);
 121        spin_unlock_irq(&chip->reg_lock);
 122        return changed;
 123}
 124