~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/uniphier/aio-core.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php