162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// Socionext UniPhier AIO ALSA CPU DAI driver.
462306a36Sopenharmony_ci//
562306a36Sopenharmony_ci// Copyright (c) 2016-2018 Socionext Inc.
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/clk.h>
862306a36Sopenharmony_ci#include <linux/errno.h>
962306a36Sopenharmony_ci#include <linux/kernel.h>
1062306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/of.h>
1362306a36Sopenharmony_ci#include <linux/of_platform.h>
1462306a36Sopenharmony_ci#include <linux/platform_device.h>
1562306a36Sopenharmony_ci#include <linux/reset.h>
1662306a36Sopenharmony_ci#include <sound/core.h>
1762306a36Sopenharmony_ci#include <sound/pcm.h>
1862306a36Sopenharmony_ci#include <sound/pcm_params.h>
1962306a36Sopenharmony_ci#include <sound/soc.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "aio.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic bool is_valid_pll(struct uniphier_aio_chip *chip, int pll_id)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	struct device *dev = &chip->pdev->dev;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	if (pll_id < 0 || chip->num_plls <= pll_id) {
2862306a36Sopenharmony_ci		dev_err(dev, "PLL(%d) is not supported\n", pll_id);
2962306a36Sopenharmony_ci		return false;
3062306a36Sopenharmony_ci	}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	return chip->plls[pll_id].enable;
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/**
3662306a36Sopenharmony_ci * find_volume - find volume supported HW port by HW port number
3762306a36Sopenharmony_ci * @chip: the AIO chip pointer
3862306a36Sopenharmony_ci * @oport_hw: HW port number, one of AUD_HW_XXXX
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci * Find AIO device from device list by HW port number. Volume feature is
4162306a36Sopenharmony_ci * available only in Output and PCM ports, this limitation comes from HW
4262306a36Sopenharmony_ci * specifications.
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci * Return: The pointer of AIO substream if successful, otherwise NULL on error.
4562306a36Sopenharmony_ci */
4662306a36Sopenharmony_cistatic struct uniphier_aio_sub *find_volume(struct uniphier_aio_chip *chip,
4762306a36Sopenharmony_ci					    int oport_hw)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	int i;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	for (i = 0; i < chip->num_aios; i++) {
5262306a36Sopenharmony_ci		struct uniphier_aio_sub *sub = &chip->aios[i].sub[0];
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci		if (!sub->swm)
5562306a36Sopenharmony_ci			continue;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci		if (sub->swm->oport.hw == oport_hw)
5862306a36Sopenharmony_ci			return sub;
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	return NULL;
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic bool match_spec(const struct uniphier_aio_spec *spec,
6562306a36Sopenharmony_ci		       const char *name, int dir)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	if (dir == SNDRV_PCM_STREAM_PLAYBACK &&
6862306a36Sopenharmony_ci	    spec->swm.dir != PORT_DIR_OUTPUT) {
6962306a36Sopenharmony_ci		return false;
7062306a36Sopenharmony_ci	}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if (dir == SNDRV_PCM_STREAM_CAPTURE &&
7362306a36Sopenharmony_ci	    spec->swm.dir != PORT_DIR_INPUT) {
7462306a36Sopenharmony_ci		return false;
7562306a36Sopenharmony_ci	}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	if (spec->name && strcmp(spec->name, name) == 0)
7862306a36Sopenharmony_ci		return true;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	if (spec->gname && strcmp(spec->gname, name) == 0)
8162306a36Sopenharmony_ci		return true;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	return false;
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci/**
8762306a36Sopenharmony_ci * find_spec - find HW specification info by name
8862306a36Sopenharmony_ci * @aio: the AIO device pointer
8962306a36Sopenharmony_ci * @name: name of device
9062306a36Sopenharmony_ci * @direction: the direction of substream, SNDRV_PCM_STREAM_*
9162306a36Sopenharmony_ci *
9262306a36Sopenharmony_ci * Find hardware specification information from list by device name. This
9362306a36Sopenharmony_ci * information is used for telling the difference of SoCs to driver.
9462306a36Sopenharmony_ci *
9562306a36Sopenharmony_ci * Specification list is array of 'struct uniphier_aio_spec' which is defined
9662306a36Sopenharmony_ci * in each drivers (see: aio-i2s.c).
9762306a36Sopenharmony_ci *
9862306a36Sopenharmony_ci * Return: The pointer of hardware specification of AIO if successful,
9962306a36Sopenharmony_ci * otherwise NULL on error.
10062306a36Sopenharmony_ci */
10162306a36Sopenharmony_cistatic const struct uniphier_aio_spec *find_spec(struct uniphier_aio *aio,
10262306a36Sopenharmony_ci						 const char *name,
10362306a36Sopenharmony_ci						 int direction)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	const struct uniphier_aio_chip_spec *chip_spec = aio->chip->chip_spec;
10662306a36Sopenharmony_ci	int i;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	for (i = 0; i < chip_spec->num_specs; i++) {
10962306a36Sopenharmony_ci		const struct uniphier_aio_spec *spec = &chip_spec->specs[i];
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci		if (match_spec(spec, name, direction))
11262306a36Sopenharmony_ci			return spec;
11362306a36Sopenharmony_ci	}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	return NULL;
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci/**
11962306a36Sopenharmony_ci * find_divider - find clock divider by frequency
12062306a36Sopenharmony_ci * @aio: the AIO device pointer
12162306a36Sopenharmony_ci * @pll_id: PLL ID, should be AUD_PLL_XX
12262306a36Sopenharmony_ci * @freq: required frequency
12362306a36Sopenharmony_ci *
12462306a36Sopenharmony_ci * Find suitable clock divider by frequency.
12562306a36Sopenharmony_ci *
12662306a36Sopenharmony_ci * Return: The ID of PLL if successful, otherwise negative error value.
12762306a36Sopenharmony_ci */
12862306a36Sopenharmony_cistatic int find_divider(struct uniphier_aio *aio, int pll_id, unsigned int freq)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	struct uniphier_aio_pll *pll;
13162306a36Sopenharmony_ci	static const int mul[] = { 1, 1, 1, 2, };
13262306a36Sopenharmony_ci	static const int div[] = { 2, 3, 1, 3, };
13362306a36Sopenharmony_ci	int i;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	if (!is_valid_pll(aio->chip, pll_id))
13662306a36Sopenharmony_ci		return -EINVAL;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	pll = &aio->chip->plls[pll_id];
13962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mul); i++)
14062306a36Sopenharmony_ci		if (pll->freq * mul[i] / div[i] == freq)
14162306a36Sopenharmony_ci			return i;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	return -ENOTSUPP;
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic int uniphier_aio_set_sysclk(struct snd_soc_dai *dai, int clk_id,
14762306a36Sopenharmony_ci				   unsigned int freq, int dir)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
15062306a36Sopenharmony_ci	struct device *dev = &aio->chip->pdev->dev;
15162306a36Sopenharmony_ci	bool pll_auto = false;
15262306a36Sopenharmony_ci	int pll_id, div_id;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	switch (clk_id) {
15562306a36Sopenharmony_ci	case AUD_CLK_IO:
15662306a36Sopenharmony_ci		return -ENOTSUPP;
15762306a36Sopenharmony_ci	case AUD_CLK_A1:
15862306a36Sopenharmony_ci		pll_id = AUD_PLL_A1;
15962306a36Sopenharmony_ci		break;
16062306a36Sopenharmony_ci	case AUD_CLK_F1:
16162306a36Sopenharmony_ci		pll_id = AUD_PLL_F1;
16262306a36Sopenharmony_ci		break;
16362306a36Sopenharmony_ci	case AUD_CLK_A2:
16462306a36Sopenharmony_ci		pll_id = AUD_PLL_A2;
16562306a36Sopenharmony_ci		break;
16662306a36Sopenharmony_ci	case AUD_CLK_F2:
16762306a36Sopenharmony_ci		pll_id = AUD_PLL_F2;
16862306a36Sopenharmony_ci		break;
16962306a36Sopenharmony_ci	case AUD_CLK_A:
17062306a36Sopenharmony_ci		pll_id = AUD_PLL_A1;
17162306a36Sopenharmony_ci		pll_auto = true;
17262306a36Sopenharmony_ci		break;
17362306a36Sopenharmony_ci	case AUD_CLK_F:
17462306a36Sopenharmony_ci		pll_id = AUD_PLL_F1;
17562306a36Sopenharmony_ci		pll_auto = true;
17662306a36Sopenharmony_ci		break;
17762306a36Sopenharmony_ci	case AUD_CLK_APLL:
17862306a36Sopenharmony_ci		pll_id = AUD_PLL_APLL;
17962306a36Sopenharmony_ci		break;
18062306a36Sopenharmony_ci	case AUD_CLK_RX0:
18162306a36Sopenharmony_ci		pll_id = AUD_PLL_RX0;
18262306a36Sopenharmony_ci		break;
18362306a36Sopenharmony_ci	case AUD_CLK_USB0:
18462306a36Sopenharmony_ci		pll_id = AUD_PLL_USB0;
18562306a36Sopenharmony_ci		break;
18662306a36Sopenharmony_ci	case AUD_CLK_HSC0:
18762306a36Sopenharmony_ci		pll_id = AUD_PLL_HSC0;
18862306a36Sopenharmony_ci		break;
18962306a36Sopenharmony_ci	default:
19062306a36Sopenharmony_ci		dev_err(dev, "Sysclk(%d) is not supported\n", clk_id);
19162306a36Sopenharmony_ci		return -EINVAL;
19262306a36Sopenharmony_ci	}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	if (pll_auto) {
19562306a36Sopenharmony_ci		for (pll_id = 0; pll_id < aio->chip->num_plls; pll_id++) {
19662306a36Sopenharmony_ci			div_id = find_divider(aio, pll_id, freq);
19762306a36Sopenharmony_ci			if (div_id >= 0) {
19862306a36Sopenharmony_ci				aio->plldiv = div_id;
19962306a36Sopenharmony_ci				break;
20062306a36Sopenharmony_ci			}
20162306a36Sopenharmony_ci		}
20262306a36Sopenharmony_ci		if (pll_id == aio->chip->num_plls) {
20362306a36Sopenharmony_ci			dev_err(dev, "Sysclk frequency is not supported(%d)\n",
20462306a36Sopenharmony_ci				freq);
20562306a36Sopenharmony_ci			return -EINVAL;
20662306a36Sopenharmony_ci		}
20762306a36Sopenharmony_ci	}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	if (dir == SND_SOC_CLOCK_OUT)
21062306a36Sopenharmony_ci		aio->pll_out = pll_id;
21162306a36Sopenharmony_ci	else
21262306a36Sopenharmony_ci		aio->pll_in = pll_id;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	return 0;
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic int uniphier_aio_set_pll(struct snd_soc_dai *dai, int pll_id,
21862306a36Sopenharmony_ci				int source, unsigned int freq_in,
21962306a36Sopenharmony_ci				unsigned int freq_out)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
22262306a36Sopenharmony_ci	int ret;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	if (!is_valid_pll(aio->chip, pll_id))
22562306a36Sopenharmony_ci		return -EINVAL;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	ret = aio_chip_set_pll(aio->chip, pll_id, freq_out);
22862306a36Sopenharmony_ci	if (ret < 0)
22962306a36Sopenharmony_ci		return ret;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	return 0;
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic int uniphier_aio_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
23762306a36Sopenharmony_ci	struct device *dev = &aio->chip->pdev->dev;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
24062306a36Sopenharmony_ci	case SND_SOC_DAIFMT_LEFT_J:
24162306a36Sopenharmony_ci	case SND_SOC_DAIFMT_RIGHT_J:
24262306a36Sopenharmony_ci	case SND_SOC_DAIFMT_I2S:
24362306a36Sopenharmony_ci		aio->fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
24462306a36Sopenharmony_ci		break;
24562306a36Sopenharmony_ci	default:
24662306a36Sopenharmony_ci		dev_err(dev, "Format is not supported(%d)\n",
24762306a36Sopenharmony_ci			fmt & SND_SOC_DAIFMT_FORMAT_MASK);
24862306a36Sopenharmony_ci		return -EINVAL;
24962306a36Sopenharmony_ci	}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	return 0;
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic int uniphier_aio_startup(struct snd_pcm_substream *substream,
25562306a36Sopenharmony_ci				struct snd_soc_dai *dai)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
25862306a36Sopenharmony_ci	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	sub->substream = substream;
26162306a36Sopenharmony_ci	sub->pass_through = 0;
26262306a36Sopenharmony_ci	sub->use_mmap = true;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	return aio_init(sub);
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic void uniphier_aio_shutdown(struct snd_pcm_substream *substream,
26862306a36Sopenharmony_ci				  struct snd_soc_dai *dai)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
27162306a36Sopenharmony_ci	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	sub->substream = NULL;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic int uniphier_aio_hw_params(struct snd_pcm_substream *substream,
27762306a36Sopenharmony_ci				  struct snd_pcm_hw_params *params,
27862306a36Sopenharmony_ci				  struct snd_soc_dai *dai)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
28162306a36Sopenharmony_ci	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
28262306a36Sopenharmony_ci	struct device *dev = &aio->chip->pdev->dev;
28362306a36Sopenharmony_ci	int freq, ret;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	switch (params_rate(params)) {
28662306a36Sopenharmony_ci	case 48000:
28762306a36Sopenharmony_ci	case 32000:
28862306a36Sopenharmony_ci	case 24000:
28962306a36Sopenharmony_ci		freq = 12288000;
29062306a36Sopenharmony_ci		break;
29162306a36Sopenharmony_ci	case 44100:
29262306a36Sopenharmony_ci	case 22050:
29362306a36Sopenharmony_ci		freq = 11289600;
29462306a36Sopenharmony_ci		break;
29562306a36Sopenharmony_ci	default:
29662306a36Sopenharmony_ci		dev_err(dev, "Rate is not supported(%d)\n",
29762306a36Sopenharmony_ci			params_rate(params));
29862306a36Sopenharmony_ci		return -EINVAL;
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci	ret = snd_soc_dai_set_sysclk(dai, AUD_CLK_A,
30162306a36Sopenharmony_ci				     freq, SND_SOC_CLOCK_OUT);
30262306a36Sopenharmony_ci	if (ret)
30362306a36Sopenharmony_ci		return ret;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	sub->params = *params;
30662306a36Sopenharmony_ci	sub->setting = 1;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	aio_port_reset(sub);
30962306a36Sopenharmony_ci	aio_port_set_volume(sub, sub->vol);
31062306a36Sopenharmony_ci	aio_src_reset(sub);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	return 0;
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_cistatic int uniphier_aio_hw_free(struct snd_pcm_substream *substream,
31662306a36Sopenharmony_ci				struct snd_soc_dai *dai)
31762306a36Sopenharmony_ci{
31862306a36Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
31962306a36Sopenharmony_ci	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	sub->setting = 0;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	return 0;
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_cistatic int uniphier_aio_prepare(struct snd_pcm_substream *substream,
32762306a36Sopenharmony_ci				struct snd_soc_dai *dai)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
33062306a36Sopenharmony_ci	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
33162306a36Sopenharmony_ci	int ret;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	ret = aio_port_set_param(sub, sub->pass_through, &sub->params);
33462306a36Sopenharmony_ci	if (ret)
33562306a36Sopenharmony_ci		return ret;
33662306a36Sopenharmony_ci	ret = aio_src_set_param(sub, &sub->params);
33762306a36Sopenharmony_ci	if (ret)
33862306a36Sopenharmony_ci		return ret;
33962306a36Sopenharmony_ci	aio_port_set_enable(sub, 1);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	ret = aio_if_set_param(sub, sub->pass_through);
34262306a36Sopenharmony_ci	if (ret)
34362306a36Sopenharmony_ci		return ret;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (sub->swm->type == PORT_TYPE_CONV) {
34662306a36Sopenharmony_ci		ret = aio_srcif_set_param(sub);
34762306a36Sopenharmony_ci		if (ret)
34862306a36Sopenharmony_ci			return ret;
34962306a36Sopenharmony_ci		ret = aio_srcch_set_param(sub);
35062306a36Sopenharmony_ci		if (ret)
35162306a36Sopenharmony_ci			return ret;
35262306a36Sopenharmony_ci		aio_srcch_set_enable(sub, 1);
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	return 0;
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic int uniphier_aio_dai_probe(struct snd_soc_dai *dai)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
36162306a36Sopenharmony_ci	int i;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(aio->sub); i++) {
36462306a36Sopenharmony_ci		struct uniphier_aio_sub *sub = &aio->sub[i];
36562306a36Sopenharmony_ci		const struct uniphier_aio_spec *spec;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci		spec = find_spec(aio, dai->name, i);
36862306a36Sopenharmony_ci		if (!spec)
36962306a36Sopenharmony_ci			continue;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci		sub->swm = &spec->swm;
37262306a36Sopenharmony_ci		sub->spec = spec;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci		sub->vol = AUD_VOL_INIT;
37562306a36Sopenharmony_ci	}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	aio_iecout_set_enable(aio->chip, true);
37862306a36Sopenharmony_ci	aio_chip_init(aio->chip);
37962306a36Sopenharmony_ci	aio->chip->active = 1;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	return 0;
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic int uniphier_aio_dai_remove(struct snd_soc_dai *dai)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	aio->chip->active = 0;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	return 0;
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_cistatic int uniphier_aio_ld11_probe(struct snd_soc_dai *dai)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	int ret;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	ret = uniphier_aio_dai_probe(dai);
39862306a36Sopenharmony_ci	if (ret < 0)
39962306a36Sopenharmony_ci		return ret;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000);
40262306a36Sopenharmony_ci	if (ret < 0)
40362306a36Sopenharmony_ci		return ret;
40462306a36Sopenharmony_ci	ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000);
40562306a36Sopenharmony_ci	if (ret < 0)
40662306a36Sopenharmony_ci		return ret;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800);
40962306a36Sopenharmony_ci	if (ret < 0)
41062306a36Sopenharmony_ci		return ret;
41162306a36Sopenharmony_ci	ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800);
41262306a36Sopenharmony_ci	if (ret < 0)
41362306a36Sopenharmony_ci		return ret;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	return 0;
41662306a36Sopenharmony_ci}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cistatic int uniphier_aio_pxs2_probe(struct snd_soc_dai *dai)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	int ret;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	ret = uniphier_aio_dai_probe(dai);
42362306a36Sopenharmony_ci	if (ret < 0)
42462306a36Sopenharmony_ci		return ret;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000);
42762306a36Sopenharmony_ci	if (ret < 0)
42862306a36Sopenharmony_ci		return ret;
42962306a36Sopenharmony_ci	ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000);
43062306a36Sopenharmony_ci	if (ret < 0)
43162306a36Sopenharmony_ci		return ret;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800);
43462306a36Sopenharmony_ci	if (ret < 0)
43562306a36Sopenharmony_ci		return ret;
43662306a36Sopenharmony_ci	ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800);
43762306a36Sopenharmony_ci	if (ret < 0)
43862306a36Sopenharmony_ci		return ret;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	return 0;
44162306a36Sopenharmony_ci}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ciconst struct snd_soc_dai_ops uniphier_aio_i2s_ld11_ops = {
44462306a36Sopenharmony_ci	.probe		= uniphier_aio_ld11_probe,
44562306a36Sopenharmony_ci	.remove		= uniphier_aio_dai_remove,
44662306a36Sopenharmony_ci	.set_sysclk	= uniphier_aio_set_sysclk,
44762306a36Sopenharmony_ci	.set_pll	= uniphier_aio_set_pll,
44862306a36Sopenharmony_ci	.set_fmt	= uniphier_aio_set_fmt,
44962306a36Sopenharmony_ci	.startup	= uniphier_aio_startup,
45062306a36Sopenharmony_ci	.shutdown	= uniphier_aio_shutdown,
45162306a36Sopenharmony_ci	.hw_params	= uniphier_aio_hw_params,
45262306a36Sopenharmony_ci	.hw_free	= uniphier_aio_hw_free,
45362306a36Sopenharmony_ci	.prepare	= uniphier_aio_prepare,
45462306a36Sopenharmony_ci};
45562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_i2s_ld11_ops);
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ciconst struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops = {
45862306a36Sopenharmony_ci	.probe		= uniphier_aio_ld11_probe,
45962306a36Sopenharmony_ci	.remove		= uniphier_aio_dai_remove,
46062306a36Sopenharmony_ci	.set_sysclk	= uniphier_aio_set_sysclk,
46162306a36Sopenharmony_ci	.set_pll	= uniphier_aio_set_pll,
46262306a36Sopenharmony_ci	.startup	= uniphier_aio_startup,
46362306a36Sopenharmony_ci	.shutdown	= uniphier_aio_shutdown,
46462306a36Sopenharmony_ci	.hw_params	= uniphier_aio_hw_params,
46562306a36Sopenharmony_ci	.hw_free	= uniphier_aio_hw_free,
46662306a36Sopenharmony_ci	.prepare	= uniphier_aio_prepare,
46762306a36Sopenharmony_ci};
46862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_spdif_ld11_ops);
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ciconst struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops2 = {
47162306a36Sopenharmony_ci	.probe		= uniphier_aio_ld11_probe,
47262306a36Sopenharmony_ci	.remove		= uniphier_aio_dai_remove,
47362306a36Sopenharmony_ci	.set_sysclk	= uniphier_aio_set_sysclk,
47462306a36Sopenharmony_ci	.set_pll	= uniphier_aio_set_pll,
47562306a36Sopenharmony_ci	.startup	= uniphier_aio_startup,
47662306a36Sopenharmony_ci	.shutdown	= uniphier_aio_shutdown,
47762306a36Sopenharmony_ci	.hw_params	= uniphier_aio_hw_params,
47862306a36Sopenharmony_ci	.hw_free	= uniphier_aio_hw_free,
47962306a36Sopenharmony_ci	.prepare	= uniphier_aio_prepare,
48062306a36Sopenharmony_ci	.compress_new	= snd_soc_new_compress,
48162306a36Sopenharmony_ci};
48262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_spdif_ld11_ops2);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ciconst struct snd_soc_dai_ops uniphier_aio_i2s_pxs2_ops = {
48562306a36Sopenharmony_ci	.probe		= uniphier_aio_pxs2_probe,
48662306a36Sopenharmony_ci	.remove		= uniphier_aio_dai_remove,
48762306a36Sopenharmony_ci	.set_sysclk	= uniphier_aio_set_sysclk,
48862306a36Sopenharmony_ci	.set_pll	= uniphier_aio_set_pll,
48962306a36Sopenharmony_ci	.set_fmt	= uniphier_aio_set_fmt,
49062306a36Sopenharmony_ci	.startup	= uniphier_aio_startup,
49162306a36Sopenharmony_ci	.shutdown	= uniphier_aio_shutdown,
49262306a36Sopenharmony_ci	.hw_params	= uniphier_aio_hw_params,
49362306a36Sopenharmony_ci	.hw_free	= uniphier_aio_hw_free,
49462306a36Sopenharmony_ci	.prepare	= uniphier_aio_prepare,
49562306a36Sopenharmony_ci};
49662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_i2s_pxs2_ops);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ciconst struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops = {
49962306a36Sopenharmony_ci	.probe		= uniphier_aio_pxs2_probe,
50062306a36Sopenharmony_ci	.remove		= uniphier_aio_dai_remove,
50162306a36Sopenharmony_ci	.set_sysclk	= uniphier_aio_set_sysclk,
50262306a36Sopenharmony_ci	.set_pll	= uniphier_aio_set_pll,
50362306a36Sopenharmony_ci	.startup	= uniphier_aio_startup,
50462306a36Sopenharmony_ci	.shutdown	= uniphier_aio_shutdown,
50562306a36Sopenharmony_ci	.hw_params	= uniphier_aio_hw_params,
50662306a36Sopenharmony_ci	.hw_free	= uniphier_aio_hw_free,
50762306a36Sopenharmony_ci	.prepare	= uniphier_aio_prepare,
50862306a36Sopenharmony_ci};
50962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_spdif_pxs2_ops);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ciconst struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops2 = {
51262306a36Sopenharmony_ci	.probe		= uniphier_aio_pxs2_probe,
51362306a36Sopenharmony_ci	.remove		= uniphier_aio_dai_remove,
51462306a36Sopenharmony_ci	.set_sysclk	= uniphier_aio_set_sysclk,
51562306a36Sopenharmony_ci	.set_pll	= uniphier_aio_set_pll,
51662306a36Sopenharmony_ci	.startup	= uniphier_aio_startup,
51762306a36Sopenharmony_ci	.shutdown	= uniphier_aio_shutdown,
51862306a36Sopenharmony_ci	.hw_params	= uniphier_aio_hw_params,
51962306a36Sopenharmony_ci	.hw_free	= uniphier_aio_hw_free,
52062306a36Sopenharmony_ci	.prepare	= uniphier_aio_prepare,
52162306a36Sopenharmony_ci	.compress_new	= snd_soc_new_compress,
52262306a36Sopenharmony_ci};
52362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_spdif_pxs2_ops2);
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_cistatic void uniphier_aio_dai_suspend(struct snd_soc_dai *dai)
52662306a36Sopenharmony_ci{
52762306a36Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	if (!snd_soc_dai_active(dai))
53062306a36Sopenharmony_ci		return;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	aio->chip->num_wup_aios--;
53362306a36Sopenharmony_ci	if (!aio->chip->num_wup_aios) {
53462306a36Sopenharmony_ci		reset_control_assert(aio->chip->rst);
53562306a36Sopenharmony_ci		clk_disable_unprepare(aio->chip->clk);
53662306a36Sopenharmony_ci	}
53762306a36Sopenharmony_ci}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_cistatic int uniphier_aio_suspend(struct snd_soc_component *component)
54062306a36Sopenharmony_ci{
54162306a36Sopenharmony_ci	struct snd_soc_dai *dai;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	for_each_component_dais(component, dai)
54462306a36Sopenharmony_ci		uniphier_aio_dai_suspend(dai);
54562306a36Sopenharmony_ci	return 0;
54662306a36Sopenharmony_ci}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_cistatic int uniphier_aio_dai_resume(struct snd_soc_dai *dai)
54962306a36Sopenharmony_ci{
55062306a36Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
55162306a36Sopenharmony_ci	int ret, i;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	if (!snd_soc_dai_active(dai))
55462306a36Sopenharmony_ci		return 0;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	if (!aio->chip->active)
55762306a36Sopenharmony_ci		return 0;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	if (!aio->chip->num_wup_aios) {
56062306a36Sopenharmony_ci		ret = clk_prepare_enable(aio->chip->clk);
56162306a36Sopenharmony_ci		if (ret)
56262306a36Sopenharmony_ci			return ret;
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci		ret = reset_control_deassert(aio->chip->rst);
56562306a36Sopenharmony_ci		if (ret)
56662306a36Sopenharmony_ci			goto err_out_clock;
56762306a36Sopenharmony_ci	}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	aio_iecout_set_enable(aio->chip, true);
57062306a36Sopenharmony_ci	aio_chip_init(aio->chip);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(aio->sub); i++) {
57362306a36Sopenharmony_ci		struct uniphier_aio_sub *sub = &aio->sub[i];
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci		if (!sub->spec || !sub->substream)
57662306a36Sopenharmony_ci			continue;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci		ret = aio_init(sub);
57962306a36Sopenharmony_ci		if (ret)
58062306a36Sopenharmony_ci			goto err_out_reset;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci		if (!sub->setting)
58362306a36Sopenharmony_ci			continue;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci		aio_port_reset(sub);
58662306a36Sopenharmony_ci		aio_src_reset(sub);
58762306a36Sopenharmony_ci	}
58862306a36Sopenharmony_ci	aio->chip->num_wup_aios++;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	return 0;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_cierr_out_reset:
59362306a36Sopenharmony_ci	if (!aio->chip->num_wup_aios)
59462306a36Sopenharmony_ci		reset_control_assert(aio->chip->rst);
59562306a36Sopenharmony_cierr_out_clock:
59662306a36Sopenharmony_ci	if (!aio->chip->num_wup_aios)
59762306a36Sopenharmony_ci		clk_disable_unprepare(aio->chip->clk);
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	return ret;
60062306a36Sopenharmony_ci}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_cistatic int uniphier_aio_resume(struct snd_soc_component *component)
60362306a36Sopenharmony_ci{
60462306a36Sopenharmony_ci	struct snd_soc_dai *dai;
60562306a36Sopenharmony_ci	int ret = 0;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	for_each_component_dais(component, dai)
60862306a36Sopenharmony_ci		ret |= uniphier_aio_dai_resume(dai);
60962306a36Sopenharmony_ci	return ret;
61062306a36Sopenharmony_ci}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_cistatic int uniphier_aio_vol_info(struct snd_kcontrol *kcontrol,
61362306a36Sopenharmony_ci				 struct snd_ctl_elem_info *uinfo)
61462306a36Sopenharmony_ci{
61562306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
61662306a36Sopenharmony_ci	uinfo->count = 1;
61762306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
61862306a36Sopenharmony_ci	uinfo->value.integer.max = AUD_VOL_MAX;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	return 0;
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_cistatic int uniphier_aio_vol_get(struct snd_kcontrol *kcontrol,
62462306a36Sopenharmony_ci				struct snd_ctl_elem_value *ucontrol)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
62762306a36Sopenharmony_ci	struct uniphier_aio_chip *chip = snd_soc_component_get_drvdata(comp);
62862306a36Sopenharmony_ci	struct uniphier_aio_sub *sub;
62962306a36Sopenharmony_ci	int oport_hw = kcontrol->private_value;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	sub = find_volume(chip, oport_hw);
63262306a36Sopenharmony_ci	if (!sub)
63362306a36Sopenharmony_ci		return 0;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = sub->vol;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	return 0;
63862306a36Sopenharmony_ci}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_cistatic int uniphier_aio_vol_put(struct snd_kcontrol *kcontrol,
64162306a36Sopenharmony_ci				struct snd_ctl_elem_value *ucontrol)
64262306a36Sopenharmony_ci{
64362306a36Sopenharmony_ci	struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
64462306a36Sopenharmony_ci	struct uniphier_aio_chip *chip = snd_soc_component_get_drvdata(comp);
64562306a36Sopenharmony_ci	struct uniphier_aio_sub *sub;
64662306a36Sopenharmony_ci	int oport_hw = kcontrol->private_value;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	sub = find_volume(chip, oport_hw);
64962306a36Sopenharmony_ci	if (!sub)
65062306a36Sopenharmony_ci		return 0;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	if (sub->vol == ucontrol->value.integer.value[0])
65362306a36Sopenharmony_ci		return 0;
65462306a36Sopenharmony_ci	sub->vol = ucontrol->value.integer.value[0];
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	aio_port_set_volume(sub, sub->vol);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	return 0;
65962306a36Sopenharmony_ci}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_cistatic const struct snd_kcontrol_new uniphier_aio_controls[] = {
66262306a36Sopenharmony_ci	{
66362306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
66462306a36Sopenharmony_ci		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
66562306a36Sopenharmony_ci		.name = "HPCMOUT1 Volume",
66662306a36Sopenharmony_ci		.info = uniphier_aio_vol_info,
66762306a36Sopenharmony_ci		.get = uniphier_aio_vol_get,
66862306a36Sopenharmony_ci		.put = uniphier_aio_vol_put,
66962306a36Sopenharmony_ci		.private_value = AUD_HW_HPCMOUT1,
67062306a36Sopenharmony_ci	},
67162306a36Sopenharmony_ci	{
67262306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
67362306a36Sopenharmony_ci		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
67462306a36Sopenharmony_ci		.name = "PCMOUT1 Volume",
67562306a36Sopenharmony_ci		.info = uniphier_aio_vol_info,
67662306a36Sopenharmony_ci		.get = uniphier_aio_vol_get,
67762306a36Sopenharmony_ci		.put = uniphier_aio_vol_put,
67862306a36Sopenharmony_ci		.private_value = AUD_HW_PCMOUT1,
67962306a36Sopenharmony_ci	},
68062306a36Sopenharmony_ci	{
68162306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
68262306a36Sopenharmony_ci		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
68362306a36Sopenharmony_ci		.name = "PCMOUT2 Volume",
68462306a36Sopenharmony_ci		.info = uniphier_aio_vol_info,
68562306a36Sopenharmony_ci		.get = uniphier_aio_vol_get,
68662306a36Sopenharmony_ci		.put = uniphier_aio_vol_put,
68762306a36Sopenharmony_ci		.private_value = AUD_HW_PCMOUT2,
68862306a36Sopenharmony_ci	},
68962306a36Sopenharmony_ci	{
69062306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
69162306a36Sopenharmony_ci		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
69262306a36Sopenharmony_ci		.name = "PCMOUT3 Volume",
69362306a36Sopenharmony_ci		.info = uniphier_aio_vol_info,
69462306a36Sopenharmony_ci		.get = uniphier_aio_vol_get,
69562306a36Sopenharmony_ci		.put = uniphier_aio_vol_put,
69662306a36Sopenharmony_ci		.private_value = AUD_HW_PCMOUT3,
69762306a36Sopenharmony_ci	},
69862306a36Sopenharmony_ci	{
69962306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
70062306a36Sopenharmony_ci		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
70162306a36Sopenharmony_ci		.name = "HIECOUT1 Volume",
70262306a36Sopenharmony_ci		.info = uniphier_aio_vol_info,
70362306a36Sopenharmony_ci		.get = uniphier_aio_vol_get,
70462306a36Sopenharmony_ci		.put = uniphier_aio_vol_put,
70562306a36Sopenharmony_ci		.private_value = AUD_HW_HIECOUT1,
70662306a36Sopenharmony_ci	},
70762306a36Sopenharmony_ci	{
70862306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
70962306a36Sopenharmony_ci		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
71062306a36Sopenharmony_ci		.name = "IECOUT1 Volume",
71162306a36Sopenharmony_ci		.info = uniphier_aio_vol_info,
71262306a36Sopenharmony_ci		.get = uniphier_aio_vol_get,
71362306a36Sopenharmony_ci		.put = uniphier_aio_vol_put,
71462306a36Sopenharmony_ci		.private_value = AUD_HW_IECOUT1,
71562306a36Sopenharmony_ci	},
71662306a36Sopenharmony_ci};
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_cistatic const struct snd_soc_component_driver uniphier_aio_component = {
71962306a36Sopenharmony_ci	.name = "uniphier-aio",
72062306a36Sopenharmony_ci	.controls = uniphier_aio_controls,
72162306a36Sopenharmony_ci	.num_controls = ARRAY_SIZE(uniphier_aio_controls),
72262306a36Sopenharmony_ci	.suspend = uniphier_aio_suspend,
72362306a36Sopenharmony_ci	.resume  = uniphier_aio_resume,
72462306a36Sopenharmony_ci};
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ciint uniphier_aio_probe(struct platform_device *pdev)
72762306a36Sopenharmony_ci{
72862306a36Sopenharmony_ci	struct uniphier_aio_chip *chip;
72962306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
73062306a36Sopenharmony_ci	int ret, i, j;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
73362306a36Sopenharmony_ci	if (!chip)
73462306a36Sopenharmony_ci		return -ENOMEM;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	chip->chip_spec = of_device_get_match_data(dev);
73762306a36Sopenharmony_ci	if (!chip->chip_spec)
73862306a36Sopenharmony_ci		return -EINVAL;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	chip->regmap_sg = syscon_regmap_lookup_by_phandle(dev->of_node,
74162306a36Sopenharmony_ci							  "socionext,syscon");
74262306a36Sopenharmony_ci	if (IS_ERR(chip->regmap_sg)) {
74362306a36Sopenharmony_ci		if (PTR_ERR(chip->regmap_sg) == -EPROBE_DEFER)
74462306a36Sopenharmony_ci			return -EPROBE_DEFER;
74562306a36Sopenharmony_ci		chip->regmap_sg = NULL;
74662306a36Sopenharmony_ci	}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	chip->clk = devm_clk_get(dev, "aio");
74962306a36Sopenharmony_ci	if (IS_ERR(chip->clk))
75062306a36Sopenharmony_ci		return PTR_ERR(chip->clk);
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	chip->rst = devm_reset_control_get_shared(dev, "aio");
75362306a36Sopenharmony_ci	if (IS_ERR(chip->rst))
75462306a36Sopenharmony_ci		return PTR_ERR(chip->rst);
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	chip->num_aios = chip->chip_spec->num_dais;
75762306a36Sopenharmony_ci	chip->num_wup_aios = chip->num_aios;
75862306a36Sopenharmony_ci	chip->aios = devm_kcalloc(dev,
75962306a36Sopenharmony_ci				  chip->num_aios, sizeof(struct uniphier_aio),
76062306a36Sopenharmony_ci				  GFP_KERNEL);
76162306a36Sopenharmony_ci	if (!chip->aios)
76262306a36Sopenharmony_ci		return -ENOMEM;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	chip->num_plls = chip->chip_spec->num_plls;
76562306a36Sopenharmony_ci	chip->plls = devm_kcalloc(dev,
76662306a36Sopenharmony_ci				  chip->num_plls,
76762306a36Sopenharmony_ci				  sizeof(struct uniphier_aio_pll),
76862306a36Sopenharmony_ci				  GFP_KERNEL);
76962306a36Sopenharmony_ci	if (!chip->plls)
77062306a36Sopenharmony_ci		return -ENOMEM;
77162306a36Sopenharmony_ci	memcpy(chip->plls, chip->chip_spec->plls,
77262306a36Sopenharmony_ci	       sizeof(struct uniphier_aio_pll) * chip->num_plls);
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	for (i = 0; i < chip->num_aios; i++) {
77562306a36Sopenharmony_ci		struct uniphier_aio *aio = &chip->aios[i];
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci		aio->chip = chip;
77862306a36Sopenharmony_ci		aio->fmt = SND_SOC_DAIFMT_I2S;
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(aio->sub); j++) {
78162306a36Sopenharmony_ci			struct uniphier_aio_sub *sub = &aio->sub[j];
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci			sub->aio = aio;
78462306a36Sopenharmony_ci			spin_lock_init(&sub->lock);
78562306a36Sopenharmony_ci		}
78662306a36Sopenharmony_ci	}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	chip->pdev = pdev;
78962306a36Sopenharmony_ci	platform_set_drvdata(pdev, chip);
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	ret = clk_prepare_enable(chip->clk);
79262306a36Sopenharmony_ci	if (ret)
79362306a36Sopenharmony_ci		return ret;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	ret = reset_control_deassert(chip->rst);
79662306a36Sopenharmony_ci	if (ret)
79762306a36Sopenharmony_ci		goto err_out_clock;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	ret = devm_snd_soc_register_component(dev, &uniphier_aio_component,
80062306a36Sopenharmony_ci					      chip->chip_spec->dais,
80162306a36Sopenharmony_ci					      chip->chip_spec->num_dais);
80262306a36Sopenharmony_ci	if (ret) {
80362306a36Sopenharmony_ci		dev_err(dev, "Register component failed.\n");
80462306a36Sopenharmony_ci		goto err_out_reset;
80562306a36Sopenharmony_ci	}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	ret = uniphier_aiodma_soc_register_platform(pdev);
80862306a36Sopenharmony_ci	if (ret) {
80962306a36Sopenharmony_ci		dev_err(dev, "Register platform failed.\n");
81062306a36Sopenharmony_ci		goto err_out_reset;
81162306a36Sopenharmony_ci	}
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	return 0;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_cierr_out_reset:
81662306a36Sopenharmony_ci	reset_control_assert(chip->rst);
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_cierr_out_clock:
81962306a36Sopenharmony_ci	clk_disable_unprepare(chip->clk);
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	return ret;
82262306a36Sopenharmony_ci}
82362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_probe);
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ciint uniphier_aio_remove(struct platform_device *pdev)
82662306a36Sopenharmony_ci{
82762306a36Sopenharmony_ci	struct uniphier_aio_chip *chip = platform_get_drvdata(pdev);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	reset_control_assert(chip->rst);
83062306a36Sopenharmony_ci	clk_disable_unprepare(chip->clk);
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	return 0;
83362306a36Sopenharmony_ci}
83462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_remove);
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ciMODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
83762306a36Sopenharmony_ciMODULE_DESCRIPTION("UniPhier AIO CPU DAI driver.");
83862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
839