Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  es8375.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * es8375.c  --  ES8375 ALSA SoC Audio Codec
 *
 * Copyright Everest Semiconductor Co., Ltd
 *
 * Authors:  Michael Zhang (zhangyi@everest-semi.com)
 */


#include <linux/gpio/consumer.h>
#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 <linux/regulator/consumer.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/tlv.h>
#include <sound/soc.h>
#include <linux/acpi.h>
#include "es8375.h"

struct es8375_priv {
 struct regmap *regmap;
 struct clk *mclk;
 struct regulator_bulk_data core_supply[2];
 unsigned int  mclk_freq;
 int mastermode;
 u8 mclk_src;
 u8 vddd;
 enum snd_soc_bias_level bias_level;
};

static const char * const es8375_core_supplies[] = {
 "vddd",
 "vdda",
};

static const DECLARE_TLV_DB_SCALE(es8375_adc_osr_gain_tlv, -3100, 100, 0);
static const DECLARE_TLV_DB_SCALE(es8375_adc_volume_tlv, -9550, 50, 0);
static const DECLARE_TLV_DB_SCALE(es8375_adc_automute_attn_tlv, 0, 100, 0);
static const DECLARE_TLV_DB_SCALE(es8375_adc_dmic_volume_tlv, 0, 600, 0);
static const DECLARE_TLV_DB_SCALE(es8375_dac_volume_tlv, -9550, 50, 0);
static const DECLARE_TLV_DB_SCALE(es8375_dac_vppscale_tlv, -388, 12, 0);
static const DECLARE_TLV_DB_SCALE(es8375_dac_automute_attn_tlv, 0, 400, 0);
static const DECLARE_TLV_DB_SCALE(es8375_automute_ng_tlv, -9600, 600, 0);

static const char *const es8375_ramprate_txt[] = {
 "0.125dB/LRCK",
 "0.125dB/2LRCK",
 "0.125dB/4LRCK",
 "0.125dB/8LRCK",
 "0.125dB/16LRCK",
 "0.125dB/32LRCK",
 "0.125dB/64LRCK",
 "0.125dB/128LRCK",
 "disable softramp",
};
static SOC_ENUM_SINGLE_DECL(es8375_adc_ramprate, ES8375_ADC2,
  ADC_RAMPRATE_SHIFT_0, es8375_ramprate_txt);
static SOC_ENUM_SINGLE_DECL(es8375_dac_ramprate, ES8375_DAC2,
  DAC_RAMPRATE_SHIFT_0, es8375_ramprate_txt);

static const char *const es8375_automute_ws_txt[] = {
 "256 samples",
 "512 samples",
 "1024 samples",
 "2048 samples",
 "4096 samples",
 "8192 samples",
 "16384 samples",
 "32768 samples",
};
static SOC_ENUM_SINGLE_DECL(es8375_adc_automute_ws, ES8375_ADC_AUTOMUTE,
  ADC_AUTOMUTE_WS_SHIFT_3, es8375_automute_ws_txt);
static SOC_ENUM_SINGLE_DECL(es8375_dac_automute_ws, ES8375_DAC_AUTOMUTE,
  DAC_AUTOMUTE_WS_SHIFT_5, es8375_automute_ws_txt);

static const char *const es8375_dmic_pol_txt[] = {
 "Low",
 "High",
};

static SOC_ENUM_SINGLE_DECL(es8375_dmic_pol, ES8375_ADC1,
  DMIC_POL_SHIFT_4, es8375_dmic_pol_txt);

static const char *const es8375_adc_hpf_txt[] = {
 "Freeze Offset",
 "Dynamic HPF",
};

static SOC_ENUM_SINGLE_DECL(es8375_adc_hpf, ES8375_HPF1,
  ADC_HPF_SHIFT_5, es8375_adc_hpf_txt);

static const char *const es8375_dmic_mux_txt[] = {
 "AMIC",
 "DMIC",
};
static const struct soc_enum es8375_dmic_mux_enum =
 SOC_ENUM_SINGLE(ES8375_ADC1, ADC_SRC_SHIFT_7,
   ARRAY_SIZE(es8375_dmic_mux_txt), es8375_dmic_mux_txt);

static const struct snd_kcontrol_new es8375_dmic_mux_controls =
 SOC_DAPM_ENUM("ADC MUX", es8375_dmic_mux_enum);

