/*
* wm8988.c -- WM8988 ALSA SoC audio driver
*
* Copyright 2009 Wolfson Microelectronics plc
* Copyright 2005 Openedhand Ltd.
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/tlv.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include "wm8988.h"
/*
* wm8988 register cache
* We can't read the WM8988 register space when we
* are using 2 wire for device control, so we cache them instead.
*/
static const u16 wm8988_reg[] = {
0x0097, 0x0097, 0x0079, 0x0079, /* 0 */
0x0000, 0x0008, 0x0000, 0x000a, /* 4 */
0x0000, 0x0000, 0x00ff, 0x00ff, /* 8 */
0x000f, 0x000f, 0x0000, 0x0000, /* 12 */
0x0000, 0x007b, 0x0000, 0x0032, /* 16 */
0x0000, 0x00c3, 0x00c3, 0x00c0, /* 20 */
0x0000, 0x0000, 0x0000, 0x0000, /* 24 */
0x0000, 0x0000, 0x0000, 0x0000, /* 28 */
0x0000, 0x0000, 0x0050, 0x0050, /* 32 */
0x0050, 0x0050, 0x0050, 0x0050, /* 36 */
0x0079, 0x0079, 0x0079, /* 40 */
};
/* codec private data */
struct wm8988_priv {
unsigned int sysclk;
struct snd_soc_codec codec;
struct snd_pcm_hw_constraint_list *sysclk_constraints;
u16 reg_cache[WM8988_NUM_REG];
};
#define wm8988_reset(c) snd_soc_write(c, WM8988_RESET, 0)
/*
* WM8988 Controls
*/
static const char *bass_boost_txt[] = {"Linear Control", "Adaptive Boost"};
static const struct soc_enum bass_boost =
SOC_ENUM_SINGLE(WM8988_BASS, 7, 2, bass_boost_txt);
static const char *bass_filter_txt[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" };
static const struct soc_enum bass_filter =
SOC_ENUM_SINGLE(WM8988_BASS, 6, 2, bass_filter_txt);
static const char *treble_txt[] = {"8kHz", "4kHz"};
static const struct soc_enum treble =
SOC_ENUM_SINGLE(WM8988_TREBLE, 6, 2, treble_txt);
static const char *stereo_3d_lc_txt[] = {"200Hz", "500Hz"};
static const struct soc_enum stereo_3d_lc =
SOC_ENUM_SINGLE(WM8988_3D, 5, 2, stereo_3d_lc_txt);
static const char *stereo_3d_uc_txt[] = {"2.2kHz", "1.5kHz"};
static const struct soc_enum stereo_3d_uc =
SOC_ENUM_SINGLE(WM8988_3D, 6, 2, stereo_3d_uc_txt);
static const char *stereo_3d_func_txt[] = {"Capture", "Playback"};
static const struct soc_enum stereo_3d_func =
SOC_ENUM_SINGLE(WM8988_3D, 7, 2, stereo_3d_func_txt);
static const char *alc_func_txt[] = {"Off", "Right", "Left", "Stereo"};
static const struct soc_enum alc_func =
SOC_ENUM_SINGLE(WM8988_ALC1, 7, 4, alc_func_txt);
static const char *ng_type_txt[] = {"Constant PGA Gain",
"Mute ADC Output"};
static const struct soc_enum ng_type =
SOC_ENUM_SINGLE(WM8988_NGATE, 1, 2, ng_type_txt);
static const char *deemph_txt[] = {"None", "32Khz", "44.1Khz", "48Khz"};
static const struct soc_enum deemph =
SOC_ENUM_SINGLE(WM8988_ADCDAC, 1, 4, deemph_txt);
static const char *adcpol_txt[] = {"Normal", "L Invert", "R Invert",
"L + R Invert"};
static const struct soc_enum adcpol =
SOC_ENUM_SINGLE(WM8988_ADCDAC, 5, 4, adcpol_txt);
static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0);
static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1);
static const DECLARE_TLV_DB_SCALE(dac_tlv