ASoC: Add WM2000 driver

The WM2000 is a low power, high quality handset receiver speaker
driver with Wolfson myZone™ Ambient Noise Cancellation (ANC). It
provides enhanced voice communication quality in a noisy environment
if the handset acoustics are designed appropriately.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>

+999
+26
include/sound/wm2000.h
··· 1 + /* 2 + * linux/sound/wm2000.h -- Platform data for WM2000 3 + * 4 + * Copyright 2010 Wolfson Microelectronics. PLC. 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + */ 10 + 11 + #ifndef __LINUX_SND_WM2000_H 12 + #define __LINUX_SND_WM2000_H 13 + 14 + struct wm2000_platform_data { 15 + /** Filename for system-specific image to download to device. */ 16 + const char *download_file; 17 + 18 + /** Divide MCLK by 2 for system clock? */ 19 + unsigned int mclkdiv2:1; 20 + 21 + /** Disable speech clarity enhancement, for use when an 22 + * external algorithm is used. */ 23 + unsigned int speech_enh_disable:1; 24 + }; 25 + 26 + #endif
+4
sound/soc/codecs/Kconfig
··· 36 36 select SND_SOC_TWL4030 if TWL4030_CORE 37 37 select SND_SOC_UDA134X 38 38 select SND_SOC_UDA1380 if I2C 39 + select SND_SOC_WM2000 if I2C 39 40 select SND_SOC_WM8350 if MFD_WM8350 40 41 select SND_SOC_WM8400 if MFD_WM8400 41 42 select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI ··· 265 264 tristate 266 265 267 266 config SND_SOC_TPA6130A2 267 + tristate 268 + 269 + config SND_SOC_WM2000 268 270 tristate
+2
sound/soc/codecs/Makefile
··· 58 58 # Amp 59 59 snd-soc-max9877-objs := max9877.o 60 60 snd-soc-tpa6130a2-objs := tpa6130a2.o 61 + snd-soc-wm2000-objs := wm2000.o 61 62 62 63 obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o 63 64 obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o ··· 120 119 # Amp 121 120 obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o 122 121 obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o 122 + obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o
+888
sound/soc/codecs/wm2000.c
··· 1 + /* 2 + * wm2000.c -- WM2000 ALSA Soc Audio driver 3 + * 4 + * Copyright 2008-2010 Wolfson Microelectronics PLC. 5 + * 6 + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + * 12 + * The download image for the WM2000 will be requested as 13 + * 'wm2000_anc.bin' by default (overridable via platform data) at 14 + * runtime and is expected to be in flat binary format. This is 15 + * generated by Wolfson configuration tools and includes 16 + * system-specific callibration information. If supplied as a 17 + * sequence of ASCII-encoded hexidecimal bytes this can be converted 18 + * into a flat binary with a command such as this on the command line: 19 + * 20 + * perl -e 'while (<>) { s/[\r\n]+// ; printf("%c", hex($_)); }' 21 + * < file > wm2000_anc.bin 22 + */ 23 + 24 + #include <linux/module.h> 25 + #include <linux/moduleparam.h> 26 + #include <linux/version.h> 27 + #include <linux/kernel.h> 28 + #include <linux/init.h> 29 + #include <linux/firmware.h> 30 + #include <linux/delay.h> 31 + #include <linux/pm.h> 32 + #include <linux/i2c.h> 33 + #include <linux/platform_device.h> 34 + #include <linux/debugfs.h> 35 + #include <sound/core.h> 36 + #include <sound/pcm.h> 37 + #include <sound/pcm_params.h> 38 + #include <sound/soc.h> 39 + #include <sound/soc-dapm.h> 40 + #include <sound/initval.h> 41 + #include <sound/tlv.h> 42 + 43 + #include <sound/wm2000.h> 44 + 45 + #include "wm2000.h" 46 + 47 + enum wm2000_anc_mode { 48 + ANC_ACTIVE = 0, 49 + ANC_BYPASS = 1, 50 + ANC_STANDBY = 2, 51 + ANC_OFF = 3, 52 + }; 53 + 54 + struct wm2000_priv { 55 + struct i2c_client *i2c; 56 + 57 + enum wm2000_anc_mode anc_mode; 58 + 59 + unsigned int anc_active:1; 60 + unsigned int anc_eng_ena:1; 61 + unsigned int spk_ena:1; 62 + 63 + unsigned int mclk_div:1; 64 + unsigned int speech_clarity:1; 65 + 66 + int anc_download_size; 67 + char *anc_download; 68 + }; 69 + 70 + static struct i2c_client *wm2000_i2c; 71 + 72 + static int wm2000_write(struct i2c_client *i2c, unsigned int reg, 73 + unsigned int value) 74 + { 75 + u8 data[3]; 76 + int ret; 77 + 78 + data[0] = (reg >> 8) & 0xff; 79 + data[1] = reg & 0xff; 80 + data[2] = value & 0xff; 81 + 82 + dev_vdbg(&i2c->dev, "write %x = %x\n", reg, value); 83 + 84 + ret = i2c_master_send(i2c, data, 3); 85 + if (ret == 3) 86 + return 0; 87 + if (ret < 0) 88 + return ret; 89 + else 90 + return -EIO; 91 + } 92 + 93 + static unsigned int wm2000_read(struct i2c_client *i2c, unsigned int r) 94 + { 95 + struct i2c_msg xfer[2]; 96 + u8 reg[2]; 97 + u8 data; 98 + int ret; 99 + 100 + /* Write register */ 101 + reg[0] = (r >> 8) & 0xff; 102 + reg[1] = r & 0xff; 103 + xfer[0].addr = i2c->addr; 104 + xfer[0].flags = 0; 105 + xfer[0].len = sizeof(reg); 106 + xfer[0].buf = &reg[0]; 107 + 108 + /* Read data */ 109 + xfer[1].addr = i2c->addr; 110 + xfer[1].flags = I2C_M_RD; 111 + xfer[1].len = 1; 112 + xfer[1].buf = &data; 113 + 114 + ret = i2c_transfer(i2c->adapter, xfer, 2); 115 + if (ret != 2) { 116 + dev_err(&i2c->dev, "i2c_transfer() returned %d\n", ret); 117 + return 0; 118 + } 119 + 120 + dev_vdbg(&i2c->dev, "read %x from %x\n", data, r); 121 + 122 + return data; 123 + } 124 + 125 + static void wm2000_reset(struct wm2000_priv *wm2000) 126 + { 127 + struct i2c_client *i2c = wm2000->i2c; 128 + 129 + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_ENG_CLR); 130 + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_CLR); 131 + wm2000_write(i2c, WM2000_REG_ID1, 0); 132 + 133 + wm2000->anc_mode = ANC_OFF; 134 + } 135 + 136 + static int wm2000_poll_bit(struct i2c_client *i2c, 137 + unsigned int reg, u8 mask, int timeout) 138 + { 139 + int val; 140 + 141 + val = wm2000_read(i2c, reg); 142 + 143 + while (!(val & mask) && --timeout) { 144 + msleep(1); 145 + val = wm2000_read(i2c, reg); 146 + } 147 + 148 + if (timeout == 0) 149 + return 0; 150 + else 151 + return 1; 152 + } 153 + 154 + static int wm2000_power_up(struct i2c_client *i2c, int analogue) 155 + { 156 + struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); 157 + int ret, timeout; 158 + 159 + BUG_ON(wm2000->anc_mode != ANC_OFF); 160 + 161 + dev_dbg(&i2c->dev, "Beginning power up\n"); 162 + 163 + if (!wm2000->mclk_div) { 164 + dev_dbg(&i2c->dev, "Disabling MCLK divider\n"); 165 + wm2000_write(i2c, WM2000_REG_SYS_CTL2, 166 + WM2000_MCLK_DIV2_ENA_CLR); 167 + } else { 168 + dev_dbg(&i2c->dev, "Enabling MCLK divider\n"); 169 + wm2000_write(i2c, WM2000_REG_SYS_CTL2, 170 + WM2000_MCLK_DIV2_ENA_SET); 171 + } 172 + 173 + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_ENG_CLR); 174 + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_ENG_SET); 175 + 176 + /* Wait for ANC engine to become ready */ 177 + if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT, 178 + WM2000_ANC_ENG_IDLE, 1)) { 179 + dev_err(&i2c->dev, "ANC engine failed to reset\n"); 180 + return -ETIMEDOUT; 181 + } 182 + 183 + if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, 184 + WM2000_STATUS_BOOT_COMPLETE, 1)) { 185 + dev_err(&i2c->dev, "ANC engine failed to initialise\n"); 186 + return -ETIMEDOUT; 187 + } 188 + 189 + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_SET); 190 + 191 + /* Open code download of the data since it is the only bulk 192 + * write we do. */ 193 + dev_dbg(&i2c->dev, "Downloading %d bytes\n", 194 + wm2000->anc_download_size - 2); 195 + 196 + ret = i2c_master_send(i2c, wm2000->anc_download, 197 + wm2000->anc_download_size); 198 + if (ret < 0) { 199 + dev_err(&i2c->dev, "i2c_transfer() failed: %d\n", ret); 200 + return ret; 201 + } 202 + if (ret != wm2000->anc_download_size) { 203 + dev_err(&i2c->dev, "i2c_transfer() failed, %d != %d\n", 204 + ret, wm2000->anc_download_size); 205 + return -EIO; 206 + } 207 + 208 + dev_dbg(&i2c->dev, "Download complete\n"); 209 + 210 + if (analogue) { 211 + timeout = 248; 212 + wm2000_write(i2c, WM2000_REG_ANA_VMID_PU_TIME, timeout / 4); 213 + 214 + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, 215 + WM2000_MODE_ANA_SEQ_INCLUDE | 216 + WM2000_MODE_MOUSE_ENABLE | 217 + WM2000_MODE_THERMAL_ENABLE); 218 + } else { 219 + timeout = 10; 220 + 221 + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, 222 + WM2000_MODE_MOUSE_ENABLE | 223 + WM2000_MODE_THERMAL_ENABLE); 224 + } 225 + 226 + ret = wm2000_read(i2c, WM2000_REG_SPEECH_CLARITY); 227 + if (wm2000->speech_clarity) 228 + ret &= ~WM2000_SPEECH_CLARITY; 229 + else 230 + ret |= WM2000_SPEECH_CLARITY; 231 + wm2000_write(i2c, WM2000_REG_SPEECH_CLARITY, ret); 232 + 233 + wm2000_write(i2c, WM2000_REG_SYS_START0, 0x33); 234 + wm2000_write(i2c, WM2000_REG_SYS_START1, 0x02); 235 + 236 + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_INT_N_CLR); 237 + 238 + if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, 239 + WM2000_STATUS_MOUSE_ACTIVE, timeout)) { 240 + dev_err(&i2c->dev, "Timed out waiting for device after %dms\n", 241 + timeout * 10); 242 + return -ETIMEDOUT; 243 + } 244 + 245 + dev_dbg(&i2c->dev, "ANC active\n"); 246 + if (analogue) 247 + dev_dbg(&i2c->dev, "Analogue active\n"); 248 + wm2000->anc_mode = ANC_ACTIVE; 249 + 250 + return 0; 251 + } 252 + 253 + static int wm2000_power_down(struct i2c_client *i2c, int analogue) 254 + { 255 + struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); 256 + int timeout; 257 + 258 + if (analogue) { 259 + timeout = 248; 260 + wm2000_write(i2c, WM2000_REG_ANA_VMID_PD_TIME, timeout / 4); 261 + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, 262 + WM2000_MODE_ANA_SEQ_INCLUDE | 263 + WM2000_MODE_POWER_DOWN); 264 + } else { 265 + timeout = 10; 266 + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, 267 + WM2000_MODE_POWER_DOWN); 268 + } 269 + 270 + if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, 271 + WM2000_STATUS_POWER_DOWN_COMPLETE, timeout)) { 272 + dev_err(&i2c->dev, "Timeout waiting for ANC power down\n"); 273 + return -ETIMEDOUT; 274 + } 275 + 276 + if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT, 277 + WM2000_ANC_ENG_IDLE, 1)) { 278 + dev_err(&i2c->dev, "Timeout waiting for ANC engine idle\n"); 279 + return -ETIMEDOUT; 280 + } 281 + 282 + dev_dbg(&i2c->dev, "powered off\n"); 283 + wm2000->anc_mode = ANC_OFF; 284 + 285 + return 0; 286 + } 287 + 288 + static int wm2000_enter_bypass(struct i2c_client *i2c, int analogue) 289 + { 290 + struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); 291 + 292 + BUG_ON(wm2000->anc_mode != ANC_ACTIVE); 293 + 294 + if (analogue) { 295 + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, 296 + WM2000_MODE_ANA_SEQ_INCLUDE | 297 + WM2000_MODE_THERMAL_ENABLE | 298 + WM2000_MODE_BYPASS_ENTRY); 299 + } else { 300 + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, 301 + WM2000_MODE_THERMAL_ENABLE | 302 + WM2000_MODE_BYPASS_ENTRY); 303 + } 304 + 305 + if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, 306 + WM2000_STATUS_ANC_DISABLED, 10)) { 307 + dev_err(&i2c->dev, "Timeout waiting for ANC disable\n"); 308 + return -ETIMEDOUT; 309 + } 310 + 311 + if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT, 312 + WM2000_ANC_ENG_IDLE, 1)) { 313 + dev_err(&i2c->dev, "Timeout waiting for ANC engine idle\n"); 314 + return -ETIMEDOUT; 315 + } 316 + 317 + wm2000_write(i2c, WM2000_REG_SYS_CTL1, WM2000_SYS_STBY); 318 + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_CLR); 319 + 320 + wm2000->anc_mode = ANC_BYPASS; 321 + dev_dbg(&i2c->dev, "bypass enabled\n"); 322 + 323 + return 0; 324 + } 325 + 326 + static int wm2000_exit_bypass(struct i2c_client *i2c, int analogue) 327 + { 328 + struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); 329 + 330 + BUG_ON(wm2000->anc_mode != ANC_BYPASS); 331 + 332 + wm2000_write(i2c, WM2000_REG_SYS_CTL1, 0); 333 + 334 + if (analogue) { 335 + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, 336 + WM2000_MODE_ANA_SEQ_INCLUDE | 337 + WM2000_MODE_MOUSE_ENABLE | 338 + WM2000_MODE_THERMAL_ENABLE); 339 + } else { 340 + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, 341 + WM2000_MODE_MOUSE_ENABLE | 342 + WM2000_MODE_THERMAL_ENABLE); 343 + } 344 + 345 + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_SET); 346 + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_INT_N_CLR); 347 + 348 + if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, 349 + WM2000_STATUS_MOUSE_ACTIVE, 10)) { 350 + dev_err(&i2c->dev, "Timed out waiting for MOUSE\n"); 351 + return -ETIMEDOUT; 352 + } 353 + 354 + wm2000->anc_mode = ANC_ACTIVE; 355 + dev_dbg(&i2c->dev, "MOUSE active\n"); 356 + 357 + return 0; 358 + } 359 + 360 + static int wm2000_enter_standby(struct i2c_client *i2c, int analogue) 361 + { 362 + struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); 363 + int timeout; 364 + 365 + BUG_ON(wm2000->anc_mode != ANC_ACTIVE); 366 + 367 + if (analogue) { 368 + timeout = 248; 369 + wm2000_write(i2c, WM2000_REG_ANA_VMID_PD_TIME, timeout / 4); 370 + 371 + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, 372 + WM2000_MODE_ANA_SEQ_INCLUDE | 373 + WM2000_MODE_THERMAL_ENABLE | 374 + WM2000_MODE_STANDBY_ENTRY); 375 + } else { 376 + timeout = 10; 377 + 378 + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, 379 + WM2000_MODE_THERMAL_ENABLE | 380 + WM2000_MODE_STANDBY_ENTRY); 381 + } 382 + 383 + if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, 384 + WM2000_STATUS_ANC_DISABLED, timeout)) { 385 + dev_err(&i2c->dev, 386 + "Timed out waiting for ANC disable after 1ms\n"); 387 + return -ETIMEDOUT; 388 + } 389 + 390 + if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT, WM2000_ANC_ENG_IDLE, 391 + 1)) { 392 + dev_err(&i2c->dev, 393 + "Timed out waiting for standby after %dms\n", 394 + timeout * 10); 395 + return -ETIMEDOUT; 396 + } 397 + 398 + wm2000_write(i2c, WM2000_REG_SYS_CTL1, WM2000_SYS_STBY); 399 + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_CLR); 400 + 401 + wm2000->anc_mode = ANC_STANDBY; 402 + dev_dbg(&i2c->dev, "standby\n"); 403 + if (analogue) 404 + dev_dbg(&i2c->dev, "Analogue disabled\n"); 405 + 406 + return 0; 407 + } 408 + 409 + static int wm2000_exit_standby(struct i2c_client *i2c, int analogue) 410 + { 411 + struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); 412 + int timeout; 413 + 414 + BUG_ON(wm2000->anc_mode != ANC_STANDBY); 415 + 416 + wm2000_write(i2c, WM2000_REG_SYS_CTL1, 0); 417 + 418 + if (analogue) { 419 + timeout = 248; 420 + wm2000_write(i2c, WM2000_REG_ANA_VMID_PU_TIME, timeout / 4); 421 + 422 + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, 423 + WM2000_MODE_ANA_SEQ_INCLUDE | 424 + WM2000_MODE_THERMAL_ENABLE | 425 + WM2000_MODE_MOUSE_ENABLE); 426 + } else { 427 + timeout = 10; 428 + 429 + wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL, 430 + WM2000_MODE_THERMAL_ENABLE | 431 + WM2000_MODE_MOUSE_ENABLE); 432 + } 433 + 434 + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_SET); 435 + wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_INT_N_CLR); 436 + 437 + if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, 438 + WM2000_STATUS_MOUSE_ACTIVE, timeout)) { 439 + dev_err(&i2c->dev, "Timed out waiting for MOUSE after %dms\n", 440 + timeout * 10); 441 + return -ETIMEDOUT; 442 + } 443 + 444 + wm2000->anc_mode = ANC_ACTIVE; 445 + dev_dbg(&i2c->dev, "MOUSE active\n"); 446 + if (analogue) 447 + dev_dbg(&i2c->dev, "Analogue enabled\n"); 448 + 449 + return 0; 450 + } 451 + 452 + typedef int (*wm2000_mode_fn)(struct i2c_client *i2c, int analogue); 453 + 454 + static struct { 455 + enum wm2000_anc_mode source; 456 + enum wm2000_anc_mode dest; 457 + int analogue; 458 + wm2000_mode_fn step[2]; 459 + } anc_transitions[] = { 460 + { 461 + .source = ANC_OFF, 462 + .dest = ANC_ACTIVE, 463 + .analogue = 1, 464 + .step = { 465 + wm2000_power_up, 466 + }, 467 + }, 468 + { 469 + .source = ANC_OFF, 470 + .dest = ANC_STANDBY, 471 + .step = { 472 + wm2000_power_up, 473 + wm2000_enter_standby, 474 + }, 475 + }, 476 + { 477 + .source = ANC_OFF, 478 + .dest = ANC_BYPASS, 479 + .analogue = 1, 480 + .step = { 481 + wm2000_power_up, 482 + wm2000_enter_bypass, 483 + }, 484 + }, 485 + { 486 + .source = ANC_ACTIVE, 487 + .dest = ANC_BYPASS, 488 + .analogue = 1, 489 + .step = { 490 + wm2000_enter_bypass, 491 + }, 492 + }, 493 + { 494 + .source = ANC_ACTIVE, 495 + .dest = ANC_STANDBY, 496 + .analogue = 1, 497 + .step = { 498 + wm2000_enter_standby, 499 + }, 500 + }, 501 + { 502 + .source = ANC_ACTIVE, 503 + .dest = ANC_OFF, 504 + .analogue = 1, 505 + .step = { 506 + wm2000_power_down, 507 + }, 508 + }, 509 + { 510 + .source = ANC_BYPASS, 511 + .dest = ANC_ACTIVE, 512 + .analogue = 1, 513 + .step = { 514 + wm2000_exit_bypass, 515 + }, 516 + }, 517 + { 518 + .source = ANC_BYPASS, 519 + .dest = ANC_STANDBY, 520 + .analogue = 1, 521 + .step = { 522 + wm2000_exit_bypass, 523 + wm2000_enter_standby, 524 + }, 525 + }, 526 + { 527 + .source = ANC_BYPASS, 528 + .dest = ANC_OFF, 529 + .step = { 530 + wm2000_exit_bypass, 531 + wm2000_power_down, 532 + }, 533 + }, 534 + { 535 + .source = ANC_STANDBY, 536 + .dest = ANC_ACTIVE, 537 + .analogue = 1, 538 + .step = { 539 + wm2000_exit_standby, 540 + }, 541 + }, 542 + { 543 + .source = ANC_STANDBY, 544 + .dest = ANC_BYPASS, 545 + .analogue = 1, 546 + .step = { 547 + wm2000_exit_standby, 548 + wm2000_enter_bypass, 549 + }, 550 + }, 551 + { 552 + .source = ANC_STANDBY, 553 + .dest = ANC_OFF, 554 + .step = { 555 + wm2000_exit_standby, 556 + wm2000_power_down, 557 + }, 558 + }, 559 + }; 560 + 561 + static int wm2000_anc_transition(struct wm2000_priv *wm2000, 562 + enum wm2000_anc_mode mode) 563 + { 564 + struct i2c_client *i2c = wm2000->i2c; 565 + int i, j; 566 + int ret; 567 + 568 + if (wm2000->anc_mode == mode) 569 + return 0; 570 + 571 + for (i = 0; i < ARRAY_SIZE(anc_transitions); i++) 572 + if (anc_transitions[i].source == wm2000->anc_mode && 573 + anc_transitions[i].dest == mode) 574 + break; 575 + if (i == ARRAY_SIZE(anc_transitions)) { 576 + dev_err(&i2c->dev, "No transition for %d->%d\n", 577 + wm2000->anc_mode, mode); 578 + return -EINVAL; 579 + } 580 + 581 + for (j = 0; j < ARRAY_SIZE(anc_transitions[j].step); j++) { 582 + if (!anc_transitions[i].step[j]) 583 + break; 584 + ret = anc_transitions[i].step[j](i2c, 585 + anc_transitions[i].analogue); 586 + if (ret != 0) 587 + return ret; 588 + } 589 + 590 + return 0; 591 + } 592 + 593 + static int wm2000_anc_set_mode(struct wm2000_priv *wm2000) 594 + { 595 + struct i2c_client *i2c = wm2000->i2c; 596 + enum wm2000_anc_mode mode; 597 + 598 + if (wm2000->anc_eng_ena && wm2000->spk_ena) 599 + if (wm2000->anc_active) 600 + mode = ANC_ACTIVE; 601 + else 602 + mode = ANC_BYPASS; 603 + else 604 + mode = ANC_STANDBY; 605 + 606 + dev_dbg(&i2c->dev, "Set mode %d (enabled %d, mute %d, active %d)\n", 607 + mode, wm2000->anc_eng_ena, !wm2000->spk_ena, 608 + wm2000->anc_active); 609 + 610 + return wm2000_anc_transition(wm2000, mode); 611 + } 612 + 613 + static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol, 614 + struct snd_ctl_elem_value *ucontrol) 615 + { 616 + struct wm2000_priv *wm2000 = dev_get_drvdata(&wm2000_i2c->dev); 617 + 618 + ucontrol->value.enumerated.item[0] = wm2000->anc_active; 619 + 620 + return 0; 621 + } 622 + 623 + static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol, 624 + struct snd_ctl_elem_value *ucontrol) 625 + { 626 + struct wm2000_priv *wm2000 = dev_get_drvdata(&wm2000_i2c->dev); 627 + int anc_active = ucontrol->value.enumerated.item[0]; 628 + 629 + if (anc_active > 1) 630 + return -EINVAL; 631 + 632 + wm2000->anc_active = anc_active; 633 + 634 + return wm2000_anc_set_mode(wm2000); 635 + } 636 + 637 + static int wm2000_speaker_get(struct snd_kcontrol *kcontrol, 638 + struct snd_ctl_elem_value *ucontrol) 639 + { 640 + struct wm2000_priv *wm2000 = dev_get_drvdata(&wm2000_i2c->dev); 641 + 642 + ucontrol->value.enumerated.item[0] = wm2000->spk_ena; 643 + 644 + return 0; 645 + } 646 + 647 + static int wm2000_speaker_put(struct snd_kcontrol *kcontrol, 648 + struct snd_ctl_elem_value *ucontrol) 649 + { 650 + struct wm2000_priv *wm2000 = dev_get_drvdata(&wm2000_i2c->dev); 651 + int val = ucontrol->value.enumerated.item[0]; 652 + 653 + if (val > 1) 654 + return -EINVAL; 655 + 656 + wm2000->spk_ena = val; 657 + 658 + return wm2000_anc_set_mode(wm2000); 659 + } 660 + 661 + static const struct snd_kcontrol_new wm2000_controls[] = { 662 + SOC_SINGLE_BOOL_EXT("WM2000 ANC Switch", 0, 663 + wm2000_anc_mode_get, 664 + wm2000_anc_mode_put), 665 + SOC_SINGLE_BOOL_EXT("WM2000 Switch", 0, 666 + wm2000_speaker_get, 667 + wm2000_speaker_put), 668 + }; 669 + 670 + static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w, 671 + struct snd_kcontrol *kcontrol, int event) 672 + { 673 + struct wm2000_priv *wm2000 = dev_get_drvdata(&wm2000_i2c->dev); 674 + 675 + if (SND_SOC_DAPM_EVENT_ON(event)) 676 + wm2000->anc_eng_ena = 1; 677 + 678 + if (SND_SOC_DAPM_EVENT_OFF(event)) 679 + wm2000->anc_eng_ena = 0; 680 + 681 + return wm2000_anc_set_mode(wm2000); 682 + } 683 + 684 + static const struct snd_soc_dapm_widget wm2000_dapm_widgets[] = { 685 + /* Externally visible pins */ 686 + SND_SOC_DAPM_OUTPUT("WM2000 SPKN"), 687 + SND_SOC_DAPM_OUTPUT("WM2000 SPKP"), 688 + 689 + SND_SOC_DAPM_INPUT("WM2000 LINN"), 690 + SND_SOC_DAPM_INPUT("WM2000 LINP"), 691 + 692 + SND_SOC_DAPM_PGA_E("ANC Engine", SND_SOC_NOPM, 0, 0, NULL, 0, 693 + wm2000_anc_power_event, 694 + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 695 + }; 696 + 697 + /* Target, Path, Source */ 698 + static const struct snd_soc_dapm_route audio_map[] = { 699 + { "WM2000 SPKN", NULL, "ANC Engine" }, 700 + { "WM2000 SPKP", NULL, "ANC Engine" }, 701 + { "ANC Engine", NULL, "WM2000 LINN" }, 702 + { "ANC Engine", NULL, "WM2000 LINP" }, 703 + }; 704 + 705 + /* Called from the machine driver */ 706 + int wm2000_add_controls(struct snd_soc_codec *codec) 707 + { 708 + int ret; 709 + 710 + if (!wm2000_i2c) { 711 + pr_err("WM2000 not yet probed\n"); 712 + return -ENODEV; 713 + } 714 + 715 + ret = snd_soc_dapm_new_controls(codec, wm2000_dapm_widgets, 716 + ARRAY_SIZE(wm2000_dapm_widgets)); 717 + if (ret < 0) 718 + return ret; 719 + 720 + ret = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); 721 + if (ret < 0) 722 + return ret; 723 + 724 + return snd_soc_add_controls(codec, wm2000_controls, 725 + ARRAY_SIZE(wm2000_controls)); 726 + } 727 + EXPORT_SYMBOL_GPL(wm2000_add_controls); 728 + 729 + static int __devinit wm2000_i2c_probe(struct i2c_client *i2c, 730 + const struct i2c_device_id *i2c_id) 731 + { 732 + struct wm2000_priv *wm2000; 733 + struct wm2000_platform_data *pdata; 734 + const char *filename; 735 + const struct firmware *fw; 736 + int reg, ret; 737 + u16 id; 738 + 739 + if (wm2000_i2c) { 740 + dev_err(&i2c->dev, "Another WM2000 is already registered\n"); 741 + return -EINVAL; 742 + } 743 + 744 + wm2000 = kzalloc(sizeof(struct wm2000_priv), GFP_KERNEL); 745 + if (wm2000 == NULL) { 746 + dev_err(&i2c->dev, "Unable to allocate private data\n"); 747 + return -ENOMEM; 748 + } 749 + 750 + /* Verify that this is a WM2000 */ 751 + reg = wm2000_read(i2c, WM2000_REG_ID1); 752 + id = reg << 8; 753 + reg = wm2000_read(i2c, WM2000_REG_ID2); 754 + id |= reg & 0xff; 755 + 756 + if (id != 0x2000) { 757 + dev_err(&i2c->dev, "Device is not a WM2000 - ID %x\n", id); 758 + ret = -ENODEV; 759 + goto err; 760 + } 761 + 762 + reg = wm2000_read(i2c, WM2000_REG_REVISON); 763 + dev_info(&i2c->dev, "revision %c\n", reg + 'A'); 764 + 765 + filename = "wm2000_anc.bin"; 766 + pdata = dev_get_platdata(&i2c->dev); 767 + if (pdata) { 768 + wm2000->mclk_div = pdata->mclkdiv2; 769 + wm2000->speech_clarity = !pdata->speech_enh_disable; 770 + 771 + if (pdata->download_file) 772 + filename = pdata->download_file; 773 + } 774 + 775 + ret = request_firmware(&fw, filename, &i2c->dev); 776 + if (ret != 0) { 777 + dev_err(&i2c->dev, "Failed to acquire ANC data: %d\n", ret); 778 + goto err; 779 + } 780 + 781 + /* Pre-cook the concatenation of the register address onto the image */ 782 + wm2000->anc_download_size = fw->size + 2; 783 + wm2000->anc_download = kmalloc(wm2000->anc_download_size, GFP_KERNEL); 784 + if (wm2000->anc_download == NULL) { 785 + dev_err(&i2c->dev, "Out of memory\n"); 786 + ret = -ENOMEM; 787 + goto err_fw; 788 + } 789 + 790 + wm2000->anc_download[0] = 0x80; 791 + wm2000->anc_download[1] = 0x00; 792 + memcpy(wm2000->anc_download + 2, fw->data, fw->size); 793 + 794 + release_firmware(fw); 795 + 796 + dev_set_drvdata(&i2c->dev, wm2000); 797 + wm2000->anc_eng_ena = 1; 798 + wm2000->i2c = i2c; 799 + 800 + wm2000_reset(wm2000); 801 + 802 + /* This will trigger a transition to standby mode by default */ 803 + wm2000_anc_set_mode(wm2000); 804 + 805 + wm2000_i2c = i2c; 806 + 807 + return 0; 808 + 809 + err_fw: 810 + release_firmware(fw); 811 + err: 812 + kfree(wm2000); 813 + return ret; 814 + } 815 + 816 + static __devexit int wm2000_i2c_remove(struct i2c_client *i2c) 817 + { 818 + struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); 819 + 820 + wm2000_anc_transition(wm2000, ANC_OFF); 821 + 822 + wm2000_i2c = NULL; 823 + kfree(wm2000->anc_download); 824 + kfree(wm2000); 825 + 826 + return 0; 827 + } 828 + 829 + static void wm2000_i2c_shutdown(struct i2c_client *i2c) 830 + { 831 + struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); 832 + 833 + wm2000_anc_transition(wm2000, ANC_OFF); 834 + } 835 + 836 + #ifdef CONFIG_PM 837 + static int wm2000_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg) 838 + { 839 + struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); 840 + 841 + return wm2000_anc_transition(wm2000, ANC_OFF); 842 + } 843 + 844 + static int wm2000_i2c_resume(struct i2c_client *i2c) 845 + { 846 + struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); 847 + 848 + return wm2000_anc_set_mode(wm2000); 849 + } 850 + #else 851 + #define wm2000_i2c_suspend NULL 852 + #define wm2000_i2c_resume NULL 853 + #endif 854 + 855 + static const struct i2c_device_id wm2000_i2c_id[] = { 856 + { "wm2000", 0 }, 857 + { } 858 + }; 859 + MODULE_DEVICE_TABLE(i2c, wm2000_i2c_id); 860 + 861 + static struct i2c_driver wm2000_i2c_driver = { 862 + .driver = { 863 + .name = "wm2000", 864 + .owner = THIS_MODULE, 865 + }, 866 + .probe = wm2000_i2c_probe, 867 + .remove = __devexit_p(wm2000_i2c_remove), 868 + .suspend = wm2000_i2c_suspend, 869 + .resume = wm2000_i2c_resume, 870 + .shutdown = wm2000_i2c_shutdown, 871 + .id_table = wm2000_i2c_id, 872 + }; 873 + 874 + static int __init wm2000_init(void) 875 + { 876 + return i2c_add_driver(&wm2000_i2c_driver); 877 + } 878 + module_init(wm2000_init); 879 + 880 + static void __exit wm2000_exit(void) 881 + { 882 + i2c_del_driver(&wm2000_i2c_driver); 883 + } 884 + module_exit(wm2000_exit); 885 + 886 + MODULE_DESCRIPTION("ASoC WM2000 driver"); 887 + MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>"); 888 + MODULE_LICENSE("GPL");
+79
sound/soc/codecs/wm2000.h
··· 1 + /* 2 + * wm2000.h -- WM2000 Soc Audio driver 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + 9 + #ifndef _WM2000_H 10 + #define _WM2000_H 11 + 12 + struct wm2000_setup_data { 13 + unsigned short i2c_address; 14 + int mclk_div; /* Set to a non-zero value if MCLK_DIV_2 required */ 15 + }; 16 + 17 + extern int wm2000_add_controls(struct snd_soc_codec *codec); 18 + 19 + extern struct snd_soc_dai wm2000_dai; 20 + extern struct snd_soc_codec_device soc_codec_dev_wm2000; 21 + 22 + #define WM2000_REG_SYS_START 0x8000 23 + #define WM2000_REG_SPEECH_CLARITY 0x8fef 24 + #define WM2000_REG_SYS_WATCHDOG 0x8ff6 25 + #define WM2000_REG_ANA_VMID_PD_TIME 0x8ff7 26 + #define WM2000_REG_ANA_VMID_PU_TIME 0x8ff8 27 + #define WM2000_REG_CAT_FLTR_INDX 0x8ff9 28 + #define WM2000_REG_CAT_GAIN_0 0x8ffa 29 + #define WM2000_REG_SYS_STATUS 0x8ffc 30 + #define WM2000_REG_SYS_MODE_CNTRL 0x8ffd 31 + #define WM2000_REG_SYS_START0 0x8ffe 32 + #define WM2000_REG_SYS_START1 0x8fff 33 + #define WM2000_REG_ID1 0xf000 34 + #define WM2000_REG_ID2 0xf001 35 + #define WM2000_REG_REVISON 0xf002 36 + #define WM2000_REG_SYS_CTL1 0xf003 37 + #define WM2000_REG_SYS_CTL2 0xf004 38 + #define WM2000_REG_ANC_STAT 0xf005 39 + #define WM2000_REG_IF_CTL 0xf006 40 + 41 + /* SPEECH_CLARITY */ 42 + #define WM2000_SPEECH_CLARITY 0x01 43 + 44 + /* SYS_STATUS */ 45 + #define WM2000_STATUS_MOUSE_ACTIVE 0x40 46 + #define WM2000_STATUS_CAT_FREQ_COMPLETE 0x20 47 + #define WM2000_STATUS_CAT_GAIN_COMPLETE 0x10 48 + #define WM2000_STATUS_THERMAL_SHUTDOWN_COMPLETE 0x08 49 + #define WM2000_STATUS_ANC_DISABLED 0x04 50 + #define WM2000_STATUS_POWER_DOWN_COMPLETE 0x02 51 + #define WM2000_STATUS_BOOT_COMPLETE 0x01 52 + 53 + /* SYS_MODE_CNTRL */ 54 + #define WM2000_MODE_ANA_SEQ_INCLUDE 0x80 55 + #define WM2000_MODE_MOUSE_ENABLE 0x40 56 + #define WM2000_MODE_CAT_FREQ_ENABLE 0x20 57 + #define WM2000_MODE_CAT_GAIN_ENABLE 0x10 58 + #define WM2000_MODE_BYPASS_ENTRY 0x08 59 + #define WM2000_MODE_STANDBY_ENTRY 0x04 60 + #define WM2000_MODE_THERMAL_ENABLE 0x02 61 + #define WM2000_MODE_POWER_DOWN 0x01 62 + 63 + /* SYS_CTL1 */ 64 + #define WM2000_SYS_STBY 0x01 65 + 66 + /* SYS_CTL2 */ 67 + #define WM2000_MCLK_DIV2_ENA_CLR 0x80 68 + #define WM2000_MCLK_DIV2_ENA_SET 0x40 69 + #define WM2000_ANC_ENG_CLR 0x20 70 + #define WM2000_ANC_ENG_SET 0x10 71 + #define WM2000_ANC_INT_N_CLR 0x08 72 + #define WM2000_ANC_INT_N_SET 0x04 73 + #define WM2000_RAM_CLR 0x02 74 + #define WM2000_RAM_SET 0x01 75 + 76 + /* ANC_STAT */ 77 + #define WM2000_ANC_ENG_IDLE 0x01 78 + 79 + #endif