18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * 38c2ecf20Sopenharmony_ci * hda_loongson.c - Implementation of primary alsa driver code base 48c2ecf20Sopenharmony_ci * for Intel HD Audio. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (c) 2004 Intel Corporation. All rights reserved. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> 98c2ecf20Sopenharmony_ci * PeiSen Hou <pshou@realtek.com.tw> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Copyright (c) 2014 Huacai Chen <chenhc@lemote.com> 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify it 148c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License as published by the Free 158c2ecf20Sopenharmony_ci * Software Foundation; either version 2 of the License, or (at your option) 168c2ecf20Sopenharmony_ci * any later version. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but WITHOUT 198c2ecf20Sopenharmony_ci * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 208c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 218c2ecf20Sopenharmony_ci * more details. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License along with 248c2ecf20Sopenharmony_ci * this program; if not, write to the Free Software Foundation, Inc., 59 258c2ecf20Sopenharmony_ci * Temple Place - Suite 330, Boston, MA 02111-1307, USA. 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * CONTACTS: 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * Matt Jared matt.jared@intel.com 308c2ecf20Sopenharmony_ci * Andy Kopp andy.kopp@intel.com 318c2ecf20Sopenharmony_ci * Dan Kogan dan.d.kogan@intel.com 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * CHANGES: 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * 2004.12.01 Major rewrite by tiwai, merged the work of pshou 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#include <linux/delay.h> 408c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 418c2ecf20Sopenharmony_ci#include <linux/kernel.h> 428c2ecf20Sopenharmony_ci#include <linux/module.h> 438c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 448c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 458c2ecf20Sopenharmony_ci#include <linux/init.h> 468c2ecf20Sopenharmony_ci#include <linux/slab.h> 478c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 488c2ecf20Sopenharmony_ci#include <linux/mutex.h> 498c2ecf20Sopenharmony_ci#include <linux/reboot.h> 508c2ecf20Sopenharmony_ci#include <linux/io.h> 518c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 528c2ecf20Sopenharmony_ci#include <linux/clocksource.h> 538c2ecf20Sopenharmony_ci#include <linux/time.h> 548c2ecf20Sopenharmony_ci#include <linux/completion.h> 558c2ecf20Sopenharmony_ci#include <linux/firmware.h> 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#include <sound/core.h> 588c2ecf20Sopenharmony_ci#include <sound/initval.h> 598c2ecf20Sopenharmony_ci#include <sound/hda_codec.h> 608c2ecf20Sopenharmony_ci#include <loongson.h> 618c2ecf20Sopenharmony_ci#include "hda_controller.h" 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define LS7A_NUM_CAPTURE 4 648c2ecf20Sopenharmony_ci#define LS7A_NUM_PLAYBACK 4 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; 678c2ecf20Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; 688c2ecf20Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; 698c2ecf20Sopenharmony_cistatic char *model[SNDRV_CARDS]; 708c2ecf20Sopenharmony_cistatic int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; 718c2ecf20Sopenharmony_cistatic int probe_only[SNDRV_CARDS]; 728c2ecf20Sopenharmony_cistatic int jackpoll_ms[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1200}; 738c2ecf20Sopenharmony_cistatic bool single_cmd; 748c2ecf20Sopenharmony_cistatic int enable_msi = -1; 758c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_HDA_INPUT_BEEP 768c2ecf20Sopenharmony_cistatic bool beep_mode[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 778c2ecf20Sopenharmony_ci CONFIG_SND_HDA_INPUT_BEEP_MODE}; 788c2ecf20Sopenharmony_ci#endif 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cimodule_param_array(index, int, NULL, 0444); 818c2ecf20Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); 828c2ecf20Sopenharmony_cimodule_param_array(id, charp, NULL, 0444); 838c2ecf20Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for Intel HD audio interface."); 848c2ecf20Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444); 858c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable Intel HD audio interface."); 868c2ecf20Sopenharmony_cimodule_param_array(model, charp, NULL, 0444); 878c2ecf20Sopenharmony_ciMODULE_PARM_DESC(model, "Use the given board model."); 888c2ecf20Sopenharmony_cimodule_param_array(bdl_pos_adj, int, NULL, 0644); 898c2ecf20Sopenharmony_ciMODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset."); 908c2ecf20Sopenharmony_cimodule_param_array(probe_only, int, NULL, 0444); 918c2ecf20Sopenharmony_ciMODULE_PARM_DESC(probe_only, "Only probing and no codec initialization."); 928c2ecf20Sopenharmony_cimodule_param_array(jackpoll_ms, int, NULL, 0444); 938c2ecf20Sopenharmony_ciMODULE_PARM_DESC(jackpoll_ms, "Ms between polling for jack events (default = 0, using unsol events only)"); 948c2ecf20Sopenharmony_cimodule_param(single_cmd, bool, 0444); 958c2ecf20Sopenharmony_ciMODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " 968c2ecf20Sopenharmony_ci "(for debugging only)."); 978c2ecf20Sopenharmony_cimodule_param(enable_msi, bint, 0444); 988c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); 998c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_HDA_INPUT_BEEP 1008c2ecf20Sopenharmony_cimodule_param_array(beep_mode, bool, NULL, 0444); 1018c2ecf20Sopenharmony_ciMODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode " 1028c2ecf20Sopenharmony_ci "(0=off, 1=on) (default=1)."); 1038c2ecf20Sopenharmony_ci#endif 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 1068c2ecf20Sopenharmony_cistatic int param_set_xint(const char *val, const struct kernel_param *kp); 1078c2ecf20Sopenharmony_cistatic struct kernel_param_ops param_ops_xint = { 1088c2ecf20Sopenharmony_ci .set = param_set_xint, 1098c2ecf20Sopenharmony_ci .get = param_get_int, 1108c2ecf20Sopenharmony_ci}; 1118c2ecf20Sopenharmony_ci#define param_check_xint param_check_int 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; 1148c2ecf20Sopenharmony_cimodule_param(power_save, xint, 0644); 1158c2ecf20Sopenharmony_ciMODULE_PARM_DESC(power_save, "Automatic power-saving timeout " 1168c2ecf20Sopenharmony_ci "(in second, 0 = disable)."); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* reset the HD-audio controller in power save mode. 1198c2ecf20Sopenharmony_ci * this may give more power-saving, but will take longer time to 1208c2ecf20Sopenharmony_ci * wake up. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_cistatic bool power_save_controller = 1; 1238c2ecf20Sopenharmony_cimodule_param(power_save_controller, bool, 0644); 1248c2ecf20Sopenharmony_ciMODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode."); 1258c2ecf20Sopenharmony_ci#else 1268c2ecf20Sopenharmony_ci#define power_save 0 1278c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic int align_buffer_size = -1; 1308c2ecf20Sopenharmony_cimodule_param(align_buffer_size, bint, 0644); 1318c2ecf20Sopenharmony_ciMODULE_PARM_DESC(align_buffer_size, 1328c2ecf20Sopenharmony_ci "Force buffer and period sizes to be multiple of 128 bytes."); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1358c2ecf20Sopenharmony_ciMODULE_SUPPORTED_DEVICE("{Loongson, LS7A}"); 1368c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Loongson LS7A HDA driver"); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/* driver types */ 1398c2ecf20Sopenharmony_cienum { 1408c2ecf20Sopenharmony_ci AZX_DRIVER_LS7A, 1418c2ecf20Sopenharmony_ci AZX_DRIVER_HDMI, 1428c2ecf20Sopenharmony_ci AZX_NUM_DRIVERS, /* keep this as last entry */ 1438c2ecf20Sopenharmony_ci}; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic char *driver_short_names[] = { 1468c2ecf20Sopenharmony_ci [AZX_DRIVER_LS7A] = "HD-Audio Loongson", 1478c2ecf20Sopenharmony_ci [AZX_DRIVER_HDMI] = "HD-Audio Loongson HDMI", 1488c2ecf20Sopenharmony_ci}; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistruct hda_loongson { 1518c2ecf20Sopenharmony_ci struct azx chip; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* for pending irqs */ 1548c2ecf20Sopenharmony_ci struct work_struct irq_pending_work; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* sync probing */ 1578c2ecf20Sopenharmony_ci struct completion probe_wait; 1588c2ecf20Sopenharmony_ci struct work_struct probe_work; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci /* card list (for power_save trigger) */ 1618c2ecf20Sopenharmony_ci struct list_head list; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci /* extra flags */ 1648c2ecf20Sopenharmony_ci unsigned int irq_pending_warned:1; 1658c2ecf20Sopenharmony_ci unsigned int probe_continued:1; 1668c2ecf20Sopenharmony_ci}; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic int azx_acquire_irq(struct azx *chip, int do_disconnect); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci/* called from IRQ */ 1738c2ecf20Sopenharmony_cistatic int azx_position_check(struct azx *chip, struct azx_dev *azx_dev) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci struct hda_loongson *hda = container_of(chip, struct hda_loongson, chip); 1768c2ecf20Sopenharmony_ci int ok; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci ok = azx_position_ok(chip, azx_dev); 1798c2ecf20Sopenharmony_ci if (ok == 1) { 1808c2ecf20Sopenharmony_ci azx_dev->irq_pending = 0; 1818c2ecf20Sopenharmony_ci return ok; 1828c2ecf20Sopenharmony_ci } else if (ok == 0) { 1838c2ecf20Sopenharmony_ci /* bogus IRQ, process it later */ 1848c2ecf20Sopenharmony_ci azx_dev->irq_pending = 1; 1858c2ecf20Sopenharmony_ci schedule_work(&hda->irq_pending_work); 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci return 0; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci/* 1918c2ecf20Sopenharmony_ci * Check whether the current DMA position is acceptable for updating 1928c2ecf20Sopenharmony_ci * periods. Returns non-zero if it's OK. 1938c2ecf20Sopenharmony_ci * 1948c2ecf20Sopenharmony_ci * Many HD-audio controllers appear pretty inaccurate about 1958c2ecf20Sopenharmony_ci * the update-IRQ timing. The IRQ is issued before actually the 1968c2ecf20Sopenharmony_ci * data is processed. So, we need to process it afterwords in a 1978c2ecf20Sopenharmony_ci * workqueue. 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_cistatic int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci return 1; /* OK, it's fine */ 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci/* 2058c2ecf20Sopenharmony_ci * The work for pending PCM period updates. 2068c2ecf20Sopenharmony_ci */ 2078c2ecf20Sopenharmony_cistatic void azx_irq_pending_work(struct work_struct *work) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci struct hda_loongson *hda = container_of(work, struct hda_loongson, irq_pending_work); 2108c2ecf20Sopenharmony_ci struct azx *chip = &hda->chip; 2118c2ecf20Sopenharmony_ci struct hdac_bus *bus = azx_bus(chip); 2128c2ecf20Sopenharmony_ci struct hdac_stream *s; 2138c2ecf20Sopenharmony_ci int pending, ok; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (!hda->irq_pending_warned) { 2168c2ecf20Sopenharmony_ci dev_info(chip->card->dev, 2178c2ecf20Sopenharmony_ci "IRQ timing workaround is activated for card #%d. Suggest a bigger bdl_pos_adj.\n", 2188c2ecf20Sopenharmony_ci chip->card->number); 2198c2ecf20Sopenharmony_ci hda->irq_pending_warned = 1; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci for (;;) { 2238c2ecf20Sopenharmony_ci pending = 0; 2248c2ecf20Sopenharmony_ci spin_lock_irq(&bus->reg_lock); 2258c2ecf20Sopenharmony_ci list_for_each_entry(s, &bus->stream_list, list) { 2268c2ecf20Sopenharmony_ci struct azx_dev *azx_dev = stream_to_azx_dev(s); 2278c2ecf20Sopenharmony_ci if (!azx_dev->irq_pending || 2288c2ecf20Sopenharmony_ci !s->substream || 2298c2ecf20Sopenharmony_ci !s->running) 2308c2ecf20Sopenharmony_ci continue; 2318c2ecf20Sopenharmony_ci ok = azx_position_ok(chip, azx_dev); 2328c2ecf20Sopenharmony_ci if (ok > 0) { 2338c2ecf20Sopenharmony_ci azx_dev->irq_pending = 0; 2348c2ecf20Sopenharmony_ci spin_unlock(&bus->reg_lock); 2358c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(s->substream); 2368c2ecf20Sopenharmony_ci spin_lock(&bus->reg_lock); 2378c2ecf20Sopenharmony_ci } else if (ok < 0) { 2388c2ecf20Sopenharmony_ci pending = 0; /* too early */ 2398c2ecf20Sopenharmony_ci } else 2408c2ecf20Sopenharmony_ci pending++; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci spin_unlock_irq(&bus->reg_lock); 2438c2ecf20Sopenharmony_ci if (!pending) 2448c2ecf20Sopenharmony_ci return; 2458c2ecf20Sopenharmony_ci msleep(1); 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci/* clear irq_pending flags and assure no on-going workq */ 2508c2ecf20Sopenharmony_cistatic void azx_clear_irq_pending(struct azx *chip) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct hdac_bus *bus = azx_bus(chip); 2538c2ecf20Sopenharmony_ci struct hdac_stream *s; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci spin_lock_irq(&bus->reg_lock); 2568c2ecf20Sopenharmony_ci list_for_each_entry(s, &bus->stream_list, list) { 2578c2ecf20Sopenharmony_ci struct azx_dev *azx_dev = stream_to_azx_dev(s); 2588c2ecf20Sopenharmony_ci azx_dev->irq_pending = 0; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci spin_unlock_irq(&bus->reg_lock); 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic int azx_acquire_irq(struct azx *chip, int do_disconnect) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci struct hdac_bus *bus = azx_bus(chip); 2668c2ecf20Sopenharmony_ci int irq; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (chip->pci) 2698c2ecf20Sopenharmony_ci irq = chip->pci->irq; 2708c2ecf20Sopenharmony_ci else 2718c2ecf20Sopenharmony_ci irq = platform_get_irq(to_platform_device(chip->card->dev), 0); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (request_irq(irq, azx_interrupt, chip->msi ? 0 : IRQF_SHARED, 2748c2ecf20Sopenharmony_ci KBUILD_MODNAME, chip)) { 2758c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 2768c2ecf20Sopenharmony_ci "unable to grab IRQ %d, disabling device\n", irq); 2778c2ecf20Sopenharmony_ci if (do_disconnect) 2788c2ecf20Sopenharmony_ci snd_card_disconnect(chip->card); 2798c2ecf20Sopenharmony_ci return -1; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci bus->irq = irq; 2828c2ecf20Sopenharmony_ci return 0; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 2868c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(card_list_lock); 2878c2ecf20Sopenharmony_cistatic LIST_HEAD(card_list); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic void azx_add_card_list(struct azx *chip) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct hda_loongson *hda = container_of(chip, struct hda_loongson, chip); 2928c2ecf20Sopenharmony_ci mutex_lock(&card_list_lock); 2938c2ecf20Sopenharmony_ci list_add(&hda->list, &card_list); 2948c2ecf20Sopenharmony_ci mutex_unlock(&card_list_lock); 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic void azx_del_card_list(struct azx *chip) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci struct hda_loongson *hda = container_of(chip, struct hda_loongson, chip); 3008c2ecf20Sopenharmony_ci mutex_lock(&card_list_lock); 3018c2ecf20Sopenharmony_ci list_del_init(&hda->list); 3028c2ecf20Sopenharmony_ci mutex_unlock(&card_list_lock); 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci/* trigger power-save check at writing parameter */ 3068c2ecf20Sopenharmony_cistatic int param_set_xint(const char *val, const struct kernel_param *kp) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci struct hda_loongson *hda; 3098c2ecf20Sopenharmony_ci struct azx *chip; 3108c2ecf20Sopenharmony_ci int prev = power_save; 3118c2ecf20Sopenharmony_ci int ret = param_set_int(val, kp); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (ret || prev == power_save) 3148c2ecf20Sopenharmony_ci return ret; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci mutex_lock(&card_list_lock); 3178c2ecf20Sopenharmony_ci list_for_each_entry(hda, &card_list, list) { 3188c2ecf20Sopenharmony_ci chip = &hda->chip; 3198c2ecf20Sopenharmony_ci if (!hda->probe_continued || chip->disabled) 3208c2ecf20Sopenharmony_ci continue; 3218c2ecf20Sopenharmony_ci snd_hda_set_power_save(&chip->bus, power_save * 1000); 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci mutex_unlock(&card_list_lock); 3248c2ecf20Sopenharmony_ci return 0; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci#else 3278c2ecf20Sopenharmony_ci#define azx_add_card_list(chip) /* NOP */ 3288c2ecf20Sopenharmony_ci#define azx_del_card_list(chip) /* NOP */ 3298c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci#if defined(CONFIG_PM_SLEEP) 3328c2ecf20Sopenharmony_ci/* 3338c2ecf20Sopenharmony_ci * power management 3348c2ecf20Sopenharmony_ci */ 3358c2ecf20Sopenharmony_cistatic int azx_suspend(struct device *dev) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci struct snd_card *card = dev_get_drvdata(dev); 3388c2ecf20Sopenharmony_ci struct azx *chip = card->private_data; 3398c2ecf20Sopenharmony_ci struct hdac_bus *bus; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (chip->disabled) 3428c2ecf20Sopenharmony_ci return 0; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci bus = azx_bus(chip); 3458c2ecf20Sopenharmony_ci snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); 3468c2ecf20Sopenharmony_ci azx_clear_irq_pending(chip); 3478c2ecf20Sopenharmony_ci azx_stop_chip(chip); 3488c2ecf20Sopenharmony_ci azx_enter_link_reset(chip); 3498c2ecf20Sopenharmony_ci if (bus->irq >= 0) { 3508c2ecf20Sopenharmony_ci free_irq(bus->irq, chip); 3518c2ecf20Sopenharmony_ci bus->irq = -1; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci return 0; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic int azx_resume(struct device *dev) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci struct snd_card *card = dev_get_drvdata(dev); 3598c2ecf20Sopenharmony_ci struct azx *chip = card->private_data; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci if (chip->disabled) 3628c2ecf20Sopenharmony_ci return 0; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci chip->msi = 0; 3658c2ecf20Sopenharmony_ci if (azx_acquire_irq(chip, 1) < 0) 3668c2ecf20Sopenharmony_ci return -EIO; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci azx_init_chip(chip, true); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci snd_power_change_state(card, SNDRV_CTL_POWER_D0); 3718c2ecf20Sopenharmony_ci return 0; 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 3768c2ecf20Sopenharmony_cistatic int azx_runtime_suspend(struct device *dev) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct snd_card *card = dev_get_drvdata(dev); 3798c2ecf20Sopenharmony_ci struct azx *chip = card->private_data; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if (chip->disabled) 3828c2ecf20Sopenharmony_ci return 0; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (!azx_has_pm_runtime(chip)) 3858c2ecf20Sopenharmony_ci return 0; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci /* enable controller wake up event */ 3888c2ecf20Sopenharmony_ci azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) | 3898c2ecf20Sopenharmony_ci STATESTS_INT_MASK); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci azx_stop_chip(chip); 3928c2ecf20Sopenharmony_ci azx_enter_link_reset(chip); 3938c2ecf20Sopenharmony_ci azx_clear_irq_pending(chip); 3948c2ecf20Sopenharmony_ci return 0; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic int azx_runtime_resume(struct device *dev) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci struct snd_card *card = dev_get_drvdata(dev); 4008c2ecf20Sopenharmony_ci struct azx *chip = card->private_data; 4018c2ecf20Sopenharmony_ci struct hda_codec *codec; 4028c2ecf20Sopenharmony_ci int status; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (chip->disabled) 4058c2ecf20Sopenharmony_ci return 0; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (!azx_has_pm_runtime(chip)) 4088c2ecf20Sopenharmony_ci return 0; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci /* Read STATESTS before controller reset */ 4118c2ecf20Sopenharmony_ci status = azx_readw(chip, STATESTS); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci azx_init_chip(chip, true); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (status) { 4168c2ecf20Sopenharmony_ci list_for_each_codec(codec, &chip->bus) 4178c2ecf20Sopenharmony_ci if (status & (1 << codec->addr)) 4188c2ecf20Sopenharmony_ci schedule_delayed_work(&codec->jackpoll_work, 4198c2ecf20Sopenharmony_ci codec->jackpoll_interval); 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* disable controller Wake Up event*/ 4238c2ecf20Sopenharmony_ci azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) & 4248c2ecf20Sopenharmony_ci ~STATESTS_INT_MASK); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci return 0; 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cistatic int azx_runtime_idle(struct device *dev) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci struct snd_card *card = dev_get_drvdata(dev); 4328c2ecf20Sopenharmony_ci struct azx *chip = card->private_data; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (chip->disabled) 4358c2ecf20Sopenharmony_ci return 0; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (!power_save_controller || !azx_has_pm_runtime(chip) || 4388c2ecf20Sopenharmony_ci azx_bus(chip)->codec_powered) 4398c2ecf20Sopenharmony_ci return -EBUSY; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci return 0; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 4478c2ecf20Sopenharmony_cistatic const struct dev_pm_ops azx_pm = { 4488c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(azx_suspend, azx_resume) 4498c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, azx_runtime_idle) 4508c2ecf20Sopenharmony_ci}; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci#define AZX_PM_OPS &azx_pm 4538c2ecf20Sopenharmony_ci#else 4548c2ecf20Sopenharmony_ci#define AZX_PM_OPS NULL 4558c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cistatic int azx_probe_continue(struct azx *chip); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci/* 4608c2ecf20Sopenharmony_ci * destructor 4618c2ecf20Sopenharmony_ci */ 4628c2ecf20Sopenharmony_cistatic int azx_free(struct azx *chip) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci struct device *snddev = chip->card->dev; 4658c2ecf20Sopenharmony_ci struct hda_loongson *hda = container_of(chip, struct hda_loongson, chip); 4668c2ecf20Sopenharmony_ci struct hdac_bus *bus = azx_bus(chip); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci if (azx_has_pm_runtime(chip) && chip->running) 4698c2ecf20Sopenharmony_ci pm_runtime_get_noresume(snddev); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci azx_del_card_list(chip); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci complete_all(&hda->probe_wait); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci if (bus->chip_init) { 4768c2ecf20Sopenharmony_ci azx_clear_irq_pending(chip); 4778c2ecf20Sopenharmony_ci azx_stop_all_streams(chip); 4788c2ecf20Sopenharmony_ci azx_stop_chip(chip); 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (bus->irq >= 0) 4828c2ecf20Sopenharmony_ci free_irq(bus->irq, (void*)chip); 4838c2ecf20Sopenharmony_ci if (bus->remap_addr) 4848c2ecf20Sopenharmony_ci iounmap(bus->remap_addr); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci azx_free_stream_pages(chip); 4878c2ecf20Sopenharmony_ci azx_free_streams(chip); 4888c2ecf20Sopenharmony_ci snd_hdac_bus_exit(bus); 4898c2ecf20Sopenharmony_ci kfree(hda); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci return 0; 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic int azx_dev_disconnect(struct snd_device *device) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci struct azx *chip = device->device_data; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci chip->bus.shutdown = 1; 4998c2ecf20Sopenharmony_ci return 0; 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic int azx_dev_free(struct snd_device *device) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci return azx_free(device->device_data); 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci/* 5088c2ecf20Sopenharmony_ci * constructor 5098c2ecf20Sopenharmony_ci */ 5108c2ecf20Sopenharmony_cistatic const struct hda_controller_ops loongson_hda_ops; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic int azx_create(struct snd_card *card, struct pci_dev *pcidev, 5138c2ecf20Sopenharmony_ci struct platform_device *platdev, int dev, 5148c2ecf20Sopenharmony_ci unsigned int driver_caps, struct azx **rchip) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci static struct snd_device_ops ops = { 5178c2ecf20Sopenharmony_ci .dev_disconnect = azx_dev_disconnect, 5188c2ecf20Sopenharmony_ci .dev_free = azx_dev_free, 5198c2ecf20Sopenharmony_ci }; 5208c2ecf20Sopenharmony_ci struct hda_loongson *hda; 5218c2ecf20Sopenharmony_ci struct azx *chip; 5228c2ecf20Sopenharmony_ci int err; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci *rchip = NULL; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci hda = kzalloc(sizeof(*hda), GFP_KERNEL); 5278c2ecf20Sopenharmony_ci if (!hda) { 5288c2ecf20Sopenharmony_ci dev_err(card->dev, "Cannot allocate hda\n"); 5298c2ecf20Sopenharmony_ci return -ENOMEM; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci chip = &hda->chip; 5338c2ecf20Sopenharmony_ci mutex_init(&chip->open_mutex); 5348c2ecf20Sopenharmony_ci chip->card = card; 5358c2ecf20Sopenharmony_ci chip->pci = pcidev; 5368c2ecf20Sopenharmony_ci chip->ops = &loongson_hda_ops; 5378c2ecf20Sopenharmony_ci chip->driver_caps = driver_caps; 5388c2ecf20Sopenharmony_ci chip->driver_type = driver_caps & 0xff; 5398c2ecf20Sopenharmony_ci chip->dev_index = dev; 5408c2ecf20Sopenharmony_ci if (jackpoll_ms[dev] >= 50 && jackpoll_ms[dev] <= 60000) 5418c2ecf20Sopenharmony_ci chip->jackpoll_interval = msecs_to_jiffies(jackpoll_ms[dev]); 5428c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&chip->pcm_list); 5438c2ecf20Sopenharmony_ci INIT_WORK(&hda->irq_pending_work, azx_irq_pending_work); 5448c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&hda->list); 5458c2ecf20Sopenharmony_ci init_completion(&hda->probe_wait); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci chip->get_position[0] = chip->get_position[1] = azx_get_pos_lpib; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci chip->snoop = false; 5508c2ecf20Sopenharmony_ci chip->single_cmd = single_cmd; 5518c2ecf20Sopenharmony_ci azx_bus(chip)->codec_mask = chip->codec_probe_mask = 0xf; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci if (bdl_pos_adj[dev] < 0) { 5548c2ecf20Sopenharmony_ci switch (chip->driver_type) { 5558c2ecf20Sopenharmony_ci case AZX_DRIVER_LS7A: 5568c2ecf20Sopenharmony_ci bdl_pos_adj[dev] = 1; 5578c2ecf20Sopenharmony_ci break; 5588c2ecf20Sopenharmony_ci default: 5598c2ecf20Sopenharmony_ci bdl_pos_adj[dev] = 32; 5608c2ecf20Sopenharmony_ci break; 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci chip->bdl_pos_adj = bdl_pos_adj[dev]; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci err = azx_bus_init(chip, model[dev]); 5668c2ecf20Sopenharmony_ci if (err < 0) { 5678c2ecf20Sopenharmony_ci kfree(hda); 5688c2ecf20Sopenharmony_ci return err; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); 5728c2ecf20Sopenharmony_ci if (err < 0) { 5738c2ecf20Sopenharmony_ci dev_err(card->dev, "Error creating device [card]!\n"); 5748c2ecf20Sopenharmony_ci azx_free(chip); 5758c2ecf20Sopenharmony_ci return err; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci *rchip = chip; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci return 0; 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic int azx_first_init(struct azx *chip) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci int dev = chip->dev_index; 5868c2ecf20Sopenharmony_ci struct snd_card *card = chip->card; 5878c2ecf20Sopenharmony_ci struct hdac_bus *bus = azx_bus(chip); 5888c2ecf20Sopenharmony_ci int err; 5898c2ecf20Sopenharmony_ci unsigned short gcap; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci bus->addr = pci_resource_start(chip->pci, 0); 5928c2ecf20Sopenharmony_ci bus->remap_addr = ioremap(bus->addr, 5938c2ecf20Sopenharmony_ci pci_resource_end(chip->pci, 0) - pci_resource_start(chip->pci, 0) + 1); 5948c2ecf20Sopenharmony_ci if (bus->remap_addr == NULL) { 5958c2ecf20Sopenharmony_ci dev_err(card->dev, "ioremap error\n"); 5968c2ecf20Sopenharmony_ci return -ENXIO; 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci chip->msi = 0; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (azx_acquire_irq(chip, 0) < 0) 6028c2ecf20Sopenharmony_ci return -EBUSY; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci synchronize_irq(bus->irq); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci gcap = azx_readw(chip, GCAP); 6078c2ecf20Sopenharmony_ci dev_dbg(card->dev, "chipset global capabilities = 0x%x\n", gcap); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci /* disable 64bit DMA address on some devices */ 6108c2ecf20Sopenharmony_ci if (chip->driver_caps & AZX_DCAPS_NO_64BIT) { 6118c2ecf20Sopenharmony_ci dev_dbg(card->dev, "Disabling 64bit DMA\n"); 6128c2ecf20Sopenharmony_ci gcap &= ~AZX_GCAP_64OK; 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci /* disable buffer size rounding to 128-byte multiples if supported */ 6168c2ecf20Sopenharmony_ci if (align_buffer_size >= 0) 6178c2ecf20Sopenharmony_ci chip->align_buffer_size = !!align_buffer_size; 6188c2ecf20Sopenharmony_ci else { 6198c2ecf20Sopenharmony_ci if (chip->driver_caps & AZX_DCAPS_NO_ALIGN_BUFSIZE) 6208c2ecf20Sopenharmony_ci chip->align_buffer_size = 0; 6218c2ecf20Sopenharmony_ci else 6228c2ecf20Sopenharmony_ci chip->align_buffer_size = 1; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci /* allow 64bit DMA address if supported by H/W */ 6268c2ecf20Sopenharmony_ci if ((gcap & AZX_GCAP_64OK) && !dma_set_mask(chip->card->dev, DMA_BIT_MASK(64))) 6278c2ecf20Sopenharmony_ci dma_set_coherent_mask(chip->card->dev, DMA_BIT_MASK(64)); 6288c2ecf20Sopenharmony_ci else { 6298c2ecf20Sopenharmony_ci dma_set_mask(chip->card->dev, DMA_BIT_MASK(32)); 6308c2ecf20Sopenharmony_ci dma_set_coherent_mask(chip->card->dev, DMA_BIT_MASK(32)); 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci /* read number of streams from GCAP register instead of using 6348c2ecf20Sopenharmony_ci * hardcoded value 6358c2ecf20Sopenharmony_ci */ 6368c2ecf20Sopenharmony_ci chip->capture_streams = (gcap >> 8) & 0x0f; 6378c2ecf20Sopenharmony_ci chip->playback_streams = (gcap >> 12) & 0x0f; 6388c2ecf20Sopenharmony_ci if (!chip->playback_streams && !chip->capture_streams) { 6398c2ecf20Sopenharmony_ci /* gcap didn't give any info, switching to old method */ 6408c2ecf20Sopenharmony_ci chip->capture_streams = LS7A_NUM_CAPTURE; 6418c2ecf20Sopenharmony_ci chip->playback_streams = LS7A_NUM_PLAYBACK; 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci chip->capture_index_offset = 0; 6448c2ecf20Sopenharmony_ci chip->playback_index_offset = chip->capture_streams; 6458c2ecf20Sopenharmony_ci chip->num_streams = chip->playback_streams + chip->capture_streams; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* initialize streams */ 6488c2ecf20Sopenharmony_ci err = azx_init_streams(chip); 6498c2ecf20Sopenharmony_ci if (err < 0) 6508c2ecf20Sopenharmony_ci return err; 6518c2ecf20Sopenharmony_ci chip->playback_streams = chip->capture_streams = 1; /* Loongson */ 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci err = azx_alloc_stream_pages(chip); 6548c2ecf20Sopenharmony_ci if (err < 0) 6558c2ecf20Sopenharmony_ci return err; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci /* initialize chip */ 6588c2ecf20Sopenharmony_ci azx_init_chip(chip, (probe_only[dev] & 2) == 0); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci /* codec detection */ 6618c2ecf20Sopenharmony_ci if (!azx_bus(chip)->codec_mask) { 6628c2ecf20Sopenharmony_ci dev_err(card->dev, "no codecs found!\n"); 6638c2ecf20Sopenharmony_ci return -ENODEV; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci strcpy(card->driver, "HDA-Loongson"); 6678c2ecf20Sopenharmony_ci strlcpy(card->shortname, driver_short_names[chip->driver_type], 6688c2ecf20Sopenharmony_ci sizeof(card->shortname)); 6698c2ecf20Sopenharmony_ci snprintf(card->longname, sizeof(card->longname), 6708c2ecf20Sopenharmony_ci "%s at 0x%lx irq %i", 6718c2ecf20Sopenharmony_ci card->shortname, bus->addr, bus->irq); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci return 0; 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cistatic const struct hda_controller_ops loongson_hda_ops = { 6778c2ecf20Sopenharmony_ci .position_check = azx_position_check, 6788c2ecf20Sopenharmony_ci}; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci/* number of codec slots for each chipset: 0 = default slots (i.e. 4) */ 6818c2ecf20Sopenharmony_cistatic unsigned int azx_max_codecs[AZX_NUM_DRIVERS] = {}; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_cistatic int azx_probe_continue(struct azx *chip) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci struct hda_loongson *hda = container_of(chip, struct hda_loongson, chip); 6868c2ecf20Sopenharmony_ci int dev = chip->dev_index; 6878c2ecf20Sopenharmony_ci int err; 6888c2ecf20Sopenharmony_ci struct device *snddev = chip->card->dev; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci hda->probe_continued = 1; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci err = azx_first_init(chip); 6938c2ecf20Sopenharmony_ci if (err < 0) 6948c2ecf20Sopenharmony_ci goto out_free; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_HDA_INPUT_BEEP 6978c2ecf20Sopenharmony_ci chip->beep_mode = beep_mode[dev]; 6988c2ecf20Sopenharmony_ci#endif 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci /* create codec instances */ 7018c2ecf20Sopenharmony_ci err = azx_probe_codecs(chip, azx_max_codecs[chip->driver_type]); 7028c2ecf20Sopenharmony_ci if (err < 0) 7038c2ecf20Sopenharmony_ci goto out_free; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci if ((probe_only[dev] & 1) == 0) { 7068c2ecf20Sopenharmony_ci err = azx_codec_configure(chip); 7078c2ecf20Sopenharmony_ci if (err < 0) 7088c2ecf20Sopenharmony_ci goto out_free; 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci err = snd_card_register(chip->card); 7128c2ecf20Sopenharmony_ci if (err < 0) 7138c2ecf20Sopenharmony_ci goto out_free; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci chip->running = 1; 7168c2ecf20Sopenharmony_ci azx_add_card_list(chip); 7178c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 7188c2ecf20Sopenharmony_ci pm_runtime_forbid(snddev); 7198c2ecf20Sopenharmony_ci pm_runtime_set_active(snddev); 7208c2ecf20Sopenharmony_ci#endif 7218c2ecf20Sopenharmony_ci snd_hda_set_power_save(&chip->bus, power_save * 1000); 7228c2ecf20Sopenharmony_ci if (azx_has_pm_runtime(chip)) 7238c2ecf20Sopenharmony_ci pm_runtime_put_noidle(snddev); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ciout_free: 7268c2ecf20Sopenharmony_ci complete_all(&hda->probe_wait); 7278c2ecf20Sopenharmony_ci return err; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_cistatic const struct pci_device_id azx_ids[] = { 7318c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_HDA), 7328c2ecf20Sopenharmony_ci .driver_data = AZX_DRIVER_LS7A | AZX_DCAPS_LS2X_WORKAROUND}, 7338c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_HDMI), 7348c2ecf20Sopenharmony_ci .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_LS2X_WORKAROUND}, 7358c2ecf20Sopenharmony_ci {} 7368c2ecf20Sopenharmony_ci}; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, azx_ids); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_cistatic int azx_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) 7418c2ecf20Sopenharmony_ci{ 7428c2ecf20Sopenharmony_ci int ret; 7438c2ecf20Sopenharmony_ci bool probe_now; 7448c2ecf20Sopenharmony_ci static int dev; 7458c2ecf20Sopenharmony_ci struct snd_card *card; 7468c2ecf20Sopenharmony_ci struct azx *chip; 7478c2ecf20Sopenharmony_ci struct hda_loongson *hda; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci /* Enable device in PCI config */ 7508c2ecf20Sopenharmony_ci ret = pci_enable_device(pdev); 7518c2ecf20Sopenharmony_ci if (ret < 0) { 7528c2ecf20Sopenharmony_ci printk(KERN_ERR "Loongson HDA (%s): Cannot enable PCI device\n", 7538c2ecf20Sopenharmony_ci pci_name(pdev)); 7548c2ecf20Sopenharmony_ci goto out; 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci /* request the mem regions */ 7588c2ecf20Sopenharmony_ci ret = pci_request_region(pdev, 0, "Loongson HDA"); 7598c2ecf20Sopenharmony_ci if (ret < 0) { 7608c2ecf20Sopenharmony_ci printk( KERN_ERR "Loongson HDA (%s): cannot request region 0.\n", 7618c2ecf20Sopenharmony_ci pci_name(pdev)); 7628c2ecf20Sopenharmony_ci goto out; 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci if (dev >= SNDRV_CARDS) 7668c2ecf20Sopenharmony_ci return -ENODEV; 7678c2ecf20Sopenharmony_ci if (!enable[dev]) { 7688c2ecf20Sopenharmony_ci dev++; 7698c2ecf20Sopenharmony_ci return -ENOENT; 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci ret = snd_card_new(&pdev->dev, index[dev], id[dev], THIS_MODULE, 7738c2ecf20Sopenharmony_ci 0, &card); 7748c2ecf20Sopenharmony_ci if (ret < 0) { 7758c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Error creating card!\n"); 7768c2ecf20Sopenharmony_ci return ret; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci ret = azx_create(card, pdev, NULL, dev, pid->driver_data, &chip); 7808c2ecf20Sopenharmony_ci if (ret < 0) 7818c2ecf20Sopenharmony_ci goto out_free; 7828c2ecf20Sopenharmony_ci card->private_data = chip; 7838c2ecf20Sopenharmony_ci hda = container_of(chip, struct hda_loongson, chip); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci dev_set_drvdata(&pdev->dev, card); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci probe_now = !chip->disabled; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci if (probe_now) { 7908c2ecf20Sopenharmony_ci ret = azx_probe_continue(chip); 7918c2ecf20Sopenharmony_ci if (ret < 0) 7928c2ecf20Sopenharmony_ci goto out_free; 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci dev++; 7968c2ecf20Sopenharmony_ci if (chip->disabled) 7978c2ecf20Sopenharmony_ci complete_all(&hda->probe_wait); 7988c2ecf20Sopenharmony_ci return 0; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ciout_free: 8018c2ecf20Sopenharmony_ci snd_card_free(card); 8028c2ecf20Sopenharmony_ciout: 8038c2ecf20Sopenharmony_ci return ret; 8048c2ecf20Sopenharmony_ci} 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_cistatic void azx_pci_remove(struct pci_dev *pdev) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci snd_card_free(dev_get_drvdata(&pdev->dev)); 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_cistatic void azx_pci_shutdown(struct pci_dev *pdev) 8128c2ecf20Sopenharmony_ci{ 8138c2ecf20Sopenharmony_ci struct snd_card *card = dev_get_drvdata(&pdev->dev); 8148c2ecf20Sopenharmony_ci struct azx *chip; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci if (!card) 8178c2ecf20Sopenharmony_ci return; 8188c2ecf20Sopenharmony_ci chip = card->private_data; 8198c2ecf20Sopenharmony_ci if (chip && chip->running) 8208c2ecf20Sopenharmony_ci azx_stop_chip(chip); 8218c2ecf20Sopenharmony_ci} 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci/* pci_driver definition */ 8248c2ecf20Sopenharmony_cistatic struct pci_driver azx_pci_driver = { 8258c2ecf20Sopenharmony_ci .name = "loongson-audio", 8268c2ecf20Sopenharmony_ci .id_table = azx_ids, 8278c2ecf20Sopenharmony_ci .probe = azx_pci_probe, 8288c2ecf20Sopenharmony_ci .remove = azx_pci_remove, 8298c2ecf20Sopenharmony_ci .shutdown = azx_pci_shutdown, 8308c2ecf20Sopenharmony_ci .driver.pm = AZX_PM_OPS, 8318c2ecf20Sopenharmony_ci}; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_cistatic int __init alsa_card_azx_init(void) 8348c2ecf20Sopenharmony_ci{ 8358c2ecf20Sopenharmony_ci int ret; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci ret = pci_register_driver(&azx_pci_driver); 8388c2ecf20Sopenharmony_ci if (ret) 8398c2ecf20Sopenharmony_ci pr_err("hda azx pci driver register\n"); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci return ret; 8428c2ecf20Sopenharmony_ci} 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_cistatic void __exit alsa_card_azx_exit(void) 8458c2ecf20Sopenharmony_ci{ 8468c2ecf20Sopenharmony_ci pci_unregister_driver(&azx_pci_driver); 8478c2ecf20Sopenharmony_ci} 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_cimodule_init(alsa_card_azx_init) 8508c2ecf20Sopenharmony_cimodule_exit(alsa_card_azx_exit) 851