static const struct snd_kcontrol_new es8375_snd_controls[] = {
 SOC_SINGLE_TLV("ADC OSR Volume", ES8375_ADC_OSR_GAIN,
   ADC_OSR_GAIN_SHIFT_0, ES8375_ADC_OSR_GAIN_MAX, 0,
   es8375_adc_osr_gain_tlv),
 SOC_SINGLE("ADC Invert Switch", ES8375_ADC1, ADC_INV_SHIFT_6, 1, 0),
 SOC_SINGLE("ADC RAM Clear", ES8375_ADC1, ADC_RAMCLR_SHIFT_5, 1, 0),
 SOC_ENUM("DMIC Polarity", es8375_dmic_pol),
 SOC_SINGLE_TLV("DMIC Volume", ES8375_ADC1,
  DMIC_GAIN_SHIFT_2, ES8375_DMIC_GAIN_MAX,
  0, es8375_adc_dmic_volume_tlv),
 SOC_ENUM("ADC Ramp Rate", es8375_adc_ramprate),
 SOC_SINGLE_TLV("ADC Volume", ES8375_ADC_VOLUME,
   ADC_VOLUME_SHIFT_0, ES8375_ADC_VOLUME_MAX,
   0, es8375_adc_volume_tlv),
 SOC_SINGLE("ADC Automute Switch", ES8375_ADC_AUTOMUTE,
   ADC_AUTOMUTE_SHIFT_7, 1, 0),
 SOC_ENUM("ADC Automute Winsize", es8375_adc_automute_ws),
 SOC_SINGLE_TLV("ADC Automute Noise Gate", ES8375_ADC_AUTOMUTE,
  ADC_AUTOMUTE_NG_SHIFT_0, ES8375_AUTOMUTE_NG_MAX,
  0, es8375_automute_ng_tlv),
 SOC_SINGLE_TLV("ADC Automute Volume", ES8375_ADC_AUTOMUTE_ATTN,
   ADC_AUTOMUTE_ATTN_SHIFT_0, ES8375_ADC_AUTOMUTE_ATTN_MAX,
   0, es8375_adc_automute_attn_tlv),
 SOC_ENUM("ADC HPF", es8375_adc_hpf),

 SOC_SINGLE("DAC DSM Mute Switch", ES8375_DAC1, DAC_DSMMUTE_SHIFT_7, 1, 0),
 SOC_SINGLE("DAC DEM Mute Switch", ES8375_DAC1, DAC_DEMMUTE_SHIFT_6, 1, 0),
 SOC_SINGLE("DAC Invert Switch", ES8375_DAC1, DAC_INV_SHIFT_5, 1, 0),
 SOC_SINGLE("DAC RAM Clear", ES8375_DAC1, DAC_RAMCLR_SHIFT_4, 1, 0),
 SOC_ENUM("DAC Ramp Rate", es8375_dac_ramprate),
 SOC_SINGLE_TLV("DAC Volume", ES8375_DAC_VOLUME,
   DAC_VOLUME_SHIFT_0, ES8375_DAC_VOLUME_MAX,
   0, es8375_dac_volume_tlv),
 SOC_SINGLE_TLV("DAC VPP Scale", ES8375_DAC_VPPSCALE,
   DAC_VPPSCALE_SHIFT_0, ES8375_DAC_VPPSCALE_MAX,
   0, es8375_dac_vppscale_tlv),
 SOC_SINGLE("DAC Automute Switch", ES8375_DAC_AUTOMUTE1,
   DAC_AUTOMUTE_EN_SHIFT_7, 1, 0),
 SOC_SINGLE_TLV("DAC Automute Noise Gate", ES8375_DAC_AUTOMUTE1,
  DAC_AUTOMUTE_NG_SHIFT_0, ES8375_AUTOMUTE_NG_MAX,
  0, es8375_automute_ng_tlv),
 SOC_ENUM("DAC Automute Winsize", es8375_dac_automute_ws),
 SOC_SINGLE_TLV("DAC Automute Volume", ES8375_DAC_AUTOMUTE,
   DAC_AUTOMUTE_ATTN_SHIFT_0, ES8375_DAC_AUTOMUTE_ATTN_MAX,
   0, es8375_dac_automute_attn_tlv),
};

