blob: fef445f938a94b875333989af093637c1e0f2471 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0-only
/*
* es8311.c -- ES8311/ES8312 ALSA SoC Audio Codec
*
* Copyright (C) 2018 Everest Semiconductor Co., Ltd
*
* Authors: David Yang(yangxiaohua@everest-semi.com)
*
* 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.
*/
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/i2c.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 <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/clk-provider.h>
#include "es8311.h"
#ifndef CONFIG_OF
#define CONFIG_OF
#endif
/* component private data */
struct es8311_private {
struct snd_soc_component *component;
struct regmap *regmap;
struct device *dev;
struct clk *mclk;
unsigned int mclk_rate;
int mastermode;
bool sclkinv;
bool mclkinv;
bool dmic_enable;
unsigned int mclk_src;
enum snd_soc_bias_level bias_level;
//add new
struct pinctrl *pctrl;
struct pinctrl_state *state0;
struct clk *clk;
};
#if 0
struct aic31xx_priv {
struct snd_soc_component *component;
u8 i2c_regs_status;
struct device *dev;
struct regmap *regmap;
enum aic31xx_type codec_type;
struct gpio_desc *gpio_reset;
int micbias_vg;
struct aic31xx_pdata pdata;
struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES];
struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES];
struct snd_soc_jack *jack;
unsigned int sysclk;
u8 p_div;
int rate_div_line;
bool master_dapm_route_applied;
int irq;
u8 ocmv; /* output common-mode voltage */
};
#endif
struct es8311_private *es8311_data;
struct snd_soc_component *es8311_component;
static bool es8311_volatile_register(struct device *dev,
unsigned int reg)
{
//printk("Enter into %s()\n", __func__);
if ((reg <= 0xff))
return true;
else
return false;
}
static bool es8311_readable_register(struct device *dev,
unsigned int reg)
{
//printk("Enter into %s()\n", __func__);
if ((reg <= 0xff))
return true;
else
return false;
}
static bool es8311_writable_register(struct device *dev,
unsigned int reg)
{
//printk("Enter into %s()\n", __func__);
if ((reg <= 0xff))
return true;
else
return false;
}
static const DECLARE_TLV_DB_SCALE(vdac_tlv, -9550, 50, 1);
static const DECLARE_TLV_DB_SCALE(vadc_tlv, -9550, 50, 1);
static const DECLARE_TLV_DB_SCALE(mic_pga_tlv, 0, 300, 1);
static const DECLARE_TLV_DB_SCALE(adc_scale_tlv, 0, 600, 0);
static const DECLARE_TLV_DB_SCALE(alc_winsize_tlv, 0, 25, 0);
static const DECLARE_TLV_DB_SCALE(alc_maxlevel_tlv, -3600, 200, 0);
static const DECLARE_TLV_DB_SCALE(alc_minlevel_tlv, -3600, 200, 0);
static const DECLARE_TLV_DB_SCALE(alc_noisegate_tlv, -9600, 600, 0);
static const DECLARE_TLV_DB_SCALE(alc_noisegate_winsize_tlv, 2048, 2048, 0);
static const DECLARE_TLV_DB_SCALE(alc_automute_gain_tlv, 0, -400, 0);
static const DECLARE_TLV_DB_SCALE(adc_ramprate_tlv, 0, 25, 0);
static const char * const dmic_type_txt[] = {
"dmic at high level",
"dmic at low level"
};
static const struct soc_enum dmic_type =
SOC_ENUM_SINGLE(ES8311_ADC_REG15, 0, 2, dmic_type_txt);
static const char * const automute_type_txt[] = {
"automute disabled",
"automute enable"
};
static const struct soc_enum alc_automute_type =
SOC_ENUM_SINGLE(ES8311_ADC_REG18, 6, 2, automute_type_txt);
static const char * const dacdsm_mute_type_txt[] = {
"mute to 8",
"mute to 7/9"
};
static const struct soc_enum dacdsm_mute_type =
SOC_ENUM_SINGLE(ES8311_DAC_REG31, 7, 2, dacdsm_mute_type_txt);
static const char * const aec_type_txt[] = {
"adc left, adc right",
"adc left, null right",
"null left, adc right",
"null left, null right",
"dac left, adc right",
"adc left, dac right",
"dac left, dac right",
"N/A"
};
static const struct soc_enum aec_type =
SOC_ENUM_SINGLE(ES8311_GPIO_REG44, 4, 7, aec_type_txt);
static const char * const adc2dac_sel_txt[] = {
"disable",
"adc data to dac",
};
static const struct soc_enum adc2dac_sel =
SOC_ENUM_SINGLE(ES8311_GPIO_REG44, 7, 2, adc2dac_sel_txt);
static const char * const mclk_sel_txt[] = {
"from mclk pin",
"from bclk",
};
static const struct soc_enum mclk_src =
SOC_ENUM_SINGLE(ES8311_CLK_MANAGER_REG01, 7, 2, mclk_sel_txt);
/*
* es8311 Controls
*/
static const struct snd_kcontrol_new es8311_snd_controls[] = {
SOC_SINGLE_TLV("MIC PGA GAIN", ES8311_SYSTEM_REG14,
0, 10, 0, mic_pga_tlv),
SOC_SINGLE_TLV("ADC SCALE", ES8311_ADC_REG16,
0, 7, 0, adc_scale_tlv),
SOC_ENUM("DMIC TYPE", dmic_type),
SOC_SINGLE_TLV("ADC RAMP RATE", ES8311_ADC_REG15,
4, 15, 0, adc_ramprate_tlv),
SOC_SINGLE("ADC SDP MUTE", ES8311_SDPOUT_REG0A, 6, 1, 0),
SOC_SINGLE("ADC INVERTED", ES8311_ADC_REG16, 4, 1, 0),
SOC_SINGLE("ADC SYNC", ES8311_ADC_REG16, 5, 1, 1),
SOC_SINGLE("ADC RAM CLR", ES8311_ADC_REG16, 3, 1, 0),
SOC_SINGLE_TLV("ADC VOLUME", ES8311_ADC_REG17,
0, 255, 0, vadc_tlv),
SOC_SINGLE("ALC ENABLE", ES8311_ADC_REG18, 7, 1, 0),
SOC_ENUM("ALC AUTOMUTE TYPE", alc_automute_type),
SOC_SINGLE_TLV("ALC WIN SIZE", ES8311_ADC_REG18,
0, 15, 0, alc_winsize_tlv),
SOC_SINGLE_TLV("ALC MAX LEVEL", ES8311_ADC_REG19,
4, 15, 0, alc_maxlevel_tlv),
SOC_SINGLE_TLV("ALC MIN LEVEL", ES8311_ADC_REG19,
0, 15, 0, alc_minlevel_tlv),
SOC_SINGLE_TLV("ALC AUTOMUTE WINSIZE", ES8311_ADC_REG1A,
4, 15, 0, alc_noisegate_winsize_tlv),
SOC_SINGLE_TLV("ALC AUTOMUTE GATE THRESHOLD", ES8311_ADC_REG1A,
0, 15, 0, alc_noisegate_tlv),
SOC_SINGLE_TLV("ALC AUTOMUTE VOLUME", ES8311_ADC_REG1B,
5, 7, 0, alc_automute_gain_tlv),
SOC_SINGLE("ADC FS MODE", ES8311_CLK_MANAGER_REG03, 6, 1, 0),
SOC_SINGLE("DAC SDP MUTE", ES8311_SDPIN_REG09, 6, 1, 0),
SOC_SINGLE("DAC DEM MUTE", ES8311_DAC_REG31, 5, 1, 0),
SOC_SINGLE("DAC INVERT", ES8311_DAC_REG31, 4, 1, 0),
SOC_SINGLE("DAC RAM CLR", ES8311_DAC_REG31, 3, 1, 0),
SOC_ENUM("DAC DSM MUTE", dacdsm_mute_type),
SOC_SINGLE("DAC OFFSET", ES8311_DAC_REG33, 0, 255, 0),
SOC_SINGLE_TLV("DAC VOLUME", ES8311_DAC_REG32,
0, 255, 0, vdac_tlv),
SOC_SINGLE("DRC ENABLE", ES8311_DAC_REG34, 7, 1, 0),
SOC_SINGLE_TLV("DRC WIN SIZE", ES8311_DAC_REG34,
0, 15, 0, alc_winsize_tlv),
SOC_SINGLE_TLV("DRC MAX LEVEL", ES8311_DAC_REG35,
4, 15, 0, alc_maxlevel_tlv),
SOC_SINGLE_TLV("DRC MIN LEVEL", ES8311_DAC_REG35,
0, 15, 0, alc_minlevel_tlv),
SOC_SINGLE_TLV("DAC RAMP RATE", ES8311_DAC_REG37,
4, 15, 0, adc_ramprate_tlv),
SOC_ENUM("AEC MODE", aec_type),
SOC_ENUM("ADC DATA TO DAC TEST MODE", adc2dac_sel),
SOC_SINGLE("MCLK INVERT", ES8311_CLK_MANAGER_REG01, 6, 1, 0),
SOC_SINGLE("BCLK INVERT", ES8311_CLK_MANAGER_REG06, 5, 1, 0),
SOC_ENUM("MCLK SOURCE", mclk_src),
};
/*
* DAPM Controls
*/
static const char * const es8311_dmic_mux_txt[] = {
"DMIC DISABLE",
"DMIC ENABLE"
};
static const unsigned int es8311_dmic_mux_values[] = {
0, 1
};
static const struct soc_enum es8311_dmic_mux_enum =
SOC_VALUE_ENUM_SINGLE(ES8311_SYSTEM_REG14, 6, 1,
ARRAY_SIZE(es8311_dmic_mux_txt),
es8311_dmic_mux_txt,
es8311_dmic_mux_values);
static const struct snd_kcontrol_new es8311_dmic_mux_controls =
SOC_DAPM_ENUM("DMIC ROUTE", es8311_dmic_mux_enum);
static const char * const es8311_adc_sdp_mux_txt[] = {
"FROM EQUALIZER",
"FROM ADC OUT",
};
static const unsigned int es8311_adc_sdp_mux_values[] = {
0, 1
};
static const struct soc_enum es8311_adc_sdp_mux_enum =
SOC_VALUE_ENUM_SINGLE(ES8311_ADC_REG1C, 6, 1,
ARRAY_SIZE(es8311_adc_sdp_mux_txt),
es8311_adc_sdp_mux_txt,
es8311_adc_sdp_mux_values);
static const struct snd_kcontrol_new es8311_adc_sdp_mux_controls =
SOC_DAPM_ENUM("ADC SDP ROUTE", es8311_adc_sdp_mux_enum);
/*
* DAC data soure
*/
static const char * const es8311_dac_data_mux_txt[] = {
"SELECT SDP LEFT DATA",
"SELECT SDP RIGHT DATA",
};
static const unsigned int es8311_dac_data_mux_values[] = {
0, 1
};
static const struct soc_enum es8311_dac_data_mux_enum =
SOC_VALUE_ENUM_SINGLE(ES8311_SDPIN_REG09, 7, 1,
ARRAY_SIZE(es8311_dac_data_mux_txt),
es8311_dac_data_mux_txt,
es8311_dac_data_mux_values);
static const struct snd_kcontrol_new es8311_dac_data_mux_controls =
SOC_DAPM_ENUM("DAC SDP ROUTE", es8311_dac_data_mux_enum);
static const struct snd_soc_dapm_widget es8311_dapm_widgets[] = {
/* Input*/
SND_SOC_DAPM_INPUT("DMIC"),
SND_SOC_DAPM_INPUT("AMIC"),
//SND_SOC_DAPM_PGA("INPUT PGA", ES8311_SYSTEM_REG0E,
// 6, 0, NULL, 0),
SND_SOC_DAPM_PGA("INPUT PGA", SND_SOC_NOPM,
0, 0, NULL, 0),
/* ADCs */
//SND_SOC_DAPM_ADC("MONO ADC", NULL, ES8311_SYSTEM_REG0E, 5, 0),
SND_SOC_DAPM_ADC("MONO ADC", NULL, SND_SOC_NOPM, 0, 0),
/* Dmic MUX */
SND_SOC_DAPM_MUX("DMIC MUX", SND_SOC_NOPM, 0, 0,
&es8311_dmic_mux_controls),
/* sdp MUX */
SND_SOC_DAPM_MUX("SDP OUT MUX", SND_SOC_NOPM, 0, 0,
&es8311_adc_sdp_mux_controls),
/* Digital Interface */
//SND_SOC_DAPM_AIF_OUT("I2S OUT", "I2S1 Capture", 1,
SND_SOC_DAPM_AIF_OUT("I2S OUT", "I2S1 Capture", 0,
SND_SOC_NOPM, 0, 0),
/* Render path */
SND_SOC_DAPM_AIF_IN("I2S IN", "I2S1 Playback", 0,
SND_SOC_NOPM, 0, 0),
/*DACs SDP DATA SRC MUX */
SND_SOC_DAPM_MUX("DAC SDP SRC MUX", ES8311_SDPIN_REG09, 7, 2,
&es8311_dac_data_mux_controls),
SND_SOC_DAPM_DAC("MONO DAC", NULL, SND_SOC_NOPM, 0, 0),
/* Output Lines */
SND_SOC_DAPM_OUTPUT("DIFFERENTIAL OUT"),
};
static const struct snd_soc_dapm_route es8311_dapm_routes[] = {
/* record route map */
{"INPUT PGA", NULL, "AMIC"},
{"MONO ADC", NULL, "INPUT PGA"},
{"DMIC MUX", "DMIC DISABLE", "MONO ADC"},
{"DMIC MUX", "DMIC ENABLE", "DMIC"},
{"SDP OUT MUX", "FROM ADC OUT", "DMIC MUX"},
{"SDP OUT MUX", "FROM EQUALIZER", "DMIC MUX"},
{"I2S OUT", NULL, "SDP OUT MUX"},
/* playback route map */
{"DAC SDP SRC MUX", "SELECT SDP LEFT DATA", "I2S IN"},
{"DAC SDP SRC MUX", "SELECT SDP RIGHT DATA", "I2S IN"},
{"MONO DAC", NULL, "DAC SDP SRC MUX"},
{"DIFFERENTIAL OUT", NULL, "MONO DAC"},
};
struct _coeff_div {
u32 mclk; /* mclk frequency */
u32 rate; /* sample rate */
u8 prediv; /* the pre divider with range from 1 to 8 */
u8 premulti; /* the pre multiplier with x1, x2, x4 and x8 selection */
u8 adcdiv; /* adcclk divider */
u8 dacdiv; /* dacclk divider */
u8 fsmode; /* double speed or single speed, =0, ss, =1, ds */
u8 lrck_h; /* adclrck divider and daclrck divider */
u8 lrck_l;
u8 bclkdiv; /* sclk divider */
u8 adcosr; /* adc osr */
u8 dacosr; /* dac osr */
u8 adcscale;
};
/* component hifi mclk clock divider coefficients */
static const struct _coeff_div coeff_div[] = {
//mclk rate prediv mult adcdiv dacdiv fsmode lrch lrcl bckdiv osr adcscale
/* 8k */
{12288000, 8000, 0x06, 0x01, 0x01, 0x01, 0x00, 0x05, 0xff, 0x04, 0x10, 0x20, 0x04}, //1536
{18432000, 8000, 0x03, 0x01, 0x03, 0x03, 0x00, 0x08, 0xff, 0x18, 0x10, 0x20, 0x04}, //2304
{16384000, 8000, 0x08, 0x01, 0x01, 0x01, 0x00, 0x07, 0xff, 0x04, 0x10, 0x20, 0x04}, //2048
{8192000, 8000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x03, 0xff, 0x04, 0x10, 0x20, 0x04}, //1024
{6144000, 8000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x02, 0xff, 0x04, 0x10, 0x20, 0x04}, //768
{4096000, 8000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x20, 0x04}, //512
{3072000, 8000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x01, 0x7f, 0x04, 0x10, 0x20, 0x04}, //384
{2048000, 8000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20, 0x04}, //256
{1536000, 8000, 0x01, 0x04, 0x03, 0x03, 0x00, 0x00, 0xbf, 0x04, 0x10, 0x20, 0x04}, //192
{1024000, 8000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0x7f, 0x04, 0x10, 0x20, 0x04}, //128
{12000000, 8000, 0x05, 0x04, 0x03, 0x03, 0x00, 0x05, 0xDB, 0x04, 0x19, 0x19, 0x01}, //1500
{26000000, 8000 , 0x04, 0x03, 0x0C, 0x0C, 0x00, 0x06, 0x58, 0x18, 0x1B, 0x1B, 0x01},
/* 11.025k */
{11289600, 11025, 0x04, 0x01, 0x01, 0x01, 0x00, 0x03, 0xff, 0x04, 0x10, 0x20, 0x04}, //1024
{5644800, 11025, 0x02, 0x01, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x20, 0x04}, //512
{2822400, 11025, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20, 0x04}, //256
{1411200, 11025, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0x7f, 0x04, 0x10, 0x20, 0x04}, //128
/* 12k */
{12288000, 12000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x03, 0xff, 0x04, 0x10, 0x20, 0x04}, //1024
{6144000, 12000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x20, 0x04}, //512
{3072000, 12000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20, 0x04}, //256
{1536000, 12000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0x7f, 0x04, 0x10, 0x20, 0x04}, //128
/* 16k */
//{24576000, 16000, 0x06, 0x01, 0x01, 0x01, 0x00, 0x05, 0xff, 0x04, 0x10, 0x20, 0x04}, //1536
{12288000, 16000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x02, 0xff, 0x04, 0x10, 0x20, 0x04}, //768
{18432000, 16000, 0x03, 0x02, 0x03, 0x03, 0x00, 0x04, 0x7f, 0x0c, 0x10, 0x20, 0x04}, //1152
{16384000, 16000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x03, 0xff, 0x04, 0x10, 0x20, 0x04}, //1024
{8192000, 16000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x20, 0x04}, //512
{6144000, 16000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x01, 0x7f, 0x04, 0x10, 0x20, 0x04}, //384
{4096000, 16000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20, 0x04}, //256
{3072000, 16000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xbf, 0x04, 0x10, 0x20, 0x04}, //192
{2048000, 16000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0x7f, 0x04, 0x10, 0x20, 0x04}, //128
{1536000, 16000, 0x01, 0x08, 0x03, 0x03, 0x00, 0x00, 0x5f, 0x02, 0x10, 0x20, 0x04}, //96
{1024000, 16000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0x3f, 0x02, 0x10, 0x20, 0x04}, //64
{12000000, 16000, 0x05, 0x08, 0x03, 0x03, 0x00, 0x02, 0xED, 0x04, 0x19, 0x19, 0x01}, //750
{26000000, 16000 , 0x04, 0x03, 0x06, 0x06, 0x00, 0x06, 0x58, 0x18, 0x1B, 0x1B, 0x01},
/* 22.05k */
{11289600, 22050, 0x02, 0x01, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x20, 0x04}, //512
{5644800, 22050, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20, 0x04}, //256
{2822400, 22050, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0x7f, 0x04, 0x10, 0x20, 0x04}, //128
{1411200, 22050, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0x3f, 0x02, 0x10, 0x20, 0x04}, //64
/* 24k */
//{24576000, 24000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x03, 0xff, 0x04, 0x10, 0x20, 0x04}, //1024
{12288000, 24000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x20, 0x04}, //512
{18432000, 24000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x02, 0xff, 0x04, 0x10, 0x20, 0x04}, //768
{6144000, 24000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20, 0x04}, //256
{3072000, 24000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0x7f, 0x04, 0x10, 0x20, 0x04}, //128
{1536000, 24000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0x3f, 0x02, 0x10, 0x20, 0x04}, //64
{12000000, 24000, 0x05, 0x04, 0x01, 0x01, 0x00, 0x01, 0xF3, 0x04, 0x19, 0x19, 0x01}, //500
/* 32k */
//{24576000, 32000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x02, 0xff, 0x04, 0x10, 0x10, 0x04}, //768
{12288000, 32000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x01, 0x7f, 0x04, 0x10, 0x10, 0x04}, //384
{18432000, 32000, 0x03, 0x04, 0x03, 0x03, 0x00, 0x02, 0x3f, 0x0c, 0x10, 0x10, 0x04}, //576
{16384000, 32000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10, 0x04}, //512
{8192000, 32000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10, 0x04}, //256
{6144000, 32000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xbf, 0x04, 0x10, 0x10, 0x04}, //192
{4096000, 32000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0x7f, 0x04, 0x10, 0x10, 0x04}, //128
{3072000, 32000, 0x03, 0x08, 0x01, 0x01, 0x00, 0x00, 0x5f, 0x02, 0x10, 0x10, 0x04}, //96
{2048000, 32000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0x3f, 0x02, 0x10, 0x10, 0x04}, //64
{1536000, 32000, 0x01, 0x08, 0x03, 0x03, 0x01, 0x00, 0x2f, 0x02, 0x10, 0x10, 0x04}, //48
{1024000, 32000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0x1f, 0x02, 0x10, 0x10, 0x04}, //32
/* 44.1k */
//{22579200, 44100, 0x02, 0x01, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10, 0x04}, //512
{11289600, 44100, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10, 0x04}, //256
{5644800, 44100, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0x7f, 0x04, 0x10, 0x10, 0x04}, //128
{2822400, 44100, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0x3f, 0x02, 0x10, 0x10, 0x04}, //64
{1411200, 44100, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0x1f, 0x02, 0x10, 0x10, 0x04}, //32
/* 48k */
{24576000, 48000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x01, 0xff, 0x04, 0x10, 0x10, 0x04}, //512
{12288000, 48000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10, 0x04}, //256
{18432000, 48000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x01, 0x7f, 0x04, 0x10, 0x10, 0x04}, //384
{6144000, 48000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0x7f, 0x04, 0x10, 0x10, 0x04}, //128
{3072000, 48000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0x3f, 0x02, 0x10, 0x10, 0x04}, //64
{1536000, 48000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0x1f, 0x02, 0x10, 0x10, 0x04}, //32
{12000000, 48000, 0x05, 0x08, 0x01, 0x01, 0x00, 0x00, 0xF9, 0x04, 0x19, 0x19, 0x01}, //250
/* 64k */
{12288000, 64000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xbf, 0x04, 0x10, 0x10, 0x04}, //192
{18432000, 64000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x1f, 0x06, 0x12, 0x12, 0x03}, //288
{16384000, 64000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10, 0x04}, //256
{8192000, 64000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0x7f, 0x04, 0x10, 0x10, 0x04}, //128
{6144000, 64000, 0x03, 0x08, 0x01, 0x01, 0x01, 0x00, 0x5f, 0x02, 0x10, 0x10, 0x04}, //96
{4096000, 64000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0x3f, 0x02, 0x10, 0x10, 0x04}, //64
{3072000, 64000, 0x03, 0x08, 0x01, 0x01, 0x01, 0x00, 0x2f, 0x02, 0x10, 0x10, 0x04}, //48
{2048000, 64000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0x1f, 0x02, 0x10, 0x10, 0x04}, //32
/* 88.2k */
{11289600, 88200, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0x7f, 0x04, 0x10, 0x10, 0x04}, //128
{5644800, 88200, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0x3f, 0x02, 0x10, 0x10, 0x04}, //64
{2822400, 88200, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0x1f, 0x02, 0x10, 0x10, 0x04}, //32
/* 96k */
{12288000, 96000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0x7f, 0x04, 0x10, 0x10, 0x04}, //128
{18432000, 96000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xbf, 0x04, 0x10, 0x10, 0x04}, //192
{6144000, 96000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0x3f, 0x02, 0x10, 0x10, 0x04}, //64
{3072000, 96000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0x1f, 0x02, 0x10, 0x10, 0x04}, //32
};
static inline int get_coeff(int mclk, int rate)
{
int i;
for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
return i;
}
return -EINVAL;
}
/*
* if PLL not be used, use internal clk1 for mclk,otherwise, use internal clk2 for PLL source.
*/
static int es8311_set_dai_sysclk(struct snd_soc_dai *dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_component *component = dai->component;
struct es8311_private *es8311 = snd_soc_component_get_drvdata(component);
printk("Enter into %s(), freq:%d\n", __func__,freq);
switch (freq) {
case 11289600:
case 22579200:
case 5644800:
case 2822400:
case 1411200:
case 12288000:
case 16384000:
case 18432000:
case 24576000:
case 8192000:
case 6144000:
case 4096000:
case 2048000:
case 3072000:
case 1536000:
case 1024000:
case 12000000:
case 26000000:
es8311->mclk_rate = freq;
return 0;
}
return -EINVAL;
}
static int es8311_set_dai_fmt(struct snd_soc_dai *component_dai, unsigned int fmt)
{
struct snd_soc_component *component = component_dai->component;
struct es8311_private *es8311 = snd_soc_component_get_drvdata(component);
u8 iface = 0;
u8 adciface = 0;
u8 daciface = 0;
printk("Enter into %s()\n", __func__);
dev_dbg(component->dev, "Enter into %s()\n", __func__);
iface = snd_soc_component_read(component, ES8311_RESET_REG00);
adciface = snd_soc_component_read(component, ES8311_SDPOUT_REG0A);
daciface = snd_soc_component_read(component, ES8311_SDPIN_REG09);
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM: /* MASTER MODE */
pr_info("%s mastermode\n", __func__);
es8311->mastermode = 1;
dev_dbg(component->dev, "ES8311 in Master mode\n");
iface |= 0x40;
break;
case SND_SOC_DAIFMT_CBS_CFS: /* SLAVE MODE */
es8311->mastermode = 0;
dev_dbg(component->dev, "ES8311 in Slave mode\n");
iface &= 0xBF;
break;
default:
return -EINVAL;
}
snd_soc_component_write(component, ES8311_RESET_REG00, iface);
/* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
dev_dbg(component->dev, "ES8311 in I2S Format\n");
adciface &= 0xFC;
daciface &= 0xFC;
break;
case SND_SOC_DAIFMT_RIGHT_J:
return -EINVAL;
case SND_SOC_DAIFMT_LEFT_J:
dev_dbg(component->dev, "ES8311 in LJ Format\n");
adciface &= 0xFC;
daciface &= 0xFC;
adciface |= 0x01;
daciface |= 0x01;
break;
case SND_SOC_DAIFMT_DSP_A:
dev_dbg(component->dev, "ES8311 in DSP-A Format\n");
adciface &= 0xDC;
daciface &= 0xDC;
adciface |= 0x03;
daciface |= 0x03;
break;
case SND_SOC_DAIFMT_DSP_B:
dev_dbg(component->dev, "ES8311 in DSP-B Format\n");
adciface &= 0xDC;
daciface &= 0xDC;
adciface |= 0x23;
daciface |= 0x23;
break;
default:
return -EINVAL;
}
iface = snd_soc_component_read(component, ES8311_CLK_MANAGER_REG06);
/* clock inversion */
if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) ||
((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_LEFT_J)) {
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
iface &= 0xDF;
adciface &= 0xDF;
daciface &= 0xDF;
break;
case SND_SOC_DAIFMT_IB_IF:
iface |= 0x20;
adciface |= 0x20;
daciface |= 0x20;
break;
case SND_SOC_DAIFMT_IB_NF:
iface |= 0x20;
adciface &= 0xDF;
daciface &= 0xDF;
break;
case SND_SOC_DAIFMT_NB_IF:
iface &= 0xDF;
adciface |= 0x20;
daciface |= 0x20;
break;
default:
return -EINVAL;
}
}
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG06, iface);
snd_soc_component_write(component, ES8311_SDPOUT_REG0A, adciface);
snd_soc_component_write(component, ES8311_SDPIN_REG09, daciface);
return 0;
}
static int es8311_pcm_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
printk("Enter into %s()\n", __func__);
return 0;
}
static int es8311_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct es8311_private *es8311 = snd_soc_component_get_drvdata(component);
u16 iface;
int coeff;
u8 regv, datmp;
int rate;
printk("Enter into %s()\n", __func__);
/* we need mclk rate to configure registers. Set MCLK here if failed
* to get mclk from set_sysclk.
*
* If the es8311->mclk_rate is a constant value, for example 12.288M,
* set es8311->mclk_rate = 12288000;
* else if es8311->mclk_rate is dynamic, for example 128Fs,
* set es8311->mclk_rate = 128 * params_rate(params);
*/
if (es8311->mclk_src == ES8311_BCLK_PIN) {
/*
* Here 64 is ratio of BCLK/LRCK.
* If BCLK/LRCK isn't 64, please change it according to actual ratio.
*/
snd_soc_component_update_bits(component,
ES8311_CLK_MANAGER_REG01, 0x80, 0x80);
es8311->mclk_rate = 64 * params_rate(params);
}
pr_info("%s, mclk = %d, lrck = %d\n", __func__,
es8311->mclk_rate, params_rate(params));
rate = params_rate(params);
printk("yanming rate:%d\n",rate);
coeff = get_coeff(es8311->mclk_rate, params_rate(params));
if (coeff < 0) {
pr_info("Unable to configure sample rate %dHz with %dHz MCLK\n",
params_rate(params), es8311->mclk_rate);
//return -EINVAL;
}
/*
* set clock parammeters
*/
if (coeff >= 0) {
regv = snd_soc_component_read(component,
ES8311_CLK_MANAGER_REG02) & 0x07;
regv |= (coeff_div[coeff].prediv - 1) << 5;
datmp = 0;
switch (coeff_div[coeff].premulti) {
case 1:
datmp = 0;
break;
case 2:
datmp = 1;
break;
case 4:
datmp = 2;
break;
case 8:
datmp = 3;
break;
default:
break;
}
regv |= (datmp) << 3;
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG02, regv);
regv = snd_soc_component_read(component,
ES8311_CLK_MANAGER_REG05) & 0x00;
regv |= (coeff_div[coeff].adcdiv - 1) << 4;
regv |= (coeff_div[coeff].dacdiv - 1) << 0;
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG05, regv);
regv = snd_soc_component_read(component,
ES8311_CLK_MANAGER_REG03) & 0x80;
regv |= coeff_div[coeff].fsmode << 6;
regv |= coeff_div[coeff].adcosr << 0;
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG03, regv);
regv = snd_soc_component_read(component,
ES8311_CLK_MANAGER_REG04) & 0x80;
regv |= coeff_div[coeff].dacosr << 0;
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG04, regv);
regv = snd_soc_component_read(component,
ES8311_CLK_MANAGER_REG07) & 0xf0;
regv |= coeff_div[coeff].lrck_h << 0;
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG07, regv);
regv = snd_soc_component_read(component,
ES8311_CLK_MANAGER_REG08) & 0x00;
regv |= coeff_div[coeff].lrck_l << 0;
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG08, regv);
regv = snd_soc_component_read(component,
ES8311_CLK_MANAGER_REG06) & 0xE0;
if (coeff_div[coeff].bclkdiv < 19)
regv |= (coeff_div[coeff].bclkdiv - 1) << 0;
else
regv |= coeff_div[coeff].bclkdiv << 0;
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG06, regv);
regv = snd_soc_component_read(component, ES8311_ADC_REG16) & 0x38;
regv |= (coeff_div[coeff].adcscale) << 0;
snd_soc_component_write(component, ES8311_ADC_REG16, regv);
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
iface = snd_soc_component_read(component,
ES8311_SDPIN_REG09) & 0xE3;
/* bit size */
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
iface |= 0x0c;
break;
case SNDRV_PCM_FORMAT_S20_3LE:
iface |= 0x04;
break;
case SNDRV_PCM_FORMAT_S24_LE:
break;
case SNDRV_PCM_FORMAT_S32_LE:
iface |= 0x10;
break;
}
/* set iface */
snd_soc_component_write(component, ES8311_SDPIN_REG09, iface);
} else {
iface = snd_soc_component_read(component,
ES8311_SDPOUT_REG0A) & 0xE3;
/* bit size */
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
iface |= 0x0c;
break;
case SNDRV_PCM_FORMAT_S20_3LE:
iface |= 0x04;
break;
case SNDRV_PCM_FORMAT_S24_LE:
break;
case SNDRV_PCM_FORMAT_S32_LE:
iface |= 0x10;
break;
}
/* set iface */
snd_soc_component_write(component, ES8311_SDPOUT_REG0A, iface);
}
/* yu.dong@20240508[ZXW-277]Modified Platform CODEC ES8311 Compatible with I2S and TDM Modes start */
#ifdef CONFIG_USE_TOP_TDM
#else
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG02, 0x98);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG03, 0x1b);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG04, 0x1b);
/*
if(rate == 8000){
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG05, 0xbb);
pr_info("%s rate:%d\n",__FUNCTION__,rate);
}
if(rate == 16000){
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG05, 0x55);
pr_info("%s rate:%d\n",__FUNCTION__,rate);
}
*/
if(rate == 44100){
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG02, 0x90);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG03, 0x1d);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG04, 0x1d);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG05, 0x00);
pr_info("%s rate:%d\n",__FUNCTION__,rate);
}
#endif
/* yu.dong@20240508[ZXW-277]Modified Platform CODEC ES8311 Compatible with I2S and TDM Modes end */
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG06, 0x18);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG07, 0x06);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG08, 0x58);
return 0;
}
static int es8311_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
int regv;
struct es8311_private *es8311 = snd_soc_component_get_drvdata(component);
printk("Enter into %s(), level = %d\n", __func__, level);
switch (level) {
case SND_SOC_BIAS_ON:
printk("%s on\n", __func__);
snd_soc_component_write(component, ES8311_GP_REG45, 0x00);
if (es8311->mclk_src == ES8311_MCLK_PIN) {
snd_soc_component_write(component,
ES8311_CLK_MANAGER_REG01, 0x30);
} else {
snd_soc_component_write(component,
ES8311_CLK_MANAGER_REG01, 0xB0);
}
//snd_soc_component_write(component, ES8311_ADC_REG16, 0x24);
snd_soc_component_write(component, ES8311_SYSTEM_REG0B, 0x00);
snd_soc_component_write(component, ES8311_SYSTEM_REG0C, 0x00);
if (ES8311_AVDD == ES8311_1V8) {
snd_soc_component_write(component,
ES8311_SYSTEM_REG10, 0x61);
snd_soc_component_write(component,
ES8311_SYSTEM_REG11, 0x7B);
} else {
snd_soc_component_write(component,
ES8311_SYSTEM_REG10, 0x03);
snd_soc_component_write(component,
ES8311_SYSTEM_REG11, 0x57);
}
if (es8311->mclk_src == ES8311_MCLK_PIN) {
snd_soc_component_write(component,
ES8311_CLK_MANAGER_REG01, 0x3F);
} else {
snd_soc_component_write(component,
ES8311_CLK_MANAGER_REG01, 0xBF);
}
if (es8311->mclkinv == true) {
snd_soc_component_update_bits(component,
ES8311_CLK_MANAGER_REG01, 0x40, 0x40);
} else {
snd_soc_component_update_bits(component,
ES8311_CLK_MANAGER_REG01, 0x40, 0x00);
}
if (es8311->sclkinv == true) {
snd_soc_component_update_bits(component,
ES8311_CLK_MANAGER_REG06, 0x20, 0x20);
} else {
snd_soc_component_update_bits(component,
ES8311_CLK_MANAGER_REG06, 0x20, 0x00);
}
//digital reset
snd_soc_component_write(component, ES8311_RESET_REG00, 0x1f);
usleep_range(1000, 2000);
if (es8311->mastermode == 1) {
snd_soc_component_write(component,
ES8311_RESET_REG00, 0xC0);
} else {
snd_soc_component_write(component,
ES8311_RESET_REG00, 0x80);
}
usleep_range(1500, 3000);
snd_soc_component_write(component, ES8311_SYSTEM_REG0D, 0x01);
regv = snd_soc_component_read(component, ES8311_SYSTEM_REG14) & 0xCF;
regv |= 0x1A;
snd_soc_component_write(component, ES8311_SYSTEM_REG14, regv);
if (es8311->dmic_enable == true) {
snd_soc_component_update_bits(component, ES8311_SYSTEM_REG14,
0x40, 0x40);
} else {
snd_soc_component_update_bits(component, ES8311_SYSTEM_REG14,
0x40, 0x00);
}
snd_soc_component_write(component, ES8311_SYSTEM_REG12, 0x00);
snd_soc_component_write(component, ES8311_SYSTEM_REG13, 0x10);
snd_soc_component_write(component, ES8311_SYSTEM_REG0E, 0x02);
printk("%s biason REG0E=0X%X\n", __func__,snd_soc_component_read(component, ES8311_SYSTEM_REG0E));
snd_soc_component_write(component, ES8311_SYSTEM_REG0F, 0x7F);
snd_soc_component_write(component, ES8311_ADC_REG15, 0x40);
snd_soc_component_write(component, ES8311_ADC_REG1B, 0x0A);
snd_soc_component_write(component, ES8311_ADC_REG1C, 0x6A);
snd_soc_component_write(component, ES8311_DAC_REG37, 0x48);
/* yu.dong@20240718[ZXW-277]Optimizing Recording in CODEC 8311 TDM Mode start*/
#if defined(CONFIG_USE_TOP_TDM)
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG01, 0x9f);
snd_soc_component_write(component, ES8311_ADC_REG15, 0x00);
#endif
/* yu.dong@20240718[ZXW-277]Optimizing Recording in CODEC 8311 TDM Mode end*/
//snd_soc_component_write(component, ES8311_ADC_REG17, 0xBF);
//snd_soc_component_write(component, ES8311_DAC_REG32, 0xBF);
break;
case SND_SOC_BIAS_PREPARE:
printk("%s prepare\n", __func__);
break;
case SND_SOC_BIAS_STANDBY:
printk("%s standby\n", __func__);
if (es8311->bias_level == SND_SOC_BIAS_PREPARE) {
//snd_soc_component_write(component, ES8311_DAC_REG32, 0x00);
//snd_soc_component_write(component, ES8311_ADC_REG17, 0x00);
snd_soc_component_write(component, ES8311_SYSTEM_REG0E, 0xFF);
snd_soc_component_write(component, ES8311_SYSTEM_REG12, 0x02);
snd_soc_component_write(component, ES8311_SYSTEM_REG14, 0x00);
snd_soc_component_write(component, ES8311_SYSTEM_REG0D, 0xF9);
snd_soc_component_write(component, ES8311_ADC_REG15, 0x00);
snd_soc_component_write(component, ES8311_DAC_REG37, 0x08);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG02, 0x10);
snd_soc_component_write(component, ES8311_RESET_REG00, 0x00);
snd_soc_component_write(component, ES8311_RESET_REG00, 0x1F);
/* yu.dong@20240508[ZXW-277]Modified Platform CODEC ES8311 Compatible with I2S and TDM Modes start */
#ifdef CONFIG_USE_TOP_TDM
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG01, 0xB0);
#else
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG01, 0x30);
#endif
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG01, 0x00);
snd_soc_component_write(component, ES8311_GP_REG45, 0x00);
}
break;
case SND_SOC_BIAS_OFF:
printk("%s off\n", __func__);
if (es8311->bias_level == SND_SOC_BIAS_STANDBY) {
//snd_soc_component_write(component, ES8311_DAC_REG32, 0x00);
//snd_soc_component_write(component, ES8311_ADC_REG17, 0x00);
snd_soc_component_write(component, ES8311_SYSTEM_REG0E, 0xFF);
snd_soc_component_write(component, ES8311_SYSTEM_REG12, 0x02);
snd_soc_component_write(component, ES8311_SYSTEM_REG14, 0x00);
snd_soc_component_write(component, ES8311_SYSTEM_REG0D, 0xF9);
snd_soc_component_write(component, ES8311_ADC_REG15, 0x00);
snd_soc_component_write(component, ES8311_DAC_REG37, 0x08);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG02, 0x10);
snd_soc_component_write(component, ES8311_RESET_REG00, 0x00);
snd_soc_component_write(component, ES8311_RESET_REG00, 0x1F);
#ifdef CONFIG_USE_TOP_TDM
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG01, 0xB0);
#else
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG01, 0x30);
#endif
/* yu.dong@20240508[ZXW-277]Modified Platform CODEC ES8311 Compatible with I2S and TDM Modes end */
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG01, 0x00);
snd_soc_component_write(component, ES8311_GP_REG45, 0x00);
snd_soc_component_write(component, ES8311_SYSTEM_REG0D, 0xFC);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG02, 0x00);
}
break;
}
es8311->bias_level = level;
printk("%s END bias_level(%d),REG0E=0X%X\n", __func__,level,snd_soc_component_read(component, ES8311_SYSTEM_REG0E));
return 0;
}
static int es8311_set_tristate(struct snd_soc_dai *dai, int tristate)
{
struct snd_soc_component *component = dai->component;
printk("Enter into %s(), tristate = %d\n", __func__, tristate);
if (tristate) {
snd_soc_component_update_bits(component,
ES8311_CLK_MANAGER_REG07, 0x30, 0x30);
} else {
snd_soc_component_update_bits(component,
ES8311_CLK_MANAGER_REG07, 0x30, 0x00);
}
return 0;
}
static int es8311_mute(struct snd_soc_dai *dai, int mute, int direction)
{
struct snd_soc_component *component = dai->component;
printk("Enter into %s(), mute = %d\n", __func__, mute);
if (mute) {
snd_soc_component_write(component, ES8311_SYSTEM_REG12,
0x02);
snd_soc_component_update_bits(component, ES8311_DAC_REG31,
0x60, 0x60);
//snd_soc_component_write(component, ES8311_DAC_REG32, 0x00);
} else {
snd_soc_component_update_bits(component, ES8311_DAC_REG31,
0x60, 0x00);
snd_soc_component_write(component, ES8311_SYSTEM_REG12,
0x00);
//snd_soc_component_write(component, ES8311_DAC_REG32, 0xbf);
}
printk("%s mute=%d biason REG0E=0X%X\n", __func__,mute,snd_soc_component_read(component, ES8311_SYSTEM_REG0E));
return 0;
}
#define es8311_RATES SNDRV_PCM_RATE_8000_96000
#define es8311_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
static const struct snd_soc_dai_ops es8311_ops = {
.startup = es8311_pcm_startup,
.hw_params = es8311_pcm_hw_params,
.set_fmt = es8311_set_dai_fmt,
.set_sysclk = es8311_set_dai_sysclk,
.mute_stream = es8311_mute,
.set_tristate = es8311_set_tristate,
};
static struct snd_soc_dai_driver es8311_dai = {
.name = "ES8311 HiFi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
.rates = es8311_RATES,
.formats = es8311_FORMATS,
},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 2,
.rates = es8311_RATES,
.formats = es8311_FORMATS,
},
.ops = &es8311_ops,
.symmetric_rates = 1,
};
static int es8311_suspend(struct snd_soc_component *component)
{
printk("Enter into %s()\n", __func__);
//snd_soc_component_write(component, ES8311_DAC_REG32, 0x00);
//snd_soc_component_write(component, ES8311_ADC_REG17, 0x00);
snd_soc_component_write(component, ES8311_SYSTEM_REG0E, 0xFF);
snd_soc_component_write(component, ES8311_SYSTEM_REG12, 0x02);
snd_soc_component_write(component, ES8311_SYSTEM_REG14, 0x00);
snd_soc_component_write(component, ES8311_SYSTEM_REG0D, 0xF9);
snd_soc_component_write(component, ES8311_ADC_REG15, 0x00);
snd_soc_component_write(component, ES8311_DAC_REG37, 0x08);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG02, 0x10);
snd_soc_component_write(component, ES8311_RESET_REG00, 0x00);
snd_soc_component_write(component, ES8311_RESET_REG00, 0x1F);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG01, 0x30);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG01, 0x00);
snd_soc_component_write(component, ES8311_GP_REG45, 0x00);
snd_soc_component_write(component, ES8311_SYSTEM_REG0D, 0xFC);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG02, 0x00);
return 0;
}
static int es8311_resume(struct snd_soc_component *component)
{
printk("Enter into %s()\n", __func__);
//yu.dong@20240416[ZXW-268]Added codec re-initialization for power down and I2S default configuration adjustment
return 0;
}
static int es8311_probe(struct snd_soc_component *component)
{
int ret = 0;
struct es8311_private *es8311 = es8311_data;
printk("Enter into %s()\n", __func__);
snd_soc_component_set_drvdata(component, es8311);
if (component == NULL) {
dev_err(component->dev, "Codec device not registered\n");
return -ENODEV;
}
es8311_component = component;
es8311->component = component;
es8311->mastermode = 0;
/* yu.dong@20240508[ZXW-277]Modified Platform CODEC ES8311 Compatible with I2S and TDM Modes start */
#ifdef CONFIG_USE_TOP_TDM
es8311->mclk_src = ES8311_BCLK_PIN;
#else
es8311->mclk_src = ES8311_MCLK_SOURCE;
#endif
/* yu.dong@20240508[ZXW-277]Modified Platform CODEC ES8311 Compatible with I2S and TDM Modes end */
/* Enable the following code if there is no mclk.
* a clock named "mclk" need to be defined in the dts (see sample dts)
*
* No need to enable the following code to get mclk if:
* 1. sclk/bclk is used as mclk
* 2. mclk is controled by soc I2S
*/
//if (es8311->mclk_src == ES8311_MCLK_PIN) {
if (0) {
es8311->mclk = devm_clk_get(component->dev, "mclk");
if (IS_ERR(es8311->mclk)) {
dev_err(component->dev, "%s,unable to get mclk\n", __func__);
return PTR_ERR(es8311->mclk);
}
if (!es8311->mclk)
dev_err(component->dev, "%s, assuming static mclk\n", __func__);
ret = clk_prepare_enable(es8311->mclk);
if (ret) {
dev_err(component->dev, "%s, unable to enable mclk\n", __func__);
return ret;
}
}
/* yu.dong@20240508[ZXW-277]Modified Platform CODEC ES8311 Compatible with I2S and TDM Modes start */
snd_soc_component_write(component, ES8311_GP_REG45, 0x00);
#ifdef CONFIG_USE_TOP_TDM
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG01, 0xB0);
#else
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG01, 0x30);
#endif
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG02, 0x00);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG03, 0x10);
//snd_soc_component_write(component, ES8311_ADC_REG16, 0x24);
snd_soc_component_write(component, ES8311_ADC_REG16, 0x21);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG04, 0x10);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG05, 0x00);
snd_soc_component_write(component, ES8311_SDPIN_REG09, 0x00);
snd_soc_component_write(component, ES8311_SDPOUT_REG0A, 0x00);
snd_soc_component_write(component, ES8311_SYSTEM_REG0B, 0x00);
snd_soc_component_write(component, ES8311_SYSTEM_REG0C, 0x00);
if (ES8311_AVDD == ES8311_1V8) {
snd_soc_component_write(component, ES8311_SYSTEM_REG10, 0x61);
snd_soc_component_write(component, ES8311_SYSTEM_REG11, 0x7B);
} else {
snd_soc_component_write(component, ES8311_SYSTEM_REG10, 0x03);
snd_soc_component_write(component, ES8311_SYSTEM_REG11, 0x57);
}
if (es8311->mclk_src == ES8311_MCLK_PIN)
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG01, 0x3F);
else
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG01, 0xBF);
if (es8311->mastermode == 1)
snd_soc_component_write(component, ES8311_RESET_REG00, 0xC0);
else
snd_soc_component_write(component, ES8311_RESET_REG00, 0x80);
usleep_range(1500, 3000);
snd_soc_component_write(component, ES8311_SYSTEM_REG0D, 0x01);
if (es8311->mclkinv == true) {
snd_soc_component_update_bits(component, ES8311_CLK_MANAGER_REG01,
0x40, 0x40);
} else {
snd_soc_component_update_bits(component, ES8311_CLK_MANAGER_REG01,
0x40, 0x00);
}
if (es8311->sclkinv == true) {
snd_soc_component_update_bits(component, ES8311_CLK_MANAGER_REG06,
0x20, 0x20);
} else {
snd_soc_component_update_bits(component, ES8311_CLK_MANAGER_REG06,
0x20, 0x00);
}
snd_soc_component_write(component, ES8311_SYSTEM_REG14, 0x1A);
if (es8311->dmic_enable == true) {
snd_soc_component_update_bits(component, ES8311_SYSTEM_REG14,
0x40, 0x40);
} else {
snd_soc_component_update_bits(component, ES8311_SYSTEM_REG14,
0x40, 0x00);
}
snd_soc_component_write(component, ES8311_SYSTEM_REG12, 0x00);
snd_soc_component_write(component, ES8311_SYSTEM_REG13, 0x10);
snd_soc_component_write(component, ES8311_SYSTEM_REG0E, 0x02);
snd_soc_component_write(component, ES8311_SYSTEM_REG0F, 0x7F);
snd_soc_component_write(component, ES8311_ADC_REG15, 0x40);
snd_soc_component_write(component, ES8311_ADC_REG1B, 0x0A);
snd_soc_component_write(component, ES8311_ADC_REG1C, 0x6A);
snd_soc_component_write(component, ES8311_DAC_REG37, 0x48);
snd_soc_component_write(component, ES8311_ADC_REG17, 0xBF);
snd_soc_component_write(component, ES8311_DAC_REG32, 0xBF);
#ifdef CONFIG_USE_TOP_TDM
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG02, 0x1A);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG03, 0x1b);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG04, 0x1b);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG05, 0x00);
snd_soc_component_write(component, ES8311_SDPIN_REG09,0x0F);
snd_soc_component_write(component, ES8311_SDPOUT_REG0A,0x0F);
#else
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG02, 0x98);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG03, 0x1b);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG04, 0x1b);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG05, 0xbb);
#endif
/* yu.dong@20240508[ZXW-277]Modified Platform CODEC ES8311 Compatible with I2S and TDM Modes end */
msleep(100);
es8311_set_bias_level(component, SND_SOC_BIAS_STANDBY);
printk("%s end\n", __func__);
return ret;
}
static void es8311_remove(struct snd_soc_component *component)
{
printk("Enter into %s()\n", __func__);
es8311_set_bias_level(component, SND_SOC_BIAS_OFF);
}
static int clkout_init_pinctrl(struct device *dev)
{
struct pinctrl *pctrl;
struct pinctrl_state *state0;
struct clk *clk;
int ret;
struct es8311_private *info = dev_get_drvdata(dev);
struct device_node *np = dev->of_node;
//yu.dong@20240416[T106BUG-551][codec] codec 8311 sleep power consumption does not go down
dev_info(dev, "%s:start!\n", __func__);
if(dev == NULL){
dev_err(dev, "%s:dev is null ,return\n",__func__);
return -EINVAL;
}
dev_info(dev, "%s: get clk pinctrl\n", __func__);
pctrl = devm_pinctrl_get(dev);
if (IS_ERR(pctrl)) {
dev_warn(dev, "Failed to get clk_test pins\n");
pctrl = NULL;
return -EINVAL;
}
state0 = pinctrl_lookup_state(pctrl, "clk_out2");
if (IS_ERR(state0)) {
devm_pinctrl_put(pctrl);
dev_err(dev, "missing clk_out\n");
return -EINVAL;
}
dev_info(dev, "%s: select pinctrl\n", __func__);
if ( pinctrl_select_state(pctrl, state0) < 0) {
//devm_pinctrl_put(pctrl);
dev_err(dev, "setting clk_out failed\n");
ret = -EINVAL;
goto err_put_pinctrl;
}
dev_info(dev, "%s: get clk\n", __func__);
clk = of_clk_get_by_name(np, "clk_out2");
if (IS_ERR(clk)) {
dev_err(dev, "Could not get clk_out\n");
ret = PTR_ERR(clk);
goto err_put_pinctrl;
}
#if 1
dev_info(dev, "%s: clk prepare\n", __func__);
ret = clk_prepare(clk);
if (ret) {
dev_err(dev, "failed to clk prepare\n");
goto err_put_clk;
}
#else
dev_info(dev, "%s: clk enable\n", __func__);
ret = clk_prepare_enable(clk);
if (ret) {
dev_err(dev, "failed to enable clkout");
goto err_put_clk;
}
#endif
if(info != NULL){
dev_info(dev, "%s: set drvdata\n", __func__);
info->pctrl = pctrl;
info->state0 = state0;
info->clk = clk;
}
else{
dev_info(dev, "%s: info is null\n", __func__);
}
dev_info(dev, "%s: init clkout end!\n",__func__);
return 0;
err_put_clk:
clk_put(clk);
err_put_pinctrl:
devm_pinctrl_put(pctrl);
return ret;
}
//yu.dong@20240416[ZXW-268]Added codec re-initialization for power down and I2S default configuration adjustment start
static void es8311_reinit(struct snd_soc_component *component, struct es8311_private *es8311)
{
pr_info("%s:begin!\n", __func__);
/* yu.dong@20240508[ZXW-277]Modified Platform CODEC ES8311 Compatible with I2S and TDM Modes start */
snd_soc_component_write(component, ES8311_GP_REG45, 0x00);
#ifdef CONFIG_USE_TOP_TDM
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG01, 0xB0);
#else
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG01, 0x30);
#endif
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG02, 0x00);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG03, 0x10);
//snd_soc_component_write(component, ES8311_ADC_REG16, 0x24);
snd_soc_component_write(component, ES8311_ADC_REG16, 0x21);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG04, 0x10);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG05, 0x00);
snd_soc_component_write(component, ES8311_SDPIN_REG09, 0x00);
snd_soc_component_write(component, ES8311_SDPOUT_REG0A, 0x00);
snd_soc_component_write(component, ES8311_SYSTEM_REG0B, 0x00);
snd_soc_component_write(component, ES8311_SYSTEM_REG0C, 0x00);
if (ES8311_AVDD == ES8311_1V8) {
snd_soc_component_write(component, ES8311_SYSTEM_REG10, 0x61);
snd_soc_component_write(component, ES8311_SYSTEM_REG11, 0x7B);
} else {
snd_soc_component_write(component, ES8311_SYSTEM_REG10, 0x03);
snd_soc_component_write(component, ES8311_SYSTEM_REG11, 0x57);
}
if (es8311->mclk_src == ES8311_MCLK_PIN) {
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG01, 0x3F);
} else {
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG01, 0xBF);
}
if (es8311->mastermode == 1) {
snd_soc_component_write(component, ES8311_RESET_REG00, 0xC0);
} else {
snd_soc_component_write(component, ES8311_RESET_REG00, 0x80);
}
usleep_range(1500, 3000);
snd_soc_component_write(component, ES8311_SYSTEM_REG0D, 0x01);
if (es8311->mclkinv == true) {
snd_soc_component_update_bits(component, ES8311_CLK_MANAGER_REG01, 0x40, 0x40);
} else {
snd_soc_component_update_bits(component, ES8311_CLK_MANAGER_REG01, 0x40, 0x00);
}
if (es8311->sclkinv == true) {
snd_soc_component_update_bits(component, ES8311_CLK_MANAGER_REG06, 0x20, 0x20);
} else {
snd_soc_component_update_bits(component, ES8311_CLK_MANAGER_REG06, 0x20, 0x00);
}
snd_soc_component_write(component, ES8311_SYSTEM_REG14, 0x1A);
if (es8311->dmic_enable == true) {
snd_soc_component_update_bits(component, ES8311_SYSTEM_REG14, 0x40, 0x40);
} else {
snd_soc_component_update_bits(component, ES8311_SYSTEM_REG14, 0x40, 0x00);
}
snd_soc_component_write(component, ES8311_SYSTEM_REG12, 0x00);
snd_soc_component_write(component, ES8311_SYSTEM_REG13, 0x10);
snd_soc_component_write(component, ES8311_SYSTEM_REG0E, 0x02);
snd_soc_component_write(component, ES8311_SYSTEM_REG0F, 0x7F);
snd_soc_component_write(component, ES8311_ADC_REG15, 0x40);
snd_soc_component_write(component, ES8311_ADC_REG1B, 0x0A);
snd_soc_component_write(component, ES8311_ADC_REG1C, 0x6A);
snd_soc_component_write(component, ES8311_DAC_REG37, 0x48);
snd_soc_component_write(component, ES8311_ADC_REG17, 0xBF);
snd_soc_component_write(component, ES8311_DAC_REG32, 0xBF);
#ifdef CONFIG_USE_TOP_TDM
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG02, 0x1A);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG03, 0x1b);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG04, 0x1b);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG05, 0x00);
snd_soc_component_write(component, ES8311_SDPIN_REG09,0x0F);
snd_soc_component_write(component, ES8311_SDPOUT_REG0A,0x0F);
#else
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG02, 0x98);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG03, 0x1b);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG04, 0x1b);
snd_soc_component_write(component, ES8311_CLK_MANAGER_REG05, 0xbb);
#endif
/* yu.dong@20240508[ZXW-277]Modified Platform CODEC ES8311 Compatible with I2S and TDM Modes end */
msleep(100);
es8311_set_bias_level(component, SND_SOC_BIAS_STANDBY);
pr_info("%s:end!\n", __func__);
}
extern int zx29_i2s_config_sleep_pin(void);
extern int zx29_i2s_config_default_pin(void);
static int component_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
int ret = 0;
struct es8311_private *info = snd_soc_component_get_drvdata(component);
printk("Enter into %s()\n", __func__);
if(info->clk != NULL){
ret = clk_enable(info->clk);
if (ret) {
pr_err( "failed to enable clkout");
}
}
/* yu.dong@20240508[ZXW-277]Modified Platform CODEC ES8311 Compatible with I2S and TDM Modes start */
ret = zx29_i2s_config_default_pin();
if(ret < 0) {
pr_err("%s select state failure %d !! \n", __func__, ret);
}
es8311_reinit(component, info);
/* yu.dong@20240508[ZXW-277]Modified Platform CODEC ES8311 Compatible with I2S and TDM Modes end */
pr_info("%s:clk en end!\n",__func__);
return ret;
}
static int component_close(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
int ret = 0;
struct es8311_private *info = snd_soc_component_get_drvdata(component);
printk("Enter into %s()\n", __func__);
if(info->clk != NULL){
clk_disable(info->clk);
}
pr_info("%s:clk dis end!\n",__func__);
/* yu.dong@20240508[ZXW-277]Modified Platform CODEC ES8311 Compatible with I2S and TDM Modes start */
ret = zx29_i2s_config_sleep_pin();
if(ret < 0) {
pr_err("%s select state failure %d !! \n", __func__, ret);
}
/* yu.dong@20240508[ZXW-277]Modified Platform CODEC ES8311 Compatible with I2S and TDM Modes end */
return ret;
}
//yu.dong@20240416[ZXW-268]Added codec re-initialization for power down and I2S default configuration adjustment end
static const struct snd_soc_component_driver soc_component_dev_es8311 = {
.probe = es8311_probe,
.remove = es8311_remove,
.suspend = es8311_suspend,
.resume = es8311_resume,
.set_bias_level = es8311_set_bias_level,
.suspend_bias_off = 1,
.idle_bias_on = 1,
.controls = es8311_snd_controls,
.num_controls = ARRAY_SIZE(es8311_snd_controls),
.dapm_widgets = es8311_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(es8311_dapm_widgets),
.dapm_routes = es8311_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(es8311_dapm_routes),
.open = component_open,
.close = component_close,
};
static struct regmap_config es8311_regmap = {
.name= "ES8311",
.reg_bits = 8,
.val_bits = 8,
.max_register = ES8311_MAX_REGISTER,
.volatile_reg = es8311_volatile_register,
.writeable_reg = es8311_writable_register,
.readable_reg = es8311_readable_register,
.cache_type = REGCACHE_RBTREE,
};
#ifdef CONFIG_OF
static const struct of_device_id es8311_if_dt_ids[] = {
{.compatible = "everest,es8311", },
{ }
};
MODULE_DEVICE_TABLE(of, es8311_if_dt_ids);
#endif
static void es8311_i2c_shutdown(struct i2c_client *i2c)
{
printk("Enter into %s()\n", __func__);
}
static u32 cur_reg;
static ssize_t es8311_show(struct device *dev,
struct device_attribute *attr, char *_buf)
{
int ret;
int i ;
int reg_max = 256;
for( i = 0;i < reg_max;i++){
//sprintf(_buf, "%s(): get reg0x%04x=0x%04x\n", __func__, i,
//snd_soc_component_read(es8311_component, i));
printk("%s(): get reg0x%04x=0x%04x\n", __func__, i,
snd_soc_component_read(es8311_component, i));
}
return 0;
}
static ssize_t es8311_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int val = 0, flag = 0;
u8 i = 0, reg, num, value_w, value_r;
val = simple_strtol(buf, NULL, 16);
flag = (val >> 16) & 0xFF;
if (flag) {
reg = (val >> 8) & 0xFF;
value_w = val & 0xFF;
pr_info("\nWrite: start REG:0x%02x,val:0x%02x,count:0x%02x\n",
reg, value_w, flag);
while (flag--) {
snd_soc_component_write(es8311_component, reg, value_w);
pr_info("Write 0x%02x to REG:0x%02x\n", value_w, reg);
reg++;
}
} else {
reg = (val >> 8) & 0xFF;
num = val & 0xff;
pr_info("\nRead: start REG:0x%02x,count:0x%02x\n", reg, num);
do {
value_r = 0;
value_r = snd_soc_component_read(es8311_component, reg);
pr_info("REG[0x%02x]: 0x%02x;\n", reg, value_r);
reg++;
i++;
} while (i < num);
}
return count;
}
static DEVICE_ATTR(es8311, 0664, es8311_show, es8311_store);
static ssize_t codec_info_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
ssize_t count = 0;
struct device *dev = container_of(kobj, struct device, kobj);
struct es8311_private *info;
char cmd_str[16] = {0};
int ret,i;
int regs, rege;
unsigned int val;
struct snd_soc_component *component;
info = (struct es8311_private *) dev_get_drvdata(dev);
component = snd_soc_lookup_component(dev,NULL);
if (!component){
pr_err(" %s:(%d), snd_soc_lookup_component fail !\n", __func__, __LINE__ );
return count;
}
dev_info(dev," %s:(%d),snd_soc_lookup_component ,name=%s\n", __func__, __LINE__, component->name);
//info->component = component;
regs = 0x0;
rege = 0x45;
for (i = regs; i < rege; i++) {
//val = snd_soc_component_read(info->component, i);
regmap_read(info->regmap, i, &val);
dev_info(dev,"cocec reg read ,Reg(0x%x)=0x%x \n",i, val);
}
return count;
}
static ssize_t codec_info_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n)
{
ssize_t ret =0;
unsigned int val = 0;
struct device *dev = container_of(kobj, struct device, kobj);
struct es8311_private *info;
char cmd_str[17] = {0};
u32 param1 = 0,param2 = 0,param3 = 0;
int i;
struct snd_soc_component *component;
info = (struct es8311_private *) dev_get_drvdata(dev);
component = snd_soc_lookup_component(dev, NULL);
if (!component){
pr_err(" %s:(%d), snd_soc_lookup_component fail !\n", __func__, __LINE__ );
return n;
}
dev_info(dev," %s:(%d),snd_soc_lookup_component ,name=%s\n", __func__, __LINE__, component->name);
//info->component = component;
//dev_info(dev, "pcieinfo_store name %s \n", pdev->name);
sscanf(buf, "%16s %x %x %x", cmd_str,&param1,&param2,&param3);
dev_info(dev, "cmd_str:%s,param1:%x,param2:%x,param3:%x\n",cmd_str,param1,param2,param3);
dev_info(dev, "%s:cmd_str=%s \n",__func__,cmd_str);
ret = strcmp(cmd_str,"reg_read");
if( ret == 0)
{
dev_info(dev, "reg_read start\n");
if(param1 > 0xff){
dev_err(dev, "reg_read param invalidate fail,param1=%d \n",param1);
return -1;
}
//val = snd_soc_component_read(info->component, param1);
regmap_read(info->regmap, param1,&val);
dev_info(dev, "reg_read reg(%d)=0x%x \n",param1,val);
}
ret = strcmp(cmd_str,"reg_write");
if( ret == 0)
{
//u32 offset = param1;
//u32 mask = param2;
dev_info(dev, "reg_write start\n");
if(param1 > 0xff){
dev_err(dev, "reg_write param invalidate fail,param1=%d \n",param1);
return -1;
}
val = param2;
//ret = snd_soc_component_write(info->component, param1, val);
regmap_write(info->regmap, param1, val);
if (ret){
pr_err(" %s:(%d), cocec reg write fail - ret=%d\n", __func__, __LINE__ ,ret);
//return ret;
}
dev_info(dev, "reg_write reg(%d)=0x%x \n",param1,val);
}
return n;
}
#define CODEC_ATTR(_name) \
static struct kobj_attribute _name##_attr = { \
.attr = { \
.name = __stringify(_name), \
.mode = 0644, \
}, \
.show = _name##_show, \
.store = _name##_store, \
}
CODEC_ATTR(codec_info);
static struct attribute *es8311_debug_attrs[] = {
&dev_attr_es8311.attr,
&codec_info_attr.attr,
NULL,
};
static struct attribute_group es8311_debug_attr_group = {
.name = "es8311_debug",
.attrs = es8311_debug_attrs,
};
static int es8311_i2c_probe(struct i2c_client *i2c_client,
const struct i2c_device_id *id)
{
struct es8311_private *es8311;
int ret = -1;
unsigned int val;
pr_info("Enter into %s\n", __func__);
es8311 = devm_kzalloc(&i2c_client->dev,
sizeof(*es8311), GFP_KERNEL);
if (es8311 == NULL)
return -ENOMEM;
es8311->dmic_enable = false; // dmic interface disabled
/* the edge of lrck is always at the falling edge of mclk */
es8311->mclkinv = false;
/* the edge of lrck is always at the falling edge of sclk */
es8311->sclkinv = false;
i2c_set_clientdata(i2c_client, es8311);
es8311->regmap = devm_regmap_init_i2c(i2c_client, &es8311_regmap);
if (IS_ERR(es8311->regmap)) {
ret = PTR_ERR(es8311->regmap);
dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
return ret;
}
es8311->dev = &i2c_client->dev;
/* verify that we have an es8311 */
ret = regmap_read(es8311->regmap, ES8311_CHD1_REGFD, &val);
if (ret < 0) {
dev_err(&i2c_client->dev, "failed to read i2c at addr %X\n",
i2c_client->addr);
return ret;
}
/* The first ID should be 0x83 */
if (val != 0x83) {
dev_err(&i2c_client->dev, "device at addr %X is not an es8311\n",
i2c_client->addr);
return -ENODEV;
}
ret = regmap_read(es8311->regmap, ES8311_CHD2_REGFE, &val);
/* The NEXT ID should be 0x11 */
if (val != 0x11) {
dev_err(&i2c_client->dev, "device at addr %X is not an es8311\n",
i2c_client->addr);
return -ENODEV;
}
es8311_data = es8311;
es8311->pctrl = NULL;
es8311->state0 = NULL;
es8311->clk = NULL;
/* yu.dong@20240508[ZXW-277]Modified Platform CODEC ES8311 Compatible with I2S and TDM Modes start */
#ifndef CONFIG_USE_TOP_TDM
clkout_init_pinctrl(&i2c_client->dev);
#endif
/* yu.dong@20240508[ZXW-277]Modified Platform CODEC ES8311 Compatible with I2S and TDM Modes end */
ret = snd_soc_register_component(&i2c_client->dev,
&soc_component_dev_es8311,
&es8311_dai,
1);
if (ret < 0) {
kfree(es8311);
return ret;
}
pr_info("Enter into %s-----4\n", __func__);
ret = sysfs_create_group(&i2c_client->dev.kobj,
&es8311_debug_attr_group);
if (ret)
pr_err("failed to create attr group\n");
printk("%s end\n", __func__);
return ret;
}
static const struct i2c_device_id es8311_i2c_id[] = {
{"es8311", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, es8311_i2c_id);
static struct i2c_driver es8311_i2c_driver = {
.driver = {
.name = "es8311",
.owner = THIS_MODULE,
.of_match_table = es8311_if_dt_ids,
},
.shutdown = es8311_i2c_shutdown,
.probe = es8311_i2c_probe,
.id_table = es8311_i2c_id,
};
static int __init es8311_init(void)
{
int ret;
printk("Enter into %s()\n", __func__);
ret = i2c_add_driver(&es8311_i2c_driver);
if (ret != 0)
pr_info("Failed to register es8311 i2c driver\n");
return ret;
}
static void __exit es8311_exit(void)
{
printk("Enter into %s()\n", __func__);
return i2c_del_driver(&es8311_i2c_driver);
}
late_initcall(es8311_init);
module_exit(es8311_exit);
MODULE_DESCRIPTION("ASoC es8311 driver");
MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>");
MODULE_LICENSE("GPL");