Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 29 Dec 2016 14:00:10 +0000 (UTC)
From:      Jared McNeill <jmcneill@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r310776 - head/sys/mips/ingenic
Message-ID:  <201612291400.uBTE0AOX026001@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jmcneill
Date: Thu Dec 29 14:00:10 2016
New Revision: 310776
URL: https://svnweb.freebsd.org/changeset/base/310776

Log:
  The JZ4780 I2S can feed either the internal audio codec or the HDMI
  transmitter, but not both at the same time. This patch:
  
   - Adds a dev.pcm.0.internal_codec sysctl node for selecting between
     internal and external codec
   - Changes playback sample rate from 96 kHz to 48 kHz for HDMI compatibility
   - Enables i2s clock on codec access
  
  Reviewed by:		br
  Differential Revision:	https://reviews.freebsd.org/D8960

Modified:
  head/sys/mips/ingenic/jz4780_aic.c
  head/sys/mips/ingenic/jz4780_codec.c
  head/sys/mips/ingenic/jz4780_codec.h

Modified: head/sys/mips/ingenic/jz4780_aic.c
==============================================================================
--- head/sys/mips/ingenic/jz4780_aic.c	Thu Dec 29 13:27:04 2016	(r310775)
+++ head/sys/mips/ingenic/jz4780_aic.c	Thu Dec 29 14:00:10 2016	(r310776)
@@ -81,6 +81,7 @@ struct aic_softc {
 	void			*ih;
 	struct xdma_channel	*xchan;
 	xdma_controller_t	*xdma_tx;
+	int			internal_codec;
 };
 
 /* Channel registers */
@@ -120,7 +121,7 @@ struct aic_rate {
 };
 
 static struct aic_rate rate_map[] = {
-	{ 96000 },
+	{ 48000 },
 	/* TODO: add more frequences */
 	{ 0 },
 };
@@ -355,7 +356,6 @@ aic_start(struct sc_pcminfo *scp)
 	int reg;
 
 	sc = scp->sc;
-	sc->pos = 0;
 
 	/* Ensure clock enabled. */
 	reg = READ4(sc, I2SCR);
@@ -387,10 +387,6 @@ aic_stop(struct sc_pcminfo *scp)
 
 	xdma_terminate(sc->xchan);
 
-	sc->pos = 0;
-
-	bzero(sc->buf_base, sc->dma_size);
-
 	return (0);
 }
 
