1218822Sdim// SPDX-License-Identifier: GPL-2.0-only 238889Sjdp/* 3218822Sdim * helper functions for Asus Xonar cards 4218822Sdim * 538889Sjdp * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 6218822Sdim */ 7218822Sdim 860484Sobrien#include <linux/delay.h> 9218822Sdim#include <sound/core.h> 10218822Sdim#include <sound/control.h> 11218822Sdim#include <sound/pcm.h> 1238889Sjdp#include <sound/pcm_params.h> 1338889Sjdp#include "xonar.h" 14218822Sdim 15218822Sdim 1638889Sjdp#define GPIO_CS53x1_M_MASK 0x000c 17218822Sdim#define GPIO_CS53x1_M_SINGLE 0x0000 18218822Sdim#define GPIO_CS53x1_M_DOUBLE 0x0004 1938889Sjdp#define GPIO_CS53x1_M_QUAD 0x0008 20218822Sdim 21218822Sdim 2260484Sobrienvoid xonar_enable_output(struct oxygen *chip) 23218822Sdim{ 24218822Sdim struct xonar_generic *data = chip->model_data; 2538889Sjdp 26218822Sdim oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, data->output_enable_bit); 27218822Sdim msleep(data->anti_pop_delay); 2860484Sobrien oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit); 29218822Sdim} 30218822Sdim 3160484Sobrienvoid xonar_disable_output(struct oxygen *chip) 32218822Sdim{ 33218822Sdim struct xonar_generic *data = chip->model_data; 3438889Sjdp 35218822Sdim oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit); 36218822Sdim} 37218822Sdim 3860484Sobrienstatic void xonar_ext_power_gpio_changed(struct oxygen *chip) 39218822Sdim{ 40218822Sdim struct xonar_generic *data = chip->model_data; 4138889Sjdp u8 has_power; 42218822Sdim 43218822Sdim has_power = !!(oxygen_read8(chip, data->ext_power_reg) 44218822Sdim & data->ext_power_bit); 4538889Sjdp if (has_power != data->has_power) { 46218822Sdim data->has_power = has_power; 47218822Sdim if (has_power) { 4838889Sjdp dev_notice(chip->card->dev, "power restored\n"); 49218822Sdim } else { 50218822Sdim dev_crit(chip->card->dev, 51218822Sdim "Hey! Don't unplug the power cable!\n"); 5238889Sjdp /* TODO: stop PCMs */ 53218822Sdim } 54218822Sdim } 5538889Sjdp} 56218822Sdim 57218822Sdimvoid xonar_init_ext_power(struct oxygen *chip) 5838889Sjdp{ 59218822Sdim struct xonar_generic *data = chip->model_data; 60218822Sdim 6138889Sjdp oxygen_set_bits8(chip, data->ext_power_int_reg, 62218822Sdim data->ext_power_bit); 63218822Sdim chip->interrupt_mask |= OXYGEN_INT_GPIO; 6438889Sjdp chip->model.gpio_changed = xonar_ext_power_gpio_changed; 65218822Sdim data->has_power = !!(oxygen_read8(chip, data->ext_power_reg) 6660484Sobrien & data->ext_power_bit); 6738889Sjdp} 68218822Sdim 6960484Sobrienvoid xonar_init_cs53x1(struct oxygen *chip) 7038889Sjdp{ 71218822Sdim oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CS53x1_M_MASK); 72218822Sdim oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, 7338889Sjdp GPIO_CS53x1_M_SINGLE, GPIO_CS53x1_M_MASK); 74218822Sdim} 75218822Sdim 7638889Sjdpvoid xonar_set_cs53x1_params(struct oxygen *chip, 77218822Sdim struct snd_pcm_hw_params *params) 78218822Sdim{ 7938889Sjdp unsigned int value; 80218822Sdim 81218822Sdim if (params_rate(params) <= 54000) 8238889Sjdp value = GPIO_CS53x1_M_SINGLE; 83218822Sdim else if (params_rate(params) <= 108000) 8438889Sjdp value = GPIO_CS53x1_M_DOUBLE; 8538889Sjdp else 86218822Sdim value = GPIO_CS53x1_M_QUAD; 87218822Sdim oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, 8838889Sjdp value, GPIO_CS53x1_M_MASK); 89218822Sdim} 9038889Sjdp 9138889Sjdpint xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl, 92218822Sdim struct snd_ctl_elem_value *value) 9338889Sjdp{ 9438889Sjdp struct oxygen *chip = ctl->private_data; 95218822Sdim u16 bit = ctl->private_value; 96218822Sdim bool invert = ctl->private_value & XONAR_GPIO_BIT_INVERT; 9760484Sobrien 98218822Sdim value->value.integer.value[0] = 9938889Sjdp !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit) ^ invert; 10060484Sobrien return 0; 101218822Sdim} 102218822Sdim 10360484Sobrienint xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl, 104218822Sdim struct snd_ctl_elem_value *value) 105218822Sdim{ 106218822Sdim struct oxygen *chip = ctl->private_data; 10760484Sobrien u16 bit = ctl->private_value; 108218822Sdim bool invert = ctl->private_value & XONAR_GPIO_BIT_INVERT; 109218822Sdim u16 old_bits, new_bits; 11060484Sobrien int changed; 111218822Sdim 112218822Sdim spin_lock_irq(&chip->reg_lock); 11377298Sobrien old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); 114218822Sdim if (!!value->value.integer.value[0] ^ invert) 115130561Sobrien new_bits = old_bits | bit; 116130561Sobrien else 117218822Sdim new_bits = old_bits & ~bit; 118130561Sobrien changed = new_bits != old_bits; 119130561Sobrien if (changed) 120218822Sdim oxygen_write16(chip, OXYGEN_GPIO_DATA, new_bits); 121130561Sobrien spin_unlock_irq(&chip->reg_lock); 122130561Sobrien return changed; 123218822Sdim} 124218822Sdim