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        u32 slotsel_2ch[] = {
 281                0, 0, 0, 0, 0,
 282        };
 283        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, *slotsel;
 291        int i;
 292
 293        switch (params_channels(&sub->params)) {
 294        case 8:
 295        case 6:
 296                mode = OPORTMXTYSLOTCTR_MODE;
 297                slotsel = slotsel_multi;
 298                break;
 299        case 2:
 300                mode = 0;
 301                slotsel = slotsel_2ch;
 302                break;
 303        default:
 304                return -EINVAL;
 305        }
 306
 307        for (i = 0; i < AUD_MAX_SLOTSEL; i++) {
 308                regmap_update_bits(r, OPORTMXTYSLOTCTR(sub->swm->oport.map, i),
 309                                   OPORTMXTYSLOTCTR_MODE, mode);
 310                regmap_update_bits(r, OPORTMXTYSLOTCTR(sub->swm->oport.map, i),
 311                                   OPORTMXTYSLOTCTR_SLOTSEL_MASK, slotsel[i]);
 312        }
 313
 314        return 0;
 315}
 316
 317/**
 318 * aio_port_set_rate - set sampling rate of LPCM
 319 * @sub: the AIO substream pointer, PCM substream only
 320 * @rate: Sampling rate in Hz.
 321 *
 322 * Set suitable I2S format settings to input/output port block of AIO.
 323 * Parameter is specified by hw_params().
 324 *
 325 * This function may return error if non-PCM substream.
 326 *
 327 * Return: Zero if successful, otherwise a negative value on error.
 328 */
 329static int aio_port_set_rate(struct uniphier_aio_sub *sub, int rate)
 330{
 331        struct regmap *r = sub->aio->chip->regmap;
 332        struct device *dev = &sub->aio->chip->pdev->dev;
 333        u32 v;
 334
 335        if (sub->swm->dir == PORT_DIR_OUTPUT) {
 336                switch (rate) {
 337                case 8000:
 338                        v = OPORTMXCTR1_FSSEL_8;
 339                        break;
 340                case 11025:
 341                        v = OPORTMXCTR1_FSSEL_11_025;
 342                        break;
 343                case 12000:
 344                        v = OPORTMXCTR1_FSSEL_12;
 345                        break;
 346                case 16000:
 347                        v = OPORTMXCTR1_FSSEL_16;
 348                        break;
 349                case 22050:
 350                        v = OPORTMXCTR1_FSSEL_22_05;
 351                        break;
 352                case 24000:
 353                        v = OPORTMXCTR1_FSSEL_24;
 354                        break;
 355                case 32000:
 356                        v = OPORTMXCTR1_FSSEL_32;
 357                        break;
 358                case 44100:
 359                        v = OPORTMXCTR1_FSSEL_44_1;
 360                        break;
 361                case 48000:
 362                        v = OPORTMXCTR1_FSSEL_48;
 363                        break;
 364                case 88200:
 365                        v = OPORTMXCTR1_FSSEL_88_2;
 366                        break;
 367                case 96000:
 368                        v = OPORTMXCTR1_FSSEL_96;
 369                        break;
 370                case 176400:
 371                        v = OPORTMXCTR1_FSSEL_176_4;
 372                        break;
 373                case 192000:
 374                        v = OPORTMXCTR1_FSSEL_192;
 375                        break;
 376                default:
 377                        dev_err(dev, "Rate not supported(%d)\n", rate);
 378                        return -EINVAL;
 379                }
 380
 381                regmap_update_bits(r, OPORTMXCTR1(sub->swm->oport.map),
 382                                   OPORTMXCTR1_FSSEL_MASK, v);
 383        } else {
 384                switch (rate) {
 385                case 8000:
 386                        v = IPORTMXCTR1_FSSEL_8;
 387                        break;
 388                case 11025:
 389                        v = IPORTMXCTR1_FSSEL_11_025;
 390                        break;
 391                case 12000:
 392                        v = IPORTMXCTR1_FSSEL_12;
 393                        break;
 394                case 16000:
 395                        v = IPORTMXCTR1_FSSEL_16;
 396                        break;
 397                case 22050:
 398                        v = IPORTMXCTR1_FSSEL_22_05;
 399                        break;
 400                case 24000:
 401                        v = IPORTMXCTR1_FSSEL_24;
 402                        break;
 403                case 32000:
 404                        v = IPORTMXCTR1_FSSEL_32;
 405                        break;
 406                case 44100:
 407                        v = IPORTMXCTR1_FSSEL_44_1;
 408                        break;
 409                case 48000:
 410                        v = IPORTMXCTR1_FSSEL_48;
 411                        break;
 412                case 88200:
 413                        v = IPORTMXCTR1_FSSEL_88_2;
 414                        break;
 415                case 96000:
 416                        v = IPORTMXCTR1_FSSEL_96;
 417                        break;
 418                case 176400:
 419                        v = IPORTMXCTR1_FSSEL_176_4;
 420                        break;
 421                case 192000:
 422                        v = IPORTMXCTR1_FSSEL_192;
 423                        break;
 424                default:
 425                        dev_err(dev, "Rate not supported(%d)\n", rate);
 426                        return -EINVAL;
 427                }
 428
 429                regmap_update_bits(r, IPORTMXCTR1(sub->swm->iport.map),
 430                                   IPORTMXCTR1_FSSEL_MASK, v);
 431        }
 432
 433        return 0;
 434}
 435
 436/**
 437 * aio_port_set_fmt - set format of I2S data
 438 * @sub: the AIO substream pointer, PCM substream only
 439 * This parameter has no effect if substream is I2S or PCM.
 440 *
 441 * Set suitable I2S format settings to input/output port block of AIO.
 442 * Parameter is specified by set_fmt().
 443 *
 444 * This function may return error if non-PCM substream.
 445 *
 446 * Return: Zero if successful, otherwise a negative value on error.
 447 */
 448static int aio_port_set_fmt(struct uniphier_aio_sub *sub)
 449{
 450        struct regmap *r = sub->aio->chip->regmap;
 451        struct device *dev = &sub->aio->chip->pdev->dev;
 452        u32 v;
 453
 454        if (sub->swm->dir == PORT_DIR_OUTPUT) {
 455                switch (sub->aio->fmt) {
 456                case SND_SOC_DAIFMT_LEFT_J:
 457                        v = OPORTMXCTR1_I2SLRSEL_LEFT;
 458                        break;
 459                case SND_SOC_DAIFMT_RIGHT_J:
 460                        v = OPORTMXCTR1_I2SLRSEL_RIGHT;
 461                        break;
 462                case SND_SOC_DAIFMT_I2S:
 463                        v = OPORTMXCTR1_I2SLRSEL_I2S;
 464                        break;
 465                default:
 466                        dev_err(dev, "Format is not supported(%d)\n",
 467                                sub->aio->fmt);
 468                        return -EINVAL;
 469                }
 470
 471                v |= OPORTMXCTR1_OUTBITSEL_24;
 472                regmap_update_bits(r, OPORTMXCTR1(sub->swm->oport.map),
 473                                   OPORTMXCTR1_I2SLRSEL_MASK |
 474                                   OPORTMXCTR1_OUTBITSEL_MASK, v);
 475        } else {
 476                switch (sub->aio->fmt) {
 477                case SND_SOC_DAIFMT_LEFT_J:
 478                        v = IPORTMXCTR1_LRSEL_LEFT;
 479                        break;
 480                case SND_SOC_DAIFMT_RIGHT_J:
 481                        v = IPORTMXCTR1_LRSEL_RIGHT;
 482                        break;
 483                case SND_SOC_DAIFMT_I2S:
 484                        v = IPORTMXCTR1_LRSEL_I2S;
 485                        break;
 486                default:
 487                        dev_err(dev, "Format is not supported(%d)\n",
 488                                sub->aio->fmt);
 489                        return -EINVAL;
 490                }
 491
 492                v |= IPORTMXCTR1_OUTBITSEL_24 |
 493                        IPORTMXCTR1_CHSEL_ALL;
 494                regmap_update_bits(r, IPORTMXCTR1(sub->swm->iport.map),
 495                                   IPORTMXCTR1_LRSEL_MASK |
 496                                   IPORTMXCTR1_OUTBITSEL_MASK |
 497                                   IPORTMXCTR1_CHSEL_MASK, v);
 498        }
 499
 500        return 0;
 501}
 502
 503/**
 504 * aio_port_set_clk - set clock and divider of AIO port block
 505 * @sub: the AIO substream pointer
 506 *
 507 * Set suitable PLL clock divider and relational settings to
 508 * input/output port block of AIO. Parameters are specified by
 509 * set_sysclk() and set_pll().
 510 *
 511 * Return: Zero if successful, otherwise a negative value on error.
 512 */
 513static int aio_port_set_clk(struct uniphier_aio_sub *sub)
 514{
 515        struct uniphier_aio_chip *chip = sub->aio->chip;
 516        struct device *dev = &sub->aio->chip->pdev->dev;
 517        struct regmap *r = sub->aio->chip->regmap;
 518        u32 v_pll[] = {
 519                OPORTMXCTR2_ACLKSEL_A1, OPORTMXCTR2_ACLKSEL_F1,
 520                OPORTMXCTR2_ACLKSEL_A2, OPORTMXCTR2_ACLKSEL_F2,
 521                OPORTMXCTR2_ACLKSEL_A2PLL,
 522                OPORTMXCTR2_ACLKSEL_RX1,
 523        };
 524        u32 v_div[] = {
 525                OPORTMXCTR2_DACCKSEL_1_2, OPORTMXCTR2_DACCKSEL_1_3,
 526                OPORTMXCTR2_DACCKSEL_1_1, OPORTMXCTR2_DACCKSEL_2_3,
 527        };
 528        u32 v;
 529
 530        if (sub->swm->dir == PORT_DIR_OUTPUT) {
 531                if (sub->swm->type == PORT_TYPE_I2S) {
 532                        if (sub->aio->pll_out >= ARRAY_SIZE(v_pll)) {
 533                                dev_err(dev, "PLL(%d) is invalid\n",
 534                                        sub->aio->pll_out);
 535                                return -EINVAL;
 536                        }
 537                        if (sub->aio->plldiv >= ARRAY_SIZE(v_div)) {
 538                                dev_err(dev, "PLL divider(%d) is invalid\n",
 539                                        sub->aio->plldiv);
 540                                return -EINVAL;
 541                        }
 542
 543                        v = v_pll[sub->aio->pll_out] |
 544                                OPORTMXCTR2_MSSEL_MASTER |
 545                                v_div[sub->aio->plldiv];
 546
 547                        switch (chip->plls[sub->aio->pll_out].freq) {
 548                        case 0:
 549                        case 36864000:
 550                        case 33868800:
 551                                v |= OPORTMXCTR2_EXTLSIFSSEL_36;
 552                                break;
 553                        default:
 554                                v |= OPORTMXCTR2_EXTLSIFSSEL_24;
 555                                break;
 556                        }
 557                } else if (sub->swm->type == PORT_TYPE_EVE) {
 558                        v = OPORTMXCTR2_ACLKSEL_A2PLL |
 559                                OPORTMXCTR2_MSSEL_MASTER |
 560                                OPORTMXCTR2_EXTLSIFSSEL_36 |
 561                                OPORTMXCTR2_DACCKSEL_1_2;
 562                } else if (sub->swm->type == PORT_TYPE_SPDIF) {
 563                        if (sub->aio->pll_out >= ARRAY_SIZE(v_pll)) {
 564                                dev_err(dev, "PLL(%d) is invalid\n",
 565                                        sub->aio->pll_out);
 566                                return -EINVAL;
 567                        }
 568                        v = v_pll[sub->aio->pll_out] |
 569                                OPORTMXCTR2_MSSEL_MASTER |
 570                                OPORTMXCTR2_DACCKSEL_1_2;
 571
 572                        switch (chip->plls[sub->aio->pll_out].freq) {
 573                        case 0:
 574                        case 36864000:
 575                        case 33868800:
 576                                v |= OPORTMXCTR2_EXTLSIFSSEL_36;
 577                                break;
 578                        default:
 579                                v |= OPORTMXCTR2_EXTLSIFSSEL_24;
 580                                break;
 581                        }
 582                } else {
 583                        v = OPORTMXCTR2_ACLKSEL_A1 |
 584                                OPORTMXCTR2_MSSEL_MASTER |
 585                                OPORTMXCTR2_EXTLSIFSSEL_36 |
 586                                OPORTMXCTR2_DACCKSEL_1_2;
 587                }
 588                regmap_write(r, OPORTMXCTR2(sub->swm->oport.map), v);
 589        } else {
 590                v = IPORTMXCTR2_ACLKSEL_A1 |
 591                        IPORTMXCTR2_MSSEL_SLAVE |
 592                        IPORTMXCTR2_EXTLSIFSSEL_36 |
 593                        IPORTMXCTR2_DACCKSEL_1_2;
 594                regmap_write(r, IPORTMXCTR2(sub->swm->iport.map), v);
 595        }
 596
 597        return 0;
 598}
 599
 600/**
 601 * aio_port_set_param - set parameters of AIO port block
 602 * @sub: the AIO substream pointer
 603 * @pass_through: Zero if sound data is LPCM, otherwise if data is not LPCM.
 604 * This parameter has no effect if substream is I2S or PCM.
 605 * @params: hardware parameters of ALSA
 606 *
 607 * Set suitable setting to input/output port block of AIO to process the
 608 * specified in params.
 609 *
 610 * Return: Zero if successful, otherwise a negative value on error.
 611 */
 612int aio_port_set_param(struct uniphier_aio_sub *sub, int pass_through,
 613                       const struct snd_pcm_hw_params *params)
 614{
 615        struct regmap *r = sub->aio->chip->regmap;
 616        unsigned int rate;
 617        u32 v;
 618        int ret;
 619
 620        if (!pass_through) {
 621                if (sub->swm->type == PORT_TYPE_EVE ||
 622                    sub->swm->type == PORT_TYPE_CONV) {
 623                        rate = 48000;
 624                } else {
 625                        rate = params_rate(params);
 626                }
 627
 628                ret = aio_port_set_ch(sub);
 629                if (ret)
 630                        return ret;
 631
 632                ret = aio_port_set_rate(sub, rate);
 633                if (ret)
 634                        return ret;
 635
 636                ret = aio_port_set_fmt(sub);
 637                if (ret)
 638                        return ret;
 639        }
 640
 641        ret = aio_port_set_clk(sub);
 642        if (ret)
 643                return ret;
 644
 645        if (sub->swm->dir == PORT_DIR_OUTPUT) {
 646                if (pass_through)
 647                        v = OPORTMXCTR3_SRCSEL_STREAM |
 648                                OPORTMXCTR3_VALID_STREAM;
 649                else
 650                        v = OPORTMXCTR3_SRCSEL_PCM |
 651                                OPORTMXCTR3_VALID_PCM;
 652
 653                v |= OPORTMXCTR3_IECTHUR_IECOUT |
 654                        OPORTMXCTR3_PMSEL_PAUSE |
 655                        OPORTMXCTR3_PMSW_MUTE_OFF;
 656                regmap_write(r, OPORTMXCTR3(sub->swm->oport.map), v);
 657        } else {
 658                regmap_write(r, IPORTMXACLKSEL0EX(sub->swm->iport.map),
 659                             IPORTMXACLKSEL0EX_ACLKSEL0EX_INTERNAL);
 660                regmap_write(r, IPORTMXEXNOE(sub->swm->iport.map),
 661                             IPORTMXEXNOE_PCMINOE_INPUT);
 662        }
 663
 664        return 0;
 665}
 666
 667/**
 668 * aio_port_set_enable - start or stop of AIO port block
 669 * @sub: the AIO substream pointer
 670 * @enable: zero to stop the block, otherwise to start
 671 *
 672 * Start or stop the signal input/output port block of AIO.
 673 */
 674void aio_port_set_enable(struct uniphier_aio_sub *sub, int enable)
 675{
 676        struct regmap *r = sub->aio->chip->regmap;
 677
 678        if (sub->swm->dir == PORT_DIR_OUTPUT) {
 679                regmap_write(r, OPORTMXPATH(sub->swm->oport.map),
 680                             sub->swm->oif.map);
 681
 682                regmap_update_bits(r, OPORTMXMASK(sub->swm->oport.map),
 683                                   OPORTMXMASK_IUDXMSK_MASK |
 684                                   OPORTMXMASK_IUXCKMSK_MASK |
 685                                   OPORTMXMASK_DXMSK_MASK |
 686                                   OPORTMXMASK_XCKMSK_MASK,
 687                                   OPORTMXMASK_IUDXMSK_OFF |
 688                                   OPORTMXMASK_IUXCKMSK_OFF |
 689                                   OPORTMXMASK_DXMSK_OFF |
 690                                   OPORTMXMASK_XCKMSK_OFF);
 691
 692                if (enable)
 693                        regmap_write(r, AOUTENCTR0, BIT(sub->swm->oport.map));
 694                else
 695                        regmap_write(r, AOUTENCTR1, BIT(sub->swm->oport.map));
 696        } else {
 697                regmap_update_bits(r, IPORTMXMASK(sub->swm->iport.map),
 698                                   IPORTMXMASK_IUXCKMSK_MASK |
 699                                   IPORTMXMASK_XCKMSK_MASK,
 700                                   IPORTMXMASK_IUXCKMSK_OFF |
 701                                   IPORTMXMASK_XCKMSK_OFF);
 702
 703                if (enable)
 704                        regmap_update_bits(r,
 705                                           IPORTMXCTR2(sub->swm->iport.map),
 706                                           IPORTMXCTR2_REQEN_MASK,
 707                                           IPORTMXCTR2_REQEN_ENABLE);
 708                else
 709                        regmap_update_bits(r,
 710                                           IPORTMXCTR2(sub->swm->iport.map),
 711                                           IPORTMXCTR2_REQEN_MASK,
 712                                           IPORTMXCTR2_REQEN_DISABLE);
 713        }
 714}
 715
 716/**
 717 * aio_port_get_volume - get volume of AIO port block
 718 * @sub: the AIO substream pointer
 719 *
 720 * Return: current volume, range is 0x0000 - 0xffff
 721 */
 722int aio_port_get_volume(struct uniphier_aio_sub *sub)
 723{
 724        struct regmap *r = sub->aio->chip->regmap;
 725        u32 v;
 726
 727        regmap_read(r, OPORTMXTYVOLGAINSTATUS(sub->swm->oport.map, 0), &v);
 728
 729        return FIELD_GET(OPORTMXTYVOLGAINSTATUS_CUR_MASK, v);
 730}
 731
 732/**
 733 * aio_port_set_volume - set volume of AIO port block
 734 * @sub: the AIO substream pointer
 735 * @vol: target volume, range is 0x0000 - 0xffff.
 736 *
 737 * Change digital volume and perfome fade-out/fade-in effect for specified
 738 * output slot of port. Gained PCM value can calculate as the following:
 739 *   Gained = Original * vol / 0x4000
 740 */
 741void aio_port_set_volume(struct uniphier_aio_sub *sub, int vol)
 742{
 743        struct regmap *r = sub->aio->chip->regmap;
 744        int oport_map = sub->swm->oport.map;
 745        int cur, diff, slope = 0, fs;
 746
 747        if (sub->swm->dir == PORT_DIR_INPUT)
 748                return;
 749
 750        cur = aio_port_get_volume(sub);
 751        diff = abs(vol - cur);
 752        fs = params_rate(&sub->params);
 753        if (fs)
 754                slope = diff / AUD_VOL_FADE_TIME * 1000 / fs;
 755        slope = max(1, slope);
 756
 757        regmap_update_bits(r, OPORTMXTYVOLPARA1(oport_map, 0),
 758                           OPORTMXTYVOLPARA1_SLOPEU_MASK, slope << 16);
 759        regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
 760                           OPORTMXTYVOLPARA2_TARGET_MASK, vol);
 761
 762        if (cur < vol)
 763                regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
 764                                   OPORTMXTYVOLPARA2_FADE_MASK,
 765                                   OPORTMXTYVOLPARA2_FADE_FADEIN);
 766        else
 767                regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
 768                                   OPORTMXTYVOLPARA2_FADE_MASK,
 769                                   OPORTMXTYVOLPARA2_FADE_FADEOUT);
 770
 771        regmap_write(r, AOUTFADECTR0, BIT(oport_map));
 772}
 773
 774/**
 775 * aio_if_set_param - set parameters of AIO DMA I/F block
 776 * @sub: the AIO substream pointer
 777 * @pass_through: Zero if sound data is LPCM, otherwise if data is not LPCM.
 778 * This parameter has no effect if substream is I2S or PCM.
 779 *
 780 * Set suitable setting to DMA interface block of AIO to process the
 781 * specified in settings.
 782 *
 783 * Return: Zero if successful, otherwise a negative value on error.
 784 */
 785int aio_if_set_param(struct uniphier_aio_sub *sub, int pass_through)
 786{
 787        struct regmap *r = sub->aio->chip->regmap;
 788        u32 memfmt, v;
 789
 790        if (sub->swm->dir == PORT_DIR_OUTPUT) {
 791                if (pass_through) {
 792                        v = PBOUTMXCTR0_ENDIAN_0123 |
 793                                PBOUTMXCTR0_MEMFMT_STREAM;
 794                } else {
 795                        switch (params_channels(&sub->params)) {
 796                        case 2:
 797                                memfmt = PBOUTMXCTR0_MEMFMT_2CH;
 798                                break;
 799                        case 6:
 800                                memfmt = PBOUTMXCTR0_MEMFMT_6CH;
 801                                break;
 802                        case 8:
 803                                memfmt = PBOUTMXCTR0_MEMFMT_8CH;
 804                                break;
 805                        default:
 806                                return -EINVAL;
 807                        }
 808                        v = PBOUTMXCTR0_ENDIAN_3210 | memfmt;
 809                }
 810
 811                regmap_write(r, PBOUTMXCTR0(sub->swm->oif.map), v);
 812                regmap_write(r, PBOUTMXCTR1(sub->swm->oif.map), 0);
 813        } else {
 814                regmap_write(r, PBINMXCTR(sub->swm->iif.map),
 815                             PBINMXCTR_NCONNECT_CONNECT |
 816                             PBINMXCTR_INOUTSEL_IN |
 817                             (sub->swm->iport.map << PBINMXCTR_PBINSEL_SHIFT) |
 818                             PBINMXCTR_ENDIAN_3210 |
 819                             PBINMXCTR_MEMFMT_D0);
 820        }
 821
 822        return 0;
 823}
 824
 825/**
 826 * aio_oport_set_stream_type - set parameters of AIO playback port block
 827 * @sub: the AIO substream pointer
 828 * @pc: Pc type of IEC61937
 829 *
 830 * Set special setting to output port block of AIO to output the stream
 831 * via S/PDIF.
 832 *
 833 * Return: Zero if successful, otherwise a negative value on error.
 834 */
 835int aio_oport_set_stream_type(struct uniphier_aio_sub *sub,
 836                              enum IEC61937_PC pc)
 837{
 838        struct regmap *r = sub->aio->chip->regmap;
 839        u32 repet = 0, pause = OPORTMXPAUDAT_PAUSEPC_CMN;
 840
 841        switch (pc) {
 842        case IEC61937_PC_AC3:
 843                repet = OPORTMXREPET_STRLENGTH_AC3 |
 844                        OPORTMXREPET_PMLENGTH_AC3;
 845                pause |= OPORTMXPAUDAT_PAUSEPD_AC3;
 846                break;
 847        case IEC61937_PC_MPA:
 848                repet = OPORTMXREPET_STRLENGTH_MPA |
 849                        OPORTMXREPET_PMLENGTH_MPA;
 850                pause |= OPORTMXPAUDAT_PAUSEPD_MPA;
 851                break;
 852        case IEC61937_PC_MP3:
 853                repet = OPORTMXREPET_STRLENGTH_MP3 |
 854                        OPORTMXREPET_PMLENGTH_MP3;
 855                pause |= OPORTMXPAUDAT_PAUSEPD_MP3;
 856                break;
 857        case IEC61937_PC_DTS1:
 858                repet = OPORTMXREPET_STRLENGTH_DTS1 |
 859                        OPORTMXREPET_PMLENGTH_DTS1;
 860                pause |= OPORTMXPAUDAT_PAUSEPD_DTS1;
 861                break;
 862        case IEC61937_PC_DTS2:
 863                repet = OPORTMXREPET_STRLENGTH_DTS2 |
 864                        OPORTMXREPET_PMLENGTH_DTS2;
 865                pause |= OPORTMXPAUDAT_PAUSEPD_DTS2;
 866                break;
 867        case IEC61937_PC_DTS3:
 868                repet = OPORTMXREPET_STRLENGTH_DTS3 |
 869                        OPORTMXREPET_PMLENGTH_DTS3;
 870                pause |= OPORTMXPAUDAT_PAUSEPD_DTS3;
 871                break;
 872        case IEC61937_PC_AAC:
 873                repet = OPORTMXREPET_STRLENGTH_AAC |
 874                        OPORTMXREPET_PMLENGTH_AAC;
 875                pause |= OPORTMXPAUDAT_PAUSEPD_AAC;
 876                break;
 877        case IEC61937_PC_PAUSE:
 878                /* Do nothing */
 879                break;
 880        }
 881
 882        regmap_write(r, OPORTMXREPET(sub->swm->oport.map), repet);
 883        regmap_write(r, OPORTMXPAUDAT(sub->swm->oport.map), pause);
 884
 885        return 0;
 886}
 887
 888/**
 889 * aio_src_reset - reset AIO SRC block
 890 * @sub: the AIO substream pointer
 891 *
 892 * Resets the digital signal input/output port with sampling rate converter
 893 * block of AIO.
 894 * This function has no effect if substream is not supported rate converter.
 895 */
 896void aio_src_reset(struct uniphier_aio_sub *sub)
 897{
 898        struct regmap *r = sub->aio->chip->regmap;
 899
 900        if (sub->swm->dir != PORT_DIR_OUTPUT)
 901                return;
 902
 903        regmap_write(r, AOUTSRCRSTCTR0, BIT(sub->swm->oport.map));
 904        regmap_write(r, AOUTSRCRSTCTR1, BIT(sub->swm->oport.map));
 905}
 906
 907/**
 908 * aio_src_set_param - set parameters of AIO SRC block
 909 * @sub: the AIO substream pointer
 910 * @params: hardware parameters of ALSA
 911 *
 912 * Set suitable setting to input/output port with sampling rate converter
 913 * block of AIO to process the specified in params.
 914 * This function has no effect if substream is not supported rate converter.
 915 *
 916 * Return: Zero if successful, otherwise a negative value on error.
 917 */
 918int aio_src_set_param(struct uniphier_aio_sub *sub,
 919                      const struct snd_pcm_hw_params *params)
 920{
 921        struct regmap *r = sub->aio->chip->regmap;
 922        u32 v;
 923
 924        if (sub->swm->dir != PORT_DIR_OUTPUT)
 925                return 0;
 926
 927        regmap_write(r, OPORTMXSRC1CTR(sub->swm->oport.map),
 928                     OPORTMXSRC1CTR_THMODE_SRC |
 929                     OPORTMXSRC1CTR_SRCPATH_CALC |
 930                     OPORTMXSRC1CTR_SYNC_ASYNC |
 931                     OPORTMXSRC1CTR_FSIIPSEL_INNER |
 932                     OPORTMXSRC1CTR_FSISEL_ACLK);
 933
 934        switch (params_rate(params)) {
 935        default:
 936        case 48000:
 937                v = OPORTMXRATE_I_ACLKSEL_APLLA1 |
 938                        OPORTMXRATE_I_MCKSEL_36 |
 939                        OPORTMXRATE_I_FSSEL_48;
 940                break;
 941        case 44100:
 942                v = OPORTMXRATE_I_ACLKSEL_APLLA2 |
 943                        OPORTMXRATE_I_MCKSEL_33 |
 944                        OPORTMXRATE_I_FSSEL_44_1;
 945                break;
 946        case 32000:
 947                v = OPORTMXRATE_I_ACLKSEL_APLLA1 |
 948                        OPORTMXRATE_I_MCKSEL_36 |
 949                        OPORTMXRATE_I_FSSEL_32;
 950                break;
 951        }
 952
 953        regmap_write(r, OPORTMXRATE_I(sub->swm->oport.map),
 954                     v | OPORTMXRATE_I_ACLKSRC_APLL |
 955                     OPORTMXRATE_I_LRCKSTP_STOP);
 956        regmap_update_bits(r, OPORTMXRATE_I(sub->swm->oport.map),
 957                           OPORTMXRATE_I_LRCKSTP_MASK,
 958                           OPORTMXRATE_I_LRCKSTP_START);
 959
 960        return 0;
 961}
 962
 963int aio_srcif_set_param(struct uniphier_aio_sub *sub)
 964{
 965        struct regmap *r = sub->aio->chip->regmap;
 966
 967        regmap_write(r, PBINMXCTR(sub->swm->iif.map),
 968                     PBINMXCTR_NCONNECT_CONNECT |
 969                     PBINMXCTR_INOUTSEL_OUT |
 970                     (sub->swm->oport.map << PBINMXCTR_PBINSEL_SHIFT) |
 971                     PBINMXCTR_ENDIAN_3210 |
 972                     PBINMXCTR_MEMFMT_D0);
 973
 974        return 0;
 975}
 976
 977int aio_srcch_set_param(struct uniphier_aio_sub *sub)
 978{
 979        struct regmap *r = sub->aio->chip->regmap;
 980
 981        regmap_write(r, CDA2D_CHMXCTRL1(sub->swm->och.map),
 982                     CDA2D_CHMXCTRL1_INDSIZE_INFINITE);
 983
 984        regmap_write(r, CDA2D_CHMXSRCAMODE(sub->swm->och.map),
 985                     CDA2D_CHMXAMODE_ENDIAN_3210 |
 986                     CDA2D_CHMXAMODE_AUPDT_FIX |
 987                     CDA2D_CHMXAMODE_TYPE_NORMAL);
 988
 989        regmap_write(r, CDA2D_CHMXDSTAMODE(sub->swm->och.map),
 990                     CDA2D_CHMXAMODE_ENDIAN_3210 |
 991                     CDA2D_CHMXAMODE_AUPDT_INC |
 992                     CDA2D_CHMXAMODE_TYPE_RING |
 993                     (sub->swm->och.map << CDA2D_CHMXAMODE_RSSEL_SHIFT));
 994
 995        return 0;
 996}
 997
 998void aio_srcch_set_enable(struct uniphier_aio_sub *sub, int enable)
 999{
1000        struct regmap *r = sub->aio->chip->regmap;
1001        u32 v;
1002
1003        if (enable)
1004                v = CDA2D_STRT0_STOP_START;
1005        else
1006                v = CDA2D_STRT0_STOP_STOP;
1007
1008        regmap_write(r, CDA2D_STRT0,
1009                     v | BIT(sub->swm->och.map));
1010}
1011
1012int aiodma_ch_set_param(struct uniphier_aio_sub *sub)
1013{
1014        struct regmap *r = sub->aio->chip->regmap;
1015        u32 v;
1016
1017        regmap_write(r, CDA2D_CHMXCTRL1(sub->swm->ch.map),
1018                     CDA2D_CHMXCTRL1_INDSIZE_INFINITE);
1019
1020        v = CDA2D_CHMXAMODE_ENDIAN_3210 |
1021                CDA2D_CHMXAMODE_AUPDT_INC |
1022                CDA2D_CHMXAMODE_TYPE_NORMAL |
1023                (sub->swm->rb.map << CDA2D_CHMXAMODE_RSSEL_SHIFT);
1024        if (sub->swm->dir == PORT_DIR_OUTPUT)
1025                regmap_write(r, CDA2D_CHMXSRCAMODE(sub->swm->ch.map), v);
1026        else
1027                regmap_write(r, CDA2D_CHMXDSTAMODE(sub->swm->ch.map), v);
1028
1029        return 0;
1030}
1031
1032void aiodma_ch_set_enable(struct uniphier_aio_sub *sub, int enable)
1033{
1034        struct regmap *r = sub->aio->chip->regmap;
1035
1036        if (enable) {
1037                regmap_write(r, CDA2D_STRT0,
1038                             CDA2D_STRT0_STOP_START | BIT(sub->swm->ch.map));
1039
1040                regmap_update_bits(r, INTRBIM(0),
1041                                   BIT(sub->swm->rb.map),
1042                                   BIT(sub->swm->rb.map));
1043        } else {
1044                regmap_write(r, CDA2D_STRT0,
1045                             CDA2D_STRT0_STOP_STOP | BIT(sub->swm->ch.map));
1046
1047                regmap_update_bits(r, INTRBIM(0),
1048                                   BIT(sub->swm->rb.map),
1049                                   0);
1050        }
1051}
1052
1053static u64 aiodma_rb_get_rp(struct uniphier_aio_sub *sub)
1054{
1055        struct regmap *r = sub->aio->chip->regmap;
1056        u32 pos_u, pos_l;
1057        int i;
1058
1059        regmap_write(r, CDA2D_RDPTRLOAD,
1060                     CDA2D_RDPTRLOAD_LSFLAG_STORE | BIT(sub->swm->rb.map));
1061        /* Wait for setup */
1062        for (i = 0; i < 6; i++)
1063                regmap_read(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), &pos_l);
1064
1065        regmap_read(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), &pos_l);
1066        regmap_read(r, CDA2D_RBMXRDPTRU(sub->swm->rb.map), &pos_u);
1067        pos_u = FIELD_GET(CDA2D_RBMXPTRU_PTRU_MASK, pos_u);
1068
1069        return ((u64)pos_u << 32) | pos_l;
1070}
1071
1072static void aiodma_rb_set_rp(struct uniphier_aio_sub *sub, u64 pos)
1073{
1074        struct regmap *r = sub->aio->chip->regmap;
1075        u32 tmp;
1076        int i;
1077
1078        regmap_write(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), (u32)pos);
1079        regmap_write(r, CDA2D_RBMXRDPTRU(sub->swm->rb.map), (u32)(pos >> 32));
1080        regmap_write(r, CDA2D_RDPTRLOAD, BIT(sub->swm->rb.map));
1081        /* Wait for setup */
1082        for (i = 0; i < 6; i++)
1083                regmap_read(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), &tmp);
1084}
1085
1086static u64 aiodma_rb_get_wp(struct uniphier_aio_sub *sub)
1087{
1088        struct regmap *r = sub->aio->chip->regmap;
1089        u32 pos_u, pos_l;
1090        int i;
1091
1092        regmap_write(r, CDA2D_WRPTRLOAD,
1093                     CDA2D_WRPTRLOAD_LSFLAG_STORE | BIT(sub->swm->rb.map));
1094        /* Wait for setup */
1095        for (i = 0; i < 6; i++)
1096                regmap_read(r, CDA2D_RBMXWRPTR(sub->swm->rb.map), &pos_l);
1097
1098        regmap_read(r, CDA2D_RBMXWRPTR(sub->swm->rb.map), &pos_l);
1099        regmap_read(r, CDA2D_RBMXWRPTRU(sub->swm->rb.map), &pos_u);
1100        pos_u = FIELD_GET(CDA2D_RBMXPTRU_PTRU_MASK, pos_u);
1101
1102        return ((u64)pos_u << 32) | pos_l;
1103}
1104
1105static void aiodma_rb_set_wp(struct uniphier_aio_sub *sub, u64 pos)
1106{
1107        struct regmap *r = sub->aio->chip->regmap;
1108        u32 tmp;
1109        int i;
1110
1111        regmap_write(r, CDA2D_RBMXWRPTR(sub->swm->rb.map),
1112                     lower_32_bits(pos));
1113        regmap_write(r, CDA2D_RBMXWRPTRU(sub->swm->rb.map),
1114                     upper_32_bits(pos));
1115        regmap_write(r, CDA2D_WRPTRLOAD, BIT(sub->swm->rb.map));
1116        /* Wait for setup */
1117        for (i = 0; i < 6; i++)
1118                regmap_read(r, CDA2D_RBMXWRPTR(sub->swm->rb.map), &tmp);
1119}
1120
1121int aiodma_rb_set_threshold(struct uniphier_aio_sub *sub, u64 size, u32 th)
1122{
1123        struct regmap *r = sub->aio->chip->regmap;
1124
1125        if (size <= th)
1126                return -EINVAL;
1127
1128        regmap_write(r, CDA2D_RBMXBTH(sub->swm->rb.map), th);
1129        regmap_write(r, CDA2D_RBMXRTH(sub->swm->rb.map), th);
1130
1131        return 0;
1132}
1133
1134int aiodma_rb_set_buffer(struct uniphier_aio_sub *sub, u64 start, u64 end,
1135                         int period)
1136{
1137        struct regmap *r = sub->aio->chip->regmap;
1138        u64 size = end - start;
1139        int ret;
1140
1141        if (end < start || period < 0)
1142                return -EINVAL;
1143
1144        regmap_write(r, CDA2D_RBMXCNFG(sub->swm->rb.map), 0);
1145        regmap_write(r, CDA2D_RBMXBGNADRS(sub->swm->rb.map),
1146                     lower_32_bits(start));
1147        regmap_write(r, CDA2D_RBMXBGNADRSU(sub->swm->rb.map),
1148                     upper_32_bits(start));
1149        regmap_write(r, CDA2D_RBMXENDADRS(sub->swm->rb.map),
1150                     lower_32_bits(end));
1151        regmap_write(r, CDA2D_RBMXENDADRSU(sub->swm->rb.map),
1152                     upper_32_bits(end));
1153
1154        regmap_write(r, CDA2D_RBADRSLOAD, BIT(sub->swm->rb.map));
1155
1156        ret = aiodma_rb_set_threshold(sub, size, 2 * period);
1157        if (ret)
1158                return ret;
1159
1160        if (sub->swm->dir == PORT_DIR_OUTPUT) {
1161                aiodma_rb_set_rp(sub, start);
1162                aiodma_rb_set_wp(sub, end - period);
1163
1164                regmap_update_bits(r, CDA2D_RBMXIE(sub->swm->rb.map),
1165                                   CDA2D_RBMXIX_SPACE,
1166                                   CDA2D_RBMXIX_SPACE);
1167        } else {
1168                aiodma_rb_set_rp(sub, end - period);
1169                aiodma_rb_set_wp(sub, start);
1170
1171                regmap_update_bits(r, CDA2D_RBMXIE(sub->swm->rb.map),
1172                                   CDA2D_RBMXIX_REMAIN,
1173                                   CDA2D_RBMXIX_REMAIN);
1174        }
1175
1176        sub->threshold = 2 * period;
1177        sub->rd_offs = 0;
1178        sub->wr_offs = 0;
1179        sub->rd_org = 0;
1180        sub->wr_org = 0;
1181        sub->rd_total = 0;
1182        sub->wr_total = 0;
1183
1184        return 0;
1185}
1186
1187void aiodma_rb_sync(struct uniphier_aio_sub *sub, u64 start, u64 size,
1188                    int period)
1189{
1190        if (sub->swm->dir == PORT_DIR_OUTPUT) {
1191                sub->rd_offs = aiodma_rb_get_rp(sub) - start;
1192
1193                if (sub->use_mmap) {
1194                        sub->threshold = 2 * period;
1195                        aiodma_rb_set_threshold(sub, size, 2 * period);
1196
1197                        sub->wr_offs = sub->rd_offs - period;
1198                        if (sub->rd_offs < period)
1199                                sub->wr_offs += size;
1200                }
1201                aiodma_rb_set_wp(sub, sub->wr_offs + start);
1202        } else {
1203                sub->wr_offs = aiodma_rb_get_wp(sub) - start;
1204
1205                if (sub->use_mmap) {
1206                        sub->threshold = 2 * period;
1207                        aiodma_rb_set_threshold(sub, size, 2 * period);
1208
1209                        sub->rd_offs = sub->wr_offs - period;
1210                        if (sub->wr_offs < period)
1211                                sub->rd_offs += size;
1212                }
1213                aiodma_rb_set_rp(sub, sub->rd_offs + start);
1214        }
1215
1216        sub->rd_total += sub->rd_offs - sub->rd_org;
1217        if (sub->rd_offs < sub->rd_org)
1218                sub->rd_total += size;
1219        sub->wr_total += sub->wr_offs - sub->wr_org;
1220        if (sub->wr_offs < sub->wr_org)
1221                sub->wr_total += size;
1222
1223        sub->rd_org = sub->rd_offs;
1224        sub->wr_org = sub->wr_offs;
1225}
1226
1227bool aiodma_rb_is_irq(struct uniphier_aio_sub *sub)
1228{
1229        struct regmap *r = sub->aio->chip->regmap;
1230        u32 ir;
1231
1232        regmap_read(r, CDA2D_RBMXIR(sub->swm->rb.map), &ir);
1233
1234        if (sub->swm->dir == PORT_DIR_OUTPUT)
1235                return !!(ir & CDA2D_RBMXIX_SPACE);
1236        else
1237                return !!(ir & CDA2D_RBMXIX_REMAIN);
1238}
1239
1240void aiodma_rb_clear_irq(struct uniphier_aio_sub *sub)
1241{
1242        struct regmap *r = sub->aio->chip->regmap;
1243
1244        if (sub->swm->dir == PORT_DIR_OUTPUT)
1245                regmap_write(r, CDA2D_RBMXIR(sub->swm->rb.map),
1246                             CDA2D_RBMXIX_SPACE);
1247        else
1248                regmap_write(r, CDA2D_RBMXIR(sub->swm->rb.map),
1249                             CDA2D_RBMXIX_REMAIN);
1250}
1251