The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arm/allwinner/a10_codec.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2014-2016 Jared D. McNeill <jmcneill@invisible.ca>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   19  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   21  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   22  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * $FreeBSD$
   27  */
   28 
   29 /*
   30  * Allwinner A10/A20 and H3 Audio Codec
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD$");
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/bus.h>
   39 #include <sys/rman.h>
   40 #include <sys/condvar.h>
   41 #include <sys/kernel.h>
   42 #include <sys/module.h>
   43 #include <sys/gpio.h>
   44 
   45 #include <machine/bus.h>
   46 
   47 #include <dev/sound/pcm/sound.h>
   48 #include <dev/sound/chip.h>
   49 
   50 #include <dev/ofw/ofw_bus.h>
   51 #include <dev/ofw/ofw_bus_subr.h>
   52 
   53 #include <dev/gpio/gpiobusvar.h>
   54 
   55 #include <dev/extres/clk/clk.h>
   56 #include <dev/extres/hwreset/hwreset.h>
   57 
   58 #include "sunxi_dma_if.h"
   59 #include "mixer_if.h"
   60 
   61 struct a10codec_info;
   62 
   63 struct a10codec_config {
   64         /* mixer class */
   65         struct kobj_class *mixer_class;
   66 
   67         /* toggle DAC/ADC mute */
   68         void            (*mute)(struct a10codec_info *, int, int);
   69 
   70         /* DRQ types */
   71         u_int           drqtype_codec;
   72         u_int           drqtype_sdram;
   73 
   74         /* register map */
   75         bus_size_t      DPC,
   76                         DAC_FIFOC,
   77                         DAC_FIFOS,
   78                         DAC_TXDATA,
   79                         ADC_FIFOC,
   80                         ADC_FIFOS,
   81                         ADC_RXDATA,
   82                         DAC_CNT,
   83                         ADC_CNT;
   84 };
   85 
   86 #define TX_TRIG_LEVEL   0xf
   87 #define RX_TRIG_LEVEL   0x7
   88 #define DRQ_CLR_CNT     0x3
   89 
   90 #define AC_DAC_DPC(_sc)         ((_sc)->cfg->DPC)       
   91 #define  DAC_DPC_EN_DA                  0x80000000
   92 #define AC_DAC_FIFOC(_sc)       ((_sc)->cfg->DAC_FIFOC)
   93 #define  DAC_FIFOC_FS_SHIFT             29
   94 #define  DAC_FIFOC_FS_MASK              (7U << DAC_FIFOC_FS_SHIFT)
   95 #define   DAC_FS_48KHZ                  0
   96 #define   DAC_FS_32KHZ                  1
   97 #define   DAC_FS_24KHZ                  2
   98 #define   DAC_FS_16KHZ                  3
   99 #define   DAC_FS_12KHZ                  4
  100 #define   DAC_FS_8KHZ                   5
  101 #define   DAC_FS_192KHZ                 6
  102 #define   DAC_FS_96KHZ                  7
  103 #define  DAC_FIFOC_FIFO_MODE_SHIFT      24
  104 #define  DAC_FIFOC_FIFO_MODE_MASK       (3U << DAC_FIFOC_FIFO_MODE_SHIFT)
  105 #define   FIFO_MODE_24_31_8             0
  106 #define   FIFO_MODE_16_31_16            0
  107 #define   FIFO_MODE_16_15_0             1
  108 #define  DAC_FIFOC_DRQ_CLR_CNT_SHIFT    21
  109 #define  DAC_FIFOC_DRQ_CLR_CNT_MASK     (3U << DAC_FIFOC_DRQ_CLR_CNT_SHIFT)
  110 #define  DAC_FIFOC_TX_TRIG_LEVEL_SHIFT  8
  111 #define  DAC_FIFOC_TX_TRIG_LEVEL_MASK   (0x7f << DAC_FIFOC_TX_TRIG_LEVEL_SHIFT)
  112 #define  DAC_FIFOC_MONO_EN              (1U << 6)
  113 #define  DAC_FIFOC_TX_BITS              (1U << 5)
  114 #define  DAC_FIFOC_DRQ_EN               (1U << 4)
  115 #define  DAC_FIFOC_FIFO_FLUSH           (1U << 0)
  116 #define AC_DAC_FIFOS(_sc)       ((_sc)->cfg->DAC_FIFOS)
  117 #define AC_DAC_TXDATA(_sc)      ((_sc)->cfg->DAC_TXDATA)
  118 #define AC_ADC_FIFOC(_sc)       ((_sc)->cfg->ADC_FIFOC)
  119 #define  ADC_FIFOC_FS_SHIFT             29
  120 #define  ADC_FIFOC_FS_MASK              (7U << ADC_FIFOC_FS_SHIFT)
  121 #define   ADC_FS_48KHZ          0
  122 #define  ADC_FIFOC_EN_AD                (1U << 28)
  123 #define  ADC_FIFOC_RX_FIFO_MODE         (1U << 24)
  124 #define  ADC_FIFOC_RX_TRIG_LEVEL_SHIFT  8
  125 #define  ADC_FIFOC_RX_TRIG_LEVEL_MASK   (0x1f << ADC_FIFOC_RX_TRIG_LEVEL_SHIFT)
  126 #define  ADC_FIFOC_MONO_EN              (1U << 7)
  127 #define  ADC_FIFOC_RX_BITS              (1U << 6)
  128 #define  ADC_FIFOC_DRQ_EN               (1U << 4)
  129 #define  ADC_FIFOC_FIFO_FLUSH           (1U << 1)
  130 #define AC_ADC_FIFOS(_sc)       ((_sc)->cfg->ADC_FIFOS)
  131 #define AC_ADC_RXDATA(_sc)      ((_sc)->cfg->ADC_RXDATA)
  132 #define AC_DAC_CNT(_sc)         ((_sc)->cfg->DAC_CNT)
  133 #define AC_ADC_CNT(_sc)         ((_sc)->cfg->ADC_CNT)
  134 
  135 static uint32_t a10codec_fmt[] = {
  136         SND_FORMAT(AFMT_S16_LE, 1, 0),
  137         SND_FORMAT(AFMT_S16_LE, 2, 0),
  138         0
  139 };
  140 
  141 static struct pcmchan_caps a10codec_pcaps = { 8000, 192000, a10codec_fmt, 0 };
  142 static struct pcmchan_caps a10codec_rcaps = { 8000, 48000, a10codec_fmt, 0 };
  143 
  144 struct a10codec_info;
  145 
  146 struct a10codec_chinfo {
  147         struct snd_dbuf         *buffer;
  148         struct pcm_channel      *channel;       
  149         struct a10codec_info    *parent;
  150         bus_dmamap_t            dmamap;
  151         void                    *dmaaddr;
  152         bus_addr_t              physaddr;
  153         bus_size_t              fifo;
  154         device_t                dmac;
  155         void                    *dmachan;
  156 
  157         int                     dir;
  158         int                     run;
  159         uint32_t                pos;
  160         uint32_t                format;
  161         uint32_t                blocksize;
  162         uint32_t                speed;
  163 };
  164 
  165 struct a10codec_info {
  166         device_t                dev;
  167         struct resource         *res[2];
  168         struct mtx              *lock;
  169         bus_dma_tag_t           dmat;
  170         unsigned                dmasize;
  171         void                    *ih;
  172 
  173         struct a10codec_config  *cfg;
  174 
  175         struct a10codec_chinfo  play;
  176         struct a10codec_chinfo  rec;
  177 };
  178 
  179 static struct resource_spec a10codec_spec[] = {
  180         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
  181         { -1, 0 }
  182 };
  183 
  184 #define CODEC_ANALOG_READ(sc, reg)              bus_read_4((sc)->res[1], (reg))
  185 #define CODEC_ANALOG_WRITE(sc, reg, val)        bus_write_4((sc)->res[1], (reg), (val))
  186 
  187 #define CODEC_READ(sc, reg)             bus_read_4((sc)->res[0], (reg))
  188 #define CODEC_WRITE(sc, reg, val)       bus_write_4((sc)->res[0], (reg), (val))
  189 
  190 /*
  191  * A10/A20 mixer interface
  192  */
  193 
  194 #define A10_DAC_ACTL    0x10
  195 #define  A10_DACAREN                    (1U << 31)
  196 #define  A10_DACALEN                    (1U << 30)
  197 #define  A10_MIXEN                      (1U << 29)
  198 #define  A10_DACPAS                     (1U << 8)
  199 #define  A10_PAMUTE                     (1U << 6)
  200 #define  A10_PAVOL_SHIFT                0
  201 #define  A10_PAVOL_MASK                 (0x3f << A10_PAVOL_SHIFT)
  202 #define A10_ADC_ACTL    0x28
  203 #define  A10_ADCREN                     (1U << 31)
  204 #define  A10_ADCLEN                     (1U << 30)
  205 #define  A10_PREG1EN                    (1U << 29)
  206 #define  A10_PREG2EN                    (1U << 28)
  207 #define  A10_VMICEN                     (1U << 27)
  208 #define  A10_ADCG_SHIFT                 20
  209 #define  A10_ADCG_MASK                  (7U << A10_ADCG_SHIFT)
  210 #define  A10_ADCIS_SHIFT                17
  211 #define  A10_ADCIS_MASK                 (7U << A10_ADCIS_SHIFT)
  212 #define   A10_ADC_IS_LINEIN                     0
  213 #define   A10_ADC_IS_FMIN                       1
  214 #define   A10_ADC_IS_MIC1                       2
  215 #define   A10_ADC_IS_MIC2                       3
  216 #define   A10_ADC_IS_MIC1_L_MIC2_R              4
  217 #define   A10_ADC_IS_MIC1_LR_MIC2_LR            5
  218 #define   A10_ADC_IS_OMIX                       6
  219 #define   A10_ADC_IS_LINEIN_L_MIC1_R            7
  220 #define  A10_LNRDF                      (1U << 16)
  221 #define  A10_LNPREG_SHIFT               13
  222 #define  A10_LNPREG_MASK                (7U << A10_LNPREG_SHIFT)
  223 #define  A10_PA_EN                      (1U << 4)
  224 #define  A10_DDE                        (1U << 3)
  225 
  226 static int
  227 a10_mixer_init(struct snd_mixer *m)
  228 {
  229         struct a10codec_info *sc = mix_getdevinfo(m);
  230         uint32_t val;
  231 
  232         mix_setdevs(m, SOUND_MASK_VOLUME | SOUND_MASK_LINE | SOUND_MASK_RECLEV);
  233         mix_setrecdevs(m, SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC);
  234 
  235         /* Unmute input source to PA */
  236         val = CODEC_READ(sc, A10_DAC_ACTL);
  237         val |= A10_PAMUTE;
  238         CODEC_WRITE(sc, A10_DAC_ACTL, val);
  239 
  240         /* Enable PA */
  241         val = CODEC_READ(sc, A10_ADC_ACTL);
  242         val |= A10_PA_EN;
  243         CODEC_WRITE(sc, A10_ADC_ACTL, val);
  244 
  245         return (0);
  246 }
  247 
  248 static const struct a10_mixer {
  249         unsigned reg;
  250         unsigned mask;
  251         unsigned shift;
  252 } a10_mixers[SOUND_MIXER_NRDEVICES] = {
  253         [SOUND_MIXER_VOLUME]    = { A10_DAC_ACTL, A10_PAVOL_MASK,
  254                                     A10_PAVOL_SHIFT },
  255         [SOUND_MIXER_LINE]      = { A10_ADC_ACTL, A10_LNPREG_MASK,
  256                                     A10_LNPREG_SHIFT },
  257         [SOUND_MIXER_RECLEV]    = { A10_ADC_ACTL, A10_ADCG_MASK,
  258                                     A10_ADCG_SHIFT },
  259 }; 
  260 
  261 static int
  262 a10_mixer_set(struct snd_mixer *m, unsigned dev, unsigned left,
  263     unsigned right)
  264 {
  265         struct a10codec_info *sc = mix_getdevinfo(m);
  266         uint32_t val;
  267         unsigned nvol, max;
  268 
  269         max = a10_mixers[dev].mask >> a10_mixers[dev].shift;
  270         nvol = (left * max) / 100;
  271 
  272         val = CODEC_READ(sc, a10_mixers[dev].reg);
  273         val &= ~a10_mixers[dev].mask;
  274         val |= (nvol << a10_mixers[dev].shift);
  275         CODEC_WRITE(sc, a10_mixers[dev].reg, val);
  276 
  277         left = right = (left * 100) / max;
  278         return (left | (right << 8));
  279 }
  280 
  281 static uint32_t
  282 a10_mixer_setrecsrc(struct snd_mixer *m, uint32_t src)
  283 {
  284         struct a10codec_info *sc = mix_getdevinfo(m);
  285         uint32_t val;
  286 
  287         val = CODEC_READ(sc, A10_ADC_ACTL);
  288 
  289         switch (src) {
  290         case SOUND_MASK_LINE:   /* line-in */
  291                 val &= ~A10_ADCIS_MASK;
  292                 val |= (A10_ADC_IS_LINEIN << A10_ADCIS_SHIFT);
  293                 break;
  294         case SOUND_MASK_MIC:    /* MIC1 */
  295                 val &= ~A10_ADCIS_MASK;
  296                 val |= (A10_ADC_IS_MIC1 << A10_ADCIS_SHIFT);
  297                 break;
  298         case SOUND_MASK_LINE1:  /* MIC2 */
  299                 val &= ~A10_ADCIS_MASK;
  300                 val |= (A10_ADC_IS_MIC2 << A10_ADCIS_SHIFT);
  301                 break;
  302         default:
  303                 break;
  304         }
  305 
  306         CODEC_WRITE(sc, A10_ADC_ACTL, val);
  307 
  308         switch ((val & A10_ADCIS_MASK) >> A10_ADCIS_SHIFT) {
  309         case A10_ADC_IS_LINEIN:
  310                 return (SOUND_MASK_LINE);
  311         case A10_ADC_IS_MIC1:
  312                 return (SOUND_MASK_MIC);
  313         case A10_ADC_IS_MIC2:
  314                 return (SOUND_MASK_LINE1);
  315         default:
  316                 return (0);
  317         }
  318 }
  319 
  320 static void
  321 a10_mute(struct a10codec_info *sc, int mute, int dir)
  322 {
  323         uint32_t val;
  324 
  325         if (dir == PCMDIR_PLAY) {
  326                 val = CODEC_READ(sc, A10_DAC_ACTL);
  327                 if (mute) {
  328                         /* Disable DAC analog l/r channels and output mixer */
  329                         val &= ~A10_DACAREN;
  330                         val &= ~A10_DACALEN;
  331                         val &= ~A10_DACPAS;
  332                 } else {
  333                         /* Enable DAC analog l/r channels and output mixer */
  334                         val |= A10_DACAREN;
  335                         val |= A10_DACALEN;
  336                         val |= A10_DACPAS;
  337                 }
  338                 CODEC_WRITE(sc, A10_DAC_ACTL, val);
  339         } else {
  340                 val = CODEC_READ(sc, A10_ADC_ACTL);
  341                 if (mute) {
  342                         /* Disable ADC analog l/r channels, MIC1 preamp,
  343                          * and VMIC pin voltage
  344                          */
  345                         val &= ~A10_ADCREN;
  346                         val &= ~A10_ADCLEN;
  347                         val &= ~A10_PREG1EN;
  348                         val &= ~A10_VMICEN;
  349                 } else {
  350                         /* Enable ADC analog l/r channels, MIC1 preamp,
  351                          * and VMIC pin voltage
  352                          */
  353                         val |= A10_ADCREN;
  354                         val |= A10_ADCLEN;
  355                         val |= A10_PREG1EN;
  356                         val |= A10_VMICEN;
  357                 }
  358                 CODEC_WRITE(sc, A10_ADC_ACTL, val);
  359         }
  360 }
  361 
  362 static kobj_method_t a10_mixer_methods[] = {
  363         KOBJMETHOD(mixer_init,          a10_mixer_init),
  364         KOBJMETHOD(mixer_set,           a10_mixer_set),
  365         KOBJMETHOD(mixer_setrecsrc,     a10_mixer_setrecsrc),
  366         KOBJMETHOD_END
  367 };
  368 MIXER_DECLARE(a10_mixer);
  369 
  370 /*
  371  * H3 mixer interface
  372  */
  373 
  374 #define H3_PR_CFG               0x00
  375 #define  H3_AC_PR_RST           (1 << 28)
  376 #define  H3_AC_PR_RW            (1 << 24)
  377 #define  H3_AC_PR_ADDR_SHIFT    16
  378 #define  H3_AC_PR_ADDR_MASK     (0x1f << H3_AC_PR_ADDR_SHIFT)
  379 #define  H3_ACDA_PR_WDAT_SHIFT  8
  380 #define  H3_ACDA_PR_WDAT_MASK   (0xff << H3_ACDA_PR_WDAT_SHIFT)
  381 #define  H3_ACDA_PR_RDAT_SHIFT  0
  382 #define  H3_ACDA_PR_RDAT_MASK   (0xff << H3_ACDA_PR_RDAT_SHIFT)
  383 
  384 #define H3_LOMIXSC              0x01
  385 #define  H3_LOMIXSC_LDAC        (1 << 1)
  386 #define H3_ROMIXSC              0x02
  387 #define  H3_ROMIXSC_RDAC        (1 << 1)
  388 #define H3_DAC_PA_SRC           0x03
  389 #define  H3_DACAREN             (1 << 7)
  390 #define  H3_DACALEN             (1 << 6)
  391 #define  H3_RMIXEN              (1 << 5)
  392 #define  H3_LMIXEN              (1 << 4)
  393 #define H3_LINEIN_GCTR          0x05
  394 #define  H3_LINEING_SHIFT       4
  395 #define  H3_LINEING_MASK        (0x7 << H3_LINEING_SHIFT)
  396 #define H3_MIC_GCTR             0x06
  397 #define  H3_MIC1_GAIN_SHIFT     4
  398 #define  H3_MIC1_GAIN_MASK      (0x7 << H3_MIC1_GAIN_SHIFT)
  399 #define  H3_MIC2_GAIN_SHIFT     0
  400 #define  H3_MIC2_GAIN_MASK      (0x7 << H3_MIC2_GAIN_SHIFT)
  401 #define H3_PAEN_CTR             0x07
  402 #define  H3_LINEOUTEN           (1 << 7)
  403 #define H3_LINEOUT_VOLC         0x09
  404 #define  H3_LINEOUTVOL_SHIFT    3
  405 #define  H3_LINEOUTVOL_MASK     (0x1f << H3_LINEOUTVOL_SHIFT)
  406 #define H3_MIC2G_LINEOUT_CTR    0x0a
  407 #define  H3_LINEOUT_LSEL        (1 << 3)
  408 #define  H3_LINEOUT_RSEL        (1 << 2)
  409 #define H3_LADCMIXSC            0x0c
  410 #define H3_RADCMIXSC            0x0d
  411 #define  H3_ADCMIXSC_MIC1       (1 << 6)
  412 #define  H3_ADCMIXSC_MIC2       (1 << 5)
  413 #define  H3_ADCMIXSC_LINEIN     (1 << 2)
  414 #define  H3_ADCMIXSC_OMIXER     (3 << 0)
  415 #define H3_ADC_AP_EN            0x0f
  416 #define  H3_ADCREN              (1 << 7)
  417 #define  H3_ADCLEN              (1 << 6)
  418 #define  H3_ADCG_SHIFT          0
  419 #define  H3_ADCG_MASK           (0x7 << H3_ADCG_SHIFT)
  420 
  421 static u_int 
  422 h3_pr_read(struct a10codec_info *sc, u_int addr)
  423 {
  424         uint32_t val;
  425 
  426         /* Read current value */
  427         val = CODEC_ANALOG_READ(sc, H3_PR_CFG);
  428 
  429         /* De-assert reset */
  430         val |= H3_AC_PR_RST;
  431         CODEC_ANALOG_WRITE(sc, H3_PR_CFG, val);
  432 
  433         /* Read mode */
  434         val &= ~H3_AC_PR_RW;
  435         CODEC_ANALOG_WRITE(sc, H3_PR_CFG, val);
  436 
  437         /* Set address */
  438         val &= ~H3_AC_PR_ADDR_MASK;
  439         val |= (addr << H3_AC_PR_ADDR_SHIFT);
  440         CODEC_ANALOG_WRITE(sc, H3_PR_CFG, val);
  441 
  442         /* Read data */
  443         return (CODEC_ANALOG_READ(sc , H3_PR_CFG) & H3_ACDA_PR_RDAT_MASK);
  444 }
  445 
  446 static void
  447 h3_pr_write(struct a10codec_info *sc, u_int addr, u_int data)
  448 {
  449         uint32_t val;
  450 
  451         /* Read current value */
  452         val = CODEC_ANALOG_READ(sc, H3_PR_CFG);
  453 
  454         /* De-assert reset */
  455         val |= H3_AC_PR_RST;
  456         CODEC_ANALOG_WRITE(sc, H3_PR_CFG, val);
  457 
  458         /* Set address */
  459         val &= ~H3_AC_PR_ADDR_MASK;
  460         val |= (addr << H3_AC_PR_ADDR_SHIFT);
  461         CODEC_ANALOG_WRITE(sc, H3_PR_CFG, val);
  462 
  463         /* Write data */
  464         val &= ~H3_ACDA_PR_WDAT_MASK;
  465         val |= (data << H3_ACDA_PR_WDAT_SHIFT);
  466         CODEC_ANALOG_WRITE(sc, H3_PR_CFG, val);
  467 
  468         /* Write mode */
  469         val |= H3_AC_PR_RW;
  470         CODEC_ANALOG_WRITE(sc, H3_PR_CFG, val);
  471 }
  472 
  473 static void
  474 h3_pr_set_clear(struct a10codec_info *sc, u_int addr, u_int set, u_int clr)
  475 {
  476         u_int old, new;
  477 
  478         old = h3_pr_read(sc, addr);
  479         new = set | (old & ~clr);
  480         h3_pr_write(sc, addr, new);
  481 }
  482 
  483 static int
  484 h3_mixer_init(struct snd_mixer *m)
  485 {
  486         int rid=1;
  487         pcell_t reg[2];
  488         phandle_t analogref;
  489         struct a10codec_info *sc = mix_getdevinfo(m);
  490 
  491         if (OF_getencprop(ofw_bus_get_node(sc->dev), "allwinner,codec-analog-controls",
  492             &analogref, sizeof(analogref)) <= 0) {
  493                 return (ENXIO);
  494         }
  495 
  496         if (OF_getencprop(OF_node_from_xref(analogref), "reg",
  497             reg, sizeof(reg)) <= 0) {
  498                 return (ENXIO);
  499         }
  500 
  501         sc->res[1] = bus_alloc_resource(sc->dev, SYS_RES_MEMORY, &rid, reg[0],
  502             reg[0]+reg[1], reg[1], RF_ACTIVE );
  503 
  504         if (sc->res[1] == NULL) {
  505                 return (ENXIO);
  506         }
  507 
  508         mix_setdevs(m, SOUND_MASK_PCM | SOUND_MASK_VOLUME | SOUND_MASK_RECLEV |
  509             SOUND_MASK_MIC | SOUND_MASK_LINE | SOUND_MASK_LINE1);
  510         mix_setrecdevs(m, SOUND_MASK_MIC | SOUND_MASK_LINE | SOUND_MASK_LINE1 |
  511             SOUND_MASK_IMIX);
  512 
  513         pcm_setflags(sc->dev, pcm_getflags(sc->dev) | SD_F_SOFTPCMVOL);
  514 
  515         /* Right & Left LINEOUT enable */
  516         h3_pr_set_clear(sc, H3_PAEN_CTR, H3_LINEOUTEN, 0);
  517         h3_pr_set_clear(sc, H3_MIC2G_LINEOUT_CTR,
  518             H3_LINEOUT_LSEL | H3_LINEOUT_RSEL, 0);
  519 
  520         return (0);
  521 }
  522 
  523 static const struct h3_mixer {
  524         unsigned reg;
  525         unsigned mask;
  526         unsigned shift;
  527 } h3_mixers[SOUND_MIXER_NRDEVICES] = {
  528         [SOUND_MIXER_VOLUME]    = { H3_LINEOUT_VOLC, H3_LINEOUTVOL_MASK,
  529                                     H3_LINEOUTVOL_SHIFT },
  530         [SOUND_MIXER_RECLEV]    = { H3_ADC_AP_EN, H3_ADCG_MASK,
  531                                     H3_ADCG_SHIFT },
  532         [SOUND_MIXER_LINE]      = { H3_LINEIN_GCTR, H3_LINEING_MASK,
  533                                     H3_LINEING_SHIFT },
  534         [SOUND_MIXER_MIC]       = { H3_MIC_GCTR, H3_MIC1_GAIN_MASK,
  535                                     H3_MIC1_GAIN_SHIFT },
  536         [SOUND_MIXER_LINE1]     = { H3_MIC_GCTR, H3_MIC2_GAIN_MASK,
  537                                     H3_MIC2_GAIN_SHIFT },
  538 };
  539 
  540 static int
  541 h3_mixer_set(struct snd_mixer *m, unsigned dev, unsigned left,
  542     unsigned right)
  543 {
  544         struct a10codec_info *sc = mix_getdevinfo(m);
  545         unsigned nvol, max;
  546 
  547         max = h3_mixers[dev].mask >> h3_mixers[dev].shift;
  548         nvol = (left * max) / 100;
  549 
  550         h3_pr_set_clear(sc, h3_mixers[dev].reg,
  551             nvol << h3_mixers[dev].shift, h3_mixers[dev].mask);
  552 
  553         left = right = (left * 100) / max;
  554         return (left | (right << 8));
  555 }
  556 
  557 static uint32_t
  558 h3_mixer_setrecsrc(struct snd_mixer *m, uint32_t src)
  559 {
  560         struct a10codec_info *sc = mix_getdevinfo(m);
  561         uint32_t val;
  562 
  563         val = 0;
  564         src &= (SOUND_MASK_LINE | SOUND_MASK_MIC |
  565             SOUND_MASK_LINE1 | SOUND_MASK_IMIX);
  566 
  567         if ((src & SOUND_MASK_LINE) != 0)       /* line-in */
  568                 val |= H3_ADCMIXSC_LINEIN;
  569         if ((src & SOUND_MASK_MIC) != 0)        /* MIC1 */
  570                 val |= H3_ADCMIXSC_MIC1;
  571         if ((src & SOUND_MASK_LINE1) != 0)      /* MIC2 */
  572                 val |= H3_ADCMIXSC_MIC2;
  573         if ((src & SOUND_MASK_IMIX) != 0)       /* l/r output mixer */
  574                 val |= H3_ADCMIXSC_OMIXER;
  575 
  576         h3_pr_write(sc, H3_LADCMIXSC, val);
  577         h3_pr_write(sc, H3_RADCMIXSC, val);
  578 
  579         return (src);
  580 }
  581 
  582 static void
  583 h3_mute(struct a10codec_info *sc, int mute, int dir)
  584 {
  585         if (dir == PCMDIR_PLAY) {
  586                 if (mute) {
  587                         /* Mute DAC l/r channels to output mixer */
  588                         h3_pr_set_clear(sc, H3_LOMIXSC, 0, H3_LOMIXSC_LDAC);
  589                         h3_pr_set_clear(sc, H3_ROMIXSC, 0, H3_ROMIXSC_RDAC);
  590                         /* Disable DAC analog l/r channels and output mixer */
  591                         h3_pr_set_clear(sc, H3_DAC_PA_SRC,
  592                             0, H3_DACAREN | H3_DACALEN | H3_RMIXEN | H3_LMIXEN);
  593                 } else {
  594                         /* Enable DAC analog l/r channels and output mixer */
  595                         h3_pr_set_clear(sc, H3_DAC_PA_SRC,
  596                             H3_DACAREN | H3_DACALEN | H3_RMIXEN | H3_LMIXEN, 0);
  597                         /* Unmute DAC l/r channels to output mixer */
  598                         h3_pr_set_clear(sc, H3_LOMIXSC, H3_LOMIXSC_LDAC, 0);
  599                         h3_pr_set_clear(sc, H3_ROMIXSC, H3_ROMIXSC_RDAC, 0);
  600                 }
  601         } else {
  602                 if (mute) {
  603                         /* Disable ADC analog l/r channels */
  604                         h3_pr_set_clear(sc, H3_ADC_AP_EN,
  605                             0, H3_ADCREN | H3_ADCLEN);
  606                 } else {
  607                         /* Enable ADC analog l/r channels */
  608                         h3_pr_set_clear(sc, H3_ADC_AP_EN,
  609                             H3_ADCREN | H3_ADCLEN, 0);
  610                 }
  611         }
  612 }
  613 
  614 static kobj_method_t h3_mixer_methods[] = {
  615         KOBJMETHOD(mixer_init,          h3_mixer_init),
  616         KOBJMETHOD(mixer_set,           h3_mixer_set),
  617         KOBJMETHOD(mixer_setrecsrc,     h3_mixer_setrecsrc),
  618         KOBJMETHOD_END
  619 };
  620 MIXER_DECLARE(h3_mixer);
  621 
  622 /*
  623  * Channel interface
  624  */
  625 
  626 static void
  627 a10codec_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
  628 {
  629         struct a10codec_chinfo *ch = arg;
  630 
  631         if (error != 0)
  632                 return;
  633 
  634         ch->physaddr = segs[0].ds_addr;
  635 }
  636 
  637 static void
  638 a10codec_transfer(struct a10codec_chinfo *ch)
  639 {
  640         bus_addr_t src, dst;
  641         int error;
  642 
  643         if (ch->dir == PCMDIR_PLAY) {
  644                 src = ch->physaddr + ch->pos;
  645                 dst = ch->fifo;
  646         } else {
  647                 src = ch->fifo;
  648                 dst = ch->physaddr + ch->pos;
  649         }
  650 
  651         error = SUNXI_DMA_TRANSFER(ch->dmac, ch->dmachan, src, dst,
  652             ch->blocksize);
  653         if (error) {
  654                 ch->run = 0;
  655                 device_printf(ch->parent->dev, "DMA transfer failed: %d\n",
  656                     error);
  657         }
  658 }
  659 
  660 static void
  661 a10codec_dmaconfig(struct a10codec_chinfo *ch)
  662 {
  663         struct a10codec_info *sc = ch->parent;
  664         struct sunxi_dma_config conf;
  665 
  666         memset(&conf, 0, sizeof(conf));
  667         conf.src_width = conf.dst_width = 16;
  668         conf.src_burst_len = conf.dst_burst_len = 4;
  669 
  670         if (ch->dir == PCMDIR_PLAY) {
  671                 conf.dst_noincr = true;
  672                 conf.src_drqtype = sc->cfg->drqtype_sdram;
  673                 conf.dst_drqtype = sc->cfg->drqtype_codec;
  674         } else {
  675                 conf.src_noincr = true;
  676                 conf.src_drqtype = sc->cfg->drqtype_codec;
  677                 conf.dst_drqtype = sc->cfg->drqtype_sdram;
  678         }
  679 
  680         SUNXI_DMA_SET_CONFIG(ch->dmac, ch->dmachan, &conf);
  681 }
  682 
  683 static void
  684 a10codec_dmaintr(void *priv)
  685 {
  686         struct a10codec_chinfo *ch = priv;
  687         unsigned bufsize;
  688 
  689         bufsize = sndbuf_getsize(ch->buffer);
  690 
  691         ch->pos += ch->blocksize;
  692         if (ch->pos >= bufsize)
  693                 ch->pos -= bufsize;
  694 
  695         if (ch->run) {
  696                 chn_intr(ch->channel);
  697                 a10codec_transfer(ch);
  698         }
  699 }
  700 
  701 static unsigned
  702 a10codec_fs(struct a10codec_chinfo *ch)
  703 {
  704         switch (ch->speed) {
  705         case 48000:
  706                 return (DAC_FS_48KHZ);
  707         case 24000:
  708                 return (DAC_FS_24KHZ);
  709         case 12000:
  710                 return (DAC_FS_12KHZ);
  711         case 192000:
  712                 return (DAC_FS_192KHZ);
  713         case 32000:
  714                 return (DAC_FS_32KHZ);
  715         case 16000:
  716                 return (DAC_FS_16KHZ);
  717         case 8000:
  718                 return (DAC_FS_8KHZ);
  719         case 96000:
  720                 return (DAC_FS_96KHZ);
  721         default:
  722                 return (DAC_FS_48KHZ);
  723         }
  724 }
  725 
  726 static void
  727 a10codec_start(struct a10codec_chinfo *ch)
  728 {
  729         struct a10codec_info *sc = ch->parent;
  730         uint32_t val;
  731 
  732         ch->pos = 0;
  733 
  734         if (ch->dir == PCMDIR_PLAY) {
  735                 /* Flush DAC FIFO */
  736                 CODEC_WRITE(sc, AC_DAC_FIFOC(sc), DAC_FIFOC_FIFO_FLUSH);
  737 
  738                 /* Clear DAC FIFO status */
  739                 CODEC_WRITE(sc, AC_DAC_FIFOS(sc),
  740                     CODEC_READ(sc, AC_DAC_FIFOS(sc)));
  741 
  742                 /* Unmute output */
  743                 sc->cfg->mute(sc, 0, ch->dir);
  744 
  745                 /* Configure DAC DMA channel */
  746                 a10codec_dmaconfig(ch);
  747 
  748                 /* Configure DAC FIFO */
  749                 CODEC_WRITE(sc, AC_DAC_FIFOC(sc),
  750                     (AFMT_CHANNEL(ch->format) == 1 ? DAC_FIFOC_MONO_EN : 0) |
  751                     (a10codec_fs(ch) << DAC_FIFOC_FS_SHIFT) |
  752                     (FIFO_MODE_16_15_0 << DAC_FIFOC_FIFO_MODE_SHIFT) |
  753                     (DRQ_CLR_CNT << DAC_FIFOC_DRQ_CLR_CNT_SHIFT) |
  754                     (TX_TRIG_LEVEL << DAC_FIFOC_TX_TRIG_LEVEL_SHIFT));
  755 
  756                 /* Enable DAC DRQ */
  757                 val = CODEC_READ(sc, AC_DAC_FIFOC(sc));
  758                 val |= DAC_FIFOC_DRQ_EN;
  759                 CODEC_WRITE(sc, AC_DAC_FIFOC(sc), val);
  760         } else {
  761                 /* Flush ADC FIFO */
  762                 CODEC_WRITE(sc, AC_ADC_FIFOC(sc), ADC_FIFOC_FIFO_FLUSH);
  763 
  764                 /* Clear ADC FIFO status */
  765                 CODEC_WRITE(sc, AC_ADC_FIFOS(sc),
  766                     CODEC_READ(sc, AC_ADC_FIFOS(sc)));
  767 
  768                 /* Unmute input */
  769                 sc->cfg->mute(sc, 0, ch->dir);
  770 
  771                 /* Configure ADC DMA channel */
  772                 a10codec_dmaconfig(ch);
  773 
  774                 /* Configure ADC FIFO */
  775                 CODEC_WRITE(sc, AC_ADC_FIFOC(sc),
  776                     ADC_FIFOC_EN_AD |
  777                     ADC_FIFOC_RX_FIFO_MODE |
  778                     (AFMT_CHANNEL(ch->format) == 1 ? ADC_FIFOC_MONO_EN : 0) |
  779                     (a10codec_fs(ch) << ADC_FIFOC_FS_SHIFT) |
  780                     (RX_TRIG_LEVEL << ADC_FIFOC_RX_TRIG_LEVEL_SHIFT));
  781 
  782                 /* Enable ADC DRQ */
  783                 val = CODEC_READ(sc, AC_ADC_FIFOC(sc));
  784                 val |= ADC_FIFOC_DRQ_EN;
  785                 CODEC_WRITE(sc, AC_ADC_FIFOC(sc), val);
  786         }
  787 
  788         /* Start DMA transfer */
  789         a10codec_transfer(ch);
  790 }
  791 
  792 static void
  793 a10codec_stop(struct a10codec_chinfo *ch)
  794 {
  795         struct a10codec_info *sc = ch->parent;
  796 
  797         /* Disable DMA channel */
  798         SUNXI_DMA_HALT(ch->dmac, ch->dmachan);
  799 
  800         sc->cfg->mute(sc, 1, ch->dir);
  801 
  802         if (ch->dir == PCMDIR_PLAY) {
  803                 /* Disable DAC DRQ */
  804                 CODEC_WRITE(sc, AC_DAC_FIFOC(sc), 0);
  805         } else {
  806                 /* Disable ADC DRQ */
  807                 CODEC_WRITE(sc, AC_ADC_FIFOC(sc), 0);
  808         }
  809 }
  810 
  811 static void *
  812 a10codec_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
  813     struct pcm_channel *c, int dir)
  814 {
  815         struct a10codec_info *sc = devinfo;
  816         struct a10codec_chinfo *ch = dir == PCMDIR_PLAY ? &sc->play : &sc->rec;
  817         phandle_t xref;
  818         pcell_t *cells;
  819         int ncells, error;
  820 
  821         error = ofw_bus_parse_xref_list_alloc(ofw_bus_get_node(sc->dev),
  822             "dmas", "#dma-cells", dir == PCMDIR_PLAY ? 1 : 0,
  823             &xref, &ncells, &cells);
  824         if (error != 0) {
  825                 device_printf(sc->dev, "cannot parse 'dmas' property\n");
  826                 return (NULL);
  827         }
  828         OF_prop_free(cells);
  829 
  830         ch->parent = sc;
  831         ch->channel = c;
  832         ch->buffer = b;
  833         ch->dir = dir;
  834         ch->fifo = rman_get_start(sc->res[0]) +
  835             (dir == PCMDIR_REC ? AC_ADC_RXDATA(sc) : AC_DAC_TXDATA(sc));
  836 
  837         ch->dmac = OF_device_from_xref(xref);
  838         if (ch->dmac == NULL) {
  839                 device_printf(sc->dev, "cannot find DMA controller\n");
  840                 device_printf(sc->dev, "xref = 0x%x\n", (u_int)xref);
  841                 return (NULL);
  842         }
  843         ch->dmachan = SUNXI_DMA_ALLOC(ch->dmac, false, a10codec_dmaintr, ch);
  844         if (ch->dmachan == NULL) {
  845                 device_printf(sc->dev, "cannot allocate DMA channel\n");
  846                 return (NULL);
  847         }
  848 
  849         error = bus_dmamem_alloc(sc->dmat, &ch->dmaaddr,
  850             BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &ch->dmamap);
  851         if (error != 0) {
  852                 device_printf(sc->dev, "cannot allocate channel buffer\n");
  853                 return (NULL);
  854         }
  855         error = bus_dmamap_load(sc->dmat, ch->dmamap, ch->dmaaddr,
  856             sc->dmasize, a10codec_dmamap_cb, ch, BUS_DMA_NOWAIT);
  857         if (error != 0) {
  858                 device_printf(sc->dev, "cannot load DMA map\n");
  859                 return (NULL);
  860         }
  861         memset(ch->dmaaddr, 0, sc->dmasize);
  862 
  863         if (sndbuf_setup(ch->buffer, ch->dmaaddr, sc->dmasize) != 0) {
  864                 device_printf(sc->dev, "cannot setup sndbuf\n");
  865                 return (NULL);
  866         }
  867 
  868         return (ch);
  869 }
  870 
  871 static int
  872 a10codec_chan_free(kobj_t obj, void *data)
  873 {
  874         struct a10codec_chinfo *ch = data;
  875         struct a10codec_info *sc = ch->parent;
  876 
  877         SUNXI_DMA_FREE(ch->dmac, ch->dmachan);
  878         bus_dmamap_unload(sc->dmat, ch->dmamap);
  879         bus_dmamem_free(sc->dmat, ch->dmaaddr, ch->dmamap);
  880 
  881         return (0);
  882 }
  883 
  884 static int
  885 a10codec_chan_setformat(kobj_t obj, void *data, uint32_t format)
  886 {
  887         struct a10codec_chinfo *ch = data;
  888 
  889         ch->format = format;
  890 
  891         return (0);
  892 }
  893 
  894 static uint32_t
  895 a10codec_chan_setspeed(kobj_t obj, void *data, uint32_t speed)
  896 {
  897         struct a10codec_chinfo *ch = data;
  898 
  899         /*
  900          * The codec supports full duplex operation but both DAC and ADC
  901          * use the same source clock (PLL2). Limit the available speeds to
  902          * those supported by a 24576000 Hz input.
  903          */
  904         switch (speed) {
  905         case 8000:
  906         case 12000:
  907         case 16000:
  908         case 24000:
  909         case 32000:
  910         case 48000:
  911                 ch->speed = speed;
  912                 break;
  913         case 96000:
  914         case 192000:
  915                 /* 96 KHz / 192 KHz mode only supported for playback */
  916                 if (ch->dir == PCMDIR_PLAY) {
  917                         ch->speed = speed;
  918                 } else {
  919                         ch->speed = 48000;
  920                 }
  921                 break;
  922         case 44100:
  923                 ch->speed = 48000;
  924                 break;
  925         case 22050:
  926                 ch->speed = 24000;
  927                 break;
  928         case 11025:
  929                 ch->speed = 12000;
  930                 break;
  931         default:
  932                 ch->speed = 48000;
  933                 break;
  934         }
  935 
  936         return (ch->speed);
  937 }
  938 
  939 static uint32_t
  940 a10codec_chan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
  941 {
  942         struct a10codec_chinfo *ch = data;
  943 
  944         ch->blocksize = blocksize & ~3;
  945 
  946         return (ch->blocksize);
  947 }
  948 
  949 static int
  950 a10codec_chan_trigger(kobj_t obj, void *data, int go)
  951 {
  952         struct a10codec_chinfo *ch = data;
  953         struct a10codec_info *sc = ch->parent;
  954 
  955         if (!PCMTRIG_COMMON(go))
  956                 return (0);
  957 
  958         snd_mtxlock(sc->lock);
  959         switch (go) {
  960         case PCMTRIG_START:
  961                 ch->run = 1;
  962                 a10codec_stop(ch);
  963                 a10codec_start(ch);
  964                 break;
  965         case PCMTRIG_STOP:
  966         case PCMTRIG_ABORT:
  967                 ch->run = 0;
  968                 a10codec_stop(ch);
  969                 break;
  970         default:
  971                 break;
  972         }
  973         snd_mtxunlock(sc->lock);
  974 
  975         return (0);
  976 }
  977 
  978 static uint32_t
  979 a10codec_chan_getptr(kobj_t obj, void *data)
  980 {
  981         struct a10codec_chinfo *ch = data;
  982 
  983         return (ch->pos);
  984 }
  985 
  986 static struct pcmchan_caps *
  987 a10codec_chan_getcaps(kobj_t obj, void *data)
  988 {
  989         struct a10codec_chinfo *ch = data;
  990 
  991         if (ch->dir == PCMDIR_PLAY) {
  992                 return (&a10codec_pcaps);
  993         } else {
  994                 return (&a10codec_rcaps);
  995         }
  996 }
  997 
  998 static kobj_method_t a10codec_chan_methods[] = {
  999         KOBJMETHOD(channel_init,                a10codec_chan_init),
 1000         KOBJMETHOD(channel_free,                a10codec_chan_free),
 1001         KOBJMETHOD(channel_setformat,           a10codec_chan_setformat),
 1002         KOBJMETHOD(channel_setspeed,            a10codec_chan_setspeed),
 1003         KOBJMETHOD(channel_setblocksize,        a10codec_chan_setblocksize),
 1004         KOBJMETHOD(channel_trigger,             a10codec_chan_trigger),
 1005         KOBJMETHOD(channel_getptr,              a10codec_chan_getptr),
 1006         KOBJMETHOD(channel_getcaps,             a10codec_chan_getcaps),
 1007         KOBJMETHOD_END
 1008 };
 1009 CHANNEL_DECLARE(a10codec_chan);
 1010 
 1011 /*
 1012  * Device interface
 1013  */
 1014 
 1015 static const struct a10codec_config a10_config = {
 1016         .mixer_class    = &a10_mixer_class,
 1017         .mute           = a10_mute,
 1018         .drqtype_codec  = 19,
 1019         .drqtype_sdram  = 22,
 1020         .DPC            = 0x00,
 1021         .DAC_FIFOC      = 0x04,
 1022         .DAC_FIFOS      = 0x08,
 1023         .DAC_TXDATA     = 0x0c,
 1024         .ADC_FIFOC      = 0x1c,
 1025         .ADC_FIFOS      = 0x20,
 1026         .ADC_RXDATA     = 0x24,
 1027         .DAC_CNT        = 0x30,
 1028         .ADC_CNT        = 0x34,
 1029 };
 1030 
 1031 static const struct a10codec_config h3_config = {
 1032         .mixer_class    = &h3_mixer_class,
 1033         .mute           = h3_mute,
 1034         .drqtype_codec  = 15,
 1035         .drqtype_sdram  = 1,
 1036         .DPC            = 0x00,
 1037         .DAC_FIFOC      = 0x04,
 1038         .DAC_FIFOS      = 0x08,
 1039         .DAC_TXDATA     = 0x20,
 1040         .ADC_FIFOC      = 0x10,
 1041         .ADC_FIFOS      = 0x14,
 1042         .ADC_RXDATA     = 0x18,
 1043         .DAC_CNT        = 0x40,
 1044         .ADC_CNT        = 0x44,
 1045 };
 1046 
 1047 static struct ofw_compat_data compat_data[] = {
 1048         { "allwinner,sun4i-a10-codec",  (uintptr_t)&a10_config },
 1049         { "allwinner,sun7i-a20-codec",  (uintptr_t)&a10_config },
 1050         { "allwinner,sun8i-h3-codec",   (uintptr_t)&h3_config },
 1051         { NULL, 0 }
 1052 };
 1053 
 1054 static int
 1055 a10codec_probe(device_t dev)
 1056 {
 1057         if (!ofw_bus_status_okay(dev))
 1058                 return (ENXIO);
 1059 
 1060         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
 1061                 return (ENXIO);
 1062 
 1063         device_set_desc(dev, "Allwinner Audio Codec");
 1064         return (BUS_PROBE_DEFAULT);
 1065 }
 1066 
 1067 static int
 1068 a10codec_attach(device_t dev)
 1069 {
 1070         struct a10codec_info *sc;
 1071         char status[SND_STATUSLEN];
 1072         struct gpiobus_pin *pa_pin;
 1073         phandle_t node;
 1074         clk_t clk_bus, clk_codec;
 1075         hwreset_t rst;
 1076         uint32_t val;
 1077         int error;
 1078 
 1079         node = ofw_bus_get_node(dev);
 1080 
 1081         sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
 1082         sc->cfg = (void *)ofw_bus_search_compatible(dev, compat_data)->ocd_data;
 1083         sc->dev = dev;
 1084         sc->lock = snd_mtxcreate(device_get_nameunit(dev), "a10codec softc");
 1085 
 1086         if (bus_alloc_resources(dev, a10codec_spec, sc->res)) {
 1087                 device_printf(dev, "cannot allocate resources for device\n");
 1088                 error = ENXIO;
 1089                 goto fail;
 1090         }
 1091 
 1092         sc->dmasize = 131072;
 1093         error = bus_dma_tag_create(
 1094             bus_get_dma_tag(dev),
 1095             4, sc->dmasize,             /* alignment, boundary */
 1096             BUS_SPACE_MAXADDR_32BIT,    /* lowaddr */
 1097             BUS_SPACE_MAXADDR,          /* highaddr */
 1098             NULL, NULL,                 /* filter, filterarg */
 1099             sc->dmasize, 1,             /* maxsize, nsegs */
 1100             sc->dmasize, 0,             /* maxsegsize, flags */
 1101             NULL, NULL,                 /* lockfunc, lockarg */
 1102             &sc->dmat);
 1103         if (error != 0) {
 1104                 device_printf(dev, "cannot create DMA tag\n");
 1105                 goto fail;
 1106         }
 1107 
 1108         /* Get clocks */
 1109         if (clk_get_by_ofw_name(dev, 0, "apb", &clk_bus) != 0 &&
 1110             clk_get_by_ofw_name(dev, 0, "ahb", &clk_bus) != 0) {
 1111                 device_printf(dev, "cannot find bus clock\n");
 1112                 goto fail;
 1113         }
 1114         if (clk_get_by_ofw_name(dev, 0, "codec", &clk_codec) != 0) {
 1115                 device_printf(dev, "cannot find codec clock\n");
 1116                 goto fail;
 1117         }
 1118 
 1119         /* Gating bus clock for codec */
 1120         if (clk_enable(clk_bus) != 0) {
 1121                 device_printf(dev, "cannot enable bus clock\n");
 1122                 goto fail;
 1123         }
 1124         /* Activate audio codec clock. According to the A10 and A20 user
 1125          * manuals, Audio_pll can be either 24.576MHz or 22.5792MHz. Most
 1126          * audio sampling rates require an 24.576MHz input clock with the
 1127          * exception of 44.1kHz, 22.05kHz, and 11.025kHz. Unfortunately,
 1128          * both capture and playback use the same clock source so to
 1129          * safely support independent full duplex operation, we use a fixed
 1130          * 24.576MHz clock source and don't advertise native support for
 1131          * the three sampling rates that require a 22.5792MHz input.
 1132          */
 1133         error = clk_set_freq(clk_codec, 24576000, CLK_SET_ROUND_DOWN);
 1134         if (error != 0) {
 1135                 device_printf(dev, "cannot set codec clock frequency\n");
 1136                 goto fail;
 1137         }
 1138         /* Enable audio codec clock */
 1139         error = clk_enable(clk_codec);
 1140         if (error != 0) {
 1141                 device_printf(dev, "cannot enable codec clock\n");
 1142                 goto fail;
 1143         }
 1144 
 1145         /* De-assert hwreset */
 1146         if (hwreset_get_by_ofw_idx(dev, 0, 0, &rst) == 0) {
 1147                 error = hwreset_deassert(rst);
 1148                 if (error != 0) {
 1149                         device_printf(dev, "cannot de-assert reset\n");
 1150                         goto fail;
 1151                 }
 1152         }
 1153 
 1154         /* Enable DAC */
 1155         val = CODEC_READ(sc, AC_DAC_DPC(sc));
 1156         val |= DAC_DPC_EN_DA;
 1157         CODEC_WRITE(sc, AC_DAC_DPC(sc), val);
 1158 
 1159         if (mixer_init(dev, sc->cfg->mixer_class, sc)) {
 1160                 device_printf(dev, "mixer_init failed\n");
 1161                 goto fail;
 1162         }
 1163 
 1164         /* Unmute PA */
 1165         if (gpio_pin_get_by_ofw_property(dev, node, "allwinner,pa-gpios",
 1166             &pa_pin) == 0) {
 1167                 error = gpio_pin_set_active(pa_pin, 1);
 1168                 if (error != 0)
 1169                         device_printf(dev, "failed to unmute PA\n");
 1170         }
 1171 
 1172         pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE);
 1173 
 1174         if (pcm_register(dev, sc, 1, 1)) {
 1175                 device_printf(dev, "pcm_register failed\n");
 1176                 goto fail;
 1177         }
 1178 
 1179         pcm_addchan(dev, PCMDIR_PLAY, &a10codec_chan_class, sc);
 1180         pcm_addchan(dev, PCMDIR_REC, &a10codec_chan_class, sc);
 1181 
 1182         snprintf(status, SND_STATUSLEN, "at %s", ofw_bus_get_name(dev));
 1183         pcm_setstatus(dev, status);
 1184 
 1185         return (0);
 1186 
 1187 fail:
 1188         bus_release_resources(dev, a10codec_spec, sc->res);
 1189         snd_mtxfree(sc->lock);
 1190         free(sc, M_DEVBUF);
 1191 
 1192         return (ENXIO);
 1193 }
 1194 
 1195 static device_method_t a10codec_pcm_methods[] = {
 1196         /* Device interface */
 1197         DEVMETHOD(device_probe,         a10codec_probe),
 1198         DEVMETHOD(device_attach,        a10codec_attach),
 1199 
 1200         DEVMETHOD_END
 1201 };
 1202 
 1203 static driver_t a10codec_pcm_driver = {
 1204         "pcm",
 1205         a10codec_pcm_methods,
 1206         PCM_SOFTC_SIZE,
 1207 };
 1208 
 1209 DRIVER_MODULE(a10codec, simplebus, a10codec_pcm_driver, pcm_devclass, 0, 0);
 1210 MODULE_DEPEND(a10codec, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
 1211 MODULE_VERSION(a10codec, 1);

Cache object: 94c56043b1570a68102833f8ea6f90df


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.