ALSA: hda - Move codec create to hda_controller
Codec creation and stream initialization can be shared between hda_intel and hda platform drivers. Move it and the static functions it depends on to hda_controller.c. Signed-off-by: Dylan Reid <dgreid@chromium.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
f0b1df8871
commit
154867cf4e
3 changed files with 235 additions and 248 deletions
|
@ -25,6 +25,7 @@
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/initval.h>
|
#include <sound/initval.h>
|
||||||
|
@ -1022,7 +1023,6 @@ int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
|
||||||
pcm->dev = &codec->dev;
|
pcm->dev = &codec->dev;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(azx_attach_pcm_stream);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CORB / RIRB interface
|
* CORB / RIRB interface
|
||||||
|
@ -1380,7 +1380,7 @@ static unsigned int azx_single_get_response(struct hda_bus *bus,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* send a command */
|
/* send a command */
|
||||||
int azx_send_cmd(struct hda_bus *bus, unsigned int val)
|
static int azx_send_cmd(struct hda_bus *bus, unsigned int val)
|
||||||
{
|
{
|
||||||
struct azx *chip = bus->private_data;
|
struct azx *chip = bus->private_data;
|
||||||
|
|
||||||
|
@ -1395,7 +1395,7 @@ int azx_send_cmd(struct hda_bus *bus, unsigned int val)
|
||||||
EXPORT_SYMBOL_GPL(azx_send_cmd);
|
EXPORT_SYMBOL_GPL(azx_send_cmd);
|
||||||
|
|
||||||
/* get a response */
|
/* get a response */
|
||||||
unsigned int azx_get_response(struct hda_bus *bus,
|
static unsigned int azx_get_response(struct hda_bus *bus,
|
||||||
unsigned int addr)
|
unsigned int addr)
|
||||||
{
|
{
|
||||||
struct azx *chip = bus->private_data;
|
struct azx *chip = bus->private_data;
|
||||||
|
@ -1420,9 +1420,9 @@ azx_get_dsp_loader_dev(struct azx *chip)
|
||||||
return &chip->azx_dev[chip->playback_index_offset];
|
return &chip->azx_dev[chip->playback_index_offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format,
|
static int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format,
|
||||||
unsigned int byte_size,
|
unsigned int byte_size,
|
||||||
struct snd_dma_buffer *bufp)
|
struct snd_dma_buffer *bufp)
|
||||||
{
|
{
|
||||||
u32 *bdl;
|
u32 *bdl;
|
||||||
struct azx *chip = bus->private_data;
|
struct azx *chip = bus->private_data;
|
||||||
|
@ -1480,9 +1480,8 @@ int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format,
|
||||||
dsp_unlock(azx_dev);
|
dsp_unlock(azx_dev);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(azx_load_dsp_prepare);
|
|
||||||
|
|
||||||
void azx_load_dsp_trigger(struct hda_bus *bus, bool start)
|
static void azx_load_dsp_trigger(struct hda_bus *bus, bool start)
|
||||||
{
|
{
|
||||||
struct azx *chip = bus->private_data;
|
struct azx *chip = bus->private_data;
|
||||||
struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip);
|
struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip);
|
||||||
|
@ -1493,10 +1492,9 @@ void azx_load_dsp_trigger(struct hda_bus *bus, bool start)
|
||||||
azx_stream_stop(chip, azx_dev);
|
azx_stream_stop(chip, azx_dev);
|
||||||
azx_dev->running = start;
|
azx_dev->running = start;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(azx_load_dsp_trigger);
|
|
||||||
|
|
||||||
void azx_load_dsp_cleanup(struct hda_bus *bus,
|
static void azx_load_dsp_cleanup(struct hda_bus *bus,
|
||||||
struct snd_dma_buffer *dmab)
|
struct snd_dma_buffer *dmab)
|
||||||
{
|
{
|
||||||
struct azx *chip = bus->private_data;
|
struct azx *chip = bus->private_data;
|
||||||
struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip);
|
struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip);
|
||||||
|
@ -1523,7 +1521,6 @@ void azx_load_dsp_cleanup(struct hda_bus *bus,
|
||||||
spin_unlock_irq(&chip->reg_lock);
|
spin_unlock_irq(&chip->reg_lock);
|
||||||
dsp_unlock(azx_dev);
|
dsp_unlock(azx_dev);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(azx_load_dsp_cleanup);
|
|
||||||
#endif /* CONFIG_SND_HDA_DSP_LOADER */
|
#endif /* CONFIG_SND_HDA_DSP_LOADER */
|
||||||
|
|
||||||
int azx_alloc_stream_pages(struct azx *chip)
|
int azx_alloc_stream_pages(struct azx *chip)
|
||||||
|
@ -1746,6 +1743,7 @@ void azx_stop_chip(struct azx *chip)
|
||||||
|
|
||||||
chip->initialized = 0;
|
chip->initialized = 0;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(azx_stop_chip);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* interrupt handler
|
* interrupt handler
|
||||||
|
@ -1812,5 +1810,222 @@ irqreturn_t azx_interrupt(int irq, void *dev_id)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(azx_interrupt);
|
EXPORT_SYMBOL_GPL(azx_interrupt);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Codec initerface
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Probe the given codec address
|
||||||
|
*/
|
||||||
|
static int probe_codec(struct azx *chip, int addr)
|
||||||
|
{
|
||||||
|
unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) |
|
||||||
|
(AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
|
||||||
|
unsigned int res;
|
||||||
|
|
||||||
|
mutex_lock(&chip->bus->cmd_mutex);
|
||||||
|
chip->probing = 1;
|
||||||
|
azx_send_cmd(chip->bus, cmd);
|
||||||
|
res = azx_get_response(chip->bus, addr);
|
||||||
|
chip->probing = 0;
|
||||||
|
mutex_unlock(&chip->bus->cmd_mutex);
|
||||||
|
if (res == -1)
|
||||||
|
return -EIO;
|
||||||
|
dev_dbg(chip->card->dev, "codec #%d probed OK\n", addr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void azx_bus_reset(struct hda_bus *bus)
|
||||||
|
{
|
||||||
|
struct azx *chip = bus->private_data;
|
||||||
|
|
||||||
|
bus->in_reset = 1;
|
||||||
|
azx_stop_chip(chip);
|
||||||
|
azx_init_chip(chip, 1);
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
if (chip->initialized) {
|
||||||
|
struct azx_pcm *p;
|
||||||
|
list_for_each_entry(p, &chip->pcm_list, list)
|
||||||
|
snd_pcm_suspend_all(p->pcm);
|
||||||
|
snd_hda_suspend(chip->bus);
|
||||||
|
snd_hda_resume(chip->bus);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
bus->in_reset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
/* power-up/down the controller */
|
||||||
|
static void azx_power_notify(struct hda_bus *bus, bool power_up)
|
||||||
|
{
|
||||||
|
struct azx *chip = bus->private_data;
|
||||||
|
|
||||||
|
if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (power_up)
|
||||||
|
pm_runtime_get_sync(chip->card->dev);
|
||||||
|
else
|
||||||
|
pm_runtime_put_sync(chip->card->dev);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int get_jackpoll_interval(struct azx *chip)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned int j;
|
||||||
|
|
||||||
|
if (!chip->jackpoll_ms)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
i = chip->jackpoll_ms[chip->dev_index];
|
||||||
|
if (i == 0)
|
||||||
|
return 0;
|
||||||
|
if (i < 50 || i > 60000)
|
||||||
|
j = 0;
|
||||||
|
else
|
||||||
|
j = msecs_to_jiffies(i);
|
||||||
|
if (j == 0)
|
||||||
|
dev_warn(chip->card->dev,
|
||||||
|
"jackpoll_ms value out of range: %d\n", i);
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Codec initialization */
|
||||||
|
int azx_codec_create(struct azx *chip, const char *model,
|
||||||
|
unsigned int max_slots,
|
||||||
|
int *power_save_to)
|
||||||
|
{
|
||||||
|
struct hda_bus_template bus_temp;
|
||||||
|
int c, codecs, err;
|
||||||
|
|
||||||
|
memset(&bus_temp, 0, sizeof(bus_temp));
|
||||||
|
bus_temp.private_data = chip;
|
||||||
|
bus_temp.modelname = model;
|
||||||
|
bus_temp.pci = chip->pci;
|
||||||
|
bus_temp.ops.command = azx_send_cmd;
|
||||||
|
bus_temp.ops.get_response = azx_get_response;
|
||||||
|
bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
|
||||||
|
bus_temp.ops.bus_reset = azx_bus_reset;
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
bus_temp.power_save = power_save_to;
|
||||||
|
bus_temp.ops.pm_notify = azx_power_notify;
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_SND_HDA_DSP_LOADER
|
||||||
|
bus_temp.ops.load_dsp_prepare = azx_load_dsp_prepare;
|
||||||
|
bus_temp.ops.load_dsp_trigger = azx_load_dsp_trigger;
|
||||||
|
bus_temp.ops.load_dsp_cleanup = azx_load_dsp_cleanup;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) {
|
||||||
|
dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n");
|
||||||
|
chip->bus->needs_damn_long_delay = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
codecs = 0;
|
||||||
|
if (!max_slots)
|
||||||
|
max_slots = AZX_DEFAULT_CODECS;
|
||||||
|
|
||||||
|
/* First try to probe all given codec slots */
|
||||||
|
for (c = 0; c < max_slots; c++) {
|
||||||
|
if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
|
||||||
|
if (probe_codec(chip, c) < 0) {
|
||||||
|
/* Some BIOSen give you wrong codec addresses
|
||||||
|
* that don't exist
|
||||||
|
*/
|
||||||
|
dev_warn(chip->card->dev,
|
||||||
|
"Codec #%d probe error; disabling it...\n", c);
|
||||||
|
chip->codec_mask &= ~(1 << c);
|
||||||
|
/* More badly, accessing to a non-existing
|
||||||
|
* codec often screws up the controller chip,
|
||||||
|
* and disturbs the further communications.
|
||||||
|
* Thus if an error occurs during probing,
|
||||||
|
* better to reset the controller chip to
|
||||||
|
* get back to the sanity state.
|
||||||
|
*/
|
||||||
|
azx_stop_chip(chip);
|
||||||
|
azx_init_chip(chip, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* AMD chipsets often cause the communication stalls upon certain
|
||||||
|
* sequence like the pin-detection. It seems that forcing the synced
|
||||||
|
* access works around the stall. Grrr...
|
||||||
|
*/
|
||||||
|
if (chip->driver_caps & AZX_DCAPS_SYNC_WRITE) {
|
||||||
|
dev_dbg(chip->card->dev, "Enable sync_write for stable communication\n");
|
||||||
|
chip->bus->sync_write = 1;
|
||||||
|
chip->bus->allow_bus_reset = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Then create codec instances */
|
||||||
|
for (c = 0; c < max_slots; c++) {
|
||||||
|
if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
|
||||||
|
struct hda_codec *codec;
|
||||||
|
err = snd_hda_codec_new(chip->bus, c, &codec);
|
||||||
|
if (err < 0)
|
||||||
|
continue;
|
||||||
|
codec->jackpoll_interval = get_jackpoll_interval(chip);
|
||||||
|
codec->beep_mode = chip->beep_mode;
|
||||||
|
codecs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!codecs) {
|
||||||
|
dev_err(chip->card->dev, "no codecs initialized\n");
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(azx_codec_create);
|
||||||
|
|
||||||
|
/* configure each codec instance */
|
||||||
|
int azx_codec_configure(struct azx *chip)
|
||||||
|
{
|
||||||
|
struct hda_codec *codec;
|
||||||
|
list_for_each_entry(codec, &chip->bus->codec_list, list) {
|
||||||
|
snd_hda_codec_configure(codec);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(azx_codec_configure);
|
||||||
|
|
||||||
|
/* mixer creation - all stuff is implemented in hda module */
|
||||||
|
int azx_mixer_create(struct azx *chip)
|
||||||
|
{
|
||||||
|
return snd_hda_build_controls(chip->bus);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(azx_mixer_create);
|
||||||
|
|
||||||
|
|
||||||
|
/* initialize SD streams */
|
||||||
|
int azx_init_stream(struct azx *chip)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* initialize each stream (aka device)
|
||||||
|
* assign the starting bdl address to each stream (device)
|
||||||
|
* and initialize
|
||||||
|
*/
|
||||||
|
for (i = 0; i < chip->num_streams; i++) {
|
||||||
|
struct azx_dev *azx_dev = &chip->azx_dev[i];
|
||||||
|
azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8);
|
||||||
|
/* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
|
||||||
|
azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
|
||||||
|
/* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */
|
||||||
|
azx_dev->sd_int_sta_mask = 1 << i;
|
||||||
|
/* stream tag: must be non-zero and unique */
|
||||||
|
azx_dev->index = i;
|
||||||
|
azx_dev->stream_tag = i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(azx_init_stream);
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_DESCRIPTION("Common HDA driver funcitons");
|
MODULE_DESCRIPTION("Common HDA driver funcitons");
|
||||||
|
|
|
@ -21,8 +21,6 @@
|
||||||
#include "hda_priv.h"
|
#include "hda_priv.h"
|
||||||
|
|
||||||
/* PCM setup */
|
/* PCM setup */
|
||||||
int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
|
|
||||||
struct hda_pcm *cpcm);
|
|
||||||
static inline struct azx_dev *get_azx_dev(struct snd_pcm_substream *substream)
|
static inline struct azx_dev *get_azx_dev(struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
return substream->runtime->private_data;
|
return substream->runtime->private_data;
|
||||||
|
@ -34,30 +32,22 @@ unsigned int azx_get_position(struct azx *chip,
|
||||||
/* Stream control. */
|
/* Stream control. */
|
||||||
void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev);
|
void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev);
|
||||||
|
|
||||||
#ifdef CONFIG_SND_HDA_DSP_LOADER
|
|
||||||
int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format,
|
|
||||||
unsigned int byte_size,
|
|
||||||
struct snd_dma_buffer *bufp);
|
|
||||||
void azx_load_dsp_trigger(struct hda_bus *bus, bool start);
|
|
||||||
void azx_load_dsp_cleanup(struct hda_bus *bus,
|
|
||||||
struct snd_dma_buffer *dmab);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Allocation functions. */
|
/* Allocation functions. */
|
||||||
int azx_alloc_stream_pages(struct azx *chip);
|
int azx_alloc_stream_pages(struct azx *chip);
|
||||||
void azx_free_stream_pages(struct azx *chip);
|
void azx_free_stream_pages(struct azx *chip);
|
||||||
|
|
||||||
/*
|
|
||||||
* CORB / RIRB interface
|
|
||||||
*/
|
|
||||||
int azx_send_cmd(struct hda_bus *bus, unsigned int val);
|
|
||||||
unsigned int azx_get_response(struct hda_bus *bus,
|
|
||||||
unsigned int addr);
|
|
||||||
|
|
||||||
/* Low level azx interface */
|
/* Low level azx interface */
|
||||||
void azx_init_chip(struct azx *chip, int full_reset);
|
void azx_init_chip(struct azx *chip, int full_reset);
|
||||||
void azx_stop_chip(struct azx *chip);
|
void azx_stop_chip(struct azx *chip);
|
||||||
void azx_enter_link_reset(struct azx *chip);
|
void azx_enter_link_reset(struct azx *chip);
|
||||||
irqreturn_t azx_interrupt(int irq, void *dev_id);
|
irqreturn_t azx_interrupt(int irq, void *dev_id);
|
||||||
|
|
||||||
|
/* Codec interface */
|
||||||
|
int azx_codec_create(struct azx *chip, const char *model,
|
||||||
|
unsigned int max_slots,
|
||||||
|
int *power_save_to);
|
||||||
|
int azx_codec_configure(struct azx *chip);
|
||||||
|
int azx_mixer_create(struct azx *chip);
|
||||||
|
int azx_init_stream(struct azx *chip);
|
||||||
|
|
||||||
#endif /* __SOUND_HDA_CONTROLLER_H */
|
#endif /* __SOUND_HDA_CONTROLLER_H */
|
||||||
|
|
|
@ -336,10 +336,6 @@ static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev,
|
||||||
|
|
||||||
static int azx_acquire_irq(struct azx *chip, int do_disconnect);
|
static int azx_acquire_irq(struct azx *chip, int do_disconnect);
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
|
||||||
static void azx_power_notify(struct hda_bus *bus, bool power_up);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize the PCI registers
|
* initialize the PCI registers
|
||||||
*/
|
*/
|
||||||
|
@ -432,171 +428,6 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Probe the given codec address
|
|
||||||
*/
|
|
||||||
static int probe_codec(struct azx *chip, int addr)
|
|
||||||
{
|
|
||||||
unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) |
|
|
||||||
(AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
|
|
||||||
unsigned int res;
|
|
||||||
|
|
||||||
mutex_lock(&chip->bus->cmd_mutex);
|
|
||||||
chip->probing = 1;
|
|
||||||
azx_send_cmd(chip->bus, cmd);
|
|
||||||
res = azx_get_response(chip->bus, addr);
|
|
||||||
chip->probing = 0;
|
|
||||||
mutex_unlock(&chip->bus->cmd_mutex);
|
|
||||||
if (res == -1)
|
|
||||||
return -EIO;
|
|
||||||
dev_dbg(chip->card->dev, "codec #%d probed OK\n", addr);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void azx_bus_reset(struct hda_bus *bus)
|
|
||||||
{
|
|
||||||
struct azx *chip = bus->private_data;
|
|
||||||
|
|
||||||
bus->in_reset = 1;
|
|
||||||
azx_stop_chip(chip);
|
|
||||||
azx_init_chip(chip, 1);
|
|
||||||
#ifdef CONFIG_PM
|
|
||||||
if (chip->initialized) {
|
|
||||||
struct azx_pcm *p;
|
|
||||||
list_for_each_entry(p, &chip->pcm_list, list)
|
|
||||||
snd_pcm_suspend_all(p->pcm);
|
|
||||||
snd_hda_suspend(chip->bus);
|
|
||||||
snd_hda_resume(chip->bus);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
bus->in_reset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_jackpoll_interval(struct azx *chip)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
unsigned int j;
|
|
||||||
|
|
||||||
if (!chip->jackpoll_ms)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
i = chip->jackpoll_ms[chip->dev_index];
|
|
||||||
if (i == 0)
|
|
||||||
return 0;
|
|
||||||
if (i < 50 || i > 60000)
|
|
||||||
j = 0;
|
|
||||||
else
|
|
||||||
j = msecs_to_jiffies(i);
|
|
||||||
if (j == 0)
|
|
||||||
dev_warn(chip->card->dev,
|
|
||||||
"jackpoll_ms value out of range: %d\n", i);
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Codec initialization
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int azx_codec_create(struct azx *chip, const char *model,
|
|
||||||
unsigned int max_slots,
|
|
||||||
int *power_save_to)
|
|
||||||
{
|
|
||||||
struct hda_bus_template bus_temp;
|
|
||||||
int c, codecs, err;
|
|
||||||
|
|
||||||
memset(&bus_temp, 0, sizeof(bus_temp));
|
|
||||||
bus_temp.private_data = chip;
|
|
||||||
bus_temp.modelname = model;
|
|
||||||
bus_temp.pci = chip->pci;
|
|
||||||
bus_temp.ops.command = azx_send_cmd;
|
|
||||||
bus_temp.ops.get_response = azx_get_response;
|
|
||||||
bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
|
|
||||||
bus_temp.ops.bus_reset = azx_bus_reset;
|
|
||||||
#ifdef CONFIG_PM
|
|
||||||
bus_temp.power_save = power_save_to;
|
|
||||||
bus_temp.ops.pm_notify = azx_power_notify;
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_SND_HDA_DSP_LOADER
|
|
||||||
bus_temp.ops.load_dsp_prepare = azx_load_dsp_prepare;
|
|
||||||
bus_temp.ops.load_dsp_trigger = azx_load_dsp_trigger;
|
|
||||||
bus_temp.ops.load_dsp_cleanup = azx_load_dsp_cleanup;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) {
|
|
||||||
dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n");
|
|
||||||
chip->bus->needs_damn_long_delay = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
codecs = 0;
|
|
||||||
if (!max_slots)
|
|
||||||
max_slots = AZX_DEFAULT_CODECS;
|
|
||||||
|
|
||||||
/* First try to probe all given codec slots */
|
|
||||||
for (c = 0; c < max_slots; c++) {
|
|
||||||
if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
|
|
||||||
if (probe_codec(chip, c) < 0) {
|
|
||||||
/* Some BIOSen give you wrong codec addresses
|
|
||||||
* that don't exist
|
|
||||||
*/
|
|
||||||
dev_warn(chip->card->dev,
|
|
||||||
"Codec #%d probe error; disabling it...\n", c);
|
|
||||||
chip->codec_mask &= ~(1 << c);
|
|
||||||
/* More badly, accessing to a non-existing
|
|
||||||
* codec often screws up the controller chip,
|
|
||||||
* and disturbs the further communications.
|
|
||||||
* Thus if an error occurs during probing,
|
|
||||||
* better to reset the controller chip to
|
|
||||||
* get back to the sanity state.
|
|
||||||
*/
|
|
||||||
azx_stop_chip(chip);
|
|
||||||
azx_init_chip(chip, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* AMD chipsets often cause the communication stalls upon certain
|
|
||||||
* sequence like the pin-detection. It seems that forcing the synced
|
|
||||||
* access works around the stall. Grrr...
|
|
||||||
*/
|
|
||||||
if (chip->driver_caps & AZX_DCAPS_SYNC_WRITE) {
|
|
||||||
dev_dbg(chip->card->dev, "Enable sync_write for stable communication\n");
|
|
||||||
chip->bus->sync_write = 1;
|
|
||||||
chip->bus->allow_bus_reset = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Then create codec instances */
|
|
||||||
for (c = 0; c < max_slots; c++) {
|
|
||||||
if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
|
|
||||||
struct hda_codec *codec;
|
|
||||||
err = snd_hda_codec_new(chip->bus, c, &codec);
|
|
||||||
if (err < 0)
|
|
||||||
continue;
|
|
||||||
codec->jackpoll_interval = get_jackpoll_interval(chip);
|
|
||||||
codec->beep_mode = chip->beep_mode;
|
|
||||||
codecs++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!codecs) {
|
|
||||||
dev_err(chip->card->dev, "no codecs initialized\n");
|
|
||||||
return -ENXIO;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* configure each codec instance */
|
|
||||||
static int azx_codec_configure(struct azx *chip)
|
|
||||||
{
|
|
||||||
struct hda_codec *codec;
|
|
||||||
list_for_each_entry(codec, &chip->bus->codec_list, list) {
|
|
||||||
snd_hda_codec_configure(codec);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check whether the current DMA position is acceptable for updating
|
* Check whether the current DMA position is acceptable for updating
|
||||||
* periods. Returns non-zero if it's OK.
|
* periods. Returns non-zero if it's OK.
|
||||||
|
@ -681,41 +512,6 @@ static void azx_clear_irq_pending(struct azx *chip)
|
||||||
spin_unlock_irq(&chip->reg_lock);
|
spin_unlock_irq(&chip->reg_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* mixer creation - all stuff is implemented in hda module
|
|
||||||
*/
|
|
||||||
static int azx_mixer_create(struct azx *chip)
|
|
||||||
{
|
|
||||||
return snd_hda_build_controls(chip->bus);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* initialize SD streams
|
|
||||||
*/
|
|
||||||
static int azx_init_stream(struct azx *chip)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* initialize each stream (aka device)
|
|
||||||
* assign the starting bdl address to each stream (device)
|
|
||||||
* and initialize
|
|
||||||
*/
|
|
||||||
for (i = 0; i < chip->num_streams; i++) {
|
|
||||||
struct azx_dev *azx_dev = &chip->azx_dev[i];
|
|
||||||
azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8);
|
|
||||||
/* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
|
|
||||||
azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
|
|
||||||
/* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */
|
|
||||||
azx_dev->sd_int_sta_mask = 1 << i;
|
|
||||||
/* stream tag: must be non-zero and unique */
|
|
||||||
azx_dev->index = i;
|
|
||||||
azx_dev->stream_tag = i + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int azx_acquire_irq(struct azx *chip, int do_disconnect)
|
static int azx_acquire_irq(struct azx *chip, int do_disconnect)
|
||||||
{
|
{
|
||||||
if (request_irq(chip->pci->irq, azx_interrupt,
|
if (request_irq(chip->pci->irq, azx_interrupt,
|
||||||
|
@ -734,20 +530,6 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
/* power-up/down the controller */
|
|
||||||
static void azx_power_notify(struct hda_bus *bus, bool power_up)
|
|
||||||
{
|
|
||||||
struct azx *chip = bus->private_data;
|
|
||||||
|
|
||||||
if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (power_up)
|
|
||||||
pm_runtime_get_sync(chip->card->dev);
|
|
||||||
else
|
|
||||||
pm_runtime_put_sync(chip->card->dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static DEFINE_MUTEX(card_list_lock);
|
static DEFINE_MUTEX(card_list_lock);
|
||||||
static LIST_HEAD(card_list);
|
static LIST_HEAD(card_list);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue