/*
* wm8940.c -- WM8940 ALSA Soc Audio driver
*
* Author: Jonathan Cameron <jic23@cam.ac.uk>
*
* Based on wm8510.c
* Copyright 2006 Wolfson Microelectronics PLC.
* Author: Liam Girdwood <lrg@slimlogic.co.uk>
*
* 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.
*
* Not currently handled:
* Notch filter control
* AUXMode (inverting vs mixer)
* No means to obtain current gain if alc enabled.
* No use made of gpio
* Fast VMID discharge for power down
* Soft Start
* DLR and ALR Swaps not enabled
* Digital Sidetone not supported
*/
#include <linux/module.h>
#include <linux/moduleparam.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 <linux/spi/spi.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 "wm8940.h"
struct wm8940_priv {
unsigned int sysclk;
u16 reg_cache[WM8940_CACHEREGNUM];
struct snd_soc_codec codec;
};
static u16 wm8940_reg_defaults[] = {
0x8940, /* Soft Reset */
0x0000, /* Power 1 */
0x0000, /* Power 2 */
0x0000, /* Power 3 */
0x0010, /* Interface Control */
0x0000, /* Companding Control */
0x0140, /* Clock Control */
0x0000, /* Additional Controls */
0x0000, /* GPIO Control */
0x0002, /* Auto Increment Control */
0x0000, /* DAC Control */
0x00FF, /* DAC Volume */
0,
0,
0x0100, /* ADC Control */
0x00FF, /* ADC Volume */
0x0000, /* Notch Filter 1 Control 1 */
0x0000, /* Notch Filter 1 Control 2 */
0x0000, /* Notch Filter 2 Control 1 */
0x0000, /* Notch Filter 2 Control 2 */
0x0000, /* Notch Filter 3 Control 1 */
0x0000, /* Notch Filter 3 Control 2 */
0x0000, /* Notch Filter 4 Control 1 */
0x0000, /* Notch Filter 4 Control 2 */
0x0032, /* DAC Limit Control 1 */
0x0000, /* DAC Limit Control 2 */
0,
0,
0,
0,
0,
0,
0x0038, /* ALC Control 1 */
0x000B, /* ALC Control 2 */
0x0032, /* ALC Control 3 */
0x0000, /* Noise Gate */
0x0041, /* PLLN */
0x000C, /* PLLK1 */
0x0093, /* PLLK2 */
0x00E9, /* PLLK3 */
0,
0,
0x0030, /* ALC Control 4 */
0,
0x0002, /* Input Control */
0x0050, /* PGA Gain */
0,
0x0002, /* ADC Boost Control */
0,
0x0002, /* Output Control */
0x0000, /* Speaker Mixer Control */
0,
0,
0,
0x0079, /* Speaker Volume */
0,
0x0000, /* Mono Mixer Control */
};
static inline unsigned int wm8940_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
if (reg >= ARRAY_SIZE(wm8940_reg_defaults))
return -1;
return cache[reg];
}
static inline int wm8940_write_reg_cache(struct snd_soc_codec *codec,
u16 reg, unsigned int value)
{
u16 *cache = codec->reg_cache;
if (reg >= ARRAY_SIZE(wm8940_reg_defaults))
return -1;
cache[reg] = value;
return 0;
}
static int wm8940_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
int ret;
u8 data[3] = { reg,
(value & 0xff00) >> 8,
(value & 0x00ff)
};
wm8940_write_reg_cache(codec, reg, value);
ret = codec->hw_write(codec->control_data, data, 3);
if (ret < 0)
return ret;
else if (ret != 3)
return -EIO;
return 0;
}
static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" };
static const struct soc_enum wm8940_adc_companding_enum
= SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 1, 4, wm8940_companding);
static const struct soc_enum wm8940_dac_companding_enum
= SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 3, 4, wm8940_companding);
static const char *wm8940_alc_mode_text[] = {"ALC", "Limiter"};
static const struct soc_enum wm8940_alc_mode_enum
= SOC_ENUM_SINGLE(WM8940_ALC3, 8, 2, wm8940_alc_mode_text);
static const char *wm8940_mic_bias_level_text[] = {"0.9", "0.65"};
static const struct soc_enum wm8940_mic_bias_level_enum
= SOC_ENUM_SINGLE(WM8940_INPUTCTL, 8, 2, wm8940_mic_bias_level_text);
static const char *wm8940_filter_mode_text[] = {"Audio", "Application"};
static const struct soc_enum wm8940_filter_mode_enum
= SOC_ENUM_SINGLE(WM8940_ADC, 7, 2, wm8940_filter_mode_text);
static DECLARE_TLV_DB_SCALE(wm8940_spk_vol_tlv, -5700, 100, 1);
static DECLARE_TLV_DB_SCALE(wm8940_att_tlv,