Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/intel/boards/skl_hda_dsp_generic.c
26493 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
// Copyright(c) 2015-18 Intel Corporation.
3
4
/*
5
* Machine Driver for SKL+ platforms with DSP and iDisp, HDA Codecs
6
*/
7
8
#include <linux/module.h>
9
#include <linux/platform_device.h>
10
#include <sound/core.h>
11
#include <sound/hda_codec.h>
12
#include <sound/jack.h>
13
#include <sound/pcm.h>
14
#include <sound/pcm_params.h>
15
#include <sound/soc.h>
16
#include <sound/soc-acpi.h>
17
#include "../../codecs/hdac_hda.h"
18
#include "../../sof/intel/hda.h"
19
#include "sof_board_helpers.h"
20
21
static int skl_hda_card_late_probe(struct snd_soc_card *card)
22
{
23
return sof_intel_board_card_late_probe(card);
24
}
25
26
#define HDA_CODEC_AUTOSUSPEND_DELAY_MS 1000
27
28
static void skl_set_hda_codec_autosuspend_delay(struct snd_soc_card *card)
29
{
30
struct snd_soc_pcm_runtime *rtd;
31
struct hdac_hda_priv *hda_pvt;
32
struct snd_soc_dai *dai;
33
34
for_each_card_rtds(card, rtd) {
35
if (!strstr(rtd->dai_link->codecs->name, "ehdaudio0D0"))
36
continue;
37
dai = snd_soc_rtd_to_codec(rtd, 0);
38
hda_pvt = snd_soc_component_get_drvdata(dai->component);
39
if (hda_pvt) {
40
/*
41
* all codecs are on the same bus, so it's sufficient
42
* to look up only the first one
43
*/
44
snd_hda_set_power_save(hda_pvt->codec->bus,
45
HDA_CODEC_AUTOSUSPEND_DELAY_MS);
46
break;
47
}
48
}
49
}
50
51
#define IDISP_HDMI_BE_ID 1
52
#define HDA_BE_ID 4
53
#define DMIC01_BE_ID 6
54
#define DMIC16K_BE_ID 7
55
#define BT_OFFLOAD_BE_ID 8
56
57
#define HDA_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_IDISP_HDMI, \
58
SOF_LINK_HDA, \
59
SOF_LINK_DMIC01, \
60
SOF_LINK_DMIC16K, \
61
SOF_LINK_BT_OFFLOAD, \
62
SOF_LINK_NONE, \
63
SOF_LINK_NONE)
64
65
#define HDA_LINK_IDS SOF_LINK_ORDER(IDISP_HDMI_BE_ID, \
66
HDA_BE_ID, \
67
DMIC01_BE_ID, \
68
DMIC16K_BE_ID, \
69
BT_OFFLOAD_BE_ID, \
70
0, \
71
0)
72
73
static unsigned long
74
skl_hda_get_board_quirk(struct snd_soc_acpi_mach_params *mach_params)
75
{
76
unsigned long board_quirk = 0;
77
int ssp_bt;
78
79
if (hweight_long(mach_params->bt_link_mask) == 1) {
80
ssp_bt = fls(mach_params->bt_link_mask) - 1;
81
board_quirk |= SOF_SSP_PORT_BT_OFFLOAD(ssp_bt) |
82
SOF_BT_OFFLOAD_PRESENT;
83
}
84
85
return board_quirk;
86
}
87
88
static int skl_hda_add_dai_link(struct snd_soc_card *card,
89
struct snd_soc_dai_link *link)
90
{
91
struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
92
93
/* Ignore the HDMI PCM link if iDisp is not present */
94
if (strstr(link->stream_name, "HDMI") && !ctx->hdmi.idisp_codec)
95
link->ignore = true;
96
97
return 0;
98
}
99
100
static int skl_hda_audio_probe(struct platform_device *pdev)
101
{
102
struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
103
struct sof_card_private *ctx;
104
struct snd_soc_card *card;
105
unsigned long board_quirk = skl_hda_get_board_quirk(&mach->mach_params);
106
int ret;
107
108
card = devm_kzalloc(&pdev->dev, sizeof(struct snd_soc_card), GFP_KERNEL);
109
if (!card)
110
return -ENOMEM;
111
112
card->name = "hda-dsp";
113
card->owner = THIS_MODULE;
114
card->fully_routed = true;
115
card->late_probe = skl_hda_card_late_probe;
116
card->add_dai_link = skl_hda_add_dai_link;
117
118
dev_dbg(&pdev->dev, "board_quirk = %lx\n", board_quirk);
119
120
/* initialize ctx with board quirk */
121
ctx = sof_intel_board_get_ctx(&pdev->dev, board_quirk);
122
if (!ctx)
123
return -ENOMEM;
124
125
if (HDA_EXT_CODEC(mach->mach_params.codec_mask))
126
ctx->hda_codec_present = true;
127
128
if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
129
ctx->hdmi.idisp_codec = true;
130
131
ctx->link_order_overwrite = HDA_LINK_ORDER;
132
ctx->link_id_overwrite = HDA_LINK_IDS;
133
134
/* update dai_link */
135
ret = sof_intel_board_set_dai_link(&pdev->dev, card, ctx);
136
if (ret)
137
return ret;
138
139
card->dev = &pdev->dev;
140
141
if (mach->mach_params.dmic_num > 0) {
142
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
143
"cfg-dmics:%d",
144
mach->mach_params.dmic_num);
145
if (!card->components)
146
return -ENOMEM;
147
}
148
149
ret = snd_soc_fixup_dai_links_platform_name(card,
150
mach->mach_params.platform);
151
if (ret)
152
return ret;
153
154
snd_soc_card_set_drvdata(card, ctx);
155
156
ret = devm_snd_soc_register_card(&pdev->dev, card);
157
if (!ret)
158
skl_set_hda_codec_autosuspend_delay(card);
159
160
return ret;
161
}
162
163
static struct platform_driver skl_hda_audio = {
164
.probe = skl_hda_audio_probe,
165
.driver = {
166
.name = "skl_hda_dsp_generic",
167
.pm = &snd_soc_pm_ops,
168
},
169
};
170
171
module_platform_driver(skl_hda_audio)
172
173
/* Module information */
174
MODULE_DESCRIPTION("SKL/KBL/BXT/APL HDA Generic Machine driver");
175
MODULE_AUTHOR("Rakesh Ughreja <[email protected]>");
176
MODULE_LICENSE("GPL v2");
177
MODULE_ALIAS("platform:skl_hda_dsp_generic");
178
MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS");
179
180