linux/sound/soc/sof/intel/hda-codec.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
   2//
   3// This file is provided under a dual BSD/GPLv2 license.  When using or
   4// redistributing this file, you may do so under either license.
   5//
   6// Copyright(c) 2018 Intel Corporation. All rights reserved.
   7//
   8// Authors: Keyon Jie <yang.jie@linux.intel.com>
   9//
  10
  11#include <linux/module.h>
  12#include <sound/hdaudio_ext.h>
  13#include <sound/hda_codec.h>
  14#include <sound/hda_i915.h>
  15#include <sound/sof.h>
  16#include "../ops.h"
  17#include "hda.h"
  18#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
  19#include "../../codecs/hdac_hda.h"
  20#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */
  21
  22#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
  23#define IDISP_VID_INTEL 0x80860000
  24
  25/* load the legacy HDA codec driver */
  26#ifdef MODULE
  27static void hda_codec_load_module(struct hda_codec *codec)
  28{
  29        char alias[MODULE_NAME_LEN];
  30        const char *module = alias;
  31
  32        snd_hdac_codec_modalias(&codec->core, alias, sizeof(alias));
  33        dev_dbg(&codec->core.dev, "loading codec module: %s\n", module);
  34        request_module(module);
  35}
  36#else
  37static void hda_codec_load_module(struct hda_codec *codec) {}
  38#endif
  39
  40#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */
  41
  42/* probe individual codec */
  43static int hda_codec_probe(struct snd_sof_dev *sdev, int address)
  44{
  45        struct hda_bus *hbus = sof_to_hbus(sdev);
  46        struct hdac_device *hdev;
  47#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
  48        struct hdac_hda_priv *hda_priv;
  49#endif
  50        u32 hda_cmd = (address << 28) | (AC_NODE_ROOT << 20) |
  51                (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
  52        u32 resp = -1;
  53        int ret;
  54
  55        mutex_lock(&hbus->core.cmd_mutex);
  56        snd_hdac_bus_send_cmd(&hbus->core, hda_cmd);
  57        snd_hdac_bus_get_response(&hbus->core, address, &resp);
  58        mutex_unlock(&hbus->core.cmd_mutex);
  59        if (resp == -1)
  60                return -EIO;
  61        dev_dbg(sdev->dev, "HDA codec #%d probed OK: response: %x\n",
  62                address, resp);
  63
  64#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
  65        /* snd_hdac_ext_bus_device_exit will use kfree to free hdev */
  66        hda_priv = kzalloc(sizeof(*hda_priv), GFP_KERNEL);
  67        if (!hda_priv)
  68                return -ENOMEM;
  69
  70        hda_priv->codec.bus = hbus;
  71        hdev = &hda_priv->codec.core;
  72
  73        ret = snd_hdac_ext_bus_device_init(&hbus->core, address, hdev);
  74        if (ret < 0)
  75                return ret;
  76
  77        /* use legacy bus only for HDA codecs, idisp uses ext bus */
  78        if ((resp & 0xFFFF0000) != IDISP_VID_INTEL) {
  79                hdev->type = HDA_DEV_LEGACY;
  80                hda_codec_load_module(&hda_priv->codec);
  81        }
  82
  83        return 0;
  84#else
  85        /* snd_hdac_ext_bus_device_exit will use kfree to free hdev */
  86        hdev = kzalloc(sizeof(*hdev), GFP_KERNEL);
  87        if (!hdev)
  88                return -ENOMEM;
  89
  90        ret = snd_hdac_ext_bus_device_init(&hbus->core, address, hdev);
  91
  92        return ret;
  93#endif
  94}
  95
  96/* Codec initialization */
  97int hda_codec_probe_bus(struct snd_sof_dev *sdev)
  98{
  99        struct hdac_bus *bus = sof_to_bus(sdev);
 100        int i, ret;
 101
 102        /* probe codecs in avail slots */
 103        for (i = 0; i < HDA_MAX_CODECS; i++) {
 104
 105                if (!(bus->codec_mask & (1 << i)))
 106                        continue;
 107
 108                ret = hda_codec_probe(sdev, i);
 109                if (ret < 0) {
 110                        dev_err(bus->dev, "error: codec #%d probe error, ret: %d\n",
 111                                i, ret);
 112                        return ret;
 113                }
 114        }
 115
 116        return 0;
 117}
 118EXPORT_SYMBOL(hda_codec_probe_bus);
 119
 120#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)
 121
 122void hda_codec_i915_get(struct snd_sof_dev *sdev)
 123{
 124        struct hdac_bus *bus = sof_to_bus(sdev);
 125
 126        dev_dbg(bus->dev, "Turning i915 HDAC power on\n");
 127        snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);
 128}
 129EXPORT_SYMBOL(hda_codec_i915_get);
 130
 131void hda_codec_i915_put(struct snd_sof_dev *sdev)
 132{
 133        struct hdac_bus *bus = sof_to_bus(sdev);
 134
 135        dev_dbg(bus->dev, "Turning i915 HDAC power off\n");
 136        snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
 137}
 138EXPORT_SYMBOL(hda_codec_i915_put);
 139
 140int hda_codec_i915_init(struct snd_sof_dev *sdev)
 141{
 142        struct hdac_bus *bus = sof_to_bus(sdev);
 143        int ret;
 144
 145        /* i915 exposes a HDA codec for HDMI audio */
 146        ret = snd_hdac_i915_init(bus);
 147        if (ret < 0)
 148                return ret;
 149
 150        hda_codec_i915_get(sdev);
 151
 152        return 0;
 153}
 154EXPORT_SYMBOL(hda_codec_i915_init);
 155
 156int hda_codec_i915_exit(struct snd_sof_dev *sdev)
 157{
 158        struct hdac_bus *bus = sof_to_bus(sdev);
 159        int ret;
 160
 161        hda_codec_i915_put(sdev);
 162
 163        ret = snd_hdac_i915_exit(bus);
 164
 165        return ret;
 166}
 167EXPORT_SYMBOL(hda_codec_i915_exit);
 168
 169#endif /* CONFIG_SND_SOC_HDAC_HDMI */
 170
 171MODULE_LICENSE("Dual BSD/GPL");
 172