xref: /linux/sound/soc/meson/axg-tdm-formatter.c (revision ebf68996de0ab250c5d520eb2291ab65643e9a1e)
1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2 //
3 // Copyright (c) 2018 BayLibre, SAS.
4 // Author: Jerome Brunet <jbrunet@baylibre.com>
5 
6 #include <linux/clk.h>
7 #include <linux/module.h>
8 #include <linux/of_platform.h>
9 #include <linux/regmap.h>
10 #include <sound/soc.h>
11 
12 #include "axg-tdm-formatter.h"
13 
14 struct axg_tdm_formatter {
15 	struct list_head list;
16 	struct axg_tdm_stream *stream;
17 	const struct axg_tdm_formatter_driver *drv;
18 	struct clk *pclk;
19 	struct clk *sclk;
20 	struct clk *lrclk;
21 	struct clk *sclk_sel;
22 	struct clk *lrclk_sel;
23 	bool enabled;
24 	struct regmap *map;
25 };
26 
27 int axg_tdm_formatter_set_channel_masks(struct regmap *map,
28 					struct axg_tdm_stream *ts,
29 					unsigned int offset)
30 {
31 	unsigned int val, ch = ts->channels;
32 	unsigned long mask;
33 	int i, j;
34 
35 	/*
36 	 * Distribute the channels of the stream over the available slots
37 	 * of each TDM lane
38 	 */
39 	for (i = 0; i < AXG_TDM_NUM_LANES; i++) {
40 		val = 0;
41 		mask = ts->mask[i];
42 
43 		for (j = find_first_bit(&mask, 32);
44 		     (j < 32) && ch;
45 		     j = find_next_bit(&mask, 32, j + 1)) {
46 			val |= 1 << j;
47 			ch -= 1;
48 		}
49 
50 		regmap_write(map, offset, val);
51 		offset += regmap_get_reg_stride(map);
52 	}
53 
54 	/*
55 	 * If we still have channel left at the end of the process, it means
56 	 * the stream has more channels than we can accommodate and we should
57 	 * have caught this earlier.
58 	 */
59 	if (WARN_ON(ch != 0)) {
60 		pr_err("channel mask error\n");
61 		return -EINVAL;
62 	}
63 
64 	return 0;
65 }
66 EXPORT_SYMBOL_GPL(axg_tdm_formatter_set_channel_masks);
67 
68 static int axg_tdm_formatter_enable(struct axg_tdm_formatter *formatter)
69 {
70 	struct axg_tdm_stream *ts = formatter->stream;
71 	bool invert = formatter->drv->quirks->invert_sclk;
72 	int ret;
73 
74 	/* Do nothing if the formatter is already enabled */
75 	if (formatter->enabled)
76 		return 0;
77 
78 	/*
79 	 * If sclk is inverted, invert it back and provide the inversion
80 	 * required by the formatter
81 	 */
82 	invert ^= axg_tdm_sclk_invert(ts->iface->fmt);
83 	ret = clk_set_phase(formatter->sclk, invert ? 180 : 0);
84 	if (ret)
85 		return ret;
86 
87 	/* Setup the stream parameter in the formatter */
88 	ret = formatter->drv->ops->prepare(formatter->map,
89 					   formatter->drv->quirks,
90 					   formatter->stream);
91 	if (ret)
92 		return ret;
93 
94 	/* Enable the signal clocks feeding the formatter */
95 	ret = clk_prepare_enable(formatter->sclk);
96 	if (ret)
97 		return ret;
98 
99 	ret = clk_prepare_enable(formatter->lrclk);
100 	if (ret) {
101 		clk_disable_unprepare(formatter->sclk);
102 		return ret;
103 	}
104 
105 	/* Finally, actually enable the formatter */
106 	formatter->drv->ops->enable(formatter->map);
107 	formatter->enabled = true;
108 
109 	return 0;
110 }
111 
112 static void axg_tdm_formatter_disable(struct axg_tdm_formatter *formatter)
113 {
114 	/* Do nothing if the formatter is already disabled */
115 	if (!formatter->enabled)
116 		return;
117 
118 	formatter->drv->ops->disable(formatter->map);
119 	clk_disable_unprepare(formatter->lrclk);
120 	clk_disable_unprepare(formatter->sclk);
121 	formatter->enabled = false;
122 }
123 
124 static int axg_tdm_formatter_attach(struct axg_tdm_formatter *formatter)
125 {
126 	struct axg_tdm_stream *ts = formatter->stream;
127 	int ret = 0;
128 
129 	mutex_lock(&ts->lock);
130 
131 	/* Catch up if the stream is already running when we attach */
132 	if (ts->ready) {
133 		ret = axg_tdm_formatter_enable(formatter);
134 		if (ret) {
135 			pr_err("failed to enable formatter\n");
136 			goto out;
137 		}
138 	}
139 
140 	list_add_tail(&formatter->list, &ts->formatter_list);
141 out:
142 	mutex_unlock(&ts->lock);
143 	return ret;
144 }
145 
146 static void axg_tdm_formatter_dettach(struct axg_tdm_formatter *formatter)
147 {
148 	struct axg_tdm_stream *ts = formatter->stream;
149 
150 	mutex_lock(&ts->lock);
151 	list_del(&formatter->list);
152 	mutex_unlock(&ts->lock);
153 
154 	axg_tdm_formatter_disable(formatter);
155 }
156 
157 static int axg_tdm_formatter_power_up(struct axg_tdm_formatter *formatter,
158 				      struct snd_soc_dapm_widget *w)
159 {
160 	struct axg_tdm_stream *ts = formatter->drv->ops->get_stream(w);
161 	int ret;
162 
163 	/*
164 	 * If we don't get a stream at this stage, it would mean that the
165 	 * widget is powering up but is not attached to any backend DAI.
166 	 * It should not happen, ever !
167 	 */
168 	if (WARN_ON(!ts))
169 		return -ENODEV;
170 
171 	/* Clock our device */
172 	ret = clk_prepare_enable(formatter->pclk);
173 	if (ret)
174 		return ret;
175 
176 	/* Reparent the bit clock to the TDM interface */
177 	ret = clk_set_parent(formatter->sclk_sel, ts->iface->sclk);
178 	if (ret)
179 		goto disable_pclk;
180 
181 	/* Reparent the sample clock to the TDM interface */
182 	ret = clk_set_parent(formatter->lrclk_sel, ts->iface->lrclk);
183 	if (ret)
184 		goto disable_pclk;
185 
186 	formatter->stream = ts;
187 	ret = axg_tdm_formatter_attach(formatter);
188 	if (ret)
189 		goto disable_pclk;
190 
191 	return 0;
192 
193 disable_pclk:
194 	clk_disable_unprepare(formatter->pclk);
195 	return ret;
196 }
197 
198 static void axg_tdm_formatter_power_down(struct axg_tdm_formatter *formatter)
199 {
200 	axg_tdm_formatter_dettach(formatter);
201 	clk_disable_unprepare(formatter->pclk);
202 	formatter->stream = NULL;
203 }
204 
205 int axg_tdm_formatter_event(struct snd_soc_dapm_widget *w,
206 			    struct snd_kcontrol *control,
207 			    int event)
208 {
209 	struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
210 	struct axg_tdm_formatter *formatter = snd_soc_component_get_drvdata(c);
211 	int ret = 0;
212 
213 	switch (event) {
214 	case SND_SOC_DAPM_PRE_PMU:
215 		ret = axg_tdm_formatter_power_up(formatter, w);
216 		break;
217 
218 	case SND_SOC_DAPM_PRE_PMD:
219 		axg_tdm_formatter_power_down(formatter);
220 		break;
221 
222 	default:
223 		dev_err(c->dev, "Unexpected event %d\n", event);
224 		return -EINVAL;
225 	}
226 
227 	return ret;
228 }
229 EXPORT_SYMBOL_GPL(axg_tdm_formatter_event);
230 
231 int axg_tdm_formatter_probe(struct platform_device *pdev)
232 {
233 	struct device *dev = &pdev->dev;
234 	const struct axg_tdm_formatter_driver *drv;
235 	struct axg_tdm_formatter *formatter;
236 	struct resource *res;
237 	void __iomem *regs;
238 	int ret;
239 
240 	drv = of_device_get_match_data(dev);
241 	if (!drv) {
242 		dev_err(dev, "failed to match device\n");
243 		return -ENODEV;
244 	}
245 
246 	formatter = devm_kzalloc(dev, sizeof(*formatter), GFP_KERNEL);
247 	if (!formatter)
248 		return -ENOMEM;
249 	platform_set_drvdata(pdev, formatter);
250 	formatter->drv = drv;
251 
252 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
253 	regs = devm_ioremap_resource(dev, res);
254 	if (IS_ERR(regs))
255 		return PTR_ERR(regs);
256 
257 	formatter->map = devm_regmap_init_mmio(dev, regs, drv->regmap_cfg);
258 	if (IS_ERR(formatter->map)) {
259 		dev_err(dev, "failed to init regmap: %ld\n",
260 			PTR_ERR(formatter->map));
261 		return PTR_ERR(formatter->map);
262 	}
263 
264 	/* Peripharal clock */
265 	formatter->pclk = devm_clk_get(dev, "pclk");
266 	if (IS_ERR(formatter->pclk)) {
267 		ret = PTR_ERR(formatter->pclk);
268 		if (ret != -EPROBE_DEFER)
269 			dev_err(dev, "failed to get pclk: %d\n", ret);
270 		return ret;
271 	}
272 
273 	/* Formatter bit clock */
274 	formatter->sclk = devm_clk_get(dev, "sclk");
275 	if (IS_ERR(formatter->sclk)) {
276 		ret = PTR_ERR(formatter->sclk);
277 		if (ret != -EPROBE_DEFER)
278 			dev_err(dev, "failed to get sclk: %d\n", ret);
279 		return ret;
280 	}
281 
282 	/* Formatter sample clock */
283 	formatter->lrclk = devm_clk_get(dev, "lrclk");
284 	if (IS_ERR(formatter->lrclk)) {
285 		ret = PTR_ERR(formatter->lrclk);
286 		if (ret != -EPROBE_DEFER)
287 			dev_err(dev, "failed to get lrclk: %d\n", ret);
288 		return ret;
289 	}
290 
291 	/* Formatter bit clock input multiplexer */
292 	formatter->sclk_sel = devm_clk_get(dev, "sclk_sel");
293 	if (IS_ERR(formatter->sclk_sel)) {
294 		ret = PTR_ERR(formatter->sclk_sel);
295 		if (ret != -EPROBE_DEFER)
296 			dev_err(dev, "failed to get sclk_sel: %d\n", ret);
297 		return ret;
298 	}
299 
300 	/* Formatter sample clock input multiplexer */
301 	formatter->lrclk_sel = devm_clk_get(dev, "lrclk_sel");
302 	if (IS_ERR(formatter->lrclk_sel)) {
303 		ret = PTR_ERR(formatter->lrclk_sel);
304 		if (ret != -EPROBE_DEFER)
305 			dev_err(dev, "failed to get lrclk_sel: %d\n", ret);
306 		return ret;
307 	}
308 
309 	return devm_snd_soc_register_component(dev, drv->component_drv,
310 					       NULL, 0);
311 }
312 EXPORT_SYMBOL_GPL(axg_tdm_formatter_probe);
313 
314 int axg_tdm_stream_start(struct axg_tdm_stream *ts)
315 {
316 	struct axg_tdm_formatter *formatter;
317 	int ret = 0;
318 
319 	mutex_lock(&ts->lock);
320 	ts->ready = true;
321 
322 	/* Start all the formatters attached to the stream */
323 	list_for_each_entry(formatter, &ts->formatter_list, list) {
324 		ret = axg_tdm_formatter_enable(formatter);
325 		if (ret) {
326 			pr_err("failed to start tdm stream\n");
327 			goto out;
328 		}
329 	}
330 
331 out:
332 	mutex_unlock(&ts->lock);
333 	return ret;
334 }
335 EXPORT_SYMBOL_GPL(axg_tdm_stream_start);
336 
337 void axg_tdm_stream_stop(struct axg_tdm_stream *ts)
338 {
339 	struct axg_tdm_formatter *formatter;
340 
341 	mutex_lock(&ts->lock);
342 	ts->ready = false;
343 
344 	/* Stop all the formatters attached to the stream */
345 	list_for_each_entry(formatter, &ts->formatter_list, list) {
346 		axg_tdm_formatter_disable(formatter);
347 	}
348 
349 	mutex_unlock(&ts->lock);
350 }
351 EXPORT_SYMBOL_GPL(axg_tdm_stream_stop);
352 
353 struct axg_tdm_stream *axg_tdm_stream_alloc(struct axg_tdm_iface *iface)
354 {
355 	struct axg_tdm_stream *ts;
356 
357 	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
358 	if (ts) {
359 		INIT_LIST_HEAD(&ts->formatter_list);
360 		mutex_init(&ts->lock);
361 		ts->iface = iface;
362 	}
363 
364 	return ts;
365 }
366 EXPORT_SYMBOL_GPL(axg_tdm_stream_alloc);
367 
368 void axg_tdm_stream_free(struct axg_tdm_stream *ts)
369 {
370 	/*
371 	 * If the list is not empty, it would mean that one of the formatter
372 	 * widget is still powered and attached to the interface while we
373 	 * we are removing the TDM DAI. It should not be possible
374 	 */
375 	WARN_ON(!list_empty(&ts->formatter_list));
376 	mutex_destroy(&ts->lock);
377 	kfree(ts);
378 }
379 EXPORT_SYMBOL_GPL(axg_tdm_stream_free);
380 
381 MODULE_DESCRIPTION("Amlogic AXG TDM formatter driver");
382 MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
383 MODULE_LICENSE("GPL v2");
384