Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // Socionext UniPhier AIO ALSA CPU DAI driver.
0004 //
0005 // Copyright (c) 2016-2018 Socionext Inc.
0006 
0007 #include <linux/clk.h>
0008 #include <linux/errno.h>
0009 #include <linux/kernel.h>
0010 #include <linux/mfd/syscon.h>
0011 #include <linux/module.h>
0012 #include <linux/of.h>
0013 #include <linux/of_platform.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/reset.h>
0016 #include <sound/core.h>
0017 #include <sound/pcm.h>
0018 #include <sound/pcm_params.h>
0019 #include <sound/soc.h>
0020 
0021 #include "aio.h"
0022 
0023 static bool is_valid_pll(struct uniphier_aio_chip *chip, int pll_id)
0024 {
0025     struct device *dev = &chip->pdev->dev;
0026 
0027     if (pll_id < 0 || chip->num_plls <= pll_id) {
0028         dev_err(dev, "PLL(%d) is not supported\n", pll_id);
0029         return false;
0030     }
0031 
0032     return chip->plls[pll_id].enable;
0033 }
0034 
0035 /**
0036  * find_volume - find volume supported HW port by HW port number
0037  * @chip: the AIO chip pointer
0038  * @oport_hw: HW port number, one of AUD_HW_XXXX
0039  *
0040  * Find AIO device from device list by HW port number. Volume feature is
0041  * available only in Output and PCM ports, this limitation comes from HW
0042  * specifications.
0043  *
0044  * Return: The pointer of AIO substream if successful, otherwise NULL on error.
0045  */
0046 static struct uniphier_aio_sub *find_volume(struct uniphier_aio_chip *chip,
0047                         int oport_hw)
0048 {
0049     int i;
0050 
0051     for (i = 0; i < chip->num_aios; i++) {
0052         struct uniphier_aio_sub *sub = &chip->aios[i].sub[0];
0053 
0054         if (!sub->swm)
0055             continue;
0056 
0057         if (sub->swm->oport.hw == oport_hw)
0058             return sub;
0059     }
0060 
0061     return NULL;
0062 }
0063 
0064 static bool match_spec(const struct uniphier_aio_spec *spec,
0065                const char *name, int dir)
0066 {
0067     if (dir == SNDRV_PCM_STREAM_PLAYBACK &&
0068         spec->swm.dir != PORT_DIR_OUTPUT) {
0069         return false;
0070     }
0071 
0072     if (dir == SNDRV_PCM_STREAM_CAPTURE &&
0073         spec->swm.dir != PORT_DIR_INPUT) {
0074         return false;
0075     }
0076 
0077     if (spec->name && strcmp(spec->name, name) == 0)
0078         return true;
0079 
0080     if (spec->gname && strcmp(spec->gname, name) == 0)
0081         return true;
0082 
0083     return false;
0084 }
0085 
0086 /**
0087  * find_spec - find HW specification info by name
0088  * @aio: the AIO device pointer
0089  * @name: name of device
0090  * @direction: the direction of substream, SNDRV_PCM_STREAM_*
0091  *
0092  * Find hardware specification information from list by device name. This
0093  * information is used for telling the difference of SoCs to driver.
0094  *
0095  * Specification list is array of 'struct uniphier_aio_spec' which is defined
0096  * in each drivers (see: aio-i2s.c).
0097  *
0098  * Return: The pointer of hardware specification of AIO if successful,
0099  * otherwise NULL on error.
0100  */
0101 static const struct uniphier_aio_spec *find_spec(struct uniphier_aio *aio,
0102                          const char *name,
0103                          int direction)
0104 {
0105     const struct uniphier_aio_chip_spec *chip_spec = aio->chip->chip_spec;
0106     int i;
0107 
0108     for (i = 0; i < chip_spec->num_specs; i++) {
0109         const struct uniphier_aio_spec *spec = &chip_spec->specs[i];
0110 
0111         if (match_spec(spec, name, direction))
0112             return spec;
0113     }
0114 
0115     return NULL;
0116 }
0117 
0118 /**
0119  * find_divider - find clock divider by frequency
0120  * @aio: the AIO device pointer
0121  * @pll_id: PLL ID, should be AUD_PLL_XX
0122  * @freq: required frequency
0123  *
0124  * Find suitable clock divider by frequency.
0125  *
0126  * Return: The ID of PLL if successful, otherwise negative error value.
0127  */
0128 static int find_divider(struct uniphier_aio *aio, int pll_id, unsigned int freq)
0129 {
0130     struct uniphier_aio_pll *pll;
0131     static const int mul[] = { 1, 1, 1, 2, };
0132     static const int div[] = { 2, 3, 1, 3, };
0133     int i;
0134 
0135     if (!is_valid_pll(aio->chip, pll_id))
0136         return -EINVAL;
0137 
0138     pll = &aio->chip->plls[pll_id];
0139     for (i = 0; i < ARRAY_SIZE(mul); i++)
0140         if (pll->freq * mul[i] / div[i] == freq)
0141             return i;
0142 
0143     return -ENOTSUPP;
0144 }
0145 
0146 static int uniphier_aio_set_sysclk(struct snd_soc_dai *dai, int clk_id,
0147                    unsigned int freq, int dir)
0148 {
0149     struct uniphier_aio *aio = uniphier_priv(dai);
0150     struct device *dev = &aio->chip->pdev->dev;
0151     bool pll_auto = false;
0152     int pll_id, div_id;
0153 
0154     switch (clk_id) {
0155     case AUD_CLK_IO:
0156         return -ENOTSUPP;
0157     case AUD_CLK_A1:
0158         pll_id = AUD_PLL_A1;
0159         break;
0160     case AUD_CLK_F1:
0161         pll_id = AUD_PLL_F1;
0162         break;
0163     case AUD_CLK_A2:
0164         pll_id = AUD_PLL_A2;
0165         break;
0166     case AUD_CLK_F2:
0167         pll_id = AUD_PLL_F2;
0168         break;
0169     case AUD_CLK_A:
0170         pll_id = AUD_PLL_A1;
0171         pll_auto = true;
0172         break;
0173     case AUD_CLK_F:
0174         pll_id = AUD_PLL_F1;
0175         pll_auto = true;
0176         break;
0177     case AUD_CLK_APLL:
0178         pll_id = AUD_PLL_APLL;
0179         break;
0180     case AUD_CLK_RX0:
0181         pll_id = AUD_PLL_RX0;
0182         break;
0183     case AUD_CLK_USB0:
0184         pll_id = AUD_PLL_USB0;
0185         break;
0186     case AUD_CLK_HSC0:
0187         pll_id = AUD_PLL_HSC0;
0188         break;
0189     default:
0190         dev_err(dev, "Sysclk(%d) is not supported\n", clk_id);
0191         return -EINVAL;
0192     }
0193 
0194     if (pll_auto) {
0195         for (pll_id = 0; pll_id < aio->chip->num_plls; pll_id++) {
0196             div_id = find_divider(aio, pll_id, freq);
0197             if (div_id >= 0) {
0198                 aio->plldiv = div_id;
0199                 break;
0200             }
0201         }
0202         if (pll_id == aio->chip->num_plls) {
0203             dev_err(dev, "Sysclk frequency is not supported(%d)\n",
0204                 freq);
0205             return -EINVAL;
0206         }
0207     }
0208 
0209     if (dir == SND_SOC_CLOCK_OUT)
0210         aio->pll_out = pll_id;
0211     else
0212         aio->pll_in = pll_id;
0213 
0214     return 0;
0215 }
0216 
0217 static int uniphier_aio_set_pll(struct snd_soc_dai *dai, int pll_id,
0218                 int source, unsigned int freq_in,
0219                 unsigned int freq_out)
0220 {
0221     struct uniphier_aio *aio = uniphier_priv(dai);
0222     int ret;
0223 
0224     if (!is_valid_pll(aio->chip, pll_id))
0225         return -EINVAL;
0226 
0227     ret = aio_chip_set_pll(aio->chip, pll_id, freq_out);
0228     if (ret < 0)
0229         return ret;
0230 
0231     return 0;
0232 }
0233 
0234 static int uniphier_aio_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
0235 {
0236     struct uniphier_aio *aio = uniphier_priv(dai);
0237     struct device *dev = &aio->chip->pdev->dev;
0238 
0239     switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
0240     case SND_SOC_DAIFMT_LEFT_J:
0241     case SND_SOC_DAIFMT_RIGHT_J:
0242     case SND_SOC_DAIFMT_I2S:
0243         aio->fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
0244         break;
0245     default:
0246         dev_err(dev, "Format is not supported(%d)\n",
0247             fmt & SND_SOC_DAIFMT_FORMAT_MASK);
0248         return -EINVAL;
0249     }
0250 
0251     return 0;
0252 }
0253 
0254 static int uniphier_aio_startup(struct snd_pcm_substream *substream,
0255                 struct snd_soc_dai *dai)
0256 {
0257     struct uniphier_aio *aio = uniphier_priv(dai);
0258     struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
0259 
0260     sub->substream = substream;
0261     sub->pass_through = 0;
0262     sub->use_mmap = true;
0263 
0264     return aio_init(sub);
0265 }
0266 
0267 static void uniphier_aio_shutdown(struct snd_pcm_substream *substream,
0268                   struct snd_soc_dai *dai)
0269 {
0270     struct uniphier_aio *aio = uniphier_priv(dai);
0271     struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
0272 
0273     sub->substream = NULL;
0274 }
0275 
0276 static int uniphier_aio_hw_params(struct snd_pcm_substream *substream,
0277                   struct snd_pcm_hw_params *params,
0278                   struct snd_soc_dai *dai)
0279 {
0280     struct uniphier_aio *aio = uniphier_priv(dai);
0281     struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
0282     struct device *dev = &aio->chip->pdev->dev;
0283     int freq, ret;
0284 
0285     switch (params_rate(params)) {
0286     case 48000:
0287     case 32000:
0288     case 24000:
0289         freq = 12288000;
0290         break;
0291     case 44100:
0292     case 22050:
0293         freq = 11289600;
0294         break;
0295     default:
0296         dev_err(dev, "Rate is not supported(%d)\n",
0297             params_rate(params));
0298         return -EINVAL;
0299     }
0300     ret = snd_soc_dai_set_sysclk(dai, AUD_CLK_A,
0301                      freq, SND_SOC_CLOCK_OUT);
0302     if (ret)
0303         return ret;
0304 
0305     sub->params = *params;
0306     sub->setting = 1;
0307 
0308     aio_port_reset(sub);
0309     aio_port_set_volume(sub, sub->vol);
0310     aio_src_reset(sub);
0311 
0312     return 0;
0313 }
0314 
0315 static int uniphier_aio_hw_free(struct snd_pcm_substream *substream,
0316                 struct snd_soc_dai *dai)
0317 {
0318     struct uniphier_aio *aio = uniphier_priv(dai);
0319     struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
0320 
0321     sub->setting = 0;
0322 
0323     return 0;
0324 }
0325 
0326 static int uniphier_aio_prepare(struct snd_pcm_substream *substream,
0327                 struct snd_soc_dai *dai)
0328 {
0329     struct uniphier_aio *aio = uniphier_priv(dai);
0330     struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
0331     int ret;
0332 
0333     ret = aio_port_set_param(sub, sub->pass_through, &sub->params);
0334     if (ret)
0335         return ret;
0336     ret = aio_src_set_param(sub, &sub->params);
0337     if (ret)
0338         return ret;
0339     aio_port_set_enable(sub, 1);
0340 
0341     ret = aio_if_set_param(sub, sub->pass_through);
0342     if (ret)
0343         return ret;
0344 
0345     if (sub->swm->type == PORT_TYPE_CONV) {
0346         ret = aio_srcif_set_param(sub);
0347         if (ret)
0348             return ret;
0349         ret = aio_srcch_set_param(sub);
0350         if (ret)
0351             return ret;
0352         aio_srcch_set_enable(sub, 1);
0353     }
0354 
0355     return 0;
0356 }
0357 
0358 const struct snd_soc_dai_ops uniphier_aio_i2s_ops = {
0359     .set_sysclk  = uniphier_aio_set_sysclk,
0360     .set_pll     = uniphier_aio_set_pll,
0361     .set_fmt     = uniphier_aio_set_fmt,
0362     .startup     = uniphier_aio_startup,
0363     .shutdown    = uniphier_aio_shutdown,
0364     .hw_params   = uniphier_aio_hw_params,
0365     .hw_free     = uniphier_aio_hw_free,
0366     .prepare     = uniphier_aio_prepare,
0367 };
0368 EXPORT_SYMBOL_GPL(uniphier_aio_i2s_ops);
0369 
0370 const struct snd_soc_dai_ops uniphier_aio_spdif_ops = {
0371     .set_sysclk  = uniphier_aio_set_sysclk,
0372     .set_pll     = uniphier_aio_set_pll,
0373     .startup     = uniphier_aio_startup,
0374     .shutdown    = uniphier_aio_shutdown,
0375     .hw_params   = uniphier_aio_hw_params,
0376     .hw_free     = uniphier_aio_hw_free,
0377     .prepare     = uniphier_aio_prepare,
0378 };
0379 EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ops);
0380 
0381 int uniphier_aio_dai_probe(struct snd_soc_dai *dai)
0382 {
0383     struct uniphier_aio *aio = uniphier_priv(dai);
0384     int i;
0385 
0386     for (i = 0; i < ARRAY_SIZE(aio->sub); i++) {
0387         struct uniphier_aio_sub *sub = &aio->sub[i];
0388         const struct uniphier_aio_spec *spec;
0389 
0390         spec = find_spec(aio, dai->name, i);
0391         if (!spec)
0392             continue;
0393 
0394         sub->swm = &spec->swm;
0395         sub->spec = spec;
0396 
0397         sub->vol = AUD_VOL_INIT;
0398     }
0399 
0400     aio_iecout_set_enable(aio->chip, true);
0401     aio_chip_init(aio->chip);
0402     aio->chip->active = 1;
0403 
0404     return 0;
0405 }
0406 EXPORT_SYMBOL_GPL(uniphier_aio_dai_probe);
0407 
0408 int uniphier_aio_dai_remove(struct snd_soc_dai *dai)
0409 {
0410     struct uniphier_aio *aio = uniphier_priv(dai);
0411 
0412     aio->chip->active = 0;
0413 
0414     return 0;
0415 }
0416 EXPORT_SYMBOL_GPL(uniphier_aio_dai_remove);
0417 
0418 static void uniphier_aio_dai_suspend(struct snd_soc_dai *dai)
0419 {
0420     struct uniphier_aio *aio = uniphier_priv(dai);
0421 
0422     if (!snd_soc_dai_active(dai))
0423         return;
0424 
0425     aio->chip->num_wup_aios--;
0426     if (!aio->chip->num_wup_aios) {
0427         reset_control_assert(aio->chip->rst);
0428         clk_disable_unprepare(aio->chip->clk);
0429     }
0430 }
0431 
0432 static int uniphier_aio_suspend(struct snd_soc_component *component)
0433 {
0434     struct snd_soc_dai *dai;
0435 
0436     for_each_component_dais(component, dai)
0437         uniphier_aio_dai_suspend(dai);
0438     return 0;
0439 }
0440 
0441 static int uniphier_aio_dai_resume(struct snd_soc_dai *dai)
0442 {
0443     struct uniphier_aio *aio = uniphier_priv(dai);
0444     int ret, i;
0445 
0446     if (!snd_soc_dai_active(dai))
0447         return 0;
0448 
0449     if (!aio->chip->active)
0450         return 0;
0451 
0452     if (!aio->chip->num_wup_aios) {
0453         ret = clk_prepare_enable(aio->chip->clk);
0454         if (ret)
0455             return ret;
0456 
0457         ret = reset_control_deassert(aio->chip->rst);
0458         if (ret)
0459             goto err_out_clock;
0460     }
0461 
0462     aio_iecout_set_enable(aio->chip, true);
0463     aio_chip_init(aio->chip);
0464 
0465     for (i = 0; i < ARRAY_SIZE(aio->sub); i++) {
0466         struct uniphier_aio_sub *sub = &aio->sub[i];
0467 
0468         if (!sub->spec || !sub->substream)
0469             continue;
0470 
0471         ret = aio_init(sub);
0472         if (ret)
0473             goto err_out_reset;
0474 
0475         if (!sub->setting)
0476             continue;
0477 
0478         aio_port_reset(sub);
0479         aio_src_reset(sub);
0480     }
0481     aio->chip->num_wup_aios++;
0482 
0483     return 0;
0484 
0485 err_out_reset:
0486     if (!aio->chip->num_wup_aios)
0487         reset_control_assert(aio->chip->rst);
0488 err_out_clock:
0489     if (!aio->chip->num_wup_aios)
0490         clk_disable_unprepare(aio->chip->clk);
0491 
0492     return ret;
0493 }
0494 
0495 static int uniphier_aio_resume(struct snd_soc_component *component)
0496 {
0497     struct snd_soc_dai *dai;
0498     int ret = 0;
0499 
0500     for_each_component_dais(component, dai)
0501         ret |= uniphier_aio_dai_resume(dai);
0502     return ret;
0503 }
0504 
0505 static int uniphier_aio_vol_info(struct snd_kcontrol *kcontrol,
0506                  struct snd_ctl_elem_info *uinfo)
0507 {
0508     uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
0509     uinfo->count = 1;
0510     uinfo->value.integer.min = 0;
0511     uinfo->value.integer.max = AUD_VOL_MAX;
0512 
0513     return 0;
0514 }
0515 
0516 static int uniphier_aio_vol_get(struct snd_kcontrol *kcontrol,
0517                 struct snd_ctl_elem_value *ucontrol)
0518 {
0519     struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
0520     struct uniphier_aio_chip *chip = snd_soc_component_get_drvdata(comp);
0521     struct uniphier_aio_sub *sub;
0522     int oport_hw = kcontrol->private_value;
0523 
0524     sub = find_volume(chip, oport_hw);
0525     if (!sub)
0526         return 0;
0527 
0528     ucontrol->value.integer.value[0] = sub->vol;
0529 
0530     return 0;
0531 }
0532 
0533 static int uniphier_aio_vol_put(struct snd_kcontrol *kcontrol,
0534                 struct snd_ctl_elem_value *ucontrol)
0535 {
0536     struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
0537     struct uniphier_aio_chip *chip = snd_soc_component_get_drvdata(comp);
0538     struct uniphier_aio_sub *sub;
0539     int oport_hw = kcontrol->private_value;
0540 
0541     sub = find_volume(chip, oport_hw);
0542     if (!sub)
0543         return 0;
0544 
0545     if (sub->vol == ucontrol->value.integer.value[0])
0546         return 0;
0547     sub->vol = ucontrol->value.integer.value[0];
0548 
0549     aio_port_set_volume(sub, sub->vol);
0550 
0551     return 0;
0552 }
0553 
0554 static const struct snd_kcontrol_new uniphier_aio_controls[] = {
0555     {
0556         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0557         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
0558         .name = "HPCMOUT1 Volume",
0559         .info = uniphier_aio_vol_info,
0560         .get = uniphier_aio_vol_get,
0561         .put = uniphier_aio_vol_put,
0562         .private_value = AUD_HW_HPCMOUT1,
0563     },
0564     {
0565         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0566         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
0567         .name = "PCMOUT1 Volume",
0568         .info = uniphier_aio_vol_info,
0569         .get = uniphier_aio_vol_get,
0570         .put = uniphier_aio_vol_put,
0571         .private_value = AUD_HW_PCMOUT1,
0572     },
0573     {
0574         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0575         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
0576         .name = "PCMOUT2 Volume",
0577         .info = uniphier_aio_vol_info,
0578         .get = uniphier_aio_vol_get,
0579         .put = uniphier_aio_vol_put,
0580         .private_value = AUD_HW_PCMOUT2,
0581     },
0582     {
0583         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0584         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
0585         .name = "PCMOUT3 Volume",
0586         .info = uniphier_aio_vol_info,
0587         .get = uniphier_aio_vol_get,
0588         .put = uniphier_aio_vol_put,
0589         .private_value = AUD_HW_PCMOUT3,
0590     },
0591     {
0592         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0593         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
0594         .name = "HIECOUT1 Volume",
0595         .info = uniphier_aio_vol_info,
0596         .get = uniphier_aio_vol_get,
0597         .put = uniphier_aio_vol_put,
0598         .private_value = AUD_HW_HIECOUT1,
0599     },
0600     {
0601         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0602         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
0603         .name = "IECOUT1 Volume",
0604         .info = uniphier_aio_vol_info,
0605         .get = uniphier_aio_vol_get,
0606         .put = uniphier_aio_vol_put,
0607         .private_value = AUD_HW_IECOUT1,
0608     },
0609 };
0610 
0611 static const struct snd_soc_component_driver uniphier_aio_component = {
0612     .name = "uniphier-aio",
0613     .controls = uniphier_aio_controls,
0614     .num_controls = ARRAY_SIZE(uniphier_aio_controls),
0615     .suspend = uniphier_aio_suspend,
0616     .resume  = uniphier_aio_resume,
0617 };
0618 
0619 int uniphier_aio_probe(struct platform_device *pdev)
0620 {
0621     struct uniphier_aio_chip *chip;
0622     struct device *dev = &pdev->dev;
0623     int ret, i, j;
0624 
0625     chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
0626     if (!chip)
0627         return -ENOMEM;
0628 
0629     chip->chip_spec = of_device_get_match_data(dev);
0630     if (!chip->chip_spec)
0631         return -EINVAL;
0632 
0633     chip->regmap_sg = syscon_regmap_lookup_by_phandle(dev->of_node,
0634                               "socionext,syscon");
0635     if (IS_ERR(chip->regmap_sg)) {
0636         if (PTR_ERR(chip->regmap_sg) == -EPROBE_DEFER)
0637             return -EPROBE_DEFER;
0638         chip->regmap_sg = NULL;
0639     }
0640 
0641     chip->clk = devm_clk_get(dev, "aio");
0642     if (IS_ERR(chip->clk))
0643         return PTR_ERR(chip->clk);
0644 
0645     chip->rst = devm_reset_control_get_shared(dev, "aio");
0646     if (IS_ERR(chip->rst))
0647         return PTR_ERR(chip->rst);
0648 
0649     chip->num_aios = chip->chip_spec->num_dais;
0650     chip->num_wup_aios = chip->num_aios;
0651     chip->aios = devm_kcalloc(dev,
0652                   chip->num_aios, sizeof(struct uniphier_aio),
0653                   GFP_KERNEL);
0654     if (!chip->aios)
0655         return -ENOMEM;
0656 
0657     chip->num_plls = chip->chip_spec->num_plls;
0658     chip->plls = devm_kcalloc(dev,
0659                   chip->num_plls,
0660                   sizeof(struct uniphier_aio_pll),
0661                   GFP_KERNEL);
0662     if (!chip->plls)
0663         return -ENOMEM;
0664     memcpy(chip->plls, chip->chip_spec->plls,
0665            sizeof(struct uniphier_aio_pll) * chip->num_plls);
0666 
0667     for (i = 0; i < chip->num_aios; i++) {
0668         struct uniphier_aio *aio = &chip->aios[i];
0669 
0670         aio->chip = chip;
0671         aio->fmt = SND_SOC_DAIFMT_I2S;
0672 
0673         for (j = 0; j < ARRAY_SIZE(aio->sub); j++) {
0674             struct uniphier_aio_sub *sub = &aio->sub[j];
0675 
0676             sub->aio = aio;
0677             spin_lock_init(&sub->lock);
0678         }
0679     }
0680 
0681     chip->pdev = pdev;
0682     platform_set_drvdata(pdev, chip);
0683 
0684     ret = clk_prepare_enable(chip->clk);
0685     if (ret)
0686         return ret;
0687 
0688     ret = reset_control_deassert(chip->rst);
0689     if (ret)
0690         goto err_out_clock;
0691 
0692     ret = devm_snd_soc_register_component(dev, &uniphier_aio_component,
0693                           chip->chip_spec->dais,
0694                           chip->chip_spec->num_dais);
0695     if (ret) {
0696         dev_err(dev, "Register component failed.\n");
0697         goto err_out_reset;
0698     }
0699 
0700     ret = uniphier_aiodma_soc_register_platform(pdev);
0701     if (ret) {
0702         dev_err(dev, "Register platform failed.\n");
0703         goto err_out_reset;
0704     }
0705 
0706     return 0;
0707 
0708 err_out_reset:
0709     reset_control_assert(chip->rst);
0710 
0711 err_out_clock:
0712     clk_disable_unprepare(chip->clk);
0713 
0714     return ret;
0715 }
0716 EXPORT_SYMBOL_GPL(uniphier_aio_probe);
0717 
0718 int uniphier_aio_remove(struct platform_device *pdev)
0719 {
0720     struct uniphier_aio_chip *chip = platform_get_drvdata(pdev);
0721 
0722     reset_control_assert(chip->rst);
0723     clk_disable_unprepare(chip->clk);
0724 
0725     return 0;
0726 }
0727 EXPORT_SYMBOL_GPL(uniphier_aio_remove);
0728 
0729 MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
0730 MODULE_DESCRIPTION("UniPhier AIO CPU DAI driver.");
0731 MODULE_LICENSE("GPL v2");