.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (c) 2015 The Linux Foundation. All rights reserved. |
---|
3 | | - * |
---|
4 | | - * This program is free software; you can redistribute it and/or modify |
---|
5 | | - * it under the terms of the GNU General Public License version 2 and |
---|
6 | | - * only version 2 as published by the Free Software Foundation. |
---|
7 | | - * |
---|
8 | | - * This program is distributed in the hope that it will be useful, |
---|
9 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
10 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
11 | | - * GNU General Public License for more details. |
---|
12 | | - * |
---|
13 | 4 | */ |
---|
14 | 5 | |
---|
15 | 6 | #include <linux/device.h> |
---|
.. | .. |
---|
25 | 16 | #include <sound/soc.h> |
---|
26 | 17 | #include <uapi/linux/input-event-codes.h> |
---|
27 | 18 | #include <dt-bindings/sound/apq8016-lpass.h> |
---|
| 19 | +#include "common.h" |
---|
28 | 20 | |
---|
29 | 21 | struct apq8016_sbc_data { |
---|
| 22 | + struct snd_soc_card card; |
---|
30 | 23 | void __iomem *mic_iomux; |
---|
31 | 24 | void __iomem *spkr_iomux; |
---|
32 | 25 | struct snd_soc_jack jack; |
---|
33 | 26 | bool jack_setup; |
---|
34 | | - struct snd_soc_dai_link dai_link[]; /* dynamically allocated */ |
---|
35 | 27 | }; |
---|
36 | 28 | |
---|
37 | 29 | #define MIC_CTRL_TER_WS_SLAVE_SEL BIT(21) |
---|
.. | .. |
---|
42 | 34 | |
---|
43 | 35 | static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd) |
---|
44 | 36 | { |
---|
45 | | - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
---|
| 37 | + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); |
---|
| 38 | + struct snd_soc_dai *codec_dai; |
---|
46 | 39 | struct snd_soc_component *component; |
---|
47 | | - struct snd_soc_dai_link *dai_link = rtd->dai_link; |
---|
48 | 40 | struct snd_soc_card *card = rtd->card; |
---|
49 | 41 | struct apq8016_sbc_data *pdata = snd_soc_card_get_drvdata(card); |
---|
50 | 42 | int i, rval; |
---|
.. | .. |
---|
99 | 91 | pdata->jack_setup = true; |
---|
100 | 92 | } |
---|
101 | 93 | |
---|
102 | | - for (i = 0 ; i < dai_link->num_codecs; i++) { |
---|
103 | | - struct snd_soc_dai *dai = rtd->codec_dais[i]; |
---|
| 94 | + for_each_rtd_codec_dais(rtd, i, codec_dai) { |
---|
104 | 95 | |
---|
105 | | - component = dai->component; |
---|
| 96 | + component = codec_dai->component; |
---|
106 | 97 | /* Set default mclk for internal codec */ |
---|
107 | 98 | rval = snd_soc_component_set_sysclk(component, 0, 0, DEFAULT_MCLK_RATE, |
---|
108 | 99 | SND_SOC_CLOCK_IN); |
---|
.. | .. |
---|
120 | 111 | return 0; |
---|
121 | 112 | } |
---|
122 | 113 | |
---|
123 | | -static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card) |
---|
| 114 | +static void apq8016_sbc_add_ops(struct snd_soc_card *card) |
---|
124 | 115 | { |
---|
125 | | - struct device *dev = card->dev; |
---|
126 | 116 | struct snd_soc_dai_link *link; |
---|
127 | | - struct device_node *np, *codec, *cpu, *node = dev->of_node; |
---|
128 | | - struct apq8016_sbc_data *data; |
---|
129 | | - int ret, num_links; |
---|
| 117 | + int i; |
---|
130 | 118 | |
---|
131 | | - ret = snd_soc_of_parse_card_name(card, "qcom,model"); |
---|
132 | | - if (ret) { |
---|
133 | | - dev_err(dev, "Error parsing card name: %d\n", ret); |
---|
134 | | - return ERR_PTR(ret); |
---|
135 | | - } |
---|
136 | | - |
---|
137 | | - /* DAPM routes */ |
---|
138 | | - if (of_property_read_bool(node, "qcom,audio-routing")) { |
---|
139 | | - ret = snd_soc_of_parse_audio_routing(card, |
---|
140 | | - "qcom,audio-routing"); |
---|
141 | | - if (ret) |
---|
142 | | - return ERR_PTR(ret); |
---|
143 | | - } |
---|
144 | | - |
---|
145 | | - |
---|
146 | | - /* Populate links */ |
---|
147 | | - num_links = of_get_child_count(node); |
---|
148 | | - |
---|
149 | | - /* Allocate the private data and the DAI link array */ |
---|
150 | | - data = devm_kzalloc(dev, |
---|
151 | | - struct_size(data, dai_link, num_links), |
---|
152 | | - GFP_KERNEL); |
---|
153 | | - if (!data) |
---|
154 | | - return ERR_PTR(-ENOMEM); |
---|
155 | | - |
---|
156 | | - card->dai_link = &data->dai_link[0]; |
---|
157 | | - card->num_links = num_links; |
---|
158 | | - |
---|
159 | | - link = data->dai_link; |
---|
160 | | - |
---|
161 | | - for_each_child_of_node(node, np) { |
---|
162 | | - cpu = of_get_child_by_name(np, "cpu"); |
---|
163 | | - codec = of_get_child_by_name(np, "codec"); |
---|
164 | | - |
---|
165 | | - if (!cpu || !codec) { |
---|
166 | | - dev_err(dev, "Can't find cpu/codec DT node\n"); |
---|
167 | | - ret = -EINVAL; |
---|
168 | | - goto error; |
---|
169 | | - } |
---|
170 | | - |
---|
171 | | - link->cpu_of_node = of_parse_phandle(cpu, "sound-dai", 0); |
---|
172 | | - if (!link->cpu_of_node) { |
---|
173 | | - dev_err(card->dev, "error getting cpu phandle\n"); |
---|
174 | | - ret = -EINVAL; |
---|
175 | | - goto error; |
---|
176 | | - } |
---|
177 | | - |
---|
178 | | - ret = snd_soc_of_get_dai_name(cpu, &link->cpu_dai_name); |
---|
179 | | - if (ret) { |
---|
180 | | - dev_err(card->dev, "error getting cpu dai name\n"); |
---|
181 | | - goto error; |
---|
182 | | - } |
---|
183 | | - |
---|
184 | | - ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); |
---|
185 | | - |
---|
186 | | - if (ret < 0) { |
---|
187 | | - dev_err(card->dev, "error getting codec dai name\n"); |
---|
188 | | - goto error; |
---|
189 | | - } |
---|
190 | | - |
---|
191 | | - link->platform_of_node = link->cpu_of_node; |
---|
192 | | - ret = of_property_read_string(np, "link-name", &link->name); |
---|
193 | | - if (ret) { |
---|
194 | | - dev_err(card->dev, "error getting codec dai_link name\n"); |
---|
195 | | - goto error; |
---|
196 | | - } |
---|
197 | | - |
---|
198 | | - link->stream_name = link->name; |
---|
| 119 | + for_each_card_prelinks(card, i, link) |
---|
199 | 120 | link->init = apq8016_sbc_dai_init; |
---|
200 | | - link++; |
---|
201 | | - |
---|
202 | | - of_node_put(cpu); |
---|
203 | | - of_node_put(codec); |
---|
204 | | - } |
---|
205 | | - |
---|
206 | | - return data; |
---|
207 | | - |
---|
208 | | - error: |
---|
209 | | - of_node_put(np); |
---|
210 | | - of_node_put(cpu); |
---|
211 | | - of_node_put(codec); |
---|
212 | | - return ERR_PTR(ret); |
---|
213 | 121 | } |
---|
214 | 122 | |
---|
215 | 123 | static const struct snd_soc_dapm_widget apq8016_sbc_dapm_widgets[] = { |
---|
.. | .. |
---|
227 | 135 | struct snd_soc_card *card; |
---|
228 | 136 | struct apq8016_sbc_data *data; |
---|
229 | 137 | struct resource *res; |
---|
| 138 | + int ret; |
---|
230 | 139 | |
---|
231 | | - card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); |
---|
232 | | - if (!card) |
---|
| 140 | + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); |
---|
| 141 | + if (!data) |
---|
233 | 142 | return -ENOMEM; |
---|
234 | 143 | |
---|
| 144 | + card = &data->card; |
---|
235 | 145 | card->dev = dev; |
---|
236 | 146 | card->owner = THIS_MODULE; |
---|
237 | 147 | card->dapm_widgets = apq8016_sbc_dapm_widgets; |
---|
238 | 148 | card->num_dapm_widgets = ARRAY_SIZE(apq8016_sbc_dapm_widgets); |
---|
239 | | - data = apq8016_sbc_parse_of(card); |
---|
240 | | - if (IS_ERR(data)) { |
---|
241 | | - dev_err(&pdev->dev, "Error resolving dai links: %ld\n", |
---|
242 | | - PTR_ERR(data)); |
---|
243 | | - return PTR_ERR(data); |
---|
244 | | - } |
---|
| 149 | + |
---|
| 150 | + ret = qcom_snd_parse_of(card); |
---|
| 151 | + if (ret) |
---|
| 152 | + return ret; |
---|
245 | 153 | |
---|
246 | 154 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mic-iomux"); |
---|
247 | 155 | data->mic_iomux = devm_ioremap_resource(dev, res); |
---|
.. | .. |
---|
255 | 163 | |
---|
256 | 164 | snd_soc_card_set_drvdata(card, data); |
---|
257 | 165 | |
---|
| 166 | + apq8016_sbc_add_ops(card); |
---|
258 | 167 | return devm_snd_soc_register_card(&pdev->dev, card); |
---|
259 | 168 | } |
---|
260 | 169 | |
---|