static const struct snd_soc_dapm_widget es8375_dapm_widgets[] = {
 SND_SOC_DAPM_INPUT("MIC1"),
 SND_SOC_DAPM_INPUT("DMIC"),
 SND_SOC_DAPM_PGA("PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
 SND_SOC_DAPM_ADC("Mono ADC", NULL, SND_SOC_NOPM, 0, 0),
 SND_SOC_DAPM_AIF_OUT("AIF1TX""AIF1 Capture", 0, ES8375_SDP2,
   ES8375_ADC_P2S_MUTE_SHIFT_5, 1),

 SND_SOC_DAPM_MUX("ADC MUX", SND_SOC_NOPM, 0, 0, &es8375_dmic_mux_controls),

 SND_SOC_DAPM_AIF_IN("AIF1RX""AIF1 Playback", 0, ES8375_SDP,
  SND_SOC_NOPM, 0),
 SND_SOC_DAPM_DAC("Mono DAC", NULL, SND_SOC_NOPM, 0, 0),
 SND_SOC_DAPM_OUTPUT("OUT"),
};

static const struct snd_soc_dapm_route es8375_dapm_routes[] = {
 {"ADC MUX""AMIC""MIC1"},
 {"ADC MUX""DMIC""DMIC"},
 {"PGA", NULL, "ADC MUX"},
 {"Mono ADC", NULL, "PGA"},
 {"AIF1TX", NULL, "Mono ADC"},

 {"Mono DAC", NULL, "AIF1RX"},
 {"OUT", NULL, "Mono DAC"},
};

struct _coeff_div {
 u16 mclk_lrck_ratio;
 u32 mclk;
 u32 rate;
 u8 Reg0x04;
 u8 Reg0x05;
 u8 Reg0x06;
 u8 Reg0x07;
 u8 Reg0x08;
 u8 Reg0x09;
 u8 Reg0x0A;
 u8 Reg0x0B;
 u8 Reg0x19;
 u8 dvdd_vol;
 u8 dmic_sel;
};

static const struct _coeff_div coeff_div[] = {
 {32, 256000, 8000, 0x05, 0x34, 0xDD, 0x55, 0x1F, 0x00, 0x95, 0x00, 0x1F, 2, 2},
 {32, 512000, 16000, 0x05, 0x34, 0xDD, 0x55, 0x1F, 0x00, 0x94, 0x00, 0x1F, 2, 2},
 {32, 1536000, 48000, 0x05, 0x33, 0xD5, 0x55, 0x1F, 0x00, 0x93, 0x00, 0x1F, 2, 2},
 {36, 288000, 8000, 0x05, 0x34, 0xDD, 0x55, 0x23, 0x08, 0x95, 0x00, 0x1F, 2, 2},
 {36, 576000, 16000, 0x05, 0x34, 0xDD, 0x55, 0x23, 0x08, 0x94, 0x00, 0x1F, 2, 2},
 {36, 1728000, 48000, 0x05, 0x33, 0xD5, 0x55, 0x23, 0x08, 0x93, 0x00, 0x1F, 2, 2},
 {48, 384000, 8000, 0x05, 0x14, 0x5D, 0x55, 0x17, 0x20, 0x94, 0x00, 0x28, 2, 2},
 {48, 768000, 16000, 0x05, 0x14, 0x5D, 0x55, 0x17, 0x20, 0x94, 0x00, 0x28, 2, 2},
 {48, 2304000, 48000, 0x05, 0x11, 0x53, 0x55, 0x17, 0x20, 0x92, 0x00, 0x28, 2, 2},
 {50, 400000, 8000, 0x05, 0x14, 0x5D, 0x55, 0x18, 0x24, 0x94, 0x00, 0x27, 2, 2},
 {50, 800000, 16000, 0x05, 0x14, 0x5D, 0x55, 0x18, 0x24, 0x94, 0x00, 0x27, 2, 2},
 {50, 2400000, 48000, 0x05, 0x11, 0x53, 0x55, 0x18, 0x24, 0x92, 0x00, 0x27, 2, 2},
 {64, 512000, 8000, 0x05, 0x14, 0x5D, 0x33, 0x1F, 0x00, 0x94, 0x00, 0x1F, 2, 2},
 {64, 1024000, 16000, 0x05, 0x13, 0x55, 0x33, 0x1F, 0x00, 0x93, 0x00, 0x1F, 2, 2},
 {64, 3072000, 48000, 0x05, 0x11, 0x53, 0x33, 0x1F, 0x00, 0x92, 0x00, 0x1F, 2, 2},
 {72, 576000, 8000, 0x05, 0x14, 0x5D, 0x33, 0x23, 0x08, 0x94, 0x00, 0x1F, 2, 2},
 {72, 1152000, 16000, 0x05, 0x13, 0x55, 0x33, 0x23, 0x08, 0x93, 0x00, 0x1F, 2, 2},
 {72, 3456000, 48000, 0x05, 0x11, 0x53, 0x33, 0x23, 0x08, 0x92, 0x00, 0x1F, 2, 2},
 {96, 768000, 8000, 0x15, 0x34, 0xDD, 0x55, 0x1F, 0x00, 0x94, 0x00, 0x1F, 2, 2},
 {96, 1536000, 16000, 0x15, 0x34, 0xDD, 0x55, 0x1F, 0x00, 0x93, 0x00, 0x1F, 2, 2},
 {96, 4608000, 48000, 0x15, 0x33, 0xD5, 0x55, 0x1F, 0x00, 0x92, 0x00, 0x1F, 2, 2},
 {100, 800000, 8000, 0x05, 0x03, 0x35, 0x33, 0x18, 0x24, 0x94, 0x00, 0x27, 2, 2},
 {100, 1600000, 16000, 0x05, 0x03, 0x35, 0x33, 0x18, 0x24, 0x93, 0x00, 0x27, 2, 2},
 {100, 4800000, 48000, 0x03, 0x00, 0x31, 0x33, 0x18, 0x24, 0x92, 0x00, 0x27, 2, 2},
 {128, 1024000, 8000, 0x05, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x93, 0x01, 0x1F, 2, 2},
 {128, 2048000, 16000, 0x03, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x01, 0x1F, 2, 2},
 {128, 6144000, 48000, 0x03, 0x00, 0x31, 0x11, 0x1F, 0x00, 0x92, 0x01, 0x1F, 2, 2},
 {144, 1152000, 8000, 0x05, 0x03, 0x35, 0x11, 0x23, 0x08, 0x93, 0x01, 0x1F, 2, 2},
 {144, 2304000, 16000, 0x03, 0x01, 0x33, 0x11, 0x23, 0x08, 0x92, 0x01, 0x1F, 2, 2},
 {144, 6912000, 48000, 0x03, 0x00, 0x31, 0x11, 0x23, 0x08, 0x92, 0x01, 0x1F, 2, 2},
 {192, 1536000, 8000, 0x15, 0x14, 0x5D, 0x33, 0x1F, 0x00, 0x93, 0x02, 0x1F, 2, 2},
 {192, 3072000, 16000, 0x15, 0x13, 0x55, 0x33, 0x1F, 0x00, 0x92, 0x02, 0x1F, 2, 2},
 {192, 9216000, 48000, 0x15, 0x11, 0x53, 0x33, 0x1F, 0x00, 0x92, 0x02, 0x1F, 2, 2},
 {250, 12000000, 48000, 0x25, 0x11, 0x53, 0x55, 0x18, 0x24, 0x92, 0x04, 0x27, 2, 2},
 {256, 2048000, 8000, 0x0D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x03, 0x1F, 2, 2},
 {256, 4096000, 16000, 0x0B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x03, 0x1F, 2, 2},
 {256, 12288000, 48000, 0x0B, 0x00, 0x31, 0x11, 0x1F, 0x00, 0x92, 0x03, 0x1F, 2, 2},
 {384, 3072000, 8000, 0x15, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x05, 0x1F, 2, 2},
 {384, 6144000, 16000, 0x13, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x05, 0x1F, 2, 2},
 {384, 18432000, 48000, 0x13, 0x00, 0x31, 0x11, 0x1F, 0x00, 0x92, 0x05, 0x1F, 2, 2},
 {400, 19200000, 48000, 0x1B, 0x00, 0x31, 0x33, 0x18, 0x24, 0x92, 0x04, 0x27, 2, 2},
 {500, 24000000, 48000, 0x23, 0x00, 0x31, 0x33, 0x18, 0x24, 0x92, 0x04, 0x27, 2, 2},
 {512, 4096000, 8000, 0x1D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x07, 0x1F, 2, 2},
 {512, 8192000, 16000, 0x1B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x07, 0x1F, 2, 2},
 {512, 24576000, 48000, 0x1B, 0x00, 0x31, 0x11, 0x1F, 0x00, 0x92, 0x07, 0x1F, 2, 2},
 {768, 6144000, 8000, 0x2D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x0B, 0x1F, 2, 2},
 {768, 12288000, 16000, 0x2B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x0B, 0x1F, 2, 2},
 {1024, 8192000, 8000, 0x3D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x0F, 0x1F, 2, 2},
 {1024, 16384000, 16000, 0x3B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x0F, 0x1F, 2, 2},
 {1152, 9216000, 8000, 0x45, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x0F, 0x1F, 2, 2},
 {1152, 18432000, 16000, 0x43, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x0F, 0x1F, 2, 2},
 {1200, 9600000, 8000, 0x5D, 0x03, 0x35, 0x33, 0x18, 0x24, 0x92, 0x11, 0x27, 2, 2},
 {1200, 19200000, 16000, 0x5D, 0x03, 0x35, 0x33, 0x18, 0x24, 0x92, 0x11, 0x27, 2, 2},
 {1536, 12288000, 8000, 0x5D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x17, 0x1F, 2, 2},
 {1536, 24576000, 16000, 0x5B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x17, 0x1F, 2, 2},
 {2048, 16384000, 8000, 0x7D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x1F, 0x1F, 2, 2},
 {2304, 18432000, 8000, 0x8D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x23, 0x1F, 2, 2},
 {2400, 19200000, 8000, 0xBD, 0x03, 0x35, 0x33, 0x18, 0x24, 0x92, 0x25, 0x27, 2, 2},
 {3072, 24576000, 8000, 0xBD, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x2F, 0x1F, 2, 2},
 {32, 3072000, 96000, 0x05, 0x11, 0x53, 0x55, 0x0F, 0x00, 0x92, 0x00, 0x37, 2, 2},
 {64, 6144000, 96000, 0x03, 0x00, 0x31, 0x33, 0x0F, 0x00, 0x92, 0x00, 0x37, 2, 2},
 {96, 9216000, 96000, 0x15, 0x11, 0x53, 0x55, 0x0F, 0x00, 0x92, 0x00, 0x37, 2, 2},
 {128, 12288000, 96000, 0x0B, 0x00, 0x31, 0x33, 0x0F, 0x00, 0x92, 0x01, 0x37, 2, 2},
};

static inline int get_coeff(u8 vddd, u8 dmic, int mclk, int rate)
{
 int i;
 u8 dmic_det, vddd_det;

 for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
  if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) {
   vddd_det = ~(coeff_div[i].dvdd_vol ^ vddd) & 0x01;
   dmic_det = ~(coeff_div[i].dmic_sel ^ dmic) & 0x01;
   vddd_det |= ~(coeff_div[i].dvdd_vol % 2) & 0x01;
   dmic_det |= ~(coeff_div[i].dmic_sel % 2) & 0x01;

   if (vddd_det && dmic_det)
    return i;
  }
 }

 return -EINVAL;
}

