/*
* 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 <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];
};
/*
* read wm8988 register cache
*/
static inline unsigned int wm8988_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
if (reg > WM8988_NUM_REG)
return -1;
return cache[reg];
}
/*
* write wm8988 register cache
*/
static inline void wm8988_write_reg_cache(struct snd_soc_codec *codec,
unsigned int reg, unsigned int value)
{
u16 *cache = codec->reg_cache;
if (reg > WM8988_NUM_REG)
return;
cache[reg] = value;
}
static int wm8988_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
u8 data[2];
/* data is
* D15..D9 WM8753 register offset
* D8...D0 register data
*/
data[0] = (reg << 1) | ((value >> 8) & 0x0001);
data[1] = value & 0x00ff;
wm8988_write_reg_cache(codec, reg, value);
if (codec->hw_write(codec->control_data, data, 2) == 2)
return 0;
else
return -EIO;
}
#define wm8988_reset(c) wm8988_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