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/pci/spicds.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 (c) 2006 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
    5  * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp>
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  * $FreeBSD$
   30  */
   31 
   32 #ifdef HAVE_KERNEL_OPTION_HEADERS
   33 #include "opt_snd.h"
   34 #endif
   35 
   36 #include <dev/sound/pcm/sound.h>
   37 
   38 #include <dev/sound/pci/spicds.h>
   39 
   40 static MALLOC_DEFINE(M_SPICDS, "spicds", "SPI codec");
   41 
   42 #define SPICDS_NAMELEN  16
   43 struct spicds_info {
   44         device_t dev;
   45         spicds_ctrl ctrl;
   46         void *devinfo;
   47         int num; /* number of this device */
   48         unsigned int type;   /* codec type */
   49         unsigned int cif;    /* Controll data Interface Format (0/1) */
   50         unsigned int format; /* data format and master clock frequency */
   51         unsigned int dvc;    /* De-emphasis and Volume Control */
   52         unsigned int left, right;
   53         char name[SPICDS_NAMELEN];
   54         struct mtx *lock;
   55 };
   56 
   57 static void
   58 spicds_wrbit(struct spicds_info *codec, int bit)
   59 {
   60         unsigned int cs, cdti;
   61         if (codec->cif)
   62                 cs = 1;
   63         else
   64                 cs = 0;
   65         if (bit)
   66                 cdti = 1;
   67         else
   68                 cdti = 0;
   69         codec->ctrl(codec->devinfo, cs, 0, cdti);
   70         DELAY(1);
   71         codec->ctrl(codec->devinfo, cs, 1, cdti);
   72         DELAY(1);
   73 
   74         return;
   75 }
   76 
   77 static void
   78 spicds_wrcd(struct spicds_info *codec, int reg, u_int16_t val)
   79 {
   80         int mask;
   81 
   82 #if(0)
   83         device_printf(codec->dev, "spicds_wrcd(codec, 0x%02x, 0x%02x)\n", reg, val);
   84 #endif
   85         /* start */
   86         if (codec->cif)
   87                 codec->ctrl(codec->devinfo, 1, 1, 0);
   88         else
   89                 codec->ctrl(codec->devinfo, 0, 1, 0);
   90         DELAY(1);
   91         if (codec->type != SPICDS_TYPE_WM8770) {
   92         if (codec->type == SPICDS_TYPE_AK4381) {
   93         /* AK4381 chip address */
   94         spicds_wrbit(codec, 0);
   95         spicds_wrbit(codec, 1);
   96         }
   97         else if (codec->type == SPICDS_TYPE_AK4396)
   98         {
   99         /* AK4396 chip address */
  100         spicds_wrbit(codec, 0);
  101         spicds_wrbit(codec, 0);
  102         }
  103         else {
  104         /* chip address */
  105         spicds_wrbit(codec, 1);
  106         spicds_wrbit(codec, 0);
  107         }
  108         /* write */
  109         spicds_wrbit(codec, 1);
  110         /* register address */
  111         for (mask = 0x10; mask != 0; mask >>= 1)
  112                 spicds_wrbit(codec, reg & mask);
  113         /* data */
  114         for (mask = 0x80; mask != 0; mask >>= 1)
  115                 spicds_wrbit(codec, val & mask);
  116         /* stop */
  117         DELAY(1);
  118         }
  119         else {
  120         /* register address */
  121         for (mask = 0x40; mask != 0; mask >>= 1)
  122                 spicds_wrbit(codec, reg & mask);
  123         /* data */
  124         for (mask = 0x100; mask != 0; mask >>= 1)
  125                 spicds_wrbit(codec, val & mask);
  126         /* stop */
  127         DELAY(1);
  128         }
  129         if (codec->cif) {
  130                 codec->ctrl(codec->devinfo, 0, 1, 0);
  131                 DELAY(1);
  132                 codec->ctrl(codec->devinfo, 1, 1, 0);
  133         }
  134         else {
  135                 codec->ctrl(codec->devinfo, 1, 1, 0);
  136         }
  137 
  138         return;
  139 }
  140 
  141 struct spicds_info *
  142 spicds_create(device_t dev, void *devinfo, int num, spicds_ctrl ctrl)
  143 {
  144         struct spicds_info *codec;
  145 
  146 #if(0)
  147         device_printf(dev, "spicds_create(dev, devinfo, %d, ctrl)\n", num);
  148 #endif
  149         codec = (struct spicds_info *)malloc(sizeof *codec, M_SPICDS, M_NOWAIT);
  150         if (codec == NULL)
  151                 return NULL;
  152 
  153         snprintf(codec->name, SPICDS_NAMELEN, "%s:spicds%d", device_get_nameunit(dev), num);
  154         codec->lock = snd_mtxcreate(codec->name, codec->name);
  155         codec->dev = dev;
  156         codec->ctrl = ctrl;
  157         codec->devinfo = devinfo;
  158         codec->num = num;
  159         codec->type = SPICDS_TYPE_AK4524;
  160         codec->cif = 0;
  161         codec->format = AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X;
  162         codec->dvc = AK452X_DVC_DEMOFF | AK452X_DVC_ZTM1024 | AK452X_DVC_ZCE;
  163 
  164         return codec;
  165 }
  166 
  167 void
  168 spicds_destroy(struct spicds_info *codec)
  169 {
  170         snd_mtxfree(codec->lock);
  171         free(codec, M_SPICDS);
  172 }
  173 
  174 void
  175 spicds_settype(struct spicds_info *codec, unsigned int type)
  176 {
  177         snd_mtxlock(codec->lock);
  178         codec->type = type;
  179         snd_mtxunlock(codec->lock);
  180 }
  181 
  182 void
  183 spicds_setcif(struct spicds_info *codec, unsigned int cif)
  184 {
  185         snd_mtxlock(codec->lock);
  186         codec->cif = cif;
  187         snd_mtxunlock(codec->lock);
  188 }
  189 
  190 void
  191 spicds_setformat(struct spicds_info *codec, unsigned int format)
  192 {
  193         snd_mtxlock(codec->lock);
  194         codec->format = format;
  195         snd_mtxunlock(codec->lock);
  196 }
  197 
  198 void
  199 spicds_setdvc(struct spicds_info *codec, unsigned int dvc)
  200 {
  201         snd_mtxlock(codec->lock);
  202         codec->dvc = dvc;
  203         snd_mtxunlock(codec->lock);
  204 }
  205 
  206 void
  207 spicds_init(struct spicds_info *codec)
  208 {
  209 #if(0)
  210         device_printf(codec->dev, "spicds_init(codec)\n");
  211 #endif
  212         snd_mtxlock(codec->lock);
  213         if (codec->type == SPICDS_TYPE_AK4524 ||\
  214             codec->type == SPICDS_TYPE_AK4528) {
  215                 /* power off */
  216                 spicds_wrcd(codec, AK4524_POWER, 0);
  217                 /* set parameter */
  218                 spicds_wrcd(codec, AK4524_FORMAT, codec->format);
  219                 spicds_wrcd(codec, AK4524_DVC, codec->dvc);
  220                 /* power on */
  221                 spicds_wrcd(codec, AK4524_POWER,
  222                     AK452X_POWER_PWDA | AK452X_POWER_PWAD | AK452X_POWER_PWVR);
  223                 /* free reset register */
  224                 spicds_wrcd(codec, AK4524_RESET,
  225                     AK452X_RESET_RSDA | AK452X_RESET_RSAD);
  226         }
  227         if (codec->type == SPICDS_TYPE_WM8770) {
  228                 /* WM8770 init values are taken from ALSA */
  229 
  230                 /* These come first to reduce init pop noise */
  231                 spicds_wrcd(codec, 0x1b, 0x044);        /* ADC Mux (AC'97 source) */
  232                 spicds_wrcd(codec, 0x1c, 0x00B);        /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
  233                 spicds_wrcd(codec, 0x1d, 0x009);        /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
  234 
  235                 spicds_wrcd(codec, 0x18, 0x000);        /* All power-up */
  236 
  237                 spicds_wrcd(codec, 0x16, 0x122);        /* I2S, normal polarity, 24bit */
  238                 spicds_wrcd(codec, 0x17, 0x022);        /* 256fs, slave mode */
  239 
  240                 spicds_wrcd(codec, 0x19, 0x000);        /* -12dB ADC/L */
  241                 spicds_wrcd(codec, 0x1a, 0x000);        /* -12dB ADC/R */
  242         }
  243         if (codec->type == SPICDS_TYPE_AK4358)
  244                 spicds_wrcd(codec, 0x00, 0x07);         /* I2S, 24bit, power-up */
  245         if (codec->type == SPICDS_TYPE_AK4381)
  246                 spicds_wrcd(codec, 0x00, 0x8f);         /* I2S, 24bit, power-up */
  247         if (codec->type == SPICDS_TYPE_AK4396)
  248                 spicds_wrcd(codec, 0x00, 0x07);         /* I2S, 24bit, power-up */
  249         snd_mtxunlock(codec->lock);
  250 }
  251 
  252 void
  253 spicds_reinit(struct spicds_info *codec)
  254 {
  255         snd_mtxlock(codec->lock);
  256         if (codec->type != SPICDS_TYPE_WM8770) {
  257                 /* reset */
  258                 spicds_wrcd(codec, AK4524_RESET, 0);
  259                 /* set parameter */
  260                 spicds_wrcd(codec, AK4524_FORMAT, codec->format);
  261                 spicds_wrcd(codec, AK4524_DVC, codec->dvc);
  262                 /* free reset register */
  263                 spicds_wrcd(codec, AK4524_RESET,
  264                     AK452X_RESET_RSDA | AK452X_RESET_RSAD);
  265         } else {
  266                 /* WM8770 reinit */
  267                 /* AK4358 reinit */
  268                 /* AK4381 reinit */
  269         }
  270         snd_mtxunlock(codec->lock);
  271 }
  272 
  273 void
  274 spicds_set(struct spicds_info *codec, int dir, unsigned int left, unsigned int right)
  275 {
  276 #if(0)
  277         device_printf(codec->dev, "spicds_set(codec, %d, %d, %d)\n", dir, left, right);
  278 #endif
  279         snd_mtxlock(codec->lock);
  280         if (left >= 100)
  281                 if ((codec->type == SPICDS_TYPE_AK4381) || \
  282                 (codec->type == SPICDS_TYPE_AK4396))
  283                         left = 255;
  284                 else
  285                         left = 127;
  286         else
  287                 switch (codec->type) {
  288                 case SPICDS_TYPE_WM8770:
  289                         left = left + 27;
  290                         break;
  291                 case SPICDS_TYPE_AK4381:
  292                 case SPICDS_TYPE_AK4396:
  293                         left = left * 255 / 100;
  294                         break;
  295                 default:
  296                         left = left * 127 / 100;
  297                 }
  298         if (right >= 100)
  299                 if ((codec->type == SPICDS_TYPE_AK4381) || \
  300                 (codec->type == SPICDS_TYPE_AK4396))
  301                         right = 255;
  302                 else
  303                         right  = 127;
  304         else
  305                 switch (codec->type) {
  306                 case SPICDS_TYPE_WM8770:
  307                         right = right + 27;
  308                         break;
  309                 case SPICDS_TYPE_AK4381:
  310                 case SPICDS_TYPE_AK4396:
  311                         right = right * 255 / 100;
  312                         break;
  313                 default:
  314                         right = right * 127 / 100;
  315                 }
  316         if (dir == PCMDIR_REC && codec->type == SPICDS_TYPE_AK4524) {
  317 #if(0)
  318                 device_printf(codec->dev, "spicds_set(): AK4524(REC) %d/%d\n", left, right);
  319 #endif
  320                 spicds_wrcd(codec, AK4524_LIPGA, left);
  321                 spicds_wrcd(codec, AK4524_RIPGA, right);
  322         }
  323         if (dir == PCMDIR_PLAY && codec->type == SPICDS_TYPE_AK4524) {
  324 #if(0)
  325                 device_printf(codec->dev, "spicds_set(): AK4524(PLAY) %d/%d\n", left, right);
  326 #endif
  327                 spicds_wrcd(codec, AK4524_LOATT, left);
  328                 spicds_wrcd(codec, AK4524_ROATT, right);
  329         }
  330         if (dir == PCMDIR_PLAY && codec->type == SPICDS_TYPE_AK4528) {
  331 #if(0)
  332                 device_printf(codec->dev, "spicds_set(): AK4528(PLAY) %d/%d\n", left, right);
  333 #endif
  334                 spicds_wrcd(codec, AK4528_LOATT, left);
  335                 spicds_wrcd(codec, AK4528_ROATT, right);
  336         }
  337         if (dir == PCMDIR_PLAY && codec->type == SPICDS_TYPE_WM8770) {
  338 #if(0)
  339                 device_printf(codec->dev, "spicds_set(): WM8770(PLAY) %d/%d\n", left, right);
  340 #endif
  341                 spicds_wrcd(codec, WM8770_AOATT_L1, left | WM8770_AOATT_UPDATE);
  342                 spicds_wrcd(codec, WM8770_AOATT_R1, right | WM8770_AOATT_UPDATE);
  343         }
  344         if (dir == PCMDIR_PLAY && codec->type == SPICDS_TYPE_AK4358) {
  345 #if(0)
  346                 device_printf(codec->dev, "spicds_set(): AK4358(PLAY) %d/%d\n", left, right);
  347 #endif
  348                 spicds_wrcd(codec, AK4358_LO1ATT, left | AK4358_OATT_ENABLE);
  349                 spicds_wrcd(codec, AK4358_RO1ATT, right | AK4358_OATT_ENABLE);
  350         }
  351         if (dir == PCMDIR_PLAY && codec->type == SPICDS_TYPE_AK4381) {
  352 #if(0)
  353                 device_printf(codec->dev, "spicds_set(): AK4381(PLAY) %d/%d\n", left, right);
  354 #endif
  355                 spicds_wrcd(codec, AK4381_LOATT, left);
  356                 spicds_wrcd(codec, AK4381_ROATT, right);
  357         }
  358 
  359         if (dir == PCMDIR_PLAY && codec->type == SPICDS_TYPE_AK4396) {
  360 #if(0)
  361                 device_printf(codec->dev, "spicds_set(): AK4396(PLAY) %d/%d\n", left, right);
  362 #endif
  363                 spicds_wrcd(codec, AK4396_LOATT, left);
  364                 spicds_wrcd(codec, AK4396_ROATT, right);
  365         }
  366 
  367         snd_mtxunlock(codec->lock);
  368 }
  369 
  370 MODULE_DEPEND(snd_spicds, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
  371 MODULE_VERSION(snd_spicds, 1);

Cache object: b355a8dbe1fed8a3f415568a28d32fd2


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