1// SPDX-License-Identifier: GPL-2.0
2//
3// Socionext UniPhier AIO ALSA CPU DAI driver.
4//
5// Copyright (c) 2016-2018 Socionext Inc.
6
7#include <linux/clk.h>
8#include <linux/errno.h>
9#include <linux/kernel.h>
10#include <linux/mfd/syscon.h>
11#include <linux/module.h>
12#include <linux/of.h>
13#include <linux/of_platform.h>
14#include <linux/platform_device.h>
15#include <linux/reset.h>
16#include <sound/core.h>
17#include <sound/pcm.h>
18#include <sound/pcm_params.h>
19#include <sound/soc.h>
20
21#include "aio.h"
22
23static bool is_valid_pll(struct uniphier_aio_chip *chip, int pll_id)
24{
25	struct device *dev = &chip->pdev->dev;
26
27	if (pll_id < 0 || chip->num_plls <= pll_id) {
28		dev_err(dev, "PLL(%d) is not supported\n", pll_id);
29		return false;
30	}
31
32	return chip->plls[pll_id].enable;
33}
34
35/**
36 * find_volume - find volume supported HW port by HW port number
37 * @chip: the AIO chip pointer
38 * @oport_hw: HW port number, one of AUD_HW_XXXX
39 *
40 * Find AIO device from device list by HW port number. Volume feature is
41 * available only in Output and PCM ports, this limitation comes from HW
42 * specifications.
43 *
44 * Return: The pointer of AIO substream if successful, otherwise NULL on error.
45 */
46static struct uniphier_aio_sub *find_volume(struct uniphier_aio_chip *chip,
47					    int oport_hw)
48{
49	int i;
50
51	for (i = 0; i < chip->num_aios; i++) {
52		struct uniphier_aio_sub *sub = &chip->aios[i].sub[0];
53
54		if (!sub->swm)
55			continue;
56
57		if (sub->swm->oport.hw == oport_hw)
58			return sub;
59	}
60
61	return NULL;
62}
63
64static bool match_spec(const struct uniphier_aio_spec *spec,
65		       const char *name, int dir)
66{
67	if (dir == SNDRV_PCM_STREAM_PLAYBACK &&
68	    spec->swm.dir != PORT_DIR_OUTPUT) {
69		return false;
70	}
71
72	if (dir == SNDRV_PCM_STREAM_CAPTURE &&
73	    spec->swm.dir != PORT_DIR_INPUT) {
74		return false;
75	}
76
77	if (spec->name && strcmp(spec->name, name) == 0)
78		return true;
79
80	if (spec->gname && strcmp(spec->gname, name) == 0)
81		return true;
82
83	return false;
84}
85
86/**
87 * find_spec - find HW specification info by name
88 * @aio: the AIO device pointer
89 * @name: name of device
90 * @direction: the direction of substream, SNDRV_PCM_STREAM_*
91 *
92 * Find hardware specification information from list by device name. This
93 * information is used for telling the difference of SoCs to driver.
94 *
95 * Specification list is array of 'struct uniphier_aio_spec' which is defined
96 * in each drivers (see: aio-i2s.c).
97 *
98 * Return: The pointer of hardware specification of AIO if successful,
99 * otherwise NULL on error.
100 */
101static const struct uniphier_aio_spec *find_spec(struct uniphier_aio *aio,
102						 const char *name,
103						 int direction)
104{
105	const struct uniphier_aio_chip_spec *chip_spec = aio->chip->chip_spec;
106	int i;
107
108	for (i = 0; i < chip_spec->num_specs; i++) {
109		const struct uniphier_aio_spec *spec = &chip_spec->specs[i];
110
111		if (match_spec(spec, name, direction))
112			return spec;
113	}
114
115	return NULL;
116}
117
118/**
119 * find_divider - find clock divider by frequency
120 * @aio: the AIO device pointer
121 * @pll_id: PLL ID, should be AUD_PLL_XX
122 * @freq: required frequency
123 *
124 * Find suitable clock divider by frequency.
125 *
126 * Return: The ID of PLL if successful, otherwise negative error value.
127 */
128static int find_divider(struct uniphier_aio *aio, int pll_id, unsigned int freq)
129{
130	struct uniphier_aio_pll *pll;
131	static const int mul[] = { 1, 1, 1, 2, };
132	static const int div[] = { 2, 3, 1, 3, };
133	int i;
134
135	if (!is_valid_pll(aio->chip, pll_id))
136		return -EINVAL;
137
138	pll = &aio->chip->plls[pll_id];
139	for (i = 0; i < ARRAY_SIZE(mul); i++)
140		if (pll->freq * mul[i] / div[i] == freq)
141			return i;
142
143	return -ENOTSUPP;
144}
145
146static int uniphier_aio_set_sysclk(struct snd_soc_dai *dai, int clk_id,
147				   unsigned int freq, int dir)
148{
149	struct uniphier_aio *aio = uniphier_priv(dai);
150	struct device *dev = &aio->chip->pdev->dev;
151	bool pll_auto = false;
152	int pll_id, div_id;
153
154	switch (clk_id) {
155	case AUD_CLK_IO:
156		return -ENOTSUPP;
157	case AUD_CLK_A1:
158		pll_id = AUD_PLL_A1;
159		break;
160	case AUD_CLK_F1:
161		pll_id = AUD_PLL_F1;
162		break;
163	case AUD_CLK_A2:
164		pll_id = AUD_PLL_A2;
165		break;
166	case AUD_CLK_F2:
167		pll_id = AUD_PLL_F2;
168		break;
169	case AUD_CLK_A:
170		pll_id = AUD_PLL_A1;
171		pll_auto = true;
172		break;
173	case AUD_CLK_F:
174		pll_id = AUD_PLL_F1;
175		pll_auto = true;
176		break;
177	case AUD_CLK_APLL:
178		pll_id = AUD_PLL_APLL;
179		break;
180	case AUD_CLK_RX0:
181		pll_id = AUD_PLL_RX0;
182		break;
183	case AUD_CLK_USB0:
184		pll_id = AUD_PLL_USB0;
185		break;
186	case AUD_CLK_HSC0:
187		pll_id = AUD_PLL_HSC0;
188		break;
189	default:
190		dev_err(dev, "Sysclk(%d) is not supported\n", clk_id);
191		return -EINVAL;
192	}
193
194	if (pll_auto) {
195		for (pll_id = 0; pll_id < aio->chip->num_plls; pll_id++) {
196			div_id = find_divider(aio, pll_id, freq);
197			if (div_id >= 0) {
198				aio->plldiv = div_id;
199				break;
200			}
201		}
202		if (pll_id == aio->chip->num_plls) {
203			dev_err(dev, "Sysclk frequency is not supported(%d)\n",
204				freq);
205			return -EINVAL;
206		}
207	}
208
209	if (dir == SND_SOC_CLOCK_OUT)
210		aio->pll_out = pll_id;
211	else
212		aio->pll_in = pll_id;
213
214	return 0;
215}
216
217static int uniphier_aio_set_pll(struct snd_soc_dai *dai, int pll_id,
218				int source, unsigned int freq_in,
219				unsigned int freq_out)
220{
221	struct uniphier_aio *aio = uniphier_priv(dai);
222	int ret;
223
224	if (!is_valid_pll(aio->chip, pll_id))
225		return -EINVAL;
226
227	ret = aio_chip_set_pll(aio->chip, pll_id, freq_out);
228	if (ret < 0)
229		return ret;
230
231	return 0;
232}
233
234static int uniphier_aio_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
235{
236	struct uniphier_aio *aio = uniphier_priv(dai);
237	struct device *dev = &aio->chip->pdev->dev;
238
239	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
240	case SND_SOC_DAIFMT_LEFT_J:
241	case SND_SOC_DAIFMT_RIGHT_J:
242	case SND_SOC_DAIFMT_I2S:
243		aio->fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
244		break;
245	default:
246		dev_err(dev, "Format is not supported(%d)\n",
247			fmt & SND_SOC_DAIFMT_FORMAT_MASK);
248		return -EINVAL;
249	}
250
251	return 0;
252}
253
254static int uniphier_aio_startup(struct snd_pcm_substream *substream,
255				struct snd_soc_dai *dai)
256{
257	struct uniphier_aio *aio = uniphier_priv(dai);
258	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
259
260	sub->substream = substream;
261	sub->pass_through = 0;
262	sub->use_mmap = true;
263
264	return aio_init(sub);
265}
266
267static void uniphier_aio_shutdown(struct snd_pcm_substream *substream,
268				  struct snd_soc_dai *dai)
269{
270	struct uniphier_aio *aio = uniphier_priv(dai);
271	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
272
273	sub->substream = NULL;
274}
275
276static int uniphier_aio_hw_params(struct snd_pcm_substream *substream,
277				  struct snd_pcm_hw_params *params,
278				  struct snd_soc_dai *dai)
279{
280	struct uniphier_aio *aio = uniphier_priv(dai);
281	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
282	struct device *dev = &aio->chip->pdev->dev;
283	int freq, ret;
284
285	switch (params_rate(params)) {
286	case 48000:
287	case 32000:
288	case 24000:
289		freq = 12288000;
290		break;
291	case 44100:
292	case 22050:
293		freq = 11289600;
294		break;
295	default:
296		dev_err(dev, "Rate is not supported(%d)\n",
297			params_rate(params));
298		return -EINVAL;
299	}
300	ret = snd_soc_dai_set_sysclk(dai, AUD_CLK_A,
301				     freq, SND_SOC_CLOCK_OUT);
302	if (ret)
303		return ret;
304
305	sub->params = *params;
306	sub->setting = 1;
307
308	aio_port_reset(sub);
309	aio_port_set_volume(sub, sub->vol);
310	aio_src_reset(sub);
311
312	return 0;
313}
314
315static int uniphier_aio_hw_free(struct snd_pcm_substream *substream,
316				struct snd_soc_dai *dai)
317{
318	struct uniphier_aio *aio = uniphier_priv(dai);
319	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
320
321	sub->setting = 0;
322
323	return 0;
324}
325
326static int uniphier_aio_prepare(struct snd_pcm_substream *substream,
327				struct snd_soc_dai *dai)
328{
329	struct uniphier_aio *aio = uniphier_priv(dai);
330	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
331	int ret;
332
333	ret = aio_port_set_param(sub, sub->pass_through, &sub->params);
334	if (ret)
335		return ret;
336	ret = aio_src_set_param(sub, &sub->params);
337	if (ret)
338		return ret;
339	aio_port_set_enable(sub, 1);
340
341	ret = aio_if_set_param(sub, sub->pass_through);
342	if (ret)
343		return ret;
344
345	if (sub->swm->type == PORT_TYPE_CONV) {
346		ret = aio_srcif_set_param(sub);
347		if (ret)
348			return ret;
349		ret = aio_srcch_set_param(sub);
350		if (ret)
351			return ret;
352		aio_srcch_set_enable(sub, 1);
353	}
354
355	return 0;
356}
357
358static int uniphier_aio_dai_probe(struct snd_soc_dai *dai)
359{
360	struct uniphier_aio *aio = uniphier_priv(dai);
361	int i;
362
363	for (i = 0; i < ARRAY_SIZE(aio->sub); i++) {
364		struct uniphier_aio_sub *sub = &aio->sub[i];
365		const struct uniphier_aio_spec *spec;
366
367		spec = find_spec(aio, dai->name, i);
368		if (!spec)
369			continue;
370
371		sub->swm = &spec->swm;
372		sub->spec = spec;
373
374		sub->vol = AUD_VOL_INIT;
375	}
376
377	aio_iecout_set_enable(aio->chip, true);
378	aio_chip_init(aio->chip);
379	aio->chip->active = 1;
380
381	return 0;
382}
383
384static int uniphier_aio_dai_remove(struct snd_soc_dai *dai)
385{
386	struct uniphier_aio *aio = uniphier_priv(dai);
387
388	aio->chip->active = 0;
389
390	return 0;
391}
392
393static int uniphier_aio_ld11_probe(struct snd_soc_dai *dai)
394{
395	int ret;
396
397	ret = uniphier_aio_dai_probe(dai);
398	if (ret < 0)
399		return ret;
400
401	ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000);
402	if (ret < 0)
403		return ret;
404	ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000);
405	if (ret < 0)
406		return ret;
407
408	ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800);
409	if (ret < 0)
410		return ret;
411	ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800);
412	if (ret < 0)
413		return ret;
414
415	return 0;
416}
417
418static int uniphier_aio_pxs2_probe(struct snd_soc_dai *dai)
419{
420	int ret;
421
422	ret = uniphier_aio_dai_probe(dai);
423	if (ret < 0)
424		return ret;
425
426	ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000);
427	if (ret < 0)
428		return ret;
429	ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000);
430	if (ret < 0)
431		return ret;
432
433	ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800);
434	if (ret < 0)
435		return ret;
436	ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800);
437	if (ret < 0)
438		return ret;
439
440	return 0;
441}
442
443const struct snd_soc_dai_ops uniphier_aio_i2s_ld11_ops = {
444	.probe		= uniphier_aio_ld11_probe,
445	.remove		= uniphier_aio_dai_remove,
446	.set_sysclk	= uniphier_aio_set_sysclk,
447	.set_pll	= uniphier_aio_set_pll,
448	.set_fmt	= uniphier_aio_set_fmt,
449	.startup	= uniphier_aio_startup,
450	.shutdown	= uniphier_aio_shutdown,
451	.hw_params	= uniphier_aio_hw_params,
452	.hw_free	= uniphier_aio_hw_free,
453	.prepare	= uniphier_aio_prepare,
454};
455EXPORT_SYMBOL_GPL(uniphier_aio_i2s_ld11_ops);
456
457const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops = {
458	.probe		= uniphier_aio_ld11_probe,
459	.remove		= uniphier_aio_dai_remove,
460	.set_sysclk	= uniphier_aio_set_sysclk,
461	.set_pll	= uniphier_aio_set_pll,
462	.startup	= uniphier_aio_startup,
463	.shutdown	= uniphier_aio_shutdown,
464	.hw_params	= uniphier_aio_hw_params,
465	.hw_free	= uniphier_aio_hw_free,
466	.prepare	= uniphier_aio_prepare,
467};
468EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ld11_ops);
469
470const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops2 = {
471	.probe		= uniphier_aio_ld11_probe,
472	.remove		= uniphier_aio_dai_remove,
473	.set_sysclk	= uniphier_aio_set_sysclk,
474	.set_pll	= uniphier_aio_set_pll,
475	.startup	= uniphier_aio_startup,
476	.shutdown	= uniphier_aio_shutdown,
477	.hw_params	= uniphier_aio_hw_params,
478	.hw_free	= uniphier_aio_hw_free,
479	.prepare	= uniphier_aio_prepare,
480	.compress_new	= snd_soc_new_compress,
481};
482EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ld11_ops2);
483
484const struct snd_soc_dai_ops uniphier_aio_i2s_pxs2_ops = {
485	.probe		= uniphier_aio_pxs2_probe,
486	.remove		= uniphier_aio_dai_remove,
487	.set_sysclk	= uniphier_aio_set_sysclk,
488	.set_pll	= uniphier_aio_set_pll,
489	.set_fmt	= uniphier_aio_set_fmt,
490	.startup	= uniphier_aio_startup,
491	.shutdown	= uniphier_aio_shutdown,
492	.hw_params	= uniphier_aio_hw_params,
493	.hw_free	= uniphier_aio_hw_free,
494	.prepare	= uniphier_aio_prepare,
495};
496EXPORT_SYMBOL_GPL(uniphier_aio_i2s_pxs2_ops);
497
498const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops = {
499	.probe		= uniphier_aio_pxs2_probe,
500	.remove		= uniphier_aio_dai_remove,
501	.set_sysclk	= uniphier_aio_set_sysclk,
502	.set_pll	= uniphier_aio_set_pll,
503	.startup	= uniphier_aio_startup,
504	.shutdown	= uniphier_aio_shutdown,
505	.hw_params	= uniphier_aio_hw_params,
506	.hw_free	= uniphier_aio_hw_free,
507	.prepare	= uniphier_aio_prepare,
508};
509EXPORT_SYMBOL_GPL(uniphier_aio_spdif_pxs2_ops);
510
511const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops2 = {
512	.probe		= uniphier_aio_pxs2_probe,
513	.remove		= uniphier_aio_dai_remove,
514	.set_sysclk	= uniphier_aio_set_sysclk,
515	.set_pll	= uniphier_aio_set_pll,
516	.startup	= uniphier_aio_startup,
517	.shutdown	= uniphier_aio_shutdown,
518	.hw_params	= uniphier_aio_hw_params,
519	.hw_free	= uniphier_aio_hw_free,
520	.prepare	= uniphier_aio_prepare,
521	.compress_new	= snd_soc_new_compress,
522};
523EXPORT_SYMBOL_GPL(uniphier_aio_spdif_pxs2_ops2);
524
525static void uniphier_aio_dai_suspend(struct snd_soc_dai *dai)
526{
527	struct uniphier_aio *aio = uniphier_priv(dai);
528
529	if (!snd_soc_dai_active(dai))
530		return;
531
532	aio->chip->num_wup_aios--;
533	if (!aio->chip->num_wup_aios) {
534		reset_control_assert(aio->chip->rst);
535		clk_disable_unprepare(aio->chip->clk);
536	}
537}
538
539static int uniphier_aio_suspend(struct snd_soc_component *component)
540{
541	struct snd_soc_dai *dai;
542
543	for_each_component_dais(component, dai)
544		uniphier_aio_dai_suspend(dai);
545	return 0;
546}
547
548static int uniphier_aio_dai_resume(struct snd_soc_dai *dai)
549{
550	struct uniphier_aio *aio = uniphier_priv(dai);
551	int ret, i;
552
553	if (!snd_soc_dai_active(dai))
554		return 0;
555
556	if (!aio->chip->active)
557		return 0;
558
559	if (!aio->chip->num_wup_aios) {
560		ret = clk_prepare_enable(aio->chip->clk);
561		if (ret)
562			return ret;
563
564		ret = reset_control_deassert(aio->chip->rst);
565		if (ret)
566			goto err_out_clock;
567	}
568
569	aio_iecout_set_enable(aio->chip, true);
570	aio_chip_init(aio->chip);
571
572	for (i = 0; i < ARRAY_SIZE(aio->sub); i++) {
573		struct uniphier_aio_sub *sub = &aio->sub[i];
574
575		if (!sub->spec || !sub->substream)
576			continue;
577
578		ret = aio_init(sub);
579		if (ret)
580			goto err_out_reset;
581
582		if (!sub->setting)
583			continue;
584
585		aio_port_reset(sub);
586		aio_src_reset(sub);
587	}
588	aio->chip->num_wup_aios++;
589
590	return 0;
591
592err_out_reset:
593	if (!aio->chip->num_wup_aios)
594		reset_control_assert(aio->chip->rst);
595err_out_clock:
596	if (!aio->chip->num_wup_aios)
597		clk_disable_unprepare(aio->chip->clk);
598
599	return ret;
600}
601
602static int uniphier_aio_resume(struct snd_soc_component *component)
603{
604	struct snd_soc_dai *dai;
605	int ret = 0;
606
607	for_each_component_dais(component, dai)
608		ret |= uniphier_aio_dai_resume(dai);
609	return ret;
610}
611
612static int uniphier_aio_vol_info(struct snd_kcontrol *kcontrol,
613				 struct snd_ctl_elem_info *uinfo)
614{
615	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
616	uinfo->count = 1;
617	uinfo->value.integer.min = 0;
618	uinfo->value.integer.max = AUD_VOL_MAX;
619
620	return 0;
621}
622
623static int uniphier_aio_vol_get(struct snd_kcontrol *kcontrol,
624				struct snd_ctl_elem_value *ucontrol)
625{
626	struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
627	struct uniphier_aio_chip *chip = snd_soc_component_get_drvdata(comp);
628	struct uniphier_aio_sub *sub;
629	int oport_hw = kcontrol->private_value;
630
631	sub = find_volume(chip, oport_hw);
632	if (!sub)
633		return 0;
634
635	ucontrol->value.integer.value[0] = sub->vol;
636
637	return 0;
638}
639
640static int uniphier_aio_vol_put(struct snd_kcontrol *kcontrol,
641				struct snd_ctl_elem_value *ucontrol)
642{
643	struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
644	struct uniphier_aio_chip *chip = snd_soc_component_get_drvdata(comp);
645	struct uniphier_aio_sub *sub;
646	int oport_hw = kcontrol->private_value;
647
648	sub = find_volume(chip, oport_hw);
649	if (!sub)
650		return 0;
651
652	if (sub->vol == ucontrol->value.integer.value[0])
653		return 0;
654	sub->vol = ucontrol->value.integer.value[0];
655
656	aio_port_set_volume(sub, sub->vol);
657
658	return 0;
659}
660
661static const struct snd_kcontrol_new uniphier_aio_controls[] = {
662	{
663		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
664		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
665		.name = "HPCMOUT1 Volume",
666		.info = uniphier_aio_vol_info,
667		.get = uniphier_aio_vol_get,
668		.put = uniphier_aio_vol_put,
669		.private_value = AUD_HW_HPCMOUT1,
670	},
671	{
672		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
673		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
674		.name = "PCMOUT1 Volume",
675		.info = uniphier_aio_vol_info,
676		.get = uniphier_aio_vol_get,
677		.put = uniphier_aio_vol_put,
678		.private_value = AUD_HW_PCMOUT1,
679	},
680	{
681		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
682		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
683		.name = "PCMOUT2 Volume",
684		.info = uniphier_aio_vol_info,
685		.get = uniphier_aio_vol_get,
686		.put = uniphier_aio_vol_put,
687		.private_value = AUD_HW_PCMOUT2,
688	},
689	{
690		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
691		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
692		.name = "PCMOUT3 Volume",
693		.info = uniphier_aio_vol_info,
694		.get = uniphier_aio_vol_get,
695		.put = uniphier_aio_vol_put,
696		.private_value = AUD_HW_PCMOUT3,
697	},
698	{
699		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
700		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
701		.name = "HIECOUT1 Volume",
702		.info = uniphier_aio_vol_info,
703		.get = uniphier_aio_vol_get,
704		.put = uniphier_aio_vol_put,
705		.private_value = AUD_HW_HIECOUT1,
706	},
707	{
708		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
709		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
710		.name = "IECOUT1 Volume",
711		.info = uniphier_aio_vol_info,
712		.get = uniphier_aio_vol_get,
713		.put = uniphier_aio_vol_put,
714		.private_value = AUD_HW_IECOUT1,
715	},
716};
717
718static const struct snd_soc_component_driver uniphier_aio_component = {
719	.name = "uniphier-aio",
720	.controls = uniphier_aio_controls,
721	.num_controls = ARRAY_SIZE(uniphier_aio_controls),
722	.suspend = uniphier_aio_suspend,
723	.resume  = uniphier_aio_resume,
724};
725
726int uniphier_aio_probe(struct platform_device *pdev)
727{
728	struct uniphier_aio_chip *chip;
729	struct device *dev = &pdev->dev;
730	int ret, i, j;
731
732	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
733	if (!chip)
734		return -ENOMEM;
735
736	chip->chip_spec = of_device_get_match_data(dev);
737	if (!chip->chip_spec)
738		return -EINVAL;
739
740	chip->regmap_sg = syscon_regmap_lookup_by_phandle(dev->of_node,
741							  "socionext,syscon");
742	if (IS_ERR(chip->regmap_sg)) {
743		if (PTR_ERR(chip->regmap_sg) == -EPROBE_DEFER)
744			return -EPROBE_DEFER;
745		chip->regmap_sg = NULL;
746	}
747
748	chip->clk = devm_clk_get(dev, "aio");
749	if (IS_ERR(chip->clk))
750		return PTR_ERR(chip->clk);
751
752	chip->rst = devm_reset_control_get_shared(dev, "aio");
753	if (IS_ERR(chip->rst))
754		return PTR_ERR(chip->rst);
755
756	chip->num_aios = chip->chip_spec->num_dais;
757	chip->num_wup_aios = chip->num_aios;
758	chip->aios = devm_kcalloc(dev,
759				  chip->num_aios, sizeof(struct uniphier_aio),
760				  GFP_KERNEL);
761	if (!chip->aios)
762		return -ENOMEM;
763
764	chip->num_plls = chip->chip_spec->num_plls;
765	chip->plls = devm_kcalloc(dev,
766				  chip->num_plls,
767				  sizeof(struct uniphier_aio_pll),
768				  GFP_KERNEL);
769	if (!chip->plls)
770		return -ENOMEM;
771	memcpy(chip->plls, chip->chip_spec->plls,
772	       sizeof(struct uniphier_aio_pll) * chip->num_plls);
773
774	for (i = 0; i < chip->num_aios; i++) {
775		struct uniphier_aio *aio = &chip->aios[i];
776
777		aio->chip = chip;
778		aio->fmt = SND_SOC_DAIFMT_I2S;
779
780		for (j = 0; j < ARRAY_SIZE(aio->sub); j++) {
781			struct uniphier_aio_sub *sub = &aio->sub[j];
782
783			sub->aio = aio;
784			spin_lock_init(&sub->lock);
785		}
786	}
787
788	chip->pdev = pdev;
789	platform_set_drvdata(pdev, chip);
790
791	ret = clk_prepare_enable(chip->clk);
792	if (ret)
793		return ret;
794
795	ret = reset_control_deassert(chip->rst);
796	if (ret)
797		goto err_out_clock;
798
799	ret = devm_snd_soc_register_component(dev, &uniphier_aio_component,
800					      chip->chip_spec->dais,
801					      chip->chip_spec->num_dais);
802	if (ret) {
803		dev_err(dev, "Register component failed.\n");
804		goto err_out_reset;
805	}
806
807	ret = uniphier_aiodma_soc_register_platform(pdev);
808	if (ret) {
809		dev_err(dev, "Register platform failed.\n");
810		goto err_out_reset;
811	}
812
813	return 0;
814
815err_out_reset:
816	reset_control_assert(chip->rst);
817
818err_out_clock:
819	clk_disable_unprepare(chip->clk);
820
821	return ret;
822}
823EXPORT_SYMBOL_GPL(uniphier_aio_probe);
824
825int uniphier_aio_remove(struct platform_device *pdev)
826{
827	struct uniphier_aio_chip *chip = platform_get_drvdata(pdev);
828
829	reset_control_assert(chip->rst);
830	clk_disable_unprepare(chip->clk);
831
832	return 0;
833}
834EXPORT_SYMBOL_GPL(uniphier_aio_remove);
835
836MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
837MODULE_DESCRIPTION("UniPhier AIO CPU DAI driver.");
838MODULE_LICENSE("GPL v2");
839