static int es8375_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 es8375_priv *es8375 = snd_soc_component_get_drvdata(component);
 int par_width = params_width(params);
 u8 dmic_enable, iface = 0;
 unsigned int regv;
 int coeff, ret;

 if (es8375->mclk_src == ES8375_BCLK_PIN) {
  regmap_update_bits(es8375->regmap,
    ES8375_MCLK_SEL, 0x80, 0x80);

  es8375->mclk_freq = 2 * (unsigned int)par_width * params_rate(params);
 }

 regmap_read(es8375->regmap, ES8375_ADC1, ®v);
 dmic_enable = regv >> 7 & 0x01;

 ret = regulator_get_voltage(es8375->core_supply[ES8375_SUPPLY_VD].consumer);
 switch (ret) {
 case 1800000 ... 2000000:
  es8375->vddd = ES8375_1V8;
  break;
 case 2500000 ... 3300000:
  es8375->vddd = ES8375_3V3;
  break;
 default:
  es8375->vddd = ES8375_3V3;
  break;
 }

 coeff = get_coeff(es8375->vddd, dmic_enable, es8375->mclk_freq, params_rate(params));
 if (coeff < 0) {
  dev_warn(component->dev, "Clock coefficients do not match");
  return coeff;
 }
 regmap_write(es8375->regmap, ES8375_CLK_MGR4,
   coeff_div[coeff].Reg0x04);
 regmap_write(es8375->regmap, ES8375_CLK_MGR5,
   coeff_div[coeff].Reg0x05);
 regmap_write(es8375->regmap, ES8375_CLK_MGR6,
   coeff_div[coeff].Reg0x06);
 regmap_write(es8375->regmap, ES8375_CLK_MGR7,
   coeff_div[coeff].Reg0x07);
 regmap_write(es8375->regmap, ES8375_CLK_MGR8,
   coeff_div[coeff].Reg0x08);
 regmap_write(es8375->regmap, ES8375_CLK_MGR9,
   coeff_div[coeff].Reg0x09);
 regmap_write(es8375->regmap, ES8375_CLK_MGR10,
   coeff_div[coeff].Reg0x0A);
 regmap_write(es8375->regmap, ES8375_CLK_MGR11,
   coeff_div[coeff].Reg0x0B);
 regmap_write(es8375->regmap, ES8375_ADC_OSR_GAIN,
   coeff_div[coeff].Reg0x19);

 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;
 }

 regmap_update_bits(es8375->regmap, ES8375_SDP, 0x1c, iface);

 return 0;
}

