* published by the Free Software Foundation.
*/
+#include <linux/clk.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/regmap.h>
#include "es8316.h"
-#if 1
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...) do { } while (0)
-#endif
-#define alsa_dbg DBG
-
-#define dmic_used 1
-#define amic_used 0
-
#define INVALID_GPIO -1
-
-#define ES8316_CODEC_SET_SPK 1
-#define ES8316_CODEC_SET_HP 2
-
-
-int HP_IRQ = 0;
-int hp_irq_flag = 0;
-int es8316_init_reg = 0;
-
#define GPIO_LOW 0
#define GPIO_HIGH 1
-#ifndef es8316_DEF_VOL
#define es8316_DEF_VOL 0x1e
-#endif
-
-struct snd_soc_codec *es8316_codec;
-static int es8316_init_regs(struct snd_soc_codec *codec);
-static int es8316_set_bias_level(struct snd_soc_codec *codec,
- enum snd_soc_bias_level level);
static const struct reg_default es8316_reg_defaults[] = {
{0x00, 0x03}, {0x01, 0x03}, {0x02, 0x00}, {0x03, 0x20},
{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
};
-static int es8316_readable(struct snd_soc_codec *codec, unsigned int reg)
-{
- if (reg <= 90)
- return 1;
- else
- return 0;
-}
-static int es8316_volatile(struct snd_soc_codec *codec, unsigned int reg)
-{
- if (reg <= 90)
- return 1;
- else
- return 0;
-}
/* codec private data */
struct es8316_priv {
struct regmap *regmap;
unsigned int dmic_amic;
unsigned int sysclk;
struct snd_pcm_hw_constraint_list *sysclk_constraints;
+ struct clk *mclk;
+ int debounce_time;
+ int hp_det_invert;
+ struct delayed_work work;
int spk_ctl_gpio;
- int hp_ctl_gpio;
int hp_det_gpio;
-
- bool spk_gpio_level;
- bool hp_gpio_level;
- bool hp_det_level;
+ bool muted;
+ bool hp_inserted;
+ bool spk_active_level;
int pwr_count;
};
-struct es8316_priv *es8316_private;
-
/*
* es8316_reset
* write value 0xff to reg0x00, the chip will be in reset mode
return snd_soc_write(codec, ES8316_RESET_REG00, 0x03);
}
-static int es8316_set_gpio(int gpio, bool level)
-{
- struct es8316_priv *es8316 = es8316_private;
-
- if (!es8316) {
- DBG("%s : es8316_priv is NULL\n", __func__);
- return 0;
- }
- DBG("%s : set %s %s ctl gpio %s\n", __func__,
- gpio & ES8316_CODEC_SET_SPK ? "spk" : "",
- gpio & ES8316_CODEC_SET_HP ? "hp" : "",
- level ? "HIGH" : "LOW");
- if ((gpio & ES8316_CODEC_SET_SPK)
- && es8316 && es8316->spk_ctl_gpio != INVALID_GPIO) {
- DBG("%d,set_value%s\n", es8316->spk_ctl_gpio, level ?
- "HIGH" : "LOW");
- gpio_set_value(es8316->spk_ctl_gpio, level);
- }
- return 0;
-}
-
-static char mute_flag = 1;
-static irqreturn_t hp_det_irq_handler(int irq, void *dev_id)
+static void es8316_enable_spk(struct es8316_priv *es8316, bool enable)
{
- int ret;
- unsigned int type;
- struct es8316_priv *es8316 = es8316_private;
-
- disable_irq_nosync(irq);
-
- type = gpio_get_value(es8316->hp_det_gpio) ?
- IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING;
- ret = irq_set_irq_type(irq, type);
- if (ret < 0) {
- DBG("%s: irq_set_irq_type(%d, %d) failed\n",
- __func__, irq, type);
- return -1;
- }
-
- if (es8316->hp_det_level != gpio_get_value(es8316->hp_det_gpio))
- hp_irq_flag = 0;
- else
- hp_irq_flag = 1;
- if (mute_flag == 0) {
- if (es8316->hp_det_level == gpio_get_value(es8316->hp_det_gpio))
- es8316_set_gpio(ES8316_CODEC_SET_SPK,
- !es8316->spk_gpio_level);
- else
- es8316_set_gpio(ES8316_CODEC_SET_SPK,
- es8316->spk_gpio_level);
- }
- enable_irq(irq);
+ bool level;
- return IRQ_HANDLED;
+ level = enable ? es8316->spk_active_level : !es8316->spk_active_level;
+ gpio_set_value(es8316->spk_ctl_gpio, level);
}
-/*
-* es8316S Controls
-*/
-/*#define DECLARE_TLV_DB_SCALE(name, min, step, mute) */
-/*static const DECLARE_TLV_DB_SCALE(hpout_vol_tlv, -4800, 1200, 0);*/
static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9600, 50, 1);
static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -9600, 50, 1);
static const DECLARE_TLV_DB_SCALE(hpmixer_gain_tlv, -1200, 150, 0);
static const DECLARE_TLV_DB_SCALE(mic_bst_tlv, 0, 1200, 0);
-/*static const DECLARE_TLV_DB_SCALE(linin_pga_tlv, 0, 300, 0);*/
-/* {0, +3, +6, +9, +12, +15, +18, +21, +24,+27,+30,+33} dB */
+
static unsigned int linin_pga_tlv[] = {
TLV_DB_RANGE_HEAD(12),
0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
7, 7, TLV_DB_SCALE_ITEM(2100, 0, 0),
8, 8, TLV_DB_SCALE_ITEM(2400, 0, 0),
};
+
static unsigned int hpout_vol_tlv[] = {
TLV_DB_RANGE_HEAD(1),
0, 3, TLV_DB_SCALE_ITEM(-4800, 1200, 0),
};
-static const char *const alc_func_txt[] = {"Off", "On"};
+
+static const char *const alc_func_txt[] = { "Off", "On" };
+
static const struct soc_enum alc_func =
SOC_ENUM_SINGLE(ES8316_ADC_ALC1_REG29, 6, 2, alc_func_txt);
-static const char *const ng_type_txt[] = {"Constant PGA Gain",
- "Mute ADC Output"};
+static const char *const ng_type_txt[] = {
+ "Constant PGA Gain", "Mute ADC Output" };
+
static const struct soc_enum ng_type =
SOC_ENUM_SINGLE(ES8316_ADC_ALC6_REG2E, 6, 2, ng_type_txt);
-static const char *const adcpol_txt[] = {"Normal", "Invert"};
+static const char *const adcpol_txt[] = { "Normal", "Invert" };
+
static const struct soc_enum adcpol =
SOC_ENUM_SINGLE(ES8316_ADC_MUTE_REG26, 1, 2, adcpol_txt);
-static const char *const dacpol_txt[] = {"Normal", "R Invert", "L Invert",
- "L + R Invert"};
+
+static const char *const dacpol_txt[] = {
+ "Normal", "R Invert", "L Invert", "L + R Invert" };
+
static const struct soc_enum dacpol =
SOC_ENUM_SINGLE(ES8316_DAC_SET1_REG30, 0, 4, dacpol_txt);
/* Analog Input MUX */
static const char * const es8316_analog_in_txt[] = {
- "lin1-rin1",
- "lin2-rin2",
- "lin1-rin1 with 20db Boost",
- "lin2-rin2 with 20db Boost"
-};
-static const unsigned int es8316_analog_in_values[] = {
- 0,/*1,*/
- 1,
- 2,
- 3
+ "lin1-rin1",
+ "lin2-rin2",
+ "lin1-rin1 with 20db Boost",
+ "lin2-rin2 with 20db Boost"
};
+
+static const unsigned int es8316_analog_in_values[] = { 0, 1, 2, 3 };
+
static const struct soc_enum es8316_analog_input_enum =
SOC_VALUE_ENUM_SINGLE(ES8316_ADC_PDN_LINSEL_REG22, 4, 3,
ARRAY_SIZE(es8316_analog_in_txt),
es8316_analog_in_txt,
es8316_analog_in_values);
+
static const struct snd_kcontrol_new es8316_analog_in_mux_controls =
SOC_DAPM_ENUM("Route", es8316_analog_input_enum);
/* Dmic MUX */
static const char * const es8316_dmic_txt[] = {
- "dmic disable",
- "dmic data at high level",
- "dmic data at low level",
-};
-static const unsigned int es8316_dmic_values[] = {
- 0,/*1,*/
- 1,
- 2
+ "dmic disable",
+ "dmic data at high level",
+ "dmic data at low level",
};
+
+static const unsigned int es8316_dmic_values[] = { 0, 1, 2 };
+
static const struct soc_enum es8316_dmic_src_enum =
SOC_VALUE_ENUM_SINGLE(ES8316_ADC_DMIC_REG25, 0, 3,
ARRAY_SIZE(es8316_dmic_txt),
es8316_dmic_txt,
es8316_dmic_values);
+
static const struct snd_kcontrol_new es8316_dmic_src_controls =
SOC_DAPM_ENUM("Route", es8316_dmic_src_enum);
"lin-rin with Boost and PGA"
};
-static const unsigned int es8316_hpmux_values[] = {0, 1, 2, 3};
+static const unsigned int es8316_hpmux_values[] = { 0, 1, 2, 3 };
static const struct soc_enum es8316_left_hpmux_enum =
SOC_VALUE_ENUM_SINGLE(ES8316_HPMIX_SEL_REG13, 4, 7,
ARRAY_SIZE(es8316_hpmux_texts),
es8316_hpmux_texts,
es8316_hpmux_values);
+
static const struct snd_kcontrol_new es8316_left_hpmux_controls =
- SOC_DAPM_VALUE_ENUM("Route", es8316_left_hpmux_enum);
+ SOC_DAPM_ENUM("Route", es8316_left_hpmux_enum);
static const struct soc_enum es8316_right_hpmux_enum =
SOC_VALUE_ENUM_SINGLE(ES8316_HPMIX_SEL_REG13, 0, 7,
ARRAY_SIZE(es8316_hpmux_texts),
es8316_hpmux_texts,
es8316_hpmux_values);
+
static const struct snd_kcontrol_new es8316_right_hpmux_controls =
- SOC_DAPM_VALUE_ENUM("Route", es8316_right_hpmux_enum);
+ SOC_DAPM_ENUM("Route", es8316_right_hpmux_enum);
/* headphone Output Mixer */
static const struct snd_kcontrol_new es8316_out_left_mix[] = {
SOC_DAPM_SINGLE("Left DAC Switch", ES8316_HPMIX_SWITCH_REG14,
7, 1, 0),
};
+
static const struct snd_kcontrol_new es8316_out_right_mix[] = {
SOC_DAPM_SINGLE("RLIN Switch", ES8316_HPMIX_SWITCH_REG14,
2, 1, 0),
"RDATA TO LDAC, LDATA TO RDAC",
};
-static const unsigned int es8316_dacsrc_values[] = {
- 0, 1, 2, 3};
+static const unsigned int es8316_dacsrc_values[] = { 0, 1, 2, 3 };
static const struct soc_enum es8316_dacsrc_mux_enum =
SOC_VALUE_ENUM_SINGLE(ES8316_DAC_SET1_REG30, 6, 4,
es8316_dacsrc_texts,
es8316_dacsrc_values);
static const struct snd_kcontrol_new es8316_dacsrc_mux_controls =
- SOC_DAPM_VALUE_ENUM("Route", es8316_dacsrc_mux_enum);
-
+ SOC_DAPM_ENUM("Route", es8316_dacsrc_mux_enum);
static const struct snd_soc_dapm_widget es8316_dapm_widgets[] = {
/* Input Lines */
0, 1, &es8316_out_right_mix[0],
ARRAY_SIZE(es8316_out_right_mix)),
- /* Ouput charge pump */
+ /* Output charge pump */
SND_SOC_DAPM_PGA("HPCP L", SND_SOC_NOPM,
0, 0, NULL, 0),
SND_SOC_DAPM_PGA("HPCP R", ES8316_CPHP_OUTEN_REG17,
2, 0, NULL, 0),
- /* Ouput Driver */
+ /* Output Driver */
SND_SOC_DAPM_PGA("HPVOL L", SND_SOC_NOPM,
0, 0, NULL, 0),
SND_SOC_DAPM_PGA("HPVOL R", SND_SOC_NOPM,
0, 0, NULL, 0),
- /* Ouput Driver */
+ /* Output Driver */
SND_SOC_DAPM_PGA("HPVOL L", ES8316_CPHP_OUTEN_REG17,
5, 0, NULL, 0),
SND_SOC_DAPM_PGA("HPVOL R", ES8316_CPHP_OUTEN_REG17,
u8 osr; /*adc osr*/
};
-
/* codec hifi mclk clock divider coefficients */
static const struct _coeff_div coeff_div[] = {
/* 8k */
- {12288000, 8000 , 6 , 0x06, 0x00, 21, 32},
- {11289600, 8000 , 6 , 0x05, 0x83, 20, 29},
- {18432000, 8000 , 9 , 0x09, 0x00, 27, 32},
- {16934400, 8000 , 8 , 0x08, 0x44, 25, 33},
- {12000000, 8000 , 7 , 0x05, 0xdc, 21, 25},
- {19200000, 8000 , 12, 0x09, 0x60, 27, 25},
+ { 12288000, 8000, 6, 0x06, 0x00, 21, 32 },
+ { 11289600, 8000, 6, 0x05, 0x83, 20, 29 },
+ { 18432000, 8000, 9, 0x09, 0x00, 27, 32 },
+ { 16934400, 8000, 8, 0x08, 0x44, 25, 33 },
+ { 12000000, 8000, 7, 0x05, 0xdc, 21, 25 },
+ { 19200000, 8000, 12, 0x09, 0x60, 27, 25 },
/* 11.025k */
- {11289600, 11025, 4 , 0x04, 0x00, 16, 32},
- {16934400, 11025, 6 , 0x06, 0x00, 21, 32},
- {12000000, 11025, 4 , 0x04, 0x40, 17, 34},
+ { 11289600, 11025, 4, 0x04, 0x00, 16, 32 },
+ { 16934400, 11025, 6, 0x06, 0x00, 21, 32 },
+ { 12000000, 11025, 4, 0x04, 0x40, 17, 34 },
/* 16k */
- {12288000, 16000, 3 , 0x03, 0x00, 12, 32},
- {18432000, 16000, 5 , 0x04, 0x80, 18, 25},
- {12000000, 16000, 3 , 0x02, 0xee, 12, 31},
- {19200000, 16000, 6 , 0x04, 0xb0, 18, 25},
+ { 12288000, 16000, 3, 0x03, 0x00, 12, 32 },
+ { 18432000, 16000, 5, 0x04, 0x80, 18, 25 },
+ { 12000000, 16000, 3, 0x02, 0xee, 12, 31 },
+ { 19200000, 16000, 6, 0x04, 0xb0, 18, 25 },
/* 22.05k */
- {11289600, 22050, 2 , 0x02, 0x00, 8 , 32},
- {16934400, 22050, 3 , 0x03, 0x00, 12, 32},
- {12000000, 22050, 2 , 0x02, 0x20, 8 , 34},
+ { 11289600, 22050, 2, 0x02, 0x00, 8, 32 },
+ { 16934400, 22050, 3, 0x03, 0x00, 12, 32 },
+ { 12000000, 22050, 2, 0x02, 0x20, 8, 34 },
/* 32k */
- {12288000, 32000, 1 , 0x01, 0x80, 6 , 48},
- {18432000, 32000, 2 , 0x02, 0x40, 9 , 32},
- {12000000, 32000, 1 , 0x01, 0x77, 6 , 31},
- {19200000, 32000, 3 , 0x02, 0x58, 10, 25},
+ { 12288000, 32000, 1, 0x01, 0x80, 6, 48 },
+ { 18432000, 32000, 2, 0x02, 0x40, 9, 32 },
+ { 12000000, 32000, 1, 0x01, 0x77, 6, 31 },
+ { 19200000, 32000, 3, 0x02, 0x58, 10, 25 },
/* 44.1k */
- {11289600, 44100, 1 , 0x01, 0x00, 4 , 32},
- {16934400, 44100, 1 , 0x01, 0x80, 6 , 32},
- {12000000, 44100, 1 , 0x01, 0x10, 4 , 34},
+ { 11289600, 44100, 1, 0x01, 0x00, 4, 32 },
+ { 16934400, 44100, 1, 0x01, 0x80, 6, 32 },
+ { 12000000, 44100, 1, 0x01, 0x10, 4, 34 },
/* 48k */
- {12288000, 48000, 1 , 0x01, 0x00, 4 , 32},
- {18432000, 48000, 1 , 0x01, 0x80, 6 , 32},
- {12000000, 48000, 1 , 0x00, 0xfa, 4 , 31},
- {19200000, 48000, 2 , 0x01, 0x90, 6, 25},
+ { 12288000, 48000, 1, 0x01, 0x00, 4, 32 },
+ { 18432000, 48000, 1, 0x01, 0x80, 6, 32 },
+ { 12000000, 48000, 1, 0x00, 0xfa, 4, 31 },
+ { 19200000, 48000, 2, 0x01, 0x90, 6, 25 },
/* 88.2k */
- {11289600, 88200, 1 , 0x00, 0x80, 2 , 32},
- {16934400, 88200, 1 , 0x00, 0xc0, 3 , 48},
- {12000000, 88200, 1 , 0x00, 0x88, 2 , 34},
+ { 11289600, 88200, 1, 0x00, 0x80, 2, 32 },
+ { 16934400, 88200, 1, 0x00, 0xc0, 3, 48 },
+ { 12000000, 88200, 1, 0x00, 0x88, 2, 34 },
/* 96k */
- {12288000, 96000, 1 , 0x00, 0x80, 2 , 32},
- {18432000, 96000, 1 , 0x00, 0xc0, 3 , 48},
- {12000000, 96000, 1 , 0x00, 0x7d, 1 , 31},
- {19200000, 96000, 1 , 0x00, 0xc8, 3 , 25},
+ { 12288000, 96000, 1, 0x00, 0x80, 2, 32 },
+ { 18432000, 96000, 1, 0x00, 0xc0, 3, 48 },
+ { 12000000, 96000, 1, 0x00, 0x7d, 1, 31 },
+ { 19200000, 96000, 1, 0x00, 0xc8, 3, 25 },
};
+
static inline int get_coeff(int mclk, int rate)
{
int i;
};
/*
-* Note that this should be called from init rather than from hw_params.
-*/
+ * Note that this should be called from init rather than from hw_params.
+ */
static int es8316_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
u8 adciface = 0;
u8 daciface = 0;
- alsa_dbg("%s----%d, fmt[%02x]\n", __func__, __LINE__, fmt);
-
iface = snd_soc_read(codec, ES8316_IFACE);
adciface = snd_soc_read(codec, ES8316_ADC_IFACE);
daciface = snd_soc_read(codec, ES8316_DAC_IFACE);
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
- alsa_dbg("es8316 in master mode");
iface |= 0x80;
break;
case SND_SOC_DAIFMT_CBS_CFS:
- alsa_dbg("es8316 in slave mode");
iface &= 0x7F;
break;
default:
return -EINVAL;
}
-
/* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
return -EINVAL;
}
-
/* clock inversion */
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
struct es8316_priv *es8316 = snd_soc_codec_get_drvdata(codec);
bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
- DBG("Enter::%s----%d es8316->sysclk=%d\n",
- __func__, __LINE__, es8316->sysclk);
snd_soc_write(codec, ES8316_RESET_REG00, 0xC0);
snd_soc_write(codec, ES8316_SYS_PDN_REG0D, 0x00);
/* es8316: both playback and capture need dac mclk */
ES8316_CLKMGR_DAC_MCLK_EN |
ES8316_CLKMGR_DAC_ANALOG_EN);
msleep(50);
- DBG("%s playback\n", __func__);
} else {
snd_soc_update_bits(codec,
ES8316_ADC_PDN_LINSEL_REG22, 0xC0, 0x20);
ES8316_CLKMGR_ADC_ANALOG_MASK,
ES8316_CLKMGR_ADC_MCLK_EN |
ES8316_CLKMGR_ADC_ANALOG_EN);
- DBG("%s capture\n", __func__);
}
- /* The set of sample rates that can be supported depends on the
- * MCLK supplied to the CODEC - enforce this.
- */
- if (!es8316->sysclk) {
- dev_err(codec->dev,
- "No MCLK configured, call set_sysclk() on init\n");
- return -EINVAL;
- }
-
- snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- es8316->sysclk_constraints);
-
return 0;
}
snd_soc_update_bits(codec, ES8316_CLKMGR_CLKSW_REG01,
ES8316_CLKMGR_DAC_ANALOG_MASK,
ES8316_CLKMGR_DAC_ANALOG_DIS);
- DBG("%s playback\n", __func__);
} else {
snd_soc_write(codec, ES8316_ADC_PDN_LINSEL_REG22, 0xc0);
snd_soc_update_bits(codec, ES8316_CLKMGR_CLKSW_REG01,
ES8316_CLKMGR_ADC_ANALOG_MASK,
ES8316_CLKMGR_ADC_MCLK_DIS |
ES8316_CLKMGR_ADC_ANALOG_DIS);
- DBG("%s capture\n", __func__);
}
- if (--es8316->pwr_count) {
- DBG("%s pwr count: %d\n", __func__, es8316->pwr_count);
- } else {
+ if (--es8316->pwr_count == 0) {
snd_soc_write(codec, ES8316_SYS_PDN_REG0D, 0x3F);
snd_soc_write(codec, ES8316_CLKMGR_CLKSW_REG01, 0xF3);
- DBG("%s pwr count close ES8316_SYS_PDN_REG0D\n", __func__);
}
}
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
- struct es8316_priv *es8316 = snd_soc_codec_get_drvdata(codec);
- int retv;
-
- u16 osrate = snd_soc_read(codec,
- ES8316_CLKMGR_ADCOSR_REG03) & 0xc0;
- u16 mclkdiv = snd_soc_read(codec,
- ES8316_CLKMGR_CLKSW_REG01) & 0x7f;
- u16 srate = snd_soc_read(codec,
- ES8316_SDP_MS_BCKDIV_REG09) & 0xE0;
- u16 adciface = snd_soc_read(codec,
- ES8316_SDP_ADCFMT_REG0A) & 0xE3;
- u16 daciface = snd_soc_read(codec,
- ES8316_SDP_DACFMT_REG0B) & 0xE3;
- u16 adcdiv = snd_soc_read(codec,
- ES8316_CLKMGR_ADCDIV1_REG04);
- u16 adclrckdiv_l = snd_soc_read(codec,
- ES8316_CLKMGR_ADCDIV2_REG05) & 0x00;
- u16 dacdiv = snd_soc_read(codec, ES8316_CLKMGR_DACDIV1_REG06);
- u16 daclrckdiv_l = snd_soc_read(codec,
- ES8316_CLKMGR_DACDIV2_REG07) & 0x00;
- int coeff;
- u16 adclrckdiv_h = adcdiv & 0xf0;
- u16 daclrckdiv_h = dacdiv & 0xf0;
-
- adcdiv &= 0x0f;
- dacdiv &= 0x0f;
-
-
- coeff = get_coeff(es8316->sysclk, params_rate(params));
- if (coeff < 0) {
- coeff = get_coeff(es8316->sysclk / 2, params_rate(params));
- mclkdiv |= 0x80;
- }
- if (coeff < 0) {
- dev_err(codec->dev,
- "Unable to configure sample rate %dHz with %dHz MCLK\n",
- params_rate(params), es8316->sysclk);
- return coeff;
- }
+ struct snd_soc_codec *codec = dai->codec;
+ int val;
- /* bit size */
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
- adciface |= 0x000C;
- daciface |= 0x000C;
+ val = ES8316_DACWL_16;
break;
case SNDRV_PCM_FORMAT_S20_3LE:
- adciface |= 0x0004;
- daciface |= 0x0004;
+ val = ES8316_DACWL_20;
break;
case SNDRV_PCM_FORMAT_S24_LE:
+ val = ES8316_DACWL_24;
break;
case SNDRV_PCM_FORMAT_S32_LE:
- adciface |= 0x0010;
- daciface |= 0x0010;
+ val = ES8316_DACWL_32;
break;
}
- /* set iface & srate*/
- snd_soc_update_bits(codec, ES8316_SDP_DACFMT_REG0B, 0xe3, daciface);
- snd_soc_update_bits(codec, ES8316_SDP_ADCFMT_REG0A, 0xe3, adciface);
- snd_soc_update_bits(codec, ES8316_CLKMGR_CLKSW_REG01, 0x80, mclkdiv);
- if (coeff >= 0) {
- osrate = coeff_div[coeff].osr;
- osrate &= 0x3f;
-
- srate |= coeff_div[coeff].sr;
- srate &= 0x1f;
-
- adcdiv |= (coeff_div[coeff].div << 4);
- adclrckdiv_h |= coeff_div[coeff].lrck_h;
- adcdiv &= 0xf0;
- adclrckdiv_h &= 0x0f;
- adcdiv |= adclrckdiv_h;
- adclrckdiv_l = coeff_div[coeff].lrck_l;
-
- dacdiv |= (coeff_div[coeff].div << 4);
- daclrckdiv_h |= coeff_div[coeff].lrck_h;
- dacdiv &= 0xf0;
- daclrckdiv_h &= 0x0f;
- dacdiv |= daclrckdiv_h;
- daclrckdiv_l = coeff_div[coeff].lrck_l;
- }
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ snd_soc_update_bits(codec, ES8316_SDP_DACFMT_REG0B,
+ ES8316_DACWL_MASK, val);
+ else
+ snd_soc_update_bits(codec, ES8316_SDP_ADCFMT_REG0A,
+ ES8316_ADCWL_MASK, val);
- retv = snd_soc_read(codec, ES8316_GPIO_FLAG);
return 0;
}
static int es8316_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
- struct es8316_priv *es8316 = es8316_private;
+ struct es8316_priv *es8316 = snd_soc_codec_get_drvdata(codec);
- mute_flag = mute;
+ es8316->muted = mute;
if (mute) {
- es8316_set_gpio(ES8316_CODEC_SET_SPK, !es8316->spk_gpio_level);
+ es8316_enable_spk(es8316, false);
msleep(100);
snd_soc_write(codec, ES8316_DAC_SET1_REG30, 0x20);
} else if (dai->playback_active) {
snd_soc_write(codec, ES8316_DAC_SET1_REG30, 0x00);
msleep(130);
- if (hp_irq_flag == 0)
- es8316_set_gpio(ES8316_CODEC_SET_SPK,
- es8316->spk_gpio_level);
- msleep(150);
+ if (!es8316->hp_inserted)
+ es8316_enable_spk(es8316, true);
}
return 0;
}
static int es8316_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
+ struct es8316_priv *es8316 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
switch (level) {
case SND_SOC_BIAS_ON:
- dev_dbg(codec->dev, "%s on\n", __func__);
break;
+
case SND_SOC_BIAS_PREPARE:
- dev_dbg(codec->dev, "%s prepare\n", __func__);
+ if (IS_ERR(es8316->mclk))
+ break;
+
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) {
+ clk_disable_unprepare(es8316->mclk);
+ } else {
+ ret = clk_prepare_enable(es8316->mclk);
+ if (ret)
+ return ret;
+ }
break;
+
case SND_SOC_BIAS_STANDBY:
- dev_dbg(codec->dev, "%s standby\n", __func__);
break;
+
case SND_SOC_BIAS_OFF:
- dev_dbg(codec->dev, "%s off\n", __func__);
snd_soc_write(codec, ES8316_CPHP_OUTEN_REG17, 0x00);
snd_soc_write(codec, ES8316_DAC_PDN_REG2F, 0x11);
snd_soc_write(codec, ES8316_CPHP_LDOCTL_REG1B, 0x03);
snd_soc_write(codec, ES8316_RESET_REG00, 0x00);
break;
}
- codec->dapm.bias_level = level;
return 0;
}
.symmetric_rates = 1,
};
-
static int es8316_init_regs(struct snd_soc_codec *codec)
{
- dev_dbg(codec->dev, "%s\n", __func__);
-
snd_soc_write(codec, ES8316_RESET_REG00, 0x3f);
usleep_range(5000, 5500);
snd_soc_write(codec, ES8316_RESET_REG00, 0x00);
static int es8316_resume(struct snd_soc_codec *codec)
{
- struct es8316_priv *es8316 = snd_soc_codec_get_drvdata(codec);
- int retv;
+ int ret;
- pr_info("%s: %d\n", __func__, __LINE__);
- retv = es8316_reset(codec); /* UPDATED BY DAVID,15-3-5 */
- retv = snd_soc_read(codec, ES8316_CLKMGR_ADCDIV2_REG05);
- if (retv == 0) {
+ es8316_reset(codec); /* UPDATED BY DAVID,15-3-5 */
+ ret = snd_soc_read(codec, ES8316_CLKMGR_ADCDIV2_REG05);
+ if (!ret) {
es8316_init_regs(codec);
- if (es8316->dmic_amic == dmic_used) {
- /* set gpio2 to DMIC CLK */
- snd_soc_write(codec, ES8316_GPIO_SEL_REG4D, 0x02);
- } else {
- /* set gpio2 to GM SHORT */
- snd_soc_write(codec, ES8316_GPIO_SEL_REG4D, 0x00);
- }
+ snd_soc_write(codec, ES8316_GPIO_SEL_REG4D, 0x00);
/* max debance time, enable interrupt, low active */
snd_soc_write(codec, ES8316_GPIO_DEBUNCE_INT_REG4E, 0xf3);
/* es8316_set_bias_level(codec, SND_SOC_BIAS_OFF); */
snd_soc_write(codec, ES8316_SYS_LP2_REG0F, 0xFF);
snd_soc_write(codec, ES8316_CLKMGR_CLKSW_REG01, 0xF3);
snd_soc_write(codec, ES8316_ADC_PDN_LINSEL_REG22, 0xc0);
- es8316_init_reg = 1;
}
return 0;
}
-static int es8316_probe(struct snd_soc_codec *codec)
+static irqreturn_t es8316_irq_handler(int irq, void *data)
{
- int ret = 0, retv;
- struct es8316_priv *es8316 = snd_soc_codec_get_drvdata(codec);
+ struct es8316_priv *es8316 = data;
+
+ queue_delayed_work(system_power_efficient_wq, &es8316->work,
+ msecs_to_jiffies(es8316->debounce_time));
+
+ return IRQ_HANDLED;
+}
- DBG("---%s--start--\n", __func__);
+static void hp_work(struct work_struct *work)
+{
+ struct es8316_priv *es8316;
+ int enable;
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+ es8316 = container_of(work, struct es8316_priv, work.work);
+ enable = gpio_get_value(es8316->hp_det_gpio);
+ if (es8316->hp_det_invert)
+ enable = !enable;
- if (ret < 0) {
- dev_err(codec->dev, "fail to reset audio (%d)\n", ret);
- goto err;
+ es8316->hp_inserted = enable ? true : false;
+ if (!es8316->muted) {
+ if (es8316->hp_inserted)
+ es8316_enable_spk(es8316, false);
+ else
+ es8316_enable_spk(es8316, true);
}
- retv = snd_soc_read(codec, ES8316_CLKMGR_ADCDIV2_REG05);
- if (retv == 0) {
- retv = es8316_reset(codec); /* UPDATED BY DAVID,15-3-5 */
- retv = snd_soc_read(codec, ES8316_CLKMGR_ADCDIV2_REG05);
- pr_err("%s: %d, retv=%x\n", __func__, __LINE__, retv);
- if (retv == 0) {
+}
+
+static int es8316_probe(struct snd_soc_codec *codec)
+{
+ struct es8316_priv *es8316 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+
+ es8316->mclk = devm_clk_get(codec->dev, "mclk");
+ if (PTR_ERR(es8316->mclk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ ret = clk_prepare_enable(es8316->mclk);
+ if (ret)
+ return ret;
+ ret = snd_soc_read(codec, ES8316_CLKMGR_ADCDIV2_REG05);
+ if (!ret) {
+ es8316_reset(codec); /* UPDATED BY DAVID,15-3-5 */
+ ret = snd_soc_read(codec, ES8316_CLKMGR_ADCDIV2_REG05);
+ if (!ret) {
es8316_init_regs(codec);
- if (es8316->dmic_amic == dmic_used) {
- /* set gpio2 to DMIC CLK */
- snd_soc_write(codec,
- ES8316_GPIO_SEL_REG4D, 0x02);
- } else {
- /* set gpio2 to GM SHORT */
- snd_soc_write(codec,
- ES8316_GPIO_SEL_REG4D, 0x00);
- }
+ snd_soc_write(codec, ES8316_GPIO_SEL_REG4D, 0x00);
/* max debance time, enable interrupt, low active */
snd_soc_write(codec,
ES8316_GPIO_DEBUNCE_INT_REG4E, 0xf3);
snd_soc_write(codec, ES8316_CLKMGR_CLKSW_REG01, 0xF3);
snd_soc_write(codec,
ES8316_ADC_PDN_LINSEL_REG22, 0xc0);
- es8316_init_reg = 1;
}
}
- codec->dapm.idle_bias_off = 0;
-#if defined(HS_IRQ)
- det_initalize();
-#elif defined(HS_TIMER)
- hsdet_init();
-#endif
-err:
+
return ret;
}
return 0;
}
+const struct regmap_config es8316_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = ES8316_TEST3_REG53,
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = es8316_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(es8316_reg_defaults),
+};
+
static struct snd_soc_codec_driver soc_codec_dev_es8316 = {
.probe = es8316_probe,
.remove = es8316_remove,
.suspend = es8316_suspend,
.resume = es8316_resume,
.set_bias_level = es8316_set_bias_level,
- .reg_cache_size = ARRAY_SIZE(es8316_reg_defaults),
- .reg_word_size = sizeof(u8),
- .reg_cache_default = es8316_reg_defaults,
- .volatile_register = es8316_volatile,
- .readable_register = es8316_readable,
.controls = es8316_snd_controls,
.num_controls = ARRAY_SIZE(es8316_snd_controls),
.num_dapm_routes = ARRAY_SIZE(es8316_dapm_routes),
};
-#if defined(CONFIG_SPI_MASTER)
-static int es8316_spi_probe(struct spi_device *spi)
-{
- struct es8316_priv *es8316;
- int ret;
-
- es8316 = kzalloc(sizeof(*es8316), GFP_KERNEL);
- if (es8316 == NULL)
- return -ENOMEM;
-
- spi_set_drvdata(spi, es8316);
- ret = snd_soc_register_codec(&spi->dev,
- &soc_codec_dev_es8316,
- &es8316_dai, 1);
- if (ret < 0)
- kfree(es8316);
- return ret;
-}
-
-static int es8316_spi_remove(struct spi_device *spi)
-{
- snd_soc_unregister_codec(&spi->dev);
- kfree(spi_get_drvdata(spi));
- return 0;
-}
-
-static struct spi_driver es8316_spi_driver = {
- .driver = {
- .name = "es8316",
- .owner = THIS_MODULE,
- },
- .probe = es8316_spi_probe,
- .remove = es8316_spi_remove,
-};
-#endif /* CONFIG_SPI_MASTER */
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-
-static void es8316_i2c_shutdown(struct i2c_client *i2c)
-{
- struct snd_soc_codec *codec;
- struct es8316_priv *es8316 = es8316_private;
-
- if (!es8316_codec)
- goto err;
-
- es8316_set_gpio(ES8316_CODEC_SET_SPK, !es8316->spk_gpio_level);
- mdelay(150);
-
-
- codec = es8316_codec;
- snd_soc_write(codec, ES8316_CPHP_ICAL_VOL_REG18, 0x33);
- snd_soc_write(codec, ES8316_CPHP_OUTEN_REG17, 0x00);
- snd_soc_write(codec, ES8316_CPHP_LDOCTL_REG1B, 0x03);
- snd_soc_write(codec, ES8316_CPHP_PDN2_REG1A, 0x22);
- snd_soc_write(codec, ES8316_CPHP_PDN1_REG19, 0x06);
- snd_soc_write(codec, ES8316_HPMIX_SWITCH_REG14, 0x00);
- snd_soc_write(codec, ES8316_HPMIX_PDN_REG15, 0x33);
- snd_soc_write(codec, ES8316_HPMIX_VOL_REG16, 0x00);
- snd_soc_write(codec, ES8316_ADC_PDN_LINSEL_REG22, 0xC0);
- snd_soc_write(codec, ES8316_DAC_PDN_REG2F, 0x11);
- snd_soc_write(codec, ES8316_SYS_PDN_REG0D, 0x3F);
- snd_soc_write(codec, ES8316_CLKMGR_CLKSW_REG01, 0x03);
- snd_soc_write(codec, ES8316_RESET_REG00, 0x7F);
-err:
- return;
-}
-
-static int es8316_i2c_probe(struct i2c_client *i2c_client,
+static int es8316_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct es8316_priv *es8316;
int ret = -1;
- unsigned long irq_flag = 0;
- int hp_irq = 0;
- int val = 0;
+ int hp_irq;
enum of_gpio_flags flags;
- struct device_node *np = i2c_client->dev.of_node;
-
- DBG("---%s---probe start\n", __func__);
+ struct device_node *np = i2c->dev.of_node;
- es8316 = kzalloc(sizeof(*es8316), GFP_KERNEL);
- if (es8316 == NULL)
+ es8316 = devm_kzalloc(&i2c->dev, sizeof(*es8316), GFP_KERNEL);
+ if (!es8316)
return -ENOMEM;
- else
- es8316_private = es8316;
- es8316->dmic_amic = amic_used; /*if internal mic is amic*/
+ es8316->debounce_time = 200;
+ es8316->hp_det_invert = 0;
es8316->pwr_count = 0;
- i2c_set_clientdata(i2c_client, es8316);
+ es8316->hp_inserted = false;
+ es8316->muted = true;
+
+ es8316->regmap = devm_regmap_init_i2c(i2c, &es8316_regmap_config);
+ if (IS_ERR(es8316->regmap)) {
+ ret = PTR_ERR(es8316->regmap);
+ dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
+ return ret;
+ }
+ i2c_set_clientdata(i2c, es8316);
es8316->spk_ctl_gpio = of_get_named_gpio_flags(np,
- "spk-con-gpio", 0, &flags);
+ "spk-con-gpio",
+ 0,
+ &flags);
if (es8316->spk_ctl_gpio < 0) {
- DBG("%s() Can not read property spk codec-en-gpio\n", __func__);
+ dev_info(&i2c->dev, "Can not read property spk_ctl_gpio\n");
es8316->spk_ctl_gpio = INVALID_GPIO;
} else {
- es8316->spk_gpio_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
- ret = gpio_request(es8316->spk_ctl_gpio, NULL);
- gpio_direction_output(es8316->spk_ctl_gpio,
- !es8316->spk_gpio_level);
- }
-
- es8316->hp_ctl_gpio = of_get_named_gpio_flags(np,
- "hp-con-gpio", 0, &flags);
- if (es8316->hp_ctl_gpio < 0) {
- DBG("%s() Can not read property hp codec-en-gpio\n", __func__);
- es8316->hp_ctl_gpio = INVALID_GPIO;
- } else {
- es8316->hp_gpio_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
- ret = gpio_request(es8316->hp_ctl_gpio, NULL);
- gpio_direction_output(es8316->hp_ctl_gpio, !es8316->hp_gpio_level);
+ es8316->spk_active_level = !(flags & OF_GPIO_ACTIVE_LOW);
+ ret = devm_gpio_request_one(&i2c->dev, es8316->spk_ctl_gpio,
+ GPIOF_DIR_OUT, NULL);
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to request spk_ctl_gpio\n");
+ return ret;
+ }
+ es8316_enable_spk(es8316, false);
}
es8316->hp_det_gpio = of_get_named_gpio_flags(np,
- "hp-det-gpio", 0, &flags);
+ "hp-det-gpio",
+ 0,
+ &flags);
if (es8316->hp_det_gpio < 0) {
- DBG("%s() Can not read property hp_det gpio\n", __func__);
+ dev_info(&i2c->dev, "Can not read property hp_det_gpio\n");
es8316->hp_det_gpio = INVALID_GPIO;
} else {
- es8316->hp_det_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
- ret = gpio_request(es8316->hp_det_gpio, NULL);
- if (ret != 0) {
- DBG("%s request HP_DET error", __func__);
+ INIT_DELAYED_WORK(&es8316->work, hp_work);
+ es8316->hp_det_invert = !!(flags & OF_GPIO_ACTIVE_LOW);
+ ret = devm_gpio_request_one(&i2c->dev, es8316->hp_det_gpio,
+ GPIOF_IN, "hp det");
+ if (ret < 0)
return ret;
- }
- gpio_direction_input(es8316->hp_det_gpio);
-
- irq_flag = IRQF_TRIGGER_LOW | IRQF_ONESHOT;
hp_irq = gpio_to_irq(es8316->hp_det_gpio);
-
- val = gpio_get_value(es8316->hp_det_gpio);
- if (val == es8316->hp_det_level) {
- pr_info("hp inserted.\n");
- hp_irq_flag = 1;
- es8316_set_gpio(ES8316_CODEC_SET_SPK,
- !es8316->spk_gpio_level);
+ ret = devm_request_threaded_irq(&i2c->dev, hp_irq, NULL,
+ es8316_irq_handler,
+ IRQF_TRIGGER_FALLING |
+ IRQF_TRIGGER_RISING |
+ IRQF_ONESHOT,
+ "es8316_interrupt", es8316);
+ if (ret < 0) {
+ dev_err(&i2c->dev, "request_irq failed: %d\n", ret);
+ return ret;
}
- if (hp_irq)
- ret = request_threaded_irq(hp_irq, NULL,
- hp_det_irq_handler, irq_flag, "ES8316", NULL);
+ schedule_delayed_work(&es8316->work,
+ msecs_to_jiffies(es8316->debounce_time));
}
- ret = snd_soc_register_codec(&i2c_client->dev,
+ ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_es8316,
&es8316_dai, 1);
- if (ret < 0) {
- kfree(es8316);
- return ret;
- }
-
-
return ret;
}
static int es8316_i2c_remove(struct i2c_client *client)
{
snd_soc_unregister_codec(&client->dev);
- kfree(i2c_get_clientdata(client));
return 0;
}
-static const unsigned short normal_i2c[] = {0x10, I2C_CLIENT_END};
static const struct i2c_device_id es8316_i2c_id[] = {
{"es8316", 0},
{"10ES8316:00", 0},
};
MODULE_DEVICE_TABLE(i2c, es8316_i2c_id);
+static const struct of_device_id es8316_of_match[] = {
+ { .compatible = "everest,es8316", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, es8316_of_match);
+
static struct i2c_driver es8316_i2c_driver = {
.driver = {
- .name = "es8316",
- .owner = THIS_MODULE,
+ .name = "es8316",
+ .of_match_table = es8316_of_match,
},
- .shutdown = es8316_i2c_shutdown,
- .probe = es8316_i2c_probe,
- .remove = es8316_i2c_remove,
+ .probe = es8316_i2c_probe,
+ .remove = es8316_i2c_remove,
.id_table = es8316_i2c_id,
- .class = I2C_CLASS_HWMON,
- .address_list = normal_i2c,
};
-#endif
-
-static int __init es8316_init(void)
-{
- DBG("--%s--start--\n", __func__);
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- return i2c_add_driver(&es8316_i2c_driver);
-#endif
-#if defined(CONFIG_SPI_MASTER)
- return spi_register_driver(&es8316_spi_driver);
-#endif
-}
-
-static void __exit es8316_exit(void)
-{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- return i2c_del_driver(&es8316_i2c_driver);
-#endif
-#if defined(CONFIG_SPI_MASTER)
- return spi_unregister_driver(&es8316_spi_driver);
-#endif
-}
-
-module_init(es8316_init);
-module_exit(es8316_exit);
+module_i2c_driver(es8316_i2c_driver);
MODULE_DESCRIPTION("ASoC es8316 driver");
MODULE_AUTHOR("Will <will@everset-semi.com>");