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