/*
ALC5632 ALSA SoC Audio Codec
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/regmap.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/tlv.h>
#include <sound/soc.h>
#include <sound/initval.h>
#include "alc5632.h"
/*
* ALC5632 register cache
*/
static struct reg_default alc5632_reg_defaults[] = {
{ 2, 0x8080 }, /* R2 - Speaker Output Volume */
{ 4, 0x8080 }, /* R4 - Headphone Output Volume */
{ 6, 0x8080 }, /* R6 - AUXOUT Volume */
{ 8, 0xC800 }, /* R8 - Phone Input */
{ 10, 0xE808 }, /* R10 - LINE_IN Volume */
{ 12, 0x1010 }, /* R12 - STEREO DAC Input Volume */
{ 14, 0x0808 }, /* R14 - MIC Input Volume */
{ 16, 0xEE0F }, /* R16 - Stereo DAC and MIC Routing Control */
{ 18, 0xCBCB }, /* R18 - ADC Record Gain */
{ 20, 0x7F7F }, /* R20 - ADC Record Mixer Control */
{ 24, 0xE010 }, /* R24 - Voice DAC Volume */
{ 28, 0x8008 }, /* R28 - Output Mixer Control */
{ 34, 0x0000 }, /* R34 - Microphone Control */
{ 36, 0x00C0 }, /* R36 - Codec Digital MIC/Digital Boost
Control */
{ 46, 0x0000 }, /* R46 - Stereo DAC/Voice DAC/Stereo ADC
Function Select */
{ 52, 0x8000 }, /* R52 - Main Serial Data Port Control
(Stereo I2S) */
{ 54, 0x0000 }, /* R54 - Extend Serial Data Port Control
(VoDAC_I2S/PCM) */
{ 58, 0x0000 }, /* R58 - Power Management Addition 1 */
{ 60, 0x0000 }, /* R60 - Power Management Addition 2 */
{ 62, 0x8000 }, /* R62 - Power Management Addition 3 */
{ 64, 0x0C0A }, /* R64 - General Purpose Control Register 1 */
{ 66, 0x0000 }, /* R66 - General Purpose Control Register 2 */
{ 68, 0x0000 }, /* R68 - PLL1 Control */
{ 70, 0x0000 }, /* R70 - PLL2 Control */
{ 76, 0xBE3E }, /* R76 - GPIO Pin Configuration */
{ 78, 0xBE3E }, /* R78 - GPIO Pin Polarity */
{ 80, 0x0000 }, /* R80 - GPIO Pin Sticky */
{ 82, 0x0000 }, /* R82 - GPIO Pin Wake Up */
{ 86, 0x0000 }, /* R86 - Pin Sharing */
{ 90, 0x0009 }, /* R90 - Soft Volume Control Setting */
{ 92, 0x0000 }, /* R92 - GPIO_Output Pin Control */
{ 94, 0x3000 }, /* R94 - MISC Control */
{ 96, 0x3075 }, /* R96 - Stereo DAC Clock Control_1 */
{ 98, 0x1010 }, /* R98 - Stereo DAC Clock Control_2 */
{ 100, 0x3110 }, /* R100 - VoDAC_PCM Clock Control_1 */
{ 104, 0x0553 }, /* R104 - Pseudo Stereo and Spatial Effect
Block Control */
{ 106, 0x0000 }, /* R106 - Private Register Address */
};
/* codec private data */
struct alc5632_priv {
struct regmap *regmap;
u8 id;
unsigned int sysclk;
};
static bool alc5632_volatile_register(struct device *dev,
unsigned int reg)
{
switch (reg) {
case ALC5632_RESET:
case ALC5632_PWR_DOWN_CTRL_STATUS:
case ALC5632_GPIO_PIN_STATUS:
case ALC5632_OVER_CURR_STATUS:
case ALC5632_HID_CTRL_DATA:
case ALC5632_EQ_CTRL:
case ALC5632_VENDOR_ID1:
case ALC5632_VENDOR_ID2:
return true;
default:
break;
}
return false;
}
static inline int alc5632_reset(struct regmap *map)
{
return regmap_write(map, ALC5632_RESET, 0x59B4);
}
static int amp_mixer_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
/* to power-on/off class-d amp generators/speaker */
/* need to write to 'index-46h' register : */
/* so write index num (here 0x46) to reg 0x6a */
/* and then 0xffff/0 to reg 0x6c */
snd_soc_write(w->codec, ALC5632_HID_CTRL_INDEX, 0x46);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
snd_soc_write(w->codec, ALC5632_HID_CTRL_DATA, 0xFFFF);
break;
case SND_SOC_DAPM_POST_PMD:
snd_soc_write(w->codec, ALC5632_HID_CTRL_DATA, 0);
break;
}
return 0;
}
/*
* ALC5632 Controls
*/
/* -34.5db min scale, 1.5db steps, no mute */
static const DECLARE_TLV_DB_SCALE(vol_tlv, -3450, 150, 0);
/* -46.5db min scale, 1.5db steps, no mute */
static const DECLARE_TLV_DB_SCALE(hp_tlv, -4650, 150, 0);
/* -16.5db min scale, 1.5db steps, no mute */
static const DECLARE_TLV_DB_SCALE(adc_rec_tlv, -1650, 150, 0);
static const unsigned int boost_tlv[] = {
TLV_DB_RANGE_HEAD(2),
0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
1, 3, TLV_DB_SCALE_ITEM(2000, 1000, 0),
};
/* 0db min scale, 6 db steps, no mute */
static const DECLARE_TLV_DB_SCALE(dig_tlv, 0, 600, 0);
/* 0db min scalem 0.75db steps, no mute */
static const DECLARE_TLV_DB_SCALE(vdac_tlv, -3525, 75, 0);
static const struct snd_kcontrol_new alc5632_vol_snd_controls[] = {
/* left starts at bit 8, right at bit 0 */
/* 31 steps (5 bit), -46.5db scale */
SOC_DOUBLE_TLV("Speaker Playback Volume",
ALC5632_SPK_OUT_VOL, 8, 0, 31, 1, hp_tlv),
/* bit 15 mutes left, bit 7 right */
SOC_DOUBLE("Speaker Playback Switch",
ALC5632_SPK_OUT_VOL, 15, 7, 1, 1),
SOC_DOUBLE_TLV("Headphone Playback Volume",
ALC5632_HP_OUT_VOL, 8, 0, 31, 1, hp_tlv),
SOC_DOUBLE("Headphone Playback Switch",
ALC5632_HP_OUT_VOL, 15, 7, 1, 1),
};
static const struct snd_kcontrol_new alc5632_snd_controls[] = {
SOC_DOUBLE_TLV("Auxout Playback Volume",
ALC5632_AUX_OUT_VOL, 8, 0, 31, 1, hp_tlv),
SOC_DOUBLE("Auxout Playback Switch",
ALC5632_AUX_OUT_VOL, 15, 7, 1, 1),
SOC_SINGLE_TLV("Voice DAC Playback Volume",
ALC5632_VOICE_DAC_VOL, 0, 63, 0, vdac_tlv),
SOC_SINGLE("Voice DAC Playback Switch",
ALC5632_VOICE_DAC_VOL, 12, 1, 1),
SOC_SINGLE_TLV("Phone Playback Volume",
ALC5632_PHONE_IN_VOL, 8, 31, 1, vol_tlv),
SOC_DOUBLE_TLV("LineIn Playback Volume",
ALC5632_LINE_IN_VOL, 8, 0, 31, 1, vol_tlv),
SOC_DOUBLE_TLV("Master Playback Volume",
ALC5632_STEREO_DAC_IN_VOL, 8, 0, 63, 1, vdac_tlv),
SOC_DOUBLE("Master Playback Switch",
ALC5632_STEREO_DAC_IN_VOL, 15, 7, 1, 1),
SOC_SINGLE_TLV("Mic1 Playback Volume",
ALC5632_MIC_VOL, 8, 31, 1, vol_tlv),
SOC_SINGLE_TLV("Mic2 Playback Volume",
ALC5632_MIC_VOL, 0, 31, 1, vol_tlv),
SOC_DOUBLE_TLV("Rec Capture Volume",
ALC5632_ADC_REC_GAIN, 8, 0, 31, 0, adc_rec_tlv),
SOC_SINGLE_TLV("Mic 1 Boost Volume",
ALC5632_MIC_CTRL, 10, 3, 0, boost_tlv),
SOC_SINGLE_TLV("Mic 2 Boost Volume",
ALC5632_MIC_CTRL, 8, 3, 0, boost_tlv),
SOC_SINGLE_TLV("DMIC Boost Capture Volume",
ALC5632_DIGI_BOOST_CTRL, 0, 7, 0, dig_tlv),
SOC_SINGLE("DMIC En Capture Switch",
ALC5632_DIGI_BOOST_CTRL, 15, 1, 0),
SOC_SINGLE("DMIC PreFilter Capture Switch",
ALC5632_DIGI_BOOST_CTRL, 12, 1, 0),
};
/*
* DAPM Controls
*/
static const struct snd_kcontrol_new alc5632_hp_mixer_controls[] = {
SOC_DAPM_SINGLE("LI2HP Playback Switch", ALC5632_LINE_IN_VOL, 15, 1, 1),
SOC_DAPM_SINGLE("PHONE2HP Playback Switch", ALC5632_PHONE_IN_VOL, 15, 1, 1),
SOC_DAPM_SINGLE("MIC12HP Playback Switch", ALC5632_MIC_ROUTING_CTRL, 15, 1, 1),
SOC_DAPM_SINGLE("MIC22HP Playback Switch", ALC5632_MIC_ROUTING_CTRL, 11, 1, 1),
SOC_DAPM_SINGLE("VOICE2HP Playback Switch", ALC5632_VOICE_DAC_VOL, 15, 1, 1),
};
static const struct snd_kcontrol_new alc5632_hpl_mixer_controls[] = {
SOC_DAPM_SINGLE("ADC2HP_L Playback Switch", ALC5632_ADC_REC_GAIN, 15, 1, 1),
SOC_DAPM_SINGLE("DACL2HP Playback Switch", ALC5632_MIC_ROUTING_CTRL, 3, 1, 1),
};
static const struct snd_kcontrol_new alc5632_hpr_mixer_controls[] = {
SOC_DAPM_SINGLE("ADC2HP_R Playback Switch", ALC5632_ADC_REC_GAIN, 7, 1, 1),
SOC_DAPM_SINGLE("DACR2HP Playback Switch", ALC5632_MIC_ROUTING_CTRL, 2, 1, 1),
};
static const struct snd_kcontrol_new alc5632_mono_mixer_controls[] = {
SOC_DAPM_SINGLE("ADC2MONO_L Playback Switch", ALC5632_ADC_REC_GAIN, 14, 1, 1),
SOC_DAPM_SINGLE("ADC2MONO_R Playback Switch", ALC5632_ADC_REC_GAIN, 6, 1, 1),
SOC_DAPM_SINGLE("LI2MONO Playback Switch", ALC5632_LINE_IN_VOL, 13, 1, 1),
SOC_DAPM_SINGLE("MIC12MONO Playback Switch",
ALC5632_MIC_ROUTING_CTRL, 13, 1, 1),
SOC_DAPM_SINGLE("MIC22MONO Playback Switch",
ALC5632_MIC_ROUTING_CTRL, 9, 1, 1),
SOC_DAPM_SINGLE("DAC2MONO Playback Switch", ALC5632_MIC_ROUTING_CTRL, 0, 1, 1),
SOC_DAPM_SINGLE("VOICE2MONO Playback Switch", ALC5632_