[ALSA] virtuoso: monitor external power on D2X
On the Xonar D2X, monitor the GPIO pin that indicates whether external power is present. Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
committed by
Jaroslav Kysela
parent
5f7b9b4577
commit
7c0141591f
@@ -66,6 +66,7 @@ struct oxygen {
|
|||||||
struct snd_pcm_substream *streams[PCM_COUNT];
|
struct snd_pcm_substream *streams[PCM_COUNT];
|
||||||
struct snd_kcontrol *controls[CONTROL_COUNT];
|
struct snd_kcontrol *controls[CONTROL_COUNT];
|
||||||
struct work_struct spdif_input_bits_work;
|
struct work_struct spdif_input_bits_work;
|
||||||
|
struct work_struct gpio_work;
|
||||||
wait_queue_head_t ac97_waitqueue;
|
wait_queue_head_t ac97_waitqueue;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -88,6 +89,7 @@ struct oxygen_model {
|
|||||||
void (*update_dac_mute)(struct oxygen *chip);
|
void (*update_dac_mute)(struct oxygen *chip);
|
||||||
void (*ac97_switch_hook)(struct oxygen *chip, unsigned int codec,
|
void (*ac97_switch_hook)(struct oxygen *chip, unsigned int codec,
|
||||||
unsigned int reg, int mute);
|
unsigned int reg, int mute);
|
||||||
|
void (*gpio_changed)(struct oxygen *chip);
|
||||||
size_t model_data_size;
|
size_t model_data_size;
|
||||||
u8 dac_channels;
|
u8 dac_channels;
|
||||||
u8 used_channels;
|
u8 used_channels;
|
||||||
|
@@ -85,7 +85,7 @@ static irqreturn_t oxygen_interrupt(int dummy, void *dev_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (status & OXYGEN_INT_GPIO)
|
if (status & OXYGEN_INT_GPIO)
|
||||||
;
|
schedule_work(&chip->gpio_work);
|
||||||
|
|
||||||
if ((status & OXYGEN_INT_MIDI) && chip->midi)
|
if ((status & OXYGEN_INT_MIDI) && chip->midi)
|
||||||
snd_mpu401_uart_interrupt(0, chip->midi->private_data);
|
snd_mpu401_uart_interrupt(0, chip->midi->private_data);
|
||||||
@@ -157,6 +157,14 @@ static void oxygen_spdif_input_bits_changed(struct work_struct *work)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void oxygen_gpio_changed(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct oxygen *chip = container_of(work, struct oxygen, gpio_work);
|
||||||
|
|
||||||
|
if (chip->model->gpio_changed)
|
||||||
|
chip->model->gpio_changed(chip);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PROC_FS
|
#ifdef CONFIG_PROC_FS
|
||||||
static void oxygen_proc_read(struct snd_info_entry *entry,
|
static void oxygen_proc_read(struct snd_info_entry *entry,
|
||||||
struct snd_info_buffer *buffer)
|
struct snd_info_buffer *buffer)
|
||||||
@@ -413,6 +421,7 @@ int __devinit oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
|
|||||||
mutex_init(&chip->mutex);
|
mutex_init(&chip->mutex);
|
||||||
INIT_WORK(&chip->spdif_input_bits_work,
|
INIT_WORK(&chip->spdif_input_bits_work,
|
||||||
oxygen_spdif_input_bits_changed);
|
oxygen_spdif_input_bits_changed);
|
||||||
|
INIT_WORK(&chip->gpio_work, oxygen_gpio_changed);
|
||||||
init_waitqueue_head(&chip->ac97_waitqueue);
|
init_waitqueue_head(&chip->ac97_waitqueue);
|
||||||
|
|
||||||
err = pci_enable_device(pci);
|
err = pci_enable_device(pci);
|
||||||
|
@@ -136,6 +136,11 @@ MODULE_DEVICE_TABLE(pci, xonar_ids);
|
|||||||
/* register 23 */
|
/* register 23 */
|
||||||
#define PCM1796_ID_MASK 0x1f
|
#define PCM1796_ID_MASK 0x1f
|
||||||
|
|
||||||
|
struct xonar_data {
|
||||||
|
u8 is_d2x;
|
||||||
|
u8 has_power;
|
||||||
|
};
|
||||||
|
|
||||||
static void pcm1796_write(struct oxygen *chip, unsigned int codec,
|
static void pcm1796_write(struct oxygen *chip, unsigned int codec,
|
||||||
u8 reg, u8 value)
|
u8 reg, u8 value)
|
||||||
{
|
{
|
||||||
@@ -153,8 +158,11 @@ static void pcm1796_write(struct oxygen *chip, unsigned int codec,
|
|||||||
|
|
||||||
static void xonar_init(struct oxygen *chip)
|
static void xonar_init(struct oxygen *chip)
|
||||||
{
|
{
|
||||||
|
struct xonar_data *data = chip->model_data;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
|
data->is_d2x = chip->pci->subsystem_device == 0x82b7;
|
||||||
|
|
||||||
for (i = 0; i < 4; ++i) {
|
for (i = 0; i < 4; ++i) {
|
||||||
pcm1796_write(chip, i, 18, PCM1796_FMT_24_LJUST | PCM1796_ATLD);
|
pcm1796_write(chip, i, 18, PCM1796_FMT_24_LJUST | PCM1796_ATLD);
|
||||||
pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1);
|
pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1);
|
||||||
@@ -169,6 +177,15 @@ static void xonar_init(struct oxygen *chip)
|
|||||||
oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
|
oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
|
||||||
GPIO_CS5381_M_SINGLE,
|
GPIO_CS5381_M_SINGLE,
|
||||||
GPIO_CS5381_M_MASK | GPIO_ALT);
|
GPIO_CS5381_M_MASK | GPIO_ALT);
|
||||||
|
if (data->is_d2x) {
|
||||||
|
oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
|
||||||
|
GPIO_EXT_POWER);
|
||||||
|
oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK,
|
||||||
|
GPIO_EXT_POWER);
|
||||||
|
chip->interrupt_mask |= OXYGEN_INT_GPIO;
|
||||||
|
data->has_power = !!(oxygen_read16(chip, OXYGEN_GPIO_DATA)
|
||||||
|
& GPIO_EXT_POWER);
|
||||||
|
}
|
||||||
oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC);
|
oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC);
|
||||||
oxygen_ac97_clear_bits(chip, 0, CM9780_GPIO_STATUS, GPIO_LINE_MUTE);
|
oxygen_ac97_clear_bits(chip, 0, CM9780_GPIO_STATUS, GPIO_LINE_MUTE);
|
||||||
msleep(300);
|
msleep(300);
|
||||||
@@ -234,6 +251,27 @@ static void set_cs5381_params(struct oxygen *chip,
|
|||||||
value, GPIO_CS5381_M_MASK);
|
value, GPIO_CS5381_M_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void xonar_gpio_changed(struct oxygen *chip)
|
||||||
|
{
|
||||||
|
struct xonar_data *data = chip->model_data;
|
||||||
|
u8 has_power;
|
||||||
|
|
||||||
|
if (!data->is_d2x)
|
||||||
|
return;
|
||||||
|
has_power = !!(oxygen_read16(chip, OXYGEN_GPIO_DATA)
|
||||||
|
& GPIO_EXT_POWER);
|
||||||
|
if (has_power != data->has_power) {
|
||||||
|
data->has_power = has_power;
|
||||||
|
if (has_power) {
|
||||||
|
snd_printk(KERN_NOTICE "power restored\n");
|
||||||
|
} else {
|
||||||
|
snd_printk(KERN_CRIT
|
||||||
|
"Hey! Don't unplug the power cable!\n");
|
||||||
|
/* TODO: stop PCMs */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void mute_ac97_ctl(struct oxygen *chip, unsigned int control)
|
static void mute_ac97_ctl(struct oxygen *chip, unsigned int control)
|
||||||
{
|
{
|
||||||
unsigned int index = chip->controls[control]->private_value & 0xff;
|
unsigned int index = chip->controls[control]->private_value & 0xff;
|
||||||
@@ -360,6 +398,8 @@ static const struct oxygen_model model_xonar = {
|
|||||||
.update_dac_volume = update_pcm1796_volume,
|
.update_dac_volume = update_pcm1796_volume,
|
||||||
.update_dac_mute = update_pcm1796_mute,
|
.update_dac_mute = update_pcm1796_mute,
|
||||||
.ac97_switch_hook = xonar_ac97_switch_hook,
|
.ac97_switch_hook = xonar_ac97_switch_hook,
|
||||||
|
.gpio_changed = xonar_gpio_changed,
|
||||||
|
.model_data_size = sizeof(struct xonar_data),
|
||||||
.dac_channels = 8,
|
.dac_channels = 8,
|
||||||
.used_channels = OXYGEN_CHANNEL_B |
|
.used_channels = OXYGEN_CHANNEL_B |
|
||||||
OXYGEN_CHANNEL_C |
|
OXYGEN_CHANNEL_C |
|
||||||
|
Reference in New Issue
Block a user