Author: andreast
Date: Sun Aug 19 19:40:33 2012
New Revision: 239401
URL: http://svn.freebsd.org/changeset/base/239401

Log:
  Add a new sound driver for PowerMacs, found here on my Quad G5.
  It allows simple playback and volume control like the other Mac drivers,
  not more.

Added:
  head/sys/dev/sound/macio/onyx.c   (contents, props changed)
Modified:
  head/sys/conf/files.powerpc

Modified: head/sys/conf/files.powerpc
==============================================================================
--- head/sys/conf/files.powerpc Sun Aug 19 19:37:14 2012        (r239400)
+++ head/sys/conf/files.powerpc Sun Aug 19 19:40:33 2012        (r239401)
@@ -54,6 +54,7 @@ dev/sec/sec.c                 optional        sec mpc85xx
 dev/sound/macio/aoa.c          optional        snd_davbus | snd_ai2s powermac
 dev/sound/macio/davbus.c       optional        snd_davbus powermac
 dev/sound/macio/i2s.c          optional        snd_ai2s powermac
+dev/sound/macio/onyx.c         optional        snd_ai2s iicbus powermac
 dev/sound/macio/snapper.c      optional        snd_ai2s iicbus powermac
 dev/sound/macio/tumbler.c      optional        snd_ai2s iicbus powermac
 dev/syscons/scgfbrndr.c                optional        sc

