18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Implementation of primary alsa driver code base 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 128c2ecf20Sopenharmony_ci#include <linux/clocksource.h> 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#ifdef CONFIG_X86 218c2ecf20Sopenharmony_ci/* for art-tsc conversion */ 228c2ecf20Sopenharmony_ci#include <asm/tsc.h> 238c2ecf20Sopenharmony_ci#endif 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <sound/core.h> 268c2ecf20Sopenharmony_ci#include <sound/initval.h> 278c2ecf20Sopenharmony_ci#include "hda_controller.h" 288c2ecf20Sopenharmony_ci#include "hda_local.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define CREATE_TRACE_POINTS 318c2ecf20Sopenharmony_ci#include "hda_controller_trace.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* DSP lock helpers */ 348c2ecf20Sopenharmony_ci#define dsp_lock(dev) snd_hdac_dsp_lock(azx_stream(dev)) 358c2ecf20Sopenharmony_ci#define dsp_unlock(dev) snd_hdac_dsp_unlock(azx_stream(dev)) 368c2ecf20Sopenharmony_ci#define dsp_is_locked(dev) snd_hdac_stream_is_locked(azx_stream(dev)) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* assign a stream for the PCM */ 398c2ecf20Sopenharmony_cistatic inline struct azx_dev * 408c2ecf20Sopenharmony_ciazx_assign_device(struct azx *chip, struct snd_pcm_substream *substream) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci struct hdac_stream *s; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci s = snd_hdac_stream_assign(azx_bus(chip), substream); 458c2ecf20Sopenharmony_ci if (!s) 468c2ecf20Sopenharmony_ci return NULL; 478c2ecf20Sopenharmony_ci return stream_to_azx_dev(s); 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* release the assigned stream */ 518c2ecf20Sopenharmony_cistatic inline void azx_release_device(struct azx_dev *azx_dev) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci snd_hdac_stream_release(azx_stream(azx_dev)); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic inline struct hda_pcm_stream * 578c2ecf20Sopenharmony_cito_hda_pcm_stream(struct snd_pcm_substream *substream) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci struct azx_pcm *apcm = snd_pcm_substream_chip(substream); 608c2ecf20Sopenharmony_ci return &apcm->info->stream[substream->stream]; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic u64 azx_adjust_codec_delay(struct snd_pcm_substream *substream, 648c2ecf20Sopenharmony_ci u64 nsec) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci struct azx_pcm *apcm = snd_pcm_substream_chip(substream); 678c2ecf20Sopenharmony_ci struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream); 688c2ecf20Sopenharmony_ci u64 codec_frames, codec_nsecs; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (!hinfo->ops.get_delay) 718c2ecf20Sopenharmony_ci return nsec; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci codec_frames = hinfo->ops.get_delay(hinfo, apcm->codec, substream); 748c2ecf20Sopenharmony_ci codec_nsecs = div_u64(codec_frames * 1000000000LL, 758c2ecf20Sopenharmony_ci substream->runtime->rate); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 788c2ecf20Sopenharmony_ci return nsec + codec_nsecs; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* 848c2ecf20Sopenharmony_ci * PCM ops 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic int azx_pcm_close(struct snd_pcm_substream *substream) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct azx_pcm *apcm = snd_pcm_substream_chip(substream); 908c2ecf20Sopenharmony_ci struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream); 918c2ecf20Sopenharmony_ci struct azx *chip = apcm->chip; 928c2ecf20Sopenharmony_ci struct azx_dev *azx_dev = get_azx_dev(substream); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci trace_azx_pcm_close(chip, azx_dev); 958c2ecf20Sopenharmony_ci mutex_lock(&chip->open_mutex); 968c2ecf20Sopenharmony_ci azx_release_device(azx_dev); 978c2ecf20Sopenharmony_ci if (hinfo->ops.close) 988c2ecf20Sopenharmony_ci hinfo->ops.close(hinfo, apcm->codec, substream); 998c2ecf20Sopenharmony_ci snd_hda_power_down(apcm->codec); 1008c2ecf20Sopenharmony_ci mutex_unlock(&chip->open_mutex); 1018c2ecf20Sopenharmony_ci snd_hda_codec_pcm_put(apcm->info); 1028c2ecf20Sopenharmony_ci return 0; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic int azx_pcm_hw_params(struct snd_pcm_substream *substream, 1068c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci struct azx_pcm *apcm = snd_pcm_substream_chip(substream); 1098c2ecf20Sopenharmony_ci struct azx *chip = apcm->chip; 1108c2ecf20Sopenharmony_ci struct azx_dev *azx_dev = get_azx_dev(substream); 1118c2ecf20Sopenharmony_ci int ret = 0; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci trace_azx_pcm_hw_params(chip, azx_dev); 1148c2ecf20Sopenharmony_ci dsp_lock(azx_dev); 1158c2ecf20Sopenharmony_ci if (dsp_is_locked(azx_dev)) { 1168c2ecf20Sopenharmony_ci ret = -EBUSY; 1178c2ecf20Sopenharmony_ci goto unlock; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci azx_dev->core.bufsize = 0; 1218c2ecf20Sopenharmony_ci azx_dev->core.period_bytes = 0; 1228c2ecf20Sopenharmony_ci azx_dev->core.format_val = 0; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ciunlock: 1258c2ecf20Sopenharmony_ci dsp_unlock(azx_dev); 1268c2ecf20Sopenharmony_ci return ret; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic int azx_pcm_hw_free(struct snd_pcm_substream *substream) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci struct azx_pcm *apcm = snd_pcm_substream_chip(substream); 1328c2ecf20Sopenharmony_ci struct azx_dev *azx_dev = get_azx_dev(substream); 1338c2ecf20Sopenharmony_ci struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* reset BDL address */ 1368c2ecf20Sopenharmony_ci dsp_lock(azx_dev); 1378c2ecf20Sopenharmony_ci if (!dsp_is_locked(azx_dev)) 1388c2ecf20Sopenharmony_ci snd_hdac_stream_cleanup(azx_stream(azx_dev)); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci snd_hda_codec_cleanup(apcm->codec, hinfo, substream); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci azx_stream(azx_dev)->prepared = 0; 1438c2ecf20Sopenharmony_ci dsp_unlock(azx_dev); 1448c2ecf20Sopenharmony_ci return 0; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic int azx_pcm_prepare(struct snd_pcm_substream *substream) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct azx_pcm *apcm = snd_pcm_substream_chip(substream); 1508c2ecf20Sopenharmony_ci struct azx *chip = apcm->chip; 1518c2ecf20Sopenharmony_ci struct azx_dev *azx_dev = get_azx_dev(substream); 1528c2ecf20Sopenharmony_ci struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream); 1538c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 1548c2ecf20Sopenharmony_ci unsigned int format_val, stream_tag; 1558c2ecf20Sopenharmony_ci int err; 1568c2ecf20Sopenharmony_ci struct hda_spdif_out *spdif = 1578c2ecf20Sopenharmony_ci snd_hda_spdif_out_of_nid(apcm->codec, hinfo->nid); 1588c2ecf20Sopenharmony_ci unsigned short ctls = spdif ? spdif->ctls : 0; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci trace_azx_pcm_prepare(chip, azx_dev); 1618c2ecf20Sopenharmony_ci dsp_lock(azx_dev); 1628c2ecf20Sopenharmony_ci if (dsp_is_locked(azx_dev)) { 1638c2ecf20Sopenharmony_ci err = -EBUSY; 1648c2ecf20Sopenharmony_ci goto unlock; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci snd_hdac_stream_reset(azx_stream(azx_dev)); 1688c2ecf20Sopenharmony_ci format_val = snd_hdac_calc_stream_format(runtime->rate, 1698c2ecf20Sopenharmony_ci runtime->channels, 1708c2ecf20Sopenharmony_ci runtime->format, 1718c2ecf20Sopenharmony_ci hinfo->maxbps, 1728c2ecf20Sopenharmony_ci ctls); 1738c2ecf20Sopenharmony_ci if (!format_val) { 1748c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 1758c2ecf20Sopenharmony_ci "invalid format_val, rate=%d, ch=%d, format=%d\n", 1768c2ecf20Sopenharmony_ci runtime->rate, runtime->channels, runtime->format); 1778c2ecf20Sopenharmony_ci err = -EINVAL; 1788c2ecf20Sopenharmony_ci goto unlock; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci err = snd_hdac_stream_set_params(azx_stream(azx_dev), format_val); 1828c2ecf20Sopenharmony_ci if (err < 0) 1838c2ecf20Sopenharmony_ci goto unlock; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci snd_hdac_stream_setup(azx_stream(azx_dev)); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci stream_tag = azx_dev->core.stream_tag; 1888c2ecf20Sopenharmony_ci /* CA-IBG chips need the playback stream starting from 1 */ 1898c2ecf20Sopenharmony_ci if ((chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) && 1908c2ecf20Sopenharmony_ci stream_tag > chip->capture_streams) 1918c2ecf20Sopenharmony_ci stream_tag -= chip->capture_streams; 1928c2ecf20Sopenharmony_ci err = snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag, 1938c2ecf20Sopenharmony_ci azx_dev->core.format_val, substream); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci unlock: 1968c2ecf20Sopenharmony_ci if (!err) 1978c2ecf20Sopenharmony_ci azx_stream(azx_dev)->prepared = 1; 1988c2ecf20Sopenharmony_ci dsp_unlock(azx_dev); 1998c2ecf20Sopenharmony_ci return err; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct azx_pcm *apcm = snd_pcm_substream_chip(substream); 2058c2ecf20Sopenharmony_ci struct azx *chip = apcm->chip; 2068c2ecf20Sopenharmony_ci struct hdac_bus *bus = azx_bus(chip); 2078c2ecf20Sopenharmony_ci struct azx_dev *azx_dev; 2088c2ecf20Sopenharmony_ci struct snd_pcm_substream *s; 2098c2ecf20Sopenharmony_ci struct hdac_stream *hstr; 2108c2ecf20Sopenharmony_ci bool start; 2118c2ecf20Sopenharmony_ci int sbits = 0; 2128c2ecf20Sopenharmony_ci int sync_reg; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci azx_dev = get_azx_dev(substream); 2158c2ecf20Sopenharmony_ci trace_azx_pcm_trigger(chip, azx_dev, cmd); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci hstr = azx_stream(azx_dev); 2188c2ecf20Sopenharmony_ci if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC) 2198c2ecf20Sopenharmony_ci sync_reg = AZX_REG_OLD_SSYNC; 2208c2ecf20Sopenharmony_ci else 2218c2ecf20Sopenharmony_ci sync_reg = AZX_REG_SSYNC; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (dsp_is_locked(azx_dev) || !hstr->prepared) 2248c2ecf20Sopenharmony_ci return -EPIPE; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci switch (cmd) { 2278c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 2288c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 2298c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 2308c2ecf20Sopenharmony_ci start = true; 2318c2ecf20Sopenharmony_ci break; 2328c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 2338c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 2348c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 2358c2ecf20Sopenharmony_ci start = false; 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci default: 2388c2ecf20Sopenharmony_ci return -EINVAL; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci snd_pcm_group_for_each_entry(s, substream) { 2428c2ecf20Sopenharmony_ci if (s->pcm->card != substream->pcm->card) 2438c2ecf20Sopenharmony_ci continue; 2448c2ecf20Sopenharmony_ci azx_dev = get_azx_dev(s); 2458c2ecf20Sopenharmony_ci sbits |= 1 << azx_dev->core.index; 2468c2ecf20Sopenharmony_ci snd_pcm_trigger_done(s, substream); 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci spin_lock(&bus->reg_lock); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* first, set SYNC bits of corresponding streams */ 2528c2ecf20Sopenharmony_ci snd_hdac_stream_sync_trigger(hstr, true, sbits, sync_reg); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci snd_pcm_group_for_each_entry(s, substream) { 2558c2ecf20Sopenharmony_ci if (s->pcm->card != substream->pcm->card) 2568c2ecf20Sopenharmony_ci continue; 2578c2ecf20Sopenharmony_ci azx_dev = get_azx_dev(s); 2588c2ecf20Sopenharmony_ci if (start) { 2598c2ecf20Sopenharmony_ci azx_dev->insufficient = 1; 2608c2ecf20Sopenharmony_ci snd_hdac_stream_start(azx_stream(azx_dev), true); 2618c2ecf20Sopenharmony_ci } else { 2628c2ecf20Sopenharmony_ci snd_hdac_stream_stop(azx_stream(azx_dev)); 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci spin_unlock(&bus->reg_lock); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci snd_hdac_stream_sync(hstr, start, sbits); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci spin_lock(&bus->reg_lock); 2708c2ecf20Sopenharmony_ci /* reset SYNC bits */ 2718c2ecf20Sopenharmony_ci snd_hdac_stream_sync_trigger(hstr, false, sbits, sync_reg); 2728c2ecf20Sopenharmony_ci if (start) 2738c2ecf20Sopenharmony_ci snd_hdac_stream_timecounter_init(hstr, sbits); 2748c2ecf20Sopenharmony_ci spin_unlock(&bus->reg_lock); 2758c2ecf20Sopenharmony_ci return 0; 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ciunsigned int azx_get_pos_lpib(struct azx *chip, struct azx_dev *azx_dev) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci return snd_hdac_stream_get_pos_lpib(azx_stream(azx_dev)); 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_get_pos_lpib); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ciunsigned int azx_get_pos_posbuf(struct azx *chip, struct azx_dev *azx_dev) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci return snd_hdac_stream_get_pos_posbuf(azx_stream(azx_dev)); 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_get_pos_posbuf); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ciunsigned int azx_get_position(struct azx *chip, 2918c2ecf20Sopenharmony_ci struct azx_dev *azx_dev) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream = azx_dev->core.substream; 2948c2ecf20Sopenharmony_ci unsigned int pos; 2958c2ecf20Sopenharmony_ci int stream = substream->stream; 2968c2ecf20Sopenharmony_ci int delay = 0; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (chip->driver_caps & AZX_DCAPS_LS2X_WORKAROUND) { 2998c2ecf20Sopenharmony_ci pos = chip->get_position[stream](chip, azx_dev); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (pos >= azx_dev->fix_prvpos) { 3028c2ecf20Sopenharmony_ci pos = pos - azx_dev->fix_prvpos; 3038c2ecf20Sopenharmony_ci pos %= azx_dev->core.bufsize; 3048c2ecf20Sopenharmony_ci } else { 3058c2ecf20Sopenharmony_ci if (azx_dev->fix_prvpos > azx_dev->core.bufsize) 3068c2ecf20Sopenharmony_ci pos = (0x100000000ULL + pos-azx_dev->fix_prvpos) 3078c2ecf20Sopenharmony_ci % azx_dev->core.bufsize; 3088c2ecf20Sopenharmony_ci else 3098c2ecf20Sopenharmony_ci pos = pos + azx_dev->core.bufsize - azx_dev->fix_prvpos; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci return pos; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (chip->get_position[stream]) 3168c2ecf20Sopenharmony_ci pos = chip->get_position[stream](chip, azx_dev); 3178c2ecf20Sopenharmony_ci else /* use the position buffer as default */ 3188c2ecf20Sopenharmony_ci pos = azx_get_pos_posbuf(chip, azx_dev); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (pos >= azx_dev->core.bufsize) 3218c2ecf20Sopenharmony_ci pos = 0; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci if (substream->runtime) { 3248c2ecf20Sopenharmony_ci struct azx_pcm *apcm = snd_pcm_substream_chip(substream); 3258c2ecf20Sopenharmony_ci struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (chip->get_delay[stream]) 3288c2ecf20Sopenharmony_ci delay += chip->get_delay[stream](chip, azx_dev, pos); 3298c2ecf20Sopenharmony_ci if (hinfo->ops.get_delay) 3308c2ecf20Sopenharmony_ci delay += hinfo->ops.get_delay(hinfo, apcm->codec, 3318c2ecf20Sopenharmony_ci substream); 3328c2ecf20Sopenharmony_ci substream->runtime->delay = delay; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci trace_azx_get_position(chip, azx_dev, pos, delay); 3368c2ecf20Sopenharmony_ci return pos; 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_get_position); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci struct azx_pcm *apcm = snd_pcm_substream_chip(substream); 3438c2ecf20Sopenharmony_ci struct azx *chip = apcm->chip; 3448c2ecf20Sopenharmony_ci struct azx_dev *azx_dev = get_azx_dev(substream); 3458c2ecf20Sopenharmony_ci return bytes_to_frames(substream->runtime, 3468c2ecf20Sopenharmony_ci azx_get_position(chip, azx_dev)); 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci/* 3508c2ecf20Sopenharmony_ci * azx_scale64: Scale base by mult/div while not overflowing sanely 3518c2ecf20Sopenharmony_ci * 3528c2ecf20Sopenharmony_ci * Derived from scale64_check_overflow in kernel/time/timekeeping.c 3538c2ecf20Sopenharmony_ci * 3548c2ecf20Sopenharmony_ci * The tmestamps for a 48Khz stream can overflow after (2^64/10^9)/48K which 3558c2ecf20Sopenharmony_ci * is about 384307 ie ~4.5 days. 3568c2ecf20Sopenharmony_ci * 3578c2ecf20Sopenharmony_ci * This scales the calculation so that overflow will happen but after 2^64 / 3588c2ecf20Sopenharmony_ci * 48000 secs, which is pretty large! 3598c2ecf20Sopenharmony_ci * 3608c2ecf20Sopenharmony_ci * In caln below: 3618c2ecf20Sopenharmony_ci * base may overflow, but since there isn’t any additional division 3628c2ecf20Sopenharmony_ci * performed on base it’s OK 3638c2ecf20Sopenharmony_ci * rem can’t overflow because both are 32-bit values 3648c2ecf20Sopenharmony_ci */ 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci#ifdef CONFIG_X86 3678c2ecf20Sopenharmony_cistatic u64 azx_scale64(u64 base, u32 num, u32 den) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci u64 rem; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci rem = do_div(base, den); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci base *= num; 3748c2ecf20Sopenharmony_ci rem *= num; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci do_div(rem, den); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci return base + rem; 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic int azx_get_sync_time(ktime_t *device, 3828c2ecf20Sopenharmony_ci struct system_counterval_t *system, void *ctx) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream = ctx; 3858c2ecf20Sopenharmony_ci struct azx_dev *azx_dev = get_azx_dev(substream); 3868c2ecf20Sopenharmony_ci struct azx_pcm *apcm = snd_pcm_substream_chip(substream); 3878c2ecf20Sopenharmony_ci struct azx *chip = apcm->chip; 3888c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime; 3898c2ecf20Sopenharmony_ci u64 ll_counter, ll_counter_l, ll_counter_h; 3908c2ecf20Sopenharmony_ci u64 tsc_counter, tsc_counter_l, tsc_counter_h; 3918c2ecf20Sopenharmony_ci u32 wallclk_ctr, wallclk_cycles; 3928c2ecf20Sopenharmony_ci bool direction; 3938c2ecf20Sopenharmony_ci u32 dma_select; 3948c2ecf20Sopenharmony_ci u32 timeout; 3958c2ecf20Sopenharmony_ci u32 retry_count = 0; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci runtime = substream->runtime; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 4008c2ecf20Sopenharmony_ci direction = 1; 4018c2ecf20Sopenharmony_ci else 4028c2ecf20Sopenharmony_ci direction = 0; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci /* 0th stream tag is not used, so DMA ch 0 is for 1st stream tag */ 4058c2ecf20Sopenharmony_ci do { 4068c2ecf20Sopenharmony_ci timeout = 100; 4078c2ecf20Sopenharmony_ci dma_select = (direction << GTSCC_CDMAS_DMA_DIR_SHIFT) | 4088c2ecf20Sopenharmony_ci (azx_dev->core.stream_tag - 1); 4098c2ecf20Sopenharmony_ci snd_hdac_chip_writel(azx_bus(chip), GTSCC, dma_select); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci /* Enable the capture */ 4128c2ecf20Sopenharmony_ci snd_hdac_chip_updatel(azx_bus(chip), GTSCC, 0, GTSCC_TSCCI_MASK); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci while (timeout) { 4158c2ecf20Sopenharmony_ci if (snd_hdac_chip_readl(azx_bus(chip), GTSCC) & 4168c2ecf20Sopenharmony_ci GTSCC_TSCCD_MASK) 4178c2ecf20Sopenharmony_ci break; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci timeout--; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci if (!timeout) { 4238c2ecf20Sopenharmony_ci dev_err(chip->card->dev, "GTSCC capture Timedout!\n"); 4248c2ecf20Sopenharmony_ci return -EIO; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* Read wall clock counter */ 4288c2ecf20Sopenharmony_ci wallclk_ctr = snd_hdac_chip_readl(azx_bus(chip), WALFCC); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci /* Read TSC counter */ 4318c2ecf20Sopenharmony_ci tsc_counter_l = snd_hdac_chip_readl(azx_bus(chip), TSCCL); 4328c2ecf20Sopenharmony_ci tsc_counter_h = snd_hdac_chip_readl(azx_bus(chip), TSCCU); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci /* Read Link counter */ 4358c2ecf20Sopenharmony_ci ll_counter_l = snd_hdac_chip_readl(azx_bus(chip), LLPCL); 4368c2ecf20Sopenharmony_ci ll_counter_h = snd_hdac_chip_readl(azx_bus(chip), LLPCU); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* Ack: registers read done */ 4398c2ecf20Sopenharmony_ci snd_hdac_chip_writel(azx_bus(chip), GTSCC, GTSCC_TSCCD_SHIFT); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci tsc_counter = (tsc_counter_h << TSCCU_CCU_SHIFT) | 4428c2ecf20Sopenharmony_ci tsc_counter_l; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci ll_counter = (ll_counter_h << LLPC_CCU_SHIFT) | ll_counter_l; 4458c2ecf20Sopenharmony_ci wallclk_cycles = wallclk_ctr & WALFCC_CIF_MASK; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci /* 4488c2ecf20Sopenharmony_ci * An error occurs near frame "rollover". The clocks in 4498c2ecf20Sopenharmony_ci * frame value indicates whether this error may have 4508c2ecf20Sopenharmony_ci * occurred. Here we use the value of 10 i.e., 4518c2ecf20Sopenharmony_ci * HDA_MAX_CYCLE_OFFSET 4528c2ecf20Sopenharmony_ci */ 4538c2ecf20Sopenharmony_ci if (wallclk_cycles < HDA_MAX_CYCLE_VALUE - HDA_MAX_CYCLE_OFFSET 4548c2ecf20Sopenharmony_ci && wallclk_cycles > HDA_MAX_CYCLE_OFFSET) 4558c2ecf20Sopenharmony_ci break; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* 4588c2ecf20Sopenharmony_ci * Sleep before we read again, else we may again get 4598c2ecf20Sopenharmony_ci * value near to MAX_CYCLE. Try to sleep for different 4608c2ecf20Sopenharmony_ci * amount of time so we dont hit the same number again 4618c2ecf20Sopenharmony_ci */ 4628c2ecf20Sopenharmony_ci udelay(retry_count++); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci } while (retry_count != HDA_MAX_CYCLE_READ_RETRY); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (retry_count == HDA_MAX_CYCLE_READ_RETRY) { 4678c2ecf20Sopenharmony_ci dev_err_ratelimited(chip->card->dev, 4688c2ecf20Sopenharmony_ci "Error in WALFCC cycle count\n"); 4698c2ecf20Sopenharmony_ci return -EIO; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci *device = ns_to_ktime(azx_scale64(ll_counter, 4738c2ecf20Sopenharmony_ci NSEC_PER_SEC, runtime->rate)); 4748c2ecf20Sopenharmony_ci *device = ktime_add_ns(*device, (wallclk_cycles * NSEC_PER_SEC) / 4758c2ecf20Sopenharmony_ci ((HDA_MAX_CYCLE_VALUE + 1) * runtime->rate)); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci *system = convert_art_to_tsc(tsc_counter); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci return 0; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci#else 4838c2ecf20Sopenharmony_cistatic int azx_get_sync_time(ktime_t *device, 4848c2ecf20Sopenharmony_ci struct system_counterval_t *system, void *ctx) 4858c2ecf20Sopenharmony_ci{ 4868c2ecf20Sopenharmony_ci return -ENXIO; 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci#endif 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic int azx_get_crosststamp(struct snd_pcm_substream *substream, 4918c2ecf20Sopenharmony_ci struct system_device_crosststamp *xtstamp) 4928c2ecf20Sopenharmony_ci{ 4938c2ecf20Sopenharmony_ci return get_device_system_crosststamp(azx_get_sync_time, 4948c2ecf20Sopenharmony_ci substream, NULL, xtstamp); 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic inline bool is_link_time_supported(struct snd_pcm_runtime *runtime, 4988c2ecf20Sopenharmony_ci struct snd_pcm_audio_tstamp_config *ts) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci if (runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME) 5018c2ecf20Sopenharmony_ci if (ts->type_requested == SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED) 5028c2ecf20Sopenharmony_ci return true; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci return false; 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cistatic int azx_get_time_info(struct snd_pcm_substream *substream, 5088c2ecf20Sopenharmony_ci struct timespec64 *system_ts, struct timespec64 *audio_ts, 5098c2ecf20Sopenharmony_ci struct snd_pcm_audio_tstamp_config *audio_tstamp_config, 5108c2ecf20Sopenharmony_ci struct snd_pcm_audio_tstamp_report *audio_tstamp_report) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci struct azx_dev *azx_dev = get_azx_dev(substream); 5138c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 5148c2ecf20Sopenharmony_ci struct system_device_crosststamp xtstamp; 5158c2ecf20Sopenharmony_ci int ret; 5168c2ecf20Sopenharmony_ci u64 nsec; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if ((substream->runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_ATIME) && 5198c2ecf20Sopenharmony_ci (audio_tstamp_config->type_requested == SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK)) { 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci snd_pcm_gettime(substream->runtime, system_ts); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci nsec = timecounter_read(&azx_dev->core.tc); 5248c2ecf20Sopenharmony_ci nsec = div_u64(nsec, 3); /* can be optimized */ 5258c2ecf20Sopenharmony_ci if (audio_tstamp_config->report_delay) 5268c2ecf20Sopenharmony_ci nsec = azx_adjust_codec_delay(substream, nsec); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci *audio_ts = ns_to_timespec64(nsec); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK; 5318c2ecf20Sopenharmony_ci audio_tstamp_report->accuracy_report = 1; /* rest of structure is valid */ 5328c2ecf20Sopenharmony_ci audio_tstamp_report->accuracy = 42; /* 24 MHz WallClock == 42ns resolution */ 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci } else if (is_link_time_supported(runtime, audio_tstamp_config)) { 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci ret = azx_get_crosststamp(substream, &xtstamp); 5378c2ecf20Sopenharmony_ci if (ret) 5388c2ecf20Sopenharmony_ci return ret; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci switch (runtime->tstamp_type) { 5418c2ecf20Sopenharmony_ci case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC: 5428c2ecf20Sopenharmony_ci return -EINVAL; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW: 5458c2ecf20Sopenharmony_ci *system_ts = ktime_to_timespec64(xtstamp.sys_monoraw); 5468c2ecf20Sopenharmony_ci break; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci default: 5498c2ecf20Sopenharmony_ci *system_ts = ktime_to_timespec64(xtstamp.sys_realtime); 5508c2ecf20Sopenharmony_ci break; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci *audio_ts = ktime_to_timespec64(xtstamp.device); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci audio_tstamp_report->actual_type = 5578c2ecf20Sopenharmony_ci SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED; 5588c2ecf20Sopenharmony_ci audio_tstamp_report->accuracy_report = 1; 5598c2ecf20Sopenharmony_ci /* 24 MHz WallClock == 42ns resolution */ 5608c2ecf20Sopenharmony_ci audio_tstamp_report->accuracy = 42; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci } else { 5638c2ecf20Sopenharmony_ci audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT; 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci return 0; 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware azx_pcm_hw = { 5708c2ecf20Sopenharmony_ci .info = (SNDRV_PCM_INFO_MMAP | 5718c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_INTERLEAVED | 5728c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | 5738c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 5748c2ecf20Sopenharmony_ci /* No full-resume yet implemented */ 5758c2ecf20Sopenharmony_ci /* SNDRV_PCM_INFO_RESUME |*/ 5768c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_PAUSE | 5778c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_SYNC_START | 5788c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */ 5798c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_HAS_LINK_ATIME | 5808c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), 5818c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 5828c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000, 5838c2ecf20Sopenharmony_ci .rate_min = 48000, 5848c2ecf20Sopenharmony_ci .rate_max = 48000, 5858c2ecf20Sopenharmony_ci .channels_min = 2, 5868c2ecf20Sopenharmony_ci .channels_max = 2, 5878c2ecf20Sopenharmony_ci .buffer_bytes_max = AZX_MAX_BUF_SIZE, 5888c2ecf20Sopenharmony_ci .period_bytes_min = 128, 5898c2ecf20Sopenharmony_ci .period_bytes_max = AZX_MAX_BUF_SIZE / 2, 5908c2ecf20Sopenharmony_ci .periods_min = 2, 5918c2ecf20Sopenharmony_ci .periods_max = AZX_MAX_FRAG, 5928c2ecf20Sopenharmony_ci .fifo_size = 0, 5938c2ecf20Sopenharmony_ci}; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_cistatic int azx_pcm_open(struct snd_pcm_substream *substream) 5968c2ecf20Sopenharmony_ci{ 5978c2ecf20Sopenharmony_ci struct azx_pcm *apcm = snd_pcm_substream_chip(substream); 5988c2ecf20Sopenharmony_ci struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream); 5998c2ecf20Sopenharmony_ci struct azx *chip = apcm->chip; 6008c2ecf20Sopenharmony_ci struct azx_dev *azx_dev; 6018c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 6028c2ecf20Sopenharmony_ci int err; 6038c2ecf20Sopenharmony_ci int buff_step; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci snd_hda_codec_pcm_get(apcm->info); 6068c2ecf20Sopenharmony_ci mutex_lock(&chip->open_mutex); 6078c2ecf20Sopenharmony_ci azx_dev = azx_assign_device(chip, substream); 6088c2ecf20Sopenharmony_ci trace_azx_pcm_open(chip, azx_dev); 6098c2ecf20Sopenharmony_ci if (azx_dev == NULL) { 6108c2ecf20Sopenharmony_ci err = -EBUSY; 6118c2ecf20Sopenharmony_ci goto unlock; 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci runtime->private_data = azx_dev; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci runtime->hw = azx_pcm_hw; 6168c2ecf20Sopenharmony_ci if (chip->gts_present) 6178c2ecf20Sopenharmony_ci runtime->hw.info |= SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME; 6188c2ecf20Sopenharmony_ci runtime->hw.channels_min = hinfo->channels_min; 6198c2ecf20Sopenharmony_ci runtime->hw.channels_max = hinfo->channels_max; 6208c2ecf20Sopenharmony_ci runtime->hw.formats = hinfo->formats; 6218c2ecf20Sopenharmony_ci runtime->hw.rates = hinfo->rates; 6228c2ecf20Sopenharmony_ci snd_pcm_limit_hw_rates(runtime); 6238c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci /* avoid wrap-around with wall-clock */ 6268c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, 6278c2ecf20Sopenharmony_ci 20, 6288c2ecf20Sopenharmony_ci 178000000); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci if (chip->align_buffer_size) 6318c2ecf20Sopenharmony_ci /* constrain buffer sizes to be multiple of 128 6328c2ecf20Sopenharmony_ci bytes. This is more efficient in terms of memory 6338c2ecf20Sopenharmony_ci access but isn't required by the HDA spec and 6348c2ecf20Sopenharmony_ci prevents users from specifying exact period/buffer 6358c2ecf20Sopenharmony_ci sizes. For example for 44.1kHz, a period size set 6368c2ecf20Sopenharmony_ci to 20ms will be rounded to 19.59ms. */ 6378c2ecf20Sopenharmony_ci buff_step = 128; 6388c2ecf20Sopenharmony_ci else 6398c2ecf20Sopenharmony_ci /* Don't enforce steps on buffer sizes, still need to 6408c2ecf20Sopenharmony_ci be multiple of 4 bytes (HDA spec). Tested on Intel 6418c2ecf20Sopenharmony_ci HDA controllers, may not work on all devices where 6428c2ecf20Sopenharmony_ci option needs to be disabled */ 6438c2ecf20Sopenharmony_ci buff_step = 4; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 6468c2ecf20Sopenharmony_ci buff_step); 6478c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 6488c2ecf20Sopenharmony_ci buff_step); 6498c2ecf20Sopenharmony_ci snd_hda_power_up(apcm->codec); 6508c2ecf20Sopenharmony_ci if (hinfo->ops.open) 6518c2ecf20Sopenharmony_ci err = hinfo->ops.open(hinfo, apcm->codec, substream); 6528c2ecf20Sopenharmony_ci else 6538c2ecf20Sopenharmony_ci err = -ENODEV; 6548c2ecf20Sopenharmony_ci if (err < 0) { 6558c2ecf20Sopenharmony_ci azx_release_device(azx_dev); 6568c2ecf20Sopenharmony_ci goto powerdown; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci snd_pcm_limit_hw_rates(runtime); 6598c2ecf20Sopenharmony_ci /* sanity check */ 6608c2ecf20Sopenharmony_ci if (snd_BUG_ON(!runtime->hw.channels_min) || 6618c2ecf20Sopenharmony_ci snd_BUG_ON(!runtime->hw.channels_max) || 6628c2ecf20Sopenharmony_ci snd_BUG_ON(!runtime->hw.formats) || 6638c2ecf20Sopenharmony_ci snd_BUG_ON(!runtime->hw.rates)) { 6648c2ecf20Sopenharmony_ci azx_release_device(azx_dev); 6658c2ecf20Sopenharmony_ci if (hinfo->ops.close) 6668c2ecf20Sopenharmony_ci hinfo->ops.close(hinfo, apcm->codec, substream); 6678c2ecf20Sopenharmony_ci err = -EINVAL; 6688c2ecf20Sopenharmony_ci goto powerdown; 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci /* disable LINK_ATIME timestamps for capture streams 6728c2ecf20Sopenharmony_ci until we figure out how to handle digital inputs */ 6738c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 6748c2ecf20Sopenharmony_ci runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK; /* legacy */ 6758c2ecf20Sopenharmony_ci runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_LINK_ATIME; 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci snd_pcm_set_sync(substream); 6798c2ecf20Sopenharmony_ci mutex_unlock(&chip->open_mutex); 6808c2ecf20Sopenharmony_ci return 0; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci powerdown: 6838c2ecf20Sopenharmony_ci snd_hda_power_down(apcm->codec); 6848c2ecf20Sopenharmony_ci unlock: 6858c2ecf20Sopenharmony_ci mutex_unlock(&chip->open_mutex); 6868c2ecf20Sopenharmony_ci snd_hda_codec_pcm_put(apcm->info); 6878c2ecf20Sopenharmony_ci return err; 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_cistatic int azx_pcm_mmap(struct snd_pcm_substream *substream, 6918c2ecf20Sopenharmony_ci struct vm_area_struct *area) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci struct azx_pcm *apcm = snd_pcm_substream_chip(substream); 6948c2ecf20Sopenharmony_ci struct azx *chip = apcm->chip; 6958c2ecf20Sopenharmony_ci if (chip->ops->pcm_mmap_prepare) 6968c2ecf20Sopenharmony_ci chip->ops->pcm_mmap_prepare(substream, area); 6978c2ecf20Sopenharmony_ci return snd_pcm_lib_default_mmap(substream, area); 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops azx_pcm_ops = { 7018c2ecf20Sopenharmony_ci .open = azx_pcm_open, 7028c2ecf20Sopenharmony_ci .close = azx_pcm_close, 7038c2ecf20Sopenharmony_ci .hw_params = azx_pcm_hw_params, 7048c2ecf20Sopenharmony_ci .hw_free = azx_pcm_hw_free, 7058c2ecf20Sopenharmony_ci .prepare = azx_pcm_prepare, 7068c2ecf20Sopenharmony_ci .trigger = azx_pcm_trigger, 7078c2ecf20Sopenharmony_ci .pointer = azx_pcm_pointer, 7088c2ecf20Sopenharmony_ci .get_time_info = azx_get_time_info, 7098c2ecf20Sopenharmony_ci .mmap = azx_pcm_mmap, 7108c2ecf20Sopenharmony_ci}; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_cistatic void azx_pcm_free(struct snd_pcm *pcm) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci struct azx_pcm *apcm = pcm->private_data; 7158c2ecf20Sopenharmony_ci if (apcm) { 7168c2ecf20Sopenharmony_ci list_del(&apcm->list); 7178c2ecf20Sopenharmony_ci apcm->info->pcm = NULL; 7188c2ecf20Sopenharmony_ci kfree(apcm); 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci#define MAX_PREALLOC_SIZE (32 * 1024 * 1024) 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ciint snd_hda_attach_pcm_stream(struct hda_bus *_bus, struct hda_codec *codec, 7258c2ecf20Sopenharmony_ci struct hda_pcm *cpcm) 7268c2ecf20Sopenharmony_ci{ 7278c2ecf20Sopenharmony_ci struct hdac_bus *bus = &_bus->core; 7288c2ecf20Sopenharmony_ci struct azx *chip = bus_to_azx(bus); 7298c2ecf20Sopenharmony_ci struct snd_pcm *pcm; 7308c2ecf20Sopenharmony_ci struct azx_pcm *apcm; 7318c2ecf20Sopenharmony_ci int pcm_dev = cpcm->device; 7328c2ecf20Sopenharmony_ci unsigned int size; 7338c2ecf20Sopenharmony_ci int s, err; 7348c2ecf20Sopenharmony_ci int type = SNDRV_DMA_TYPE_DEV_SG; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci list_for_each_entry(apcm, &chip->pcm_list, list) { 7378c2ecf20Sopenharmony_ci if (apcm->pcm->device == pcm_dev) { 7388c2ecf20Sopenharmony_ci dev_err(chip->card->dev, "PCM %d already exists\n", 7398c2ecf20Sopenharmony_ci pcm_dev); 7408c2ecf20Sopenharmony_ci return -EBUSY; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci err = snd_pcm_new(chip->card, cpcm->name, pcm_dev, 7448c2ecf20Sopenharmony_ci cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams, 7458c2ecf20Sopenharmony_ci cpcm->stream[SNDRV_PCM_STREAM_CAPTURE].substreams, 7468c2ecf20Sopenharmony_ci &pcm); 7478c2ecf20Sopenharmony_ci if (err < 0) 7488c2ecf20Sopenharmony_ci return err; 7498c2ecf20Sopenharmony_ci strlcpy(pcm->name, cpcm->name, sizeof(pcm->name)); 7508c2ecf20Sopenharmony_ci apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); 7518c2ecf20Sopenharmony_ci if (apcm == NULL) { 7528c2ecf20Sopenharmony_ci snd_device_free(chip->card, pcm); 7538c2ecf20Sopenharmony_ci return -ENOMEM; 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci apcm->chip = chip; 7568c2ecf20Sopenharmony_ci apcm->pcm = pcm; 7578c2ecf20Sopenharmony_ci apcm->codec = codec; 7588c2ecf20Sopenharmony_ci apcm->info = cpcm; 7598c2ecf20Sopenharmony_ci pcm->private_data = apcm; 7608c2ecf20Sopenharmony_ci pcm->private_free = azx_pcm_free; 7618c2ecf20Sopenharmony_ci if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM) 7628c2ecf20Sopenharmony_ci pcm->dev_class = SNDRV_PCM_CLASS_MODEM; 7638c2ecf20Sopenharmony_ci list_add_tail(&apcm->list, &chip->pcm_list); 7648c2ecf20Sopenharmony_ci cpcm->pcm = pcm; 7658c2ecf20Sopenharmony_ci for (s = 0; s < 2; s++) { 7668c2ecf20Sopenharmony_ci if (cpcm->stream[s].substreams) 7678c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, s, &azx_pcm_ops); 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci /* buffer pre-allocation */ 7708c2ecf20Sopenharmony_ci size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024; 7718c2ecf20Sopenharmony_ci if (size > MAX_PREALLOC_SIZE) 7728c2ecf20Sopenharmony_ci size = MAX_PREALLOC_SIZE; 7738c2ecf20Sopenharmony_ci if (chip->uc_buffer) 7748c2ecf20Sopenharmony_ci type = SNDRV_DMA_TYPE_DEV_UC_SG; 7758c2ecf20Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, type, chip->card->dev, 7768c2ecf20Sopenharmony_ci size, MAX_PREALLOC_SIZE); 7778c2ecf20Sopenharmony_ci return 0; 7788c2ecf20Sopenharmony_ci} 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_cistatic unsigned int azx_command_addr(u32 cmd) 7818c2ecf20Sopenharmony_ci{ 7828c2ecf20Sopenharmony_ci unsigned int addr = cmd >> 28; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci if (addr >= AZX_MAX_CODECS) { 7858c2ecf20Sopenharmony_ci snd_BUG(); 7868c2ecf20Sopenharmony_ci addr = 0; 7878c2ecf20Sopenharmony_ci } 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci return addr; 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci/* receive a response */ 7938c2ecf20Sopenharmony_cistatic int azx_rirb_get_response(struct hdac_bus *bus, unsigned int addr, 7948c2ecf20Sopenharmony_ci unsigned int *res) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci struct azx *chip = bus_to_azx(bus); 7978c2ecf20Sopenharmony_ci struct hda_bus *hbus = &chip->bus; 7988c2ecf20Sopenharmony_ci int err; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci again: 8018c2ecf20Sopenharmony_ci err = snd_hdac_bus_get_response(bus, addr, res); 8028c2ecf20Sopenharmony_ci if (!err) 8038c2ecf20Sopenharmony_ci return 0; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci if (hbus->no_response_fallback) 8068c2ecf20Sopenharmony_ci return -EIO; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci if (!bus->polling_mode) { 8098c2ecf20Sopenharmony_ci dev_warn(chip->card->dev, 8108c2ecf20Sopenharmony_ci "azx_get_response timeout, switching to polling mode: last cmd=0x%08x\n", 8118c2ecf20Sopenharmony_ci bus->last_cmd[addr]); 8128c2ecf20Sopenharmony_ci bus->polling_mode = 1; 8138c2ecf20Sopenharmony_ci goto again; 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci if (chip->msi) { 8178c2ecf20Sopenharmony_ci dev_warn(chip->card->dev, 8188c2ecf20Sopenharmony_ci "No response from codec, disabling MSI: last cmd=0x%08x\n", 8198c2ecf20Sopenharmony_ci bus->last_cmd[addr]); 8208c2ecf20Sopenharmony_ci if (chip->ops->disable_msi_reset_irq && 8218c2ecf20Sopenharmony_ci chip->ops->disable_msi_reset_irq(chip) < 0) 8228c2ecf20Sopenharmony_ci return -EIO; 8238c2ecf20Sopenharmony_ci goto again; 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci if (chip->probing) { 8278c2ecf20Sopenharmony_ci /* If this critical timeout happens during the codec probing 8288c2ecf20Sopenharmony_ci * phase, this is likely an access to a non-existing codec 8298c2ecf20Sopenharmony_ci * slot. Better to return an error and reset the system. 8308c2ecf20Sopenharmony_ci */ 8318c2ecf20Sopenharmony_ci return -EIO; 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci /* no fallback mechanism? */ 8358c2ecf20Sopenharmony_ci if (!chip->fallback_to_single_cmd) 8368c2ecf20Sopenharmony_ci return -EIO; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci /* a fatal communication error; need either to reset or to fallback 8398c2ecf20Sopenharmony_ci * to the single_cmd mode 8408c2ecf20Sopenharmony_ci */ 8418c2ecf20Sopenharmony_ci if (hbus->allow_bus_reset && !hbus->response_reset && !hbus->in_reset) { 8428c2ecf20Sopenharmony_ci hbus->response_reset = 1; 8438c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 8448c2ecf20Sopenharmony_ci "No response from codec, resetting bus: last cmd=0x%08x\n", 8458c2ecf20Sopenharmony_ci bus->last_cmd[addr]); 8468c2ecf20Sopenharmony_ci return -EAGAIN; /* give a chance to retry */ 8478c2ecf20Sopenharmony_ci } 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 8508c2ecf20Sopenharmony_ci "azx_get_response timeout, switching to single_cmd mode: last cmd=0x%08x\n", 8518c2ecf20Sopenharmony_ci bus->last_cmd[addr]); 8528c2ecf20Sopenharmony_ci chip->single_cmd = 1; 8538c2ecf20Sopenharmony_ci hbus->response_reset = 0; 8548c2ecf20Sopenharmony_ci snd_hdac_bus_stop_cmd_io(bus); 8558c2ecf20Sopenharmony_ci return -EIO; 8568c2ecf20Sopenharmony_ci} 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci/* 8598c2ecf20Sopenharmony_ci * Use the single immediate command instead of CORB/RIRB for simplicity 8608c2ecf20Sopenharmony_ci * 8618c2ecf20Sopenharmony_ci * Note: according to Intel, this is not preferred use. The command was 8628c2ecf20Sopenharmony_ci * intended for the BIOS only, and may get confused with unsolicited 8638c2ecf20Sopenharmony_ci * responses. So, we shouldn't use it for normal operation from the 8648c2ecf20Sopenharmony_ci * driver. 8658c2ecf20Sopenharmony_ci * I left the codes, however, for debugging/testing purposes. 8668c2ecf20Sopenharmony_ci */ 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci/* receive a response */ 8698c2ecf20Sopenharmony_cistatic int azx_single_wait_for_response(struct azx *chip, unsigned int addr) 8708c2ecf20Sopenharmony_ci{ 8718c2ecf20Sopenharmony_ci int timeout = 50; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci while (timeout--) { 8748c2ecf20Sopenharmony_ci /* check IRV busy bit */ 8758c2ecf20Sopenharmony_ci if (azx_readw(chip, IRS) & AZX_IRS_VALID) { 8768c2ecf20Sopenharmony_ci /* reuse rirb.res as the response return value */ 8778c2ecf20Sopenharmony_ci azx_bus(chip)->rirb.res[addr] = azx_readl(chip, IR); 8788c2ecf20Sopenharmony_ci return 0; 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci udelay(1); 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci if (printk_ratelimit()) 8838c2ecf20Sopenharmony_ci dev_dbg(chip->card->dev, "get_response timeout: IRS=0x%x\n", 8848c2ecf20Sopenharmony_ci azx_readw(chip, IRS)); 8858c2ecf20Sopenharmony_ci azx_bus(chip)->rirb.res[addr] = -1; 8868c2ecf20Sopenharmony_ci return -EIO; 8878c2ecf20Sopenharmony_ci} 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci/* send a command */ 8908c2ecf20Sopenharmony_cistatic int azx_single_send_cmd(struct hdac_bus *bus, u32 val) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci struct azx *chip = bus_to_azx(bus); 8938c2ecf20Sopenharmony_ci unsigned int addr = azx_command_addr(val); 8948c2ecf20Sopenharmony_ci int timeout = 50; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci bus->last_cmd[azx_command_addr(val)] = val; 8978c2ecf20Sopenharmony_ci while (timeout--) { 8988c2ecf20Sopenharmony_ci /* check ICB busy bit */ 8998c2ecf20Sopenharmony_ci if (!((azx_readw(chip, IRS) & AZX_IRS_BUSY))) { 9008c2ecf20Sopenharmony_ci /* Clear IRV valid bit */ 9018c2ecf20Sopenharmony_ci azx_writew(chip, IRS, azx_readw(chip, IRS) | 9028c2ecf20Sopenharmony_ci AZX_IRS_VALID); 9038c2ecf20Sopenharmony_ci azx_writel(chip, IC, val); 9048c2ecf20Sopenharmony_ci azx_writew(chip, IRS, azx_readw(chip, IRS) | 9058c2ecf20Sopenharmony_ci AZX_IRS_BUSY); 9068c2ecf20Sopenharmony_ci return azx_single_wait_for_response(chip, addr); 9078c2ecf20Sopenharmony_ci } 9088c2ecf20Sopenharmony_ci udelay(1); 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci if (printk_ratelimit()) 9118c2ecf20Sopenharmony_ci dev_dbg(chip->card->dev, 9128c2ecf20Sopenharmony_ci "send_cmd timeout: IRS=0x%x, val=0x%x\n", 9138c2ecf20Sopenharmony_ci azx_readw(chip, IRS), val); 9148c2ecf20Sopenharmony_ci return -EIO; 9158c2ecf20Sopenharmony_ci} 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci/* receive a response */ 9188c2ecf20Sopenharmony_cistatic int azx_single_get_response(struct hdac_bus *bus, unsigned int addr, 9198c2ecf20Sopenharmony_ci unsigned int *res) 9208c2ecf20Sopenharmony_ci{ 9218c2ecf20Sopenharmony_ci if (res) 9228c2ecf20Sopenharmony_ci *res = bus->rirb.res[addr]; 9238c2ecf20Sopenharmony_ci return 0; 9248c2ecf20Sopenharmony_ci} 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci/* 9278c2ecf20Sopenharmony_ci * The below are the main callbacks from hda_codec. 9288c2ecf20Sopenharmony_ci * 9298c2ecf20Sopenharmony_ci * They are just the skeleton to call sub-callbacks according to the 9308c2ecf20Sopenharmony_ci * current setting of chip->single_cmd. 9318c2ecf20Sopenharmony_ci */ 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci/* send a command */ 9348c2ecf20Sopenharmony_cistatic int azx_send_cmd(struct hdac_bus *bus, unsigned int val) 9358c2ecf20Sopenharmony_ci{ 9368c2ecf20Sopenharmony_ci struct azx *chip = bus_to_azx(bus); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci if (chip->disabled) 9398c2ecf20Sopenharmony_ci return 0; 9408c2ecf20Sopenharmony_ci if (chip->driver_caps & AZX_DCAPS_LS2X_WORKAROUND) 9418c2ecf20Sopenharmony_ci udelay(500); 9428c2ecf20Sopenharmony_ci if (chip->single_cmd) 9438c2ecf20Sopenharmony_ci return azx_single_send_cmd(bus, val); 9448c2ecf20Sopenharmony_ci else 9458c2ecf20Sopenharmony_ci return snd_hdac_bus_send_cmd(bus, val); 9468c2ecf20Sopenharmony_ci} 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci/* get a response */ 9498c2ecf20Sopenharmony_cistatic int azx_get_response(struct hdac_bus *bus, unsigned int addr, 9508c2ecf20Sopenharmony_ci unsigned int *res) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci struct azx *chip = bus_to_azx(bus); 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci if (chip->disabled) 9558c2ecf20Sopenharmony_ci return 0; 9568c2ecf20Sopenharmony_ci if (chip->single_cmd) 9578c2ecf20Sopenharmony_ci return azx_single_get_response(bus, addr, res); 9588c2ecf20Sopenharmony_ci else 9598c2ecf20Sopenharmony_ci return azx_rirb_get_response(bus, addr, res); 9608c2ecf20Sopenharmony_ci} 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_cistatic const struct hdac_bus_ops bus_core_ops = { 9638c2ecf20Sopenharmony_ci .command = azx_send_cmd, 9648c2ecf20Sopenharmony_ci .get_response = azx_get_response, 9658c2ecf20Sopenharmony_ci}; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_HDA_DSP_LOADER 9688c2ecf20Sopenharmony_ci/* 9698c2ecf20Sopenharmony_ci * DSP loading code (e.g. for CA0132) 9708c2ecf20Sopenharmony_ci */ 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci/* use the first stream for loading DSP */ 9738c2ecf20Sopenharmony_cistatic struct azx_dev * 9748c2ecf20Sopenharmony_ciazx_get_dsp_loader_dev(struct azx *chip) 9758c2ecf20Sopenharmony_ci{ 9768c2ecf20Sopenharmony_ci struct hdac_bus *bus = azx_bus(chip); 9778c2ecf20Sopenharmony_ci struct hdac_stream *s; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci list_for_each_entry(s, &bus->stream_list, list) 9808c2ecf20Sopenharmony_ci if (s->index == chip->playback_index_offset) 9818c2ecf20Sopenharmony_ci return stream_to_azx_dev(s); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci return NULL; 9848c2ecf20Sopenharmony_ci} 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ciint snd_hda_codec_load_dsp_prepare(struct hda_codec *codec, unsigned int format, 9878c2ecf20Sopenharmony_ci unsigned int byte_size, 9888c2ecf20Sopenharmony_ci struct snd_dma_buffer *bufp) 9898c2ecf20Sopenharmony_ci{ 9908c2ecf20Sopenharmony_ci struct hdac_bus *bus = &codec->bus->core; 9918c2ecf20Sopenharmony_ci struct azx *chip = bus_to_azx(bus); 9928c2ecf20Sopenharmony_ci struct azx_dev *azx_dev; 9938c2ecf20Sopenharmony_ci struct hdac_stream *hstr; 9948c2ecf20Sopenharmony_ci bool saved = false; 9958c2ecf20Sopenharmony_ci int err; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci azx_dev = azx_get_dsp_loader_dev(chip); 9988c2ecf20Sopenharmony_ci hstr = azx_stream(azx_dev); 9998c2ecf20Sopenharmony_ci spin_lock_irq(&bus->reg_lock); 10008c2ecf20Sopenharmony_ci if (hstr->opened) { 10018c2ecf20Sopenharmony_ci chip->saved_azx_dev = *azx_dev; 10028c2ecf20Sopenharmony_ci saved = true; 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci spin_unlock_irq(&bus->reg_lock); 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci err = snd_hdac_dsp_prepare(hstr, format, byte_size, bufp); 10078c2ecf20Sopenharmony_ci if (err < 0) { 10088c2ecf20Sopenharmony_ci spin_lock_irq(&bus->reg_lock); 10098c2ecf20Sopenharmony_ci if (saved) 10108c2ecf20Sopenharmony_ci *azx_dev = chip->saved_azx_dev; 10118c2ecf20Sopenharmony_ci spin_unlock_irq(&bus->reg_lock); 10128c2ecf20Sopenharmony_ci return err; 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci hstr->prepared = 0; 10168c2ecf20Sopenharmony_ci return err; 10178c2ecf20Sopenharmony_ci} 10188c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_load_dsp_prepare); 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_civoid snd_hda_codec_load_dsp_trigger(struct hda_codec *codec, bool start) 10218c2ecf20Sopenharmony_ci{ 10228c2ecf20Sopenharmony_ci struct hdac_bus *bus = &codec->bus->core; 10238c2ecf20Sopenharmony_ci struct azx *chip = bus_to_azx(bus); 10248c2ecf20Sopenharmony_ci struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci snd_hdac_dsp_trigger(azx_stream(azx_dev), start); 10278c2ecf20Sopenharmony_ci} 10288c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_load_dsp_trigger); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_civoid snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec, 10318c2ecf20Sopenharmony_ci struct snd_dma_buffer *dmab) 10328c2ecf20Sopenharmony_ci{ 10338c2ecf20Sopenharmony_ci struct hdac_bus *bus = &codec->bus->core; 10348c2ecf20Sopenharmony_ci struct azx *chip = bus_to_azx(bus); 10358c2ecf20Sopenharmony_ci struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip); 10368c2ecf20Sopenharmony_ci struct hdac_stream *hstr = azx_stream(azx_dev); 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci if (!dmab->area || !hstr->locked) 10398c2ecf20Sopenharmony_ci return; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci snd_hdac_dsp_cleanup(hstr, dmab); 10428c2ecf20Sopenharmony_ci spin_lock_irq(&bus->reg_lock); 10438c2ecf20Sopenharmony_ci if (hstr->opened) 10448c2ecf20Sopenharmony_ci *azx_dev = chip->saved_azx_dev; 10458c2ecf20Sopenharmony_ci hstr->locked = false; 10468c2ecf20Sopenharmony_ci spin_unlock_irq(&bus->reg_lock); 10478c2ecf20Sopenharmony_ci} 10488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_load_dsp_cleanup); 10498c2ecf20Sopenharmony_ci#endif /* CONFIG_SND_HDA_DSP_LOADER */ 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci/* 10528c2ecf20Sopenharmony_ci * reset and start the controller registers 10538c2ecf20Sopenharmony_ci */ 10548c2ecf20Sopenharmony_civoid azx_init_chip(struct azx *chip, bool full_reset) 10558c2ecf20Sopenharmony_ci{ 10568c2ecf20Sopenharmony_ci if (snd_hdac_bus_init_chip(azx_bus(chip), full_reset)) { 10578c2ecf20Sopenharmony_ci /* correct RINTCNT for CXT */ 10588c2ecf20Sopenharmony_ci if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) 10598c2ecf20Sopenharmony_ci azx_writew(chip, RINTCNT, 0xc0); 10608c2ecf20Sopenharmony_ci } 10618c2ecf20Sopenharmony_ci} 10628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_init_chip); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_civoid azx_stop_all_streams(struct azx *chip) 10658c2ecf20Sopenharmony_ci{ 10668c2ecf20Sopenharmony_ci struct hdac_bus *bus = azx_bus(chip); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci snd_hdac_stop_streams(bus); 10698c2ecf20Sopenharmony_ci} 10708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_stop_all_streams); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_civoid azx_stop_chip(struct azx *chip) 10738c2ecf20Sopenharmony_ci{ 10748c2ecf20Sopenharmony_ci snd_hdac_bus_stop_chip(azx_bus(chip)); 10758c2ecf20Sopenharmony_ci} 10768c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_stop_chip); 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci/* 10798c2ecf20Sopenharmony_ci * interrupt handler 10808c2ecf20Sopenharmony_ci */ 10818c2ecf20Sopenharmony_cistatic void stream_update(struct hdac_bus *bus, struct hdac_stream *s) 10828c2ecf20Sopenharmony_ci{ 10838c2ecf20Sopenharmony_ci struct azx *chip = bus_to_azx(bus); 10848c2ecf20Sopenharmony_ci struct azx_dev *azx_dev = stream_to_azx_dev(s); 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci /* check whether this IRQ is really acceptable */ 10878c2ecf20Sopenharmony_ci if (!chip->ops->position_check || 10888c2ecf20Sopenharmony_ci chip->ops->position_check(chip, azx_dev)) { 10898c2ecf20Sopenharmony_ci spin_unlock(&bus->reg_lock); 10908c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(azx_stream(azx_dev)->substream); 10918c2ecf20Sopenharmony_ci spin_lock(&bus->reg_lock); 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci} 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ciirqreturn_t azx_interrupt(int irq, void *dev_id) 10968c2ecf20Sopenharmony_ci{ 10978c2ecf20Sopenharmony_ci struct azx *chip = dev_id; 10988c2ecf20Sopenharmony_ci struct hdac_stream *azx_dev; 10998c2ecf20Sopenharmony_ci struct hdac_bus *bus = azx_bus(chip); 11008c2ecf20Sopenharmony_ci u32 i = 0, status = 0; 11018c2ecf20Sopenharmony_ci bool active, handled = false; 11028c2ecf20Sopenharmony_ci int repeat = 0; /* count for avoiding endless loop */ 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 11058c2ecf20Sopenharmony_ci if (azx_has_pm_runtime(chip)) 11068c2ecf20Sopenharmony_ci if (!pm_runtime_active(chip->card->dev)) 11078c2ecf20Sopenharmony_ci return IRQ_NONE; 11088c2ecf20Sopenharmony_ci#endif 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci spin_lock(&bus->reg_lock); 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci if (chip->disabled) 11138c2ecf20Sopenharmony_ci goto unlock; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci do { 11168c2ecf20Sopenharmony_ci if (chip->driver_caps & AZX_DCAPS_LS2X_WORKAROUND) { 11178c2ecf20Sopenharmony_ci i = 0; 11188c2ecf20Sopenharmony_ci status = 0; 11198c2ecf20Sopenharmony_ci list_for_each_entry(azx_dev, &bus->stream_list, list) { 11208c2ecf20Sopenharmony_ci status |= (snd_hdac_stream_readb(azx_dev, SD_STS) & SD_INT_MASK) ? 11218c2ecf20Sopenharmony_ci (1 << i) : 0; 11228c2ecf20Sopenharmony_ci i++; 11238c2ecf20Sopenharmony_ci } 11248c2ecf20Sopenharmony_ci status |= (status & ~0) ? (1 << 31) : 0; 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci else 11278c2ecf20Sopenharmony_ci status = azx_readl(chip, INTSTS); 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci if (status == 0 || 11308c2ecf20Sopenharmony_ci (status == 0xffffffff && !(chip->driver_caps & AZX_DCAPS_LS2X_WORKAROUND))) 11318c2ecf20Sopenharmony_ci break; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci handled = true; 11348c2ecf20Sopenharmony_ci active = false; 11358c2ecf20Sopenharmony_ci if (snd_hdac_bus_handle_stream_irq(bus, status, stream_update)) 11368c2ecf20Sopenharmony_ci active = true; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci status = azx_readb(chip, RIRBSTS); 11398c2ecf20Sopenharmony_ci if (status & RIRB_INT_MASK) { 11408c2ecf20Sopenharmony_ci /* 11418c2ecf20Sopenharmony_ci * Clearing the interrupt status here ensures that no 11428c2ecf20Sopenharmony_ci * interrupt gets masked after the RIRB wp is read in 11438c2ecf20Sopenharmony_ci * snd_hdac_bus_update_rirb. This avoids a possible 11448c2ecf20Sopenharmony_ci * race condition where codec response in RIRB may 11458c2ecf20Sopenharmony_ci * remain unserviced by IRQ, eventually falling back 11468c2ecf20Sopenharmony_ci * to polling mode in azx_rirb_get_response. 11478c2ecf20Sopenharmony_ci */ 11488c2ecf20Sopenharmony_ci if (chip->driver_caps & AZX_DCAPS_LS2X_WORKAROUND) 11498c2ecf20Sopenharmony_ci azx_writeb(chip, RIRBSTS, status & RIRB_INT_MASK); 11508c2ecf20Sopenharmony_ci else 11518c2ecf20Sopenharmony_ci azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); 11528c2ecf20Sopenharmony_ci active = true; 11538c2ecf20Sopenharmony_ci if (status & RIRB_INT_RESPONSE) { 11548c2ecf20Sopenharmony_ci if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) 11558c2ecf20Sopenharmony_ci udelay(80); 11568c2ecf20Sopenharmony_ci snd_hdac_bus_update_rirb(bus); 11578c2ecf20Sopenharmony_ci } 11588c2ecf20Sopenharmony_ci } 11598c2ecf20Sopenharmony_ci } while (active && ++repeat < 10); 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci unlock: 11628c2ecf20Sopenharmony_ci spin_unlock(&bus->reg_lock); 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci return IRQ_RETVAL(handled); 11658c2ecf20Sopenharmony_ci} 11668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_interrupt); 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci/* 11698c2ecf20Sopenharmony_ci * Codec initerface 11708c2ecf20Sopenharmony_ci */ 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci/* 11738c2ecf20Sopenharmony_ci * Probe the given codec address 11748c2ecf20Sopenharmony_ci */ 11758c2ecf20Sopenharmony_cistatic int probe_codec(struct azx *chip, int addr) 11768c2ecf20Sopenharmony_ci{ 11778c2ecf20Sopenharmony_ci unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | 11788c2ecf20Sopenharmony_ci (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; 11798c2ecf20Sopenharmony_ci struct hdac_bus *bus = azx_bus(chip); 11808c2ecf20Sopenharmony_ci int err; 11818c2ecf20Sopenharmony_ci unsigned int res = -1; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci mutex_lock(&bus->cmd_mutex); 11848c2ecf20Sopenharmony_ci chip->probing = 1; 11858c2ecf20Sopenharmony_ci azx_send_cmd(bus, cmd); 11868c2ecf20Sopenharmony_ci err = azx_get_response(bus, addr, &res); 11878c2ecf20Sopenharmony_ci chip->probing = 0; 11888c2ecf20Sopenharmony_ci mutex_unlock(&bus->cmd_mutex); 11898c2ecf20Sopenharmony_ci if (err < 0 || res == -1) 11908c2ecf20Sopenharmony_ci return -EIO; 11918c2ecf20Sopenharmony_ci dev_dbg(chip->card->dev, "codec #%d probed OK\n", addr); 11928c2ecf20Sopenharmony_ci return 0; 11938c2ecf20Sopenharmony_ci} 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_civoid snd_hda_bus_reset(struct hda_bus *bus) 11968c2ecf20Sopenharmony_ci{ 11978c2ecf20Sopenharmony_ci struct azx *chip = bus_to_azx(&bus->core); 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci bus->in_reset = 1; 12008c2ecf20Sopenharmony_ci azx_stop_chip(chip); 12018c2ecf20Sopenharmony_ci azx_init_chip(chip, true); 12028c2ecf20Sopenharmony_ci if (bus->core.chip_init) 12038c2ecf20Sopenharmony_ci snd_hda_bus_reset_codecs(bus); 12048c2ecf20Sopenharmony_ci bus->in_reset = 0; 12058c2ecf20Sopenharmony_ci} 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci/* HD-audio bus initialization */ 12088c2ecf20Sopenharmony_ciint azx_bus_init(struct azx *chip, const char *model) 12098c2ecf20Sopenharmony_ci{ 12108c2ecf20Sopenharmony_ci struct hda_bus *bus = &chip->bus; 12118c2ecf20Sopenharmony_ci int err; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci err = snd_hdac_bus_init(&bus->core, chip->card->dev, &bus_core_ops); 12148c2ecf20Sopenharmony_ci if (err < 0) 12158c2ecf20Sopenharmony_ci return err; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci bus->card = chip->card; 12188c2ecf20Sopenharmony_ci mutex_init(&bus->prepare_mutex); 12198c2ecf20Sopenharmony_ci bus->pci = chip->pci; 12208c2ecf20Sopenharmony_ci bus->modelname = model; 12218c2ecf20Sopenharmony_ci bus->mixer_assigned = -1; 12228c2ecf20Sopenharmony_ci bus->core.snoop = azx_snoop(chip); 12238c2ecf20Sopenharmony_ci if (chip->get_position[0] != azx_get_pos_lpib || 12248c2ecf20Sopenharmony_ci chip->get_position[1] != azx_get_pos_lpib) 12258c2ecf20Sopenharmony_ci bus->core.use_posbuf = true; 12268c2ecf20Sopenharmony_ci bus->core.bdl_pos_adj = chip->bdl_pos_adj; 12278c2ecf20Sopenharmony_ci if (chip->driver_caps & AZX_DCAPS_CORBRP_SELF_CLEAR) 12288c2ecf20Sopenharmony_ci bus->core.corbrp_self_clear = true; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) 12318c2ecf20Sopenharmony_ci bus->core.align_bdle_4k = true; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci /* enable sync_write flag for stable communication as default */ 12348c2ecf20Sopenharmony_ci bus->core.sync_write = 1; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci return 0; 12378c2ecf20Sopenharmony_ci} 12388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_bus_init); 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci/* Probe codecs */ 12418c2ecf20Sopenharmony_ciint azx_probe_codecs(struct azx *chip, unsigned int max_slots) 12428c2ecf20Sopenharmony_ci{ 12438c2ecf20Sopenharmony_ci struct hdac_bus *bus = azx_bus(chip); 12448c2ecf20Sopenharmony_ci int c, codecs, err; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci codecs = 0; 12478c2ecf20Sopenharmony_ci if (!max_slots) 12488c2ecf20Sopenharmony_ci max_slots = AZX_DEFAULT_CODECS; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci /* First try to probe all given codec slots */ 12518c2ecf20Sopenharmony_ci for (c = 0; c < max_slots; c++) { 12528c2ecf20Sopenharmony_ci if ((bus->codec_mask & (1 << c)) & chip->codec_probe_mask) { 12538c2ecf20Sopenharmony_ci if (probe_codec(chip, c) < 0) { 12548c2ecf20Sopenharmony_ci /* Some BIOSen give you wrong codec addresses 12558c2ecf20Sopenharmony_ci * that don't exist 12568c2ecf20Sopenharmony_ci */ 12578c2ecf20Sopenharmony_ci dev_warn(chip->card->dev, 12588c2ecf20Sopenharmony_ci "Codec #%d probe error; disabling it...\n", c); 12598c2ecf20Sopenharmony_ci bus->codec_mask &= ~(1 << c); 12608c2ecf20Sopenharmony_ci /* More badly, accessing to a non-existing 12618c2ecf20Sopenharmony_ci * codec often screws up the controller chip, 12628c2ecf20Sopenharmony_ci * and disturbs the further communications. 12638c2ecf20Sopenharmony_ci * Thus if an error occurs during probing, 12648c2ecf20Sopenharmony_ci * better to reset the controller chip to 12658c2ecf20Sopenharmony_ci * get back to the sanity state. 12668c2ecf20Sopenharmony_ci */ 12678c2ecf20Sopenharmony_ci azx_stop_chip(chip); 12688c2ecf20Sopenharmony_ci azx_init_chip(chip, true); 12698c2ecf20Sopenharmony_ci } 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci } 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci /* Then create codec instances */ 12748c2ecf20Sopenharmony_ci for (c = 0; c < max_slots; c++) { 12758c2ecf20Sopenharmony_ci if ((bus->codec_mask & (1 << c)) & chip->codec_probe_mask) { 12768c2ecf20Sopenharmony_ci struct hda_codec *codec; 12778c2ecf20Sopenharmony_ci err = snd_hda_codec_new(&chip->bus, chip->card, c, &codec); 12788c2ecf20Sopenharmony_ci if (err < 0) 12798c2ecf20Sopenharmony_ci continue; 12808c2ecf20Sopenharmony_ci codec->jackpoll_interval = chip->jackpoll_interval; 12818c2ecf20Sopenharmony_ci codec->beep_mode = chip->beep_mode; 12828c2ecf20Sopenharmony_ci codecs++; 12838c2ecf20Sopenharmony_ci } 12848c2ecf20Sopenharmony_ci } 12858c2ecf20Sopenharmony_ci if (!codecs) { 12868c2ecf20Sopenharmony_ci dev_err(chip->card->dev, "no codecs initialized\n"); 12878c2ecf20Sopenharmony_ci return -ENXIO; 12888c2ecf20Sopenharmony_ci } 12898c2ecf20Sopenharmony_ci return 0; 12908c2ecf20Sopenharmony_ci} 12918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_probe_codecs); 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci/* configure each codec instance */ 12948c2ecf20Sopenharmony_ciint azx_codec_configure(struct azx *chip) 12958c2ecf20Sopenharmony_ci{ 12968c2ecf20Sopenharmony_ci struct hda_codec *codec, *next; 12978c2ecf20Sopenharmony_ci int success = 0; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci list_for_each_codec(codec, &chip->bus) { 13008c2ecf20Sopenharmony_ci if (!snd_hda_codec_configure(codec)) 13018c2ecf20Sopenharmony_ci success++; 13028c2ecf20Sopenharmony_ci } 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci if (success) { 13058c2ecf20Sopenharmony_ci /* unregister failed codecs if any codec has been probed */ 13068c2ecf20Sopenharmony_ci list_for_each_codec_safe(codec, next, &chip->bus) { 13078c2ecf20Sopenharmony_ci if (!codec->configured) { 13088c2ecf20Sopenharmony_ci codec_err(codec, "Unable to configure, disabling\n"); 13098c2ecf20Sopenharmony_ci snd_hdac_device_unregister(&codec->core); 13108c2ecf20Sopenharmony_ci } 13118c2ecf20Sopenharmony_ci } 13128c2ecf20Sopenharmony_ci } 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci return success ? 0 : -ENODEV; 13158c2ecf20Sopenharmony_ci} 13168c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_codec_configure); 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_cistatic int stream_direction(struct azx *chip, unsigned char index) 13198c2ecf20Sopenharmony_ci{ 13208c2ecf20Sopenharmony_ci if (index >= chip->capture_index_offset && 13218c2ecf20Sopenharmony_ci index < chip->capture_index_offset + chip->capture_streams) 13228c2ecf20Sopenharmony_ci return SNDRV_PCM_STREAM_CAPTURE; 13238c2ecf20Sopenharmony_ci return SNDRV_PCM_STREAM_PLAYBACK; 13248c2ecf20Sopenharmony_ci} 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci/* initialize SD streams */ 13278c2ecf20Sopenharmony_ciint azx_init_streams(struct azx *chip) 13288c2ecf20Sopenharmony_ci{ 13298c2ecf20Sopenharmony_ci int i; 13308c2ecf20Sopenharmony_ci int stream_tags[2] = { 0, 0 }; 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci /* initialize each stream (aka device) 13338c2ecf20Sopenharmony_ci * assign the starting bdl address to each stream (device) 13348c2ecf20Sopenharmony_ci * and initialize 13358c2ecf20Sopenharmony_ci */ 13368c2ecf20Sopenharmony_ci for (i = 0; i < chip->num_streams; i++) { 13378c2ecf20Sopenharmony_ci struct azx_dev *azx_dev = kzalloc(sizeof(*azx_dev), GFP_KERNEL); 13388c2ecf20Sopenharmony_ci int dir, tag; 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci if (!azx_dev) 13418c2ecf20Sopenharmony_ci return -ENOMEM; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci dir = stream_direction(chip, i); 13448c2ecf20Sopenharmony_ci /* stream tag must be unique throughout 13458c2ecf20Sopenharmony_ci * the stream direction group, 13468c2ecf20Sopenharmony_ci * valid values 1...15 13478c2ecf20Sopenharmony_ci * use separate stream tag if the flag 13488c2ecf20Sopenharmony_ci * AZX_DCAPS_SEPARATE_STREAM_TAG is used 13498c2ecf20Sopenharmony_ci */ 13508c2ecf20Sopenharmony_ci if (chip->driver_caps & AZX_DCAPS_SEPARATE_STREAM_TAG) 13518c2ecf20Sopenharmony_ci tag = ++stream_tags[dir]; 13528c2ecf20Sopenharmony_ci else 13538c2ecf20Sopenharmony_ci tag = i + 1; 13548c2ecf20Sopenharmony_ci snd_hdac_stream_init(azx_bus(chip), azx_stream(azx_dev), 13558c2ecf20Sopenharmony_ci i, dir, tag); 13568c2ecf20Sopenharmony_ci } 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci return 0; 13598c2ecf20Sopenharmony_ci} 13608c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_init_streams); 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_civoid azx_free_streams(struct azx *chip) 13638c2ecf20Sopenharmony_ci{ 13648c2ecf20Sopenharmony_ci struct hdac_bus *bus = azx_bus(chip); 13658c2ecf20Sopenharmony_ci struct hdac_stream *s; 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci while (!list_empty(&bus->stream_list)) { 13688c2ecf20Sopenharmony_ci s = list_first_entry(&bus->stream_list, struct hdac_stream, list); 13698c2ecf20Sopenharmony_ci list_del(&s->list); 13708c2ecf20Sopenharmony_ci kfree(stream_to_azx_dev(s)); 13718c2ecf20Sopenharmony_ci } 13728c2ecf20Sopenharmony_ci} 13738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_free_streams); 1374