Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/arm/allwinner capture support



details:   https://anonhg.NetBSD.org/src/rev/14ce9409b551
branches:  trunk
changeset: 332102:14ce9409b551
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Sat Sep 06 22:48:19 2014 +0000

description:
capture support

diffstat:

 sys/arch/arm/allwinner/awin_ac.c |  238 ++++++++++++++++++++++++++++++++++++--
 1 files changed, 223 insertions(+), 15 deletions(-)

diffs (truncated from 385 to 300 lines):

diff -r 24e3e030c700 -r 14ce9409b551 sys/arch/arm/allwinner/awin_ac.c
--- a/sys/arch/arm/allwinner/awin_ac.c  Sat Sep 06 21:21:36 2014 +0000
+++ b/sys/arch/arm/allwinner/awin_ac.c  Sat Sep 06 22:48:19 2014 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: awin_ac.c,v 1.10 2014/09/06 20:54:53 jmcneill Exp $ */
+/* $NetBSD: awin_ac.c,v 1.11 2014/09/06 22:48:19 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2014 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -30,7 +30,7 @@
 #include "opt_ddb.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: awin_ac.c,v 1.10 2014/09/06 20:54:53 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: awin_ac.c,v 1.11 2014/09/06 22:48:19 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -47,6 +47,7 @@
 #include <arm/allwinner/awin_var.h>
 
 #define AWINAC_TX_TRIG_LEVEL   0xf
+#define AWINAC_RX_TRIG_LEVEL   0x7
 #define AWINAC_DRQ_CLR_CNT     0x3
 #define AWINAC_INIT_VOL                0x3b
 
@@ -114,10 +115,46 @@
 #define  DAC_ACTL_PAVOL                __BITS(5,0)
 #define AC_DAC_TUNE            0x14
 #define AC_ADC_FIFOC           0x1c
+#define  ADC_FIFOC_FS          __BITS(31,29)
+#define   ADC_FS_48KHZ         0
+#define   ADC_FS_32KHZ         1
+#define   ADC_FS_24KHZ         2
+#define   ADC_FS_16KHZ         3
+#define   ADC_FS_12KHZ         4
+#define   DAC_FS_8KHZ          5
+#define  ADC_FIFOC_EN_AD       __BIT(28)
+#define  ADC_FIFOC_RX_FIFO_MODE        __BIT(24)
+#define  ADC_FIFOC_RX_TRIG_LEVEL __BITS(12,8)
+#define  ADC_FIFOC_MONO_EN     __BIT(7)
+#define  ADC_FIFOC_RX_SAMPLE_BITS __BIT(6)
+#define  ADC_FIFOC_DRQ_EN      __BIT(4)
+#define  ADC_FIFOC_IRQ_EN      __BIT(3)
+#define  ADC_FIFOC_OVERRUN_IRQ_EN __BIT(2)
+#define  ADC_FIFOC_FIFO_FLUSH  __BIT(1)
 #define AC_ADC_FIFOS           0x20
+#define  ADC_FIFOS_RXA         __BIT(23)
+#define  ADC_FIFOS_RXA_CNT     __BITS(13,8)
+#define  ADC_FIFOS_RXA_INT     __BIT(3)
+#define  ADC_FIFOS_RXO_INT     __BIT(1)
 #define AC_ADC_RXDATA          0x24
 #define AC_ADC_ACTL            0x28
+#define  ADC_ACTL_ADCREN       __BIT(31)
+#define  ADC_ACTL_ADCLEN       __BIT(30)
+#define  ADC_ACTL_PREG1EN      __BIT(29)
+#define  ADC_ACTL_PREG2EN      __BIT(28)
+#define  ADC_ACTL_VMICEN       __BIT(27)
+#define  ADC_ACTL_ADCG         __BITS(22,20)
+#define  ADC_ACTL_ADCIS                __BITS(19,17)
+#define  ADC_ACTL_LNRDF                __BIT(16)
+#define  ADC_ACTL_LNPREG       __BIT(15)
+#define  ADC_ACTL_LHPOUTN      __BIT(11)
+#define  ADC_ACTL_RHPOUTN      __BIT(10)
+#define  ADC_ACTL_DITHER       __BIT(8)
+#define  ADC_ACTL_DITHER_CLK_SELECT __BITS(7,6)
 #define  ADC_ACTL_PA_EN                __BIT(4)
+#define  ADC_ACTL_DDE          __BIT(3)
+#define  ADC_ACTL_COMPTEN      __BIT(2)
+#define  ADC_ACTL_PTDBS                __BITS(1,0)
 #define AC_DAC_CNT             0x30
 #define AC_ADC_CNT             0x34
 #define AC_DAC_CAL             0x38
@@ -149,9 +186,6 @@
        struct audio_encoding_set *sc_encodings;
 
        audio_params_t          sc_pparam;
-
-       void *                  sc_ih;
-
        struct awin_dma_channel *sc_pdma;
        void                    (*sc_pint)(void *);
        void                    *sc_pintarg;
@@ -160,6 +194,15 @@
        bus_addr_t              sc_pcur;
        int                     sc_pblksize;
 
+       audio_params_t          sc_rparam;
+       struct awin_dma_channel *sc_rdma;
+       void                    (*sc_rint)(void *);
+       void                    *sc_rintarg;
+       bus_addr_t              sc_rstart;
+       bus_addr_t              sc_rend;
+       bus_addr_t              sc_rcur;
+       int                     sc_rblksize;
+
        struct awin_gpio_pindata sc_pactrl_gpio;
        bool                    sc_has_pactrl_gpio;
 };
@@ -176,6 +219,8 @@
 
 static void    awinac_pint(void *);
 static int     awinac_play(struct awinac_softc *);
+static void    awinac_rint(void *);
+static int     awinac_rec(struct awinac_softc *);
 
 #if defined(DDB)
 void           awinac_dump_regs(void);
@@ -313,7 +358,12 @@
 
        sc->sc_pdma = awin_dma_alloc(AWIN_DMA_TYPE_NDMA, awinac_pint, sc);
        if (sc->sc_pdma == NULL) {
-               aprint_error_dev(self, "couldn't allocate DMA channel\n");
+               aprint_error_dev(self, "couldn't allocate play DMA channel\n");
+               return;
+       }
+       sc->sc_rdma = awin_dma_alloc(AWIN_DMA_TYPE_NDMA, awinac_rint, sc);
+       if (sc->sc_rdma == NULL) {
+               aprint_error_dev(self, "couldn't allocate rec DMA channel\n");
                return;
        }
 
@@ -386,7 +436,14 @@
        val &= ~DAC_FIFOC_FIFO_OVERRUN_IRQ_EN;
        AC_WRITE(sc, AC_DAC_FIFOC, val);
 
+       val = AC_READ(sc, AC_ADC_FIFOC);
+       val &= ~ADC_FIFOC_DRQ_EN;
+       val &= ~ADC_FIFOC_IRQ_EN;
+       val &= ~ADC_FIFOC_OVERRUN_IRQ_EN;
+       AC_WRITE(sc, AC_ADC_FIFOC, val);
+
        AC_WRITE(sc, AC_DAC_FIFOS, AC_READ(sc, AC_DAC_FIFOS));
+       AC_WRITE(sc, AC_ADC_FIFOS, AC_READ(sc, AC_ADC_FIFOS));
 }
 
 static int
@@ -474,15 +531,61 @@
        return 0;
 }
 
+static void
+awinac_rint(void *priv)
+{
+       struct awinac_softc *sc = priv;
+
+       mutex_enter(&sc->sc_intr_lock);
+       if (sc->sc_rint == NULL) {
+               mutex_exit(&sc->sc_intr_lock);
+               return;
+       }
+       sc->sc_rint(sc->sc_rintarg);
+       mutex_exit(&sc->sc_intr_lock);
+
+       awinac_rec(sc);
+}
+
+static int
+awinac_rec(struct awinac_softc *sc)
+{
+       int error;
+
+       error = awin_dma_transfer(sc->sc_rdma,
+           AWIN_CORE_PBASE + AWIN_AC_OFFSET + AC_ADC_RXDATA, sc->sc_rcur,
+           sc->sc_rblksize);
+       if (error) {
+               device_printf(sc->sc_dev, "failed to transfer DMA; error %d\n",
+                   error);
+               return error;
+       }
+
+       sc->sc_rcur += sc->sc_rblksize;
+       if (sc->sc_rcur >= sc->sc_rend)
+               sc->sc_rcur = sc->sc_rstart;
+
+       return 0;
+}
+
 static int
 awinac_open(void *priv, int flags)
 {
+       struct awinac_softc *sc = priv;
+
+       if (sc->sc_has_pactrl_gpio)
+               awin_gpio_pindata_write(&sc->sc_pactrl_gpio, 1);
+
        return 0;
 }
 
 static void
 awinac_close(void *priv)
 {
+       struct awinac_softc *sc = priv;
+
+       if (sc->sc_has_pactrl_gpio)
+               awin_gpio_pindata_write(&sc->sc_pactrl_gpio, 0);
 }
 
 static int
@@ -495,6 +598,10 @@
        val |= DAC_FIFOC_FIFO_FLUSH;
        AC_WRITE(sc, AC_DAC_FIFOC, val);
 
+       val = AC_READ(sc, AC_ADC_FIFOC);
+       val |= ADC_FIFOC_FIFO_FLUSH;
+       AC_WRITE(sc, AC_ADC_FIFOC, val);
+
        return 0;
 }
 
@@ -523,6 +630,15 @@
                    pfil->filters[0].param :
                    *play;
        }
+       if (rec && (setmode & AUMODE_RECORD)) {
+               index = auconv_set_converter(&sc->sc_format, 1,
+                   AUMODE_RECORD, rec, true, rfil);
+               if (index < 0)
+                       return EINVAL;
+               sc->sc_rparam = rfil->req_size > 0 ?
+                   rfil->filters[0].param :
+                   *rec;
+       }
 
        return 0;
 }
@@ -537,6 +653,10 @@
                return EINVAL;
        if (sc->sc_pparam.validbits != 16 && sc->sc_pparam.validbits != 24)
                return EINVAL;
+       if (sc->sc_rparam.sample_rate != 48000)
+               return EINVAL;
+       if (sc->sc_rparam.validbits != 16 && sc->sc_rparam.validbits != 24)
+               return EINVAL;
 
        val = AC_READ(sc, AC_DAC_FIFOC);
        val &= ~DAC_FIFOC_FIR_VER;
@@ -558,6 +678,21 @@
        }
        AC_WRITE(sc, AC_DAC_FIFOC, val);
 
+       val = AC_READ(sc, AC_ADC_FIFOC);
+       val |= ADC_FIFOC_EN_AD;
+       val |= ADC_FIFOC_RX_FIFO_MODE;
+       val &= ~ADC_FIFOC_FS;
+       val |= __SHIFTIN(ADC_FS_48KHZ, ADC_FIFOC_FS);
+       val &= ~ADC_FIFOC_RX_TRIG_LEVEL;
+       val |= __SHIFTIN(AWINAC_RX_TRIG_LEVEL, ADC_FIFOC_RX_TRIG_LEVEL);
+       val &= ~ADC_FIFOC_MONO_EN;
+       if (sc->sc_rparam.validbits == 16) {
+               val &= ~ADC_FIFOC_RX_SAMPLE_BITS;
+       } else {
+               val |= ADC_FIFOC_RX_SAMPLE_BITS;
+       }
+       AC_WRITE(sc, AC_ADC_FIFOC, val);
+
        return 0;
 }
 
@@ -569,9 +704,6 @@
 
        awin_dma_halt(sc->sc_pdma);
 
-       if (sc->sc_has_pactrl_gpio)
-               awin_gpio_pindata_write(&sc->sc_pactrl_gpio, 0);
-
        val = AC_READ(sc, AC_DAC_ACTL);
        val &= ~DAC_ACTL_DACAREN;
        val &= ~DAC_ACTL_DACALEN;
@@ -591,7 +723,24 @@
 static int
 awinac_halt_input(void *priv)
 {
-       return EINVAL;
+       struct awinac_softc *sc = priv;
+       uint32_t val;
+
+       awin_dma_halt(sc->sc_rdma);
+
+       val = AC_READ(sc, AC_ADC_ACTL);
+       val &= ~ADC_ACTL_ADCREN;
+       val &= ~ADC_ACTL_ADCLEN;
+       AC_WRITE(sc, AC_ADC_ACTL, val);
+
+       val = AC_READ(sc, AC_ADC_FIFOC);
+       val &= ~ADC_FIFOC_DRQ_EN;
+       AC_WRITE(sc, AC_ADC_FIFOC, val);
+
+       sc->sc_rint = NULL;
+       sc->sc_rintarg = NULL;
+       
+       return 0;
 }
 
 static int
@@ -744,7 +893,8 @@
 awinac_get_props(void *priv)
 {
        return AUDIO_PROP_PLAYBACK|AUDIO_PROP_CAPTURE|
-              AUDIO_PROP_INDEPENDENT|AUDIO_PROP_MMAP;



Home | Main Index | Thread Index | Old Index