blob: 6c3a742f707badd2f4ff6606e83fe7f780c5b082 [file] [log] [blame]
/*
* linux/sound/soc/codecs/tlv320adc3101.c
*
* Copyright 2011 Amlogic
* Author: Alex Deng <alex.deng@amlogic.com>
* Based on sound/soc/codecs/tlv320aic320x and
* TI driver for kernel 2.6.27.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/i2c.h>
#include <linux/cdev.h>
#include <linux/slab.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 "tlv320adc3101.h"
struct adc3101_rate_divs {
u32 mclk;
u32 rate;
u8 p_val;
u8 pll_j;
u16 pll_d;
u16 dosr;
u8 ndac;
u8 mdac;
u8 aosr;
u8 nadc;
u8 madc;
u8 blck_N;
};
struct adc3101_priv {
struct regmap *regmap;
u32 sysclk;
u32 power_cfg;
u32 micpga_routing;
bool swapdacs;
int rstn_gpio;
struct snd_soc_codec *codec;
/* for more control */
int codec_cnt;
int codec_mask;
unsigned int slot_number;
struct i2c_client *client[4];
u8 page_no;
/* differential_pair
* 0: Single-ended;
* 1: Differential Pair;
*/
unsigned int differential_pair;
};
enum{
MASK_1 = 1 << 0,
MASK_2 = 1 << 1,
MASK_3 = 1 << 2,
MASK_4 = 1 << 3
};
static int lr_gain = 0x20;
module_param(lr_gain, int, 0664);
MODULE_PARM_DESC(lr_gain, "PGA Level Volume");
/* 0dB min, 1dB steps */
static DECLARE_TLV_DB_SCALE(tlv_step_1, 0, 100, 0);
/* 0dB min, 0.5dB steps */
static DECLARE_TLV_DB_SCALE(tlv_step_0_5, 0, 50, 0);
static const struct snd_kcontrol_new adc3101_snd_controls[] = {
SOC_DOUBLE_R_TLV("PCM Playback Volume", ADC3101_LDACVOL,
ADC3101_RDACVOL, 0, 0x30, 0, tlv_step_0_5),
SOC_DOUBLE_R_TLV("HP Driver Gain Volume", ADC3101_HPLGAIN,
ADC3101_HPRGAIN, 0, 0x1D, 0, tlv_step_1),
SOC_DOUBLE_R_TLV("LO Driver Gain Volume", ADC3101_LOLGAIN,
ADC3101_LORGAIN, 0, 0x1D, 0, tlv_step_1),
SOC_DOUBLE_R("HP DAC Playback Switch", ADC3101_HPLGAIN,
ADC3101_HPRGAIN, 6, 0x01, 1),
SOC_DOUBLE_R("LO DAC Playback Switch", ADC3101_LOLGAIN,
ADC3101_LORGAIN, 6, 0x01, 1),
SOC_DOUBLE_R("Mic PGA Switch", ADC3101_LMICPGAVOL,
ADC3101_RMICPGAVOL, 7, 0x01, 1),
SOC_SINGLE("ADCFGA Left Mute Switch", ADC3101_ADCFGA, 7, 1, 0),
SOC_SINGLE("ADCFGA Right Mute Switch", ADC3101_ADCFGA, 3, 1, 0),
SOC_DOUBLE_R_TLV("ADC Level Volume", ADC3101_LADCVOL,
ADC3101_RADCVOL, 0, 0x28, 0, tlv_step_0_5),
SOC_DOUBLE_R_TLV("PGA Level Volume", ADC3101_LMICPGAVOL,
ADC3101_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5),
SOC_SINGLE("Auto-mute Switch", ADC3101_DACMUTE, 4, 7, 0),
SOC_SINGLE("AGC Left Switch", ADC3101_LAGC1, 7, 1, 0),
SOC_SINGLE("AGC Right Switch", ADC3101_RAGC1, 7, 1, 0),
SOC_DOUBLE_R("AGC Target Level", ADC3101_LAGC1, ADC3101_RAGC1,
4, 0x07, 0),
SOC_DOUBLE_R("AGC Gain Hysteresis", ADC3101_LAGC1, ADC3101_RAGC1,
0, 0x03, 0),
SOC_DOUBLE_R("AGC Hysteresis", ADC3101_LAGC2, ADC3101_RAGC2,
6, 0x03, 0),
SOC_DOUBLE_R("AGC Noise Threshold", ADC3101_LAGC2, ADC3101_RAGC2,
1, 0x1F, 0),
SOC_DOUBLE_R("AGC Max PGA", ADC3101_LAGC3, ADC3101_RAGC3,
0, 0x7F, 0),
SOC_DOUBLE_R("AGC Attack Time", ADC3101_LAGC4, ADC3101_RAGC4,
3, 0x1F, 0),
SOC_DOUBLE_R("AGC Decay Time", ADC3101_LAGC5, ADC3101_RAGC5,
3, 0x1F, 0),
SOC_DOUBLE_R("AGC Noise Debounce", ADC3101_LAGC6, ADC3101_RAGC6,
0, 0x1F, 0),
SOC_DOUBLE_R("AGC Signal Debounce", ADC3101_LAGC7, ADC3101_RAGC7,
0, 0x0F, 0),
};
static const struct adc3101_rate_divs adc3101_divs[] = {
/* mclk rate p j d dosr ndac mdac aosr nadc madc blk_N */
/* 8k rate */
{ADC3101_FREQ_12000000, 8000, 1, 7, 6800, 768, 5, 3, 128, 5, 18, 24},
{ADC3101_FREQ_24000000, 8000, 2, 7, 6800, 768, 15, 1, 64, 45, 4, 24},
{ADC3101_FREQ_25000000, 8000, 2, 7, 3728, 768, 15, 1, 64, 45, 4, 24},
/* 11.025k rate */
{ADC3101_FREQ_12000000, 11025, 1, 7, 5264, 512, 8, 2, 128, 8, 8, 16},
{ADC3101_FREQ_24000000, 11025, 2, 7, 5264, 512, 16, 1, 64, 32, 4, 16},
/* 16k rate */
{ADC3101_FREQ_12000000, 16000, 1, 7, 6800, 384, 5, 3, 128, 5, 9, 12},
{ADC3101_FREQ_24000000, 16000, 2, 7, 6800, 384, 15, 1, 64, 18, 5, 12},
{ADC3101_FREQ_25000000, 16000, 2, 7, 3728, 384, 15, 1, 64, 18, 5, 12},
/* 22.05k rate */
{ADC3101_FREQ_12000000, 22050, 1, 7, 5264, 256, 4, 4, 128, 4, 8, 8},
{ADC3101_FREQ_24000000, 22050, 2, 7, 5264, 256, 16, 1, 64, 16, 4, 8},
{ADC3101_FREQ_25000000, 22050, 2, 7, 2253, 256, 16, 1, 64, 16, 4, 8},
/* 32k rate */
{ADC3101_FREQ_12000000, 32000, 1, 7, 1680, 192, 2, 7, 64, 2, 21, 6},
{ADC3101_FREQ_24000000, 32000, 2, 7, 1680, 192, 7, 2, 64, 7, 6, 6},
/* 44.1k rate */
{ADC3101_FREQ_12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
{ADC3101_FREQ_24000000, 44100, 2, 7, 5264, 128, 8, 2, 64, 8, 4, 4},
{ADC3101_FREQ_25000000, 44100, 2, 7, 2253, 128, 8, 2, 64, 8, 4, 4},
/* 48k rate */
{ADC3101_FREQ_12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4},
{ADC3101_FREQ_24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4},
{ADC3101_FREQ_25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4},
{ADC3101_FREQ_2048000, 8000, 1, 4, 0, 128, 1, 1, 128, 1, 2, 1},
{ADC3101_FREQ_4096000, 16000, 1, 4, 0, 128, 1, 1, 128, 1, 2, 1},
{ADC3101_FREQ_8192000, 32000, 1, 4, 0, 128, 1, 1, 128, 1, 2, 1},
{ADC3101_FREQ_11289600, 44100, 1, 4, 0, 128, 1, 1, 128, 1, 2, 1},
{ADC3101_FREQ_12288000, 48000, 1, 4, 0, 128, 2, 1, 128, 1, 2, 1},
};
static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
SOC_DAPM_SINGLE("L_DAC Switch", ADC3101_HPLROUTE, 3, 1, 0),
SOC_DAPM_SINGLE("IN1_L Switch", ADC3101_HPLROUTE, 2, 1, 0),
};
static const struct snd_kcontrol_new hpr_output_mixer_controls[] = {
SOC_DAPM_SINGLE("R_DAC Switch", ADC3101_HPRROUTE, 3, 1, 0),
SOC_DAPM_SINGLE("IN1_R Switch", ADC3101_HPRROUTE, 2, 1, 0),
};
static const struct snd_kcontrol_new lol_output_mixer_controls[] = {
SOC_DAPM_SINGLE("L_DAC Switch", ADC3101_LOLROUTE, 3, 1, 0),
};
static const struct snd_kcontrol_new lor_output_mixer_controls[] = {
SOC_DAPM_SINGLE("R_DAC Switch", ADC3101_LORROUTE, 3, 1, 0),
};
static const struct snd_kcontrol_new left_input_mixer_controls[] = {
SOC_DAPM_SINGLE("IN1_L P Switch", ADC3101_LMICPGAPIN, 6, 1, 0),
SOC_DAPM_SINGLE("IN2_L P Switch", ADC3101_LMICPGAPIN, 4, 1, 0),
SOC_DAPM_SINGLE("IN3_L P Switch", ADC3101_LMICPGAPIN, 2, 1, 0),
};
static const struct snd_kcontrol_new right_input_mixer_controls[] = {
SOC_DAPM_SINGLE("IN1_R P Switch", ADC3101_RMICPGAPIN, 6, 1, 0),
SOC_DAPM_SINGLE("IN2_R P Switch", ADC3101_RMICPGAPIN, 4, 1, 0),
SOC_DAPM_SINGLE("IN3_R P Switch", ADC3101_RMICPGAPIN, 2, 1, 0),
};
static const struct snd_soc_dapm_widget adc3101_dapm_widgets[] = {
SND_SOC_DAPM_MIXER("Left Input Mixer", SND_SOC_NOPM, 0, 0,
&left_input_mixer_controls[0],
ARRAY_SIZE(left_input_mixer_controls)),
SND_SOC_DAPM_MIXER("Right Input Mixer", SND_SOC_NOPM, 0, 0,
&right_input_mixer_controls[0],
ARRAY_SIZE(right_input_mixer_controls)),
SND_SOC_DAPM_ADC("Left ADC", "Left Capture", ADC3101_ADCSETUP, 7, 0),
SND_SOC_DAPM_ADC("Right ADC", "Right Capture", ADC3101_ADCSETUP, 6, 0),
SND_SOC_DAPM_MICBIAS("Mic Bias", ADC3101_MICBIAS, 6, 0),
SND_SOC_DAPM_INPUT("IN1_L"),
SND_SOC_DAPM_INPUT("IN1_R"),
SND_SOC_DAPM_INPUT("IN2_L"),
SND_SOC_DAPM_INPUT("IN2_R"),
SND_SOC_DAPM_INPUT("IN3_L"),
SND_SOC_DAPM_INPUT("IN3_R"),
};
static const struct snd_soc_dapm_route adc3101_dapm_routes[] = {
/* Left input */
{"Left Input Mixer", "IN1_L P Switch", "IN1_L"},
{"Left Input Mixer", "IN2_L P Switch", "IN2_L"},
{"Left Input Mixer", "IN3_L P Switch", "IN3_L"},
{"Left ADC", NULL, "Left Input Mixer"},
/* Right Input */
{"Right Input Mixer", "IN1_R P Switch", "IN1_R"},
{"Right Input Mixer", "IN2_R P Switch", "IN2_R"},
{"Right Input Mixer", "IN3_R P Switch", "IN3_R"},
{"Right ADC", NULL, "Right Input Mixer"},
};
static const struct regmap_range_cfg adc3101_regmap_pages[] = {
{
.range_min = 0,
.range_max = ADC3101_RMICPGAVOL,
.selector_reg = ADC3101_PSEL,
.selector_mask = 0xff,
.selector_shift = 0,
.window_start = 0,
.window_len = 128,
},
};
static const struct regmap_config adc3101_i2c_regmap = {
.reg_bits = 8,
.val_bits = 8,
.ranges = adc3101_regmap_pages,
.num_ranges = ARRAY_SIZE(adc3101_regmap_pages),
.max_register = ADC3101_RMICPGAVOL,
};
static inline int adc3101_get_divs(int mclk, int rate)
{
int i;
for (i = 0; i < ARRAY_SIZE(adc3101_divs); i++) {
if ((adc3101_divs[i].rate == rate)
&& (adc3101_divs[i].mclk == mclk)) {
return i;
}
}
pr_err("adc3101: master clock and sample rate is not supported\n");
return -EINVAL;
}
static int adc3101_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct adc3101_priv *adc3101 = snd_soc_codec_get_drvdata(codec);
pr_info("%s freq:%d\n", __func__, freq);
switch (freq) {
case ADC3101_FREQ_12000000:
case ADC3101_FREQ_24000000:
case ADC3101_FREQ_25000000:
case ADC3101_FREQ_11289600:
case ADC3101_FREQ_12288000:
case ADC3101_FREQ_2048000:
case ADC3101_FREQ_4096000:
case ADC3101_FREQ_8192000:
adc3101->sysclk = freq;
return 0;
}
pr_err("adc3101: invalid frequency to set DAI system clock\n");
return -1;
}
static int adc3101_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct adc3101_priv *adc3101 = NULL;
u8 iface_reg_1;
u8 dsp_a_val;
u8 iface_reg_2;
adc3101 = snd_soc_codec_get_drvdata(codec);
if (adc3101 == NULL)
return -EINVAL;
pr_info("[%s]:slot_number=%d\n", __func__, adc3101->slot_number);
iface_reg_1 = snd_soc_read(codec, ADC3101_IFACE1);
iface_reg_1 = iface_reg_1 & ~(3 << 6 | 3 << 2);
dsp_a_val = snd_soc_read(codec, ADC3101_DATASLOTOFFSETCTL);
dsp_a_val = 0;
iface_reg_2 = snd_soc_read(codec, ADC3101_IFACE3);
iface_reg_2 = iface_reg_2 & ~(1 << 3);
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
iface_reg_1 |= ADC3101_BCLKMASTER | ADC3101_WCLKMASTER;
pr_info("%s DAIFMT_CBM_CFM\n", __func__);
break;
case SND_SOC_DAIFMT_CBS_CFS:
break;
default:
pr_err("adc3101: invalid DAI master/slave interface\n");
return -EINVAL;
}
/* set lrclk/bclk invertion */
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_IB_IF:
case SND_SOC_DAIFMT_IB_NF:
iface_reg_2 |= (1 << 3); /* invert bit clock */
break;
case SND_SOC_DAIFMT_NB_IF:
case SND_SOC_DAIFMT_NB_NF:
break;
default:
break;
}
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
break;
case SND_SOC_DAIFMT_DSP_A:
iface_reg_1 |= (ADC3101_DSP_MODE << ADC3101_PLLJ_SHIFT);
iface_reg_2 |= (1 << 3); /* invert bit clock */
/* set bclk offset according to diffrent adc */
if (adc3101->slot_number == 0)
dsp_a_val = 0;
else if (adc3101->slot_number == 1)
dsp_a_val = 64;
else if (adc3101->slot_number == 2)
dsp_a_val = 128;
else if (adc3101->slot_number == 3)
dsp_a_val = 192;
else
dsp_a_val = 0x01; /* default add offset 1 */
break;
case SND_SOC_DAIFMT_DSP_B:
iface_reg_1 |= (ADC3101_DSP_MODE << ADC3101_PLLJ_SHIFT);
iface_reg_2 |= (1 << 3); /* invert bit clock */
break;
case SND_SOC_DAIFMT_RIGHT_J:
iface_reg_1 |=
(ADC3101_RIGHT_JUSTIFIED_MODE << ADC3101_PLLJ_SHIFT);
break;
case SND_SOC_DAIFMT_LEFT_J:
iface_reg_1 |=
(ADC3101_LEFT_JUSTIFIED_MODE << ADC3101_PLLJ_SHIFT);
break;
default:
pr_err("adc3101: invalid DAI interface format\n");
return -EINVAL;
}
snd_soc_write(codec, ADC3101_IFACE1, iface_reg_1);
snd_soc_write(codec, ADC3101_DATASLOTOFFSETCTL, dsp_a_val);
snd_soc_write(codec, ADC3101_IFACE3, iface_reg_2);
return 0;
}
static int __maybe_unused adc3101_hw_high_pass_filter(
struct snd_soc_codec *codec)
{
/*page 4*/
char datas[4][31] = {
/* data 1*/
{
0x0E,
0x7F, 0xBE, 0x80, 0x42,
0x7F, 0xBE, 0x7F, 0xBE,
0x80, 0x84, 0x7F, 0xFF,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x7F, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00
},
/* data 2 */
{
0x2c,
0x7F, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7F, 0xFF,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
},
/* data 3 */
{
0x4E,
0x7F, 0xBE, 0x80,
0x42, 0x7F, 0xBE, 0x7F,
0xBE, 0x80, 0x84, 0x7F,
0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x7F, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00
},
/* data 4 */
{
0x6C,
0x7F, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7F, 0xFF,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
}
};
int i = 0, j = 0, c = 0;
int ret = 0;
int nums[] = {31, 21, 31, 21};
struct adc3101_priv *adc3101 = snd_soc_codec_get_drvdata(codec);
pr_info("%s ...\n", __func__);
snd_soc_write(codec, 0x3D, 2);
snd_soc_write(codec, 0x51, 0);
/* page 4 */
snd_soc_write(codec, ADC3101_PSEL, 0x4);
for (i = 0; i < adc3101->codec_cnt; i++) {
for (c = 0; c < 4; c++) {
for (j = 0; j < nums[c]; j++) {
ret = i2c_smbus_write_byte(
adc3101->client[i],
datas[c][j]);
if (ret < 0)
pr_err("%x write error\n",
adc3101->client[i]->addr);
}
}
}
snd_soc_write(codec, 0x51, 0xC0);
snd_soc_write(codec, 0x52, 0x00);
pr_info("%s done\n", __func__);
return 0;
}
static int adc3101_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct adc3101_priv *adc3101 = snd_soc_codec_get_drvdata(codec);
u8 data;
int i;
pr_info("%s ...\n", __func__);
i = adc3101_get_divs(adc3101->sysclk, params_rate(params));
if (i < 0) {
pr_err("adc3101: sampling rate not supported\n");
return i;
}
/* Use PLL as CODEC_CLKIN and DAC_MOD_CLK as BDIV_CLKIN */
snd_soc_write(codec, ADC3101_CLKMUX, 0);
/* We will fix R value to 1 and will make P & J=K.D as varialble */
data = snd_soc_read(codec, ADC3101_PLLPR);
data &= ~(7 << 4);
snd_soc_write(codec, ADC3101_PLLPR,
(data | (adc3101_divs[i].p_val << 4) | 0x01));
snd_soc_write(codec, ADC3101_PLLJ, adc3101_divs[i].pll_j);
snd_soc_write(codec, ADC3101_PLLDMSB, (adc3101_divs[i].pll_d >> 8));
snd_soc_write(codec, ADC3101_PLLDLSB,
(adc3101_divs[i].pll_d & 0xff));
/* NADC divider value */
data = snd_soc_read(codec, ADC3101_NADC);
data &= ~(0x7f);
data |= 0x80;
snd_soc_write(codec, ADC3101_NADC, data | adc3101_divs[i].nadc);
pr_info("%s NADC = 0x%02x\n",
__func__,
snd_soc_read(codec, ADC3101_NADC));
/* MADC divider value */
data = snd_soc_read(codec, ADC3101_MADC);
data &= ~(0x7f);
data |= 0x80;
snd_soc_write(codec, ADC3101_MADC, data | adc3101_divs[i].madc);
pr_info("%s MADC = 0x%02x\n",
__func__,
snd_soc_read(codec, ADC3101_MADC));
/* AOSR value */
snd_soc_write(codec, ADC3101_AOSR, adc3101_divs[i].aosr);
pr_info("%s AOSR=%02x\n",
__func__,
snd_soc_read(codec, ADC3101_AOSR));
data = snd_soc_read(codec, ADC3101_IFACE1);
data = data & ~(3 << 4);
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
break;
case SNDRV_PCM_FORMAT_S20_3LE:
data |= (ADC3101_WORD_LEN_20BITS << ADC3101_DOSRMSB_SHIFT);
break;
case SNDRV_PCM_FORMAT_S24_3LE:
case SNDRV_PCM_FORMAT_S24_LE:
data |= (ADC3101_WORD_LEN_24BITS << ADC3101_DOSRMSB_SHIFT);
break;
case SNDRV_PCM_FORMAT_S32_LE:
data |= (ADC3101_WORD_LEN_32BITS << ADC3101_DOSRMSB_SHIFT);
break;
}
snd_soc_write(codec, ADC3101_IFACE1, data);
pr_info("%s iface1 = %02x\n", __func__, data);
snd_soc_write(codec, ADC3101_MICBIAS, 0x50);
if (adc3101->differential_pair == 1) {
pr_info("%s differential pair\n", __func__);
snd_soc_write(codec, ADC3101_LMICPGANIN, 0x33); //54
snd_soc_write(codec, ADC3101_RMICPGANIN, 0x33); //57
snd_soc_write(codec, ADC3101_LMICPGAPIN, 0x3F); //52
snd_soc_write(codec, ADC3101_RMICPGAPIN, 0x3F); //55
} else {
pr_info("%s single end\n", __func__);
snd_soc_write(codec, ADC3101_LMICPGANIN, 0x3F); //54
snd_soc_write(codec, ADC3101_RMICPGANIN, 0x3F); //57
snd_soc_write(codec, ADC3101_LMICPGAPIN, 0xCF); //52
snd_soc_write(codec, ADC3101_RMICPGAPIN, 0xCF); //55
}
snd_soc_write(codec, ADC3101_LMICPGAVOL, lr_gain);
snd_soc_write(codec, ADC3101_RMICPGAVOL, lr_gain);
snd_soc_write(codec, ADC3101_ADCSETUP, 0xc2);
snd_soc_write(codec, ADC3101_ADCFGA, 0);
pr_info("%s ADCSETUP = %02x\n", __func__,
snd_soc_read(codec, ADC3101_ADCSETUP));
pr_info("%s DOUTCTL=%02x\n", __func__,
snd_soc_read(codec, ADC3101_DOUTCTL));
pr_info("%s MICBIAS=%02x\n", __func__,
snd_soc_read(codec, ADC3101_MICBIAS));
return 0;
}
static int adc3101_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
u8 dac_reg;
dac_reg = snd_soc_read(codec, ADC3101_DACMUTE) & ~ADC3101_MUTEON;
if (mute)
snd_soc_write(codec, ADC3101_DACMUTE, dac_reg | ADC3101_MUTEON);
else
snd_soc_write(codec, ADC3101_DACMUTE, dac_reg);
return 0;
}
static int adc3101_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
pr_debug("%s ..\n", __func__);
switch (level) {
case SND_SOC_BIAS_ON:
/* Switch on PLL */
snd_soc_update_bits(codec, ADC3101_PLLPR,
ADC3101_PLLEN, ADC3101_PLLEN);
/* Switch on NDAC Divider */
snd_soc_update_bits(codec, ADC3101_NDAC,
ADC3101_NDACEN, ADC3101_NDACEN);
/* Switch on MDAC Divider */
snd_soc_update_bits(codec, ADC3101_MDAC,
ADC3101_MDACEN, ADC3101_MDACEN);
/* Switch on NADC Divider */
snd_soc_update_bits(codec, ADC3101_NADC,
ADC3101_NADCEN, ADC3101_NADCEN);
/* Switch on MADC Divider */
snd_soc_update_bits(codec, ADC3101_MADC,
ADC3101_MADCEN, ADC3101_MADCEN);
/* Switch on BCLK_N Divider */
snd_soc_update_bits(codec, ADC3101_BCLKN,
ADC3101_BCLKEN, ADC3101_BCLKEN);
break;
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
/* Switch off PLL */
snd_soc_update_bits(codec, ADC3101_PLLPR,
ADC3101_PLLEN, 0);
/* Switch off NDAC Divider */
snd_soc_update_bits(codec, ADC3101_NDAC,
ADC3101_NDACEN, 0);
/* Switch off MDAC Divider */
snd_soc_update_bits(codec, ADC3101_MDAC,
ADC3101_MDACEN, 0);
/* Switch off NADC Divider */
snd_soc_update_bits(codec, ADC3101_NADC,
ADC3101_NADCEN, 0);
/* Switch off MADC Divider */
snd_soc_update_bits(codec, ADC3101_MADC,
ADC3101_MADCEN, 0);
/* Switch off BCLK_N Divider */
snd_soc_update_bits(codec, ADC3101_BCLKN,
ADC3101_BCLKEN, 0);
break;
case SND_SOC_BIAS_OFF:
break;
}
codec->component.dapm.bias_level = level;
snd_soc_codec_init_bias_level(codec, level);
return 0;
}
#define ADC3101_RATES SNDRV_PCM_RATE_8000_96000
#define ADC3101_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE \
| SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
static const struct snd_soc_dai_ops adc3101_ops = {
.hw_params = adc3101_hw_params,
.digital_mute = adc3101_mute,
.set_fmt = adc3101_set_dai_fmt,
.set_sysclk = adc3101_set_dai_sysclk,
};
static struct snd_soc_dai_driver adc3101_dai[] = {
{
.name = "tlv320adc3101-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
.rates = ADC3101_RATES,
.formats = ADC3101_FORMATS,},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 8,//2,
.rates = ADC3101_RATES,
.formats = ADC3101_FORMATS,},
.ops = &adc3101_ops,
.symmetric_rates = 1,
},
{
.name = "tlv320adc3101-hifi@19",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
.rates = ADC3101_RATES,
.formats = ADC3101_FORMATS,},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 8,//2,
.rates = ADC3101_RATES,
.formats = ADC3101_FORMATS,},
.ops = &adc3101_ops,
.symmetric_rates = 1,
},
{
.name = "tlv320adc3101-hifi@1a",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
.rates = ADC3101_RATES,
.formats = ADC3101_FORMATS,},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 8,//2,
.rates = ADC3101_RATES,
.formats = ADC3101_FORMATS,},
.ops = &adc3101_ops,
.symmetric_rates = 1,
},
{
.name = "tlv320adc3101-hifi@1b",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
.rates = ADC3101_RATES,
.formats = ADC3101_FORMATS,},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 8,
.rates = ADC3101_RATES,
.formats = ADC3101_FORMATS,},
.ops = &adc3101_ops,
.symmetric_rates = 1,
},
};
static int adc3101_suspend(struct snd_soc_codec *codec)
{
adc3101_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
static int adc3101_resume(struct snd_soc_codec *codec)
{
adc3101_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
static int adc3101_codec_probe(struct snd_soc_codec *codec)
{
u32 tmp_reg;
pr_info("%s ...\n", __func__);
snd_soc_write(codec, ADC3101_RESET, 0x01);
/*
* Workaround: for an unknown reason, the ADC needs to be powered up
* and down for the first capture to work properly. It seems related to
* a HW BUG or some kind of behavior not documented in the datasheet.
*/
tmp_reg = snd_soc_read(codec, ADC3101_ADCSETUP);
snd_soc_write(codec, ADC3101_ADCSETUP, tmp_reg |
ADC3101_LADC_EN | ADC3101_RADC_EN);
snd_soc_write(codec, ADC3101_ADCSETUP, tmp_reg);
pr_info("%s done...\n", __func__);
return 0;
}
static int adc3101_remove(struct snd_soc_codec *codec)
{
adc3101_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
static struct snd_soc_codec_driver __maybe_unused soc_codec_dev_adc3101_2 = {
.probe = adc3101_codec_probe,
.remove = adc3101_remove,
.suspend = adc3101_suspend,
.resume = adc3101_resume,
.set_bias_level = adc3101_set_bias_level,
};
static struct snd_soc_codec_driver soc_codec_dev_adc3101 = {
.probe = adc3101_codec_probe,
.remove = adc3101_remove,
.suspend = adc3101_suspend,
.resume = adc3101_resume,
.set_bias_level = adc3101_set_bias_level,
.component_driver = {
.controls = adc3101_snd_controls,
.num_controls = ARRAY_SIZE(adc3101_snd_controls),
.dapm_widgets = adc3101_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(adc3101_dapm_widgets),
.dapm_routes = adc3101_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(adc3101_dapm_routes),
}
};
static int adc3101_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct adc3101_priv *adc3101 = NULL;
int ret = 0;
pr_err("tlv320 %s ...\n", __func__);
adc3101 = devm_kzalloc(&i2c->dev, sizeof(struct adc3101_priv),
GFP_KERNEL);
if (adc3101 == NULL)
return -ENOMEM;
adc3101->codec_cnt = 0;
adc3101->regmap = devm_regmap_init_i2c(i2c, &adc3101_i2c_regmap);
if (IS_ERR(adc3101->regmap)) {
pr_info("%s failed devm_regmap_init_i2c\n", __func__);
return PTR_ERR(adc3101->regmap);
}
i2c_set_clientdata(i2c, adc3101);
adc3101->power_cfg = 0;
adc3101->swapdacs = false;
adc3101->micpga_routing = 0;
adc3101->rstn_gpio = -1;
ret = of_get_named_gpio(i2c->dev.of_node, "gpio-reset", 0);
if (ret > 0)
adc3101->rstn_gpio = ret;
if (adc3101->rstn_gpio > 0) {
ret = devm_gpio_request_one(&i2c->dev,
adc3101->rstn_gpio,
GPIOF_OUT_INIT_HIGH,
"adc3101-reset-pin");
if (ret < 0) {
dev_err(&i2c->dev, "not able to acquire gpio\n");
return ret;
}
}
ret = of_property_read_u32(i2c->dev.of_node, "differential_pair",
&adc3101->differential_pair);
if (ret) {
pr_err("failed to get differential_pair, set it default\n");
adc3101->differential_pair = 0;
ret = 0;
}
ret = of_property_read_u32(i2c->dev.of_node, "slot_number",
&adc3101->slot_number);
if (ret) {
pr_err("failed to get slot_number, set it default\n");
adc3101->slot_number = 0;
ret = 0;
}
pr_info("%s i2c:%p\n", __func__, i2c);
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_adc3101, adc3101_dai, 1);
pr_info("%s %x done\n", __func__, i2c->addr);
return ret;
}
static int adc3101_i2c_remove(struct i2c_client *client)
{
snd_soc_unregister_codec(&client->dev);
return 0;
}
static const struct of_device_id tlv320adc3101_of_match[] = {
{.compatible = "ti,tlv320adc3101"},
{},
};
MODULE_DEVICE_TABLE(of, tlv320aic31xx_of_match);
static const struct i2c_device_id adc3101_i2c_id[] = {
{ "tlv320adc3101", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, adc3101_i2c_id);
static struct i2c_driver adc3101_i2c_driver = {
.driver = {
.name = "tlv320adc3101",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(tlv320adc3101_of_match),
},
.probe = adc3101_i2c_probe,
.remove = adc3101_i2c_remove,
.id_table = adc3101_i2c_id,
};
module_i2c_driver(adc3101_i2c_driver);
MODULE_DESCRIPTION("ASoC tlv320adc3101 codec driver");
MODULE_AUTHOR("alex.deng <alex.deng@amlogic.com>");
MODULE_LICENSE("GPL");