Added: head/sys/dev/sound/macio/onyx.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/dev/sound/macio/onyx.c     Sun Aug 19 19:40:33 2012        
(r239401)
@@ -0,0 +1,315 @@
+/*-
+ * Copyright 2012 by Andreas Tobler. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Apple PCM3052 aka Onyx audio codec.
+ *
+ * Datasheet: http://www.ti.com/product/pcm3052a
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <machine/dbdma.h>
+#include <machine/intr_machdep.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <machine/pio.h>
+#include <sys/rman.h>
+
+#include <dev/iicbus/iicbus.h>
+#include <dev/iicbus/iiconf.h>
+#include <dev/ofw/ofw_bus.h>
+
+#ifdef HAVE_KERNEL_OPTION_HEADERS
+#include "opt_snd.h"
+#endif
+
+#include <dev/sound/pcm/sound.h>
+
+#include "mixer_if.h"
+
+extern kobj_class_t i2s_mixer_class;
+extern device_t        i2s_mixer;
+
+struct onyx_softc
+{
+       device_t sc_dev;
+       uint32_t sc_addr;
+};
+
+static int     onyx_probe(device_t);
+static int     onyx_attach(device_t);
+static int     onyx_init(struct snd_mixer *m);
+static int     onyx_uninit(struct snd_mixer *m);
+static int     onyx_reinit(struct snd_mixer *m);
+static int     onyx_set(struct snd_mixer *m, unsigned dev, unsigned left,
+                           unsigned right);
+static u_int32_t       onyx_setrecsrc(struct snd_mixer *m, u_int32_t src);
+
+static device_method_t onyx_methods[] = {
+       /* Device interface. */
+       DEVMETHOD(device_probe,         onyx_probe),
+       DEVMETHOD(device_attach,        onyx_attach),
+       { 0, 0 }
+};
+
+static driver_t onyx_driver = {
+       "onyx",
+       onyx_methods,
+       sizeof(struct onyx_softc)
+};
+static devclass_t onyx_devclass;
+
+DRIVER_MODULE(onyx, iicbus, onyx_driver, onyx_devclass, 0, 0);
+MODULE_VERSION(onyx, 1);
+MODULE_DEPEND(onyx, iicbus, 1, 1, 1);
+
+static kobj_method_t onyx_mixer_methods[] = {
+       KOBJMETHOD(mixer_init,          onyx_init),
+       KOBJMETHOD(mixer_uninit,        onyx_uninit),
+       KOBJMETHOD(mixer_reinit,        onyx_reinit),
+       KOBJMETHOD(mixer_set,           onyx_set),
+       KOBJMETHOD(mixer_setrecsrc,     onyx_setrecsrc),
+       KOBJMETHOD_END
+};
+
+MIXER_DECLARE(onyx_mixer);
+
+#define PCM3052_IICADDR        0x8C    /* Hard-coded I2C slave addr */
+
+/*
+ * PCM3052 registers.
+ * Numbering in decimal as used in the data sheet.
+ */
+#define PCM3052_REG_LEFT_ATTN       65
+#define PCM3052_REG_RIGHT_ATTN      66
+#define PCM3052_REG_CONTROL         67
+#define PCM3052_MRST                (1 << 7)
+#define PCM3052_SRST                (1 << 6)
+#define PCM3052_REG_DAC_CONTROL     68
+#define PCM3052_OVR1                (1 << 6)
+#define PCM3052_MUTE_L              (1 << 1)
+#define PCM3052_MUTE_R              (1 << 0)
+#define PCM3052_REG_DAC_DEEMPH      69
+#define PCM3052_REG_DAC_FILTER      70
+#define PCM3052_DAC_FILTER_ALWAYS   (1 << 2)
+#define PCM3052_REG_OUT_PHASE       71
+#define PCM3052_REG_ADC_CONTROL     72
+#define PCM3052_REG_ADC_HPF_BP      75
+#define PCM3052_HPF_ALWAYS          (1 << 2)
+#define PCM3052_REG_INFO_1          77
+#define PCM3052_REG_INFO_2          78
+#define PCM3052_REG_INFO_3          79
+#define PCM3052_REG_INFO_4          80
+
+struct onyx_reg {
+       u_char LEFT_ATTN;
+       u_char RIGHT_ATTN;
+       u_char CONTROL;
+       u_char DAC_CONTROL;
+       u_char DAC_DEEMPH;
+       u_char DAC_FILTER;
+       u_char OUT_PHASE;
+       u_char ADC_CONTROL;
+       u_char ADC_HPF_BP;
+       u_char INFO_1;
+       u_char INFO_2;
+       u_char INFO_3;
+       u_char INFO_4;
+};
+
+static const struct onyx_reg onyx_initdata = {
+       0x80,                             /* LEFT_ATTN, Mute default */
+       0x80,                             /* RIGHT_ATTN, Mute default */
+       PCM3052_MRST | PCM3052_SRST,      /* CONTROL */
+       0,                                /* DAC_CONTROL */
+       0,                                /* DAC_DEEMPH */
+       PCM3052_DAC_FILTER_ALWAYS,        /* DAC_FILTER */
+       0,                                /* OUT_PHASE */
+       (-1 /* dB */ + 8) & 0xf,          /* ADC_CONTROL */
+       PCM3052_HPF_ALWAYS,               /* ADC_HPF_BP */
+       (1 << 2),                         /* INFO_1 */
+       2,                                /* INFO_2,  */
+       0,                                /* INFO_3, CLK 0 (level II),
+                                            SF 0 (44.1 kHz) */
+       1                                 /* INFO_4, VALIDL/R 0,
+                                            WL 24-bit depth */
+};
+
+static int
+onyx_write(struct onyx_softc *sc, uint8_t reg, const uint8_t value)
+{
+       u_int size;
+       uint8_t buf[16];
+
+       struct iic_msg msg[] = {
+               { sc->sc_addr, IIC_M_WR, 0, buf }
+       };
+
+       size = 1;
+       msg[0].len = size + 1;
+       buf[0] = reg;
+       buf[1] = value;
+
+       iicbus_transfer(sc->sc_dev, msg, 1);
+
+       return (0);
+}
+
+static int
+onyx_probe(device_t dev)
+{
+       const char *name, *compat;
+
+       name = ofw_bus_get_name(dev);
+       if (name == NULL)
+               return (ENXIO);
+
+       if (strcmp(name, "codec") == 0) {
+               if (iicbus_get_addr(dev) != PCM3052_IICADDR)
+                       return (ENXIO);
+       } else if (strcmp(name, "codec") == 0) {
+               compat = ofw_bus_get_compat(dev);
+               if (compat == NULL || strcmp(compat, "pcm3052") != 0)
+                       return (ENXIO);
+       } else
+               return (ENXIO);
+
+       device_set_desc(dev, "Texas Instruments PCM3052 Audio Codec");
+       return (0);
+}
+
+static int
+onyx_attach(device_t dev)
+{
+       struct onyx_softc *sc;
+
+       sc = device_get_softc(dev);
+       sc->sc_dev = dev;
+       sc->sc_addr = iicbus_get_addr(dev);
+
+       i2s_mixer_class = &onyx_mixer_class;
+       i2s_mixer = dev;
+
+       return (0);
+}
+
+static int
+onyx_init(struct snd_mixer *m)
+{
+       struct onyx_softc *sc;
+       u_int  x = 0;
+
+       sc = device_get_softc(mix_getdevinfo(m));
+
+       onyx_write(sc, PCM3052_REG_LEFT_ATTN, onyx_initdata.LEFT_ATTN);
+       onyx_write(sc, PCM3052_REG_RIGHT_ATTN, onyx_initdata.RIGHT_ATTN);
+       onyx_write(sc, PCM3052_REG_CONTROL, onyx_initdata.CONTROL);
+       onyx_write(sc, PCM3052_REG_DAC_CONTROL,
+                     onyx_initdata.DAC_CONTROL);
+       onyx_write(sc, PCM3052_REG_DAC_DEEMPH, onyx_initdata.DAC_DEEMPH);
+       onyx_write(sc, PCM3052_REG_DAC_FILTER, onyx_initdata.DAC_FILTER);
+       onyx_write(sc, PCM3052_REG_OUT_PHASE, onyx_initdata.OUT_PHASE);
+       onyx_write(sc, PCM3052_REG_ADC_CONTROL,
+                     onyx_initdata.ADC_CONTROL);
+       onyx_write(sc, PCM3052_REG_ADC_HPF_BP, onyx_initdata.ADC_HPF_BP);
+       onyx_write(sc, PCM3052_REG_INFO_1, onyx_initdata.INFO_1);
+       onyx_write(sc, PCM3052_REG_INFO_2, onyx_initdata.INFO_2);
+       onyx_write(sc, PCM3052_REG_INFO_3, onyx_initdata.INFO_3);
+       onyx_write(sc, PCM3052_REG_INFO_4, onyx_initdata.INFO_4);
+
+       x |= SOUND_MASK_VOLUME;
+       mix_setdevs(m, x);
+
+       return (0);
+}
+
+static int
+onyx_uninit(struct snd_mixer *m)
+{
+       return (0);
+}
+
+static int
+onyx_reinit(struct snd_mixer *m)
+{
+       return (0);
+}
+
+static int
+onyx_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
+{
+       struct onyx_softc *sc;
+       struct mtx *mixer_lock;
+       int locked;
+       uint8_t l, r;
+
+       sc = device_get_softc(mix_getdevinfo(m));
+       mixer_lock = mixer_get_lock(m);
+       locked = mtx_owned(mixer_lock);
+
+       switch (dev) {
+       case SOUND_MIXER_VOLUME:
+
+               /*
+                * We need to unlock the mixer lock because iicbus_transfer()
+                * may sleep. The mixer lock itself is unnecessary here
+                * because it is meant to serialize hardware access, which
+                * is taken care of by the I2C layer, so this is safe.
+                */
+               if (left > 100 || right > 100)
+                       return (0);
+
+               l = left + 128;
+               r = right + 128;
+
+               if (locked)
+                       mtx_unlock(mixer_lock);
+
+               onyx_write(sc, PCM3052_REG_LEFT_ATTN, l);
+               onyx_write(sc, PCM3052_REG_RIGHT_ATTN, r);
+
+               if (locked)
+                       mtx_lock(mixer_lock);
+
+               return (left | (right << 8));
+       }
+
+       return (0);
+}
+
+static u_int32_t
+onyx_setrecsrc(struct snd_mixer *m, u_int32_t src)
+{
+       return (0);
+}
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to