18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci//
38c2ecf20Sopenharmony_ci// Socionext UniPhier AIO ALSA CPU DAI driver.
48c2ecf20Sopenharmony_ci//
58c2ecf20Sopenharmony_ci// Copyright (c) 2016-2018 Socionext Inc.
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/clk.h>
88c2ecf20Sopenharmony_ci#include <linux/errno.h>
98c2ecf20Sopenharmony_ci#include <linux/kernel.h>
108c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/of.h>
138c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
148c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
158c2ecf20Sopenharmony_ci#include <linux/reset.h>
168c2ecf20Sopenharmony_ci#include <sound/core.h>
178c2ecf20Sopenharmony_ci#include <sound/pcm.h>
188c2ecf20Sopenharmony_ci#include <sound/pcm_params.h>
198c2ecf20Sopenharmony_ci#include <sound/soc.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include "aio.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic bool is_valid_pll(struct uniphier_aio_chip *chip, int pll_id)
248c2ecf20Sopenharmony_ci{
258c2ecf20Sopenharmony_ci	struct device *dev = &chip->pdev->dev;
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	if (pll_id < 0 || chip->num_plls <= pll_id) {
288c2ecf20Sopenharmony_ci		dev_err(dev, "PLL(%d) is not supported\n", pll_id);
298c2ecf20Sopenharmony_ci		return false;
308c2ecf20Sopenharmony_ci	}
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	return chip->plls[pll_id].enable;
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci/**
368c2ecf20Sopenharmony_ci * find_volume - find volume supported HW port by HW port number
378c2ecf20Sopenharmony_ci * @chip: the AIO chip pointer
388c2ecf20Sopenharmony_ci * @oport_hw: HW port number, one of AUD_HW_XXXX
398c2ecf20Sopenharmony_ci *
408c2ecf20Sopenharmony_ci * Find AIO device from device list by HW port number. Volume feature is
418c2ecf20Sopenharmony_ci * available only in Output and PCM ports, this limitation comes from HW
428c2ecf20Sopenharmony_ci * specifications.
438c2ecf20Sopenharmony_ci *
448c2ecf20Sopenharmony_ci * Return: The pointer of AIO substream if successful, otherwise NULL on error.
458c2ecf20Sopenharmony_ci */
468c2ecf20Sopenharmony_cistatic struct uniphier_aio_sub *find_volume(struct uniphier_aio_chip *chip,
478c2ecf20Sopenharmony_ci					    int oport_hw)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	int i;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	for (i = 0; i < chip->num_aios; i++) {
528c2ecf20Sopenharmony_ci		struct uniphier_aio_sub *sub = &chip->aios[i].sub[0];
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci		if (!sub->swm)
558c2ecf20Sopenharmony_ci			continue;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci		if (sub->swm->oport.hw == oport_hw)
588c2ecf20Sopenharmony_ci			return sub;
598c2ecf20Sopenharmony_ci	}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	return NULL;
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic bool match_spec(const struct uniphier_aio_spec *spec,
658c2ecf20Sopenharmony_ci		       const char *name, int dir)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	if (dir == SNDRV_PCM_STREAM_PLAYBACK &&
688c2ecf20Sopenharmony_ci	    spec->swm.dir != PORT_DIR_OUTPUT) {
698c2ecf20Sopenharmony_ci		return false;
708c2ecf20Sopenharmony_ci	}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	if (dir == SNDRV_PCM_STREAM_CAPTURE &&
738c2ecf20Sopenharmony_ci	    spec->swm.dir != PORT_DIR_INPUT) {
748c2ecf20Sopenharmony_ci		return false;
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	if (spec->name && strcmp(spec->name, name) == 0)
788c2ecf20Sopenharmony_ci		return true;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	if (spec->gname && strcmp(spec->gname, name) == 0)
818c2ecf20Sopenharmony_ci		return true;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	return false;
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci/**
878c2ecf20Sopenharmony_ci * find_spec - find HW specification info by name
888c2ecf20Sopenharmony_ci * @aio: the AIO device pointer
898c2ecf20Sopenharmony_ci * @name: name of device
908c2ecf20Sopenharmony_ci * @direction: the direction of substream, SNDRV_PCM_STREAM_*
918c2ecf20Sopenharmony_ci *
928c2ecf20Sopenharmony_ci * Find hardware specification information from list by device name. This
938c2ecf20Sopenharmony_ci * information is used for telling the difference of SoCs to driver.
948c2ecf20Sopenharmony_ci *
958c2ecf20Sopenharmony_ci * Specification list is array of 'struct uniphier_aio_spec' which is defined
968c2ecf20Sopenharmony_ci * in each drivers (see: aio-i2s.c).
978c2ecf20Sopenharmony_ci *
988c2ecf20Sopenharmony_ci * Return: The pointer of hardware specification of AIO if successful,
998c2ecf20Sopenharmony_ci * otherwise NULL on error.
1008c2ecf20Sopenharmony_ci */
1018c2ecf20Sopenharmony_cistatic const struct uniphier_aio_spec *find_spec(struct uniphier_aio *aio,
1028c2ecf20Sopenharmony_ci						 const char *name,
1038c2ecf20Sopenharmony_ci						 int direction)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	const struct uniphier_aio_chip_spec *chip_spec = aio->chip->chip_spec;
1068c2ecf20Sopenharmony_ci	int i;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	for (i = 0; i < chip_spec->num_specs; i++) {
1098c2ecf20Sopenharmony_ci		const struct uniphier_aio_spec *spec = &chip_spec->specs[i];
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci		if (match_spec(spec, name, direction))
1128c2ecf20Sopenharmony_ci			return spec;
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	return NULL;
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci/**
1198c2ecf20Sopenharmony_ci * find_divider - find clock divider by frequency
1208c2ecf20Sopenharmony_ci * @aio: the AIO device pointer
1218c2ecf20Sopenharmony_ci * @pll_id: PLL ID, should be AUD_PLL_XX
1228c2ecf20Sopenharmony_ci * @freq: required frequency
1238c2ecf20Sopenharmony_ci *
1248c2ecf20Sopenharmony_ci * Find suitable clock divider by frequency.
1258c2ecf20Sopenharmony_ci *
1268c2ecf20Sopenharmony_ci * Return: The ID of PLL if successful, otherwise negative error value.
1278c2ecf20Sopenharmony_ci */
1288c2ecf20Sopenharmony_cistatic int find_divider(struct uniphier_aio *aio, int pll_id, unsigned int freq)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	struct uniphier_aio_pll *pll;
1318c2ecf20Sopenharmony_ci	int mul[] = { 1, 1, 1, 2, };
1328c2ecf20Sopenharmony_ci	int div[] = { 2, 3, 1, 3, };
1338c2ecf20Sopenharmony_ci	int i;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	if (!is_valid_pll(aio->chip, pll_id))
1368c2ecf20Sopenharmony_ci		return -EINVAL;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	pll = &aio->chip->plls[pll_id];
1398c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mul); i++)
1408c2ecf20Sopenharmony_ci		if (pll->freq * mul[i] / div[i] == freq)
1418c2ecf20Sopenharmony_ci			return i;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	return -ENOTSUPP;
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cistatic int uniphier_aio_set_sysclk(struct snd_soc_dai *dai, int clk_id,
1478c2ecf20Sopenharmony_ci				   unsigned int freq, int dir)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
1508c2ecf20Sopenharmony_ci	struct device *dev = &aio->chip->pdev->dev;
1518c2ecf20Sopenharmony_ci	bool pll_auto = false;
1528c2ecf20Sopenharmony_ci	int pll_id, div_id;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	switch (clk_id) {
1558c2ecf20Sopenharmony_ci	case AUD_CLK_IO:
1568c2ecf20Sopenharmony_ci		return -ENOTSUPP;
1578c2ecf20Sopenharmony_ci	case AUD_CLK_A1:
1588c2ecf20Sopenharmony_ci		pll_id = AUD_PLL_A1;
1598c2ecf20Sopenharmony_ci		break;
1608c2ecf20Sopenharmony_ci	case AUD_CLK_F1:
1618c2ecf20Sopenharmony_ci		pll_id = AUD_PLL_F1;
1628c2ecf20Sopenharmony_ci		break;
1638c2ecf20Sopenharmony_ci	case AUD_CLK_A2:
1648c2ecf20Sopenharmony_ci		pll_id = AUD_PLL_A2;
1658c2ecf20Sopenharmony_ci		break;
1668c2ecf20Sopenharmony_ci	case AUD_CLK_F2:
1678c2ecf20Sopenharmony_ci		pll_id = AUD_PLL_F2;
1688c2ecf20Sopenharmony_ci		break;
1698c2ecf20Sopenharmony_ci	case AUD_CLK_A:
1708c2ecf20Sopenharmony_ci		pll_id = AUD_PLL_A1;
1718c2ecf20Sopenharmony_ci		pll_auto = true;
1728c2ecf20Sopenharmony_ci		break;
1738c2ecf20Sopenharmony_ci	case AUD_CLK_F:
1748c2ecf20Sopenharmony_ci		pll_id = AUD_PLL_F1;
1758c2ecf20Sopenharmony_ci		pll_auto = true;
1768c2ecf20Sopenharmony_ci		break;
1778c2ecf20Sopenharmony_ci	case AUD_CLK_APLL:
1788c2ecf20Sopenharmony_ci		pll_id = AUD_PLL_APLL;
1798c2ecf20Sopenharmony_ci		break;
1808c2ecf20Sopenharmony_ci	case AUD_CLK_RX0:
1818c2ecf20Sopenharmony_ci		pll_id = AUD_PLL_RX0;
1828c2ecf20Sopenharmony_ci		break;
1838c2ecf20Sopenharmony_ci	case AUD_CLK_USB0:
1848c2ecf20Sopenharmony_ci		pll_id = AUD_PLL_USB0;
1858c2ecf20Sopenharmony_ci		break;
1868c2ecf20Sopenharmony_ci	case AUD_CLK_HSC0:
1878c2ecf20Sopenharmony_ci		pll_id = AUD_PLL_HSC0;
1888c2ecf20Sopenharmony_ci		break;
1898c2ecf20Sopenharmony_ci	default:
1908c2ecf20Sopenharmony_ci		dev_err(dev, "Sysclk(%d) is not supported\n", clk_id);
1918c2ecf20Sopenharmony_ci		return -EINVAL;
1928c2ecf20Sopenharmony_ci	}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	if (pll_auto) {
1958c2ecf20Sopenharmony_ci		for (pll_id = 0; pll_id < aio->chip->num_plls; pll_id++) {
1968c2ecf20Sopenharmony_ci			div_id = find_divider(aio, pll_id, freq);
1978c2ecf20Sopenharmony_ci			if (div_id >= 0) {
1988c2ecf20Sopenharmony_ci				aio->plldiv = div_id;
1998c2ecf20Sopenharmony_ci				break;
2008c2ecf20Sopenharmony_ci			}
2018c2ecf20Sopenharmony_ci		}
2028c2ecf20Sopenharmony_ci		if (pll_id == aio->chip->num_plls) {
2038c2ecf20Sopenharmony_ci			dev_err(dev, "Sysclk frequency is not supported(%d)\n",
2048c2ecf20Sopenharmony_ci				freq);
2058c2ecf20Sopenharmony_ci			return -EINVAL;
2068c2ecf20Sopenharmony_ci		}
2078c2ecf20Sopenharmony_ci	}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	if (dir == SND_SOC_CLOCK_OUT)
2108c2ecf20Sopenharmony_ci		aio->pll_out = pll_id;
2118c2ecf20Sopenharmony_ci	else
2128c2ecf20Sopenharmony_ci		aio->pll_in = pll_id;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	return 0;
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic int uniphier_aio_set_pll(struct snd_soc_dai *dai, int pll_id,
2188c2ecf20Sopenharmony_ci				int source, unsigned int freq_in,
2198c2ecf20Sopenharmony_ci				unsigned int freq_out)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
2228c2ecf20Sopenharmony_ci	int ret;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	if (!is_valid_pll(aio->chip, pll_id))
2258c2ecf20Sopenharmony_ci		return -EINVAL;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	ret = aio_chip_set_pll(aio->chip, pll_id, freq_out);
2288c2ecf20Sopenharmony_ci	if (ret < 0)
2298c2ecf20Sopenharmony_ci		return ret;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	return 0;
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_cistatic int uniphier_aio_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
2378c2ecf20Sopenharmony_ci	struct device *dev = &aio->chip->pdev->dev;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
2408c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_LEFT_J:
2418c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_RIGHT_J:
2428c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_I2S:
2438c2ecf20Sopenharmony_ci		aio->fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
2448c2ecf20Sopenharmony_ci		break;
2458c2ecf20Sopenharmony_ci	default:
2468c2ecf20Sopenharmony_ci		dev_err(dev, "Format is not supported(%d)\n",
2478c2ecf20Sopenharmony_ci			fmt & SND_SOC_DAIFMT_FORMAT_MASK);
2488c2ecf20Sopenharmony_ci		return -EINVAL;
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	return 0;
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic int uniphier_aio_startup(struct snd_pcm_substream *substream,
2558c2ecf20Sopenharmony_ci				struct snd_soc_dai *dai)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
2588c2ecf20Sopenharmony_ci	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
2598c2ecf20Sopenharmony_ci	int ret;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	sub->substream = substream;
2628c2ecf20Sopenharmony_ci	sub->pass_through = 0;
2638c2ecf20Sopenharmony_ci	sub->use_mmap = true;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	ret = aio_init(sub);
2668c2ecf20Sopenharmony_ci	if (ret)
2678c2ecf20Sopenharmony_ci		return ret;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	return 0;
2708c2ecf20Sopenharmony_ci}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cistatic void uniphier_aio_shutdown(struct snd_pcm_substream *substream,
2738c2ecf20Sopenharmony_ci				  struct snd_soc_dai *dai)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
2768c2ecf20Sopenharmony_ci	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	sub->substream = NULL;
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_cistatic int uniphier_aio_hw_params(struct snd_pcm_substream *substream,
2828c2ecf20Sopenharmony_ci				  struct snd_pcm_hw_params *params,
2838c2ecf20Sopenharmony_ci				  struct snd_soc_dai *dai)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
2868c2ecf20Sopenharmony_ci	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
2878c2ecf20Sopenharmony_ci	struct device *dev = &aio->chip->pdev->dev;
2888c2ecf20Sopenharmony_ci	int freq, ret;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	switch (params_rate(params)) {
2918c2ecf20Sopenharmony_ci	case 48000:
2928c2ecf20Sopenharmony_ci	case 32000:
2938c2ecf20Sopenharmony_ci	case 24000:
2948c2ecf20Sopenharmony_ci		freq = 12288000;
2958c2ecf20Sopenharmony_ci		break;
2968c2ecf20Sopenharmony_ci	case 44100:
2978c2ecf20Sopenharmony_ci	case 22050:
2988c2ecf20Sopenharmony_ci		freq = 11289600;
2998c2ecf20Sopenharmony_ci		break;
3008c2ecf20Sopenharmony_ci	default:
3018c2ecf20Sopenharmony_ci		dev_err(dev, "Rate is not supported(%d)\n",
3028c2ecf20Sopenharmony_ci			params_rate(params));
3038c2ecf20Sopenharmony_ci		return -EINVAL;
3048c2ecf20Sopenharmony_ci	}
3058c2ecf20Sopenharmony_ci	ret = snd_soc_dai_set_sysclk(dai, AUD_CLK_A,
3068c2ecf20Sopenharmony_ci				     freq, SND_SOC_CLOCK_OUT);
3078c2ecf20Sopenharmony_ci	if (ret)
3088c2ecf20Sopenharmony_ci		return ret;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	sub->params = *params;
3118c2ecf20Sopenharmony_ci	sub->setting = 1;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	aio_port_reset(sub);
3148c2ecf20Sopenharmony_ci	aio_port_set_volume(sub, sub->vol);
3158c2ecf20Sopenharmony_ci	aio_src_reset(sub);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	return 0;
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_cistatic int uniphier_aio_hw_free(struct snd_pcm_substream *substream,
3218c2ecf20Sopenharmony_ci				struct snd_soc_dai *dai)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
3248c2ecf20Sopenharmony_ci	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	sub->setting = 0;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	return 0;
3298c2ecf20Sopenharmony_ci}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_cistatic int uniphier_aio_prepare(struct snd_pcm_substream *substream,
3328c2ecf20Sopenharmony_ci				struct snd_soc_dai *dai)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
3358c2ecf20Sopenharmony_ci	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
3368c2ecf20Sopenharmony_ci	int ret;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	ret = aio_port_set_param(sub, sub->pass_through, &sub->params);
3398c2ecf20Sopenharmony_ci	if (ret)
3408c2ecf20Sopenharmony_ci		return ret;
3418c2ecf20Sopenharmony_ci	ret = aio_src_set_param(sub, &sub->params);
3428c2ecf20Sopenharmony_ci	if (ret)
3438c2ecf20Sopenharmony_ci		return ret;
3448c2ecf20Sopenharmony_ci	aio_port_set_enable(sub, 1);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	ret = aio_if_set_param(sub, sub->pass_through);
3478c2ecf20Sopenharmony_ci	if (ret)
3488c2ecf20Sopenharmony_ci		return ret;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	if (sub->swm->type == PORT_TYPE_CONV) {
3518c2ecf20Sopenharmony_ci		ret = aio_srcif_set_param(sub);
3528c2ecf20Sopenharmony_ci		if (ret)
3538c2ecf20Sopenharmony_ci			return ret;
3548c2ecf20Sopenharmony_ci		ret = aio_srcch_set_param(sub);
3558c2ecf20Sopenharmony_ci		if (ret)
3568c2ecf20Sopenharmony_ci			return ret;
3578c2ecf20Sopenharmony_ci		aio_srcch_set_enable(sub, 1);
3588c2ecf20Sopenharmony_ci	}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	return 0;
3618c2ecf20Sopenharmony_ci}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ciconst struct snd_soc_dai_ops uniphier_aio_i2s_ops = {
3648c2ecf20Sopenharmony_ci	.set_sysclk  = uniphier_aio_set_sysclk,
3658c2ecf20Sopenharmony_ci	.set_pll     = uniphier_aio_set_pll,
3668c2ecf20Sopenharmony_ci	.set_fmt     = uniphier_aio_set_fmt,
3678c2ecf20Sopenharmony_ci	.startup     = uniphier_aio_startup,
3688c2ecf20Sopenharmony_ci	.shutdown    = uniphier_aio_shutdown,
3698c2ecf20Sopenharmony_ci	.hw_params   = uniphier_aio_hw_params,
3708c2ecf20Sopenharmony_ci	.hw_free     = uniphier_aio_hw_free,
3718c2ecf20Sopenharmony_ci	.prepare     = uniphier_aio_prepare,
3728c2ecf20Sopenharmony_ci};
3738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_i2s_ops);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ciconst struct snd_soc_dai_ops uniphier_aio_spdif_ops = {
3768c2ecf20Sopenharmony_ci	.set_sysclk  = uniphier_aio_set_sysclk,
3778c2ecf20Sopenharmony_ci	.set_pll     = uniphier_aio_set_pll,
3788c2ecf20Sopenharmony_ci	.startup     = uniphier_aio_startup,
3798c2ecf20Sopenharmony_ci	.shutdown    = uniphier_aio_shutdown,
3808c2ecf20Sopenharmony_ci	.hw_params   = uniphier_aio_hw_params,
3818c2ecf20Sopenharmony_ci	.hw_free     = uniphier_aio_hw_free,
3828c2ecf20Sopenharmony_ci	.prepare     = uniphier_aio_prepare,
3838c2ecf20Sopenharmony_ci};
3848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_spdif_ops);
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ciint uniphier_aio_dai_probe(struct snd_soc_dai *dai)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
3898c2ecf20Sopenharmony_ci	int i;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(aio->sub); i++) {
3928c2ecf20Sopenharmony_ci		struct uniphier_aio_sub *sub = &aio->sub[i];
3938c2ecf20Sopenharmony_ci		const struct uniphier_aio_spec *spec;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci		spec = find_spec(aio, dai->name, i);
3968c2ecf20Sopenharmony_ci		if (!spec)
3978c2ecf20Sopenharmony_ci			continue;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci		sub->swm = &spec->swm;
4008c2ecf20Sopenharmony_ci		sub->spec = spec;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci		sub->vol = AUD_VOL_INIT;
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	aio_iecout_set_enable(aio->chip, true);
4068c2ecf20Sopenharmony_ci	aio_chip_init(aio->chip);
4078c2ecf20Sopenharmony_ci	aio->chip->active = 1;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	return 0;
4108c2ecf20Sopenharmony_ci}
4118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_dai_probe);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ciint uniphier_aio_dai_remove(struct snd_soc_dai *dai)
4148c2ecf20Sopenharmony_ci{
4158c2ecf20Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	aio->chip->active = 0;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	return 0;
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_dai_remove);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_cistatic void uniphier_aio_dai_suspend(struct snd_soc_dai *dai)
4248c2ecf20Sopenharmony_ci{
4258c2ecf20Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	if (!snd_soc_dai_active(dai))
4288c2ecf20Sopenharmony_ci		return;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	aio->chip->num_wup_aios--;
4318c2ecf20Sopenharmony_ci	if (!aio->chip->num_wup_aios) {
4328c2ecf20Sopenharmony_ci		reset_control_assert(aio->chip->rst);
4338c2ecf20Sopenharmony_ci		clk_disable_unprepare(aio->chip->clk);
4348c2ecf20Sopenharmony_ci	}
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_cistatic int uniphier_aio_suspend(struct snd_soc_component *component)
4388c2ecf20Sopenharmony_ci{
4398c2ecf20Sopenharmony_ci	struct snd_soc_dai *dai;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	for_each_component_dais(component, dai)
4428c2ecf20Sopenharmony_ci		uniphier_aio_dai_suspend(dai);
4438c2ecf20Sopenharmony_ci	return 0;
4448c2ecf20Sopenharmony_ci}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_cistatic int uniphier_aio_dai_resume(struct snd_soc_dai *dai)
4478c2ecf20Sopenharmony_ci{
4488c2ecf20Sopenharmony_ci	struct uniphier_aio *aio = uniphier_priv(dai);
4498c2ecf20Sopenharmony_ci	int ret, i;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	if (!snd_soc_dai_active(dai))
4528c2ecf20Sopenharmony_ci		return 0;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	if (!aio->chip->active)
4558c2ecf20Sopenharmony_ci		return 0;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	if (!aio->chip->num_wup_aios) {
4588c2ecf20Sopenharmony_ci		ret = clk_prepare_enable(aio->chip->clk);
4598c2ecf20Sopenharmony_ci		if (ret)
4608c2ecf20Sopenharmony_ci			return ret;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci		ret = reset_control_deassert(aio->chip->rst);
4638c2ecf20Sopenharmony_ci		if (ret)
4648c2ecf20Sopenharmony_ci			goto err_out_clock;
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	aio_iecout_set_enable(aio->chip, true);
4688c2ecf20Sopenharmony_ci	aio_chip_init(aio->chip);
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(aio->sub); i++) {
4718c2ecf20Sopenharmony_ci		struct uniphier_aio_sub *sub = &aio->sub[i];
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci		if (!sub->spec || !sub->substream)
4748c2ecf20Sopenharmony_ci			continue;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci		ret = aio_init(sub);
4778c2ecf20Sopenharmony_ci		if (ret)
4788c2ecf20Sopenharmony_ci			goto err_out_reset;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci		if (!sub->setting)
4818c2ecf20Sopenharmony_ci			continue;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci		aio_port_reset(sub);
4848c2ecf20Sopenharmony_ci		aio_src_reset(sub);
4858c2ecf20Sopenharmony_ci	}
4868c2ecf20Sopenharmony_ci	aio->chip->num_wup_aios++;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	return 0;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_cierr_out_reset:
4918c2ecf20Sopenharmony_ci	if (!aio->chip->num_wup_aios)
4928c2ecf20Sopenharmony_ci		reset_control_assert(aio->chip->rst);
4938c2ecf20Sopenharmony_cierr_out_clock:
4948c2ecf20Sopenharmony_ci	if (!aio->chip->num_wup_aios)
4958c2ecf20Sopenharmony_ci		clk_disable_unprepare(aio->chip->clk);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	return ret;
4988c2ecf20Sopenharmony_ci}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_cistatic int uniphier_aio_resume(struct snd_soc_component *component)
5018c2ecf20Sopenharmony_ci{
5028c2ecf20Sopenharmony_ci	struct snd_soc_dai *dai;
5038c2ecf20Sopenharmony_ci	int ret = 0;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	for_each_component_dais(component, dai)
5068c2ecf20Sopenharmony_ci		ret |= uniphier_aio_dai_resume(dai);
5078c2ecf20Sopenharmony_ci	return ret;
5088c2ecf20Sopenharmony_ci}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cistatic int uniphier_aio_vol_info(struct snd_kcontrol *kcontrol,
5118c2ecf20Sopenharmony_ci				 struct snd_ctl_elem_info *uinfo)
5128c2ecf20Sopenharmony_ci{
5138c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
5148c2ecf20Sopenharmony_ci	uinfo->count = 1;
5158c2ecf20Sopenharmony_ci	uinfo->value.integer.min = 0;
5168c2ecf20Sopenharmony_ci	uinfo->value.integer.max = AUD_VOL_MAX;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	return 0;
5198c2ecf20Sopenharmony_ci}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cistatic int uniphier_aio_vol_get(struct snd_kcontrol *kcontrol,
5228c2ecf20Sopenharmony_ci				struct snd_ctl_elem_value *ucontrol)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
5258c2ecf20Sopenharmony_ci	struct uniphier_aio_chip *chip = snd_soc_component_get_drvdata(comp);
5268c2ecf20Sopenharmony_ci	struct uniphier_aio_sub *sub;
5278c2ecf20Sopenharmony_ci	int oport_hw = kcontrol->private_value;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	sub = find_volume(chip, oport_hw);
5308c2ecf20Sopenharmony_ci	if (!sub)
5318c2ecf20Sopenharmony_ci		return 0;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] = sub->vol;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	return 0;
5368c2ecf20Sopenharmony_ci}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_cistatic int uniphier_aio_vol_put(struct snd_kcontrol *kcontrol,
5398c2ecf20Sopenharmony_ci				struct snd_ctl_elem_value *ucontrol)
5408c2ecf20Sopenharmony_ci{
5418c2ecf20Sopenharmony_ci	struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
5428c2ecf20Sopenharmony_ci	struct uniphier_aio_chip *chip = snd_soc_component_get_drvdata(comp);
5438c2ecf20Sopenharmony_ci	struct uniphier_aio_sub *sub;
5448c2ecf20Sopenharmony_ci	int oport_hw = kcontrol->private_value;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	sub = find_volume(chip, oport_hw);
5478c2ecf20Sopenharmony_ci	if (!sub)
5488c2ecf20Sopenharmony_ci		return 0;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	if (sub->vol == ucontrol->value.integer.value[0])
5518c2ecf20Sopenharmony_ci		return 0;
5528c2ecf20Sopenharmony_ci	sub->vol = ucontrol->value.integer.value[0];
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	aio_port_set_volume(sub, sub->vol);
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	return 0;
5578c2ecf20Sopenharmony_ci}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new uniphier_aio_controls[] = {
5608c2ecf20Sopenharmony_ci	{
5618c2ecf20Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5628c2ecf20Sopenharmony_ci		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
5638c2ecf20Sopenharmony_ci		.name = "HPCMOUT1 Volume",
5648c2ecf20Sopenharmony_ci		.info = uniphier_aio_vol_info,
5658c2ecf20Sopenharmony_ci		.get = uniphier_aio_vol_get,
5668c2ecf20Sopenharmony_ci		.put = uniphier_aio_vol_put,
5678c2ecf20Sopenharmony_ci		.private_value = AUD_HW_HPCMOUT1,
5688c2ecf20Sopenharmony_ci	},
5698c2ecf20Sopenharmony_ci	{
5708c2ecf20Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5718c2ecf20Sopenharmony_ci		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
5728c2ecf20Sopenharmony_ci		.name = "PCMOUT1 Volume",
5738c2ecf20Sopenharmony_ci		.info = uniphier_aio_vol_info,
5748c2ecf20Sopenharmony_ci		.get = uniphier_aio_vol_get,
5758c2ecf20Sopenharmony_ci		.put = uniphier_aio_vol_put,
5768c2ecf20Sopenharmony_ci		.private_value = AUD_HW_PCMOUT1,
5778c2ecf20Sopenharmony_ci	},
5788c2ecf20Sopenharmony_ci	{
5798c2ecf20Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5808c2ecf20Sopenharmony_ci		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
5818c2ecf20Sopenharmony_ci		.name = "PCMOUT2 Volume",
5828c2ecf20Sopenharmony_ci		.info = uniphier_aio_vol_info,
5838c2ecf20Sopenharmony_ci		.get = uniphier_aio_vol_get,
5848c2ecf20Sopenharmony_ci		.put = uniphier_aio_vol_put,
5858c2ecf20Sopenharmony_ci		.private_value = AUD_HW_PCMOUT2,
5868c2ecf20Sopenharmony_ci	},
5878c2ecf20Sopenharmony_ci	{
5888c2ecf20Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5898c2ecf20Sopenharmony_ci		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
5908c2ecf20Sopenharmony_ci		.name = "PCMOUT3 Volume",
5918c2ecf20Sopenharmony_ci		.info = uniphier_aio_vol_info,
5928c2ecf20Sopenharmony_ci		.get = uniphier_aio_vol_get,
5938c2ecf20Sopenharmony_ci		.put = uniphier_aio_vol_put,
5948c2ecf20Sopenharmony_ci		.private_value = AUD_HW_PCMOUT3,
5958c2ecf20Sopenharmony_ci	},
5968c2ecf20Sopenharmony_ci	{
5978c2ecf20Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5988c2ecf20Sopenharmony_ci		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
5998c2ecf20Sopenharmony_ci		.name = "HIECOUT1 Volume",
6008c2ecf20Sopenharmony_ci		.info = uniphier_aio_vol_info,
6018c2ecf20Sopenharmony_ci		.get = uniphier_aio_vol_get,
6028c2ecf20Sopenharmony_ci		.put = uniphier_aio_vol_put,
6038c2ecf20Sopenharmony_ci		.private_value = AUD_HW_HIECOUT1,
6048c2ecf20Sopenharmony_ci	},
6058c2ecf20Sopenharmony_ci	{
6068c2ecf20Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6078c2ecf20Sopenharmony_ci		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
6088c2ecf20Sopenharmony_ci		.name = "IECOUT1 Volume",
6098c2ecf20Sopenharmony_ci		.info = uniphier_aio_vol_info,
6108c2ecf20Sopenharmony_ci		.get = uniphier_aio_vol_get,
6118c2ecf20Sopenharmony_ci		.put = uniphier_aio_vol_put,
6128c2ecf20Sopenharmony_ci		.private_value = AUD_HW_IECOUT1,
6138c2ecf20Sopenharmony_ci	},
6148c2ecf20Sopenharmony_ci};
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver uniphier_aio_component = {
6178c2ecf20Sopenharmony_ci	.name = "uniphier-aio",
6188c2ecf20Sopenharmony_ci	.controls = uniphier_aio_controls,
6198c2ecf20Sopenharmony_ci	.num_controls = ARRAY_SIZE(uniphier_aio_controls),
6208c2ecf20Sopenharmony_ci	.suspend = uniphier_aio_suspend,
6218c2ecf20Sopenharmony_ci	.resume  = uniphier_aio_resume,
6228c2ecf20Sopenharmony_ci};
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ciint uniphier_aio_probe(struct platform_device *pdev)
6258c2ecf20Sopenharmony_ci{
6268c2ecf20Sopenharmony_ci	struct uniphier_aio_chip *chip;
6278c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
6288c2ecf20Sopenharmony_ci	int ret, i, j;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
6318c2ecf20Sopenharmony_ci	if (!chip)
6328c2ecf20Sopenharmony_ci		return -ENOMEM;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	chip->chip_spec = of_device_get_match_data(dev);
6358c2ecf20Sopenharmony_ci	if (!chip->chip_spec)
6368c2ecf20Sopenharmony_ci		return -EINVAL;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	chip->regmap_sg = syscon_regmap_lookup_by_phandle(dev->of_node,
6398c2ecf20Sopenharmony_ci							  "socionext,syscon");
6408c2ecf20Sopenharmony_ci	if (IS_ERR(chip->regmap_sg)) {
6418c2ecf20Sopenharmony_ci		if (PTR_ERR(chip->regmap_sg) == -EPROBE_DEFER)
6428c2ecf20Sopenharmony_ci			return -EPROBE_DEFER;
6438c2ecf20Sopenharmony_ci		chip->regmap_sg = NULL;
6448c2ecf20Sopenharmony_ci	}
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	chip->clk = devm_clk_get(dev, "aio");
6478c2ecf20Sopenharmony_ci	if (IS_ERR(chip->clk))
6488c2ecf20Sopenharmony_ci		return PTR_ERR(chip->clk);
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	chip->rst = devm_reset_control_get_shared(dev, "aio");
6518c2ecf20Sopenharmony_ci	if (IS_ERR(chip->rst))
6528c2ecf20Sopenharmony_ci		return PTR_ERR(chip->rst);
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	chip->num_aios = chip->chip_spec->num_dais;
6558c2ecf20Sopenharmony_ci	chip->num_wup_aios = chip->num_aios;
6568c2ecf20Sopenharmony_ci	chip->aios = devm_kcalloc(dev,
6578c2ecf20Sopenharmony_ci				  chip->num_aios, sizeof(struct uniphier_aio),
6588c2ecf20Sopenharmony_ci				  GFP_KERNEL);
6598c2ecf20Sopenharmony_ci	if (!chip->aios)
6608c2ecf20Sopenharmony_ci		return -ENOMEM;
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	chip->num_plls = chip->chip_spec->num_plls;
6638c2ecf20Sopenharmony_ci	chip->plls = devm_kcalloc(dev,
6648c2ecf20Sopenharmony_ci				  chip->num_plls,
6658c2ecf20Sopenharmony_ci				  sizeof(struct uniphier_aio_pll),
6668c2ecf20Sopenharmony_ci				  GFP_KERNEL);
6678c2ecf20Sopenharmony_ci	if (!chip->plls)
6688c2ecf20Sopenharmony_ci		return -ENOMEM;
6698c2ecf20Sopenharmony_ci	memcpy(chip->plls, chip->chip_spec->plls,
6708c2ecf20Sopenharmony_ci	       sizeof(struct uniphier_aio_pll) * chip->num_plls);
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	for (i = 0; i < chip->num_aios; i++) {
6738c2ecf20Sopenharmony_ci		struct uniphier_aio *aio = &chip->aios[i];
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci		aio->chip = chip;
6768c2ecf20Sopenharmony_ci		aio->fmt = SND_SOC_DAIFMT_I2S;
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(aio->sub); j++) {
6798c2ecf20Sopenharmony_ci			struct uniphier_aio_sub *sub = &aio->sub[j];
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci			sub->aio = aio;
6828c2ecf20Sopenharmony_ci			spin_lock_init(&sub->lock);
6838c2ecf20Sopenharmony_ci		}
6848c2ecf20Sopenharmony_ci	}
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	chip->pdev = pdev;
6878c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, chip);
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(chip->clk);
6908c2ecf20Sopenharmony_ci	if (ret)
6918c2ecf20Sopenharmony_ci		return ret;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	ret = reset_control_deassert(chip->rst);
6948c2ecf20Sopenharmony_ci	if (ret)
6958c2ecf20Sopenharmony_ci		goto err_out_clock;
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	ret = devm_snd_soc_register_component(dev, &uniphier_aio_component,
6988c2ecf20Sopenharmony_ci					      chip->chip_spec->dais,
6998c2ecf20Sopenharmony_ci					      chip->chip_spec->num_dais);
7008c2ecf20Sopenharmony_ci	if (ret) {
7018c2ecf20Sopenharmony_ci		dev_err(dev, "Register component failed.\n");
7028c2ecf20Sopenharmony_ci		goto err_out_reset;
7038c2ecf20Sopenharmony_ci	}
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	ret = uniphier_aiodma_soc_register_platform(pdev);
7068c2ecf20Sopenharmony_ci	if (ret) {
7078c2ecf20Sopenharmony_ci		dev_err(dev, "Register platform failed.\n");
7088c2ecf20Sopenharmony_ci		goto err_out_reset;
7098c2ecf20Sopenharmony_ci	}
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	return 0;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_cierr_out_reset:
7148c2ecf20Sopenharmony_ci	reset_control_assert(chip->rst);
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_cierr_out_clock:
7178c2ecf20Sopenharmony_ci	clk_disable_unprepare(chip->clk);
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	return ret;
7208c2ecf20Sopenharmony_ci}
7218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_probe);
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ciint uniphier_aio_remove(struct platform_device *pdev)
7248c2ecf20Sopenharmony_ci{
7258c2ecf20Sopenharmony_ci	struct uniphier_aio_chip *chip = platform_get_drvdata(pdev);
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	reset_control_assert(chip->rst);
7288c2ecf20Sopenharmony_ci	clk_disable_unprepare(chip->clk);
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	return 0;
7318c2ecf20Sopenharmony_ci}
7328c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_remove);
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ciMODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
7358c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("UniPhier AIO CPU DAI driver.");
7368c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
737