linux/sound/soc/uniphier/aio-cpu.c
<<
>>
Prefs
   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        int mul[] = { 1, 1, 1, 2, };
 132        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        int ret;
 260
 261        sub->substream = substream;
 262        sub->pass_through = 0;
 263        sub->use_mmap = true;
 264
 265        ret = aio_init(sub);
 266        if (ret)
 267                return ret;
 268
 269        return 0;
 270}
 271
 272static void uniphier_aio_shutdown(struct snd_pcm_substream *substream,
 273                                  struct snd_soc_dai *dai)
 274{
 275        struct uniphier_aio *aio = uniphier_priv(dai);
 276        struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
 277
 278        sub->substream = NULL;
 279}
 280
 281static int uniphier_aio_hw_params(struct snd_pcm_substream *substream,
 282                                  struct snd_pcm_hw_params *params,
 283                                  struct snd_soc_dai *dai)
 284{
 285        struct uniphier_aio *aio = uniphier_priv(dai);
 286        struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
 287        struct device *dev = &aio->chip->pdev->dev;
 288        int freq, ret;
 289
 290        switch (params_rate(params)) {
 291        case 48000:
 292        case 32000:
 293        case 24000:
 294                freq = 12288000;
 295                break;
 296        case 44100:
 297        case 22050:
 298                freq = 11289600;
 299                break;
 300        default:
 301                dev_err(dev, "Rate is not supported(%d)\n",
 302                        params_rate(params));
 303                return -EINVAL;
 304        }
 305        ret = snd_soc_dai_set_sysclk(dai, AUD_CLK_A,
 306                                     freq, SND_SOC_CLOCK_OUT);
 307        if (ret)
 308                return ret;
 309
 310        sub->params = *params;
 311        sub->setting = 1;
 312
 313        aio_port_reset(sub);
 314        aio_port_set_volume(sub, sub->vol);
 315        aio_src_reset(sub);
 316
 317        return 0;
 318}
 319
 320static int uniphier_aio_hw_free(struct snd_pcm_substream *substream,
 321                                struct snd_soc_dai *dai)
 322{
 323        struct uniphier_aio *aio = uniphier_priv(dai);
 324        struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
 325
 326        sub->setting = 0;
 327
 328        return 0;
 329}
 330
 331static int uniphier_aio_prepare(struct snd_pcm_substream *substream,
 332                                struct snd_soc_dai *dai)
 333{
 334        struct uniphier_aio *aio = uniphier_priv(dai);
 335        struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
 336        int ret;
 337
 338        ret = aio_port_set_param(sub, sub->pass_through, &sub->params);
 339        if (ret)
 340                return ret;
 341        ret = aio_src_set_param(sub, &sub->params);
 342        if (ret)
 343                return ret;
 344        aio_port_set_enable(sub, 1);
 345
 346        ret = aio_if_set_param(sub, sub->pass_through);
 347        if (ret)
 348                return ret;
 349
 350        if (sub->swm->type == PORT_TYPE_CONV) {
 351                ret = aio_srcif_set_param(sub);
 352                if (ret)
 353                        return ret;
 354                ret = aio_srcch_set_param(sub);
 355                if (ret)
 356                        return ret;
 357                aio_srcch_set_enable(sub, 1);
 358        }
 359
 360        return 0;
 361}
 362
 363const struct snd_soc_dai_ops uniphier_aio_i2s_ops = {
 364        .set_sysclk  = uniphier_aio_set_sysclk,
 365        .set_pll     = uniphier_aio_set_pll,
 366        .set_fmt     = uniphier_aio_set_fmt,
 367        .startup     = uniphier_aio_startup,
 368        .shutdown    = uniphier_aio_shutdown,
 369        .hw_params   = uniphier_aio_hw_params,
 370        .hw_free     = uniphier_aio_hw_free,
 371        .prepare     = uniphier_aio_prepare,
 372};
 373EXPORT_SYMBOL_GPL(uniphier_aio_i2s_ops);
 374
 375const struct snd_soc_dai_ops uniphier_aio_spdif_ops = {
 376        .set_sysclk  = uniphier_aio_set_sysclk,
 377        .set_pll     = uniphier_aio_set_pll,
 378        .startup     = uniphier_aio_startup,
 379        .shutdown    = uniphier_aio_shutdown,
 380        .hw_params   = uniphier_aio_hw_params,
 381        .hw_free     = uniphier_aio_hw_free,
 382        .prepare     = uniphier_aio_prepare,
 383};
 384EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ops);
 385
 386int uniphier_aio_dai_probe(struct snd_soc_dai *dai)
 387{
 388        struct uniphier_aio *aio = uniphier_priv(dai);
 389        int i;
 390
 391        for (i = 0; i < ARRAY_SIZE(aio->sub); i++) {
 392                struct uniphier_aio_sub *sub = &aio->sub[i];
 393                const struct uniphier_aio_spec *spec;
 394
 395                spec = find_spec(aio, dai->name, i);
 396                if (!spec)
 397                        continue;
 398
 399                sub->swm = &spec->swm;
 400                sub->spec = spec;
 401
 402                sub->vol = AUD_VOL_INIT;
 403        }
 404
 405        aio_iecout_set_enable(aio->chip, true);
 406        aio_chip_init(aio->chip);
 407        aio->chip->active = 1;
 408
 409        return 0;
 410}
 411EXPORT_SYMBOL_GPL(uniphier_aio_dai_probe);
 412
 413int uniphier_aio_dai_remove(struct snd_soc_dai *dai)
 414{
 415        struct uniphier_aio *aio = uniphier_priv(dai);
 416
 417        aio->chip->active = 0;
 418
 419        return 0;
 420}
 421EXPORT_SYMBOL_GPL(uniphier_aio_dai_remove);
 422
 423static void uniphier_aio_dai_suspend(struct snd_soc_dai *dai)
 424{
 425        struct uniphier_aio *aio = uniphier_priv(dai);
 426
 427        if (!snd_soc_dai_active(dai))
 428                return;
 429
 430        aio->chip->num_wup_aios--;
 431        if (!aio->chip->num_wup_aios) {
 432                reset_control_assert(aio->chip->rst);
 433                clk_disable_unprepare(aio->chip->clk);
 434        }
 435}
 436
 437static int uniphier_aio_suspend(struct snd_soc_component *component)
 438{
 439        struct snd_soc_dai *dai;
 440
 441        for_each_component_dais(component, dai)
 442                uniphier_aio_dai_suspend(dai);
 443        return 0;
 444}
 445
 446static int uniphier_aio_dai_resume(struct snd_soc_dai *dai)
 447{
 448        struct uniphier_aio *aio = uniphier_priv(dai);
 449        int ret, i;
 450
 451        if (!snd_soc_dai_active(dai))
 452                return 0;
 453
 454        if (!aio->chip->active)
 455                return 0;
 456
 457        if (!aio->chip->num_wup_aios) {
 458                ret = clk_prepare_enable(aio->chip->clk);
 459                if (ret)
 460                        return ret;
 461
 462                ret = reset_control_deassert(aio->chip->rst);
 463                if (ret)
 464                        goto err_out_clock;
 465        }
 466
 467        aio_iecout_set_enable(aio->chip, true);
 468        aio_chip_init(aio->chip);
 469
 470        for (i = 0; i < ARRAY_SIZE(aio->sub); i++) {
 471                struct uniphier_aio_sub *sub = &aio->sub[i];
 472
 473                if (!sub->spec || !sub->substream)
 474                        continue;
 475
 476                ret = aio_init(sub);
 477                if (ret)
 478                        goto err_out_reset;
 479
 480                if (!sub->setting)
 481                        continue;
 482
 483                aio_port_reset(sub);
 484                aio_src_reset(sub);
 485        }
 486        aio->chip->num_wup_aios++;
 487
 488        return 0;
 489
 490err_out_reset:
 491        if (!aio->chip->num_wup_aios)
 492                reset_control_assert(aio->chip->rst);
 493err_out_clock:
 494        if (!aio->chip->num_wup_aios)
 495                clk_disable_unprepare(aio->chip->clk);
 496
 497        return ret;
 498}
 499
 500static int uniphier_aio_resume(struct snd_soc_component *component)
 501{
 502        struct snd_soc_dai *dai;
 503        int ret = 0;
 504
 505        for_each_component_dais(component, dai)
 506                ret |= uniphier_aio_dai_resume(dai);
 507        return ret;
 508}
 509
 510static int uniphier_aio_vol_info(struct snd_kcontrol *kcontrol,
 511                                 struct snd_ctl_elem_info *uinfo)
 512{
 513        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 514        uinfo->count = 1;
 515        uinfo->value.integer.min = 0;
 516        uinfo->value.integer.max = AUD_VOL_MAX;
 517
 518        return 0;
 519}
 520
 521static int uniphier_aio_vol_get(struct snd_kcontrol *kcontrol,
 522                                struct snd_ctl_elem_value *ucontrol)
 523{
 524        struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
 525        struct uniphier_aio_chip *chip = snd_soc_component_get_drvdata(comp);
 526        struct uniphier_aio_sub *sub;
 527        int oport_hw = kcontrol->private_value;
 528
 529        sub = find_volume(chip, oport_hw);
 530        if (!sub)
 531                return 0;
 532
 533        ucontrol->value.integer.value[0] = sub->vol;
 534
 535        return 0;
 536}
 537
 538static int uniphier_aio_vol_put(struct snd_kcontrol *kcontrol,
 539                                struct snd_ctl_elem_value *ucontrol)
 540{
 541        struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
 542        struct uniphier_aio_chip *chip = snd_soc_component_get_drvdata(comp);
 543        struct uniphier_aio_sub *sub;
 544        int oport_hw = kcontrol->private_value;
 545
 546        sub = find_volume(chip, oport_hw);
 547        if (!sub)
 548                return 0;
 549
 550        if (sub->vol == ucontrol->value.integer.value[0])
 551                return 0;
 552        sub->vol = ucontrol->value.integer.value[0];
 553
 554        aio_port_set_volume(sub, sub->vol);
 555
 556        return 0;
 557}
 558
 559static const struct snd_kcontrol_new uniphier_aio_controls[] = {
 560        {
 561                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 562                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 563                .name = "HPCMOUT1 Volume",
 564                .info = uniphier_aio_vol_info,
 565                .get = uniphier_aio_vol_get,
 566                .put = uniphier_aio_vol_put,
 567                .private_value = AUD_HW_HPCMOUT1,
 568        },
 569        {
 570                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 571                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 572                .name = "PCMOUT1 Volume",
 573                .info = uniphier_aio_vol_info,
 574                .get = uniphier_aio_vol_get,
 575                .put = uniphier_aio_vol_put,
 576                .private_value = AUD_HW_PCMOUT1,
 577        },
 578        {
 579                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 580                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 581                .name = "PCMOUT2 Volume",
 582                .info = uniphier_aio_vol_info,
 583                .get = uniphier_aio_vol_get,
 584                .put = uniphier_aio_vol_put,
 585                .private_value = AUD_HW_PCMOUT2,
 586        },
 587        {
 588                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 589                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 590                .name = "PCMOUT3 Volume",
 591                .info = uniphier_aio_vol_info,
 592                .get = uniphier_aio_vol_get,
 593                .put = uniphier_aio_vol_put,
 594                .private_value = AUD_HW_PCMOUT3,
 595        },
 596        {
 597                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 598                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 599                .name = "HIECOUT1 Volume",
 600                .info = uniphier_aio_vol_info,
 601                .get = uniphier_aio_vol_get,
 602                .put = uniphier_aio_vol_put,
 603                .private_value = AUD_HW_HIECOUT1,
 604        },
 605        {
 606                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 607                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 608                .name = "IECOUT1 Volume",
 609                .info = uniphier_aio_vol_info,
 610                .get = uniphier_aio_vol_get,
 611                .put = uniphier_aio_vol_put,
 612                .private_value = AUD_HW_IECOUT1,
 613        },
 614};
 615
 616static const struct snd_soc_component_driver uniphier_aio_component = {
 617        .name = "uniphier-aio",
 618        .controls = uniphier_aio_controls,
 619        .num_controls = ARRAY_SIZE(uniphier_aio_controls),
 620        .suspend = uniphier_aio_suspend,
 621        .resume  = uniphier_aio_resume,
 622};
 623
 624int uniphier_aio_probe(struct platform_device *pdev)
 625{
 626        struct uniphier_aio_chip *chip;
 627        struct device *dev = &pdev->dev;
 628        int ret, i, j;
 629
 630        chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
 631        if (!chip)
 632                return -ENOMEM;
 633
 634        chip->chip_spec = of_device_get_match_data(dev);
 635        if (!chip->chip_spec)
 636                return -EINVAL;
 637
 638        chip->regmap_sg = syscon_regmap_lookup_by_phandle(dev->of_node,
 639                                                          "socionext,syscon");
 640        if (IS_ERR(chip->regmap_sg)) {
 641                if (PTR_ERR(chip->regmap_sg) == -EPROBE_DEFER)
 642                        return -EPROBE_DEFER;
 643                chip->regmap_sg = NULL;
 644        }
 645
 646        chip->clk = devm_clk_get(dev, "aio");
 647        if (IS_ERR(chip->clk))
 648                return PTR_ERR(chip->clk);
 649
 650        chip->rst = devm_reset_control_get_shared(dev, "aio");
 651        if (IS_ERR(chip->rst))
 652                return PTR_ERR(chip->rst);
 653
 654        chip->num_aios = chip->chip_spec->num_dais;
 655        chip->num_wup_aios = chip->num_aios;
 656        chip->aios = devm_kcalloc(dev,
 657                                  chip->num_aios, sizeof(struct uniphier_aio),
 658                                  GFP_KERNEL);
 659        if (!chip->aios)
 660                return -ENOMEM;
 661
 662        chip->num_plls = chip->chip_spec->num_plls;
 663        chip->plls = devm_kcalloc(dev,
 664                                  chip->num_plls,
 665                                  sizeof(struct uniphier_aio_pll),
 666                                  GFP_KERNEL);
 667        if (!chip->plls)
 668                return -ENOMEM;
 669        memcpy(chip->plls, chip->chip_spec->plls,
 670               sizeof(struct uniphier_aio_pll) * chip->num_plls);
 671
 672        for (i = 0; i < chip->num_aios; i++) {
 673                struct uniphier_aio *aio = &chip->aios[i];
 674
 675                aio->chip = chip;
 676                aio->fmt = SND_SOC_DAIFMT_I2S;
 677
 678                for (j = 0; j < ARRAY_SIZE(aio->sub); j++) {
 679                        struct uniphier_aio_sub *sub = &aio->sub[j];
 680
 681                        sub->aio = aio;
 682                        spin_lock_init(&sub->lock);
 683                }
 684        }
 685
 686        chip->pdev = pdev;
 687        platform_set_drvdata(pdev, chip);
 688
 689        ret = clk_prepare_enable(chip->clk);
 690        if (ret)
 691                return ret;
 692
 693        ret = reset_control_deassert(chip->rst);
 694        if (ret)
 695                goto err_out_clock;
 696
 697        ret = devm_snd_soc_register_component(dev, &uniphier_aio_component,
 698                                              chip->chip_spec->dais,
 699                                              chip->chip_spec->num_dais);
 700        if (ret) {
 701                dev_err(dev, "Register component failed.\n");
 702                goto err_out_reset;
 703        }
 704
 705        ret = uniphier_aiodma_soc_register_platform(pdev);
 706        if (ret) {
 707                dev_err(dev, "Register platform failed.\n");
 708                goto err_out_reset;
 709        }
 710
 711        return 0;
 712
 713err_out_reset:
 714        reset_control_assert(chip->rst);
 715
 716err_out_clock:
 717        clk_disable_unprepare(chip->clk);
 718
 719        return ret;
 720}
 721EXPORT_SYMBOL_GPL(uniphier_aio_probe);
 722
 723int uniphier_aio_remove(struct platform_device *pdev)
 724{
 725        struct uniphier_aio_chip *chip = platform_get_drvdata(pdev);
 726
 727        reset_control_assert(chip->rst);
 728        clk_disable_unprepare(chip->clk);
 729
 730        return 0;
 731}
 732EXPORT_SYMBOL_GPL(uniphier_aio_remove);
 733
 734MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
 735MODULE_DESCRIPTION("UniPhier AIO CPU DAI driver.");
 736MODULE_LICENSE("GPL v2");
 737