// SPDX-License-Identifier: GPL-2.0-only
/*
* alc5632.c -- ALC5632 ALSA SoC Audio Codec
*
* Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
*
* Authors: Leon Romanovsky <leon@leon.nu>
* Andrey Danin <danindrey@mail.ru>
* Ilya Petrov <ilya.muromec@gmail.com>
* Marc Dietrich <marvin24@gmx.de>
*
* Based on alc5623.c by Arnaud Patard
*/
#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 const 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)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
/* 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_component_write(component, ALC5632_HID_CTRL_INDEX, 0x46);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
snd_soc_component_write(component, ALC5632_HID_CTRL_DATA, 0xFFFF);
break;
case SND_SOC_DAPM_POST_PMD:
snd_soc_component_write(component, 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);