Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // Socionext UniPhier AIO ALSA common driver.
0004 //
0005 // Copyright (c) 2016-2018 Socionext Inc.
0006 
0007 #include <linux/bitfield.h>
0008 #include <linux/errno.h>
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <sound/core.h>
0012 #include <sound/pcm.h>
0013 #include <sound/pcm_params.h>
0014 #include <sound/soc.h>
0015 
0016 #include "aio.h"
0017 #include "aio-reg.h"
0018 
0019 static u64 rb_cnt(u64 wr, u64 rd, u64 len)
0020 {
0021     if (rd <= wr)
0022         return wr - rd;
0023     else
0024         return len - (rd - wr);
0025 }
0026 
0027 static u64 rb_cnt_to_end(u64 wr, u64 rd, u64 len)
0028 {
0029     if (rd <= wr)
0030         return wr - rd;
0031     else
0032         return len - rd;
0033 }
0034 
0035 static u64 rb_space(u64 wr, u64 rd, u64 len)
0036 {
0037     if (rd <= wr)
0038         return len - (wr - rd) - 8;
0039     else
0040         return rd - wr - 8;
0041 }
0042 
0043 static u64 rb_space_to_end(u64 wr, u64 rd, u64 len)
0044 {
0045     if (rd > wr)
0046         return rd - wr - 8;
0047     else if (rd > 0)
0048         return len - wr;
0049     else
0050         return len - wr - 8;
0051 }
0052 
0053 u64 aio_rb_cnt(struct uniphier_aio_sub *sub)
0054 {
0055     return rb_cnt(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
0056 }
0057 
0058 u64 aio_rbt_cnt_to_end(struct uniphier_aio_sub *sub)
0059 {
0060     return rb_cnt_to_end(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
0061 }
0062 
0063 u64 aio_rb_space(struct uniphier_aio_sub *sub)
0064 {
0065     return rb_space(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
0066 }
0067 
0068 u64 aio_rb_space_to_end(struct uniphier_aio_sub *sub)
0069 {
0070     return rb_space_to_end(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
0071 }
0072 
0073 /**
0074  * aio_iecout_set_enable - setup IEC output via SoC glue
0075  * @chip: the AIO chip pointer
0076  * @enable: false to stop the output, true to start
0077  *
0078  * Set enabled or disabled S/PDIF signal output to out of SoC via AOnIEC pins.
0079  * This function need to call at driver startup.
0080  *
0081  * The regmap of SoC glue is specified by 'socionext,syscon' optional property
0082  * of DT. This function has no effect if no property.
0083  */
0084 void aio_iecout_set_enable(struct uniphier_aio_chip *chip, bool enable)
0085 {
0086     struct regmap *r = chip->regmap_sg;
0087 
0088     if (!r)
0089         return;
0090 
0091     regmap_write(r, SG_AOUTEN, (enable) ? ~0 : 0);
0092 }
0093 
0094 /**
0095  * aio_chip_set_pll - set frequency to audio PLL
0096  * @chip: the AIO chip pointer
0097  * @pll_id: PLL
0098  * @freq: frequency in Hz, 0 is ignored
0099  *
0100  * Sets frequency of audio PLL. This function can be called anytime,
0101  * but it takes time till PLL is locked.
0102  *
0103  * Return: Zero if successful, otherwise a negative value on error.
0104  */
0105 int aio_chip_set_pll(struct uniphier_aio_chip *chip, int pll_id,
0106              unsigned int freq)
0107 {
0108     struct device *dev = &chip->pdev->dev;
0109     struct regmap *r = chip->regmap;
0110     int shift;
0111     u32 v;
0112 
0113     /* Not change */
0114     if (freq == 0)
0115         return 0;
0116 
0117     switch (pll_id) {
0118     case AUD_PLL_A1:
0119         shift = 0;
0120         break;
0121     case AUD_PLL_F1:
0122         shift = 1;
0123         break;
0124     case AUD_PLL_A2:
0125         shift = 2;
0126         break;
0127     case AUD_PLL_F2:
0128         shift = 3;
0129         break;
0130     default:
0131         dev_err(dev, "PLL(%d) not supported\n", pll_id);
0132         return -EINVAL;
0133     }
0134 
0135     switch (freq) {
0136     case 36864000:
0137         v = A2APLLCTR1_APLLX_36MHZ;
0138         break;
0139     case 33868800:
0140         v = A2APLLCTR1_APLLX_33MHZ;
0141         break;
0142     default:
0143         dev_err(dev, "PLL frequency not supported(%d)\n", freq);
0144         return -EINVAL;
0145     }
0146     chip->plls[pll_id].freq = freq;
0147 
0148     regmap_update_bits(r, A2APLLCTR1, A2APLLCTR1_APLLX_MASK << shift,
0149                v << shift);
0150 
0151     return 0;
0152 }
0153 
0154 /**
0155  * aio_chip_init - initialize AIO whole settings
0156  * @chip: the AIO chip pointer
0157  *
0158  * Sets AIO fixed and whole device settings to AIO.
0159  * This function need to call once at driver startup.
0160  *
0161  * The register area that is changed by this function is shared by all
0162  * modules of AIO. But there is not race condition since this function
0163  * has always set the same initialize values.
0164  */
0165 void aio_chip_init(struct uniphier_aio_chip *chip)
0166 {
0167     struct regmap *r = chip->regmap;
0168 
0169     regmap_update_bits(r, A2APLLCTR0,
0170                A2APLLCTR0_APLLXPOW_MASK,
0171                A2APLLCTR0_APLLXPOW_PWON);
0172 
0173     regmap_update_bits(r, A2EXMCLKSEL0,
0174                A2EXMCLKSEL0_EXMCLK_MASK,
0175                A2EXMCLKSEL0_EXMCLK_OUTPUT);
0176 
0177     regmap_update_bits(r, A2AIOINPUTSEL, A2AIOINPUTSEL_RXSEL_MASK,
0178                A2AIOINPUTSEL_RXSEL_PCMI1_HDMIRX1 |
0179                A2AIOINPUTSEL_RXSEL_PCMI2_SIF |
0180                A2AIOINPUTSEL_RXSEL_PCMI3_EVEA |
0181                A2AIOINPUTSEL_RXSEL_IECI1_HDMIRX1);
0182 
0183     if (chip->chip_spec->addr_ext)
0184         regmap_update_bits(r, CDA2D_TEST, CDA2D_TEST_DDR_MODE_MASK,
0185                    CDA2D_TEST_DDR_MODE_EXTON0);
0186     else
0187         regmap_update_bits(r, CDA2D_TEST, CDA2D_TEST_DDR_MODE_MASK,
0188                    CDA2D_TEST_DDR_MODE_EXTOFF1);
0189 }
0190 
0191 /**
0192  * aio_init - initialize AIO substream
0193  * @sub: the AIO substream pointer
0194  *
0195  * Sets fixed settings of each AIO substreams.
0196  * This function need to call once at substream startup.
0197  *
0198  * Return: Zero if successful, otherwise a negative value on error.
0199  */
0200 int aio_init(struct uniphier_aio_sub *sub)
0201 {
0202     struct device *dev = &sub->aio->chip->pdev->dev;
0203     struct regmap *r = sub->aio->chip->regmap;
0204 
0205     regmap_write(r, A2RBNMAPCTR0(sub->swm->rb.hw),
0206              MAPCTR0_EN | sub->swm->rb.map);
0207     regmap_write(r, A2CHNMAPCTR0(sub->swm->ch.hw),
0208              MAPCTR0_EN | sub->swm->ch.map);
0209 
0210     switch (sub->swm->type) {
0211     case PORT_TYPE_I2S:
0212     case PORT_TYPE_SPDIF:
0213     case PORT_TYPE_EVE:
0214         if (sub->swm->dir == PORT_DIR_INPUT) {
0215             regmap_write(r, A2IIFNMAPCTR0(sub->swm->iif.hw),
0216                      MAPCTR0_EN | sub->swm->iif.map);
0217             regmap_write(r, A2IPORTNMAPCTR0(sub->swm->iport.hw),
0218                      MAPCTR0_EN | sub->swm->iport.map);
0219         } else {
0220             regmap_write(r, A2OIFNMAPCTR0(sub->swm->oif.hw),
0221                      MAPCTR0_EN | sub->swm->oif.map);
0222             regmap_write(r, A2OPORTNMAPCTR0(sub->swm->oport.hw),
0223                      MAPCTR0_EN | sub->swm->oport.map);
0224         }
0225         break;
0226     case PORT_TYPE_CONV:
0227         regmap_write(r, A2OIFNMAPCTR0(sub->swm->oif.hw),
0228                  MAPCTR0_EN | sub->swm->oif.map);
0229         regmap_write(r, A2OPORTNMAPCTR0(sub->swm->oport.hw),
0230                  MAPCTR0_EN | sub->swm->oport.map);
0231         regmap_write(r, A2CHNMAPCTR0(sub->swm->och.hw),
0232                  MAPCTR0_EN | sub->swm->och.map);
0233         regmap_write(r, A2IIFNMAPCTR0(sub->swm->iif.hw),
0234                  MAPCTR0_EN | sub->swm->iif.map);
0235         break;
0236     default:
0237         dev_err(dev, "Unknown port type %d.\n", sub->swm->type);
0238         return -EINVAL;
0239     }
0240 
0241     return 0;
0242 }
0243 
0244 /**
0245  * aio_port_reset - reset AIO port block
0246  * @sub: the AIO substream pointer
0247  *
0248  * Resets the digital signal input/output port block of AIO.
0249  */
0250 void aio_port_reset(struct uniphier_aio_sub *sub)
0251 {
0252     struct regmap *r = sub->aio->chip->regmap;
0253 
0254     if (sub->swm->dir == PORT_DIR_OUTPUT) {
0255         regmap_write(r, AOUTRSTCTR0, BIT(sub->swm->oport.map));
0256         regmap_write(r, AOUTRSTCTR1, BIT(sub->swm->oport.map));
0257     } else {
0258         regmap_update_bits(r, IPORTMXRSTCTR(sub->swm->iport.map),
0259                    IPORTMXRSTCTR_RSTPI_MASK,
0260                    IPORTMXRSTCTR_RSTPI_RESET);
0261         regmap_update_bits(r, IPORTMXRSTCTR(sub->swm->iport.map),
0262                    IPORTMXRSTCTR_RSTPI_MASK,
0263                    IPORTMXRSTCTR_RSTPI_RELEASE);
0264     }
0265 }
0266 
0267 /**
0268  * aio_port_set_ch - set channels of LPCM
0269  * @sub: the AIO substream pointer, PCM substream only
0270  *
0271  * Set suitable slot selecting to input/output port block of AIO.
0272  *
0273  * This function may return error if non-PCM substream.
0274  *
0275  * Return: Zero if successful, otherwise a negative value on error.
0276  */
0277 static int aio_port_set_ch(struct uniphier_aio_sub *sub)
0278 {
0279     struct regmap *r = sub->aio->chip->regmap;
0280     u32 slotsel_2ch[] = {
0281         0, 0, 0, 0, 0,
0282     };
0283     u32 slotsel_multi[] = {
0284         OPORTMXTYSLOTCTR_SLOTSEL_SLOT0,
0285         OPORTMXTYSLOTCTR_SLOTSEL_SLOT1,
0286         OPORTMXTYSLOTCTR_SLOTSEL_SLOT2,
0287         OPORTMXTYSLOTCTR_SLOTSEL_SLOT3,
0288         OPORTMXTYSLOTCTR_SLOTSEL_SLOT4,
0289     };
0290     u32 mode, *slotsel;
0291     int i;
0292 
0293     switch (params_channels(&sub->params)) {
0294     case 8:
0295     case 6:
0296         mode = OPORTMXTYSLOTCTR_MODE;
0297         slotsel = slotsel_multi;
0298         break;
0299     case 2:
0300         mode = 0;
0301         slotsel = slotsel_2ch;
0302         break;
0303     default:
0304         return -EINVAL;
0305     }
0306 
0307     for (i = 0; i < AUD_MAX_SLOTSEL; i++) {
0308         regmap_update_bits(r, OPORTMXTYSLOTCTR(sub->swm->oport.map, i),
0309                    OPORTMXTYSLOTCTR_MODE, mode);
0310         regmap_update_bits(r, OPORTMXTYSLOTCTR(sub->swm->oport.map, i),
0311                    OPORTMXTYSLOTCTR_SLOTSEL_MASK, slotsel[i]);
0312     }
0313 
0314     return 0;
0315 }
0316 
0317 /**
0318  * aio_port_set_rate - set sampling rate of LPCM
0319  * @sub: the AIO substream pointer, PCM substream only
0320  * @rate: Sampling rate in Hz.
0321  *
0322  * Set suitable I2S format settings to input/output port block of AIO.
0323  * Parameter is specified by hw_params().
0324  *
0325  * This function may return error if non-PCM substream.
0326  *
0327  * Return: Zero if successful, otherwise a negative value on error.
0328  */
0329 static int aio_port_set_rate(struct uniphier_aio_sub *sub, int rate)
0330 {
0331     struct regmap *r = sub->aio->chip->regmap;
0332     struct device *dev = &sub->aio->chip->pdev->dev;
0333     u32 v;
0334 
0335     if (sub->swm->dir == PORT_DIR_OUTPUT) {
0336         switch (rate) {
0337         case 8000:
0338             v = OPORTMXCTR1_FSSEL_8;
0339             break;
0340         case 11025:
0341             v = OPORTMXCTR1_FSSEL_11_025;
0342             break;
0343         case 12000:
0344             v = OPORTMXCTR1_FSSEL_12;
0345             break;
0346         case 16000:
0347             v = OPORTMXCTR1_FSSEL_16;
0348             break;
0349         case 22050:
0350             v = OPORTMXCTR1_FSSEL_22_05;
0351             break;
0352         case 24000:
0353             v = OPORTMXCTR1_FSSEL_24;
0354             break;
0355         case 32000:
0356             v = OPORTMXCTR1_FSSEL_32;
0357             break;
0358         case 44100:
0359             v = OPORTMXCTR1_FSSEL_44_1;
0360             break;
0361         case 48000:
0362             v = OPORTMXCTR1_FSSEL_48;
0363             break;
0364         case 88200:
0365             v = OPORTMXCTR1_FSSEL_88_2;
0366             break;
0367         case 96000:
0368             v = OPORTMXCTR1_FSSEL_96;
0369             break;
0370         case 176400:
0371             v = OPORTMXCTR1_FSSEL_176_4;
0372             break;
0373         case 192000:
0374             v = OPORTMXCTR1_FSSEL_192;
0375             break;
0376         default:
0377             dev_err(dev, "Rate not supported(%d)\n", rate);
0378             return -EINVAL;
0379         }
0380 
0381         regmap_update_bits(r, OPORTMXCTR1(sub->swm->oport.map),
0382                    OPORTMXCTR1_FSSEL_MASK, v);
0383     } else {
0384         switch (rate) {
0385         case 8000:
0386             v = IPORTMXCTR1_FSSEL_8;
0387             break;
0388         case 11025:
0389             v = IPORTMXCTR1_FSSEL_11_025;
0390             break;
0391         case 12000:
0392             v = IPORTMXCTR1_FSSEL_12;
0393             break;
0394         case 16000:
0395             v = IPORTMXCTR1_FSSEL_16;
0396             break;
0397         case 22050:
0398             v = IPORTMXCTR1_FSSEL_22_05;
0399             break;
0400         case 24000:
0401             v = IPORTMXCTR1_FSSEL_24;
0402             break;
0403         case 32000:
0404             v = IPORTMXCTR1_FSSEL_32;
0405             break;
0406         case 44100:
0407             v = IPORTMXCTR1_FSSEL_44_1;
0408             break;
0409         case 48000:
0410             v = IPORTMXCTR1_FSSEL_48;
0411             break;
0412         case 88200:
0413             v = IPORTMXCTR1_FSSEL_88_2;
0414             break;
0415         case 96000:
0416             v = IPORTMXCTR1_FSSEL_96;
0417             break;
0418         case 176400:
0419             v = IPORTMXCTR1_FSSEL_176_4;
0420             break;
0421         case 192000:
0422             v = IPORTMXCTR1_FSSEL_192;
0423             break;
0424         default:
0425             dev_err(dev, "Rate not supported(%d)\n", rate);
0426             return -EINVAL;
0427         }
0428 
0429         regmap_update_bits(r, IPORTMXCTR1(sub->swm->iport.map),
0430                    IPORTMXCTR1_FSSEL_MASK, v);
0431     }
0432 
0433     return 0;
0434 }
0435 
0436 /**
0437  * aio_port_set_fmt - set format of I2S data
0438  * @sub: the AIO substream pointer, PCM substream only
0439  * This parameter has no effect if substream is I2S or PCM.
0440  *
0441  * Set suitable I2S format settings to input/output port block of AIO.
0442  * Parameter is specified by set_fmt().
0443  *
0444  * This function may return error if non-PCM substream.
0445  *
0446  * Return: Zero if successful, otherwise a negative value on error.
0447  */
0448 static int aio_port_set_fmt(struct uniphier_aio_sub *sub)
0449 {
0450     struct regmap *r = sub->aio->chip->regmap;
0451     struct device *dev = &sub->aio->chip->pdev->dev;
0452     u32 v;
0453 
0454     if (sub->swm->dir == PORT_DIR_OUTPUT) {
0455         switch (sub->aio->fmt) {
0456         case SND_SOC_DAIFMT_LEFT_J:
0457             v = OPORTMXCTR1_I2SLRSEL_LEFT;
0458             break;
0459         case SND_SOC_DAIFMT_RIGHT_J:
0460             v = OPORTMXCTR1_I2SLRSEL_RIGHT;
0461             break;
0462         case SND_SOC_DAIFMT_I2S:
0463             v = OPORTMXCTR1_I2SLRSEL_I2S;
0464             break;
0465         default:
0466             dev_err(dev, "Format is not supported(%d)\n",
0467                 sub->aio->fmt);
0468             return -EINVAL;
0469         }
0470 
0471         v |= OPORTMXCTR1_OUTBITSEL_24;
0472         regmap_update_bits(r, OPORTMXCTR1(sub->swm->oport.map),
0473                    OPORTMXCTR1_I2SLRSEL_MASK |
0474                    OPORTMXCTR1_OUTBITSEL_MASK, v);
0475     } else {
0476         switch (sub->aio->fmt) {
0477         case SND_SOC_DAIFMT_LEFT_J:
0478             v = IPORTMXCTR1_LRSEL_LEFT;
0479             break;
0480         case SND_SOC_DAIFMT_RIGHT_J:
0481             v = IPORTMXCTR1_LRSEL_RIGHT;
0482             break;
0483         case SND_SOC_DAIFMT_I2S:
0484             v = IPORTMXCTR1_LRSEL_I2S;
0485             break;
0486         default:
0487             dev_err(dev, "Format is not supported(%d)\n",
0488                 sub->aio->fmt);
0489             return -EINVAL;
0490         }
0491 
0492         v |= IPORTMXCTR1_OUTBITSEL_24 |
0493             IPORTMXCTR1_CHSEL_ALL;
0494         regmap_update_bits(r, IPORTMXCTR1(sub->swm->iport.map),
0495                    IPORTMXCTR1_LRSEL_MASK |
0496                    IPORTMXCTR1_OUTBITSEL_MASK |
0497                    IPORTMXCTR1_CHSEL_MASK, v);
0498     }
0499 
0500     return 0;
0501 }
0502 
0503 /**
0504  * aio_port_set_clk - set clock and divider of AIO port block
0505  * @sub: the AIO substream pointer
0506  *
0507  * Set suitable PLL clock divider and relational settings to
0508  * input/output port block of AIO. Parameters are specified by
0509  * set_sysclk() and set_pll().
0510  *
0511  * Return: Zero if successful, otherwise a negative value on error.
0512  */
0513 static int aio_port_set_clk(struct uniphier_aio_sub *sub)
0514 {
0515     struct uniphier_aio_chip *chip = sub->aio->chip;
0516     struct device *dev = &sub->aio->chip->pdev->dev;
0517     struct regmap *r = sub->aio->chip->regmap;
0518     u32 v_pll[] = {
0519         OPORTMXCTR2_ACLKSEL_A1, OPORTMXCTR2_ACLKSEL_F1,
0520         OPORTMXCTR2_ACLKSEL_A2, OPORTMXCTR2_ACLKSEL_F2,
0521         OPORTMXCTR2_ACLKSEL_A2PLL,
0522         OPORTMXCTR2_ACLKSEL_RX1,
0523     };
0524     u32 v_div[] = {
0525         OPORTMXCTR2_DACCKSEL_1_2, OPORTMXCTR2_DACCKSEL_1_3,
0526         OPORTMXCTR2_DACCKSEL_1_1, OPORTMXCTR2_DACCKSEL_2_3,
0527     };
0528     u32 v;
0529 
0530     if (sub->swm->dir == PORT_DIR_OUTPUT) {
0531         if (sub->swm->type == PORT_TYPE_I2S) {
0532             if (sub->aio->pll_out >= ARRAY_SIZE(v_pll)) {
0533                 dev_err(dev, "PLL(%d) is invalid\n",
0534                     sub->aio->pll_out);
0535                 return -EINVAL;
0536             }
0537             if (sub->aio->plldiv >= ARRAY_SIZE(v_div)) {
0538                 dev_err(dev, "PLL divider(%d) is invalid\n",
0539                     sub->aio->plldiv);
0540                 return -EINVAL;
0541             }
0542 
0543             v = v_pll[sub->aio->pll_out] |
0544                 OPORTMXCTR2_MSSEL_MASTER |
0545                 v_div[sub->aio->plldiv];
0546 
0547             switch (chip->plls[sub->aio->pll_out].freq) {
0548             case 0:
0549             case 36864000:
0550             case 33868800:
0551                 v |= OPORTMXCTR2_EXTLSIFSSEL_36;
0552                 break;
0553             default:
0554                 v |= OPORTMXCTR2_EXTLSIFSSEL_24;
0555                 break;
0556             }
0557         } else if (sub->swm->type == PORT_TYPE_EVE) {
0558             v = OPORTMXCTR2_ACLKSEL_A2PLL |
0559                 OPORTMXCTR2_MSSEL_MASTER |
0560                 OPORTMXCTR2_EXTLSIFSSEL_36 |
0561                 OPORTMXCTR2_DACCKSEL_1_2;
0562         } else if (sub->swm->type == PORT_TYPE_SPDIF) {
0563             if (sub->aio->pll_out >= ARRAY_SIZE(v_pll)) {
0564                 dev_err(dev, "PLL(%d) is invalid\n",
0565                     sub->aio->pll_out);
0566                 return -EINVAL;
0567             }
0568             v = v_pll[sub->aio->pll_out] |
0569                 OPORTMXCTR2_MSSEL_MASTER |
0570                 OPORTMXCTR2_DACCKSEL_1_2;
0571 
0572             switch (chip->plls[sub->aio->pll_out].freq) {
0573             case 0:
0574             case 36864000:
0575             case 33868800:
0576                 v |= OPORTMXCTR2_EXTLSIFSSEL_36;
0577                 break;
0578             default:
0579                 v |= OPORTMXCTR2_EXTLSIFSSEL_24;
0580                 break;
0581             }
0582         } else {
0583             v = OPORTMXCTR2_ACLKSEL_A1 |
0584                 OPORTMXCTR2_MSSEL_MASTER |
0585                 OPORTMXCTR2_EXTLSIFSSEL_36 |
0586                 OPORTMXCTR2_DACCKSEL_1_2;
0587         }
0588         regmap_write(r, OPORTMXCTR2(sub->swm->oport.map), v);
0589     } else {
0590         v = IPORTMXCTR2_ACLKSEL_A1 |
0591             IPORTMXCTR2_MSSEL_SLAVE |
0592             IPORTMXCTR2_EXTLSIFSSEL_36 |
0593             IPORTMXCTR2_DACCKSEL_1_2;
0594         regmap_write(r, IPORTMXCTR2(sub->swm->iport.map), v);
0595     }
0596 
0597     return 0;
0598 }
0599 
0600 /**
0601  * aio_port_set_param - set parameters of AIO port block
0602  * @sub: the AIO substream pointer
0603  * @pass_through: Zero if sound data is LPCM, otherwise if data is not LPCM.
0604  * This parameter has no effect if substream is I2S or PCM.
0605  * @params: hardware parameters of ALSA
0606  *
0607  * Set suitable setting to input/output port block of AIO to process the
0608  * specified in params.
0609  *
0610  * Return: Zero if successful, otherwise a negative value on error.
0611  */
0612 int aio_port_set_param(struct uniphier_aio_sub *sub, int pass_through,
0613                const struct snd_pcm_hw_params *params)
0614 {
0615     struct regmap *r = sub->aio->chip->regmap;
0616     unsigned int rate;
0617     u32 v;
0618     int ret;
0619 
0620     if (!pass_through) {
0621         if (sub->swm->type == PORT_TYPE_EVE ||
0622             sub->swm->type == PORT_TYPE_CONV) {
0623             rate = 48000;
0624         } else {
0625             rate = params_rate(params);
0626         }
0627 
0628         ret = aio_port_set_ch(sub);
0629         if (ret)
0630             return ret;
0631 
0632         ret = aio_port_set_rate(sub, rate);
0633         if (ret)
0634             return ret;
0635 
0636         ret = aio_port_set_fmt(sub);
0637         if (ret)
0638             return ret;
0639     }
0640 
0641     ret = aio_port_set_clk(sub);
0642     if (ret)
0643         return ret;
0644 
0645     if (sub->swm->dir == PORT_DIR_OUTPUT) {
0646         if (pass_through)
0647             v = OPORTMXCTR3_SRCSEL_STREAM |
0648                 OPORTMXCTR3_VALID_STREAM;
0649         else
0650             v = OPORTMXCTR3_SRCSEL_PCM |
0651                 OPORTMXCTR3_VALID_PCM;
0652 
0653         v |= OPORTMXCTR3_IECTHUR_IECOUT |
0654             OPORTMXCTR3_PMSEL_PAUSE |
0655             OPORTMXCTR3_PMSW_MUTE_OFF;
0656         regmap_write(r, OPORTMXCTR3(sub->swm->oport.map), v);
0657     } else {
0658         regmap_write(r, IPORTMXACLKSEL0EX(sub->swm->iport.map),
0659                  IPORTMXACLKSEL0EX_ACLKSEL0EX_INTERNAL);
0660         regmap_write(r, IPORTMXEXNOE(sub->swm->iport.map),
0661                  IPORTMXEXNOE_PCMINOE_INPUT);
0662     }
0663 
0664     return 0;
0665 }
0666 
0667 /**
0668  * aio_port_set_enable - start or stop of AIO port block
0669  * @sub: the AIO substream pointer
0670  * @enable: zero to stop the block, otherwise to start
0671  *
0672  * Start or stop the signal input/output port block of AIO.
0673  */
0674 void aio_port_set_enable(struct uniphier_aio_sub *sub, int enable)
0675 {
0676     struct regmap *r = sub->aio->chip->regmap;
0677 
0678     if (sub->swm->dir == PORT_DIR_OUTPUT) {
0679         regmap_write(r, OPORTMXPATH(sub->swm->oport.map),
0680                  sub->swm->oif.map);
0681 
0682         regmap_update_bits(r, OPORTMXMASK(sub->swm->oport.map),
0683                    OPORTMXMASK_IUDXMSK_MASK |
0684                    OPORTMXMASK_IUXCKMSK_MASK |
0685                    OPORTMXMASK_DXMSK_MASK |
0686                    OPORTMXMASK_XCKMSK_MASK,
0687                    OPORTMXMASK_IUDXMSK_OFF |
0688                    OPORTMXMASK_IUXCKMSK_OFF |
0689                    OPORTMXMASK_DXMSK_OFF |
0690                    OPORTMXMASK_XCKMSK_OFF);
0691 
0692         if (enable)
0693             regmap_write(r, AOUTENCTR0, BIT(sub->swm->oport.map));
0694         else
0695             regmap_write(r, AOUTENCTR1, BIT(sub->swm->oport.map));
0696     } else {
0697         regmap_update_bits(r, IPORTMXMASK(sub->swm->iport.map),
0698                    IPORTMXMASK_IUXCKMSK_MASK |
0699                    IPORTMXMASK_XCKMSK_MASK,
0700                    IPORTMXMASK_IUXCKMSK_OFF |
0701                    IPORTMXMASK_XCKMSK_OFF);
0702 
0703         if (enable)
0704             regmap_update_bits(r,
0705                        IPORTMXCTR2(sub->swm->iport.map),
0706                        IPORTMXCTR2_REQEN_MASK,
0707                        IPORTMXCTR2_REQEN_ENABLE);
0708         else
0709             regmap_update_bits(r,
0710                        IPORTMXCTR2(sub->swm->iport.map),
0711                        IPORTMXCTR2_REQEN_MASK,
0712                        IPORTMXCTR2_REQEN_DISABLE);
0713     }
0714 }
0715 
0716 /**
0717  * aio_port_get_volume - get volume of AIO port block
0718  * @sub: the AIO substream pointer
0719  *
0720  * Return: current volume, range is 0x0000 - 0xffff
0721  */
0722 int aio_port_get_volume(struct uniphier_aio_sub *sub)
0723 {
0724     struct regmap *r = sub->aio->chip->regmap;
0725     u32 v;
0726 
0727     regmap_read(r, OPORTMXTYVOLGAINSTATUS(sub->swm->oport.map, 0), &v);
0728 
0729     return FIELD_GET(OPORTMXTYVOLGAINSTATUS_CUR_MASK, v);
0730 }
0731 
0732 /**
0733  * aio_port_set_volume - set volume of AIO port block
0734  * @sub: the AIO substream pointer
0735  * @vol: target volume, range is 0x0000 - 0xffff.
0736  *
0737  * Change digital volume and perfome fade-out/fade-in effect for specified
0738  * output slot of port. Gained PCM value can calculate as the following:
0739  *   Gained = Original * vol / 0x4000
0740  */
0741 void aio_port_set_volume(struct uniphier_aio_sub *sub, int vol)
0742 {
0743     struct regmap *r = sub->aio->chip->regmap;
0744     int oport_map = sub->swm->oport.map;
0745     int cur, diff, slope = 0, fs;
0746 
0747     if (sub->swm->dir == PORT_DIR_INPUT)
0748         return;
0749 
0750     cur = aio_port_get_volume(sub);
0751     diff = abs(vol - cur);
0752     fs = params_rate(&sub->params);
0753     if (fs)
0754         slope = diff / AUD_VOL_FADE_TIME * 1000 / fs;
0755     slope = max(1, slope);
0756 
0757     regmap_update_bits(r, OPORTMXTYVOLPARA1(oport_map, 0),
0758                OPORTMXTYVOLPARA1_SLOPEU_MASK, slope << 16);
0759     regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
0760                OPORTMXTYVOLPARA2_TARGET_MASK, vol);
0761 
0762     if (cur < vol)
0763         regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
0764                    OPORTMXTYVOLPARA2_FADE_MASK,
0765                    OPORTMXTYVOLPARA2_FADE_FADEIN);
0766     else
0767         regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
0768                    OPORTMXTYVOLPARA2_FADE_MASK,
0769                    OPORTMXTYVOLPARA2_FADE_FADEOUT);
0770 
0771     regmap_write(r, AOUTFADECTR0, BIT(oport_map));
0772 }
0773 
0774 /**
0775  * aio_if_set_param - set parameters of AIO DMA I/F block
0776  * @sub: the AIO substream pointer
0777  * @pass_through: Zero if sound data is LPCM, otherwise if data is not LPCM.
0778  * This parameter has no effect if substream is I2S or PCM.
0779  *
0780  * Set suitable setting to DMA interface block of AIO to process the
0781  * specified in settings.
0782  *
0783  * Return: Zero if successful, otherwise a negative value on error.
0784  */
0785 int aio_if_set_param(struct uniphier_aio_sub *sub, int pass_through)
0786 {
0787     struct regmap *r = sub->aio->chip->regmap;
0788     u32 memfmt, v;
0789 
0790     if (sub->swm->dir == PORT_DIR_OUTPUT) {
0791         if (pass_through) {
0792             v = PBOUTMXCTR0_ENDIAN_0123 |
0793                 PBOUTMXCTR0_MEMFMT_STREAM;
0794         } else {
0795             switch (params_channels(&sub->params)) {
0796             case 2:
0797                 memfmt = PBOUTMXCTR0_MEMFMT_2CH;
0798                 break;
0799             case 6:
0800                 memfmt = PBOUTMXCTR0_MEMFMT_6CH;
0801                 break;
0802             case 8:
0803                 memfmt = PBOUTMXCTR0_MEMFMT_8CH;
0804                 break;
0805             default:
0806                 return -EINVAL;
0807             }
0808             v = PBOUTMXCTR0_ENDIAN_3210 | memfmt;
0809         }
0810 
0811         regmap_write(r, PBOUTMXCTR0(sub->swm->oif.map), v);
0812         regmap_write(r, PBOUTMXCTR1(sub->swm->oif.map), 0);
0813     } else {
0814         regmap_write(r, PBINMXCTR(sub->swm->iif.map),
0815                  PBINMXCTR_NCONNECT_CONNECT |
0816                  PBINMXCTR_INOUTSEL_IN |
0817                  (sub->swm->iport.map << PBINMXCTR_PBINSEL_SHIFT) |
0818                  PBINMXCTR_ENDIAN_3210 |
0819                  PBINMXCTR_MEMFMT_D0);
0820     }
0821 
0822     return 0;
0823 }
0824 
0825 /**
0826  * aio_oport_set_stream_type - set parameters of AIO playback port block
0827  * @sub: the AIO substream pointer
0828  * @pc: Pc type of IEC61937
0829  *
0830  * Set special setting to output port block of AIO to output the stream
0831  * via S/PDIF.
0832  *
0833  * Return: Zero if successful, otherwise a negative value on error.
0834  */
0835 int aio_oport_set_stream_type(struct uniphier_aio_sub *sub,
0836                   enum IEC61937_PC pc)
0837 {
0838     struct regmap *r = sub->aio->chip->regmap;
0839     u32 repet = 0, pause = OPORTMXPAUDAT_PAUSEPC_CMN;
0840 
0841     switch (pc) {
0842     case IEC61937_PC_AC3:
0843         repet = OPORTMXREPET_STRLENGTH_AC3 |
0844             OPORTMXREPET_PMLENGTH_AC3;
0845         pause |= OPORTMXPAUDAT_PAUSEPD_AC3;
0846         break;
0847     case IEC61937_PC_MPA:
0848         repet = OPORTMXREPET_STRLENGTH_MPA |
0849             OPORTMXREPET_PMLENGTH_MPA;
0850         pause |= OPORTMXPAUDAT_PAUSEPD_MPA;
0851         break;
0852     case IEC61937_PC_MP3:
0853         repet = OPORTMXREPET_STRLENGTH_MP3 |
0854             OPORTMXREPET_PMLENGTH_MP3;
0855         pause |= OPORTMXPAUDAT_PAUSEPD_MP3;
0856         break;
0857     case IEC61937_PC_DTS1:
0858         repet = OPORTMXREPET_STRLENGTH_DTS1 |
0859             OPORTMXREPET_PMLENGTH_DTS1;
0860         pause |= OPORTMXPAUDAT_PAUSEPD_DTS1;
0861         break;
0862     case IEC61937_PC_DTS2:
0863         repet = OPORTMXREPET_STRLENGTH_DTS2 |
0864             OPORTMXREPET_PMLENGTH_DTS2;
0865         pause |= OPORTMXPAUDAT_PAUSEPD_DTS2;
0866         break;
0867     case IEC61937_PC_DTS3:
0868         repet = OPORTMXREPET_STRLENGTH_DTS3 |
0869             OPORTMXREPET_PMLENGTH_DTS3;
0870         pause |= OPORTMXPAUDAT_PAUSEPD_DTS3;
0871         break;
0872     case IEC61937_PC_AAC:
0873         repet = OPORTMXREPET_STRLENGTH_AAC |
0874             OPORTMXREPET_PMLENGTH_AAC;
0875         pause |= OPORTMXPAUDAT_PAUSEPD_AAC;
0876         break;
0877     case IEC61937_PC_PAUSE:
0878         /* Do nothing */
0879         break;
0880     }
0881 
0882     regmap_write(r, OPORTMXREPET(sub->swm->oport.map), repet);
0883     regmap_write(r, OPORTMXPAUDAT(sub->swm->oport.map), pause);
0884 
0885     return 0;
0886 }
0887 
0888 /**
0889  * aio_src_reset - reset AIO SRC block
0890  * @sub: the AIO substream pointer
0891  *
0892  * Resets the digital signal input/output port with sampling rate converter
0893  * block of AIO.
0894  * This function has no effect if substream is not supported rate converter.
0895  */
0896 void aio_src_reset(struct uniphier_aio_sub *sub)
0897 {
0898     struct regmap *r = sub->aio->chip->regmap;
0899 
0900     if (sub->swm->dir != PORT_DIR_OUTPUT)
0901         return;
0902 
0903     regmap_write(r, AOUTSRCRSTCTR0, BIT(sub->swm->oport.map));
0904     regmap_write(r, AOUTSRCRSTCTR1, BIT(sub->swm->oport.map));
0905 }
0906 
0907 /**
0908  * aio_src_set_param - set parameters of AIO SRC block
0909  * @sub: the AIO substream pointer
0910  * @params: hardware parameters of ALSA
0911  *
0912  * Set suitable setting to input/output port with sampling rate converter
0913  * block of AIO to process the specified in params.
0914  * This function has no effect if substream is not supported rate converter.
0915  *
0916  * Return: Zero if successful, otherwise a negative value on error.
0917  */
0918 int aio_src_set_param(struct uniphier_aio_sub *sub,
0919               const struct snd_pcm_hw_params *params)
0920 {
0921     struct regmap *r = sub->aio->chip->regmap;
0922     u32 v;
0923 
0924     if (sub->swm->dir != PORT_DIR_OUTPUT)
0925         return 0;
0926 
0927     regmap_write(r, OPORTMXSRC1CTR(sub->swm->oport.map),
0928              OPORTMXSRC1CTR_THMODE_SRC |
0929              OPORTMXSRC1CTR_SRCPATH_CALC |
0930              OPORTMXSRC1CTR_SYNC_ASYNC |
0931              OPORTMXSRC1CTR_FSIIPSEL_INNER |
0932              OPORTMXSRC1CTR_FSISEL_ACLK);
0933 
0934     switch (params_rate(params)) {
0935     default:
0936     case 48000:
0937         v = OPORTMXRATE_I_ACLKSEL_APLLA1 |
0938             OPORTMXRATE_I_MCKSEL_36 |
0939             OPORTMXRATE_I_FSSEL_48;
0940         break;
0941     case 44100:
0942         v = OPORTMXRATE_I_ACLKSEL_APLLA2 |
0943             OPORTMXRATE_I_MCKSEL_33 |
0944             OPORTMXRATE_I_FSSEL_44_1;
0945         break;
0946     case 32000:
0947         v = OPORTMXRATE_I_ACLKSEL_APLLA1 |
0948             OPORTMXRATE_I_MCKSEL_36 |
0949             OPORTMXRATE_I_FSSEL_32;
0950         break;
0951     }
0952 
0953     regmap_write(r, OPORTMXRATE_I(sub->swm->oport.map),
0954              v | OPORTMXRATE_I_ACLKSRC_APLL |
0955              OPORTMXRATE_I_LRCKSTP_STOP);
0956     regmap_update_bits(r, OPORTMXRATE_I(sub->swm->oport.map),
0957                OPORTMXRATE_I_LRCKSTP_MASK,
0958                OPORTMXRATE_I_LRCKSTP_START);
0959 
0960     return 0;
0961 }
0962 
0963 int aio_srcif_set_param(struct uniphier_aio_sub *sub)
0964 {
0965     struct regmap *r = sub->aio->chip->regmap;
0966 
0967     regmap_write(r, PBINMXCTR(sub->swm->iif.map),
0968              PBINMXCTR_NCONNECT_CONNECT |
0969              PBINMXCTR_INOUTSEL_OUT |
0970              (sub->swm->oport.map << PBINMXCTR_PBINSEL_SHIFT) |
0971              PBINMXCTR_ENDIAN_3210 |
0972              PBINMXCTR_MEMFMT_D0);
0973 
0974     return 0;
0975 }
0976 
0977 int aio_srcch_set_param(struct uniphier_aio_sub *sub)
0978 {
0979     struct regmap *r = sub->aio->chip->regmap;
0980 
0981     regmap_write(r, CDA2D_CHMXCTRL1(sub->swm->och.map),
0982              CDA2D_CHMXCTRL1_INDSIZE_INFINITE);
0983 
0984     regmap_write(r, CDA2D_CHMXSRCAMODE(sub->swm->och.map),
0985              CDA2D_CHMXAMODE_ENDIAN_3210 |
0986              CDA2D_CHMXAMODE_AUPDT_FIX |
0987              CDA2D_CHMXAMODE_TYPE_NORMAL);
0988 
0989     regmap_write(r, CDA2D_CHMXDSTAMODE(sub->swm->och.map),
0990              CDA2D_CHMXAMODE_ENDIAN_3210 |
0991              CDA2D_CHMXAMODE_AUPDT_INC |
0992              CDA2D_CHMXAMODE_TYPE_RING |
0993              (sub->swm->och.map << CDA2D_CHMXAMODE_RSSEL_SHIFT));
0994 
0995     return 0;
0996 }
0997 
0998 void aio_srcch_set_enable(struct uniphier_aio_sub *sub, int enable)
0999 {
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 
1012 int 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 
1032 void 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 
1053 static 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 
1072 static 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 
1086 static 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 
1105 static 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 
1121 int 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 
1134 int 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 
1187 void 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 
1227 bool 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 
1240 void 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 }