/*
* wm8974.c -- WM8974 ALSA Soc Audio driver
*
* Copyright 2006 Wolfson Microelectronics PLC.
*
* Author: Liam Girdwood <linux@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/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include "wm8974.h"
static const u16 wm8974_reg[WM8974_CACHEREGNUM] = {
0x0000, 0x0000, 0x0000, 0x0000,
0x0050, 0x0000, 0x0140, 0x0000,
0x0000, 0x0000, 0x0000, 0x00ff,
0x0000, 0x0000, 0x0100, 0x00ff,
0x0000, 0x0000, 0x012c, 0x002c,
0x002c, 0x002c, 0x002c, 0x0000,
0x0032, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0038, 0x000b, 0x0032, 0x0000,
0x0008, 0x000c, 0x0093, 0x00e9,
0x0000, 0x0000, 0x0000, 0x0000,
0x0003, 0x0010, 0x0000, 0x0000,
0x0000, 0x0002, 0x0000, 0x0000,
0x0000, 0x0000, 0x0039, 0x0000,
0x0000,
};
#define WM8974_POWER1_BIASEN 0x08
#define WM8974_POWER1_BUFIOEN 0x10
struct wm8974_priv {
struct snd_soc_codec codec;
u16 reg_cache[WM8974_CACHEREGNUM];
};
static struct snd_soc_codec *wm8974_codec;
/*
* read wm8974 register cache
*/
static inline unsigned int wm8974_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
if (reg == WM8974_RESET)
return 0;
if (reg >= WM8974_CACHEREGNUM)
return -1;
return cache[reg];
}
/*
* write wm8974 register cache
*/
static inline void wm8974_write_reg_cache(struct snd_soc_codec *codec,
u16 reg, unsigned int value)
{
u16 *cache = codec->reg_cache;
if (reg >= WM8974_CACHEREGNUM)
return;
cache[reg] = value;
}
/*
* write to the WM8974 register space
*/
static int wm8974_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
u8 data[2];
/* data is
* D15..D9 WM8974 register offset
* D8...D0 register data
*/
data[0] = (reg << 1) | ((value >> 8) & 0x0001);
data[1] = value & 0x00ff;
wm8974_write_reg_cache(codec, reg, value);
if (codec->hw_write(codec->control_data, data, 2) == 2)
return 0;
else
return -EIO;
}
#define wm8974_reset(c) wm8974_write(c, WM8974_RESET, 0)
static const char *wm8974_companding[] = {"Off", "NC", "u-law", "A-law" };
static const char *wm8974_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz" };
static const char *wm8974_eqmode[] = {"Capture", "Playback" };
static const char *wm8974_bw[] = {"Narrow", "Wide" };
static const char *wm8974_eq1[] = {"80Hz", "105Hz", "135Hz", "175Hz" };
static const char *wm8974_eq2[] = {"230Hz", "300Hz", "385Hz", "500Hz" };
static const char *wm8974_eq3[] = {"650Hz", "850Hz", "1.1kHz", "1.4kHz" };
static const char *wm8974_eq4[] = {"1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz" };
static const char *wm8974_eq5[] = {"5.3kHz", "6.9kHz", "9kHz", "11.7kHz" };
static const char *wm8974_alc[] = {"ALC", "Limiter" };
static const struct soc_enum wm8974_enum[] = {
SOC_ENUM_SINGLE(WM8974_COMP, 1, 4, wm8974_companding), /* adc */
SOC_ENUM_SINGLE(WM8974_COMP, 3, 4, wm8974_companding), /* dac */
SOC_ENUM_SINGLE(WM8974_DAC, 4, 4, wm8974_deemp),
SOC_ENUM_SINGLE(WM8974_EQ1, 8, 2, wm8974_eqmode),
SOC_ENUM_SINGLE(WM8974_EQ1, 5, 4, wm8974_eq1),
SOC_ENUM_SINGLE(WM8974_EQ2, 8, 2, wm8974_bw),
SOC_ENUM_SINGLE(WM8974_EQ2, 5, 4, wm8974_eq2),
SOC_ENUM_SINGLE(WM8974_EQ3, 8, 2, wm8974_bw),
SOC_ENUM_SINGLE(WM8974_EQ3, 5, 4, wm8974_eq3),
SOC_ENUM_SINGLE(WM8974_EQ4, 8, 2, wm8974_bw),
SOC_ENUM_SINGLE(WM8974_EQ4, 5, 4, wm8974_eq4),
SOC_ENUM_SINGLE(WM8974_EQ5, 8, 2, wm8974_bw),
SOC_ENUM_SINGLE(WM8974_EQ5, 5, 4, wm8974_eq5),
SOC_ENUM_SINGLE(WM8974_ALC3, 8, 2, wm8974_alc),
};
static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);
static