static int es8375_set_sysclk(struct snd_soc_dai *dai, int clk_id,
  unsigned int freq, int dir)
{
 struct snd_soc_component *component = dai->component;
 struct es8375_priv *es8375 = snd_soc_component_get_drvdata(component);

 es8375->mclk_freq = freq;

 return 0;
}

static int es8375_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
 struct snd_soc_component *component = dai->component;
 struct es8375_priv *es8375 = snd_soc_component_get_drvdata(component);
 unsigned int iface, codeciface;

 regmap_read(es8375->regmap, ES8375_SDP, &codeciface);

 switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
 case SND_SOC_DAIFMT_CBC_CFP:
  es8375->mastermode = 1;
  regmap_update_bits(es8375->regmap, ES8375_RESET1,
    0x80, 0x80);
  break;
 case SND_SOC_DAIFMT_CBC_CFC:
  es8375->mastermode = 0;
  regmap_update_bits(es8375->regmap, ES8375_RESET1,
    0x80, 0x00);
  break;
 default:
  return -EINVAL;
 }

 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 case SND_SOC_DAIFMT_I2S:
  codeciface &= 0xFC;
  break;
 case SND_SOC_DAIFMT_RIGHT_J:
  return -EINVAL;
 case SND_SOC_DAIFMT_LEFT_J:
  codeciface &= 0xFC;
  codeciface |= 0x01;
  break;
 case SND_SOC_DAIFMT_DSP_A:
  codeciface &= 0xDC;
  codeciface |= 0x03;
  break;
 case SND_SOC_DAIFMT_DSP_B:
  codeciface &= 0xDC;
  codeciface |= 0x23;
  break;
 default:
  return -EINVAL;
 }

 regmap_read(es8375->regmap, ES8375_CLK_MGR3, &iface);

 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 case SND_SOC_DAIFMT_NB_NF:
  iface      &= 0xFE;
  codeciface &= 0xDF;
  break;
 case SND_SOC_DAIFMT_IB_IF:
  iface      |= 0x01;
  codeciface |= 0x20;
  break;
 case SND_SOC_DAIFMT_IB_NF:
  iface      |= 0x01;
  codeciface &= 0xDF;
  break;
 case SND_SOC_DAIFMT_NB_IF:
  iface      &= 0xFE;
  codeciface |= 0x20;
  break;
 default:
  return -EINVAL;
 }

 regmap_write(es8375->regmap, ES8375_CLK_MGR3, iface);
 regmap_write(es8375->regmap, ES8375_SDP, codeciface);

 return 0;
}

