// SPDX-License-Identifier: GPL-2.0-only
/*
* Analog Devices ADAU1372 Audio Codec driver
*
* Copyright 2016 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/tlv.h>
#include <sound/soc.h>
#include "adau1372.h"
#include "adau-utils.h"
struct adau1372 {
struct regmap *regmap;
void (*switch_mode)(struct device *dev);
bool use_pll;
bool enabled;
bool clock_provider;
struct snd_pcm_hw_constraint_list rate_constraints;
unsigned int slot_width;
struct clk *mclk;
struct gpio_desc *pd_gpio;
struct device *dev;
};
#define ADAU1372_REG_CLK_CTRL 0x00
#define ADAU1372_REG_PLL(x) (0x01 + (x))
#define ADAU1372_REG_DAC_SOURCE 0x11
#define ADAU1372_REG_SOUT_SOURCE_0_1 0x13
#define ADAU1372_REG_SOUT_SOURCE_2_3 0x14
#define ADAU1372_REG_SOUT_SOURCE_4_5 0x15
#define ADAU1372_REG_SOUT_SOURCE_6_7 0x16
#define ADAU1372_REG_ADC_SDATA_CH 0x17
#define ADAU1372_REG_ASRCO_SOURCE_0_1 0x18
#define ADAU1372_REG_ASRCO_SOURCE_2_3 0x19
#define ADAU1372_REG_ASRC_MODE 0x1a
#define ADAU1372_REG_ADC_CTRL0 0x1b
#define ADAU1372_REG_ADC_CTRL1 0x1c
#define ADAU1372_REG_ADC_CTRL2 0x1d
#define ADAU1372_REG_ADC_CTRL3 0x1e
#define ADAU1372_REG_ADC_VOL(x) (0x1f + (x))
#define ADAU1372_REG_PGA_CTRL(x) (0x23 + (x))
#define ADAU1372_REG_PGA_BOOST 0x28
#define ADAU1372_REG_MICBIAS 0x2d
#define ADAU1372_REG_DAC_CTRL 0x2e
#define ADAU1372_REG_DAC_VOL(x) (0x2f + (x))
#define ADAU1372_REG_OP_STAGE_MUTE 0x31
#define ADAU1372_REG_SAI0 0x32
#define ADAU1372_REG_SAI1 0x33
#define ADAU1372_REG_SOUT_CTRL 0x34
#define ADAU1372_REG_MODE_MP(x) (0x38 + (x))
#define ADAU1372_REG_OP_STAGE_CTRL 0x43
#define ADAU1372_REG_DECIM_PWR 0x44
#define ADAU1372_REG_INTERP_PWR 0x45
#define ADAU1372_REG_BIAS_CTRL0 0x46
#define ADAU1372_REG_BIAS_CTRL1 0x47
#define ADAU1372_CLK_CTRL_PLL_EN BIT(7)
#define ADAU1372_CLK_CTRL_XTAL_DIS BIT(4)
#define ADAU1372_CLK_CTRL_CLKSRC BIT(3)
#define ADAU1372_CLK_CTRL_CC_MDIV BIT(1)
#define ADAU1372_CLK_CTRL_MCLK_EN BIT(0)
#define ADAU1372_SAI0_DELAY1 (0x0 << 6)
#define ADAU1372_SAI0_DELAY0 (0x1 << 6)
#define ADAU1372_SAI0_DELAY_MASK (0x3 << 6)
#define ADAU1372_SAI0_SAI_I2S (0x0 << 4)
#define ADAU1372_SAI0_SAI_TDM2 (0x1 << 4)
#define ADAU1372_SAI0_SAI_TDM4 (0x2 << 4)
#define ADAU1372_SAI0_SAI_TDM8 (0x3 << 4)
#define ADAU1372_SAI0_SAI_MASK (0x3 << 4)
#define ADAU1372_SAI0_FS_48 0x0
#define ADAU1372_SAI0_FS_8 0x1
#define ADAU1372_SAI0_FS_12 0x2
#define ADAU1372_SAI0_FS_16 0x3
#define ADAU1372_SAI0_FS_24 0x4
#define ADAU1372_SAI0_FS_32 0x5
#define ADAU1372_SAI0_FS_96 0x6
#define ADAU1372_SAI0_FS_192 0x7
#define ADAU1372_SAI0_FS_MASK 0xf
#define ADAU1372_SAI1_TDM_TS BIT(7)
#define ADAU1372_SAI1_BCLK_TDMC BIT(6)
#define ADAU1372_SAI1_LR_MODE BIT(5)
#define ADAU1372_SAI1_LR_POL BIT(4)
#define ADAU1372_SAI1_BCLKRATE BIT(2)
#define ADAU1372_SAI1_BCLKEDGE BIT(1)
#define ADAU1372_SAI1_MS BIT(0)
static const unsigned int adau1372_rates[] = {
[ADAU1372_SAI0_FS_8] = 8000,
[ADAU1372_SAI0_FS_12] = 12000,
[ADAU1372_SAI0_FS_16] = 16000,
[ADAU1372_SAI0_FS_24] = 24000,
[ADAU1372_SAI0_FS_32] = 32000,
[ADAU1372_SAI0_FS_48] = 48000,
[ADAU1372_SAI0_FS_96] = 96000,
[ADAU1372_SAI0_FS_192] = 192000,
};
/* 8k, 12k, 24k, 48k */
#define ADAU1372_RATE_MASK_TDM8 0x17
/* + 16k, 96k */
#define ADAU1372_RATE_MASK_TDM4_MASTER (ADAU1372_RATE_MASK_TDM8 | 0x48 | 0x20)
/* +32k */
#define ADAU1372_RATE_MASK_TDM4 (ADAU1372_RATE_MASK_TDM4_MASTER | 0x20)
/* + 192k */
#define ADAU1372_RATE_MASK_TDM2 (ADAU1372_RATE_MASK_TDM4 | 0x80)
static const DECLARE_TLV_DB_MINMAX(adau1372_digital_tlv, -9563, 0);
static const DECLARE_TLV_DB_SCALE(adau1372_pga_tlv, -1200, 75, 0);
static const DECLARE_TLV_DB_SCALE(adau1372_pga_boost_tlv, 0, 1000, 0);
static const char * const adau1372_bias_text[] = {
"Normal operation", "Extreme power saving", "Enhanced performance",
"Power saving",
};
static const unsigned int adau1372_bias_adc_values[] = {
0, 2, 3,
};
static const char * const adau1372_bias_adc_text[] = {
"Normal operation", "Enhanced performance", "Power saving",
};
static const char * const adau1372_bias_dac_text[] = {
"Normal operation", "Power saving", "Superior performance",
"Enhanced performance",
};
static SOC_ENUM_SINGLE_DECL(adau1372_bias_hp_enum,
ADAU1372_REG_BIAS_CTRL0, 6, adau1372_bias_text);
static SOC_ENUM_SINGLE_DECL(adau1372_bias_afe0_1_enum,
ADAU1372_REG_BIAS_CTRL0, 4, adau1372_bias_text);
static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_bias_adc2_3_enum,
ADAU1372_REG_BIAS_CTRL0, 2, 0x3, adau1372_bias_adc_text,
adau1372_bias_adc_values);
static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_bias_adc0_1_enum,
ADAU1372_REG_BIAS_CTRL0, 0, 0x3, adau1372_bias_adc_text,
adau1372_bias_adc_values);
static SOC_ENUM_SINGLE_DECL(adau1372_bias_afe2_3_enum,
ADAU1372_REG_BIAS_CTRL1, 4, adau1372_bias_text);
static SOC_ENUM_SINGLE_DECL(adau1372_bias_mic_enum,
ADAU1372_REG_BIAS_CTRL1, 2, adau1372_bias_text);
static SOC_ENUM_SINGLE_DECL(adau1372_bias_dac_enum,
ADAU1372_REG_BIAS_CTRL1, 0, adau1372_bias_dac_text);
static const char * const adau1372_hpf_text[] = {