cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

aio-cpu.c (17023B)


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