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/dev/sound/macio/onyx.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright 2012 by Andreas Tobler. All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   20  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   22  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   23  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  *
   27  * $FreeBSD$
   28  */
   29 
   30 /*
   31  * Apple PCM3052 aka Onyx audio codec.
   32  *
   33  * Datasheet: http://www.ti.com/product/pcm3052a
   34  */
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/kernel.h>
   39 #include <sys/module.h>
   40 #include <sys/bus.h>
   41 #include <sys/malloc.h>
   42 #include <sys/lock.h>
   43 #include <sys/mutex.h>
   44 #include <machine/dbdma.h>
   45 #include <machine/intr_machdep.h>
   46 #include <machine/resource.h>
   47 #include <machine/bus.h>
   48 #include <machine/pio.h>
   49 #include <sys/rman.h>
   50 
   51 #include <dev/iicbus/iicbus.h>
   52 #include <dev/iicbus/iiconf.h>
   53 #include <dev/ofw/ofw_bus.h>
   54 
   55 #ifdef HAVE_KERNEL_OPTION_HEADERS
   56 #include "opt_snd.h"
   57 #endif
   58 
   59 #include <dev/sound/pcm/sound.h>
   60 
   61 #include "mixer_if.h"
   62 
   63 extern kobj_class_t i2s_mixer_class;
   64 extern device_t i2s_mixer;
   65 
   66 struct onyx_softc
   67 {
   68         device_t sc_dev;
   69         uint32_t sc_addr;
   70 };
   71 
   72 static int      onyx_probe(device_t);
   73 static int      onyx_attach(device_t);
   74 static int      onyx_init(struct snd_mixer *m);
   75 static int      onyx_uninit(struct snd_mixer *m);
   76 static int      onyx_reinit(struct snd_mixer *m);
   77 static int      onyx_set(struct snd_mixer *m, unsigned dev, unsigned left,
   78                             unsigned right);
   79 static u_int32_t        onyx_setrecsrc(struct snd_mixer *m, u_int32_t src);
   80 
   81 static device_method_t onyx_methods[] = {
   82         /* Device interface. */
   83         DEVMETHOD(device_probe,         onyx_probe),
   84         DEVMETHOD(device_attach,        onyx_attach),
   85         { 0, 0 }
   86 };
   87 
   88 static driver_t onyx_driver = {
   89         "onyx",
   90         onyx_methods,
   91         sizeof(struct onyx_softc)
   92 };
   93 
   94 DRIVER_MODULE(onyx, iicbus, onyx_driver, 0, 0);
   95 MODULE_VERSION(onyx, 1);
   96 MODULE_DEPEND(onyx, iicbus, 1, 1, 1);
   97 
   98 static kobj_method_t onyx_mixer_methods[] = {
   99         KOBJMETHOD(mixer_init,          onyx_init),
  100         KOBJMETHOD(mixer_uninit,        onyx_uninit),
  101         KOBJMETHOD(mixer_reinit,        onyx_reinit),
  102         KOBJMETHOD(mixer_set,           onyx_set),
  103         KOBJMETHOD(mixer_setrecsrc,     onyx_setrecsrc),
  104         KOBJMETHOD_END
  105 };
  106 
  107 MIXER_DECLARE(onyx_mixer);
  108 
  109 #define PCM3052_IICADDR 0x8C    /* Hard-coded I2C slave addr */
  110 
  111 /*
  112  * PCM3052 registers.
  113  * Numbering in decimal as used in the data sheet.
  114  */
  115 #define PCM3052_REG_LEFT_ATTN       65
  116 #define PCM3052_REG_RIGHT_ATTN      66
  117 #define PCM3052_REG_CONTROL         67
  118 #define PCM3052_MRST                (1 << 7)
  119 #define PCM3052_SRST                (1 << 6)
  120 #define PCM3052_REG_DAC_CONTROL     68
  121 #define PCM3052_OVR1                (1 << 6)
  122 #define PCM3052_MUTE_L              (1 << 1)
  123 #define PCM3052_MUTE_R              (1 << 0)
  124 #define PCM3052_REG_DAC_DEEMPH      69
  125 #define PCM3052_REG_DAC_FILTER      70
  126 #define PCM3052_DAC_FILTER_ALWAYS   (1 << 2)
  127 #define PCM3052_REG_OUT_PHASE       71
  128 #define PCM3052_REG_ADC_CONTROL     72
  129 #define PCM3052_REG_ADC_HPF_BP      75
  130 #define PCM3052_HPF_ALWAYS          (1 << 2)
  131 #define PCM3052_REG_INFO_1          77
  132 #define PCM3052_REG_INFO_2          78
  133 #define PCM3052_REG_INFO_3          79
  134 #define PCM3052_REG_INFO_4          80
  135 
  136 struct onyx_reg {
  137         u_char LEFT_ATTN;
  138         u_char RIGHT_ATTN;
  139         u_char CONTROL;
  140         u_char DAC_CONTROL;
  141         u_char DAC_DEEMPH;
  142         u_char DAC_FILTER;
  143         u_char OUT_PHASE;
  144         u_char ADC_CONTROL;
  145         u_char ADC_HPF_BP;
  146         u_char INFO_1;
  147         u_char INFO_2;
  148         u_char INFO_3;
  149         u_char INFO_4;
  150 };
  151 
  152 static const struct onyx_reg onyx_initdata = {
  153         0x80,                             /* LEFT_ATTN, Mute default */
  154         0x80,                             /* RIGHT_ATTN, Mute default */
  155         PCM3052_MRST | PCM3052_SRST,      /* CONTROL */
  156         0,                                /* DAC_CONTROL */
  157         0,                                /* DAC_DEEMPH */
  158         PCM3052_DAC_FILTER_ALWAYS,        /* DAC_FILTER */
  159         0,                                /* OUT_PHASE */
  160         (-1 /* dB */ + 8) & 0xf,          /* ADC_CONTROL */
  161         PCM3052_HPF_ALWAYS,               /* ADC_HPF_BP */
  162         (1 << 2),                         /* INFO_1 */
  163         2,                                /* INFO_2,  */
  164         0,                                /* INFO_3, CLK 0 (level II),
  165                                              SF 0 (44.1 kHz) */
  166         1                                 /* INFO_4, VALIDL/R 0,
  167                                              WL 24-bit depth */
  168 };
  169 
  170 static int
  171 onyx_write(struct onyx_softc *sc, uint8_t reg, const uint8_t value)
  172 {
  173         u_int size;
  174         uint8_t buf[16];
  175 
  176         struct iic_msg msg[] = {
  177                 { sc->sc_addr, IIC_M_WR, 0, buf }
  178         };
  179 
  180         size = 1;
  181         msg[0].len = size + 1;
  182         buf[0] = reg;
  183         buf[1] = value;
  184 
  185         iicbus_transfer(sc->sc_dev, msg, 1);
  186 
  187         return (0);
  188 }
  189 
  190 static int
  191 onyx_probe(device_t dev)
  192 {
  193         const char *name, *compat;
  194 
  195         name = ofw_bus_get_name(dev);
  196         if (name == NULL)
  197                 return (ENXIO);
  198 
  199         if (strcmp(name, "codec") == 0) {
  200                 if (iicbus_get_addr(dev) != PCM3052_IICADDR)
  201                         return (ENXIO);
  202         } else if (strcmp(name, "codec") == 0) {
  203                 compat = ofw_bus_get_compat(dev);
  204                 if (compat == NULL || strcmp(compat, "pcm3052") != 0)
  205                         return (ENXIO);
  206         } else
  207                 return (ENXIO);
  208 
  209         device_set_desc(dev, "Texas Instruments PCM3052 Audio Codec");
  210         return (0);
  211 }
  212 
  213 static int
  214 onyx_attach(device_t dev)
  215 {
  216         struct onyx_softc *sc;
  217 
  218         sc = device_get_softc(dev);
  219         sc->sc_dev = dev;
  220         sc->sc_addr = iicbus_get_addr(dev);
  221 
  222         i2s_mixer_class = &onyx_mixer_class;
  223         i2s_mixer = dev;
  224 
  225         return (0);
  226 }
  227 
  228 static int
  229 onyx_init(struct snd_mixer *m)
  230 {
  231         struct onyx_softc *sc;
  232         u_int  x = 0;
  233 
  234         sc = device_get_softc(mix_getdevinfo(m));
  235 
  236         onyx_write(sc, PCM3052_REG_LEFT_ATTN, onyx_initdata.LEFT_ATTN);
  237         onyx_write(sc, PCM3052_REG_RIGHT_ATTN, onyx_initdata.RIGHT_ATTN);
  238         onyx_write(sc, PCM3052_REG_CONTROL, onyx_initdata.CONTROL);
  239         onyx_write(sc, PCM3052_REG_DAC_CONTROL,
  240                       onyx_initdata.DAC_CONTROL);
  241         onyx_write(sc, PCM3052_REG_DAC_DEEMPH, onyx_initdata.DAC_DEEMPH);
  242         onyx_write(sc, PCM3052_REG_DAC_FILTER, onyx_initdata.DAC_FILTER);
  243         onyx_write(sc, PCM3052_REG_OUT_PHASE, onyx_initdata.OUT_PHASE);
  244         onyx_write(sc, PCM3052_REG_ADC_CONTROL,
  245                       onyx_initdata.ADC_CONTROL);
  246         onyx_write(sc, PCM3052_REG_ADC_HPF_BP, onyx_initdata.ADC_HPF_BP);
  247         onyx_write(sc, PCM3052_REG_INFO_1, onyx_initdata.INFO_1);
  248         onyx_write(sc, PCM3052_REG_INFO_2, onyx_initdata.INFO_2);
  249         onyx_write(sc, PCM3052_REG_INFO_3, onyx_initdata.INFO_3);
  250         onyx_write(sc, PCM3052_REG_INFO_4, onyx_initdata.INFO_4);
  251 
  252         x |= SOUND_MASK_VOLUME;
  253         mix_setdevs(m, x);
  254 
  255         return (0);
  256 }
  257 
  258 static int
  259 onyx_uninit(struct snd_mixer *m)
  260 {
  261         return (0);
  262 }
  263 
  264 static int
  265 onyx_reinit(struct snd_mixer *m)
  266 {
  267         return (0);
  268 }
  269 
  270 static int
  271 onyx_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
  272 {
  273         struct onyx_softc *sc;
  274         struct mtx *mixer_lock;
  275         int locked;
  276         uint8_t l, r;
  277 
  278         sc = device_get_softc(mix_getdevinfo(m));
  279         mixer_lock = mixer_get_lock(m);
  280         locked = mtx_owned(mixer_lock);
  281 
  282         switch (dev) {
  283         case SOUND_MIXER_VOLUME:
  284 
  285                 /*
  286                  * We need to unlock the mixer lock because iicbus_transfer()
  287                  * may sleep. The mixer lock itself is unnecessary here
  288                  * because it is meant to serialize hardware access, which
  289                  * is taken care of by the I2C layer, so this is safe.
  290                  */
  291                 if (left > 100 || right > 100)
  292                         return (0);
  293 
  294                 l = left + 128;
  295                 r = right + 128;
  296 
  297                 if (locked)
  298                         mtx_unlock(mixer_lock);
  299 
  300                 onyx_write(sc, PCM3052_REG_LEFT_ATTN, l);
  301                 onyx_write(sc, PCM3052_REG_RIGHT_ATTN, r);
  302 
  303                 if (locked)
  304                         mtx_lock(mixer_lock);
  305 
  306                 return (left | (right << 8));
  307         }
  308 
  309         return (0);
  310 }
  311 
  312 static u_int32_t
  313 onyx_setrecsrc(struct snd_mixer *m, u_int32_t src)
  314 {
  315         return (0);
  316 }

Cache object: 50f6b1e22f92ba1138f939c591c7bb84


[ 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.