brintos

brintos / linux-shallow public Read only

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