xref: /openbmc/linux/sound/soc/uniphier/aio-cpu.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1139a3420SKatsuhiro Suzuki // SPDX-License-Identifier: GPL-2.0
2139a3420SKatsuhiro Suzuki //
3139a3420SKatsuhiro Suzuki // Socionext UniPhier AIO ALSA CPU DAI driver.
4139a3420SKatsuhiro Suzuki //
5139a3420SKatsuhiro Suzuki // Copyright (c) 2016-2018 Socionext Inc.
6139a3420SKatsuhiro Suzuki 
7139a3420SKatsuhiro Suzuki #include <linux/clk.h>
8139a3420SKatsuhiro Suzuki #include <linux/errno.h>
9139a3420SKatsuhiro Suzuki #include <linux/kernel.h>
107c3c20f2SKatsuhiro Suzuki #include <linux/mfd/syscon.h>
11139a3420SKatsuhiro Suzuki #include <linux/module.h>
12139a3420SKatsuhiro Suzuki #include <linux/of.h>
13139a3420SKatsuhiro Suzuki #include <linux/of_platform.h>
14139a3420SKatsuhiro Suzuki #include <linux/platform_device.h>
15139a3420SKatsuhiro Suzuki #include <linux/reset.h>
16139a3420SKatsuhiro Suzuki #include <sound/core.h>
17139a3420SKatsuhiro Suzuki #include <sound/pcm.h>
18139a3420SKatsuhiro Suzuki #include <sound/pcm_params.h>
19139a3420SKatsuhiro Suzuki #include <sound/soc.h>
20139a3420SKatsuhiro Suzuki 
21139a3420SKatsuhiro Suzuki #include "aio.h"
22139a3420SKatsuhiro Suzuki 
is_valid_pll(struct uniphier_aio_chip * chip,int pll_id)23139a3420SKatsuhiro Suzuki static bool is_valid_pll(struct uniphier_aio_chip *chip, int pll_id)
24139a3420SKatsuhiro Suzuki {
25139a3420SKatsuhiro Suzuki 	struct device *dev = &chip->pdev->dev;
26139a3420SKatsuhiro Suzuki 
27139a3420SKatsuhiro Suzuki 	if (pll_id < 0 || chip->num_plls <= pll_id) {
28139a3420SKatsuhiro Suzuki 		dev_err(dev, "PLL(%d) is not supported\n", pll_id);
29139a3420SKatsuhiro Suzuki 		return false;
30139a3420SKatsuhiro Suzuki 	}
31139a3420SKatsuhiro Suzuki 
32139a3420SKatsuhiro Suzuki 	return chip->plls[pll_id].enable;
33139a3420SKatsuhiro Suzuki }
34139a3420SKatsuhiro Suzuki 
355a748de0SKatsuhiro Suzuki /**
365a748de0SKatsuhiro Suzuki  * find_volume - find volume supported HW port by HW port number
375a748de0SKatsuhiro Suzuki  * @chip: the AIO chip pointer
385a748de0SKatsuhiro Suzuki  * @oport_hw: HW port number, one of AUD_HW_XXXX
395a748de0SKatsuhiro Suzuki  *
405a748de0SKatsuhiro Suzuki  * Find AIO device from device list by HW port number. Volume feature is
415a748de0SKatsuhiro Suzuki  * available only in Output and PCM ports, this limitation comes from HW
425a748de0SKatsuhiro Suzuki  * specifications.
435a748de0SKatsuhiro Suzuki  *
445a748de0SKatsuhiro Suzuki  * Return: The pointer of AIO substream if successful, otherwise NULL on error.
455a748de0SKatsuhiro Suzuki  */
find_volume(struct uniphier_aio_chip * chip,int oport_hw)465a748de0SKatsuhiro Suzuki static struct uniphier_aio_sub *find_volume(struct uniphier_aio_chip *chip,
475a748de0SKatsuhiro Suzuki 					    int oport_hw)
485a748de0SKatsuhiro Suzuki {
495a748de0SKatsuhiro Suzuki 	int i;
505a748de0SKatsuhiro Suzuki 
515a748de0SKatsuhiro Suzuki 	for (i = 0; i < chip->num_aios; i++) {
525a748de0SKatsuhiro Suzuki 		struct uniphier_aio_sub *sub = &chip->aios[i].sub[0];
535a748de0SKatsuhiro Suzuki 
545a748de0SKatsuhiro Suzuki 		if (!sub->swm)
555a748de0SKatsuhiro Suzuki 			continue;
565a748de0SKatsuhiro Suzuki 
575a748de0SKatsuhiro Suzuki 		if (sub->swm->oport.hw == oport_hw)
585a748de0SKatsuhiro Suzuki 			return sub;
595a748de0SKatsuhiro Suzuki 	}
605a748de0SKatsuhiro Suzuki 
615a748de0SKatsuhiro Suzuki 	return NULL;
625a748de0SKatsuhiro Suzuki }
635a748de0SKatsuhiro Suzuki 
match_spec(const struct uniphier_aio_spec * spec,const char * name,int dir)64139a3420SKatsuhiro Suzuki static bool match_spec(const struct uniphier_aio_spec *spec,
65139a3420SKatsuhiro Suzuki 		       const char *name, int dir)
66139a3420SKatsuhiro Suzuki {
67139a3420SKatsuhiro Suzuki 	if (dir == SNDRV_PCM_STREAM_PLAYBACK &&
68139a3420SKatsuhiro Suzuki 	    spec->swm.dir != PORT_DIR_OUTPUT) {
69139a3420SKatsuhiro Suzuki 		return false;
70139a3420SKatsuhiro Suzuki 	}
71139a3420SKatsuhiro Suzuki 
72139a3420SKatsuhiro Suzuki 	if (dir == SNDRV_PCM_STREAM_CAPTURE &&
73139a3420SKatsuhiro Suzuki 	    spec->swm.dir != PORT_DIR_INPUT) {
74139a3420SKatsuhiro Suzuki 		return false;
75139a3420SKatsuhiro Suzuki 	}
76139a3420SKatsuhiro Suzuki 
77139a3420SKatsuhiro Suzuki 	if (spec->name && strcmp(spec->name, name) == 0)
78139a3420SKatsuhiro Suzuki 		return true;
79139a3420SKatsuhiro Suzuki 
80139a3420SKatsuhiro Suzuki 	if (spec->gname && strcmp(spec->gname, name) == 0)
81139a3420SKatsuhiro Suzuki 		return true;
82139a3420SKatsuhiro Suzuki 
83139a3420SKatsuhiro Suzuki 	return false;
84139a3420SKatsuhiro Suzuki }
85139a3420SKatsuhiro Suzuki 
86139a3420SKatsuhiro Suzuki /**
87139a3420SKatsuhiro Suzuki  * find_spec - find HW specification info by name
88139a3420SKatsuhiro Suzuki  * @aio: the AIO device pointer
89139a3420SKatsuhiro Suzuki  * @name: name of device
90139a3420SKatsuhiro Suzuki  * @direction: the direction of substream, SNDRV_PCM_STREAM_*
91139a3420SKatsuhiro Suzuki  *
92139a3420SKatsuhiro Suzuki  * Find hardware specification information from list by device name. This
93139a3420SKatsuhiro Suzuki  * information is used for telling the difference of SoCs to driver.
94139a3420SKatsuhiro Suzuki  *
95139a3420SKatsuhiro Suzuki  * Specification list is array of 'struct uniphier_aio_spec' which is defined
96139a3420SKatsuhiro Suzuki  * in each drivers (see: aio-i2s.c).
97139a3420SKatsuhiro Suzuki  *
98139a3420SKatsuhiro Suzuki  * Return: The pointer of hardware specification of AIO if successful,
99139a3420SKatsuhiro Suzuki  * otherwise NULL on error.
100139a3420SKatsuhiro Suzuki  */
find_spec(struct uniphier_aio * aio,const char * name,int direction)101139a3420SKatsuhiro Suzuki static const struct uniphier_aio_spec *find_spec(struct uniphier_aio *aio,
102139a3420SKatsuhiro Suzuki 						 const char *name,
103139a3420SKatsuhiro Suzuki 						 int direction)
104139a3420SKatsuhiro Suzuki {
105139a3420SKatsuhiro Suzuki 	const struct uniphier_aio_chip_spec *chip_spec = aio->chip->chip_spec;
106139a3420SKatsuhiro Suzuki 	int i;
107139a3420SKatsuhiro Suzuki 
108139a3420SKatsuhiro Suzuki 	for (i = 0; i < chip_spec->num_specs; i++) {
109139a3420SKatsuhiro Suzuki 		const struct uniphier_aio_spec *spec = &chip_spec->specs[i];
110139a3420SKatsuhiro Suzuki 
111139a3420SKatsuhiro Suzuki 		if (match_spec(spec, name, direction))
112139a3420SKatsuhiro Suzuki 			return spec;
113139a3420SKatsuhiro Suzuki 	}
114139a3420SKatsuhiro Suzuki 
115139a3420SKatsuhiro Suzuki 	return NULL;
116139a3420SKatsuhiro Suzuki }
117139a3420SKatsuhiro Suzuki 
118139a3420SKatsuhiro Suzuki /**
119139a3420SKatsuhiro Suzuki  * find_divider - find clock divider by frequency
120139a3420SKatsuhiro Suzuki  * @aio: the AIO device pointer
121139a3420SKatsuhiro Suzuki  * @pll_id: PLL ID, should be AUD_PLL_XX
122139a3420SKatsuhiro Suzuki  * @freq: required frequency
123139a3420SKatsuhiro Suzuki  *
124139a3420SKatsuhiro Suzuki  * Find suitable clock divider by frequency.
125139a3420SKatsuhiro Suzuki  *
126139a3420SKatsuhiro Suzuki  * Return: The ID of PLL if successful, otherwise negative error value.
127139a3420SKatsuhiro Suzuki  */
find_divider(struct uniphier_aio * aio,int pll_id,unsigned int freq)128139a3420SKatsuhiro Suzuki static int find_divider(struct uniphier_aio *aio, int pll_id, unsigned int freq)
129139a3420SKatsuhiro Suzuki {
130139a3420SKatsuhiro Suzuki 	struct uniphier_aio_pll *pll;
1315d925d98SColin Ian King 	static const int mul[] = { 1, 1, 1, 2, };
1325d925d98SColin Ian King 	static const int div[] = { 2, 3, 1, 3, };
133139a3420SKatsuhiro Suzuki 	int i;
134139a3420SKatsuhiro Suzuki 
135139a3420SKatsuhiro Suzuki 	if (!is_valid_pll(aio->chip, pll_id))
136139a3420SKatsuhiro Suzuki 		return -EINVAL;
137139a3420SKatsuhiro Suzuki 
138139a3420SKatsuhiro Suzuki 	pll = &aio->chip->plls[pll_id];
139139a3420SKatsuhiro Suzuki 	for (i = 0; i < ARRAY_SIZE(mul); i++)
140139a3420SKatsuhiro Suzuki 		if (pll->freq * mul[i] / div[i] == freq)
141139a3420SKatsuhiro Suzuki 			return i;
142139a3420SKatsuhiro Suzuki 
143139a3420SKatsuhiro Suzuki 	return -ENOTSUPP;
144139a3420SKatsuhiro Suzuki }
145139a3420SKatsuhiro Suzuki 
uniphier_aio_set_sysclk(struct snd_soc_dai * dai,int clk_id,unsigned int freq,int dir)146139a3420SKatsuhiro Suzuki static int uniphier_aio_set_sysclk(struct snd_soc_dai *dai, int clk_id,
147139a3420SKatsuhiro Suzuki 				   unsigned int freq, int dir)
148139a3420SKatsuhiro Suzuki {
149139a3420SKatsuhiro Suzuki 	struct uniphier_aio *aio = uniphier_priv(dai);
150139a3420SKatsuhiro Suzuki 	struct device *dev = &aio->chip->pdev->dev;
151139a3420SKatsuhiro Suzuki 	bool pll_auto = false;
152139a3420SKatsuhiro Suzuki 	int pll_id, div_id;
153139a3420SKatsuhiro Suzuki 
154139a3420SKatsuhiro Suzuki 	switch (clk_id) {
155139a3420SKatsuhiro Suzuki 	case AUD_CLK_IO:
156139a3420SKatsuhiro Suzuki 		return -ENOTSUPP;
157139a3420SKatsuhiro Suzuki 	case AUD_CLK_A1:
158139a3420SKatsuhiro Suzuki 		pll_id = AUD_PLL_A1;
159139a3420SKatsuhiro Suzuki 		break;
160139a3420SKatsuhiro Suzuki 	case AUD_CLK_F1:
161139a3420SKatsuhiro Suzuki 		pll_id = AUD_PLL_F1;
162139a3420SKatsuhiro Suzuki 		break;
163139a3420SKatsuhiro Suzuki 	case AUD_CLK_A2:
164139a3420SKatsuhiro Suzuki 		pll_id = AUD_PLL_A2;
165139a3420SKatsuhiro Suzuki 		break;
166139a3420SKatsuhiro Suzuki 	case AUD_CLK_F2:
167139a3420SKatsuhiro Suzuki 		pll_id = AUD_PLL_F2;
168139a3420SKatsuhiro Suzuki 		break;
169139a3420SKatsuhiro Suzuki 	case AUD_CLK_A:
170139a3420SKatsuhiro Suzuki 		pll_id = AUD_PLL_A1;
171139a3420SKatsuhiro Suzuki 		pll_auto = true;
172139a3420SKatsuhiro Suzuki 		break;
173139a3420SKatsuhiro Suzuki 	case AUD_CLK_F:
174139a3420SKatsuhiro Suzuki 		pll_id = AUD_PLL_F1;
175139a3420SKatsuhiro Suzuki 		pll_auto = true;
176139a3420SKatsuhiro Suzuki 		break;
177139a3420SKatsuhiro Suzuki 	case AUD_CLK_APLL:
178139a3420SKatsuhiro Suzuki 		pll_id = AUD_PLL_APLL;
179139a3420SKatsuhiro Suzuki 		break;
180139a3420SKatsuhiro Suzuki 	case AUD_CLK_RX0:
181139a3420SKatsuhiro Suzuki 		pll_id = AUD_PLL_RX0;
182139a3420SKatsuhiro Suzuki 		break;
183139a3420SKatsuhiro Suzuki 	case AUD_CLK_USB0:
184139a3420SKatsuhiro Suzuki 		pll_id = AUD_PLL_USB0;
185139a3420SKatsuhiro Suzuki 		break;
186139a3420SKatsuhiro Suzuki 	case AUD_CLK_HSC0:
187139a3420SKatsuhiro Suzuki 		pll_id = AUD_PLL_HSC0;
188139a3420SKatsuhiro Suzuki 		break;
189139a3420SKatsuhiro Suzuki 	default:
190139a3420SKatsuhiro Suzuki 		dev_err(dev, "Sysclk(%d) is not supported\n", clk_id);
191139a3420SKatsuhiro Suzuki 		return -EINVAL;
192139a3420SKatsuhiro Suzuki 	}
193139a3420SKatsuhiro Suzuki 
194139a3420SKatsuhiro Suzuki 	if (pll_auto) {
195139a3420SKatsuhiro Suzuki 		for (pll_id = 0; pll_id < aio->chip->num_plls; pll_id++) {
196139a3420SKatsuhiro Suzuki 			div_id = find_divider(aio, pll_id, freq);
197139a3420SKatsuhiro Suzuki 			if (div_id >= 0) {
198139a3420SKatsuhiro Suzuki 				aio->plldiv = div_id;
199139a3420SKatsuhiro Suzuki 				break;
200139a3420SKatsuhiro Suzuki 			}
201139a3420SKatsuhiro Suzuki 		}
202139a3420SKatsuhiro Suzuki 		if (pll_id == aio->chip->num_plls) {
203139a3420SKatsuhiro Suzuki 			dev_err(dev, "Sysclk frequency is not supported(%d)\n",
204139a3420SKatsuhiro Suzuki 				freq);
205139a3420SKatsuhiro Suzuki 			return -EINVAL;
206139a3420SKatsuhiro Suzuki 		}
207139a3420SKatsuhiro Suzuki 	}
208139a3420SKatsuhiro Suzuki 
209139a3420SKatsuhiro Suzuki 	if (dir == SND_SOC_CLOCK_OUT)
210139a3420SKatsuhiro Suzuki 		aio->pll_out = pll_id;
211139a3420SKatsuhiro Suzuki 	else
212139a3420SKatsuhiro Suzuki 		aio->pll_in = pll_id;
213139a3420SKatsuhiro Suzuki 
214139a3420SKatsuhiro Suzuki 	return 0;
215139a3420SKatsuhiro Suzuki }
216139a3420SKatsuhiro Suzuki 
uniphier_aio_set_pll(struct snd_soc_dai * dai,int pll_id,int source,unsigned int freq_in,unsigned int freq_out)217139a3420SKatsuhiro Suzuki static int uniphier_aio_set_pll(struct snd_soc_dai *dai, int pll_id,
218139a3420SKatsuhiro Suzuki 				int source, unsigned int freq_in,
219139a3420SKatsuhiro Suzuki 				unsigned int freq_out)
220139a3420SKatsuhiro Suzuki {
221139a3420SKatsuhiro Suzuki 	struct uniphier_aio *aio = uniphier_priv(dai);
222139a3420SKatsuhiro Suzuki 	int ret;
223139a3420SKatsuhiro Suzuki 
224139a3420SKatsuhiro Suzuki 	if (!is_valid_pll(aio->chip, pll_id))
225139a3420SKatsuhiro Suzuki 		return -EINVAL;
226139a3420SKatsuhiro Suzuki 
227139a3420SKatsuhiro Suzuki 	ret = aio_chip_set_pll(aio->chip, pll_id, freq_out);
228139a3420SKatsuhiro Suzuki 	if (ret < 0)
229139a3420SKatsuhiro Suzuki 		return ret;
230139a3420SKatsuhiro Suzuki 
231139a3420SKatsuhiro Suzuki 	return 0;
232139a3420SKatsuhiro Suzuki }
233139a3420SKatsuhiro Suzuki 
uniphier_aio_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)234139a3420SKatsuhiro Suzuki static int uniphier_aio_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
235139a3420SKatsuhiro Suzuki {
236139a3420SKatsuhiro Suzuki 	struct uniphier_aio *aio = uniphier_priv(dai);
237139a3420SKatsuhiro Suzuki 	struct device *dev = &aio->chip->pdev->dev;
238139a3420SKatsuhiro Suzuki 
239139a3420SKatsuhiro Suzuki 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
240139a3420SKatsuhiro Suzuki 	case SND_SOC_DAIFMT_LEFT_J:
241139a3420SKatsuhiro Suzuki 	case SND_SOC_DAIFMT_RIGHT_J:
242139a3420SKatsuhiro Suzuki 	case SND_SOC_DAIFMT_I2S:
243139a3420SKatsuhiro Suzuki 		aio->fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
244139a3420SKatsuhiro Suzuki 		break;
245139a3420SKatsuhiro Suzuki 	default:
246139a3420SKatsuhiro Suzuki 		dev_err(dev, "Format is not supported(%d)\n",
247139a3420SKatsuhiro Suzuki 			fmt & SND_SOC_DAIFMT_FORMAT_MASK);
248139a3420SKatsuhiro Suzuki 		return -EINVAL;
249139a3420SKatsuhiro Suzuki 	}
250139a3420SKatsuhiro Suzuki 
251139a3420SKatsuhiro Suzuki 	return 0;
252139a3420SKatsuhiro Suzuki }
253139a3420SKatsuhiro Suzuki 
uniphier_aio_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)254139a3420SKatsuhiro Suzuki static int uniphier_aio_startup(struct snd_pcm_substream *substream,
255139a3420SKatsuhiro Suzuki 				struct snd_soc_dai *dai)
256139a3420SKatsuhiro Suzuki {
257139a3420SKatsuhiro Suzuki 	struct uniphier_aio *aio = uniphier_priv(dai);
258139a3420SKatsuhiro Suzuki 	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
259139a3420SKatsuhiro Suzuki 
260139a3420SKatsuhiro Suzuki 	sub->substream = substream;
261139a3420SKatsuhiro Suzuki 	sub->pass_through = 0;
262139a3420SKatsuhiro Suzuki 	sub->use_mmap = true;
263139a3420SKatsuhiro Suzuki 
26413fba3e8Sdingsenjie 	return aio_init(sub);
265139a3420SKatsuhiro Suzuki }
266139a3420SKatsuhiro Suzuki 
uniphier_aio_shutdown(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)267139a3420SKatsuhiro Suzuki static void uniphier_aio_shutdown(struct snd_pcm_substream *substream,
268139a3420SKatsuhiro Suzuki 				  struct snd_soc_dai *dai)
269139a3420SKatsuhiro Suzuki {
270139a3420SKatsuhiro Suzuki 	struct uniphier_aio *aio = uniphier_priv(dai);
271139a3420SKatsuhiro Suzuki 	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
272139a3420SKatsuhiro Suzuki 
273139a3420SKatsuhiro Suzuki 	sub->substream = NULL;
274139a3420SKatsuhiro Suzuki }
275139a3420SKatsuhiro Suzuki 
uniphier_aio_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)276139a3420SKatsuhiro Suzuki static int uniphier_aio_hw_params(struct snd_pcm_substream *substream,
277139a3420SKatsuhiro Suzuki 				  struct snd_pcm_hw_params *params,
278139a3420SKatsuhiro Suzuki 				  struct snd_soc_dai *dai)
279139a3420SKatsuhiro Suzuki {
280139a3420SKatsuhiro Suzuki 	struct uniphier_aio *aio = uniphier_priv(dai);
281139a3420SKatsuhiro Suzuki 	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
282139a3420SKatsuhiro Suzuki 	struct device *dev = &aio->chip->pdev->dev;
283139a3420SKatsuhiro Suzuki 	int freq, ret;
284139a3420SKatsuhiro Suzuki 
285139a3420SKatsuhiro Suzuki 	switch (params_rate(params)) {
286139a3420SKatsuhiro Suzuki 	case 48000:
287139a3420SKatsuhiro Suzuki 	case 32000:
288139a3420SKatsuhiro Suzuki 	case 24000:
289139a3420SKatsuhiro Suzuki 		freq = 12288000;
290139a3420SKatsuhiro Suzuki 		break;
291139a3420SKatsuhiro Suzuki 	case 44100:
292139a3420SKatsuhiro Suzuki 	case 22050:
293139a3420SKatsuhiro Suzuki 		freq = 11289600;
294139a3420SKatsuhiro Suzuki 		break;
295139a3420SKatsuhiro Suzuki 	default:
296139a3420SKatsuhiro Suzuki 		dev_err(dev, "Rate is not supported(%d)\n",
297139a3420SKatsuhiro Suzuki 			params_rate(params));
298139a3420SKatsuhiro Suzuki 		return -EINVAL;
299139a3420SKatsuhiro Suzuki 	}
300139a3420SKatsuhiro Suzuki 	ret = snd_soc_dai_set_sysclk(dai, AUD_CLK_A,
301139a3420SKatsuhiro Suzuki 				     freq, SND_SOC_CLOCK_OUT);
302139a3420SKatsuhiro Suzuki 	if (ret)
303139a3420SKatsuhiro Suzuki 		return ret;
304139a3420SKatsuhiro Suzuki 
305139a3420SKatsuhiro Suzuki 	sub->params = *params;
306139a3420SKatsuhiro Suzuki 	sub->setting = 1;
307139a3420SKatsuhiro Suzuki 
308139a3420SKatsuhiro Suzuki 	aio_port_reset(sub);
3095a748de0SKatsuhiro Suzuki 	aio_port_set_volume(sub, sub->vol);
310139a3420SKatsuhiro Suzuki 	aio_src_reset(sub);
311139a3420SKatsuhiro Suzuki 
312139a3420SKatsuhiro Suzuki 	return 0;
313139a3420SKatsuhiro Suzuki }
314139a3420SKatsuhiro Suzuki 
uniphier_aio_hw_free(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)315139a3420SKatsuhiro Suzuki static int uniphier_aio_hw_free(struct snd_pcm_substream *substream,
316139a3420SKatsuhiro Suzuki 				struct snd_soc_dai *dai)
317139a3420SKatsuhiro Suzuki {
318139a3420SKatsuhiro Suzuki 	struct uniphier_aio *aio = uniphier_priv(dai);
319139a3420SKatsuhiro Suzuki 	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
320139a3420SKatsuhiro Suzuki 
321139a3420SKatsuhiro Suzuki 	sub->setting = 0;
322139a3420SKatsuhiro Suzuki 
323139a3420SKatsuhiro Suzuki 	return 0;
324139a3420SKatsuhiro Suzuki }
325139a3420SKatsuhiro Suzuki 
uniphier_aio_prepare(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)326139a3420SKatsuhiro Suzuki static int uniphier_aio_prepare(struct snd_pcm_substream *substream,
327139a3420SKatsuhiro Suzuki 				struct snd_soc_dai *dai)
328139a3420SKatsuhiro Suzuki {
329139a3420SKatsuhiro Suzuki 	struct uniphier_aio *aio = uniphier_priv(dai);
330139a3420SKatsuhiro Suzuki 	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
331139a3420SKatsuhiro Suzuki 	int ret;
332139a3420SKatsuhiro Suzuki 
333139a3420SKatsuhiro Suzuki 	ret = aio_port_set_param(sub, sub->pass_through, &sub->params);
334139a3420SKatsuhiro Suzuki 	if (ret)
335139a3420SKatsuhiro Suzuki 		return ret;
336139a3420SKatsuhiro Suzuki 	ret = aio_src_set_param(sub, &sub->params);
337139a3420SKatsuhiro Suzuki 	if (ret)
338139a3420SKatsuhiro Suzuki 		return ret;
339139a3420SKatsuhiro Suzuki 	aio_port_set_enable(sub, 1);
340139a3420SKatsuhiro Suzuki 
341139a3420SKatsuhiro Suzuki 	ret = aio_if_set_param(sub, sub->pass_through);
342139a3420SKatsuhiro Suzuki 	if (ret)
343139a3420SKatsuhiro Suzuki 		return ret;
344139a3420SKatsuhiro Suzuki 
345139a3420SKatsuhiro Suzuki 	if (sub->swm->type == PORT_TYPE_CONV) {
346139a3420SKatsuhiro Suzuki 		ret = aio_srcif_set_param(sub);
347139a3420SKatsuhiro Suzuki 		if (ret)
348139a3420SKatsuhiro Suzuki 			return ret;
349139a3420SKatsuhiro Suzuki 		ret = aio_srcch_set_param(sub);
350139a3420SKatsuhiro Suzuki 		if (ret)
351139a3420SKatsuhiro Suzuki 			return ret;
352139a3420SKatsuhiro Suzuki 		aio_srcch_set_enable(sub, 1);
353139a3420SKatsuhiro Suzuki 	}
354139a3420SKatsuhiro Suzuki 
355139a3420SKatsuhiro Suzuki 	return 0;
356139a3420SKatsuhiro Suzuki }
357139a3420SKatsuhiro Suzuki 
uniphier_aio_dai_probe(struct snd_soc_dai * dai)358*89621b57SKuninori Morimoto static int uniphier_aio_dai_probe(struct snd_soc_dai *dai)
359139a3420SKatsuhiro Suzuki {
360139a3420SKatsuhiro Suzuki 	struct uniphier_aio *aio = uniphier_priv(dai);
361139a3420SKatsuhiro Suzuki 	int i;
362139a3420SKatsuhiro Suzuki 
363139a3420SKatsuhiro Suzuki 	for (i = 0; i < ARRAY_SIZE(aio->sub); i++) {
364139a3420SKatsuhiro Suzuki 		struct uniphier_aio_sub *sub = &aio->sub[i];
365139a3420SKatsuhiro Suzuki 		const struct uniphier_aio_spec *spec;
366139a3420SKatsuhiro Suzuki 
367139a3420SKatsuhiro Suzuki 		spec = find_spec(aio, dai->name, i);
368139a3420SKatsuhiro Suzuki 		if (!spec)
369139a3420SKatsuhiro Suzuki 			continue;
370139a3420SKatsuhiro Suzuki 
371139a3420SKatsuhiro Suzuki 		sub->swm = &spec->swm;
372139a3420SKatsuhiro Suzuki 		sub->spec = spec;
3735a748de0SKatsuhiro Suzuki 
3745a748de0SKatsuhiro Suzuki 		sub->vol = AUD_VOL_INIT;
375139a3420SKatsuhiro Suzuki 	}
376139a3420SKatsuhiro Suzuki 
3777c3c20f2SKatsuhiro Suzuki 	aio_iecout_set_enable(aio->chip, true);
378139a3420SKatsuhiro Suzuki 	aio_chip_init(aio->chip);
379139a3420SKatsuhiro Suzuki 	aio->chip->active = 1;
380139a3420SKatsuhiro Suzuki 
381139a3420SKatsuhiro Suzuki 	return 0;
382139a3420SKatsuhiro Suzuki }
383139a3420SKatsuhiro Suzuki 
uniphier_aio_dai_remove(struct snd_soc_dai * dai)384*89621b57SKuninori Morimoto static int uniphier_aio_dai_remove(struct snd_soc_dai *dai)
385139a3420SKatsuhiro Suzuki {
386139a3420SKatsuhiro Suzuki 	struct uniphier_aio *aio = uniphier_priv(dai);
387139a3420SKatsuhiro Suzuki 
388139a3420SKatsuhiro Suzuki 	aio->chip->active = 0;
389139a3420SKatsuhiro Suzuki 
390139a3420SKatsuhiro Suzuki 	return 0;
391139a3420SKatsuhiro Suzuki }
392*89621b57SKuninori Morimoto 
uniphier_aio_ld11_probe(struct snd_soc_dai * dai)393*89621b57SKuninori Morimoto static int uniphier_aio_ld11_probe(struct snd_soc_dai *dai)
394*89621b57SKuninori Morimoto {
395*89621b57SKuninori Morimoto 	int ret;
396*89621b57SKuninori Morimoto 
397*89621b57SKuninori Morimoto 	ret = uniphier_aio_dai_probe(dai);
398*89621b57SKuninori Morimoto 	if (ret < 0)
399*89621b57SKuninori Morimoto 		return ret;
400*89621b57SKuninori Morimoto 
401*89621b57SKuninori Morimoto 	ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000);
402*89621b57SKuninori Morimoto 	if (ret < 0)
403*89621b57SKuninori Morimoto 		return ret;
404*89621b57SKuninori Morimoto 	ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000);
405*89621b57SKuninori Morimoto 	if (ret < 0)
406*89621b57SKuninori Morimoto 		return ret;
407*89621b57SKuninori Morimoto 
408*89621b57SKuninori Morimoto 	ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800);
409*89621b57SKuninori Morimoto 	if (ret < 0)
410*89621b57SKuninori Morimoto 		return ret;
411*89621b57SKuninori Morimoto 	ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800);
412*89621b57SKuninori Morimoto 	if (ret < 0)
413*89621b57SKuninori Morimoto 		return ret;
414*89621b57SKuninori Morimoto 
415*89621b57SKuninori Morimoto 	return 0;
416*89621b57SKuninori Morimoto }
417*89621b57SKuninori Morimoto 
uniphier_aio_pxs2_probe(struct snd_soc_dai * dai)418*89621b57SKuninori Morimoto static int uniphier_aio_pxs2_probe(struct snd_soc_dai *dai)
419*89621b57SKuninori Morimoto {
420*89621b57SKuninori Morimoto 	int ret;
421*89621b57SKuninori Morimoto 
422*89621b57SKuninori Morimoto 	ret = uniphier_aio_dai_probe(dai);
423*89621b57SKuninori Morimoto 	if (ret < 0)
424*89621b57SKuninori Morimoto 		return ret;
425*89621b57SKuninori Morimoto 
426*89621b57SKuninori Morimoto 	ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000);
427*89621b57SKuninori Morimoto 	if (ret < 0)
428*89621b57SKuninori Morimoto 		return ret;
429*89621b57SKuninori Morimoto 	ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000);
430*89621b57SKuninori Morimoto 	if (ret < 0)
431*89621b57SKuninori Morimoto 		return ret;
432*89621b57SKuninori Morimoto 
433*89621b57SKuninori Morimoto 	ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800);
434*89621b57SKuninori Morimoto 	if (ret < 0)
435*89621b57SKuninori Morimoto 		return ret;
436*89621b57SKuninori Morimoto 	ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800);
437*89621b57SKuninori Morimoto 	if (ret < 0)
438*89621b57SKuninori Morimoto 		return ret;
439*89621b57SKuninori Morimoto 
440*89621b57SKuninori Morimoto 	return 0;
441*89621b57SKuninori Morimoto }
442*89621b57SKuninori Morimoto 
443*89621b57SKuninori Morimoto const struct snd_soc_dai_ops uniphier_aio_i2s_ld11_ops = {
444*89621b57SKuninori Morimoto 	.probe		= uniphier_aio_ld11_probe,
445*89621b57SKuninori Morimoto 	.remove		= uniphier_aio_dai_remove,
446*89621b57SKuninori Morimoto 	.set_sysclk	= uniphier_aio_set_sysclk,
447*89621b57SKuninori Morimoto 	.set_pll	= uniphier_aio_set_pll,
448*89621b57SKuninori Morimoto 	.set_fmt	= uniphier_aio_set_fmt,
449*89621b57SKuninori Morimoto 	.startup	= uniphier_aio_startup,
450*89621b57SKuninori Morimoto 	.shutdown	= uniphier_aio_shutdown,
451*89621b57SKuninori Morimoto 	.hw_params	= uniphier_aio_hw_params,
452*89621b57SKuninori Morimoto 	.hw_free	= uniphier_aio_hw_free,
453*89621b57SKuninori Morimoto 	.prepare	= uniphier_aio_prepare,
454*89621b57SKuninori Morimoto };
455*89621b57SKuninori Morimoto EXPORT_SYMBOL_GPL(uniphier_aio_i2s_ld11_ops);
456*89621b57SKuninori Morimoto 
457*89621b57SKuninori Morimoto const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops = {
458*89621b57SKuninori Morimoto 	.probe		= uniphier_aio_ld11_probe,
459*89621b57SKuninori Morimoto 	.remove		= uniphier_aio_dai_remove,
460*89621b57SKuninori Morimoto 	.set_sysclk	= uniphier_aio_set_sysclk,
461*89621b57SKuninori Morimoto 	.set_pll	= uniphier_aio_set_pll,
462*89621b57SKuninori Morimoto 	.startup	= uniphier_aio_startup,
463*89621b57SKuninori Morimoto 	.shutdown	= uniphier_aio_shutdown,
464*89621b57SKuninori Morimoto 	.hw_params	= uniphier_aio_hw_params,
465*89621b57SKuninori Morimoto 	.hw_free	= uniphier_aio_hw_free,
466*89621b57SKuninori Morimoto 	.prepare	= uniphier_aio_prepare,
467*89621b57SKuninori Morimoto };
468*89621b57SKuninori Morimoto EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ld11_ops);
469*89621b57SKuninori Morimoto 
470*89621b57SKuninori Morimoto const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops2 = {
471*89621b57SKuninori Morimoto 	.probe		= uniphier_aio_ld11_probe,
472*89621b57SKuninori Morimoto 	.remove		= uniphier_aio_dai_remove,
473*89621b57SKuninori Morimoto 	.set_sysclk	= uniphier_aio_set_sysclk,
474*89621b57SKuninori Morimoto 	.set_pll	= uniphier_aio_set_pll,
475*89621b57SKuninori Morimoto 	.startup	= uniphier_aio_startup,
476*89621b57SKuninori Morimoto 	.shutdown	= uniphier_aio_shutdown,
477*89621b57SKuninori Morimoto 	.hw_params	= uniphier_aio_hw_params,
478*89621b57SKuninori Morimoto 	.hw_free	= uniphier_aio_hw_free,
479*89621b57SKuninori Morimoto 	.prepare	= uniphier_aio_prepare,
480*89621b57SKuninori Morimoto 	.compress_new	= snd_soc_new_compress,
481*89621b57SKuninori Morimoto };
482*89621b57SKuninori Morimoto EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ld11_ops2);
483*89621b57SKuninori Morimoto 
484*89621b57SKuninori Morimoto const struct snd_soc_dai_ops uniphier_aio_i2s_pxs2_ops = {
485*89621b57SKuninori Morimoto 	.probe		= uniphier_aio_pxs2_probe,
486*89621b57SKuninori Morimoto 	.remove		= uniphier_aio_dai_remove,
487*89621b57SKuninori Morimoto 	.set_sysclk	= uniphier_aio_set_sysclk,
488*89621b57SKuninori Morimoto 	.set_pll	= uniphier_aio_set_pll,
489*89621b57SKuninori Morimoto 	.set_fmt	= uniphier_aio_set_fmt,
490*89621b57SKuninori Morimoto 	.startup	= uniphier_aio_startup,
491*89621b57SKuninori Morimoto 	.shutdown	= uniphier_aio_shutdown,
492*89621b57SKuninori Morimoto 	.hw_params	= uniphier_aio_hw_params,
493*89621b57SKuninori Morimoto 	.hw_free	= uniphier_aio_hw_free,
494*89621b57SKuninori Morimoto 	.prepare	= uniphier_aio_prepare,
495*89621b57SKuninori Morimoto };
496*89621b57SKuninori Morimoto EXPORT_SYMBOL_GPL(uniphier_aio_i2s_pxs2_ops);
497*89621b57SKuninori Morimoto 
498*89621b57SKuninori Morimoto const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops = {
499*89621b57SKuninori Morimoto 	.probe		= uniphier_aio_pxs2_probe,
500*89621b57SKuninori Morimoto 	.remove		= uniphier_aio_dai_remove,
501*89621b57SKuninori Morimoto 	.set_sysclk	= uniphier_aio_set_sysclk,
502*89621b57SKuninori Morimoto 	.set_pll	= uniphier_aio_set_pll,
503*89621b57SKuninori Morimoto 	.startup	= uniphier_aio_startup,
504*89621b57SKuninori Morimoto 	.shutdown	= uniphier_aio_shutdown,
505*89621b57SKuninori Morimoto 	.hw_params	= uniphier_aio_hw_params,
506*89621b57SKuninori Morimoto 	.hw_free	= uniphier_aio_hw_free,
507*89621b57SKuninori Morimoto 	.prepare	= uniphier_aio_prepare,
508*89621b57SKuninori Morimoto };
509*89621b57SKuninori Morimoto EXPORT_SYMBOL_GPL(uniphier_aio_spdif_pxs2_ops);
510*89621b57SKuninori Morimoto 
511*89621b57SKuninori Morimoto const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops2 = {
512*89621b57SKuninori Morimoto 	.probe		= uniphier_aio_pxs2_probe,
513*89621b57SKuninori Morimoto 	.remove		= uniphier_aio_dai_remove,
514*89621b57SKuninori Morimoto 	.set_sysclk	= uniphier_aio_set_sysclk,
515*89621b57SKuninori Morimoto 	.set_pll	= uniphier_aio_set_pll,
516*89621b57SKuninori Morimoto 	.startup	= uniphier_aio_startup,
517*89621b57SKuninori Morimoto 	.shutdown	= uniphier_aio_shutdown,
518*89621b57SKuninori Morimoto 	.hw_params	= uniphier_aio_hw_params,
519*89621b57SKuninori Morimoto 	.hw_free	= uniphier_aio_hw_free,
520*89621b57SKuninori Morimoto 	.prepare	= uniphier_aio_prepare,
521*89621b57SKuninori Morimoto 	.compress_new	= snd_soc_new_compress,
522*89621b57SKuninori Morimoto };
523*89621b57SKuninori Morimoto EXPORT_SYMBOL_GPL(uniphier_aio_spdif_pxs2_ops2);
524139a3420SKatsuhiro Suzuki 
uniphier_aio_dai_suspend(struct snd_soc_dai * dai)5259b79b1cdSKuninori Morimoto static void uniphier_aio_dai_suspend(struct snd_soc_dai *dai)
526139a3420SKatsuhiro Suzuki {
527139a3420SKatsuhiro Suzuki 	struct uniphier_aio *aio = uniphier_priv(dai);
528139a3420SKatsuhiro Suzuki 
52925d67552SKuninori Morimoto 	if (!snd_soc_dai_active(dai))
5309b79b1cdSKuninori Morimoto 		return;
5319b79b1cdSKuninori Morimoto 
532c372a355SKunihiko Hayashi 	aio->chip->num_wup_aios--;
533c372a355SKunihiko Hayashi 	if (!aio->chip->num_wup_aios) {
534139a3420SKatsuhiro Suzuki 		reset_control_assert(aio->chip->rst);
535139a3420SKatsuhiro Suzuki 		clk_disable_unprepare(aio->chip->clk);
536c372a355SKunihiko Hayashi 	}
5379b79b1cdSKuninori Morimoto }
538139a3420SKatsuhiro Suzuki 
uniphier_aio_suspend(struct snd_soc_component * component)5399b79b1cdSKuninori Morimoto static int uniphier_aio_suspend(struct snd_soc_component *component)
5409b79b1cdSKuninori Morimoto {
5419b79b1cdSKuninori Morimoto 	struct snd_soc_dai *dai;
5429b79b1cdSKuninori Morimoto 
5439b79b1cdSKuninori Morimoto 	for_each_component_dais(component, dai)
5449b79b1cdSKuninori Morimoto 		uniphier_aio_dai_suspend(dai);
545139a3420SKatsuhiro Suzuki 	return 0;
546139a3420SKatsuhiro Suzuki }
547139a3420SKatsuhiro Suzuki 
uniphier_aio_dai_resume(struct snd_soc_dai * dai)5489b79b1cdSKuninori Morimoto static int uniphier_aio_dai_resume(struct snd_soc_dai *dai)
549139a3420SKatsuhiro Suzuki {
550139a3420SKatsuhiro Suzuki 	struct uniphier_aio *aio = uniphier_priv(dai);
551139a3420SKatsuhiro Suzuki 	int ret, i;
552139a3420SKatsuhiro Suzuki 
55325d67552SKuninori Morimoto 	if (!snd_soc_dai_active(dai))
5549b79b1cdSKuninori Morimoto 		return 0;
5559b79b1cdSKuninori Morimoto 
556139a3420SKatsuhiro Suzuki 	if (!aio->chip->active)
557139a3420SKatsuhiro Suzuki 		return 0;
558139a3420SKatsuhiro Suzuki 
559c372a355SKunihiko Hayashi 	if (!aio->chip->num_wup_aios) {
560139a3420SKatsuhiro Suzuki 		ret = clk_prepare_enable(aio->chip->clk);
561139a3420SKatsuhiro Suzuki 		if (ret)
562139a3420SKatsuhiro Suzuki 			return ret;
563139a3420SKatsuhiro Suzuki 
564139a3420SKatsuhiro Suzuki 		ret = reset_control_deassert(aio->chip->rst);
565139a3420SKatsuhiro Suzuki 		if (ret)
566139a3420SKatsuhiro Suzuki 			goto err_out_clock;
567c372a355SKunihiko Hayashi 	}
568139a3420SKatsuhiro Suzuki 
5697c3c20f2SKatsuhiro Suzuki 	aio_iecout_set_enable(aio->chip, true);
570139a3420SKatsuhiro Suzuki 	aio_chip_init(aio->chip);
571139a3420SKatsuhiro Suzuki 
572139a3420SKatsuhiro Suzuki 	for (i = 0; i < ARRAY_SIZE(aio->sub); i++) {
573139a3420SKatsuhiro Suzuki 		struct uniphier_aio_sub *sub = &aio->sub[i];
574139a3420SKatsuhiro Suzuki 
575139a3420SKatsuhiro Suzuki 		if (!sub->spec || !sub->substream)
576139a3420SKatsuhiro Suzuki 			continue;
577139a3420SKatsuhiro Suzuki 
578139a3420SKatsuhiro Suzuki 		ret = aio_init(sub);
579139a3420SKatsuhiro Suzuki 		if (ret)
580c372a355SKunihiko Hayashi 			goto err_out_reset;
581139a3420SKatsuhiro Suzuki 
582139a3420SKatsuhiro Suzuki 		if (!sub->setting)
583139a3420SKatsuhiro Suzuki 			continue;
584139a3420SKatsuhiro Suzuki 
585139a3420SKatsuhiro Suzuki 		aio_port_reset(sub);
586139a3420SKatsuhiro Suzuki 		aio_src_reset(sub);
587139a3420SKatsuhiro Suzuki 	}
588c372a355SKunihiko Hayashi 	aio->chip->num_wup_aios++;
589139a3420SKatsuhiro Suzuki 
590139a3420SKatsuhiro Suzuki 	return 0;
591139a3420SKatsuhiro Suzuki 
592c372a355SKunihiko Hayashi err_out_reset:
593c372a355SKunihiko Hayashi 	if (!aio->chip->num_wup_aios)
594c372a355SKunihiko Hayashi 		reset_control_assert(aio->chip->rst);
595139a3420SKatsuhiro Suzuki err_out_clock:
596c372a355SKunihiko Hayashi 	if (!aio->chip->num_wup_aios)
597139a3420SKatsuhiro Suzuki 		clk_disable_unprepare(aio->chip->clk);
598139a3420SKatsuhiro Suzuki 
599139a3420SKatsuhiro Suzuki 	return ret;
600139a3420SKatsuhiro Suzuki }
6019b79b1cdSKuninori Morimoto 
uniphier_aio_resume(struct snd_soc_component * component)6029b79b1cdSKuninori Morimoto static int uniphier_aio_resume(struct snd_soc_component *component)
6039b79b1cdSKuninori Morimoto {
6049b79b1cdSKuninori Morimoto 	struct snd_soc_dai *dai;
6059b79b1cdSKuninori Morimoto 	int ret = 0;
6069b79b1cdSKuninori Morimoto 
6079b79b1cdSKuninori Morimoto 	for_each_component_dais(component, dai)
6089b79b1cdSKuninori Morimoto 		ret |= uniphier_aio_dai_resume(dai);
6099b79b1cdSKuninori Morimoto 	return ret;
6109b79b1cdSKuninori Morimoto }
611139a3420SKatsuhiro Suzuki 
uniphier_aio_vol_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)6125a748de0SKatsuhiro Suzuki static int uniphier_aio_vol_info(struct snd_kcontrol *kcontrol,
6135a748de0SKatsuhiro Suzuki 				 struct snd_ctl_elem_info *uinfo)
6145a748de0SKatsuhiro Suzuki {
6155a748de0SKatsuhiro Suzuki 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
6165a748de0SKatsuhiro Suzuki 	uinfo->count = 1;
6175a748de0SKatsuhiro Suzuki 	uinfo->value.integer.min = 0;
6185a748de0SKatsuhiro Suzuki 	uinfo->value.integer.max = AUD_VOL_MAX;
6195a748de0SKatsuhiro Suzuki 
6205a748de0SKatsuhiro Suzuki 	return 0;
6215a748de0SKatsuhiro Suzuki }
6225a748de0SKatsuhiro Suzuki 
uniphier_aio_vol_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)6235a748de0SKatsuhiro Suzuki static int uniphier_aio_vol_get(struct snd_kcontrol *kcontrol,
6245a748de0SKatsuhiro Suzuki 				struct snd_ctl_elem_value *ucontrol)
6255a748de0SKatsuhiro Suzuki {
6265a748de0SKatsuhiro Suzuki 	struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
6275a748de0SKatsuhiro Suzuki 	struct uniphier_aio_chip *chip = snd_soc_component_get_drvdata(comp);
6285a748de0SKatsuhiro Suzuki 	struct uniphier_aio_sub *sub;
6295a748de0SKatsuhiro Suzuki 	int oport_hw = kcontrol->private_value;
6305a748de0SKatsuhiro Suzuki 
6315a748de0SKatsuhiro Suzuki 	sub = find_volume(chip, oport_hw);
6325a748de0SKatsuhiro Suzuki 	if (!sub)
6335a748de0SKatsuhiro Suzuki 		return 0;
6345a748de0SKatsuhiro Suzuki 
6355a748de0SKatsuhiro Suzuki 	ucontrol->value.integer.value[0] = sub->vol;
6365a748de0SKatsuhiro Suzuki 
6375a748de0SKatsuhiro Suzuki 	return 0;
6385a748de0SKatsuhiro Suzuki }
6395a748de0SKatsuhiro Suzuki 
uniphier_aio_vol_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)6405a748de0SKatsuhiro Suzuki static int uniphier_aio_vol_put(struct snd_kcontrol *kcontrol,
6415a748de0SKatsuhiro Suzuki 				struct snd_ctl_elem_value *ucontrol)
6425a748de0SKatsuhiro Suzuki {
6435a748de0SKatsuhiro Suzuki 	struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
6445a748de0SKatsuhiro Suzuki 	struct uniphier_aio_chip *chip = snd_soc_component_get_drvdata(comp);
6455a748de0SKatsuhiro Suzuki 	struct uniphier_aio_sub *sub;
6465a748de0SKatsuhiro Suzuki 	int oport_hw = kcontrol->private_value;
6475a748de0SKatsuhiro Suzuki 
6485a748de0SKatsuhiro Suzuki 	sub = find_volume(chip, oport_hw);
6495a748de0SKatsuhiro Suzuki 	if (!sub)
6505a748de0SKatsuhiro Suzuki 		return 0;
6515a748de0SKatsuhiro Suzuki 
6525a748de0SKatsuhiro Suzuki 	if (sub->vol == ucontrol->value.integer.value[0])
6535a748de0SKatsuhiro Suzuki 		return 0;
6545a748de0SKatsuhiro Suzuki 	sub->vol = ucontrol->value.integer.value[0];
6555a748de0SKatsuhiro Suzuki 
6565a748de0SKatsuhiro Suzuki 	aio_port_set_volume(sub, sub->vol);
6575a748de0SKatsuhiro Suzuki 
6585a748de0SKatsuhiro Suzuki 	return 0;
6595a748de0SKatsuhiro Suzuki }
6605a748de0SKatsuhiro Suzuki 
6615a748de0SKatsuhiro Suzuki static const struct snd_kcontrol_new uniphier_aio_controls[] = {
6625a748de0SKatsuhiro Suzuki 	{
6635a748de0SKatsuhiro Suzuki 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6645a748de0SKatsuhiro Suzuki 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
6655a748de0SKatsuhiro Suzuki 		.name = "HPCMOUT1 Volume",
6665a748de0SKatsuhiro Suzuki 		.info = uniphier_aio_vol_info,
6675a748de0SKatsuhiro Suzuki 		.get = uniphier_aio_vol_get,
6685a748de0SKatsuhiro Suzuki 		.put = uniphier_aio_vol_put,
6695a748de0SKatsuhiro Suzuki 		.private_value = AUD_HW_HPCMOUT1,
6705a748de0SKatsuhiro Suzuki 	},
6715a748de0SKatsuhiro Suzuki 	{
6725a748de0SKatsuhiro Suzuki 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6735a748de0SKatsuhiro Suzuki 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
6745a748de0SKatsuhiro Suzuki 		.name = "PCMOUT1 Volume",
6755a748de0SKatsuhiro Suzuki 		.info = uniphier_aio_vol_info,
6765a748de0SKatsuhiro Suzuki 		.get = uniphier_aio_vol_get,
6775a748de0SKatsuhiro Suzuki 		.put = uniphier_aio_vol_put,
6785a748de0SKatsuhiro Suzuki 		.private_value = AUD_HW_PCMOUT1,
6795a748de0SKatsuhiro Suzuki 	},
6805a748de0SKatsuhiro Suzuki 	{
6815a748de0SKatsuhiro Suzuki 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6825a748de0SKatsuhiro Suzuki 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
6835a748de0SKatsuhiro Suzuki 		.name = "PCMOUT2 Volume",
6845a748de0SKatsuhiro Suzuki 		.info = uniphier_aio_vol_info,
6855a748de0SKatsuhiro Suzuki 		.get = uniphier_aio_vol_get,
6865a748de0SKatsuhiro Suzuki 		.put = uniphier_aio_vol_put,
6875a748de0SKatsuhiro Suzuki 		.private_value = AUD_HW_PCMOUT2,
6885a748de0SKatsuhiro Suzuki 	},
6895a748de0SKatsuhiro Suzuki 	{
6905a748de0SKatsuhiro Suzuki 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6915a748de0SKatsuhiro Suzuki 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
6925a748de0SKatsuhiro Suzuki 		.name = "PCMOUT3 Volume",
6935a748de0SKatsuhiro Suzuki 		.info = uniphier_aio_vol_info,
6945a748de0SKatsuhiro Suzuki 		.get = uniphier_aio_vol_get,
6955a748de0SKatsuhiro Suzuki 		.put = uniphier_aio_vol_put,
6965a748de0SKatsuhiro Suzuki 		.private_value = AUD_HW_PCMOUT3,
6975a748de0SKatsuhiro Suzuki 	},
6985a748de0SKatsuhiro Suzuki 	{
6995a748de0SKatsuhiro Suzuki 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7005a748de0SKatsuhiro Suzuki 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
7015a748de0SKatsuhiro Suzuki 		.name = "HIECOUT1 Volume",
7025a748de0SKatsuhiro Suzuki 		.info = uniphier_aio_vol_info,
7035a748de0SKatsuhiro Suzuki 		.get = uniphier_aio_vol_get,
7045a748de0SKatsuhiro Suzuki 		.put = uniphier_aio_vol_put,
7055a748de0SKatsuhiro Suzuki 		.private_value = AUD_HW_HIECOUT1,
7065a748de0SKatsuhiro Suzuki 	},
7075a748de0SKatsuhiro Suzuki 	{
7085a748de0SKatsuhiro Suzuki 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7095a748de0SKatsuhiro Suzuki 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
7105a748de0SKatsuhiro Suzuki 		.name = "IECOUT1 Volume",
7115a748de0SKatsuhiro Suzuki 		.info = uniphier_aio_vol_info,
7125a748de0SKatsuhiro Suzuki 		.get = uniphier_aio_vol_get,
7135a748de0SKatsuhiro Suzuki 		.put = uniphier_aio_vol_put,
7145a748de0SKatsuhiro Suzuki 		.private_value = AUD_HW_IECOUT1,
7155a748de0SKatsuhiro Suzuki 	},
7165a748de0SKatsuhiro Suzuki };
7175a748de0SKatsuhiro Suzuki 
718139a3420SKatsuhiro Suzuki static const struct snd_soc_component_driver uniphier_aio_component = {
719139a3420SKatsuhiro Suzuki 	.name = "uniphier-aio",
7205a748de0SKatsuhiro Suzuki 	.controls = uniphier_aio_controls,
7215a748de0SKatsuhiro Suzuki 	.num_controls = ARRAY_SIZE(uniphier_aio_controls),
7229b79b1cdSKuninori Morimoto 	.suspend = uniphier_aio_suspend,
7239b79b1cdSKuninori Morimoto 	.resume  = uniphier_aio_resume,
724139a3420SKatsuhiro Suzuki };
725139a3420SKatsuhiro Suzuki 
uniphier_aio_probe(struct platform_device * pdev)726139a3420SKatsuhiro Suzuki int uniphier_aio_probe(struct platform_device *pdev)
727139a3420SKatsuhiro Suzuki {
728139a3420SKatsuhiro Suzuki 	struct uniphier_aio_chip *chip;
729139a3420SKatsuhiro Suzuki 	struct device *dev = &pdev->dev;
730139a3420SKatsuhiro Suzuki 	int ret, i, j;
731139a3420SKatsuhiro Suzuki 
732139a3420SKatsuhiro Suzuki 	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
733139a3420SKatsuhiro Suzuki 	if (!chip)
734139a3420SKatsuhiro Suzuki 		return -ENOMEM;
735139a3420SKatsuhiro Suzuki 
736139a3420SKatsuhiro Suzuki 	chip->chip_spec = of_device_get_match_data(dev);
737139a3420SKatsuhiro Suzuki 	if (!chip->chip_spec)
738139a3420SKatsuhiro Suzuki 		return -EINVAL;
739139a3420SKatsuhiro Suzuki 
7407c3c20f2SKatsuhiro Suzuki 	chip->regmap_sg = syscon_regmap_lookup_by_phandle(dev->of_node,
7417c3c20f2SKatsuhiro Suzuki 							  "socionext,syscon");
7427c3c20f2SKatsuhiro Suzuki 	if (IS_ERR(chip->regmap_sg)) {
7437c3c20f2SKatsuhiro Suzuki 		if (PTR_ERR(chip->regmap_sg) == -EPROBE_DEFER)
7447c3c20f2SKatsuhiro Suzuki 			return -EPROBE_DEFER;
7457c3c20f2SKatsuhiro Suzuki 		chip->regmap_sg = NULL;
7467c3c20f2SKatsuhiro Suzuki 	}
7477c3c20f2SKatsuhiro Suzuki 
748139a3420SKatsuhiro Suzuki 	chip->clk = devm_clk_get(dev, "aio");
749139a3420SKatsuhiro Suzuki 	if (IS_ERR(chip->clk))
750139a3420SKatsuhiro Suzuki 		return PTR_ERR(chip->clk);
751139a3420SKatsuhiro Suzuki 
752139a3420SKatsuhiro Suzuki 	chip->rst = devm_reset_control_get_shared(dev, "aio");
753139a3420SKatsuhiro Suzuki 	if (IS_ERR(chip->rst))
754139a3420SKatsuhiro Suzuki 		return PTR_ERR(chip->rst);
755139a3420SKatsuhiro Suzuki 
756139a3420SKatsuhiro Suzuki 	chip->num_aios = chip->chip_spec->num_dais;
757c372a355SKunihiko Hayashi 	chip->num_wup_aios = chip->num_aios;
758a86854d0SKees Cook 	chip->aios = devm_kcalloc(dev,
759a86854d0SKees Cook 				  chip->num_aios, sizeof(struct uniphier_aio),
760139a3420SKatsuhiro Suzuki 				  GFP_KERNEL);
761139a3420SKatsuhiro Suzuki 	if (!chip->aios)
762139a3420SKatsuhiro Suzuki 		return -ENOMEM;
763139a3420SKatsuhiro Suzuki 
764139a3420SKatsuhiro Suzuki 	chip->num_plls = chip->chip_spec->num_plls;
765a86854d0SKees Cook 	chip->plls = devm_kcalloc(dev,
766a86854d0SKees Cook 				  chip->num_plls,
767a86854d0SKees Cook 				  sizeof(struct uniphier_aio_pll),
768a86854d0SKees Cook 				  GFP_KERNEL);
769139a3420SKatsuhiro Suzuki 	if (!chip->plls)
770139a3420SKatsuhiro Suzuki 		return -ENOMEM;
771139a3420SKatsuhiro Suzuki 	memcpy(chip->plls, chip->chip_spec->plls,
772139a3420SKatsuhiro Suzuki 	       sizeof(struct uniphier_aio_pll) * chip->num_plls);
773139a3420SKatsuhiro Suzuki 
774139a3420SKatsuhiro Suzuki 	for (i = 0; i < chip->num_aios; i++) {
775139a3420SKatsuhiro Suzuki 		struct uniphier_aio *aio = &chip->aios[i];
776139a3420SKatsuhiro Suzuki 
777139a3420SKatsuhiro Suzuki 		aio->chip = chip;
778139a3420SKatsuhiro Suzuki 		aio->fmt = SND_SOC_DAIFMT_I2S;
779139a3420SKatsuhiro Suzuki 
780139a3420SKatsuhiro Suzuki 		for (j = 0; j < ARRAY_SIZE(aio->sub); j++) {
781139a3420SKatsuhiro Suzuki 			struct uniphier_aio_sub *sub = &aio->sub[j];
782139a3420SKatsuhiro Suzuki 
783139a3420SKatsuhiro Suzuki 			sub->aio = aio;
784139a3420SKatsuhiro Suzuki 			spin_lock_init(&sub->lock);
785139a3420SKatsuhiro Suzuki 		}
786139a3420SKatsuhiro Suzuki 	}
787139a3420SKatsuhiro Suzuki 
788139a3420SKatsuhiro Suzuki 	chip->pdev = pdev;
789139a3420SKatsuhiro Suzuki 	platform_set_drvdata(pdev, chip);
790139a3420SKatsuhiro Suzuki 
791139a3420SKatsuhiro Suzuki 	ret = clk_prepare_enable(chip->clk);
792139a3420SKatsuhiro Suzuki 	if (ret)
793139a3420SKatsuhiro Suzuki 		return ret;
794139a3420SKatsuhiro Suzuki 
795139a3420SKatsuhiro Suzuki 	ret = reset_control_deassert(chip->rst);
796139a3420SKatsuhiro Suzuki 	if (ret)
797139a3420SKatsuhiro Suzuki 		goto err_out_clock;
798139a3420SKatsuhiro Suzuki 
799139a3420SKatsuhiro Suzuki 	ret = devm_snd_soc_register_component(dev, &uniphier_aio_component,
800139a3420SKatsuhiro Suzuki 					      chip->chip_spec->dais,
801139a3420SKatsuhiro Suzuki 					      chip->chip_spec->num_dais);
802139a3420SKatsuhiro Suzuki 	if (ret) {
803139a3420SKatsuhiro Suzuki 		dev_err(dev, "Register component failed.\n");
804139a3420SKatsuhiro Suzuki 		goto err_out_reset;
805139a3420SKatsuhiro Suzuki 	}
806139a3420SKatsuhiro Suzuki 
807139a3420SKatsuhiro Suzuki 	ret = uniphier_aiodma_soc_register_platform(pdev);
808139a3420SKatsuhiro Suzuki 	if (ret) {
809139a3420SKatsuhiro Suzuki 		dev_err(dev, "Register platform failed.\n");
810139a3420SKatsuhiro Suzuki 		goto err_out_reset;
811139a3420SKatsuhiro Suzuki 	}
812139a3420SKatsuhiro Suzuki 
813139a3420SKatsuhiro Suzuki 	return 0;
814139a3420SKatsuhiro Suzuki 
815139a3420SKatsuhiro Suzuki err_out_reset:
816139a3420SKatsuhiro Suzuki 	reset_control_assert(chip->rst);
817139a3420SKatsuhiro Suzuki 
818139a3420SKatsuhiro Suzuki err_out_clock:
819139a3420SKatsuhiro Suzuki 	clk_disable_unprepare(chip->clk);
820139a3420SKatsuhiro Suzuki 
821139a3420SKatsuhiro Suzuki 	return ret;
822139a3420SKatsuhiro Suzuki }
823139a3420SKatsuhiro Suzuki EXPORT_SYMBOL_GPL(uniphier_aio_probe);
824139a3420SKatsuhiro Suzuki 
uniphier_aio_remove(struct platform_device * pdev)825139a3420SKatsuhiro Suzuki int uniphier_aio_remove(struct platform_device *pdev)
826139a3420SKatsuhiro Suzuki {
827139a3420SKatsuhiro Suzuki 	struct uniphier_aio_chip *chip = platform_get_drvdata(pdev);
828139a3420SKatsuhiro Suzuki 
829139a3420SKatsuhiro Suzuki 	reset_control_assert(chip->rst);
830139a3420SKatsuhiro Suzuki 	clk_disable_unprepare(chip->clk);
831139a3420SKatsuhiro Suzuki 
832139a3420SKatsuhiro Suzuki 	return 0;
833139a3420SKatsuhiro Suzuki }
834139a3420SKatsuhiro Suzuki EXPORT_SYMBOL_GPL(uniphier_aio_remove);
835139a3420SKatsuhiro Suzuki 
836139a3420SKatsuhiro Suzuki MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
837139a3420SKatsuhiro Suzuki MODULE_DESCRIPTION("UniPhier AIO CPU DAI driver.");
838139a3420SKatsuhiro Suzuki MODULE_LICENSE("GPL v2");
839