static int es8375_set_bias_level(struct snd_soc_component *component,
  enum snd_soc_bias_level level)
{
 struct es8375_priv *es8375 = snd_soc_component_get_drvdata(component);
 int ret;

 switch (level) {
 case SND_SOC_BIAS_ON:
  ret = clk_prepare_enable(es8375->mclk);
  if (ret) {
   dev_err(component->dev, "unable to prepare mclk\n");
   return  ret;
  }
  regmap_write(es8375->regmap, ES8375_CSM1, 0xA6);
  break;
 case SND_SOC_BIAS_PREPARE:
  break;
 case SND_SOC_BIAS_STANDBY:
  regmap_write(es8375->regmap, ES8375_CSM1, 0x96);
  clk_disable_unprepare(es8375->mclk);
  break;
 case SND_SOC_BIAS_OFF:
  break;
 }
 return 0;
}

static int es8375_mute(struct snd_soc_dai *dai, int mute, int stream)
{
 struct snd_soc_component *component = dai->component;
 struct es8375_priv *es8375 = snd_soc_component_get_drvdata(component);

 if (mute) {
  if (stream == SNDRV_PCM_STREAM_PLAYBACK)
   regmap_update_bits(es8375->regmap, ES8375_SDP, 0x40, 0x40);
  else
   regmap_update_bits(es8375->regmap, ES8375_SDP2, 0x20, 0x20);
 } else {
  if (stream == SNDRV_PCM_STREAM_PLAYBACK)
   regmap_update_bits(es8375->regmap, ES8375_SDP, 0x40, 0x00);
  else
   regmap_update_bits(es8375->regmap, ES8375_SDP2, 0x20, 0x00);
 }

 return 0;
}

#define es8375_RATES SNDRV_PCM_RATE_8000_96000

#define es8375_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 es8375_ops = {
 .hw_params = es8375_hw_params,
 .mute_stream = es8375_mute,
 .set_sysclk = es8375_set_sysclk,
 .set_fmt = es8375_set_dai_fmt,
};

static struct snd_soc_dai_driver es8375_dai = {
 .name = "ES8375 HiFi",
 .playback = {
  .stream_name = "AIF1 Playback",
  .channels_min = 1,
  .channels_max = 2,
  .rates = es8375_RATES,
  .formats = es8375_FORMATS,
 },
 .capture = {
  .stream_name = "AIF1 Capture",
  .channels_min = 1,
  .channels_max = 2,
  .rates = es8375_RATES,
  .formats = es8375_FORMATS,
 },
 .ops = &es8375_ops,
 .symmetric_rate = 1,
};

