162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * helper functions for Asus Xonar cards 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/delay.h> 962306a36Sopenharmony_ci#include <sound/core.h> 1062306a36Sopenharmony_ci#include <sound/control.h> 1162306a36Sopenharmony_ci#include <sound/pcm.h> 1262306a36Sopenharmony_ci#include <sound/pcm_params.h> 1362306a36Sopenharmony_ci#include "xonar.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define GPIO_CS53x1_M_MASK 0x000c 1762306a36Sopenharmony_ci#define GPIO_CS53x1_M_SINGLE 0x0000 1862306a36Sopenharmony_ci#define GPIO_CS53x1_M_DOUBLE 0x0004 1962306a36Sopenharmony_ci#define GPIO_CS53x1_M_QUAD 0x0008 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_civoid xonar_enable_output(struct oxygen *chip) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci struct xonar_generic *data = chip->model_data; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, data->output_enable_bit); 2762306a36Sopenharmony_ci msleep(data->anti_pop_delay); 2862306a36Sopenharmony_ci oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit); 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_civoid xonar_disable_output(struct oxygen *chip) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci struct xonar_generic *data = chip->model_data; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit); 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic void xonar_ext_power_gpio_changed(struct oxygen *chip) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci struct xonar_generic *data = chip->model_data; 4162306a36Sopenharmony_ci u8 has_power; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci has_power = !!(oxygen_read8(chip, data->ext_power_reg) 4462306a36Sopenharmony_ci & data->ext_power_bit); 4562306a36Sopenharmony_ci if (has_power != data->has_power) { 4662306a36Sopenharmony_ci data->has_power = has_power; 4762306a36Sopenharmony_ci if (has_power) { 4862306a36Sopenharmony_ci dev_notice(chip->card->dev, "power restored\n"); 4962306a36Sopenharmony_ci } else { 5062306a36Sopenharmony_ci dev_crit(chip->card->dev, 5162306a36Sopenharmony_ci "Hey! Don't unplug the power cable!\n"); 5262306a36Sopenharmony_ci /* TODO: stop PCMs */ 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_civoid xonar_init_ext_power(struct oxygen *chip) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci struct xonar_generic *data = chip->model_data; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci oxygen_set_bits8(chip, data->ext_power_int_reg, 6262306a36Sopenharmony_ci data->ext_power_bit); 6362306a36Sopenharmony_ci chip->interrupt_mask |= OXYGEN_INT_GPIO; 6462306a36Sopenharmony_ci chip->model.gpio_changed = xonar_ext_power_gpio_changed; 6562306a36Sopenharmony_ci data->has_power = !!(oxygen_read8(chip, data->ext_power_reg) 6662306a36Sopenharmony_ci & data->ext_power_bit); 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_civoid xonar_init_cs53x1(struct oxygen *chip) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CS53x1_M_MASK); 7262306a36Sopenharmony_ci oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, 7362306a36Sopenharmony_ci GPIO_CS53x1_M_SINGLE, GPIO_CS53x1_M_MASK); 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_civoid xonar_set_cs53x1_params(struct oxygen *chip, 7762306a36Sopenharmony_ci struct snd_pcm_hw_params *params) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci unsigned int value; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (params_rate(params) <= 54000) 8262306a36Sopenharmony_ci value = GPIO_CS53x1_M_SINGLE; 8362306a36Sopenharmony_ci else if (params_rate(params) <= 108000) 8462306a36Sopenharmony_ci value = GPIO_CS53x1_M_DOUBLE; 8562306a36Sopenharmony_ci else 8662306a36Sopenharmony_ci value = GPIO_CS53x1_M_QUAD; 8762306a36Sopenharmony_ci oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, 8862306a36Sopenharmony_ci value, GPIO_CS53x1_M_MASK); 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ciint xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl, 9262306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 9562306a36Sopenharmony_ci u16 bit = ctl->private_value; 9662306a36Sopenharmony_ci bool invert = ctl->private_value & XONAR_GPIO_BIT_INVERT; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci value->value.integer.value[0] = 9962306a36Sopenharmony_ci !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit) ^ invert; 10062306a36Sopenharmony_ci return 0; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ciint xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl, 10462306a36Sopenharmony_ci struct snd_ctl_elem_value *value) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci struct oxygen *chip = ctl->private_data; 10762306a36Sopenharmony_ci u16 bit = ctl->private_value; 10862306a36Sopenharmony_ci bool invert = ctl->private_value & XONAR_GPIO_BIT_INVERT; 10962306a36Sopenharmony_ci u16 old_bits, new_bits; 11062306a36Sopenharmony_ci int changed; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 11362306a36Sopenharmony_ci old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); 11462306a36Sopenharmony_ci if (!!value->value.integer.value[0] ^ invert) 11562306a36Sopenharmony_ci new_bits = old_bits | bit; 11662306a36Sopenharmony_ci else 11762306a36Sopenharmony_ci new_bits = old_bits & ~bit; 11862306a36Sopenharmony_ci changed = new_bits != old_bits; 11962306a36Sopenharmony_ci if (changed) 12062306a36Sopenharmony_ci oxygen_write16(chip, OXYGEN_GPIO_DATA, new_bits); 12162306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 12262306a36Sopenharmony_ci return changed; 12362306a36Sopenharmony_ci} 124