@@ -411,6 +407,8 @@ aicchan_trigger(kobj_t obj, void *data, 
 	case PCMTRIG_START:
 		ch->run = 1;
 
+		sc->pos = 0;
+
 		aic_start(scp);
 
 		break;
@@ -421,6 +419,10 @@ aicchan_trigger(kobj_t obj, void *data, 
 
 		aic_stop(scp);
 
+		sc->pos = 0;
+
+		bzero(sc->buf_base, sc->dma_size);
+
 		break;
 	}
 
@@ -448,7 +450,7 @@ static uint32_t aic_pfmt[] = {
 	0
 };
 
-static struct pcmchan_caps aic_pcaps = {96000, 96000, aic_pfmt, 0};
+static struct pcmchan_caps aic_pcaps = {48000, 48000, aic_pfmt, 0};
 
 static struct pcmchan_caps *
 aicchan_getcaps(kobj_t obj, void *data)
@@ -583,16 +585,13 @@ aic_configure_clocks(struct aic_softc *s
 static int
 aic_configure(struct aic_softc *sc)
 {
-	int internal_codec;
 	int reg;
 
-	internal_codec = 1;
-
 	WRITE4(sc, AICFR, AICFR_RST);
 
 	/* Configure AIC */
 	reg = 0;
-	if (internal_codec) {
+	if (sc->internal_codec) {
 		reg |= (AICFR_ICDC);
 	} else {
 		reg |= (AICFR_SYNCD | AICFR_BCKD);
@@ -610,6 +609,48 @@ aic_configure(struct aic_softc *sc)
 }
 
 static int
+sysctl_hw_pcm_internal_codec(SYSCTL_HANDLER_ARGS)
+{
+	struct sc_pcminfo *scp;
+	struct sc_chinfo *ch;
+	struct aic_softc *sc;
+	int error, val;
+
+	if (arg1 == NULL)
+		return (EINVAL);
+
+	scp = arg1;
+	sc = scp->sc;
+	ch = &scp->chan[0];
+
+	snd_mtxlock(sc->lock);
+
+	val = sc->internal_codec;
+	error = sysctl_handle_int(oidp, &val, 0, req);
+	if (error || req->newptr == NULL) {
+		snd_mtxunlock(sc->lock);
+		return (error);
+	}
+	if (val < 0 || val > 1) {
+		snd_mtxunlock(sc->lock);
+		return (EINVAL);
+	}
+
+	if (sc->internal_codec != val) {
+		sc->internal_codec = val;
+		if (ch->run)
+			aic_stop(scp);
+		aic_configure(sc);
+		if (ch->run)
+			aic_start(scp);
+	}
+
+	snd_mtxunlock(sc->lock);
+
+	return (0);
+}
+
+static int
 aic_probe(device_t dev)
 {
 
@@ -635,6 +676,7 @@ aic_attach(device_t dev)
 	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
 	sc->dev = dev;
 	sc->pos = 0;
+	sc->internal_codec = 1;
 
 	/* Get xDMA controller */
 	sc->xdma_tx = xdma_ofw_get(sc->dev, "tx");
@@ -718,6 +760,13 @@ aic_attach(device_t dev)
 
 	mixer_init(dev, &aicmixer_class, scp);
 
+	/* Create device sysctl node. */
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "internal_codec", CTLTYPE_INT | CTLFLAG_RW,
+	    scp, 0, sysctl_hw_pcm_internal_codec, "I",
+	    "use internal audio codec");
+
 	return (0);
 }
 

Modified: head/sys/mips/ingenic/jz4780_codec.c
==============================================================================
--- head/sys/mips/ingenic/jz4780_codec.c	Thu Dec 29 13:27:04 2016	(r310775)
+++ head/sys/mips/ingenic/jz4780_codec.c	Thu Dec 29 14:00:10 2016	(r310776)
@@ -53,6 +53,8 @@ __FBSDID("$FreeBSD$");
 
 #include <dev/gpio/gpiobusvar.h>
 
+#include <dev/extres/clk/clk.h>
+
 #include <mips/ingenic/jz4780_common.h>
 #include <mips/ingenic/jz4780_codec.h>
 
@@ -64,6 +66,7 @@ struct codec_softc {
 	struct resource		*res[1];
 	bus_space_tag_t		bst;
 	bus_space_handle_t	bsh;
+	clk_t			clk;
 };
 
 static struct resource_spec codec_spec[] = {
@@ -81,6 +84,8 @@ codec_write(struct codec_softc *sc, uint
 {
 	uint32_t tmp;
 
+	clk_enable(sc->clk);
+
 	tmp = (reg << RGADW_RGADDR_S);
 	tmp |= (val << RGADW_RGDIN_S);
 	tmp |= RGADW_RGWR;
@@ -90,6 +95,8 @@ codec_write(struct codec_softc *sc, uint
 	while(READ4(sc, CODEC_RGADW) & RGADW_RGWR)
 		;
 
+	clk_disable(sc->clk);
+
 	return (0);
 }
 
@@ -98,11 +105,15 @@ codec_read(struct codec_softc *sc, uint3
 {
 	uint32_t tmp;
 
+	clk_enable(sc->clk);
+
 	tmp = (reg << RGADW_RGADDR_S);
 	WRITE4(sc, CODEC_RGADW, tmp);
 
 	tmp = READ4(sc, CODEC_RGDATA);
 
+	clk_disable(sc->clk);
+
 	return (tmp);
 }
 
@@ -223,6 +234,12 @@ codec_attach(device_t dev)
 	sc->bst = rman_get_bustag(sc->res[0]);
 	sc->bsh = rman_get_bushandle(sc->res[0]);
 
+	if (clk_get_by_ofw_name(dev, 0, "i2s", &sc->clk) != 0) {
+		device_printf(dev, "could not get i2s clock\n");
+		bus_release_resources(dev, codec_spec, sc->res);
+		return (ENXIO);
+	}
+
 	/* Initialize codec. */
 	reg = codec_read(sc, CR_VIC);
 	reg &= ~(VIC_SB_SLEEP | VIC_SB);
@@ -236,7 +253,7 @@ codec_attach(device_t dev)
 
 	DELAY(10000);
 
-	/* I2S, 16-bit, 96 kHz. */
+	/* I2S, 16-bit, 48 kHz. */
 	reg = codec_read(sc, AICR_DAC);
 	reg &= ~(AICR_DAC_SB | DAC_ADWL_M);
 	reg |= DAC_ADWL_16;
@@ -246,7 +263,7 @@ codec_attach(device_t dev)
 
 	DELAY(10000);
 
-	reg = FCR_DAC_96;
+	reg = FCR_DAC_48;
 	codec_write(sc, FCR_DAC, reg);
 
 	DELAY(10000);

Modified: head/sys/mips/ingenic/jz4780_codec.h
==============================================================================
--- head/sys/mips/ingenic/jz4780_codec.h	Thu Dec 29 13:27:04 2016	(r310775)
+++ head/sys/mips/ingenic/jz4780_codec.h	Thu Dec 29 14:00:10 2016	(r310776)
@@ -74,6 +74,7 @@
 #define	 VIC_SB		(1 << 0)	/* complete power-down */
 #define	CR_CK		0x1C	/* Clock Control Register */
 #define	FCR_DAC		0x1D	/* DAC Frequency Control Register */
+#define	 FCR_DAC_48	8	/* 48 kHz. */
 #define	 FCR_DAC_96	10	/* 96 kHz. */
 #define	FCR_ADC		0x20	/* ADC Frequency Control Register */
 #define	CR_TIMER_MSB	0x21	/* MSB of programmable counter */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201612291400.uBTE0AOX026001>