static void es8375_init(struct snd_soc_component *component)
{
 struct es8375_priv *es8375 = snd_soc_component_get_drvdata(component);

 regmap_write(es8375->regmap, ES8375_CLK_MGR10, 0x95);
 regmap_write(es8375->regmap, ES8375_CLK_MGR3, 0x48);
 regmap_write(es8375->regmap, ES8375_DIV_SPKCLK, 0x18);
 regmap_write(es8375->regmap, ES8375_CLK_MGR4, 0x02);
 regmap_write(es8375->regmap, ES8375_CLK_MGR5, 0x05);
 regmap_write(es8375->regmap, ES8375_CSM1, 0x82);
 regmap_write(es8375->regmap, ES8375_VMID_CHARGE2, 0x20);
 regmap_write(es8375->regmap, ES8375_VMID_CHARGE3, 0x20);
 regmap_write(es8375->regmap, ES8375_DAC_CAL, 0x28);
 regmap_write(es8375->regmap, ES8375_ANALOG_SPK1, 0xFC);
 regmap_write(es8375->regmap, ES8375_ANALOG_SPK2, 0xE0);
 regmap_write(es8375->regmap, ES8375_VMID_SEL, 0xFE);
 regmap_write(es8375->regmap, ES8375_ANALOG1, 0xB8);
 regmap_write(es8375->regmap, ES8375_SYS_CTRL2, 0x03);
 regmap_write(es8375->regmap, ES8375_CLK_MGR2, 0x16);
 regmap_write(es8375->regmap, ES8375_RESET1, 0x00);
 msleep(80);
 regmap_write(es8375->regmap, ES8375_CLK_MGR3, 0x00);
 regmap_write(es8375->regmap, ES8375_CSM1, 0x86);
 regmap_write(es8375->regmap, ES8375_CLK_MGR4, 0x0B);
 regmap_write(es8375->regmap, ES8375_CLK_MGR5, 0x00);
 regmap_write(es8375->regmap, ES8375_CLK_MGR6, 0x31);
 regmap_write(es8375->regmap, ES8375_CLK_MGR7, 0x11);
 regmap_write(es8375->regmap, ES8375_CLK_MGR8, 0x1F);
 regmap_write(es8375->regmap, ES8375_CLK_MGR9, 0x00);
 regmap_write(es8375->regmap, ES8375_ADC_OSR_GAIN, 0x1F);
 regmap_write(es8375->regmap, ES8375_ADC2, 0x00);
 regmap_write(es8375->regmap, ES8375_DAC2, 0x00);
 regmap_write(es8375->regmap, ES8375_DAC_OTP, 0x88);
 regmap_write(es8375->regmap, ES8375_ANALOG_SPK2, 0xE7);
 regmap_write(es8375->regmap, ES8375_ANALOG2, 0xF0);
 regmap_write(es8375->regmap, ES8375_ANALOG3, 0x40);
 regmap_write(es8375->regmap, ES8375_CLK_MGR2, 0xFE);

 regmap_update_bits(es8375->regmap, ES8375_SDP, 0x40, 0x40);
 regmap_update_bits(es8375->regmap, ES8375_SDP2, 0x20, 0x20);
}

static int es8375_suspend(struct snd_soc_component *component)
{
 struct es8375_priv *es8375 = snd_soc_component_get_drvdata(component);

 regmap_write(es8375->regmap, ES8375_CSM1, 0x96);
 regcache_cache_only(es8375->regmap, true);
 regcache_mark_dirty(es8375->regmap);
 return 0;
}

static int es8375_resume(struct snd_soc_component *component)
{
 struct es8375_priv *es8375 = snd_soc_component_get_drvdata(component);
 unsigned int reg;

 regcache_cache_only(es8375->regmap, false);
 regcache_cache_bypass(es8375->regmap, true);
 regmap_read(es8375->regmap, ES8375_CLK_MGR2, ®);
 regcache_cache_bypass(es8375->regmap, false);

 if (reg == 0x00)
  es8375_init(component);
 else
  es8375_set_bias_level(component, SND_SOC_BIAS_ON);

 regcache_sync(es8375->regmap);

 return 0;
}

static int es8375_codec_probe(struct snd_soc_component *component)
{
 struct es8375_priv *es8375 = snd_soc_component_get_drvdata(component);

 es8375->mastermode = 0;

 es8375_init(component);

 return 0;
}

static bool es8375_writeable_register(struct device *dev, unsigned int reg)
{
 switch (reg) {
 case ES8375_CHIP_VERSION:
 case ES8375_CHIP_ID0:
 case ES8375_CHIP_ID1:
 case ES8375_SPK_OFFSET:
 case ES8375_FLAGS2:
  return false;
 default:
  return true;
 }
}

static const struct regmap_config es8375_regmap_config = {
 .reg_bits = 8,
 .val_bits = 8,
 .max_register = ES8375_REG_MAX,
 .cache_type = REGCACHE_MAPLE,
 .use_single_read = true,
 .use_single_write = true,
 .writeable_reg = es8375_writeable_register,
};

static struct snd_soc_component_driver es8375_codec_driver = {
 .probe = es8375_codec_probe,
 .suspend = es8375_suspend,
 .resume = es8375_resume,
 .set_bias_level = es8375_set_bias_level,
 .controls = es8375_snd_controls,
 .num_controls = ARRAY_SIZE(es8375_snd_controls),
 .dapm_widgets = es8375_dapm_widgets,
 .num_dapm_widgets = ARRAY_SIZE(es8375_dapm_widgets),
 .dapm_routes = es8375_dapm_routes,
 .num_dapm_routes = ARRAY_SIZE(es8375_dapm_routes),

 .idle_bias_on = 1,
 .suspend_bias_off = 1,
};

