linux/sound/soc/uniphier/aio-core.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2//
   3// Socionext UniPhier AIO ALSA common driver.
   4//
   5// Copyright (c) 2016-2018 Socionext Inc.
   6
   7#include <linux/bitfield.h>
   8#include <linux/errno.h>
   9#include <linux/kernel.h>
  10#include <linux/module.h>
  11#include <sound/core.h>
  12#include <sound/pcm.h>
  13#include <sound/pcm_params.h>
  14#include <sound/soc.h>
  15
  16#include "aio.h"
  17#include "aio-reg.h"
  18
  19static u64 rb_cnt(u64 wr, u64 rd, u64 len)
  20{
  21        if (rd <= wr)
  22                return wr - rd;
  23        else
  24                return len - (rd - wr);
  25}
  26
  27static u64 rb_cnt_to_end(u64 wr, u64 rd, u64 len)
  28{
  29        if (rd <= wr)
  30                return wr - rd;
  31        else
  32                return len - rd;
  33}
  34
  35static u64 rb_space(u64 wr, u64 rd, u64 len)
  36{
  37        if (rd <= wr)
  38                return len - (wr - rd) - 8;
  39        else
  40                return rd - wr - 8;
  41}
  42
  43static u64 rb_space_to_end(u64 wr, u64 rd, u64 len)
  44{
  45        if (rd > wr)
  46                return rd - wr - 8;
  47        else if (rd > 0)
  48                return len - wr;
  49        else
  50                return len - wr - 8;
  51}
  52
  53u64 aio_rb_cnt(struct uniphier_aio_sub *sub)
  54{
  55        return rb_cnt(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
  56}
  57
  58u64 aio_rbt_cnt_to_end(struct uniphier_aio_sub *sub)
  59{
  60        return rb_cnt_to_end(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
  61}
  62
  63u64 aio_rb_space(struct uniphier_aio_sub *sub)
  64{
  65        return rb_space(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
  66}
  67
  68u64 aio_rb_space_to_end(struct uniphier_aio_sub *sub)
  69{
  70        return rb_space_to_end(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
  71}
  72
  73/**
  74 * aio_iecout_set_enable - setup IEC output via SoC glue
  75 * @chip: the AIO chip pointer
  76 * @enable: false to stop the output, true to start
  77 *
  78 * Set enabled or disabled S/PDIF signal output to out of SoC via AOnIEC pins.
  79 * This function need to call at driver startup.
  80 *
  81 * The regmap of SoC glue is specified by 'socionext,syscon' optional property
  82 * of DT. This function has no effect if no property.
  83 */
  84void aio_iecout_set_enable(struct uniphier_aio_chip *chip, bool enable)
  85{
  86        struct regmap *r = chip->regmap_sg;
  87
  88        if (!r)
  89                return;
  90
  91        regmap_write(r, SG_AOUTEN, (enable) ? ~0 : 0);
  92}
  93
  94/**
  95 * aio_chip_set_pll - set frequency to audio PLL
  96 * @chip  : the AIO chip pointer
  97 * @source: PLL
  98 * @freq  : frequency in Hz, 0 is ignored
  99 *
 100 * Sets frequency of audio PLL. This function can be called anytime,
 101 * but it takes time till PLL is locked.
 102 *
 103 * Return: Zero if successful, otherwise a negative value on error.
 104 */
 105int aio_chip_set_pll(struct uniphier_aio_chip *chip, int pll_id,
 106                     unsigned int freq)
 107{
 108        struct device *dev = &chip->pdev->dev;
 109        struct regmap *r = chip->regmap;
 110        int shift;
 111        u32 v;
 112
 113        /* Not change */
 114        if (freq == 0)
 115                return 0;
 116
 117        switch (pll_id) {
 118        case AUD_PLL_A1:
 119                shift = 0;
 120                break;
 121        case AUD_PLL_F1:
 122                shift = 1;
 123                break;
 124        case AUD_PLL_A2:
 125                shift = 2;
 126                break;
 127        case AUD_PLL_F2:
 128                shift = 3;
 129                break;
 130        default:
 131                dev_err(dev, "PLL(%d) not supported\n", pll_id);
 132                return -EINVAL;
 133        }
 134
 135        switch (freq) {
 136        case 36864000:
 137                v = A2APLLCTR1_APLLX_36MHZ;
 138                break;
 139        case 33868800:
 140                v = A2APLLCTR1_APLLX_33MHZ;
 141                break;
 142        default:
 143                dev_err(dev, "PLL frequency not supported(%d)\n", freq);
 144                return -EINVAL;
 145        }
 146        chip->plls[pll_id].freq = freq;
 147
 148        regmap_update_bits(r, A2APLLCTR1, A2APLLCTR1_APLLX_MASK << shift,
 149                           v << shift);
 150
 151        return 0;
 152}
 153
 154/**
 155 * aio_chip_init - initialize AIO whole settings
 156 * @chip: the AIO chip pointer
 157 *
 158 * Sets AIO fixed and whole device settings to AIO.
 159 * This function need to call once at driver startup.
 160 *
 161 * The register area that is changed by this function is shared by all
 162 * modules of AIO. But there is not race condition since this function
 163 * has always set the same initialize values.
 164 */
 165void aio_chip_init(struct uniphier_aio_chip *chip)
 166{
 167        struct regmap *r = chip->regmap;
 168
 169        regmap_update_bits(r, A2APLLCTR0,
 170                           A2APLLCTR0_APLLXPOW_MASK,
 171                           A2APLLCTR0_APLLXPOW_PWON);
 172
 173        regmap_update_bits(r, A2EXMCLKSEL0,
 174                           A2EXMCLKSEL0_EXMCLK_MASK,
 175                           A2EXMCLKSEL0_EXMCLK_OUTPUT);
 176
 177        regmap_update_bits(r, A2AIOINPUTSEL, A2AIOINPUTSEL_RXSEL_MASK,
 178                           A2AIOINPUTSEL_RXSEL_PCMI1_HDMIRX1 |
 179                           A2AIOINPUTSEL_RXSEL_PCMI2_SIF |
 180                           A2AIOINPUTSEL_RXSEL_PCMI3_EVEA |
 181                           A2AIOINPUTSEL_RXSEL_IECI1_HDMIRX1);
 182
 183        if (chip->chip_spec->addr_ext)
 184                regmap_update_bits(r, CDA2D_TEST, CDA2D_TEST_DDR_MODE_MASK,
 185                                   CDA2D_TEST_DDR_MODE_EXTON0);
 186        else
 187                regmap_update_bits(r, CDA2D_TEST, CDA2D_TEST_DDR_MODE_MASK,
 188                                   CDA2D_TEST_DDR_MODE_EXTOFF1);
 189}
 190
 191/**
 192 * aio_init - initialize AIO substream
 193 * @sub: the AIO substream pointer
 194 *
 195 * Sets fixed settings of each AIO substreams.
 196 * This function need to call once at substream startup.
 197 *
 198 * Return: Zero if successful, otherwise a negative value on error.
 199 */
 200int aio_init(struct uniphier_aio_sub *sub)
 201{
 202        struct device *dev = &sub->aio->chip->pdev->dev;
 203        struct regmap *r = sub->aio->chip->regmap;
 204
 205        regmap_write(r, A2RBNMAPCTR0(sub->swm->rb.hw),
 206                     MAPCTR0_EN | sub->swm->rb.map);
 207        regmap_write(r, A2CHNMAPCTR0(sub->swm->ch.hw),
 208                     MAPCTR0_EN | sub->swm->ch.map);
 209
 210        switch (sub->swm->type) {
 211        case PORT_TYPE_I2S:
 212        case PORT_TYPE_SPDIF:
 213        case PORT_TYPE_EVE:
 214                if (sub->swm->dir == PORT_DIR_INPUT) {
 215                        regmap_write(r, A2IIFNMAPCTR0(sub->swm->iif.hw),
 216                                     MAPCTR0_EN | sub->swm->iif.map);
 217                        regmap_write(r, A2IPORTNMAPCTR0(sub->swm->iport.hw),
 218                                     MAPCTR0_EN | sub->swm->iport.map);
 219                } else {
 220                        regmap_write(r, A2OIFNMAPCTR0(sub->swm->oif.hw),
 221                                     MAPCTR0_EN | sub->swm->oif.map);
 222                        regmap_write(r, A2OPORTNMAPCTR0(sub->swm->oport.hw),
 223                                     MAPCTR0_EN | sub->swm->oport.map);
 224                }
 225                break;
 226        case PORT_TYPE_CONV:
 227                regmap_write(r, A2OIFNMAPCTR0(sub->swm->oif.hw),
 228                             MAPCTR0_EN | sub->swm->oif.map);
 229                regmap_write(r, A2OPORTNMAPCTR0(sub->swm->oport.hw),
 230                             MAPCTR0_EN | sub->swm->oport.map);
 231                regmap_write(r, A2CHNMAPCTR0(sub->swm->och.hw),
 232                             MAPCTR0_EN | sub->swm->och.map);
 233                regmap_write(r, A2IIFNMAPCTR0(sub->swm->iif.hw),
 234                             MAPCTR0_EN | sub->swm->iif.map);
 235                break;
 236        default:
 237                dev_err(dev, "Unknown port type %d.\n", sub->swm->type);
 238                return -EINVAL;
 239        }
 240
 241        return 0;
 242}
 243
 244/**
 245 * aio_port_reset - reset AIO port block
 246 * @sub: the AIO substream pointer
 247 *
 248 * Resets the digital signal input/output port block of AIO.
 249 */
 250void aio_port_reset(struct uniphier_aio_sub *sub)
 251{
 252        struct regmap *r = sub->aio->chip->regmap;
 253
 254        if (sub->swm->dir == PORT_DIR_OUTPUT) {
 255                regmap_write(r, AOUTRSTCTR0, BIT(sub->swm->oport.map));
 256                regmap_write(r, AOUTRSTCTR1, BIT(sub->swm->oport.map));
 257        } else {
 258                regmap_update_bits(r, IPORTMXRSTCTR(sub->swm->iport.map),
 259                                   IPORTMXRSTCTR_RSTPI_MASK,
 260                                   IPORTMXRSTCTR_RSTPI_RESET);
 261                regmap_update_bits(r, IPORTMXRSTCTR(sub->swm->iport.map),
 262                                   IPORTMXRSTCTR_RSTPI_MASK,
 263                                   IPORTMXRSTCTR_RSTPI_RELEASE);
 264        }
 265}
 266
 267/**
 268 * aio_port_set_ch - set channels of LPCM
 269 * @sub: the AIO substream pointer, PCM substream only
 270 * @ch : count of channels
 271 *
 272 * Set suitable slot selecting to input/output port block of AIO.
 273 *
 274 * This function may return error if non-PCM substream.
 275 *
 276 * Return: Zero if successful, otherwise a negative value on error.
 277 */
 278static int aio_port_set_ch(struct uniphier_aio_sub *sub)
 279{
 280        struct regmap *r = sub->aio->chip->regmap;
 281        u32 slotsel_2ch[] = {
 282                0, 0, 0, 0, 0,
 283        };
 284        u32 slotsel_multi[] = {
 285                OPORTMXTYSLOTCTR_SLOTSEL_SLOT0,
 286                OPORTMXTYSLOTCTR_SLOTSEL_SLOT1,
 287                OPORTMXTYSLOTCTR_SLOTSEL_SLOT2,
 288                OPORTMXTYSLOTCTR_SLOTSEL_SLOT3,
 289                OPORTMXTYSLOTCTR_SLOTSEL_SLOT4,
 290        };
 291        u32 mode, *slotsel;
 292        int i;
 293
 294        switch (params_channels(&sub->params)) {
 295        case 8:
 296        case 6:
 297                mode = OPORTMXTYSLOTCTR_MODE;
 298                slotsel = slotsel_multi;
 299                break;
 300        case 2:
 301                mode = 0;
 302                slotsel = slotsel_2ch;
 303                break;
 304        default:
 305                return -EINVAL;
 306        }
 307
 308        for (i = 0; i < AUD_MAX_SLOTSEL; i++) {
 309                regmap_update_bits(r, OPORTMXTYSLOTCTR(sub->swm->oport.map, i),
 310                                   OPORTMXTYSLOTCTR_MODE, mode);
 311                regmap_update_bits(r, OPORTMXTYSLOTCTR(sub->swm->oport.map, i),
 312                                   OPORTMXTYSLOTCTR_SLOTSEL_MASK, slotsel[i]);
 313        }
 314
 315        return 0;
 316}
 317
 318/**
 319 * aio_port_set_rate - set sampling rate of LPCM
 320 * @sub: the AIO substream pointer, PCM substream only
 321 * @rate: Sampling rate in Hz.
 322 *
 323 * Set suitable I2S format settings to input/output port block of AIO.
 324 * Parameter is specified by hw_params().
 325 *
 326 * This function may return error if non-PCM substream.
 327 *
 328 * Return: Zero if successful, otherwise a negative value on error.
 329 */
 330static int aio_port_set_rate(struct uniphier_aio_sub *sub, int rate)
 331{
 332        struct regmap *r = sub->aio->chip->regmap;
 333        struct device *dev = &sub->aio->chip->pdev->dev;
 334        u32 v;
 335
 336        if (sub->swm->dir == PORT_DIR_OUTPUT) {
 337                switch (rate) {
 338                case 8000:
 339                        v = OPORTMXCTR1_FSSEL_8;
 340                        break;
 341                case 11025:
 342                        v = OPORTMXCTR1_FSSEL_11_025;
 343                        break;
 344                case 12000:
 345                        v = OPORTMXCTR1_FSSEL_12;
 346                        break;
 347                case 16000:
 348                        v = OPORTMXCTR1_FSSEL_16;
 349                        break;
 350                case 22050:
 351                        v = OPORTMXCTR1_FSSEL_22_05;
 352                        break;
 353                case 24000:
 354                        v = OPORTMXCTR1_FSSEL_24;
 355                        break;
 356                case 32000:
 357                        v = OPORTMXCTR1_FSSEL_32;
 358                        break;
 359                case 44100:
 360                        v = OPORTMXCTR1_FSSEL_44_1;
 361                        break;
 362                case 48000:
 363                        v = OPORTMXCTR1_FSSEL_48;
 364                        break;
 365                case 88200:
 366                        v = OPORTMXCTR1_FSSEL_88_2;
 367                        break;
 368                case 96000:
 369                        v = OPORTMXCTR1_FSSEL_96;
 370                        break;
 371                case 176400:
 372                        v = OPORTMXCTR1_FSSEL_176_4;
 373                        break;
 374                case 192000:
 375                        v = OPORTMXCTR1_FSSEL_192;
 376                        break;
 377                default:
 378                        dev_err(dev, "Rate not supported(%d)\n", rate);
 379                        return -EINVAL;
 380                }
 381
 382                regmap_update_bits(r, OPORTMXCTR1(sub->swm->oport.map),
 383                                   OPORTMXCTR1_FSSEL_MASK, v);
 384        } else {
 385                switch (rate) {
 386                case 8000:
 387                        v = IPORTMXCTR1_FSSEL_8;
 388                        break;
 389                case 11025:
 390                        v = IPORTMXCTR1_FSSEL_11_025;
 391                        break;
 392                case 12000:
 393                        v = IPORTMXCTR1_FSSEL_12;
 394                        break;
 395                case 16000:
 396                        v = IPORTMXCTR1_FSSEL_16;
 397                        break;
 398                case 22050:
 399                        v = IPORTMXCTR1_FSSEL_22_05;
 400                        break;
 401                case 24000:
 402                        v = IPORTMXCTR1_FSSEL_24;
 403                        break;
 404                case 32000:
 405                        v = IPORTMXCTR1_FSSEL_32;
 406                        break;
 407                case 44100:
 408                        v = IPORTMXCTR1_FSSEL_44_1;
 409                        break;
 410                case 48000:
 411                        v = IPORTMXCTR1_FSSEL_48;
 412                        break;
 413                case 88200:
 414                        v = IPORTMXCTR1_FSSEL_88_2;
 415                        break;
 416                case 96000:
 417                        v = IPORTMXCTR1_FSSEL_96;
 418                        break;
 419                case 176400:
 420                        v = IPORTMXCTR1_FSSEL_176_4;
 421                        break;
 422                case 192000:
 423                        v = IPORTMXCTR1_FSSEL_192;
 424                        break;
 425                default:
 426                        dev_err(dev, "Rate not supported(%d)\n", rate);
 427                        return -EINVAL;
 428                }
 429
 430                regmap_update_bits(r, IPORTMXCTR1(sub->swm->iport.map),
 431                                   IPORTMXCTR1_FSSEL_MASK, v);
 432        }
 433
 434        return 0;
 435}
 436
 437/**
 438 * aio_port_set_fmt - set format of I2S data
 439 * @sub: the AIO substream pointer, PCM substream only
 440 * This parameter has no effect if substream is I2S or PCM.
 441 *
 442 * Set suitable I2S format settings to input/output port block of AIO.
 443 * Parameter is specified by set_fmt().
 444 *
 445 * This function may return error if non-PCM substream.
 446 *
 447 * Return: Zero if successful, otherwise a negative value on error.
 448 */
 449static int aio_port_set_fmt(struct uniphier_aio_sub *sub)
 450{
 451        struct regmap *r = sub->aio->chip->regmap;
 452        struct device *dev = &sub->aio->chip->pdev->dev;
 453        u32 v;
 454
 455        if (sub->swm->dir == PORT_DIR_OUTPUT) {
 456                switch (sub->aio->fmt) {
 457                case SND_SOC_DAIFMT_LEFT_J:
 458                        v = OPORTMXCTR1_I2SLRSEL_LEFT;
 459                        break;
 460                case SND_SOC_DAIFMT_RIGHT_J:
 461                        v = OPORTMXCTR1_I2SLRSEL_RIGHT;
 462                        break;
 463                case SND_SOC_DAIFMT_I2S:
 464                        v = OPORTMXCTR1_I2SLRSEL_I2S;
 465                        break;
 466                default:
 467                        dev_err(dev, "Format is not supported(%d)\n",
 468                                sub->aio->fmt);
 469                        return -EINVAL;
 470                }
 471
 472                v |= OPORTMXCTR1_OUTBITSEL_24;
 473                regmap_update_bits(r, OPORTMXCTR1(sub->swm->oport.map),
 474                                   OPORTMXCTR1_I2SLRSEL_MASK |
 475                                   OPORTMXCTR1_OUTBITSEL_MASK, v);
 476        } else {
 477                switch (sub->aio->fmt) {
 478                case SND_SOC_DAIFMT_LEFT_J:
 479                        v = IPORTMXCTR1_LRSEL_LEFT;
 480                        break;
 481                case SND_SOC_DAIFMT_RIGHT_J:
 482                        v = IPORTMXCTR1_LRSEL_RIGHT;
 483                        break;
 484                case SND_SOC_DAIFMT_I2S:
 485                        v = IPORTMXCTR1_LRSEL_I2S;
 486                        break;
 487                default:
 488                        dev_err(dev, "Format is not supported(%d)\n",
 489                                sub->aio->fmt);
 490                        return -EINVAL;
 491                }
 492
 493                v |= IPORTMXCTR1_OUTBITSEL_24 |
 494                        IPORTMXCTR1_CHSEL_ALL;
 495                regmap_update_bits(r, IPORTMXCTR1(sub->swm->iport.map),
 496                                   IPORTMXCTR1_LRSEL_MASK |
 497                                   IPORTMXCTR1_OUTBITSEL_MASK |
 498                                   IPORTMXCTR1_CHSEL_MASK, v);
 499        }
 500
 501        return 0;
 502}
 503
 504/**
 505 * aio_port_set_clk - set clock and divider of AIO port block
 506 * @sub: the AIO substream pointer
 507 *
 508 * Set suitable PLL clock divider and relational settings to
 509 * input/output port block of AIO. Parameters are specified by
 510 * set_sysclk() and set_pll().
 511 *
 512 * Return: Zero if successful, otherwise a negative value on error.
 513 */
 514static int aio_port_set_clk(struct uniphier_aio_sub *sub)
 515{
 516        struct uniphier_aio_chip *chip = sub->aio->chip;
 517        struct device *dev = &sub->aio->chip->pdev->dev;
 518        struct regmap *r = sub->aio->chip->regmap;
 519        u32 v_pll[] = {
 520                OPORTMXCTR2_ACLKSEL_A1, OPORTMXCTR2_ACLKSEL_F1,
 521                OPORTMXCTR2_ACLKSEL_A2, OPORTMXCTR2_ACLKSEL_F2,
 522                OPORTMXCTR2_ACLKSEL_A2PLL,
 523                OPORTMXCTR2_ACLKSEL_RX1,
 524        };
 525        u32 v_div[] = {
 526                OPORTMXCTR2_DACCKSEL_1_2, OPORTMXCTR2_DACCKSEL_1_3,
 527                OPORTMXCTR2_DACCKSEL_1_1, OPORTMXCTR2_DACCKSEL_2_3,
 528        };
 529        u32 v;
 530
 531        if (sub->swm->dir == PORT_DIR_OUTPUT) {
 532                if (sub->swm->type == PORT_TYPE_I2S) {
 533                        if (sub->aio->pll_out >= ARRAY_SIZE(v_pll)) {
 534                                dev_err(dev, "PLL(%d) is invalid\n",
 535                                        sub->aio->pll_out);
 536                                return -EINVAL;
 537                        }
 538                        if (sub->aio->plldiv >= ARRAY_SIZE(v_div)) {
 539                                dev_err(dev, "PLL divider(%d) is invalid\n",
 540                                        sub->aio->plldiv);
 541                                return -EINVAL;
 542                        }
 543
 544                        v = v_pll[sub->aio->pll_out] |
 545                                OPORTMXCTR2_MSSEL_MASTER |
 546                                v_div[sub->aio->plldiv];
 547
 548                        switch (chip->plls[sub->aio->pll_out].freq) {
 549                        case 0:
 550                        case 36864000:
 551                        case 33868800:
 552                                v |= OPORTMXCTR2_EXTLSIFSSEL_36;
 553                                break;
 554                        default:
 555                                v |= OPORTMXCTR2_EXTLSIFSSEL_24;
 556                                break;
 557                        }
 558                } else if (sub->swm->type == PORT_TYPE_EVE) {
 559                        v = OPORTMXCTR2_ACLKSEL_A2PLL |
 560                                OPORTMXCTR2_MSSEL_MASTER |
 561                                OPORTMXCTR2_EXTLSIFSSEL_36 |
 562                                OPORTMXCTR2_DACCKSEL_1_2;
 563                } else if (sub->swm->type == PORT_TYPE_SPDIF) {
 564                        if (sub->aio->pll_out >= ARRAY_SIZE(v_pll)) {
 565                                dev_err(dev, "PLL(%d) is invalid\n",
 566                                        sub->aio->pll_out);
 567                                return -EINVAL;
 568                        }
 569                        v = v_pll[sub->aio->pll_out] |
 570                                OPORTMXCTR2_MSSEL_MASTER |
 571                                OPORTMXCTR2_DACCKSEL_1_2;
 572
 573                        switch (chip->plls[sub->aio->pll_out].freq) {
 574                        case 0:
 575                        case 36864000:
 576                        case 33868800:
 577                                v |= OPORTMXCTR2_EXTLSIFSSEL_36;
 578                                break;
 579                        default:
 580                                v |= OPORTMXCTR2_EXTLSIFSSEL_24;
 581                                break;
 582                        }
 583                } else {
 584                        v = OPORTMXCTR2_ACLKSEL_A1 |
 585                                OPORTMXCTR2_MSSEL_MASTER |
 586                                OPORTMXCTR2_EXTLSIFSSEL_36 |
 587                                OPORTMXCTR2_DACCKSEL_1_2;
 588                }
 589                regmap_write(r, OPORTMXCTR2(sub->swm->oport.map), v);
 590        } else {
 591                v = IPORTMXCTR2_ACLKSEL_A1 |
 592                        IPORTMXCTR2_MSSEL_SLAVE |
 593                        IPORTMXCTR2_EXTLSIFSSEL_36 |
 594                        IPORTMXCTR2_DACCKSEL_1_2;
 595                regmap_write(r, IPORTMXCTR2(sub->swm->iport.map), v);
 596        }
 597
 598        return 0;
 599}
 600
 601/**
 602 * aio_port_set_param - set parameters of AIO port block
 603 * @sub: the AIO substream pointer
 604 * @pass_through: Zero if sound data is LPCM, otherwise if data is not LPCM.
 605 * This parameter has no effect if substream is I2S or PCM.
 606 * @params: hardware parameters of ALSA
 607 *
 608 * Set suitable setting to input/output port block of AIO to process the
 609 * specified in params.
 610 *
 611 * Return: Zero if successful, otherwise a negative value on error.
 612 */
 613int aio_port_set_param(struct uniphier_aio_sub *sub, int pass_through,
 614                       const struct snd_pcm_hw_params *params)
 615{
 616        struct regmap *r = sub->aio->chip->regmap;
 617        unsigned int rate;
 618        u32 v;
 619        int ret;
 620
 621        if (!pass_through) {
 622                if (sub->swm->type == PORT_TYPE_EVE ||
 623                    sub->swm->type == PORT_TYPE_CONV) {
 624                        rate = 48000;
 625                } else {
 626                        rate = params_rate(params);
 627                }
 628
 629                ret = aio_port_set_ch(sub);
 630                if (ret)
 631                        return ret;
 632
 633                ret = aio_port_set_rate(sub, rate);
 634                if (ret)
 635                        return ret;
 636
 637                ret = aio_port_set_fmt(sub);
 638                if (ret)
 639                        return ret;
 640        }
 641
 642        ret = aio_port_set_clk(sub);
 643        if (ret)
 644                return ret;
 645
 646        if (sub->swm->dir == PORT_DIR_OUTPUT) {
 647                if (pass_through)
 648                        v = OPORTMXCTR3_SRCSEL_STREAM |
 649                                OPORTMXCTR3_VALID_STREAM;
 650                else
 651                        v = OPORTMXCTR3_SRCSEL_PCM |
 652                                OPORTMXCTR3_VALID_PCM;
 653
 654                v |= OPORTMXCTR3_IECTHUR_IECOUT |
 655                        OPORTMXCTR3_PMSEL_PAUSE |
 656                        OPORTMXCTR3_PMSW_MUTE_OFF;
 657                regmap_write(r, OPORTMXCTR3(sub->swm->oport.map), v);
 658        } else {
 659                regmap_write(r, IPORTMXACLKSEL0EX(sub->swm->iport.map),
 660                             IPORTMXACLKSEL0EX_ACLKSEL0EX_INTERNAL);
 661                regmap_write(r, IPORTMXEXNOE(sub->swm->iport.map),
 662                             IPORTMXEXNOE_PCMINOE_INPUT);
 663        }
 664
 665        return 0;
 666}
 667
 668/**
 669 * aio_port_set_enable - start or stop of AIO port block
 670 * @sub: the AIO substream pointer
 671 * @enable: zero to stop the block, otherwise to start
 672 *
 673 * Start or stop the signal input/output port block of AIO.
 674 */
 675void aio_port_set_enable(struct uniphier_aio_sub *sub, int enable)
 676{
 677        struct regmap *r = sub->aio->chip->regmap;
 678
 679        if (sub->swm->dir == PORT_DIR_OUTPUT) {
 680                regmap_write(r, OPORTMXPATH(sub->swm->oport.map),
 681                             sub->swm->oif.map);
 682
 683                regmap_update_bits(r, OPORTMXMASK(sub->swm->oport.map),
 684                                   OPORTMXMASK_IUDXMSK_MASK |
 685                                   OPORTMXMASK_IUXCKMSK_MASK |
 686                                   OPORTMXMASK_DXMSK_MASK |
 687                                   OPORTMXMASK_XCKMSK_MASK,
 688                                   OPORTMXMASK_IUDXMSK_OFF |
 689                                   OPORTMXMASK_IUXCKMSK_OFF |
 690                                   OPORTMXMASK_DXMSK_OFF |
 691                                   OPORTMXMASK_XCKMSK_OFF);
 692
 693                if (enable)
 694                        regmap_write(r, AOUTENCTR0, BIT(sub->swm->oport.map));
 695                else
 696                        regmap_write(r, AOUTENCTR1, BIT(sub->swm->oport.map));
 697        } else {
 698                regmap_update_bits(r, IPORTMXMASK(sub->swm->iport.map),
 699                                   IPORTMXMASK_IUXCKMSK_MASK |
 700                                   IPORTMXMASK_XCKMSK_MASK,
 701                                   IPORTMXMASK_IUXCKMSK_OFF |
 702                                   IPORTMXMASK_XCKMSK_OFF);
 703
 704                if (enable)
 705                        regmap_update_bits(r,
 706                                           IPORTMXCTR2(sub->swm->iport.map),
 707                                           IPORTMXCTR2_REQEN_MASK,
 708                                           IPORTMXCTR2_REQEN_ENABLE);
 709                else
 710                        regmap_update_bits(r,
 711                                           IPORTMXCTR2(sub->swm->iport.map),
 712                                           IPORTMXCTR2_REQEN_MASK,
 713                                           IPORTMXCTR2_REQEN_DISABLE);
 714        }
 715}
 716
 717/**
 718 * aio_port_get_volume - get volume of AIO port block
 719 * @sub: the AIO substream pointer
 720 *
 721 * Return: current volume, range is 0x0000 - 0xffff
 722 */
 723int aio_port_get_volume(struct uniphier_aio_sub *sub)
 724{
 725        struct regmap *r = sub->aio->chip->regmap;
 726        u32 v;
 727
 728        regmap_read(r, OPORTMXTYVOLGAINSTATUS(sub->swm->oport.map, 0), &v);
 729
 730        return FIELD_GET(OPORTMXTYVOLGAINSTATUS_CUR_MASK, v);
 731}
 732
 733/**
 734 * aio_port_set_volume - set volume of AIO port block
 735 * @sub: the AIO substream pointer
 736 * @vol: target volume, range is 0x0000 - 0xffff.
 737 *
 738 * Change digital volume and perfome fade-out/fade-in effect for specified
 739 * output slot of port. Gained PCM value can calculate as the following:
 740 *   Gained = Original * vol / 0x4000
 741 */
 742void aio_port_set_volume(struct uniphier_aio_sub *sub, int vol)
 743{
 744        struct regmap *r = sub->aio->chip->regmap;
 745        int oport_map = sub->swm->oport.map;
 746        int cur, diff, slope = 0, fs;
 747
 748        if (sub->swm->dir == PORT_DIR_INPUT)
 749                return;
 750
 751        cur = aio_port_get_volume(sub);
 752        diff = abs(vol - cur);
 753        fs = params_rate(&sub->params);
 754        if (fs)
 755                slope = diff / AUD_VOL_FADE_TIME * 1000 / fs;
 756        slope = max(1, slope);
 757
 758        regmap_update_bits(r, OPORTMXTYVOLPARA1(oport_map, 0),
 759                           OPORTMXTYVOLPARA1_SLOPEU_MASK, slope << 16);
 760        regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
 761                           OPORTMXTYVOLPARA2_TARGET_MASK, vol);
 762
 763        if (cur < vol)
 764                regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
 765                                   OPORTMXTYVOLPARA2_FADE_MASK,
 766                                   OPORTMXTYVOLPARA2_FADE_FADEIN);
 767        else
 768                regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
 769                                   OPORTMXTYVOLPARA2_FADE_MASK,
 770                                   OPORTMXTYVOLPARA2_FADE_FADEOUT);
 771
 772        regmap_write(r, AOUTFADECTR0, BIT(oport_map));
 773}
 774
 775/**
 776 * aio_if_set_param - set parameters of AIO DMA I/F block
 777 * @sub: the AIO substream pointer
 778 * @pass_through: Zero if sound data is LPCM, otherwise if data is not LPCM.
 779 * This parameter has no effect if substream is I2S or PCM.
 780 *
 781 * Set suitable setting to DMA interface block of AIO to process the
 782 * specified in settings.
 783 *
 784 * Return: Zero if successful, otherwise a negative value on error.
 785 */
 786int aio_if_set_param(struct uniphier_aio_sub *sub, int pass_through)
 787{
 788        struct regmap *r = sub->aio->chip->regmap;
 789        u32 memfmt, v;
 790
 791        if (sub->swm->dir == PORT_DIR_OUTPUT) {
 792                if (pass_through) {
 793                        v = PBOUTMXCTR0_ENDIAN_0123 |
 794                                PBOUTMXCTR0_MEMFMT_STREAM;
 795                } else {
 796                        switch (params_channels(&sub->params)) {
 797                        case 2:
 798                                memfmt = PBOUTMXCTR0_MEMFMT_2CH;
 799                                break;
 800                        case 6:
 801                                memfmt = PBOUTMXCTR0_MEMFMT_6CH;
 802                                break;
 803                        case 8:
 804                                memfmt = PBOUTMXCTR0_MEMFMT_8CH;
 805                                break;
 806                        default:
 807                                return -EINVAL;
 808                        }
 809                        v = PBOUTMXCTR0_ENDIAN_3210 | memfmt;
 810                }
 811
 812                regmap_write(r, PBOUTMXCTR0(sub->swm->oif.map), v);
 813                regmap_write(r, PBOUTMXCTR1(sub->swm->oif.map), 0);
 814        } else {
 815                regmap_write(r, PBINMXCTR(sub->swm->iif.map),
 816                             PBINMXCTR_NCONNECT_CONNECT |
 817                             PBINMXCTR_INOUTSEL_IN |
 818                             (sub->swm->iport.map << PBINMXCTR_PBINSEL_SHIFT) |
 819                             PBINMXCTR_ENDIAN_3210 |
 820                             PBINMXCTR_MEMFMT_D0);
 821        }
 822
 823        return 0;
 824}
 825
 826/**
 827 * aio_oport_set_stream_type - set parameters of AIO playback port block
 828 * @sub: the AIO substream pointer
 829 * @pc: Pc type of IEC61937
 830 *
 831 * Set special setting to output port block of AIO to output the stream
 832 * via S/PDIF.
 833 *
 834 * Return: Zero if successful, otherwise a negative value on error.
 835 */
 836int aio_oport_set_stream_type(struct uniphier_aio_sub *sub,
 837                              enum IEC61937_PC pc)
 838{
 839        struct regmap *r = sub->aio->chip->regmap;
 840        u32 repet = 0, pause = OPORTMXPAUDAT_PAUSEPC_CMN;
 841
 842        switch (pc) {
 843        case IEC61937_PC_AC3:
 844                repet = OPORTMXREPET_STRLENGTH_AC3 |
 845                        OPORTMXREPET_PMLENGTH_AC3;
 846                pause |= OPORTMXPAUDAT_PAUSEPD_AC3;
 847                break;
 848        case IEC61937_PC_MPA:
 849                repet = OPORTMXREPET_STRLENGTH_MPA |
 850                        OPORTMXREPET_PMLENGTH_MPA;
 851                pause |= OPORTMXPAUDAT_PAUSEPD_MPA;
 852                break;
 853        case IEC61937_PC_MP3:
 854                repet = OPORTMXREPET_STRLENGTH_MP3 |
 855                        OPORTMXREPET_PMLENGTH_MP3;
 856                pause |= OPORTMXPAUDAT_PAUSEPD_MP3;
 857                break;
 858        case IEC61937_PC_DTS1:
 859                repet = OPORTMXREPET_STRLENGTH_DTS1 |
 860                        OPORTMXREPET_PMLENGTH_DTS1;
 861                pause |= OPORTMXPAUDAT_PAUSEPD_DTS1;
 862                break;
 863        case IEC61937_PC_DTS2:
 864                repet = OPORTMXREPET_STRLENGTH_DTS2 |
 865                        OPORTMXREPET_PMLENGTH_DTS2;
 866                pause |= OPORTMXPAUDAT_PAUSEPD_DTS2;
 867                break;
 868        case IEC61937_PC_DTS3:
 869                repet = OPORTMXREPET_STRLENGTH_DTS3 |
 870                        OPORTMXREPET_PMLENGTH_DTS3;
 871                pause |= OPORTMXPAUDAT_PAUSEPD_DTS3;
 872                break;
 873        case IEC61937_PC_AAC:
 874                repet = OPORTMXREPET_STRLENGTH_AAC |
 875                        OPORTMXREPET_PMLENGTH_AAC;
 876                pause |= OPORTMXPAUDAT_PAUSEPD_AAC;
 877                break;
 878        case IEC61937_PC_PAUSE:
 879                /* Do nothing */
 880                break;
 881        }
 882
 883        regmap_write(r, OPORTMXREPET(sub->swm->oport.map), repet);
 884        regmap_write(r, OPORTMXPAUDAT(sub->swm->oport.map), pause);
 885
 886        return 0;
 887}
 888
 889/**
 890 * aio_src_reset - reset AIO SRC block
 891 * @sub: the AIO substream pointer
 892 *
 893 * Resets the digital signal input/output port with sampling rate converter
 894 * block of AIO.
 895 * This function has no effect if substream is not supported rate converter.
 896 */
 897void aio_src_reset(struct uniphier_aio_sub *sub)
 898{
 899        struct regmap *r = sub->aio->chip->regmap;
 900
 901        if (sub->swm->dir != PORT_DIR_OUTPUT)
 902                return;
 903
 904        regmap_write(r, AOUTSRCRSTCTR0, BIT(sub->swm->oport.map));
 905        regmap_write(r, AOUTSRCRSTCTR1, BIT(sub->swm->oport.map));
 906}
 907
 908/**
 909 * aio_src_set_param - set parameters of AIO SRC block
 910 * @sub: the AIO substream pointer
 911 * @params: hardware parameters of ALSA
 912 *
 913 * Set suitable setting to input/output port with sampling rate converter
 914 * block of AIO to process the specified in params.
 915 * This function has no effect if substream is not supported rate converter.
 916 *
 917 * Return: Zero if successful, otherwise a negative value on error.
 918 */
 919int aio_src_set_param(struct uniphier_aio_sub *sub,
 920                      const struct snd_pcm_hw_params *params)
 921{
 922        struct regmap *r = sub->aio->chip->regmap;
 923        u32 v;
 924
 925        if (sub->swm->dir != PORT_DIR_OUTPUT)
 926                return 0;
 927
 928        regmap_write(r, OPORTMXSRC1CTR(sub->swm->oport.map),
 929                     OPORTMXSRC1CTR_THMODE_SRC |
 930                     OPORTMXSRC1CTR_SRCPATH_CALC |
 931                     OPORTMXSRC1CTR_SYNC_ASYNC |
 932                     OPORTMXSRC1CTR_FSIIPSEL_INNER |
 933                     OPORTMXSRC1CTR_FSISEL_ACLK);
 934
 935        switch (params_rate(params)) {
 936        default:
 937        case 48000:
 938                v = OPORTMXRATE_I_ACLKSEL_APLLA1 |
 939                        OPORTMXRATE_I_MCKSEL_36 |
 940                        OPORTMXRATE_I_FSSEL_48;
 941                break;
 942        case 44100:
 943                v = OPORTMXRATE_I_ACLKSEL_APLLA2 |
 944                        OPORTMXRATE_I_MCKSEL_33 |
 945                        OPORTMXRATE_I_FSSEL_44_1;
 946                break;
 947        case 32000:
 948                v = OPORTMXRATE_I_ACLKSEL_APLLA1 |
 949                        OPORTMXRATE_I_MCKSEL_36 |
 950                        OPORTMXRATE_I_FSSEL_32;
 951                break;
 952        }
 953
 954        regmap_write(r, OPORTMXRATE_I(sub->swm->oport.map),
 955                     v | OPORTMXRATE_I_ACLKSRC_APLL |
 956                     OPORTMXRATE_I_LRCKSTP_STOP);
 957        regmap_update_bits(r, OPORTMXRATE_I(sub->swm->oport.map),
 958                           OPORTMXRATE_I_LRCKSTP_MASK,
 959                           OPORTMXRATE_I_LRCKSTP_START);
 960
 961        return 0;
 962}
 963
 964int aio_srcif_set_param(struct uniphier_aio_sub *sub)
 965{
 966        struct regmap *r = sub->aio->chip->regmap;
 967
 968        regmap_write(r, PBINMXCTR(sub->swm->iif.map),
 969                     PBINMXCTR_NCONNECT_CONNECT |
 970                     PBINMXCTR_INOUTSEL_OUT |
 971                     (sub->swm->oport.map << PBINMXCTR_PBINSEL_SHIFT) |
 972                     PBINMXCTR_ENDIAN_3210 |
 973                     PBINMXCTR_MEMFMT_D0);
 974
 975        return 0;
 976}
 977
 978int aio_srcch_set_param(struct uniphier_aio_sub *sub)
 979{
 980        struct regmap *r = sub->aio->chip->regmap;
 981
 982        regmap_write(r, CDA2D_CHMXCTRL1(sub->swm->och.map),
 983                     CDA2D_CHMXCTRL1_INDSIZE_INFINITE);
 984
 985        regmap_write(r, CDA2D_CHMXSRCAMODE(sub->swm->och.map),
 986                     CDA2D_CHMXAMODE_ENDIAN_3210 |
 987                     CDA2D_CHMXAMODE_AUPDT_FIX |
 988                     CDA2D_CHMXAMODE_TYPE_NORMAL);
 989
 990        regmap_write(r, CDA2D_CHMXDSTAMODE(sub->swm->och.map),
 991                     CDA2D_CHMXAMODE_ENDIAN_3210 |
 992                     CDA2D_CHMXAMODE_AUPDT_INC |
 993                     CDA2D_CHMXAMODE_TYPE_RING |
 994                     (sub->swm->och.map << CDA2D_CHMXAMODE_RSSEL_SHIFT));
 995
 996        return 0;
 997}
 998
 999void aio_srcch_set_enable(struct uniphier_aio_sub *sub, int enable)
1000{
1001        struct regmap *r = sub->aio->chip->regmap;
1002        u32 v;
1003
1004        if (enable)
1005                v = CDA2D_STRT0_STOP_START;
1006        else
1007                v = CDA2D_STRT0_STOP_STOP;
1008
1009        regmap_write(r, CDA2D_STRT0,
1010                     v | BIT(sub->swm->och.map));
1011}
1012
1013int aiodma_ch_set_param(struct uniphier_aio_sub *sub)
1014{
1015        struct regmap *r = sub->aio->chip->regmap;
1016        u32 v;
1017
1018        regmap_write(r, CDA2D_CHMXCTRL1(sub->swm->ch.map),
1019                     CDA2D_CHMXCTRL1_INDSIZE_INFINITE);
1020
1021        v = CDA2D_CHMXAMODE_ENDIAN_3210 |
1022                CDA2D_CHMXAMODE_AUPDT_INC |
1023                CDA2D_CHMXAMODE_TYPE_NORMAL |
1024                (sub->swm->rb.map << CDA2D_CHMXAMODE_RSSEL_SHIFT);
1025        if (sub->swm->dir == PORT_DIR_OUTPUT)
1026                regmap_write(r, CDA2D_CHMXSRCAMODE(sub->swm->ch.map), v);
1027        else
1028                regmap_write(r, CDA2D_CHMXDSTAMODE(sub->swm->ch.map), v);
1029
1030        return 0;
1031}
1032
1033void aiodma_ch_set_enable(struct uniphier_aio_sub *sub, int enable)
1034{
1035        struct regmap *r = sub->aio->chip->regmap;
1036
1037        if (enable) {
1038                regmap_write(r, CDA2D_STRT0,
1039                             CDA2D_STRT0_STOP_START | BIT(sub->swm->ch.map));
1040
1041                regmap_update_bits(r, INTRBIM(0),
1042                                   BIT(sub->swm->rb.map),
1043                                   BIT(sub->swm->rb.map));
1044        } else {
1045                regmap_write(r, CDA2D_STRT0,
1046                             CDA2D_STRT0_STOP_STOP | BIT(sub->swm->ch.map));
1047
1048                regmap_update_bits(r, INTRBIM(0),
1049                                   BIT(sub->swm->rb.map),
1050                                   0);
1051        }
1052}
1053
1054static u64 aiodma_rb_get_rp(struct uniphier_aio_sub *sub)
1055{
1056        struct regmap *r = sub->aio->chip->regmap;
1057        u32 pos_u, pos_l;
1058        int i;
1059
1060        regmap_write(r, CDA2D_RDPTRLOAD,
1061                     CDA2D_RDPTRLOAD_LSFLAG_STORE | BIT(sub->swm->rb.map));
1062        /* Wait for setup */
1063        for (i = 0; i < 6; i++)
1064                regmap_read(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), &pos_l);
1065
1066        regmap_read(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), &pos_l);
1067        regmap_read(r, CDA2D_RBMXRDPTRU(sub->swm->rb.map), &pos_u);
1068        pos_u = FIELD_GET(CDA2D_RBMXPTRU_PTRU_MASK, pos_u);
1069
1070        return ((u64)pos_u << 32) | pos_l;
1071}
1072
1073static void aiodma_rb_set_rp(struct uniphier_aio_sub *sub, u64 pos)
1074{
1075        struct regmap *r = sub->aio->chip->regmap;
1076        u32 tmp;
1077        int i;
1078
1079        regmap_write(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), (u32)pos);
1080        regmap_write(r, CDA2D_RBMXRDPTRU(sub->swm->rb.map), (u32)(pos >> 32));
1081        regmap_write(r, CDA2D_RDPTRLOAD, BIT(sub->swm->rb.map));
1082        /* Wait for setup */
1083        for (i = 0; i < 6; i++)
1084                regmap_read(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), &tmp);
1085}
1086
1087static u64 aiodma_rb_get_wp(struct uniphier_aio_sub *sub)
1088{
1089        struct regmap *r = sub->aio->chip->regmap;
1090        u32 pos_u, pos_l;
1091        int i;
1092
1093        regmap_write(r, CDA2D_WRPTRLOAD,
1094                     CDA2D_WRPTRLOAD_LSFLAG_STORE | BIT(sub->swm->rb.map));
1095        /* Wait for setup */
1096        for (i = 0; i < 6; i++)
1097                regmap_read(r, CDA2D_RBMXWRPTR(sub->swm->rb.map), &pos_l);
1098
1099        regmap_read(r, CDA2D_RBMXWRPTR(sub->swm->rb.map), &pos_l);
1100        regmap_read(r, CDA2D_RBMXWRPTRU(sub->swm->rb.map), &pos_u);
1101        pos_u = FIELD_GET(CDA2D_RBMXPTRU_PTRU_MASK, pos_u);
1102
1103        return ((u64)pos_u << 32) | pos_l;
1104}
1105
1106static void aiodma_rb_set_wp(struct uniphier_aio_sub *sub, u64 pos)
1107{
1108        struct regmap *r = sub->aio->chip->regmap;
1109        u32 tmp;
1110        int i;
1111
1112        regmap_write(r, CDA2D_RBMXWRPTR(sub->swm->rb.map),
1113                     lower_32_bits(pos));
1114        regmap_write(r, CDA2D_RBMXWRPTRU(sub->swm->rb.map),
1115                     upper_32_bits(pos));
1116        regmap_write(r, CDA2D_WRPTRLOAD, BIT(sub->swm->rb.map));
1117        /* Wait for setup */
1118        for (i = 0; i < 6; i++)
1119                regmap_read(r, CDA2D_RBMXWRPTR(sub->swm->rb.map), &tmp);
1120}
1121
1122int aiodma_rb_set_threshold(struct uniphier_aio_sub *sub, u64 size, u32 th)
1123{
1124        struct regmap *r = sub->aio->chip->regmap;
1125
1126        if (size <= th)
1127                return -EINVAL;
1128
1129        regmap_write(r, CDA2D_RBMXBTH(sub->swm->rb.map), th);
1130        regmap_write(r, CDA2D_RBMXRTH(sub->swm->rb.map), th);
1131
1132        return 0;
1133}
1134
1135int aiodma_rb_set_buffer(struct uniphier_aio_sub *sub, u64 start, u64 end,
1136                         int period)
1137{
1138        struct regmap *r = sub->aio->chip->regmap;
1139        u64 size = end - start;
1140        int ret;
1141
1142        if (end < start || period < 0)
1143                return -EINVAL;
1144
1145        regmap_write(r, CDA2D_RBMXCNFG(sub->swm->rb.map), 0);
1146        regmap_write(r, CDA2D_RBMXBGNADRS(sub->swm->rb.map),
1147                     lower_32_bits(start));
1148        regmap_write(r, CDA2D_RBMXBGNADRSU(sub->swm->rb.map),
1149                     upper_32_bits(start));
1150        regmap_write(r, CDA2D_RBMXENDADRS(sub->swm->rb.map),
1151                     lower_32_bits(end));
1152        regmap_write(r, CDA2D_RBMXENDADRSU(sub->swm->rb.map),
1153                     upper_32_bits(end));
1154
1155        regmap_write(r, CDA2D_RBADRSLOAD, BIT(sub->swm->rb.map));
1156
1157        ret = aiodma_rb_set_threshold(sub, size, 2 * period);
1158        if (ret)
1159                return ret;
1160
1161        if (sub->swm->dir == PORT_DIR_OUTPUT) {
1162                aiodma_rb_set_rp(sub, start);
1163                aiodma_rb_set_wp(sub, end - period);
1164
1165                regmap_update_bits(r, CDA2D_RBMXIE(sub->swm->rb.map),
1166                                   CDA2D_RBMXIX_SPACE,
1167                                   CDA2D_RBMXIX_SPACE);
1168        } else {
1169                aiodma_rb_set_rp(sub, end - period);
1170                aiodma_rb_set_wp(sub, start);
1171
1172                regmap_update_bits(r, CDA2D_RBMXIE(sub->swm->rb.map),
1173                                   CDA2D_RBMXIX_REMAIN,
1174                                   CDA2D_RBMXIX_REMAIN);
1175        }
1176
1177        sub->threshold = 2 * period;
1178        sub->rd_offs = 0;
1179        sub->wr_offs = 0;
1180        sub->rd_org = 0;
1181        sub->wr_org = 0;
1182        sub->rd_total = 0;
1183        sub->wr_total = 0;
1184
1185        return 0;
1186}
1187
1188void aiodma_rb_sync(struct uniphier_aio_sub *sub, u64 start, u64 size,
1189                    int period)
1190{
1191        if (sub->swm->dir == PORT_DIR_OUTPUT) {
1192                sub->rd_offs = aiodma_rb_get_rp(sub) - start;
1193
1194                if (sub->use_mmap) {
1195                        sub->threshold = 2 * period;
1196                        aiodma_rb_set_threshold(sub, size, 2 * period);
1197
1198                        sub->wr_offs = sub->rd_offs - period;
1199                        if (sub->rd_offs < period)
1200                                sub->wr_offs += size;
1201                }
1202                aiodma_rb_set_wp(sub, sub->wr_offs + start);
1203        } else {
1204                sub->wr_offs = aiodma_rb_get_wp(sub) - start;
1205
1206                if (sub->use_mmap) {
1207                        sub->threshold = 2 * period;
1208                        aiodma_rb_set_threshold(sub, size, 2 * period);
1209
1210                        sub->rd_offs = sub->wr_offs - period;
1211                        if (sub->wr_offs < period)
1212                                sub->rd_offs += size;
1213                }
1214                aiodma_rb_set_rp(sub, sub->rd_offs + start);
1215        }
1216
1217        sub->rd_total += sub->rd_offs - sub->rd_org;
1218        if (sub->rd_offs < sub->rd_org)
1219                sub->rd_total += size;
1220        sub->wr_total += sub->wr_offs - sub->wr_org;
1221        if (sub->wr_offs < sub->wr_org)
1222                sub->wr_total += size;
1223
1224        sub->rd_org = sub->rd_offs;
1225        sub->wr_org = sub->wr_offs;
1226}
1227
1228bool aiodma_rb_is_irq(struct uniphier_aio_sub *sub)
1229{
1230        struct regmap *r = sub->aio->chip->regmap;
1231        u32 ir;
1232
1233        regmap_read(r, CDA2D_RBMXIR(sub->swm->rb.map), &ir);
1234
1235        if (sub->swm->dir == PORT_DIR_OUTPUT)
1236                return !!(ir & CDA2D_RBMXIX_SPACE);
1237        else
1238                return !!(ir & CDA2D_RBMXIX_REMAIN);
1239}
1240
1241void aiodma_rb_clear_irq(struct uniphier_aio_sub *sub)
1242{
1243        struct regmap *r = sub->aio->chip->regmap;
1244
1245        if (sub->swm->dir == PORT_DIR_OUTPUT)
1246                regmap_write(r, CDA2D_RBMXIR(sub->swm->rb.map),
1247                             CDA2D_RBMXIX_SPACE);
1248        else
1249                regmap_write(r, CDA2D_RBMXIR(sub->swm->rb.map),
1250                             CDA2D_RBMXIX_REMAIN);
1251}
1252