xref: /netbsd-src/sys/arch/arm/rockchip/rk_i2s.c (revision 6e54367a22fbc89a1139d033e95bec0c0cf0975b)
1*6e54367aSthorpej /* $NetBSD: rk_i2s.c,v 1.10 2021/01/27 03:10:19 thorpej Exp $ */
25a4a43f8Sjmcneill 
35a4a43f8Sjmcneill /*-
45a4a43f8Sjmcneill  * Copyright (c) 2019 Jared McNeill <jmcneill@invisible.ca>
55a4a43f8Sjmcneill  * All rights reserved.
65a4a43f8Sjmcneill  *
75a4a43f8Sjmcneill  * Redistribution and use in source and binary forms, with or without
85a4a43f8Sjmcneill  * modification, are permitted provided that the following conditions
95a4a43f8Sjmcneill  * are met:
105a4a43f8Sjmcneill  * 1. Redistributions of source code must retain the above copyright
115a4a43f8Sjmcneill  *    notice, this list of conditions and the following disclaimer.
125a4a43f8Sjmcneill  * 2. Redistributions in binary form must reproduce the above copyright
135a4a43f8Sjmcneill  *    notice, this list of conditions and the following disclaimer in the
145a4a43f8Sjmcneill  *    documentation and/or other materials provided with the distribution.
155a4a43f8Sjmcneill  *
165a4a43f8Sjmcneill  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
175a4a43f8Sjmcneill  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
185a4a43f8Sjmcneill  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
195a4a43f8Sjmcneill  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
205a4a43f8Sjmcneill  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
215a4a43f8Sjmcneill  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
225a4a43f8Sjmcneill  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
235a4a43f8Sjmcneill  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
245a4a43f8Sjmcneill  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
255a4a43f8Sjmcneill  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
265a4a43f8Sjmcneill  * SUCH DAMAGE.
275a4a43f8Sjmcneill  */
285a4a43f8Sjmcneill 
295a4a43f8Sjmcneill #include <sys/cdefs.h>
30*6e54367aSthorpej __KERNEL_RCSID(0, "$NetBSD: rk_i2s.c,v 1.10 2021/01/27 03:10:19 thorpej Exp $");
315a4a43f8Sjmcneill 
325a4a43f8Sjmcneill #include <sys/param.h>
335a4a43f8Sjmcneill #include <sys/bus.h>
345a4a43f8Sjmcneill #include <sys/cpu.h>
355a4a43f8Sjmcneill #include <sys/device.h>
365a4a43f8Sjmcneill #include <sys/kmem.h>
375a4a43f8Sjmcneill 
385a4a43f8Sjmcneill #include <sys/audioio.h>
395a4a43f8Sjmcneill #include <dev/audio/audio_if.h>
405a4a43f8Sjmcneill #include <dev/audio/linear.h>
415a4a43f8Sjmcneill 
425a4a43f8Sjmcneill #include <dev/fdt/fdtvar.h>
435a4a43f8Sjmcneill #include <dev/fdt/syscon.h>
445a4a43f8Sjmcneill 
455a4a43f8Sjmcneill #define	RK_I2S_FIFO_DEPTH	32
465a4a43f8Sjmcneill #define	RK_I2S_SAMPLE_RATE	48000
475a4a43f8Sjmcneill 
485a4a43f8Sjmcneill #define	I2S_TXCR		0x00
495a4a43f8Sjmcneill #define	 TXCR_RCNT			__BITS(22,17)
505a4a43f8Sjmcneill #define	 TXCR_TCSR			__BITS(16,15)
515a4a43f8Sjmcneill #define	 TXCR_HWT			__BIT(14)
525a4a43f8Sjmcneill #define	 TXCR_SJM			__BIT(12)
535a4a43f8Sjmcneill #define	 TXCR_FBM			__BIT(11)
545a4a43f8Sjmcneill #define	 TXCR_IBM			__BITS(10,9)
555a4a43f8Sjmcneill #define	 TXCR_PBM			__BITS(8,7)
565a4a43f8Sjmcneill #define	 TXCR_TFS			__BIT(5)
575a4a43f8Sjmcneill #define	 TXCR_VDW			__BITS(4,0)
585a4a43f8Sjmcneill #define	I2S_RXCR		0x04
595a4a43f8Sjmcneill #define	 RXCR_RCSR			__BITS(16,15)
605a4a43f8Sjmcneill #define	 RXCR_HWT			__BIT(14)
615a4a43f8Sjmcneill #define	 RXCR_SJM			__BIT(12)
625a4a43f8Sjmcneill #define	 RXCR_FBM			__BIT(11)
635a4a43f8Sjmcneill #define	 RXCR_IBM			__BITS(10,9)
645a4a43f8Sjmcneill #define	 RXCR_PBM			__BITS(8,7)
655a4a43f8Sjmcneill #define	 RXCR_TFS			__BIT(5)
665a4a43f8Sjmcneill #define	 RXCR_VDW			__BITS(4,0)
675a4a43f8Sjmcneill #define	I2S_CKR			0x08
685a4a43f8Sjmcneill #define	 CKR_TRCM			__BITS(29,28)
695a4a43f8Sjmcneill #define	 CKR_MSS			__BIT(27)
705a4a43f8Sjmcneill #define	 CKR_CKP			__BIT(26)
715a4a43f8Sjmcneill #define	 CKR_RLP			__BIT(25)
725a4a43f8Sjmcneill #define	 CKR_TLP			__BIT(24)
735a4a43f8Sjmcneill #define	 CKR_MDIV			__BITS(23,16)
745a4a43f8Sjmcneill #define	 CKR_RSD			__BITS(15,8)
755a4a43f8Sjmcneill #define	 CKR_TSD			__BITS(7,0)
765a4a43f8Sjmcneill #define	I2S_TXFIFOLR		0x0c
775a4a43f8Sjmcneill #define	 TXFIFOLR_TFL(n)		__BITS((n) * 6 + 5, (n) * 6)
785a4a43f8Sjmcneill #define	I2S_DMACR		0x10
795a4a43f8Sjmcneill #define	 DMACR_RDE			__BIT(24)
805a4a43f8Sjmcneill #define	 DMACR_RDL			__BITS(20,16)
815a4a43f8Sjmcneill #define	 DMACR_TDE			__BIT(8)
825a4a43f8Sjmcneill #define	 DMACR_TDL			__BITS(4,0)
835a4a43f8Sjmcneill #define	I2S_INTCR		0x14
845a4a43f8Sjmcneill #define	 INTCR_RFT			__BITS(24,20)
855a4a43f8Sjmcneill #define	 INTCR_RXOIC			__BIT(18)
865a4a43f8Sjmcneill #define	 INTCR_RXOIE			__BIT(17)
875a4a43f8Sjmcneill #define	 INTCR_RXFIE			__BIT(16)
885a4a43f8Sjmcneill #define	 INTCR_TFT			__BITS(8,4)
895a4a43f8Sjmcneill #define	 INTCR_TXUIC			__BIT(2)
905a4a43f8Sjmcneill #define	 INTCR_TXUIE			__BIT(1)
915a4a43f8Sjmcneill #define	 INTCR_TXEIE			__BIT(0)
925a4a43f8Sjmcneill #define	I2S_INTSR		0x18
935a4a43f8Sjmcneill #define	 INTSR_RXOI			__BIT(17)
945a4a43f8Sjmcneill #define	 INTSR_RXFI			__BIT(16)
955a4a43f8Sjmcneill #define	 INTSR_TXUI			__BIT(1)
965a4a43f8Sjmcneill #define	 INTSR_TXEI			__BIT(0)
975a4a43f8Sjmcneill #define	I2S_XFER		0x1c
985a4a43f8Sjmcneill #define	 XFER_RXS			__BIT(1)
995a4a43f8Sjmcneill #define	 XFER_TXS			__BIT(0)
1005a4a43f8Sjmcneill #define	I2S_CLR			0x20
1015a4a43f8Sjmcneill #define	 CLR_RXC			__BIT(1)
1025a4a43f8Sjmcneill #define	 CLR_TXC			__BIT(0)
1035a4a43f8Sjmcneill #define	I2S_TXDR		0x24
1045a4a43f8Sjmcneill #define	I2S_RXDR		0x28
1055a4a43f8Sjmcneill #define	I2S_RXFIFOLR		0x2c
1065a4a43f8Sjmcneill #define	 RXFIFOLR_RFL(n)		__BITS((n) * 6 + 5, (n) * 6)
1075a4a43f8Sjmcneill 
1085a4a43f8Sjmcneill struct rk_i2s_config {
1095a4a43f8Sjmcneill 	bus_size_t		oe_reg;
1105a4a43f8Sjmcneill 	u_int			oe_mask;
1115a4a43f8Sjmcneill 	u_int			oe_val;
1125a4a43f8Sjmcneill };
1135a4a43f8Sjmcneill 
1145a4a43f8Sjmcneill static const struct rk_i2s_config rk3399_i2s_config = {
1155a4a43f8Sjmcneill 	.oe_reg = 0x0e220,
1165a4a43f8Sjmcneill 	.oe_mask = __BITS(13,11),
1175a4a43f8Sjmcneill 	.oe_val = 0x7,
1185a4a43f8Sjmcneill };
1195a4a43f8Sjmcneill 
120646c0f59Sthorpej static const struct device_compatible_entry compat_data[] = {
121646c0f59Sthorpej 	{ .compat = "rockchip,rk3066-i2s", },
122646c0f59Sthorpej 	{ .compat = "rockchip,rk3188-i2s", },
123646c0f59Sthorpej 	{ .compat = "rockchip,rk3288-i2s", },
124646c0f59Sthorpej 	{ .compat = "rockchip,rk3399-i2s",	.data = &rk3399_i2s_config },
125*6e54367aSthorpej 	DEVICE_COMPAT_EOL
1265a4a43f8Sjmcneill };
1275a4a43f8Sjmcneill 
1285a4a43f8Sjmcneill struct rk_i2s_softc;
1295a4a43f8Sjmcneill 
1305a4a43f8Sjmcneill struct rk_i2s_chan {
1315a4a43f8Sjmcneill 	uint32_t		*ch_start;
1325a4a43f8Sjmcneill 	uint32_t		*ch_end;
1335a4a43f8Sjmcneill 	uint32_t		*ch_cur;
1345a4a43f8Sjmcneill 
1355a4a43f8Sjmcneill 	int			ch_blksize;
1365a4a43f8Sjmcneill 	int			ch_resid;
1375a4a43f8Sjmcneill 
1385a4a43f8Sjmcneill 	void			(*ch_intr)(void *);
1395a4a43f8Sjmcneill 	void			*ch_intrarg;
1405a4a43f8Sjmcneill };
1415a4a43f8Sjmcneill 
1425a4a43f8Sjmcneill struct rk_i2s_softc {
1435a4a43f8Sjmcneill 	device_t		sc_dev;
1445a4a43f8Sjmcneill 	bus_space_tag_t		sc_bst;
1455a4a43f8Sjmcneill 	bus_space_handle_t	sc_bsh;
1465a4a43f8Sjmcneill 	int			sc_phandle;
1475a4a43f8Sjmcneill 	struct clk		*sc_clk;
1485a4a43f8Sjmcneill 	struct syscon		*sc_grf;
1495a4a43f8Sjmcneill 	const struct rk_i2s_config *sc_conf;
1505a4a43f8Sjmcneill 
1515a4a43f8Sjmcneill 	kmutex_t		sc_lock;
1525a4a43f8Sjmcneill 	kmutex_t		sc_intr_lock;
1535a4a43f8Sjmcneill 
1545a4a43f8Sjmcneill 	struct audio_format	sc_format;
1555a4a43f8Sjmcneill 
1565a4a43f8Sjmcneill 	struct rk_i2s_chan	sc_pchan;
1575a4a43f8Sjmcneill 	struct rk_i2s_chan	sc_rchan;
1585a4a43f8Sjmcneill 
1595a4a43f8Sjmcneill 	u_int			sc_active;
1605a4a43f8Sjmcneill 
1615a4a43f8Sjmcneill 	struct audio_dai_device	sc_dai;
1625a4a43f8Sjmcneill };
1635a4a43f8Sjmcneill 
1645a4a43f8Sjmcneill #define	RD4(sc, reg)			\
1655a4a43f8Sjmcneill 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
1665a4a43f8Sjmcneill #define	WR4(sc, reg, val)		\
1675a4a43f8Sjmcneill 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
1685a4a43f8Sjmcneill 
1695a4a43f8Sjmcneill static int
rk_i2s_query_format(void * priv,audio_format_query_t * afp)1705a4a43f8Sjmcneill rk_i2s_query_format(void *priv, audio_format_query_t *afp)
1715a4a43f8Sjmcneill {
1725a4a43f8Sjmcneill 	struct rk_i2s_softc * const sc = priv;
1735a4a43f8Sjmcneill 
1745a4a43f8Sjmcneill 	return audio_query_format(&sc->sc_format, 1, afp);
1755a4a43f8Sjmcneill }
1765a4a43f8Sjmcneill 
1775a4a43f8Sjmcneill static int
rk_i2s_set_format(void * priv,int setmode,const audio_params_t * play,const audio_params_t * rec,audio_filter_reg_t * pfil,audio_filter_reg_t * rfil)1785a4a43f8Sjmcneill rk_i2s_set_format(void *priv, int setmode,
1795a4a43f8Sjmcneill     const audio_params_t *play, const audio_params_t *rec,
1805a4a43f8Sjmcneill     audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
1815a4a43f8Sjmcneill {
1825a4a43f8Sjmcneill 	struct rk_i2s_softc * const sc = priv;
1835a4a43f8Sjmcneill 	uint32_t ckr, txcr, rxcr;
1845a4a43f8Sjmcneill 
1855a4a43f8Sjmcneill 	ckr = RD4(sc, I2S_CKR);
1865a4a43f8Sjmcneill 	if ((ckr & CKR_MSS) == 0) {
1875a4a43f8Sjmcneill 		const u_int mclk_rate = clk_get_rate(sc->sc_clk);
1885a4a43f8Sjmcneill 		const u_int bclk_rate = 2 * 32 * RK_I2S_SAMPLE_RATE;
1895a4a43f8Sjmcneill 		const u_int bclk_div = mclk_rate / bclk_rate;
1905a4a43f8Sjmcneill 		const u_int lrck_div = bclk_rate / RK_I2S_SAMPLE_RATE;
1915a4a43f8Sjmcneill 
1925a4a43f8Sjmcneill 		ckr &= ~CKR_MDIV;
1935a4a43f8Sjmcneill 		ckr |= __SHIFTIN(bclk_div - 1, CKR_MDIV);
1945a4a43f8Sjmcneill 		ckr &= ~CKR_TSD;
1955a4a43f8Sjmcneill 		ckr |= __SHIFTIN(lrck_div - 1, CKR_TSD);
1965a4a43f8Sjmcneill 		ckr &= ~CKR_RSD;
1975a4a43f8Sjmcneill 		ckr |= __SHIFTIN(lrck_div - 1, CKR_RSD);
1985a4a43f8Sjmcneill 	}
1995a4a43f8Sjmcneill 
2005a4a43f8Sjmcneill 	ckr &= ~CKR_TRCM;
2015a4a43f8Sjmcneill 	ckr |= __SHIFTIN(0, CKR_TRCM);
2025a4a43f8Sjmcneill 	WR4(sc, I2S_CKR, ckr);
2035a4a43f8Sjmcneill 
2045a4a43f8Sjmcneill 	if (play && (setmode & AUMODE_PLAY) != 0) {
2055a4a43f8Sjmcneill 		if (play->channels & 1)
2065a4a43f8Sjmcneill 			return EINVAL;
2075a4a43f8Sjmcneill 		txcr = RD4(sc, I2S_TXCR);
2085a4a43f8Sjmcneill 		txcr &= ~TXCR_VDW;
2095a4a43f8Sjmcneill 		txcr |= __SHIFTIN(play->validbits - 1, TXCR_VDW);
2105a4a43f8Sjmcneill 		txcr &= ~TXCR_TCSR;
2115a4a43f8Sjmcneill 		txcr |= __SHIFTIN(play->channels / 2 - 1, TXCR_TCSR);
2125a4a43f8Sjmcneill 		WR4(sc, I2S_TXCR, txcr);
2135a4a43f8Sjmcneill 	}
2145a4a43f8Sjmcneill 
2155a4a43f8Sjmcneill 	if (rec && (setmode & AUMODE_RECORD) != 0) {
2165a4a43f8Sjmcneill 		if (rec->channels & 1)
2175a4a43f8Sjmcneill 			return EINVAL;
2185a4a43f8Sjmcneill 		rxcr = RD4(sc, I2S_RXCR);
2195a4a43f8Sjmcneill 		rxcr &= ~RXCR_VDW;
2205a4a43f8Sjmcneill 		rxcr |= __SHIFTIN(rec->validbits - 1, RXCR_VDW);
2215a4a43f8Sjmcneill 		rxcr &= ~RXCR_RCSR;
2225a4a43f8Sjmcneill 		rxcr |= __SHIFTIN(rec->channels / 2 - 1, RXCR_RCSR);
2235a4a43f8Sjmcneill 		WR4(sc, I2S_RXCR, rxcr);
2245a4a43f8Sjmcneill 	}
2255a4a43f8Sjmcneill 
2265a4a43f8Sjmcneill 	return 0;
2275a4a43f8Sjmcneill }
2285a4a43f8Sjmcneill 
2295a4a43f8Sjmcneill static int
rk_i2s_get_props(void * priv)2305a4a43f8Sjmcneill rk_i2s_get_props(void *priv)
2315a4a43f8Sjmcneill {
2325a4a43f8Sjmcneill 
2335a4a43f8Sjmcneill 	return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE |
2345a4a43f8Sjmcneill 	    AUDIO_PROP_FULLDUPLEX;
2355a4a43f8Sjmcneill }
2365a4a43f8Sjmcneill 
2375a4a43f8Sjmcneill static void *
rk_i2s_allocm(void * priv,int dir,size_t size)2385a4a43f8Sjmcneill rk_i2s_allocm(void *priv, int dir, size_t size)
2395a4a43f8Sjmcneill {
2405a4a43f8Sjmcneill 	return kmem_zalloc(size, KM_SLEEP);
2415a4a43f8Sjmcneill }
2425a4a43f8Sjmcneill 
2435a4a43f8Sjmcneill static void
rk_i2s_freem(void * priv,void * addr,size_t size)2445a4a43f8Sjmcneill rk_i2s_freem(void *priv, void *addr, size_t size)
2455a4a43f8Sjmcneill {
2465a4a43f8Sjmcneill 	kmem_free(addr, size);
2475a4a43f8Sjmcneill }
2485a4a43f8Sjmcneill 
2495a4a43f8Sjmcneill static int
rk_i2s_trigger_output(void * priv,void * start,void * end,int blksize,void (* intr)(void *),void * intrarg,const audio_params_t * params)2505a4a43f8Sjmcneill rk_i2s_trigger_output(void *priv, void *start, void *end, int blksize,
2515a4a43f8Sjmcneill     void (*intr)(void *), void *intrarg, const audio_params_t *params)
2525a4a43f8Sjmcneill {
2535a4a43f8Sjmcneill 	struct rk_i2s_softc * const sc = priv;
2545a4a43f8Sjmcneill 	struct rk_i2s_chan *ch = &sc->sc_pchan;
2555a4a43f8Sjmcneill 	uint32_t val;
2565a4a43f8Sjmcneill 
2575a4a43f8Sjmcneill 	if (sc->sc_active == 0) {
2585a4a43f8Sjmcneill 		val = RD4(sc, I2S_XFER);
2595a4a43f8Sjmcneill 		val |= (XFER_TXS | XFER_RXS);
2605a4a43f8Sjmcneill 		WR4(sc, I2S_XFER, val);
2615a4a43f8Sjmcneill 	}
2625a4a43f8Sjmcneill 
2635a4a43f8Sjmcneill 	sc->sc_active |= XFER_TXS;
2645a4a43f8Sjmcneill 
2655a4a43f8Sjmcneill 	val = RD4(sc, I2S_INTCR);
2665a4a43f8Sjmcneill 	val |= INTCR_TXEIE;
2675a4a43f8Sjmcneill 	val &= ~INTCR_TFT;
2685a4a43f8Sjmcneill 	val |= __SHIFTIN(RK_I2S_FIFO_DEPTH / 2, INTCR_TFT);
2695a4a43f8Sjmcneill 	WR4(sc, I2S_INTCR, val);
2705a4a43f8Sjmcneill 
2715a4a43f8Sjmcneill 	ch->ch_intr = intr;
2725a4a43f8Sjmcneill 	ch->ch_intrarg = intrarg;
2735a4a43f8Sjmcneill 	ch->ch_start = ch->ch_cur = start;
2745a4a43f8Sjmcneill 	ch->ch_end = end;
2755a4a43f8Sjmcneill 	ch->ch_blksize = blksize;
2765a4a43f8Sjmcneill 	ch->ch_resid = blksize;
2775a4a43f8Sjmcneill 
2785a4a43f8Sjmcneill 	return 0;
2795a4a43f8Sjmcneill }
2805a4a43f8Sjmcneill 
2815a4a43f8Sjmcneill static int
rk_i2s_trigger_input(void * priv,void * start,void * end,int blksize,void (* intr)(void *),void * intrarg,const audio_params_t * params)2825a4a43f8Sjmcneill rk_i2s_trigger_input(void *priv, void *start, void *end, int blksize,
2835a4a43f8Sjmcneill     void (*intr)(void *), void *intrarg, const audio_params_t *params)
2845a4a43f8Sjmcneill {
2855a4a43f8Sjmcneill 	return EIO;
2865a4a43f8Sjmcneill }
2875a4a43f8Sjmcneill 
2885a4a43f8Sjmcneill static int
rk_i2s_halt_output(void * priv)2895a4a43f8Sjmcneill rk_i2s_halt_output(void *priv)
2905a4a43f8Sjmcneill {
2915a4a43f8Sjmcneill 	struct rk_i2s_softc * const sc = priv;
2925a4a43f8Sjmcneill 	struct rk_i2s_chan *ch = &sc->sc_pchan;
2935a4a43f8Sjmcneill 	uint32_t val;
2945a4a43f8Sjmcneill 
2955a4a43f8Sjmcneill 	sc->sc_active &= ~XFER_TXS;
2965a4a43f8Sjmcneill 	if (sc->sc_active == 0) {
2975a4a43f8Sjmcneill 		val = RD4(sc, I2S_XFER);
2985a4a43f8Sjmcneill 		val &= ~(XFER_TXS|XFER_RXS);
2995a4a43f8Sjmcneill 		WR4(sc, I2S_XFER, val);
3005a4a43f8Sjmcneill 	}
3015a4a43f8Sjmcneill 
3025a4a43f8Sjmcneill 	val = RD4(sc, I2S_INTCR);
3035a4a43f8Sjmcneill 	val &= ~INTCR_TXEIE;
3045a4a43f8Sjmcneill 	WR4(sc, I2S_INTCR, val);
3055a4a43f8Sjmcneill 
3065a4a43f8Sjmcneill 	val = RD4(sc, I2S_CLR);
3075a4a43f8Sjmcneill 	val |= CLR_TXC;
3085a4a43f8Sjmcneill 	WR4(sc, I2S_CLR, val);
3095a4a43f8Sjmcneill 
3105a4a43f8Sjmcneill 	while ((RD4(sc, I2S_CLR) & CLR_TXC) != 0)
3115a4a43f8Sjmcneill 		delay(1);
3125a4a43f8Sjmcneill 
3135a4a43f8Sjmcneill 	ch->ch_intr = NULL;
3145a4a43f8Sjmcneill 	ch->ch_intrarg = NULL;
3155a4a43f8Sjmcneill 
3165a4a43f8Sjmcneill 	return 0;
3175a4a43f8Sjmcneill }
3185a4a43f8Sjmcneill 
3195a4a43f8Sjmcneill static int
rk_i2s_halt_input(void * priv)3205a4a43f8Sjmcneill rk_i2s_halt_input(void *priv)
3215a4a43f8Sjmcneill {
3225a4a43f8Sjmcneill 	struct rk_i2s_softc * const sc = priv;
3235a4a43f8Sjmcneill 	struct rk_i2s_chan *ch = &sc->sc_rchan;
3245a4a43f8Sjmcneill 	uint32_t val;
3255a4a43f8Sjmcneill 
3265a4a43f8Sjmcneill 	sc->sc_active &= ~XFER_RXS;
3275a4a43f8Sjmcneill 	if (sc->sc_active == 0) {
3285a4a43f8Sjmcneill 		val = RD4(sc, I2S_XFER);
3295a4a43f8Sjmcneill 		val &= ~(XFER_TXS|XFER_RXS);
3305a4a43f8Sjmcneill 		WR4(sc, I2S_XFER, val);
3315a4a43f8Sjmcneill 	}
3325a4a43f8Sjmcneill 
3335a4a43f8Sjmcneill 	val = RD4(sc, I2S_INTCR);
3345a4a43f8Sjmcneill 	val &= ~INTCR_RXFIE;
3355a4a43f8Sjmcneill 	WR4(sc, I2S_INTCR, val);
3365a4a43f8Sjmcneill 
3375a4a43f8Sjmcneill 	ch->ch_intr = NULL;
3385a4a43f8Sjmcneill 	ch->ch_intrarg = NULL;
3395a4a43f8Sjmcneill 
3405a4a43f8Sjmcneill 	return 0;
3415a4a43f8Sjmcneill }
3425a4a43f8Sjmcneill 
3435a4a43f8Sjmcneill static void
rk_i2s_get_locks(void * priv,kmutex_t ** intr,kmutex_t ** thread)3445a4a43f8Sjmcneill rk_i2s_get_locks(void *priv, kmutex_t **intr, kmutex_t **thread)
3455a4a43f8Sjmcneill {
3465a4a43f8Sjmcneill 	struct rk_i2s_softc * const sc = priv;
3475a4a43f8Sjmcneill 
3485a4a43f8Sjmcneill 	*intr = &sc->sc_intr_lock;
3495a4a43f8Sjmcneill 	*thread = &sc->sc_lock;
3505a4a43f8Sjmcneill }
3515a4a43f8Sjmcneill 
3525a4a43f8Sjmcneill static const struct audio_hw_if rk_i2s_hw_if = {
3535a4a43f8Sjmcneill 	.query_format = rk_i2s_query_format,
3545a4a43f8Sjmcneill 	.set_format = rk_i2s_set_format,
3555a4a43f8Sjmcneill 	.get_props = rk_i2s_get_props,
3565a4a43f8Sjmcneill 	.allocm = rk_i2s_allocm,
3575a4a43f8Sjmcneill 	.freem = rk_i2s_freem,
3585a4a43f8Sjmcneill 	.trigger_output = rk_i2s_trigger_output,
3595a4a43f8Sjmcneill 	.trigger_input = rk_i2s_trigger_input,
3605a4a43f8Sjmcneill 	.halt_output = rk_i2s_halt_output,
3615a4a43f8Sjmcneill 	.halt_input = rk_i2s_halt_input,
3625a4a43f8Sjmcneill 	.get_locks = rk_i2s_get_locks,
3635a4a43f8Sjmcneill };
3645a4a43f8Sjmcneill 
3655a4a43f8Sjmcneill static int
rk_i2s_intr(void * priv)3665a4a43f8Sjmcneill rk_i2s_intr(void *priv)
3675a4a43f8Sjmcneill {
3685a4a43f8Sjmcneill 	struct rk_i2s_softc * const sc = priv;
3695a4a43f8Sjmcneill 	struct rk_i2s_chan * const pch = &sc->sc_pchan;
3705a4a43f8Sjmcneill #if notyet
3715a4a43f8Sjmcneill 	struct rk_i2s_chan * const rch = &sc->sc_rchan;
3725a4a43f8Sjmcneill #endif
3735a4a43f8Sjmcneill 	uint32_t sr, val;
3745a4a43f8Sjmcneill 	int fifolr;
3755a4a43f8Sjmcneill 
3765a4a43f8Sjmcneill 	mutex_enter(&sc->sc_intr_lock);
3775a4a43f8Sjmcneill 
3785a4a43f8Sjmcneill 	sr = RD4(sc, I2S_INTSR);
3795a4a43f8Sjmcneill 
3805a4a43f8Sjmcneill 	if ((sr & INTSR_RXFI) != 0) {
3815a4a43f8Sjmcneill #if notyet
3825a4a43f8Sjmcneill 		val = RD4(sc, I2S_RXFIFOLR);
3835a4a43f8Sjmcneill 		fifolr = __SHIFTOUT(val, RXFIFOLR_RFL(0));
3845a4a43f8Sjmcneill 		while (fifolr > 0) {
3855a4a43f8Sjmcneill 			*rch->ch_data = RD4(sc, I2S_RXDR);
3865a4a43f8Sjmcneill 			rch->ch_data++;
3875a4a43f8Sjmcneill 			rch->ch_resid -= 4;
3885a4a43f8Sjmcneill 			if (rch->ch_resid == 0)
3895a4a43f8Sjmcneill 				rch->ch_intr(rch->ch_intrarg);
3905a4a43f8Sjmcneill 			--fifolr;
3915a4a43f8Sjmcneill 		}
3925a4a43f8Sjmcneill #endif
3935a4a43f8Sjmcneill 	}
3945a4a43f8Sjmcneill 
3955a4a43f8Sjmcneill 	if ((sr & INTSR_TXEI) != 0) {
3965a4a43f8Sjmcneill 		val = RD4(sc, I2S_TXFIFOLR);
3975a4a43f8Sjmcneill 		fifolr = __SHIFTOUT(val, TXFIFOLR_TFL(0));
3985a4a43f8Sjmcneill 		fifolr = uimin(fifolr, RK_I2S_FIFO_DEPTH);
3995a4a43f8Sjmcneill 		while (fifolr < RK_I2S_FIFO_DEPTH - 1) {
4005a4a43f8Sjmcneill 			WR4(sc, I2S_TXDR, *pch->ch_cur);
4015a4a43f8Sjmcneill 			pch->ch_cur++;
4025a4a43f8Sjmcneill 			if (pch->ch_cur == pch->ch_end)
4035a4a43f8Sjmcneill 				pch->ch_cur = pch->ch_start;
4045a4a43f8Sjmcneill 			pch->ch_resid -= 4;
4055a4a43f8Sjmcneill 			if (pch->ch_resid == 0) {
4065a4a43f8Sjmcneill 				pch->ch_intr(pch->ch_intrarg);
4075a4a43f8Sjmcneill 				pch->ch_resid = pch->ch_blksize;
4085a4a43f8Sjmcneill 			}
4095a4a43f8Sjmcneill 			++fifolr;
4105a4a43f8Sjmcneill 		}
4115a4a43f8Sjmcneill 	}
4125a4a43f8Sjmcneill 
4135a4a43f8Sjmcneill 	mutex_exit(&sc->sc_intr_lock);
4145a4a43f8Sjmcneill 
4155a4a43f8Sjmcneill 	return 0;
4165a4a43f8Sjmcneill }
4175a4a43f8Sjmcneill 
4185a4a43f8Sjmcneill static int
rk_i2s_dai_set_sysclk(audio_dai_tag_t dai,u_int rate,int dir)4195a4a43f8Sjmcneill rk_i2s_dai_set_sysclk(audio_dai_tag_t dai, u_int rate, int dir)
4205a4a43f8Sjmcneill {
4215a4a43f8Sjmcneill 	struct rk_i2s_softc * const sc = audio_dai_private(dai);
4225a4a43f8Sjmcneill 	int error;
4235a4a43f8Sjmcneill 
4245a4a43f8Sjmcneill 	error = clk_set_rate(sc->sc_clk, rate);
4255a4a43f8Sjmcneill 	if (error != 0) {
4265a4a43f8Sjmcneill 		device_printf(sc->sc_dev, "failed to set sysclk to %u Hz: %d\n",
4275a4a43f8Sjmcneill 		    rate, error);
4285a4a43f8Sjmcneill 		return error;
4295a4a43f8Sjmcneill 	}
4305a4a43f8Sjmcneill 
4315a4a43f8Sjmcneill 	return 0;
4325a4a43f8Sjmcneill }
4335a4a43f8Sjmcneill 
4345a4a43f8Sjmcneill static int
rk_i2s_dai_set_format(audio_dai_tag_t dai,u_int format)4355a4a43f8Sjmcneill rk_i2s_dai_set_format(audio_dai_tag_t dai, u_int format)
4365a4a43f8Sjmcneill {
4375a4a43f8Sjmcneill 	struct rk_i2s_softc * const sc = audio_dai_private(dai);
4385a4a43f8Sjmcneill 	uint32_t txcr, rxcr, ckr;
4395a4a43f8Sjmcneill 
4405a4a43f8Sjmcneill 	const u_int fmt = __SHIFTOUT(format, AUDIO_DAI_FORMAT_MASK);
4415a4a43f8Sjmcneill 	const u_int pol = __SHIFTOUT(format, AUDIO_DAI_POLARITY_MASK);
4425a4a43f8Sjmcneill 	const u_int clk = __SHIFTOUT(format, AUDIO_DAI_CLOCK_MASK);
4435a4a43f8Sjmcneill 
4445a4a43f8Sjmcneill 	txcr = RD4(sc, I2S_TXCR);
4455a4a43f8Sjmcneill 	rxcr = RD4(sc, I2S_RXCR);
4465a4a43f8Sjmcneill 	ckr = RD4(sc, I2S_CKR);
4475a4a43f8Sjmcneill 
4485a4a43f8Sjmcneill 	txcr &= ~(TXCR_IBM|TXCR_PBM|TXCR_TFS);
4495a4a43f8Sjmcneill 	rxcr &= ~(RXCR_IBM|RXCR_PBM|RXCR_TFS);
4505a4a43f8Sjmcneill 	switch (fmt) {
4515a4a43f8Sjmcneill 	case AUDIO_DAI_FORMAT_I2S:
4525a4a43f8Sjmcneill 		txcr |= __SHIFTIN(0, TXCR_IBM);
4535a4a43f8Sjmcneill 		rxcr |= __SHIFTIN(0, RXCR_IBM);
4545a4a43f8Sjmcneill 		break;
4555a4a43f8Sjmcneill 	case AUDIO_DAI_FORMAT_LJ:
4565a4a43f8Sjmcneill 		txcr |= __SHIFTIN(1, TXCR_IBM);
4575a4a43f8Sjmcneill 		rxcr |= __SHIFTIN(1, RXCR_IBM);
4585a4a43f8Sjmcneill 		break;
4595a4a43f8Sjmcneill 	case AUDIO_DAI_FORMAT_RJ:
4605a4a43f8Sjmcneill 		txcr |= __SHIFTIN(2, TXCR_IBM);
4615a4a43f8Sjmcneill 		rxcr |= __SHIFTIN(2, RXCR_IBM);
4625a4a43f8Sjmcneill 		break;
4635a4a43f8Sjmcneill 	case AUDIO_DAI_FORMAT_DSPA:
4645a4a43f8Sjmcneill 		txcr |= __SHIFTIN(0, TXCR_PBM);
4655a4a43f8Sjmcneill 		txcr |= TXCR_TFS;
4665a4a43f8Sjmcneill 		rxcr |= __SHIFTIN(0, RXCR_PBM);
4675a4a43f8Sjmcneill 		txcr |= RXCR_TFS;
4685a4a43f8Sjmcneill 		break;
4695a4a43f8Sjmcneill 	case AUDIO_DAI_FORMAT_DSPB:
4705a4a43f8Sjmcneill 		txcr |= __SHIFTIN(1, TXCR_PBM);
4715a4a43f8Sjmcneill 		txcr |= TXCR_TFS;
4725a4a43f8Sjmcneill 		rxcr |= __SHIFTIN(1, RXCR_PBM);
4735a4a43f8Sjmcneill 		txcr |= RXCR_TFS;
4745a4a43f8Sjmcneill 		break;
4755a4a43f8Sjmcneill 	default:
4765a4a43f8Sjmcneill 		return EINVAL;
4775a4a43f8Sjmcneill 	}
4785a4a43f8Sjmcneill 
4795a4a43f8Sjmcneill 	WR4(sc, I2S_TXCR, txcr);
4805a4a43f8Sjmcneill 	WR4(sc, I2S_RXCR, rxcr);
4815a4a43f8Sjmcneill 
4825a4a43f8Sjmcneill 	switch (pol) {
4835a4a43f8Sjmcneill 	case AUDIO_DAI_POLARITY_IB_NF:
4845a4a43f8Sjmcneill 		ckr |= CKR_CKP;
4855a4a43f8Sjmcneill 		break;
4865a4a43f8Sjmcneill 	case AUDIO_DAI_POLARITY_NB_NF:
4875a4a43f8Sjmcneill 		ckr &= ~CKR_CKP;
4885a4a43f8Sjmcneill 		break;
4895a4a43f8Sjmcneill 	default:
4905a4a43f8Sjmcneill 		return EINVAL;
4915a4a43f8Sjmcneill 	}
4925a4a43f8Sjmcneill 
4935a4a43f8Sjmcneill 	switch (clk) {
4945a4a43f8Sjmcneill 	case AUDIO_DAI_CLOCK_CBM_CFM:
4955a4a43f8Sjmcneill 		ckr |= CKR_MSS;		/* sclk input */
4965a4a43f8Sjmcneill 		break;
4975a4a43f8Sjmcneill 	case AUDIO_DAI_CLOCK_CBS_CFS:
4985a4a43f8Sjmcneill 		ckr &= ~CKR_MSS;	/* sclk output */
4995a4a43f8Sjmcneill 		break;
5005a4a43f8Sjmcneill 	default:
5015a4a43f8Sjmcneill 		return EINVAL;
5025a4a43f8Sjmcneill 	}
5035a4a43f8Sjmcneill 
5045a4a43f8Sjmcneill 	WR4(sc, I2S_CKR, ckr);
5055a4a43f8Sjmcneill 
5065a4a43f8Sjmcneill 	return 0;
5075a4a43f8Sjmcneill }
5085a4a43f8Sjmcneill 
5095a4a43f8Sjmcneill static audio_dai_tag_t
rk_i2s_dai_get_tag(device_t dev,const void * data,size_t len)5105a4a43f8Sjmcneill rk_i2s_dai_get_tag(device_t dev, const void *data, size_t len)
5115a4a43f8Sjmcneill {
5125a4a43f8Sjmcneill 	struct rk_i2s_softc * const sc = device_private(dev);
5135a4a43f8Sjmcneill 
5145a4a43f8Sjmcneill 	if (len != 4)
5155a4a43f8Sjmcneill 		return NULL;
5165a4a43f8Sjmcneill 
5175a4a43f8Sjmcneill 	return &sc->sc_dai;
5185a4a43f8Sjmcneill }
5195a4a43f8Sjmcneill 
5205a4a43f8Sjmcneill static struct fdtbus_dai_controller_func rk_i2s_dai_funcs = {
5215a4a43f8Sjmcneill 	.get_tag = rk_i2s_dai_get_tag
5225a4a43f8Sjmcneill };
5235a4a43f8Sjmcneill 
5245a4a43f8Sjmcneill static int
rk_i2s_clock_init(struct rk_i2s_softc * sc)5255a4a43f8Sjmcneill rk_i2s_clock_init(struct rk_i2s_softc *sc)
5265a4a43f8Sjmcneill {
5275a4a43f8Sjmcneill 	const int phandle = sc->sc_phandle;
5285a4a43f8Sjmcneill 	int error;
5295a4a43f8Sjmcneill 
5305a4a43f8Sjmcneill 	sc->sc_clk = fdtbus_clock_get(phandle, "i2s_clk");
5315a4a43f8Sjmcneill 	if (sc->sc_clk == NULL) {
5325a4a43f8Sjmcneill 		aprint_error(": couldn't find i2s_clk clock\n");
5335a4a43f8Sjmcneill 		return ENXIO;
5345a4a43f8Sjmcneill 	}
5355a4a43f8Sjmcneill 	error = clk_enable(sc->sc_clk);
5365a4a43f8Sjmcneill 	if (error != 0) {
5375a4a43f8Sjmcneill 		aprint_error(": couldn't enable i2s_clk clock: %d\n", error);
5385a4a43f8Sjmcneill 		return error;
5395a4a43f8Sjmcneill 	}
5405a4a43f8Sjmcneill 
5415a4a43f8Sjmcneill 	/* Enable bus clock */
5422cdfae77Smrg 	error = fdtbus_clock_enable(phandle, "i2s_hclk", true);
5432cdfae77Smrg 	if (error != 0) {
5445a4a43f8Sjmcneill 		aprint_error(": couldn't enable i2s_hclk clock: %d\n", error);
5455a4a43f8Sjmcneill 		return error;
5465a4a43f8Sjmcneill 	}
5475a4a43f8Sjmcneill 
5485a4a43f8Sjmcneill 	return 0;
5495a4a43f8Sjmcneill }
5505a4a43f8Sjmcneill 
5515a4a43f8Sjmcneill static int
rk_i2s_match(device_t parent,cfdata_t cf,void * aux)5525a4a43f8Sjmcneill rk_i2s_match(device_t parent, cfdata_t cf, void *aux)
5535a4a43f8Sjmcneill {
5545a4a43f8Sjmcneill 	struct fdt_attach_args * const faa = aux;
5555a4a43f8Sjmcneill 
556*6e54367aSthorpej 	return of_compatible_match(faa->faa_phandle, compat_data);
5575a4a43f8Sjmcneill }
5585a4a43f8Sjmcneill 
5595a4a43f8Sjmcneill static void
rk_i2s_attach(device_t parent,device_t self,void * aux)5605a4a43f8Sjmcneill rk_i2s_attach(device_t parent, device_t self, void *aux)
5615a4a43f8Sjmcneill {
5625a4a43f8Sjmcneill 	struct rk_i2s_softc * const sc = device_private(self);
5635a4a43f8Sjmcneill 	struct fdt_attach_args * const faa = aux;
5645a4a43f8Sjmcneill 	const int phandle = faa->faa_phandle;
5655a4a43f8Sjmcneill 	char intrstr[128];
5665a4a43f8Sjmcneill 	bus_addr_t addr;
5675a4a43f8Sjmcneill 	bus_size_t size;
5685a4a43f8Sjmcneill 	uint32_t val;
5695a4a43f8Sjmcneill 
5705a4a43f8Sjmcneill 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
5715a4a43f8Sjmcneill 		aprint_error(": couldn't get registers\n");
5725a4a43f8Sjmcneill 		return;
5735a4a43f8Sjmcneill 	}
5745a4a43f8Sjmcneill 	if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
5755a4a43f8Sjmcneill 		aprint_error(": couldn't decode interrupt\n");
5765a4a43f8Sjmcneill 		return;
5775a4a43f8Sjmcneill 	}
5785a4a43f8Sjmcneill 
5795a4a43f8Sjmcneill 	sc->sc_dev = self;
5805a4a43f8Sjmcneill 	sc->sc_phandle = phandle;
5815a4a43f8Sjmcneill 	sc->sc_bst = faa->faa_bst;
5825a4a43f8Sjmcneill 	if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
5835a4a43f8Sjmcneill 		aprint_error(": couldn't map registers\n");
5845a4a43f8Sjmcneill 		return;
5855a4a43f8Sjmcneill 	}
5865a4a43f8Sjmcneill 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
5875a4a43f8Sjmcneill 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
5885a4a43f8Sjmcneill 
589*6e54367aSthorpej 	sc->sc_conf = of_compatible_lookup(phandle, compat_data)->data;
59033a7d25eSjmcneill 	if (sc->sc_conf != NULL && sc->sc_conf->oe_mask != 0) {
5915a4a43f8Sjmcneill 		sc->sc_grf = fdtbus_syscon_acquire(phandle, "rockchip,grf");
59233a7d25eSjmcneill 		if (sc->sc_grf == NULL) {
59333a7d25eSjmcneill 			aprint_error(": couldn't find grf\n");
59433a7d25eSjmcneill 			return;
59533a7d25eSjmcneill 		}
5965a4a43f8Sjmcneill 		syscon_lock(sc->sc_grf);
5975a4a43f8Sjmcneill 		val = __SHIFTIN(sc->sc_conf->oe_val, sc->sc_conf->oe_mask);
5985a4a43f8Sjmcneill 		val |= (sc->sc_conf->oe_mask << 16);
5995a4a43f8Sjmcneill 		syscon_write_4(sc->sc_grf, sc->sc_conf->oe_reg, val);
6005a4a43f8Sjmcneill 		syscon_unlock(sc->sc_grf);
6015a4a43f8Sjmcneill 	}
6025a4a43f8Sjmcneill 
6035a4a43f8Sjmcneill 	if (rk_i2s_clock_init(sc) != 0)
6045a4a43f8Sjmcneill 		return;
6055a4a43f8Sjmcneill 
6065a4a43f8Sjmcneill 	aprint_naive("\n");
6075a4a43f8Sjmcneill 	aprint_normal(": I2S/PCM controller\n");
6085a4a43f8Sjmcneill 
60964e248edSryo 	if (fdtbus_intr_establish_xname(phandle, 0, IPL_AUDIO, FDT_INTR_MPSAFE,
61064e248edSryo 	    rk_i2s_intr, sc, device_xname(self)) == NULL) {
6115a4a43f8Sjmcneill 		aprint_error_dev(self, "couldn't establish interrupt on %s\n", intrstr);
6125a4a43f8Sjmcneill 		return;
6135a4a43f8Sjmcneill 	}
6145a4a43f8Sjmcneill 	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
6155a4a43f8Sjmcneill 
6165a4a43f8Sjmcneill 	sc->sc_format.mode = AUMODE_PLAY|AUMODE_RECORD;
6175a4a43f8Sjmcneill 	sc->sc_format.encoding = AUDIO_ENCODING_SLINEAR_LE;
6185a4a43f8Sjmcneill 	sc->sc_format.validbits = 16;
6195a4a43f8Sjmcneill 	sc->sc_format.precision = 16;
6205a4a43f8Sjmcneill 	sc->sc_format.channels = 2;
6215a4a43f8Sjmcneill 	sc->sc_format.channel_mask = AUFMT_STEREO;
6225a4a43f8Sjmcneill 	sc->sc_format.frequency_type = 1;
6235a4a43f8Sjmcneill 	sc->sc_format.frequency[0] = RK_I2S_SAMPLE_RATE;
6245a4a43f8Sjmcneill 
6255a4a43f8Sjmcneill 	sc->sc_dai.dai_set_sysclk = rk_i2s_dai_set_sysclk;
6265a4a43f8Sjmcneill 	sc->sc_dai.dai_set_format = rk_i2s_dai_set_format;
6275a4a43f8Sjmcneill 	sc->sc_dai.dai_hw_if = &rk_i2s_hw_if;
6285a4a43f8Sjmcneill 	sc->sc_dai.dai_dev = self;
6295a4a43f8Sjmcneill 	sc->sc_dai.dai_priv = sc;
6305a4a43f8Sjmcneill 	fdtbus_register_dai_controller(self, phandle, &rk_i2s_dai_funcs);
6315a4a43f8Sjmcneill }
6325a4a43f8Sjmcneill 
6335a4a43f8Sjmcneill CFATTACH_DECL_NEW(rk_i2s, sizeof(struct rk_i2s_softc),
6345a4a43f8Sjmcneill     rk_i2s_match, rk_i2s_attach, NULL, NULL);
635