static int es8375_read_device_properities(struct device *dev, struct es8375_priv *es8375)
{
 int ret, i;

 ret = device_property_read_u8(dev, "everest,mclk-src", &es8375->mclk_src);
 if (ret != 0)
  es8375->mclk_src = ES8375_MCLK_SOURCE;
 dev_dbg(dev, "mclk-src %x", es8375->mclk_src);

 for (i = 0; i < ARRAY_SIZE(es8375_core_supplies); i++)
  es8375->core_supply[i].supply = es8375_core_supplies[i];
 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(es8375_core_supplies), es8375->core_supply);
 if (ret) {
  dev_err(dev, "Failed to request core supplies %d\n", ret);
  return ret;
 }

 es8375->mclk = devm_clk_get(dev, "mclk");
 if (IS_ERR(es8375->mclk))
  return dev_err_probe(dev, PTR_ERR(es8375->mclk), "unable to get mclk\n");

 if (!es8375->mclk)
  dev_warn(dev, "assuming static mclk\n");

 ret = clk_prepare_enable(es8375->mclk);
 if (ret) {
  dev_err(dev, "unable to enable mclk\n");
  return ret;
 }
 ret = regulator_bulk_enable(ARRAY_SIZE(es8375_core_supplies), es8375->core_supply);
 if (ret) {
  dev_err(dev, "Failed to enable core supplies: %d\n", ret);
  clk_disable_unprepare(es8375->mclk);
  return ret;
 }

 return 0;
}

static int es8375_i2c_probe(struct i2c_client *i2c_client)
{
 struct es8375_priv *es8375;
 struct device *dev = &i2c_client->dev;
 int ret;
 unsigned int val;

 es8375 = devm_kzalloc(&i2c_client->dev, sizeof(*es8375), GFP_KERNEL);
 if (!es8375)
  return -ENOMEM;

 es8375->regmap = devm_regmap_init_i2c(i2c_client,
   &es8375_regmap_config);
 if (IS_ERR(es8375->regmap))
  return dev_err_probe(&i2c_client->dev, PTR_ERR(es8375->regmap),
   "regmap_init() failed\n");

 i2c_set_clientdata(i2c_client, es8375);

 ret = regmap_read(es8375->regmap, ES8375_CHIP_ID1, &val);
 if (ret < 0) {
  dev_err(&i2c_client->dev, "failed to read i2c at addr %X\n",
    i2c_client->addr);
  return ret;
 }

 if (val != 0x83) {
  dev_err(&i2c_client->dev, "device at addr %X is not an es8375\n",
    i2c_client->addr);
  return -ENODEV;
 }

 ret = regmap_read(es8375->regmap, ES8375_CHIP_ID0, &val);
 if (val != 0x75) {
  dev_err(&i2c_client->dev, "device at addr %X is not an es8375\n",
    i2c_client->addr);
  return -ENODEV;
 }

 ret = es8375_read_device_properities(dev, es8375);
 if (ret != 0) {
  dev_err(&i2c_client->dev, "get an error from dts info %X\n", ret);
  return ret;
 }

 return devm_snd_soc_register_component(&i2c_client->dev, &es8375_codec_driver,
   &es8375_dai, 1);
}

static void es8375_i2c_shutdown(struct i2c_client *i2c)
{
 struct es8375_priv *es8375;

 es8375 = i2c_get_clientdata(i2c);

 regmap_write(es8375->regmap, ES8375_CSM1, 0x3C);
 regmap_write(es8375->regmap, ES8375_CLK_MGR3, 0x48);
 regmap_write(es8375->regmap, ES8375_CSM2, 0x80);
 regmap_write(es8375->regmap, ES8375_CSM1, 0x3E);
 regmap_write(es8375->regmap, ES8375_CLK_MGR10, 0x15);
 regmap_write(es8375->regmap, ES8375_SYS_CTRL2, 0x0C);
 regmap_write(es8375->regmap, ES8375_RESET1, 0x00);
 regmap_write(es8375->regmap, ES8375_CSM2, 0x00);

 regulator_bulk_disable(ARRAY_SIZE(es8375_core_supplies), es8375->core_supply);
 clk_disable_unprepare(es8375->mclk);
}

static const struct i2c_device_id es8375_id[] = {
 {"es8375"},
 { }
};
MODULE_DEVICE_TABLE(i2c, es8375_id);

#ifdef CONFIG_ACPI
static const struct acpi_device_id es8375_acpi_match[] = {
 {"ESSX8375", 0},
 {},
};

MODULE_DEVICE_TABLE(acpi, es8375_acpi_match);
#endif

#ifdef CONFIG_OF
static const struct of_device_id es8375_of_match[] = {
 {.compatible = "everest,es8375",},
 {}
};

MODULE_DEVICE_TABLE(of, es8375_of_match);
#endif

static struct i2c_driver es8375_i2c_driver = {
 .driver = {
  .name = "es8375",
  .of_match_table = of_match_ptr(es8375_of_match),
  .acpi_match_table = ACPI_PTR(es8375_acpi_match),
 },
 .shutdown = es8375_i2c_shutdown,
 .probe = es8375_i2c_probe,
 .id_table = es8375_id,
};
module_i2c_driver(es8375_i2c_driver);

MODULE_DESCRIPTION("ASoC ES8375 driver");
MODULE_AUTHOR("Michael Zhang ");
MODULE_LICENSE("GPL");

Messung V0.5
C=100 H=99 G=99

¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge