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$ 27 */ 28 29 #include <dev/sound/pcm/sound.h> 30 31 #include <dev/sound/pci/ak452x.h> 32 33 MALLOC_DEFINE(M_AK452X, "ak452x", "ak452x codec"); 34 35 #define AK452X_NAMELEN 16 36 struct 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 50 static void 51 ak452x_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 70 static void 71 ak452x_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 109 struct ak452x_info * 110 ak452x_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, 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 135 void 136 ak452x_destroy(struct ak452x_info *codec) 137 { 138 snd_mtxfree(codec->lock); 139 free(codec, M_AK452X); 140 } 141 142 void 143 ak452x_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 150 void 151 ak452x_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 158 void 159 ak452x_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 166 void 167 ak452x_setdvc(struct ak452x_info *codec, unsigned int dvc) 168 { 169 snd_mtxlock(codec->lock); 170 codec->dvc = dvc; 171 snd_mtxunlock(codec->lock); 172 } 173 174 void 175 ak452x_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 193 void 194 ak452x_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 207 void 208 ak452x_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 246 MODULE_DEPEND(snd_ak452x, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 247 MODULE_VERSION(snd_ak452x, 1); 248