spicds.c revision 159687
1/* 2 * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp> 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 AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: head/sys/dev/sound/pci/spicds.c 159687 2006-06-17 14:36:44Z netchild $ 27 */ 28 29#include <dev/sound/pcm/sound.h> 30 31#include <dev/sound/pci/ak452x.h> 32 33MALLOC_DEFINE(M_AK452X, "ak452x", "ak452x codec"); 34 35#define AK452X_NAMELEN 16 36struct ak452x_info { 37 device_t dev; 38 ak452x_ctrl ctrl; 39 void *devinfo; 40 int num; /* number of this device */ 41 unsigned int type; /* codec type */ 42 unsigned int cif; /* Controll data Interface Format (0/1) */ 43 unsigned int format; /* data format and master clock frequency */ 44 unsigned int dvc; /* De-emphasis and Volume Control */ 45 unsigned int left, right; 46 char name[AK452X_NAMELEN]; 47 void *lock; 48}; 49 50static void 51ak452x_wrbit(struct ak452x_info *codec, int bit) 52{ 53 unsigned int cs, cdti; 54 if (codec->cif) 55 cs = 1; 56 else 57 cs = 0; 58 if (bit) 59 cdti = 1; 60 else 61 cdti = 0; 62 codec->ctrl(codec->devinfo, cs, 0, cdti); 63 DELAY(1); 64 codec->ctrl(codec->devinfo, cs, 1, cdti); 65 DELAY(1); 66 67 return; 68} 69 70static void 71ak452x_wrcd(struct ak452x_info *codec, int reg, u_int8_t val) 72{ 73 int mask; 74 75#if(0) 76 device_printf(codec->dev, "ak452x_wrcd(codec, 0x%02x, 0x%02x)\n", reg, val); 77#endif 78 /* start */ 79 if (codec->cif) 80 codec->ctrl(codec->devinfo, 1, 1, 0); 81 else 82 codec->ctrl(codec->devinfo, 0, 1, 0); 83 DELAY(1); 84 /* chip address */ 85 ak452x_wrbit(codec, 1); 86 ak452x_wrbit(codec, 0); 87 /* write */ 88 ak452x_wrbit(codec, 1); 89 /* register address */ 90 for (mask = 0x10; mask != 0; mask >>= 1) 91 ak452x_wrbit(codec, reg & mask); 92 /* data */ 93 for (mask = 0x80; mask != 0; mask >>= 1) 94 ak452x_wrbit(codec, val & mask); 95 /* stop */ 96 DELAY(1); 97 if (codec->cif) { 98 codec->ctrl(codec->devinfo, 0, 1, 0); 99 DELAY(1); 100 codec->ctrl(codec->devinfo, 1, 1, 0); 101 } 102 else { 103 codec->ctrl(codec->devinfo, 1, 1, 0); 104 } 105 106 return; 107} 108 109struct ak452x_info * 110ak452x_create(device_t dev, void *devinfo, int num, ak452x_ctrl ctrl) 111{ 112 struct ak452x_info *codec; 113 114#if(0) 115 device_printf(dev, "ak452x_create(dev, devinfo, %d, ctrl)\n", num); 116#endif 117 codec = (struct ak452x_info *)malloc(sizeof *codec, M_AK452X, M_NOWAIT); 118 if (codec == NULL) 119 return NULL; 120 121 snprintf(codec->name, AK452X_NAMELEN, "%s:ak452x%d", device_get_nameunit(dev), num); 122 codec->lock = snd_mtxcreate(codec->name); 123 codec->dev = dev; 124 codec->ctrl = ctrl; 125 codec->devinfo = devinfo; 126 codec->num = num; 127 codec->type = AK452X_TYPE_4524; 128 codec->cif = 0; 129 codec->format = AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X; 130 codec->dvc = AK452X_DVC_DEMOFF | AK452X_DVC_ZTM1024 | AK452X_DVC_ZCE; 131 132 return codec; 133} 134 135void 136ak452x_destroy(struct ak452x_info *codec) 137{ 138 snd_mtxfree(codec->lock); 139 free(codec, M_AK452X); 140} 141 142void 143ak452x_settype(struct ak452x_info *codec, unsigned int type) 144{ 145 snd_mtxlock(codec->lock); 146 codec->type = type; 147 snd_mtxunlock(codec->lock); 148} 149 150void 151ak452x_setcif(struct ak452x_info *codec, unsigned int cif) 152{ 153 snd_mtxlock(codec->lock); 154 codec->cif = cif; 155 snd_mtxunlock(codec->lock); 156} 157 158void 159ak452x_setformat(struct ak452x_info *codec, unsigned int format) 160{ 161 snd_mtxlock(codec->lock); 162 codec->format = format; 163 snd_mtxunlock(codec->lock); 164} 165 166void 167ak452x_setdvc(struct ak452x_info *codec, unsigned int dvc) 168{ 169 snd_mtxlock(codec->lock); 170 codec->type = dvc; 171 snd_mtxunlock(codec->lock); 172} 173 174void 175ak452x_init(struct ak452x_info *codec) 176{ 177#if(0) 178 device_printf(codec->dev, "ak452x_init(codec)\n"); 179#endif 180 snd_mtxlock(codec->lock); 181 /* power off */ 182 ak452x_wrcd(codec, AK4524_POWER, 0); 183 /* set parameter */ 184 ak452x_wrcd(codec, AK4524_FORMAT, codec->format); 185 ak452x_wrcd(codec, AK4524_DVC, codec->dvc); 186 /* power on */ 187 ak452x_wrcd(codec, AK4524_POWER, AK452X_POWER_PWDA | AK452X_POWER_PWAD | AK452X_POWER_PWVR); 188 /* free reset register */ 189 ak452x_wrcd(codec, AK4524_RESET, AK452X_RESET_RSDA | AK452X_RESET_RSAD); 190 snd_mtxunlock(codec->lock); 191} 192 193void 194ak452x_reinit(struct ak452x_info *codec) 195{ 196 snd_mtxlock(codec->lock); 197 /* reset */ 198 ak452x_wrcd(codec, AK4524_RESET, 0); 199 /* set parameter */ 200 ak452x_wrcd(codec, AK4524_FORMAT, codec->format); 201 ak452x_wrcd(codec, AK4524_DVC, codec->dvc); 202 /* free reset register */ 203 ak452x_wrcd(codec, AK4524_RESET, AK452X_RESET_RSDA | AK452X_RESET_RSAD); 204 snd_mtxunlock(codec->lock); 205} 206 207void 208ak452x_set(struct ak452x_info *codec, int dir, unsigned int left, unsigned int right) 209{ 210#if(0) 211 device_printf(codec->dev, "ak452x_set(codec, %d, %d, %d)\n", dir, left, right); 212#endif 213 snd_mtxlock(codec->lock); 214 if (left >= 100) 215 left = 127; 216 else 217 left = left * 127 / 100; 218 if (right >= 100) 219 right = 127; 220 else 221 right = right * 127 / 100; 222 if (dir == PCMDIR_REC && codec->type == AK452X_TYPE_4524) { 223#if(0) 224 device_printf(codec->dev, "ak452x_set(): AK4524(REC) %d/%d\n", left, right); 225#endif 226 ak452x_wrcd(codec, AK4524_LIPGA, left); 227 ak452x_wrcd(codec, AK4524_RIPGA, right); 228 } 229 if (dir == PCMDIR_PLAY && codec->type == AK452X_TYPE_4524) { 230#if(0) 231 device_printf(codec->dev, "ak452x_set(): AK4524(PLAY) %d/%d\n", left, right); 232#endif 233 ak452x_wrcd(codec, AK4524_LOATT, left); 234 ak452x_wrcd(codec, AK4524_ROATT, right); 235 } 236 if (dir == PCMDIR_PLAY && codec->type == AK452X_TYPE_4528) { 237#if(0) 238 device_printf(codec->dev, "ak452x_set(): AK4528(PLAY) %d/%d\n", left, right); 239#endif 240 ak452x_wrcd(codec, AK4528_LOATT, left); 241 ak452x_wrcd(codec, AK4528_ROATT, right); 242 } 243 snd_mtxunlock(codec->lock); 244} 245 246MODULE_DEPEND(snd_ak452x, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); 247MODULE_VERSION(snd_ak452x, 1); 248