tc->cycle_last = last;
}
+ static inline struct hda_pcm_stream *
+ to_hda_pcm_stream(struct snd_pcm_substream *substream)
+ {
+ struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+ return &apcm->info->stream[substream->stream];
+ }
+
static u64 azx_adjust_codec_delay(struct snd_pcm_substream *substream,
u64 nsec)
{
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
- struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+ struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
u64 codec_frames, codec_nsecs;
if (!hinfo->ops.get_delay)
static int azx_pcm_close(struct snd_pcm_substream *substream)
{
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
- struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+ struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
struct azx *chip = apcm->chip;
struct azx_dev *azx_dev = get_azx_dev(substream);
unsigned long flags;
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
struct azx_dev *azx_dev = get_azx_dev(substream);
struct azx *chip = apcm->chip;
- struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+ struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
int err;
/* reset BDL address */
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
struct azx *chip = apcm->chip;
struct azx_dev *azx_dev = get_azx_dev(substream);
- struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+ struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int bufsize, period_bytes, format_val, stream_tag;
int err;
if (substream->runtime) {
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
- struct hda_pcm_stream *hinfo = apcm->hinfo[stream];
+ struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
if (chip->get_delay[stream])
delay += chip->get_delay[stream](chip, azx_dev, pos);
static int azx_pcm_open(struct snd_pcm_substream *substream)
{
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
- struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+ struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
struct azx *chip = apcm->chip;
struct azx_dev *azx_dev;
struct snd_pcm_runtime *runtime = substream->runtime;
buff_step);
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
buff_step);
- snd_hda_power_up_d3wait(apcm->codec);
+ snd_hda_power_up(apcm->codec);
err = hinfo->ops.open(hinfo, apcm->codec, substream);
if (err < 0) {
azx_release_device(azx_dev);
struct azx_pcm *apcm = pcm->private_data;
if (apcm) {
list_del(&apcm->list);
+ apcm->info->pcm = NULL;
kfree(apcm);
}
}
apcm->chip = chip;
apcm->pcm = pcm;
apcm->codec = codec;
+ apcm->info = cpcm;
pcm->private_data = apcm;
pcm->private_free = azx_pcm_free;
if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM)
list_add_tail(&apcm->list, &chip->pcm_list);
cpcm->pcm = pcm;
for (s = 0; s < 2; s++) {
- apcm->hinfo[s] = &cpcm->stream[s];
if (cpcm->stream[s].substreams)
snd_pcm_set_ops(pcm, s, &azx_pcm_ops);
}
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
chip->card->dev,
size, MAX_PREALLOC_SIZE);
- /* link to codec */
- for (s = 0; s < 2; s++)
- pcm->streams[s].dev.parent = &codec->dev;
return 0;
}
dev_err(chip->card->dev, "cannot allocate CORB/RIRB\n");
return err;
}
-EXPORT_SYMBOL_GPL(azx_alloc_cmd_io);
static void azx_init_cmd_io(struct azx *chip)
{
azx_writeb(chip, RIRBCTL, AZX_RBCTL_DMA_EN | AZX_RBCTL_IRQ_EN);
spin_unlock_irq(&chip->reg_lock);
}
-EXPORT_SYMBOL_GPL(azx_init_cmd_io);
static void azx_free_cmd_io(struct azx *chip)
{
azx_writeb(chip, CORBCTL, 0);
spin_unlock_irq(&chip->reg_lock);
}
-EXPORT_SYMBOL_GPL(azx_free_cmd_io);
static unsigned int azx_command_addr(u32 cmd)
{
}
}
- if (!bus->no_response_fallback)
+ if (bus->no_response_fallback)
return -1;
if (!chip->polling_mode && chip->poll_count < 2) {
else
return azx_corb_send_cmd(bus, val);
}
-EXPORT_SYMBOL_GPL(azx_send_cmd);
/* get a response */
static unsigned int azx_get_response(struct hda_bus *bus,
else
return azx_rirb_get_response(bus, addr);
}
-EXPORT_SYMBOL_GPL(azx_get_response);
#ifdef CONFIG_SND_HDA_DSP_LOADER
/*
bus->in_reset = 1;
azx_stop_chip(chip);
azx_init_chip(chip, true);
- #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
+ if (chip->initialized)
+ snd_hda_bus_reset(chip->bus);
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 (!azx_has_pm_runtime(chip))
- 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;
.get_response = azx_get_response,
.attach_pcm = azx_attach_pcm_stream,
.bus_reset = azx_bus_reset,
- #ifdef CONFIG_PM
- .pm_notify = azx_power_notify,
- #endif
#ifdef CONFIG_SND_HDA_DSP_LOADER
.load_dsp_prepare = azx_load_dsp_prepare,
.load_dsp_trigger = azx_load_dsp_trigger,
};
/* HD-audio bus initialization */
- int azx_bus_create(struct azx *chip, const char *model, int *power_save_to)
+ int azx_bus_create(struct azx *chip, const char *model)
{
struct hda_bus *bus;
int err;
bus->pci = chip->pci;
bus->modelname = model;
bus->ops = bus_ops;
- #ifdef CONFIG_PM
- bus->power_save = power_save_to;
- #endif
if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) {
dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n");
return val;
}
+/* is this a stereo widget or a stereo-to-mono mix? */
+static bool is_stereo_amps(struct hda_codec *codec, hda_nid_t nid, int dir)
+{
+ unsigned int wcaps = get_wcaps(codec, nid);
+ hda_nid_t conn;
+
+ if (wcaps & AC_WCAP_STEREO)
+ return true;
+ if (dir != HDA_INPUT || get_wcaps_type(wcaps) != AC_WID_AUD_MIX)
+ return false;
+ if (snd_hda_get_num_conns(codec, nid) != 1)
+ return false;
+ if (snd_hda_get_connections(codec, nid, &conn, 1) < 0)
+ return false;
+ return !!(get_wcaps(codec, conn) & AC_WCAP_STEREO);
+}
+
/* initialize the amp value (only at the first time) */
static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx)
{
unsigned int caps = query_amp_caps(codec, nid, dir);
int val = get_amp_val_to_activate(codec, nid, dir, caps, false);
- snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val);
+
+ if (is_stereo_amps(codec, nid, dir))
+ snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val);
+ else
+ snd_hda_codec_amp_init(codec, nid, 0, dir, idx, 0xff, val);
+}
+
+/* update the amp, doing in stereo or mono depending on NID */
+static int update_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx,
+ unsigned int mask, unsigned int val)
+{
+ if (is_stereo_amps(codec, nid, dir))
+ return snd_hda_codec_amp_stereo(codec, nid, dir, idx,
+ mask, val);
+ else
+ return snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
+ mask, val);
}
/* calculate amp value mask we can modify;
return;
val &= mask;
- snd_hda_codec_amp_stereo(codec, nid, dir, idx, mask, val);
+ update_amp(codec, nid, dir, idx, mask, val);
}
static void activate_amp_out(struct hda_codec *codec, struct nid_path *path,
has_amp = nid_has_mute(codec, mix, HDA_INPUT);
for (i = 0; i < nums; i++) {
if (has_amp)
- snd_hda_codec_amp_stereo(codec, mix,
- HDA_INPUT, i,
- 0xff, HDA_AMP_MUTE);
+ update_amp(codec, mix, HDA_INPUT, i,
+ 0xff, HDA_AMP_MUTE);
else if (nid_has_volume(codec, conn[i], HDA_OUTPUT))
- snd_hda_codec_amp_stereo(codec, conn[i],
- HDA_OUTPUT, 0,
- 0xff, HDA_AMP_MUTE);
+ update_amp(codec, conn[i], HDA_OUTPUT, 0,
+ 0xff, HDA_AMP_MUTE);
}
}
#endif
};
- /**
+ /*
* snd_hda_parse_generic_codec - Generic codec parser
* @codec: the HDA codec
- *
- * This should be called from the HDA codec core.
*/
- int snd_hda_parse_generic_codec(struct hda_codec *codec)
+ static int snd_hda_parse_generic_codec(struct hda_codec *codec)
{
struct hda_gen_spec *spec;
int err;
snd_hda_gen_free(codec);
return err;
}
- EXPORT_SYMBOL_GPL(snd_hda_parse_generic_codec);
+
+ static const struct hda_codec_preset snd_hda_preset_generic[] = {
+ { .id = HDA_CODEC_ID_GENERIC, .patch = snd_hda_parse_generic_codec },
+ {} /* terminator */
+ };
+
+ static struct hda_codec_driver generic_driver = {
+ .preset = snd_hda_preset_generic,
+ };
+
+ module_hda_codec_driver(generic_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic HD-audio codec parser");
#define param_check_xint param_check_int
static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
- static int *power_save_addr = &power_save;
module_param(power_save, xint, 0644);
MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
"(in second, 0 = disable).");
module_param(power_save_controller, bool, 0644);
MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
#else
- static int *power_save_addr;
+ #define power_save 0
#endif /* CONFIG_PM */
static int align_buffer_size = -1;
{
struct hda_intel *hda;
struct azx *chip;
- struct hda_codec *c;
int prev = power_save;
int ret = param_set_int(val, kp);
chip = &hda->chip;
if (!chip->bus || chip->disabled)
continue;
- list_for_each_entry(c, &chip->bus->codec_list, list)
- snd_hda_power_sync(c);
+ snd_hda_set_power_save(chip->bus, power_save * 1000);
}
mutex_unlock(&card_list_lock);
return 0;
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip;
struct hda_intel *hda;
- struct azx_pcm *p;
if (!card)
return 0;
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
azx_clear_irq_pending(chip);
- list_for_each_entry(p, &chip->pcm_list, list)
- snd_pcm_suspend_all(p->pcm);
- if (chip->initialized)
- snd_hda_suspend(chip->bus);
azx_stop_chip(chip);
azx_enter_link_reset(chip);
if (chip->irq >= 0) {
azx_init_chip(chip, true);
- snd_hda_resume(chip->bus);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
}
if (chip->disabled || hda->init_failed)
return 0;
- if (!power_save_controller || !azx_has_pm_runtime(chip))
+ if (!power_save_controller || !azx_has_pm_runtime(chip) ||
+ chip->bus->codec_powered)
return -EBUSY;
return 0;
return 0;
}
- static void power_down_all_codecs(struct azx *chip)
- {
- #ifdef CONFIG_PM
- /* The codecs were powered up in snd_hda_codec_new().
- * Now all initialization done, so turn them down if possible
- */
- struct hda_codec *codec;
- list_for_each_entry(codec, &chip->bus->codec_list, list) {
- snd_hda_power_down(codec);
- }
- #endif
- }
-
#ifdef CONFIG_SND_HDA_PATCH_LOADER
/* callback from request_firmware_nowait() */
static void azx_firmware_cb(const struct firmware *fw, void *context)
#endif
/* create codec instances */
- err = azx_bus_create(chip, model[dev], power_save_addr);
+ err = azx_bus_create(chip, model[dev]);
if (err < 0)
goto out_free;
goto out_free;
chip->running = 1;
- power_down_all_codecs(chip);
azx_notifier_register(chip);
azx_add_card_list(chip);
+ snd_hda_set_power_save(chip->bus, power_save * 1000);
if (azx_has_pm_runtime(chip) || hda->use_vga_switcheroo)
pm_runtime_put_noidle(&pci->dev);
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
/* Panther Point */
{ PCI_DEVICE(0x8086, 0x1e20),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
/* Lynx Point */
{ PCI_DEVICE(0x8086, 0x8c20),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
SND_PCI_QUIRK(0x106b, 0x1c00, "MacBookPro 8,1", CS420X_MBP81),
SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122),
SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101),
+ SND_PCI_QUIRK(0x106b, 0x5600, "MacBookAir 5,2", CS420X_MBP81),
SND_PCI_QUIRK(0x106b, 0x5b00, "MacBookAir 4,2", CS420X_MBA42),
SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE),
{} /* terminator */
return -ENOMEM;
spec->gen.automute_hook = cs_automute;
+ codec->single_adc_amp = 1;
snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl,
cs420x_fixups);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Cirrus Logic HD-audio codec");
- static struct hda_codec_preset_list cirrus_list = {
+ static struct hda_codec_driver cirrus_driver = {
.preset = snd_hda_preset_cirrus,
- .owner = THIS_MODULE,
};
- static int __init patch_cirrus_init(void)
- {
- return snd_hda_add_codec_preset(&cirrus_list);
- }
-
- static void __exit patch_cirrus_exit(void)
- {
- snd_hda_delete_codec_preset(&cirrus_list);
- }
-
- module_init(patch_cirrus_init)
- module_exit(patch_cirrus_exit)
+ module_hda_codec_driver(cirrus_driver);
CXT_PINCFG_LENOVO_TP410,
CXT_PINCFG_LEMOTE_A1004,
CXT_PINCFG_LEMOTE_A1205,
+ CXT_PINCFG_COMPAQ_CQ60,
CXT_FIXUP_STEREO_DMIC,
CXT_FIXUP_INC_MIC_BOOST,
CXT_FIXUP_HEADPHONE_MIC_PIN,
.type = HDA_FIXUP_PINS,
.v.pins = cxt_pincfg_lemote,
},
+ [CXT_PINCFG_COMPAQ_CQ60] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ /* 0x17 was falsely set up as a mic, it should 0x1d */
+ { 0x17, 0x400001f0 },
+ { 0x1d, 0x97a70120 },
+ { }
+ }
+ },
[CXT_FIXUP_STEREO_DMIC] = {
.type = HDA_FIXUP_FUNC,
.v.func = cxt_fixup_stereo_dmic,
};
static const struct snd_pci_quirk cxt5051_fixups[] = {
+ SND_PCI_QUIRK(0x103c, 0x360b, "Compaq CQ60", CXT_PINCFG_COMPAQ_CQ60),
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT_PINCFG_LENOVO_X200),
{}
};
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Conexant HD-audio codec");
- static struct hda_codec_preset_list conexant_list = {
+ static struct hda_codec_driver conexant_driver = {
.preset = snd_hda_preset_conexant,
- .owner = THIS_MODULE,
};
- static int __init patch_conexant_init(void)
- {
- return snd_hda_add_codec_preset(&conexant_list);
- }
-
- static void __exit patch_conexant_exit(void)
- {
- snd_hda_delete_codec_preset(&conexant_list);
- }
-
- module_init(patch_conexant_init)
- module_exit(patch_conexant_exit)
+ module_hda_codec_driver(conexant_driver);
{0x17, 0x40000000},
{0x1d, 0x40700001},
{0x21, 0x02211040}),
+ SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+ ALC255_STANDARD_PINS,
+ {0x12, 0x90a60170},
+ {0x14, 0x90170140},
+ {0x17, 0x40000000},
+ {0x1d, 0x40700001},
+ {0x21, 0x02211050}),
SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4,
{0x12, 0x90a60130},
{0x13, 0x40000000},
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Realtek HD-audio codec");
- static struct hda_codec_preset_list realtek_list = {
+ static struct hda_codec_driver realtek_driver = {
.preset = snd_hda_preset_realtek,
- .owner = THIS_MODULE,
};
- static int __init patch_realtek_init(void)
- {
- return snd_hda_add_codec_preset(&realtek_list);
- }
-
- static void __exit patch_realtek_exit(void)
- {
- snd_hda_delete_codec_preset(&realtek_list);
- }
-
- module_init(patch_realtek_init)
- module_exit(patch_realtek_exit)
+ module_hda_codec_driver(realtek_driver);