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 * @pll_id: 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 *
 271 * Set suitable slot selecting to input/output port block of AIO.
 272 *
 273 * This function may return error if non-PCM substream.
 274 *
 275 * Return: Zero if successful, otherwise a negative value on error.
 276 */
 277static int aio_port_set_ch(struct uniphier_aio_sub *sub)
 278{
 279        struct regmap *r = sub->aio->chip->regmap;
 280        static const u32 slotsel_2ch[] = {
 281                0, 0, 0, 0, 0,
 282        };
 283        static const u32 slotsel_multi[] = {
 284                OPORTMXTYSLOTCTR_SLOTSEL_SLOT0,
 285                OPORTMXTYSLOTCTR_SLOTSEL_SLOT1,
 286                OPORTMXTYSLOTCTR_SLOTSEL_SLOT2,
 287                OPORTMXTYSLOTCTR_SLOTSEL_SLOT3,
 288                OPORTMXTYSLOTCTR_SLOTSEL_SLOT4,
 289        };
 290        u32 mode;
 291        const u32 *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        static const 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        static const 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        int ret;
 842
 843        switch (pc) {
 844        case IEC61937_PC_AC3:
 845                repet = OPORTMXREPET_STRLENGTH_AC3 |
 846                        OPORTMXREPET_PMLENGTH_AC3;
 847                pause |= OPORTMXPAUDAT_PAUSEPD_AC3;
 848                break;
 849        case IEC61937_PC_MPA:
 850                repet = OPORTMXREPET_STRLENGTH_MPA |
 851                        OPORTMXREPET_PMLENGTH_MPA;
 852                pause |= OPORTMXPAUDAT_PAUSEPD_MPA;
 853                break;
 854        case IEC61937_PC_MP3:
 855                repet = OPORTMXREPET_STRLENGTH_MP3 |
 856                        OPORTMXREPET_PMLENGTH_MP3;
 857                pause |= OPORTMXPAUDAT_PAUSEPD_MP3;
 858                break;
 859        case IEC61937_PC_DTS1:
 860                repet = OPORTMXREPET_STRLENGTH_DTS1 |
 861                        OPORTMXREPET_PMLENGTH_DTS1;
 862                pause |= OPORTMXPAUDAT_PAUSEPD_DTS1;
 863                break;
 864        case IEC61937_PC_DTS2:
 865                repet = OPORTMXREPET_STRLENGTH_DTS2 |
 866                        OPORTMXREPET_PMLENGTH_DTS2;
 867                pause |= OPORTMXPAUDAT_PAUSEPD_DTS2;
 868                break;
 869        case IEC61937_PC_DTS3:
 870                repet = OPORTMXREPET_STRLENGTH_DTS3 |
 871                        OPORTMXREPET_PMLENGTH_DTS3;
 872                pause |= OPORTMXPAUDAT_PAUSEPD_DTS3;
 873                break;
 874        case IEC61937_PC_AAC:
 875                repet = OPORTMXREPET_STRLENGTH_AAC |
 876                        OPORTMXREPET_PMLENGTH_AAC;
 877                pause |= OPORTMXPAUDAT_PAUSEPD_AAC;
 878                break;
 879        case IEC61937_PC_PAUSE:
 880                /* Do nothing */
 881                break;
 882        }
 883
 884        ret = regmap_write(r, OPORTMXREPET(sub->swm->oport.map), repet);
 885        if (ret)
 886                return ret;
 887        
 888        ret = regmap_write(r, OPORTMXPAUDAT(sub->swm->oport.map), pause);
 889        if (ret)
 890                return ret;
 891
 892        return 0;
 893}
 894
 895/**
 896 * aio_src_reset - reset AIO SRC block
 897 * @sub: the AIO substream pointer
 898 *
 899 * Resets the digital signal input/output port with sampling rate converter
 900 * block of AIO.
 901 * This function has no effect if substream is not supported rate converter.
 902 */
 903void aio_src_reset(struct uniphier_aio_sub *sub)
 904{
 905        struct regmap *r = sub->aio->chip->regmap;
 906
 907        if (sub->swm->dir != PORT_DIR_OUTPUT)
 908                return;
 909
 910        regmap_write(r, AOUTSRCRSTCTR0, BIT(sub->swm->oport.map));
 911        regmap_write(r, AOUTSRCRSTCTR1, BIT(sub->swm->oport.map));
 912}
 913
 914/**
 915 * aio_src_set_param - set parameters of AIO SRC block
 916 * @sub: the AIO substream pointer
 917 * @params: hardware parameters of ALSA
 918 *
 919 * Set suitable setting to input/output port with sampling rate converter
 920 * block of AIO to process the specified in params.
 921 * This function has no effect if substream is not supported rate converter.
 922 *
 923 * Return: Zero if successful, otherwise a negative value on error.
 924 */
 925int aio_src_set_param(struct uniphier_aio_sub *sub,
 926                      const struct snd_pcm_hw_params *params)
 927{
 928        struct regmap *r = sub->aio->chip->regmap;
 929        u32 v;
 930        int ret;
 931
 932        if (sub->swm->dir != PORT_DIR_OUTPUT)
 933                return 0;
 934
 935        ret = regmap_write(r, OPORTMXSRC1CTR(sub->swm->oport.map),
 936                     OPORTMXSRC1CTR_THMODE_SRC |
 937                     OPORTMXSRC1CTR_SRCPATH_CALC |
 938                     OPORTMXSRC1CTR_SYNC_ASYNC |
 939                     OPORTMXSRC1CTR_FSIIPSEL_INNER |
 940                     OPORTMXSRC1CTR_FSISEL_ACLK);
 941        if (ret)
 942                return ret;
 943
 944        switch (params_rate(params)) {
 945        default:
 946        case 48000:
 947                v = OPORTMXRATE_I_ACLKSEL_APLLA1 |
 948                        OPORTMXRATE_I_MCKSEL_36 |
 949                        OPORTMXRATE_I_FSSEL_48;
 950                break;
 951        case 44100:
 952                v = OPORTMXRATE_I_ACLKSEL_APLLA2 |
 953                        OPORTMXRATE_I_MCKSEL_33 |
 954                        OPORTMXRATE_I_FSSEL_44_1;
 955                break;
 956        case 32000:
 957                v = OPORTMXRATE_I_ACLKSEL_APLLA1 |
 958                        OPORTMXRATE_I_MCKSEL_36 |
 959                        OPORTMXRATE_I_FSSEL_32;
 960                break;
 961        }
 962
 963
 964        ret = regmap_write(r, OPORTMXRATE_I(sub->swm->oport.map),
 965                     v | OPORTMXRATE_I_ACLKSRC_APLL |
 966                     OPORTMXRATE_I_LRCKSTP_STOP);
 967        if (ret)
 968                return ret;
 969
 970        ret = regmap_update_bits(r, OPORTMXRATE_I(sub->swm->oport.map),
 971                           OPORTMXRATE_I_LRCKSTP_MASK,
 972                           OPORTMXRATE_I_LRCKSTP_START);
 973        if (ret)
 974                return ret;
 975
 976        return 0;
 977}
 978
 979int aio_srcif_set_param(struct uniphier_aio_sub *sub)
 980{
 981        struct regmap *r = sub->aio->chip->regmap;
 982
 983        regmap_write(r, PBINMXCTR(sub->swm->iif.map),
 984                     PBINMXCTR_NCONNECT_CONNECT |
 985                     PBINMXCTR_INOUTSEL_OUT |
 986                     (sub->swm->oport.map << PBINMXCTR_PBINSEL_SHIFT) |
 987                     PBINMXCTR_ENDIAN_3210 |
 988                     PBINMXCTR_MEMFMT_D0);
 989
 990        return 0;
 991}
 992
 993int aio_srcch_set_param(struct uniphier_aio_sub *sub)
 994{
 995        struct regmap *r = sub->aio->chip->regmap;
 996
 997        regmap_write(r, CDA2D_CHMXCTRL1(sub->swm->och.map),
 998                     CDA2D_CHMXCTRL1_INDSIZE_INFINITE);
 999
1000        regmap_write(r, CDA2D_CHMXSRCAMODE(sub->swm->och.map),
1001                     CDA2D_CHMXAMODE_ENDIAN_3210 |
1002                     CDA2D_CHMXAMODE_AUPDT_FIX |
1003                     CDA2D_CHMXAMODE_TYPE_NORMAL);
1004
1005        regmap_write(r, CDA2D_CHMXDSTAMODE(sub->swm->och.map),
1006                     CDA2D_CHMXAMODE_ENDIAN_3210 |
1007                     CDA2D_CHMXAMODE_AUPDT_INC |
1008                     CDA2D_CHMXAMODE_TYPE_RING |
1009                     (sub->swm->och.map << CDA2D_CHMXAMODE_RSSEL_SHIFT));
1010
1011        return 0;
1012}
1013
1014void aio_srcch_set_enable(struct uniphier_aio_sub *sub, int enable)
1015{
1016        struct regmap *r = sub->aio->chip->regmap;
1017        u32 v;
1018
1019        if (enable)
1020                v = CDA2D_STRT0_STOP_START;
1021        else
1022                v = CDA2D_STRT0_STOP_STOP;
1023
1024        regmap_write(r, CDA2D_STRT0,
1025                     v | BIT(sub->swm->och.map));
1026}
1027
1028int aiodma_ch_set_param(struct uniphier_aio_sub *sub)
1029{
1030        struct regmap *r = sub->aio->chip->regmap;
1031        u32 v;
1032
1033        regmap_write(r, CDA2D_CHMXCTRL1(sub->swm->ch.map),
1034                     CDA2D_CHMXCTRL1_INDSIZE_INFINITE);
1035
1036        v = CDA2D_CHMXAMODE_ENDIAN_3210 |
1037                CDA2D_CHMXAMODE_AUPDT_INC |
1038                CDA2D_CHMXAMODE_TYPE_NORMAL |
1039                (sub->swm->rb.map << CDA2D_CHMXAMODE_RSSEL_SHIFT);
1040        if (sub->swm->dir == PORT_DIR_OUTPUT)
1041                regmap_write(r, CDA2D_CHMXSRCAMODE(sub->swm->ch.map), v);
1042        else
1043                regmap_write(r, CDA2D_CHMXDSTAMODE(sub->swm->ch.map), v);
1044
1045        return 0;
1046}
1047
1048void aiodma_ch_set_enable(struct uniphier_aio_sub *sub, int enable)
1049{
1050        struct regmap *r = sub->aio->chip->regmap;
1051
1052        if (enable) {
1053                regmap_write(r, CDA2D_STRT0,
1054                             CDA2D_STRT0_STOP_START | BIT(sub->swm->ch.map));
1055
1056                regmap_update_bits(r, INTRBIM(0),
1057                                   BIT(sub->swm->rb.map),
1058                                   BIT(sub->swm->rb.map));
1059        } else {
1060                regmap_write(r, CDA2D_STRT0,
1061                             CDA2D_STRT0_STOP_STOP | BIT(sub->swm->ch.map));
1062
1063                regmap_update_bits(r, INTRBIM(0),
1064                                   BIT(sub->swm->rb.map),
1065                                   0);
1066        }
1067}
1068
1069static u64 aiodma_rb_get_rp(struct uniphier_aio_sub *sub)
1070{
1071        struct regmap *r = sub->aio->chip->regmap;
1072        u32 pos_u, pos_l;
1073        int i;
1074
1075        regmap_write(r, CDA2D_RDPTRLOAD,
1076                     CDA2D_RDPTRLOAD_LSFLAG_STORE | BIT(sub->swm->rb.map));
1077        /* Wait for setup */
1078        for (i = 0; i < 6; i++)
1079                regmap_read(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), &pos_l);
1080
1081        regmap_read(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), &pos_l);
1082        regmap_read(r, CDA2D_RBMXRDPTRU(sub->swm->rb.map), &pos_u);
1083        pos_u = FIELD_GET(CDA2D_RBMXPTRU_PTRU_MASK, pos_u);
1084
1085        return ((u64)pos_u << 32) | pos_l;
1086}
1087
1088static void aiodma_rb_set_rp(struct uniphier_aio_sub *sub, u64 pos)
1089{
1090        struct regmap *r = sub->aio->chip->regmap;
1091        u32 tmp;
1092        int i;
1093
1094        regmap_write(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), (u32)pos);
1095        regmap_write(r, CDA2D_RBMXRDPTRU(sub->swm->rb.map), (u32)(pos >> 32));
1096        regmap_write(r, CDA2D_RDPTRLOAD, BIT(sub->swm->rb.map));
1097        /* Wait for setup */
1098        for (i = 0; i < 6; i++)
1099                regmap_read(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), &tmp);
1100}
1101
1102static u64 aiodma_rb_get_wp(struct uniphier_aio_sub *sub)
1103{
1104        struct regmap *r = sub->aio->chip->regmap;
1105        u32 pos_u, pos_l;
1106        int i;
1107
1108        regmap_write(r, CDA2D_WRPTRLOAD,
1109                     CDA2D_WRPTRLOAD_LSFLAG_STORE | BIT(sub->swm->rb.map));
1110        /* Wait for setup */
1111        for (i = 0; i < 6; i++)
1112                regmap_read(r, CDA2D_RBMXWRPTR(sub->swm->rb.map), &pos_l);
1113
1114        regmap_read(r, CDA2D_RBMXWRPTR(sub->swm->rb.map), &pos_l);
1115        regmap_read(r, CDA2D_RBMXWRPTRU(sub->swm->rb.map), &pos_u);
1116        pos_u = FIELD_GET(CDA2D_RBMXPTRU_PTRU_MASK, pos_u);
1117
1118        return ((u64)pos_u << 32) | pos_l;
1119}
1120
1121static void aiodma_rb_set_wp(struct uniphier_aio_sub *sub, u64 pos)
1122{
1123        struct regmap *r = sub->aio->chip->regmap;
1124        u32 tmp;
1125        int i;
1126
1127        regmap_write(r, CDA2D_RBMXWRPTR(sub->swm->rb.map),
1128                     lower_32_bits(pos));
1129        regmap_write(r, CDA2D_RBMXWRPTRU(sub->swm->rb.map),
1130                     upper_32_bits(pos));
1131        regmap_write(r, CDA2D_WRPTRLOAD, BIT(sub->swm->rb.map));
1132        /* Wait for setup */
1133        for (i = 0; i < 6; i++)
1134                regmap_read(r, CDA2D_RBMXWRPTR(sub->swm->rb.map), &tmp);
1135}
1136
1137int aiodma_rb_set_threshold(struct uniphier_aio_sub *sub, u64 size, u32 th)
1138{
1139        struct regmap *r = sub->aio->chip->regmap;
1140
1141        if (size <= th)
1142                return -EINVAL;
1143
1144        regmap_write(r, CDA2D_RBMXBTH(sub->swm->rb.map), th);
1145        regmap_write(r, CDA2D_RBMXRTH(sub->swm->rb.map), th);
1146
1147        return 0;
1148}
1149
1150int aiodma_rb_set_buffer(struct uniphier_aio_sub *sub, u64 start, u64 end,
1151                         int period)
1152{
1153        struct regmap *r = sub->aio->chip->regmap;
1154        u64 size = end - start;
1155        int ret;
1156
1157        if (end < start || period < 0)
1158                return -EINVAL;
1159
1160        regmap_write(r, CDA2D_RBMXCNFG(sub->swm->rb.map), 0);
1161        regmap_write(r, CDA2D_RBMXBGNADRS(sub->swm->rb.map),
1162                     lower_32_bits(start));
1163        regmap_write(r, CDA2D_RBMXBGNADRSU(sub->swm->rb.map),
1164                     upper_32_bits(start));
1165        regmap_write(r, CDA2D_RBMXENDADRS(sub->swm->rb.map),
1166                     lower_32_bits(end));
1167        regmap_write(r, CDA2D_RBMXENDADRSU(sub->swm->rb.map),
1168                     upper_32_bits(end));
1169
1170        regmap_write(r, CDA2D_RBADRSLOAD, BIT(sub->swm->rb.map));
1171
1172        ret = aiodma_rb_set_threshold(sub, size, 2 * period);
1173        if (ret)
1174                return ret;
1175
1176        if (sub->swm->dir == PORT_DIR_OUTPUT) {
1177                aiodma_rb_set_rp(sub, start);
1178                aiodma_rb_set_wp(sub, end - period);
1179
1180                regmap_update_bits(r, CDA2D_RBMXIE(sub->swm->rb.map),
1181                                   CDA2D_RBMXIX_SPACE,
1182                                   CDA2D_RBMXIX_SPACE);
1183        } else {
1184                aiodma_rb_set_rp(sub, end - period);
1185                aiodma_rb_set_wp(sub, start);
1186
1187                regmap_update_bits(r, CDA2D_RBMXIE(sub->swm->rb.map),
1188                                   CDA2D_RBMXIX_REMAIN,
1189                                   CDA2D_RBMXIX_REMAIN);
1190        }
1191
1192        sub->threshold = 2 * period;
1193        sub->rd_offs = 0;
1194        sub->wr_offs = 0;
1195        sub->rd_org = 0;
1196        sub->wr_org = 0;
1197        sub->rd_total = 0;
1198        sub->wr_total = 0;
1199
1200        return 0;
1201}
1202
1203void aiodma_rb_sync(struct uniphier_aio_sub *sub, u64 start, u64 size,
1204                    int period)
1205{
1206        if (sub->swm->dir == PORT_DIR_OUTPUT) {
1207                sub->rd_offs = aiodma_rb_get_rp(sub) - start;
1208
1209                if (sub->use_mmap) {
1210                        sub->threshold = 2 * period;
1211                        aiodma_rb_set_threshold(sub, size, 2 * period);
1212
1213                        sub->wr_offs = sub->rd_offs - period;
1214                        if (sub->rd_offs < period)
1215                                sub->wr_offs += size;
1216                }
1217                aiodma_rb_set_wp(sub, sub->wr_offs + start);
1218        } else {
1219                sub->wr_offs = aiodma_rb_get_wp(sub) - start;
1220
1221                if (sub->use_mmap) {
1222                        sub->threshold = 2 * period;
1223                        aiodma_rb_set_threshold(sub, size, 2 * period);
1224
1225                        sub->rd_offs = sub->wr_offs - period;
1226                        if (sub->wr_offs < period)
1227                                sub->rd_offs += size;
1228                }
1229                aiodma_rb_set_rp(sub, sub->rd_offs + start);
1230        }
1231
1232        sub->rd_total += sub->rd_offs - sub->rd_org;
1233        if (sub->rd_offs < sub->rd_org)
1234                sub->rd_total += size;
1235        sub->wr_total += sub->wr_offs - sub->wr_org;
1236        if (sub->wr_offs < sub->wr_org)
1237                sub->wr_total += size;
1238
1239        sub->rd_org = sub->rd_offs;
1240        sub->wr_org = sub->wr_offs;
1241}
1242
1243bool aiodma_rb_is_irq(struct uniphier_aio_sub *sub)
1244{
1245        struct regmap *r = sub->aio->chip->regmap;
1246        u32 ir;
1247
1248        regmap_read(r, CDA2D_RBMXIR(sub->swm->rb.map), &ir);
1249
1250        if (sub->swm->dir == PORT_DIR_OUTPUT)
1251                return !!(ir & CDA2D_RBMXIX_SPACE);
1252        else
1253                return !!(ir & CDA2D_RBMXIX_REMAIN);
1254}
1255
1256void aiodma_rb_clear_irq(struct uniphier_aio_sub *sub)
1257{
1258        struct regmap *r = sub->aio->chip->regmap;
1259
1260        if (sub->swm->dir == PORT_DIR_OUTPUT)
1261                regmap_write(r, CDA2D_RBMXIR(sub->swm->rb.map),
1262                             CDA2D_RBMXIX_SPACE);
1263        else
1264                regmap_write(r, CDA2D_RBMXIR(sub->swm->rb.map),
1265                             CDA2D_RBMXIX_REMAIN);
1266}
1267