Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | /* * helper functions for Asus Xonar cards * * Copyright (c) Clemens Ladisch <clemens@ladisch.de> * * * This driver is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2. * * This driver is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this driver; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/delay.h> #include <sound/core.h> #include <sound/control.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include "xonar.h" #define GPIO_CS53x1_M_MASK 0x000c #define GPIO_CS53x1_M_SINGLE 0x0000 #define GPIO_CS53x1_M_DOUBLE 0x0004 #define GPIO_CS53x1_M_QUAD 0x0008 void xonar_enable_output(struct oxygen *chip) { struct xonar_generic *data = chip->model_data; oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, data->output_enable_bit); msleep(data->anti_pop_delay); oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit); } void xonar_disable_output(struct oxygen *chip) { struct xonar_generic *data = chip->model_data; oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit); } static void xonar_ext_power_gpio_changed(struct oxygen *chip) { struct xonar_generic *data = chip->model_data; u8 has_power; has_power = !!(oxygen_read8(chip, data->ext_power_reg) & data->ext_power_bit); if (has_power != data->has_power) { data->has_power = has_power; if (has_power) { dev_notice(chip->card->dev, "power restored\n"); } else { dev_crit(chip->card->dev, "Hey! Don't unplug the power cable!\n"); /* TODO: stop PCMs */ } } } void xonar_init_ext_power(struct oxygen *chip) { struct xonar_generic *data = chip->model_data; oxygen_set_bits8(chip, data->ext_power_int_reg, data->ext_power_bit); chip->interrupt_mask |= OXYGEN_INT_GPIO; chip->model.gpio_changed = xonar_ext_power_gpio_changed; data->has_power = !!(oxygen_read8(chip, data->ext_power_reg) & data->ext_power_bit); } void xonar_init_cs53x1(struct oxygen *chip) { oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CS53x1_M_MASK); oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, GPIO_CS53x1_M_SINGLE, GPIO_CS53x1_M_MASK); } void xonar_set_cs53x1_params(struct oxygen *chip, struct snd_pcm_hw_params *params) { unsigned int value; if (params_rate(params) <= 54000) value = GPIO_CS53x1_M_SINGLE; else if (params_rate(params) <= 108000) value = GPIO_CS53x1_M_DOUBLE; else value = GPIO_CS53x1_M_QUAD; oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, value, GPIO_CS53x1_M_MASK); } int xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) { struct oxygen *chip = ctl->private_data; u16 bit = ctl->private_value; bool invert = ctl->private_value & XONAR_GPIO_BIT_INVERT; value->value.integer.value[0] = !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit) ^ invert; return 0; } int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) { struct oxygen *chip = ctl->private_data; u16 bit = ctl->private_value; bool invert = ctl->private_value & XONAR_GPIO_BIT_INVERT; u16 old_bits, new_bits; int changed; spin_lock_irq(&chip->reg_lock); old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); if (!!value->value.integer.value[0] ^ invert) new_bits = old_bits | bit; else new_bits = old_bits & ~bit; changed = new_bits != old_bits; if (changed) oxygen_write16(chip, OXYGEN_GPIO_DATA, new_bits); spin_unlock_irq(&chip->reg_lock); return changed; } |