1*7eff0e4eSkn /* $OpenBSD: rkiis.c,v 1.4 2022/10/28 15:09:45 kn Exp $ */
243e4a63dSpatrick /* $NetBSD: rk_i2s.c,v 1.3 2020/02/29 05:51:10 isaki Exp $ */
343e4a63dSpatrick /*-
443e4a63dSpatrick * Copyright (c) 2019 Jared McNeill <jmcneill@invisible.ca>
543e4a63dSpatrick * All rights reserved.
643e4a63dSpatrick *
743e4a63dSpatrick * Redistribution and use in source and binary forms, with or without
843e4a63dSpatrick * modification, are permitted provided that the following conditions
943e4a63dSpatrick * are met:
1043e4a63dSpatrick * 1. Redistributions of source code must retain the above copyright
1143e4a63dSpatrick * notice, this list of conditions and the following disclaimer.
1243e4a63dSpatrick * 2. Redistributions in binary form must reproduce the above copyright
1343e4a63dSpatrick * notice, this list of conditions and the following disclaimer in the
1443e4a63dSpatrick * documentation and/or other materials provided with the distribution.
1543e4a63dSpatrick *
1643e4a63dSpatrick * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1743e4a63dSpatrick * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1843e4a63dSpatrick * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1943e4a63dSpatrick * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2043e4a63dSpatrick * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2143e4a63dSpatrick * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2243e4a63dSpatrick * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2343e4a63dSpatrick * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2443e4a63dSpatrick * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2543e4a63dSpatrick * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2643e4a63dSpatrick * SUCH DAMAGE.
2743e4a63dSpatrick */
2843e4a63dSpatrick
2943e4a63dSpatrick #include <sys/param.h>
3043e4a63dSpatrick #include <sys/systm.h>
3143e4a63dSpatrick #include <sys/device.h>
3243e4a63dSpatrick #include <sys/malloc.h>
33*7eff0e4eSkn #include <sys/fcntl.h>
3443e4a63dSpatrick
3543e4a63dSpatrick #include <machine/intr.h>
3643e4a63dSpatrick #include <machine/bus.h>
3743e4a63dSpatrick #include <machine/fdt.h>
3843e4a63dSpatrick
3943e4a63dSpatrick #include <dev/ofw/openfirm.h>
4043e4a63dSpatrick #include <dev/ofw/ofw_clock.h>
4143e4a63dSpatrick #include <dev/ofw/ofw_misc.h>
4243e4a63dSpatrick #include <dev/ofw/ofw_pinctrl.h>
4343e4a63dSpatrick #include <dev/ofw/fdt.h>
4443e4a63dSpatrick
4543e4a63dSpatrick #include <sys/audioio.h>
4643e4a63dSpatrick #include <dev/audio_if.h>
4743e4a63dSpatrick #include <dev/midi_if.h>
4843e4a63dSpatrick
4943e4a63dSpatrick #define RK_I2S_FIFO_DEPTH 32
5043e4a63dSpatrick #define RK_I2S_SAMPLE_RATE 48000
5143e4a63dSpatrick
5243e4a63dSpatrick #define I2S_TXCR 0x00
5343e4a63dSpatrick #define TXCR_RCNT_MASK (0x3f << 17)
5443e4a63dSpatrick #define TXCR_RCNT_SHIFT 17
5543e4a63dSpatrick #define TXCR_TCSR_MASK (0x3 << 15)
5643e4a63dSpatrick #define TXCR_TCSR_SHIFT 15
5743e4a63dSpatrick #define TXCR_HWT (1 << 14)
5843e4a63dSpatrick #define TXCR_SJM (1 << 12)
5943e4a63dSpatrick #define TXCR_FBM (1 << 11)
6043e4a63dSpatrick #define TXCR_IBM_MASK (0x3 << 9)
6143e4a63dSpatrick #define TXCR_IBM_SHIFT 9
6243e4a63dSpatrick #define TXCR_PBM_MASK (0x3 << 7)
6343e4a63dSpatrick #define TXCR_PBM_SHIFT 7
6443e4a63dSpatrick #define TXCR_TFS (1 << 5)
6543e4a63dSpatrick #define TXCR_VDW_MASK (0x1f << 0)
6643e4a63dSpatrick #define TXCR_VDW_SHIFT 0
6743e4a63dSpatrick #define I2S_RXCR 0x04
6843e4a63dSpatrick #define RXCR_RCSR_MASK (0x3 << 15)
6943e4a63dSpatrick #define RXCR_RCSR_SHIFT 15
7043e4a63dSpatrick #define RXCR_HWT (1 << 14)
7143e4a63dSpatrick #define RXCR_SJM (1 << 12)
7243e4a63dSpatrick #define RXCR_FBM (1 << 11)
7343e4a63dSpatrick #define RXCR_IBM_MASK (0x3 << 9)
7443e4a63dSpatrick #define RXCR_IBM_SHIFT 9
7543e4a63dSpatrick #define RXCR_PBM_MASK (0x3 << 7)
7643e4a63dSpatrick #define RXCR_PBM_SHIFT 7
7743e4a63dSpatrick #define RXCR_TFS (1 << 5)
7843e4a63dSpatrick #define RXCR_VDW_MASK (0x1f << 0)
7943e4a63dSpatrick #define RXCR_VDW_SHIFT 0
8043e4a63dSpatrick #define I2S_CKR 0x08
8143e4a63dSpatrick #define CKR_TRCM_MASK (0x3 << 28)
8243e4a63dSpatrick #define CKR_TRCM_SHIFT 28
8343e4a63dSpatrick #define CKR_MSS (1 << 27)
8443e4a63dSpatrick #define CKR_CKP (1 << 26)
8543e4a63dSpatrick #define CKR_RLP (1 << 25)
8643e4a63dSpatrick #define CKR_TLP (1 << 24)
8743e4a63dSpatrick #define CKR_MDIV_MASK (0xff << 16)
8843e4a63dSpatrick #define CKR_MDIV_SHIFT 16
8943e4a63dSpatrick #define CKR_RSD_MASK (0xff << 8)
9043e4a63dSpatrick #define CKR_RSD_SHIFT 8
9143e4a63dSpatrick #define CKR_TSD_MASK (0xff << 0)
9243e4a63dSpatrick #define CKR_TSD_SHIFT 0
9343e4a63dSpatrick #define I2S_TXFIFOLR 0x0c
9443e4a63dSpatrick #define TXFIFOLR_TFL_MASK(n) (0x3f << ((n) * 6))
9543e4a63dSpatrick #define TXFIFOLR_TFL_SHIFT(n) ((n) * 6)
9643e4a63dSpatrick #define I2S_DMACR 0x10
9743e4a63dSpatrick #define DMACR_RDE (1 << 24)
9843e4a63dSpatrick #define DMACR_RDL_MASK (0x1f << 16)
9943e4a63dSpatrick #define DMACR_RDL_SHIFT 16
10043e4a63dSpatrick #define DMACR_TDE (1 << 8)
10143e4a63dSpatrick #define DMACR_TDL_MASK (0x1f << 0)
10243e4a63dSpatrick #define DMACR_TDL_SHIFT 0
10343e4a63dSpatrick #define I2S_INTCR 0x14
10443e4a63dSpatrick #define INTCR_RFT_MASK (0x1f << 20)
10543e4a63dSpatrick #define INTCR_RFT_SHIFT 20
10643e4a63dSpatrick #define INTCR_RXOIC (1 << 18)
10743e4a63dSpatrick #define INTCR_RXOIE (1 << 17)
10843e4a63dSpatrick #define INTCR_RXFIE (1 << 16)
10943e4a63dSpatrick #define INTCR_TFT_MASK (0x1f << 4)
11043e4a63dSpatrick #define INTCR_TFT_SHIFT 4
11143e4a63dSpatrick #define INTCR_TXUIC (1 << 2)
11243e4a63dSpatrick #define INTCR_TXUIE (1 << 1)
11343e4a63dSpatrick #define INTCR_TXEIE (1 << 0)
11443e4a63dSpatrick #define I2S_INTSR 0x18
11543e4a63dSpatrick #define INTSR_RXOI (1 << 17)
11643e4a63dSpatrick #define INTSR_RXFI (1 << 16)
11743e4a63dSpatrick #define INTSR_TXUI (1 << 1)
11843e4a63dSpatrick #define INTSR_TXEI (1 << 0)
11943e4a63dSpatrick #define I2S_XFER 0x1c
12043e4a63dSpatrick #define XFER_RXS (1 << 1)
12143e4a63dSpatrick #define XFER_TXS (1 << 0)
12243e4a63dSpatrick #define I2S_CLR 0x20
12343e4a63dSpatrick #define CLR_RXC (1 << 1)
12443e4a63dSpatrick #define CLR_TXC (1 << 0)
12543e4a63dSpatrick #define I2S_TXDR 0x24
12643e4a63dSpatrick #define I2S_RXDR 0x28
12743e4a63dSpatrick #define I2S_RXFIFOLR 0x2c
12843e4a63dSpatrick #define RXFIFOLR_RFL_MASK(n) (0x3f << ((n) * 6))
12943e4a63dSpatrick #define RXFIFOLR_RFL_SHIFT(n) ((n) * 6)
13043e4a63dSpatrick
13143e4a63dSpatrick #define HREAD4(sc, reg) \
13243e4a63dSpatrick (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
13343e4a63dSpatrick #define HWRITE4(sc, reg, val) \
13443e4a63dSpatrick bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
13543e4a63dSpatrick #define HSET4(sc, reg, bits) \
13643e4a63dSpatrick HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
13743e4a63dSpatrick #define HCLR4(sc, reg, bits) \
13843e4a63dSpatrick HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
13943e4a63dSpatrick
14043e4a63dSpatrick int rkiis_match(struct device *, void *, void *);
14143e4a63dSpatrick void rkiis_attach(struct device *, struct device *, void *);
14243e4a63dSpatrick
14343e4a63dSpatrick int rkiis_intr(void *);
14443e4a63dSpatrick int rkiis_set_format(void *, uint32_t, uint32_t, uint32_t);
14543e4a63dSpatrick int rkiis_set_sysclk(void *, uint32_t);
14643e4a63dSpatrick
14743e4a63dSpatrick int rkiis_open(void *, int);
14843e4a63dSpatrick int rkiis_set_params(void *, int, int,
14943e4a63dSpatrick struct audio_params *, struct audio_params *);
15043e4a63dSpatrick void *rkiis_allocm(void *, int, size_t, int, int);
15143e4a63dSpatrick void rkiis_freem(void *, void *, int);
15243e4a63dSpatrick int rkiis_trigger_output(void *, void *, void *, int,
15343e4a63dSpatrick void (*)(void *), void *, struct audio_params *);
15443e4a63dSpatrick int rkiis_trigger_input(void *, void *, void *, int,
15543e4a63dSpatrick void (*)(void *), void *, struct audio_params *);
15643e4a63dSpatrick int rkiis_halt_output(void *);
15743e4a63dSpatrick int rkiis_halt_input(void *);
15843e4a63dSpatrick
15943e4a63dSpatrick struct rkiis_config {
16043e4a63dSpatrick bus_size_t oe_reg;
16143e4a63dSpatrick uint32_t oe_mask;
16243e4a63dSpatrick uint32_t oe_shift;
16343e4a63dSpatrick uint32_t oe_val;
16443e4a63dSpatrick };
16543e4a63dSpatrick
16643e4a63dSpatrick struct rkiis_config rk3399_i2s_config = {
16743e4a63dSpatrick .oe_reg = 0xe220,
16843e4a63dSpatrick .oe_mask = 0x7,
16943e4a63dSpatrick .oe_shift = 11,
17043e4a63dSpatrick .oe_val = 0x7,
17143e4a63dSpatrick };
17243e4a63dSpatrick
17343e4a63dSpatrick struct rkiis_chan {
17443e4a63dSpatrick uint32_t *ch_start;
17543e4a63dSpatrick uint32_t *ch_end;
17643e4a63dSpatrick uint32_t *ch_cur;
17743e4a63dSpatrick
17843e4a63dSpatrick int ch_blksize;
17943e4a63dSpatrick int ch_resid;
18043e4a63dSpatrick
18143e4a63dSpatrick void (*ch_intr)(void *);
18243e4a63dSpatrick void *ch_intrarg;
18343e4a63dSpatrick };
18443e4a63dSpatrick
18543e4a63dSpatrick struct rkiis_softc {
18643e4a63dSpatrick struct device sc_dev;
18743e4a63dSpatrick bus_space_tag_t sc_iot;
18843e4a63dSpatrick bus_space_handle_t sc_ioh;
18943e4a63dSpatrick void *sc_ih;
19043e4a63dSpatrick
19143e4a63dSpatrick int sc_node;
19243e4a63dSpatrick struct rkiis_config *sc_conf;
19343e4a63dSpatrick
19443e4a63dSpatrick struct rkiis_chan sc_pchan;
19543e4a63dSpatrick struct rkiis_chan sc_rchan;
19643e4a63dSpatrick
19743e4a63dSpatrick uint32_t sc_active;
19843e4a63dSpatrick
19943e4a63dSpatrick struct dai_device sc_dai;
20043e4a63dSpatrick };
20143e4a63dSpatrick
2020d6a2fdeSmiod const struct audio_hw_if rkiis_hw_if = {
203*7eff0e4eSkn .open = rkiis_open,
20443e4a63dSpatrick .set_params = rkiis_set_params,
20543e4a63dSpatrick .allocm = rkiis_allocm,
20643e4a63dSpatrick .freem = rkiis_freem,
20743e4a63dSpatrick .trigger_output = rkiis_trigger_output,
20843e4a63dSpatrick .trigger_input = rkiis_trigger_input,
20943e4a63dSpatrick .halt_output = rkiis_halt_output,
21043e4a63dSpatrick .halt_input = rkiis_halt_input,
21143e4a63dSpatrick };
21243e4a63dSpatrick
213471aeecfSnaddy const struct cfattach rkiis_ca = {
21443e4a63dSpatrick sizeof (struct rkiis_softc), rkiis_match, rkiis_attach
21543e4a63dSpatrick };
21643e4a63dSpatrick
21743e4a63dSpatrick struct cfdriver rkiis_cd = {
21843e4a63dSpatrick NULL, "rkiis", DV_DULL
21943e4a63dSpatrick };
22043e4a63dSpatrick
22143e4a63dSpatrick int
rkiis_match(struct device * parent,void * match,void * aux)22243e4a63dSpatrick rkiis_match(struct device *parent, void *match, void *aux)
22343e4a63dSpatrick {
22443e4a63dSpatrick struct fdt_attach_args *faa = aux;
22543e4a63dSpatrick
22643e4a63dSpatrick return OF_is_compatible(faa->fa_node, "rockchip,rk3399-i2s");
22743e4a63dSpatrick }
22843e4a63dSpatrick
22943e4a63dSpatrick void
rkiis_attach(struct device * parent,struct device * self,void * aux)23043e4a63dSpatrick rkiis_attach(struct device *parent, struct device *self, void *aux)
23143e4a63dSpatrick {
23243e4a63dSpatrick struct rkiis_softc *sc = (struct rkiis_softc *)self;
23343e4a63dSpatrick struct fdt_attach_args *faa = aux;
23443e4a63dSpatrick struct regmap *rm;
23543e4a63dSpatrick uint32_t grf, val;
23643e4a63dSpatrick
23743e4a63dSpatrick if (faa->fa_nreg < 1) {
23843e4a63dSpatrick printf(": no registers\n");
23943e4a63dSpatrick return;
24043e4a63dSpatrick }
24143e4a63dSpatrick
24243e4a63dSpatrick sc->sc_iot = faa->fa_iot;
24343e4a63dSpatrick sc->sc_node = faa->fa_node;
24443e4a63dSpatrick sc->sc_conf = &rk3399_i2s_config;
24543e4a63dSpatrick
24643e4a63dSpatrick if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
24743e4a63dSpatrick faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
24843e4a63dSpatrick printf(": can't map registers\n");
24943e4a63dSpatrick return;
25043e4a63dSpatrick }
25143e4a63dSpatrick
25243e4a63dSpatrick pinctrl_byname(sc->sc_node, "default");
25343e4a63dSpatrick clock_enable_all(sc->sc_node);
25443e4a63dSpatrick
25543e4a63dSpatrick grf = OF_getpropint(sc->sc_node, "rockchip,grf", 0);
25643e4a63dSpatrick rm = regmap_byphandle(grf);
25743e4a63dSpatrick if (rm && sc->sc_conf->oe_mask) {
25843e4a63dSpatrick val = sc->sc_conf->oe_val << sc->sc_conf->oe_shift;
25943e4a63dSpatrick val |= (sc->sc_conf->oe_mask << sc->sc_conf->oe_shift) << 16;
26043e4a63dSpatrick regmap_write_4(rm, sc->sc_conf->oe_reg, val);
26143e4a63dSpatrick }
26243e4a63dSpatrick
26343e4a63dSpatrick sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_AUDIO | IPL_MPSAFE,
26443e4a63dSpatrick rkiis_intr, sc, sc->sc_dev.dv_xname);
26543e4a63dSpatrick if (sc->sc_ih == NULL) {
26643e4a63dSpatrick printf(": can't establish interrupt\n");
26743e4a63dSpatrick goto unmap;
26843e4a63dSpatrick }
26943e4a63dSpatrick
27043e4a63dSpatrick printf("\n");
27143e4a63dSpatrick
27243e4a63dSpatrick sc->sc_dai.dd_node = faa->fa_node;
27343e4a63dSpatrick sc->sc_dai.dd_cookie = sc;
27443e4a63dSpatrick sc->sc_dai.dd_hw_if = &rkiis_hw_if;
27543e4a63dSpatrick sc->sc_dai.dd_set_format = rkiis_set_format;
27643e4a63dSpatrick sc->sc_dai.dd_set_sysclk = rkiis_set_sysclk;
27743e4a63dSpatrick dai_register(&sc->sc_dai);
27843e4a63dSpatrick return;
27943e4a63dSpatrick
28043e4a63dSpatrick unmap:
28143e4a63dSpatrick bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size);
28243e4a63dSpatrick }
28343e4a63dSpatrick
28443e4a63dSpatrick int
rkiis_intr(void * cookie)28543e4a63dSpatrick rkiis_intr(void *cookie)
28643e4a63dSpatrick {
28743e4a63dSpatrick struct rkiis_softc *sc = cookie;
28843e4a63dSpatrick struct rkiis_chan *pch = &sc->sc_pchan;
28943e4a63dSpatrick #if notyet
29043e4a63dSpatrick struct rkiis_chan *rch = &sc->sc_rchan;
29143e4a63dSpatrick #endif
29243e4a63dSpatrick uint32_t sr, val;
29343e4a63dSpatrick int fifolr;
29443e4a63dSpatrick
29543e4a63dSpatrick mtx_enter(&audio_lock);
29643e4a63dSpatrick
29743e4a63dSpatrick sr = HREAD4(sc, I2S_INTSR);
29843e4a63dSpatrick
29943e4a63dSpatrick if ((sr & INTSR_RXFI) != 0) {
30043e4a63dSpatrick #if notyet
30143e4a63dSpatrick val = HREAD4(sc, I2S_RXFIFOLR);
30243e4a63dSpatrick fifolr = val & RXFIFOLR_RFL_MASK(0);
30343e4a63dSpatrick fifolr >>= RXFIFOLR_RFL_SHIFT(0);
30443e4a63dSpatrick while (fifolr > 0) {
30543e4a63dSpatrick *rch->ch_data = HREAD4(sc, I2S_RXDR);
30643e4a63dSpatrick rch->ch_data++;
30743e4a63dSpatrick rch->ch_resid -= 4;
30843e4a63dSpatrick if (rch->ch_resid == 0)
30943e4a63dSpatrick rch->ch_intr(rch->ch_intrarg);
31043e4a63dSpatrick --fifolr;
31143e4a63dSpatrick }
31243e4a63dSpatrick #endif
31343e4a63dSpatrick }
31443e4a63dSpatrick
31543e4a63dSpatrick if ((sr & INTSR_TXEI) != 0) {
31643e4a63dSpatrick val = HREAD4(sc, I2S_TXFIFOLR);
31743e4a63dSpatrick fifolr = val & TXFIFOLR_TFL_MASK(0);
31843e4a63dSpatrick fifolr >>= TXFIFOLR_TFL_SHIFT(0);
31943e4a63dSpatrick fifolr = min(fifolr, RK_I2S_FIFO_DEPTH);
32043e4a63dSpatrick while (fifolr < RK_I2S_FIFO_DEPTH - 1) {
32143e4a63dSpatrick HWRITE4(sc, I2S_TXDR, *pch->ch_cur);
32243e4a63dSpatrick pch->ch_cur++;
32343e4a63dSpatrick if (pch->ch_cur == pch->ch_end)
32443e4a63dSpatrick pch->ch_cur = pch->ch_start;
32543e4a63dSpatrick pch->ch_resid -= 4;
32643e4a63dSpatrick if (pch->ch_resid == 0) {
32743e4a63dSpatrick pch->ch_intr(pch->ch_intrarg);
32843e4a63dSpatrick pch->ch_resid = pch->ch_blksize;
32943e4a63dSpatrick }
33043e4a63dSpatrick ++fifolr;
33143e4a63dSpatrick }
33243e4a63dSpatrick }
33343e4a63dSpatrick
33443e4a63dSpatrick mtx_leave(&audio_lock);
33543e4a63dSpatrick
33643e4a63dSpatrick return 1;
33743e4a63dSpatrick }
33843e4a63dSpatrick
33943e4a63dSpatrick int
rkiis_set_format(void * cookie,uint32_t fmt,uint32_t pol,uint32_t clk)34043e4a63dSpatrick rkiis_set_format(void *cookie, uint32_t fmt, uint32_t pol,
34143e4a63dSpatrick uint32_t clk)
34243e4a63dSpatrick {
34343e4a63dSpatrick struct rkiis_softc *sc = cookie;
34443e4a63dSpatrick uint32_t txcr, rxcr, ckr;
34543e4a63dSpatrick
34643e4a63dSpatrick txcr = HREAD4(sc, I2S_TXCR);
34743e4a63dSpatrick rxcr = HREAD4(sc, I2S_RXCR);
34843e4a63dSpatrick ckr = HREAD4(sc, I2S_CKR);
34943e4a63dSpatrick
35043e4a63dSpatrick txcr &= ~(TXCR_IBM_MASK|TXCR_PBM_MASK|TXCR_TFS);
35143e4a63dSpatrick rxcr &= ~(RXCR_IBM_MASK|RXCR_PBM_MASK|RXCR_TFS);
35243e4a63dSpatrick switch (fmt) {
35343e4a63dSpatrick case DAI_FORMAT_I2S:
35443e4a63dSpatrick txcr |= 0 << TXCR_IBM_SHIFT;
35543e4a63dSpatrick rxcr |= 0 << RXCR_IBM_SHIFT;
35643e4a63dSpatrick break;
35743e4a63dSpatrick case DAI_FORMAT_LJ:
35843e4a63dSpatrick txcr |= 1 << TXCR_IBM_SHIFT;
35943e4a63dSpatrick rxcr |= 1 << RXCR_IBM_SHIFT;
36043e4a63dSpatrick break;
36143e4a63dSpatrick case DAI_FORMAT_RJ:
36243e4a63dSpatrick txcr |= 2 << TXCR_IBM_SHIFT;
36343e4a63dSpatrick rxcr |= 2 << RXCR_IBM_SHIFT;
36443e4a63dSpatrick break;
36543e4a63dSpatrick case DAI_FORMAT_DSPA:
36643e4a63dSpatrick txcr |= 0 << TXCR_PBM_SHIFT;
36743e4a63dSpatrick txcr |= TXCR_TFS;
36843e4a63dSpatrick rxcr |= 0 << RXCR_PBM_SHIFT;
36943e4a63dSpatrick txcr |= RXCR_TFS;
37043e4a63dSpatrick break;
37143e4a63dSpatrick case DAI_FORMAT_DSPB:
37243e4a63dSpatrick txcr |= 1 << TXCR_PBM_SHIFT;
37343e4a63dSpatrick txcr |= TXCR_TFS;
37443e4a63dSpatrick rxcr |= 1 << RXCR_PBM_SHIFT;
37543e4a63dSpatrick txcr |= RXCR_TFS;
37643e4a63dSpatrick break;
37743e4a63dSpatrick default:
37843e4a63dSpatrick return EINVAL;
37943e4a63dSpatrick }
38043e4a63dSpatrick
38143e4a63dSpatrick HWRITE4(sc, I2S_TXCR, txcr);
38243e4a63dSpatrick HWRITE4(sc, I2S_RXCR, rxcr);
38343e4a63dSpatrick
38443e4a63dSpatrick switch (pol) {
38543e4a63dSpatrick case DAI_POLARITY_IB|DAI_POLARITY_NF:
38643e4a63dSpatrick ckr |= CKR_CKP;
38743e4a63dSpatrick break;
38843e4a63dSpatrick case DAI_POLARITY_NB|DAI_POLARITY_NF:
38943e4a63dSpatrick ckr &= ~CKR_CKP;
39043e4a63dSpatrick break;
39143e4a63dSpatrick default:
39243e4a63dSpatrick return EINVAL;
39343e4a63dSpatrick }
39443e4a63dSpatrick
39543e4a63dSpatrick switch (clk) {
39643e4a63dSpatrick case DAI_CLOCK_CBM|DAI_CLOCK_CFM:
39743e4a63dSpatrick ckr |= CKR_MSS; /* sclk input */
39843e4a63dSpatrick break;
39943e4a63dSpatrick case DAI_CLOCK_CBS|DAI_CLOCK_CFS:
40043e4a63dSpatrick ckr &= ~CKR_MSS; /* sclk output */
40143e4a63dSpatrick break;
40243e4a63dSpatrick default:
40343e4a63dSpatrick return EINVAL;
40443e4a63dSpatrick }
40543e4a63dSpatrick
40643e4a63dSpatrick HWRITE4(sc, I2S_CKR, ckr);
40743e4a63dSpatrick
40843e4a63dSpatrick return 0;
40943e4a63dSpatrick }
41043e4a63dSpatrick
41143e4a63dSpatrick int
rkiis_set_sysclk(void * cookie,uint32_t rate)41243e4a63dSpatrick rkiis_set_sysclk(void *cookie, uint32_t rate)
41343e4a63dSpatrick {
41443e4a63dSpatrick struct rkiis_softc *sc = cookie;
41543e4a63dSpatrick int error;
41643e4a63dSpatrick
41743e4a63dSpatrick error = clock_set_frequency(sc->sc_node, "i2s_clk", rate);
41843e4a63dSpatrick if (error != 0) {
41943e4a63dSpatrick printf("%s: can't set sysclk to %u Hz\n",
42043e4a63dSpatrick sc->sc_dev.dv_xname, rate);
42143e4a63dSpatrick return error;
42243e4a63dSpatrick }
42343e4a63dSpatrick
42443e4a63dSpatrick return 0;
42543e4a63dSpatrick }
42643e4a63dSpatrick
42743e4a63dSpatrick int
rkiis_open(void * cookie,int flags)428*7eff0e4eSkn rkiis_open(void *cookie, int flags)
429*7eff0e4eSkn {
430*7eff0e4eSkn if ((flags & (FWRITE | FREAD)) == (FWRITE | FREAD))
431*7eff0e4eSkn return ENXIO;
432*7eff0e4eSkn
433*7eff0e4eSkn return 0;
434*7eff0e4eSkn }
435*7eff0e4eSkn
436*7eff0e4eSkn int
rkiis_set_params(void * cookie,int setmode,int usemode,struct audio_params * play,struct audio_params * rec)43743e4a63dSpatrick rkiis_set_params(void *cookie, int setmode, int usemode,
43843e4a63dSpatrick struct audio_params *play, struct audio_params *rec)
43943e4a63dSpatrick {
44043e4a63dSpatrick struct rkiis_softc *sc = cookie;
44143e4a63dSpatrick uint32_t mclk_rate, bclk_rate;
44243e4a63dSpatrick uint32_t bclk_div, lrck_div;
44343e4a63dSpatrick uint32_t ckr, txcr, rxcr;
44443e4a63dSpatrick int i;
44543e4a63dSpatrick
44643e4a63dSpatrick ckr = HREAD4(sc, I2S_CKR);
44743e4a63dSpatrick if ((ckr & CKR_MSS) == 0) {
44843e4a63dSpatrick mclk_rate = clock_get_frequency(sc->sc_node, "i2s_clk");
44943e4a63dSpatrick bclk_rate = 2 * 32 * RK_I2S_SAMPLE_RATE;
45043e4a63dSpatrick bclk_div = mclk_rate / bclk_rate;
45143e4a63dSpatrick lrck_div = bclk_rate / RK_I2S_SAMPLE_RATE;
45243e4a63dSpatrick
45343e4a63dSpatrick ckr &= ~CKR_MDIV_MASK;
45443e4a63dSpatrick ckr |= (bclk_div - 1) << CKR_MDIV_SHIFT;
45543e4a63dSpatrick ckr &= ~CKR_TSD_MASK;
45643e4a63dSpatrick ckr |= (lrck_div - 1) << CKR_TSD_SHIFT;
45743e4a63dSpatrick ckr &= ~CKR_RSD_MASK;
45843e4a63dSpatrick ckr |= (lrck_div - 1) << CKR_RSD_SHIFT;
45943e4a63dSpatrick }
46043e4a63dSpatrick
46143e4a63dSpatrick ckr &= ~CKR_TRCM_MASK;
46243e4a63dSpatrick HWRITE4(sc, I2S_CKR, ckr);
46343e4a63dSpatrick
46443e4a63dSpatrick for (i = 0; i < 2; i++) {
46543e4a63dSpatrick struct audio_params *p;
46643e4a63dSpatrick int mode;
46743e4a63dSpatrick
46843e4a63dSpatrick switch (i) {
46943e4a63dSpatrick case 0:
47043e4a63dSpatrick mode = AUMODE_PLAY;
47143e4a63dSpatrick p = play;
47243e4a63dSpatrick break;
47343e4a63dSpatrick case 1:
47443e4a63dSpatrick mode = AUMODE_RECORD;
47543e4a63dSpatrick p = rec;
47643e4a63dSpatrick break;
47743e4a63dSpatrick default:
47843e4a63dSpatrick return EINVAL;
47943e4a63dSpatrick }
48043e4a63dSpatrick
48143e4a63dSpatrick if (!(setmode & mode))
48243e4a63dSpatrick continue;
48343e4a63dSpatrick
48443e4a63dSpatrick if (p->channels & 1)
48543e4a63dSpatrick return EINVAL;
48643e4a63dSpatrick
48743e4a63dSpatrick if (setmode & AUMODE_PLAY) {
48843e4a63dSpatrick txcr = HREAD4(sc, I2S_TXCR);
48943e4a63dSpatrick txcr &= ~TXCR_VDW_MASK;
49043e4a63dSpatrick txcr |= (16 - 1) << TXCR_VDW_SHIFT;
49143e4a63dSpatrick txcr &= ~TXCR_TCSR_MASK;
49243e4a63dSpatrick txcr |= (p->channels / 2 - 1) << TXCR_TCSR_SHIFT;
49343e4a63dSpatrick HWRITE4(sc, I2S_TXCR, txcr);
49443e4a63dSpatrick } else {
49543e4a63dSpatrick rxcr = HREAD4(sc, I2S_RXCR);
49643e4a63dSpatrick rxcr &= ~RXCR_VDW_MASK;
49743e4a63dSpatrick rxcr |= (16 - 1) << RXCR_VDW_SHIFT;
49843e4a63dSpatrick rxcr &= ~RXCR_RCSR_MASK;
49943e4a63dSpatrick rxcr |= (p->channels / 2 - 1) << RXCR_RCSR_SHIFT;
50043e4a63dSpatrick HWRITE4(sc, I2S_RXCR, rxcr);
50143e4a63dSpatrick }
50243e4a63dSpatrick
50343e4a63dSpatrick p->encoding = AUDIO_ENCODING_SLINEAR_LE;
50443e4a63dSpatrick p->precision = 16;
50543e4a63dSpatrick p->bps = AUDIO_BPS(p->precision);
50643e4a63dSpatrick p->msb = 1;
50743e4a63dSpatrick p->sample_rate = RK_I2S_SAMPLE_RATE;
50843e4a63dSpatrick }
50943e4a63dSpatrick
51043e4a63dSpatrick return 0;
51143e4a63dSpatrick }
51243e4a63dSpatrick
51343e4a63dSpatrick void *
rkiis_allocm(void * cookie,int direction,size_t size,int type,int flags)51443e4a63dSpatrick rkiis_allocm(void *cookie, int direction, size_t size, int type,
51543e4a63dSpatrick int flags)
51643e4a63dSpatrick {
51743e4a63dSpatrick return malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
51843e4a63dSpatrick }
51943e4a63dSpatrick
52043e4a63dSpatrick void
rkiis_freem(void * cookie,void * addr,int size)52143e4a63dSpatrick rkiis_freem(void *cookie, void *addr, int size)
52243e4a63dSpatrick {
52343e4a63dSpatrick free(addr, M_DEVBUF, size);
52443e4a63dSpatrick }
52543e4a63dSpatrick
52643e4a63dSpatrick int
rkiis_trigger_output(void * cookie,void * start,void * end,int blksize,void (* intr)(void *),void * intrarg,struct audio_params * params)52743e4a63dSpatrick rkiis_trigger_output(void *cookie, void *start, void *end, int blksize,
52843e4a63dSpatrick void (*intr)(void *), void *intrarg, struct audio_params *params)
52943e4a63dSpatrick {
53043e4a63dSpatrick struct rkiis_softc *sc = cookie;
53143e4a63dSpatrick struct rkiis_chan *ch = &sc->sc_pchan;
53243e4a63dSpatrick uint32_t val;
53343e4a63dSpatrick
53443e4a63dSpatrick if (sc->sc_active == 0) {
53543e4a63dSpatrick val = HREAD4(sc, I2S_XFER);
53643e4a63dSpatrick val |= (XFER_TXS | XFER_RXS);
53743e4a63dSpatrick HWRITE4(sc, I2S_XFER, val);
53843e4a63dSpatrick }
53943e4a63dSpatrick
54043e4a63dSpatrick sc->sc_active |= XFER_TXS;
54143e4a63dSpatrick
54243e4a63dSpatrick val = HREAD4(sc, I2S_INTCR);
54343e4a63dSpatrick val |= INTCR_TXEIE;
54443e4a63dSpatrick val &= ~INTCR_TFT_MASK;
54543e4a63dSpatrick val |= (RK_I2S_FIFO_DEPTH / 2) << INTCR_TFT_SHIFT;
54643e4a63dSpatrick HWRITE4(sc, I2S_INTCR, val);
54743e4a63dSpatrick
54843e4a63dSpatrick ch->ch_intr = intr;
54943e4a63dSpatrick ch->ch_intrarg = intrarg;
55043e4a63dSpatrick ch->ch_start = ch->ch_cur = start;
55143e4a63dSpatrick ch->ch_end = end;
55243e4a63dSpatrick ch->ch_blksize = blksize;
55343e4a63dSpatrick ch->ch_resid = blksize;
55443e4a63dSpatrick
55543e4a63dSpatrick return 0;
55643e4a63dSpatrick }
55743e4a63dSpatrick
55843e4a63dSpatrick int
rkiis_trigger_input(void * cookie,void * start,void * end,int blksize,void (* intr)(void *),void * intrarg,struct audio_params * params)55943e4a63dSpatrick rkiis_trigger_input(void *cookie, void *start, void *end, int blksize,
56043e4a63dSpatrick void (*intr)(void *), void *intrarg, struct audio_params *params)
56143e4a63dSpatrick {
56243e4a63dSpatrick return EIO;
56343e4a63dSpatrick }
56443e4a63dSpatrick
56543e4a63dSpatrick int
rkiis_halt_output(void * cookie)56643e4a63dSpatrick rkiis_halt_output(void *cookie)
56743e4a63dSpatrick {
56843e4a63dSpatrick struct rkiis_softc *sc = cookie;
56943e4a63dSpatrick struct rkiis_chan *ch = &sc->sc_pchan;
57043e4a63dSpatrick uint32_t val;
57143e4a63dSpatrick
57243e4a63dSpatrick sc->sc_active &= ~XFER_TXS;
57343e4a63dSpatrick if (sc->sc_active == 0) {
57443e4a63dSpatrick val = HREAD4(sc, I2S_XFER);
57543e4a63dSpatrick val &= ~(XFER_TXS|XFER_RXS);
57643e4a63dSpatrick HWRITE4(sc, I2S_XFER, val);
57743e4a63dSpatrick }
57843e4a63dSpatrick
57943e4a63dSpatrick val = HREAD4(sc, I2S_INTCR);
58043e4a63dSpatrick val &= ~INTCR_TXEIE;
58143e4a63dSpatrick HWRITE4(sc, I2S_INTCR, val);
58243e4a63dSpatrick
58343e4a63dSpatrick val = HREAD4(sc, I2S_CLR);
58443e4a63dSpatrick val |= CLR_TXC;
58543e4a63dSpatrick HWRITE4(sc, I2S_CLR, val);
58643e4a63dSpatrick
58743e4a63dSpatrick while ((HREAD4(sc, I2S_CLR) & CLR_TXC) != 0)
58843e4a63dSpatrick delay(1);
58943e4a63dSpatrick
59043e4a63dSpatrick ch->ch_intr = NULL;
59143e4a63dSpatrick ch->ch_intrarg = NULL;
59243e4a63dSpatrick
59343e4a63dSpatrick return 0;
59443e4a63dSpatrick }
59543e4a63dSpatrick
59643e4a63dSpatrick int
rkiis_halt_input(void * cookie)59743e4a63dSpatrick rkiis_halt_input(void *cookie)
59843e4a63dSpatrick {
59943e4a63dSpatrick struct rkiis_softc *sc = cookie;
60043e4a63dSpatrick struct rkiis_chan *ch = &sc->sc_rchan;
60143e4a63dSpatrick uint32_t val;
60243e4a63dSpatrick
60343e4a63dSpatrick sc->sc_active &= ~XFER_RXS;
60443e4a63dSpatrick if (sc->sc_active == 0) {
60543e4a63dSpatrick val = HREAD4(sc, I2S_XFER);
60643e4a63dSpatrick val &= ~(XFER_TXS|XFER_RXS);
60743e4a63dSpatrick HWRITE4(sc, I2S_XFER, val);
60843e4a63dSpatrick }
60943e4a63dSpatrick
61043e4a63dSpatrick val = HREAD4(sc, I2S_INTCR);
61143e4a63dSpatrick val &= ~INTCR_RXFIE;
61243e4a63dSpatrick HWRITE4(sc, I2S_INTCR, val);
61343e4a63dSpatrick
61443e4a63dSpatrick ch->ch_intr = NULL;
61543e4a63dSpatrick ch->ch_intrarg = NULL;
61643e4a63dSpatrick
61743e4a63dSpatrick return 0;
61843e4a63dSpatrick }
619