Eine aufbereitete Darstellung der Quelle

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

Benutzer

SSL max9860.c   Interaktion und
PortierbarkeitC

 

// SPDX-License-Identifier: GPL-2.0
//
// Driver for the MAX9860 Mono Audio Voice Codec
//
// https://datasheets.maximintegrated.com/en/ds/MAX9860.pdf
//
// The driver does not support sidetone since the DVST register field is
// backwards with the mute near the maximum level instead of the minimum.
//
// Author: Peter Rosin <peda@axentia.s>
//         Copyright 2016 Axentia Technologies

#include <linux/init.h>
#include <linux/module.h>
#include <linux/clk.h>
#include <linux/kernel.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/i2c.h>
#include <linux/regulator/consumer.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm_params.h>
#include <sound/tlv.h>

#include "max9860.h"

struct max9860_priv {
 struct regmap *regmap;
 struct regulator *dvddio;
 struct notifier_block dvddio_nb;
 u8 psclk;
 unsigned long pclk_rate;
 int fmt;
};

static int max9860_dvddio_event(struct notifier_block *nb,
    unsigned long event, void *data)
{
 struct max9860_priv *max9860 = container_of(nb, struct max9860_priv,
          dvddio_nb);
 if (event & REGULATOR_EVENT_DISABLE) {
  regcache_mark_dirty(max9860->regmap);
  regcache_cache_only(max9860->regmap, true);
 }

 return 0;
}

static const struct reg_default max9860_reg_defaults[] = {
 { MAX9860_PWRMAN,       0x00 },
 { MAX9860_INTEN,        0x00 },
 { MAX9860_SYSCLK,       0x00 },
 { MAX9860_AUDIOCLKHIGH, 0x00 },
 { MAX9860_AUDIOCLKLOW,  0x00 },
 { MAX9860_IFC1A,        0x00 },
 { MAX9860_IFC1B,        0x00 },
 { MAX9860_VOICEFLTR,    0x00 },
 { MAX9860_DACATTN,      0x00 },
 { MAX9860_ADCLEVEL,     0x00 },
 { MAX9860_DACGAIN,      0x00 },
 { MAX9860_MICGAIN,      0x00 },
 { MAX9860_MICADC,       0x00 },
 { MAX9860_NOISEGATE,    0x00 },
};

static bool max9860_readable(struct device *dev, unsigned int reg)
{
 switch (reg) {
 case MAX9860_INTRSTATUS ... MAX9860_MICGAIN:
 case MAX9860_MICADC ... MAX9860_PWRMAN:
 case MAX9860_REVISION:
  return true;
 }

 return false;
}

static bool max9860_writeable(struct device *dev, unsigned int reg)
{
 switch (reg) {
 case MAX9860_INTEN ... MAX9860_MICGAIN:
 case MAX9860_MICADC ... MAX9860_PWRMAN:
  return true;
 }

 return false;
}

static bool max9860_volatile(struct device *dev, unsigned int reg)
{
 switch (reg) {
 case MAX9860_INTRSTATUS:
 case MAX9860_MICREADBACK:
  return true;
 }

 return false;
}

static bool max9860_precious(struct device *dev, unsigned int reg)
{
 switch (reg) {
 case MAX9860_INTRSTATUS:
  return true;
 }

 return false;
}

static const struct regmap_config max9860_regmap = {
 .reg_bits = 8,
 .val_bits = 8,

 .readable_reg = max9860_readable,
 .writeable_reg = max9860_writeable,
 .volatile_reg = max9860_volatile,
 .precious_reg = max9860_precious,

 .max_register = MAX9860_MAX_REGISTER,
 .reg_defaults = max9860_reg_defaults,
 .num_reg_defaults = ARRAY_SIZE(max9860_reg_defaults),
 .cache_type = REGCACHE_RBTREE,
};

static const DECLARE_TLV_DB_SCALE(dva_tlv, -9100, 100, 1);
static const DECLARE_TLV_DB_SCALE(dvg_tlv, 0, 600, 0);
static const DECLARE_TLV_DB_SCALE(adc_tlv, -1200, 100, 0);
static const DECLARE_TLV_DB_RANGE(pam_tlv,
 0, MAX9860_PAM_MAX - 1,             TLV_DB_SCALE_ITEM(-2000, 2000, 1),
 MAX9860_PAM_MAX, MAX9860_PAM_MAX,   TLV_DB_SCALE_ITEM(3000, 0, 0));
static const DECLARE_TLV_DB_SCALE(pgam_tlv, 0, 100, 0);
static const DECLARE_TLV_DB_SCALE(anth_tlv, -7600, 400, 1);
static const DECLARE_TLV_DB_SCALE(agcth_tlv, -1800, 100, 0);

static const char * const agchld_text[] = {
 "AGC Disabled", "50ms", "100ms", "400ms"
};

static SOC_ENUM_SINGLE_DECL(agchld_enum, MAX9860_MICADC,
       MAX9860_AGCHLD_SHIFT, agchld_text);

static const char * const agcsrc_text[] = {
 "Left ADC", "Left/Right ADC"
};

static SOC_ENUM_SINGLE_DECL(agcsrc_enum, MAX9860_MICADC,
       MAX9860_AGCSRC_SHIFT, agcsrc_text);

static const char * const agcatk_text[] = {
 "3ms", "12ms", "50ms", "200ms"
};

static SOC_ENUM_SINGLE_DECL(agcatk_enum, MAX9860_MICADC,
       MAX9860_AGCATK_SHIFT, agcatk_text);

static const char * const agcrls_text[] = {
 "78ms", "156ms", "312ms", "625ms",
 "1.25s", "2.5s", "5s", "10s"
};

static SOC_ENUM_SINGLE_DECL(agcrls_enum, MAX9860_MICADC,
       MAX9860_AGCRLS_SHIFT, agcrls_text);

static const char * const filter_text[] = {
 "Disabled",
 "Elliptical HP 217Hz notch (16kHz)",
 "Butterworth HP 500Hz (16kHz)",
 "Elliptical HP 217Hz notch (8kHz)",
 "Butterworth HP 500Hz (8kHz)",
 "Butterworth HP 200Hz (48kHz)"
};

static SOC_ENUM_SINGLE_DECL(avflt_enum, MAX9860_VOICEFLTR,
       MAX9860_AVFLT_SHIFT, filter_text);

static SOC_ENUM_SINGLE_DECL(dvflt_enum, MAX9860_VOICEFLTR,
       MAX9860_DVFLT_SHIFT, filter_text);

static const struct snd_kcontrol_new max9860_controls[] = {
SOC_SINGLE_TLV("Master Playback Volume", MAX9860_DACATTN,
        MAX9860_DVA_SHIFT, MAX9860_DVA_MUTE, 1, dva_tlv),
SOC_SINGLE_TLV("DAC Gain Volume", MAX9860_DACGAIN,
        MAX9860_DVG_SHIFT, MAX9860_DVG_MAX, 0, dvg_tlv),
SOC_DOUBLE_TLV("Line Capture Volume", MAX9860_ADCLEVEL,
        MAX9860_ADCLL_SHIFT, MAX9860_ADCRL_SHIFT, MAX9860_ADCxL_MIN, 1,
        adc_tlv),

SOC_ENUM("AGC Hold Time", agchld_enum),
SOC_ENUM("AGC/Noise Gate Source", agcsrc_enum),
SOC_ENUM("AGC Attack Time", agcatk_enum),
SOC_ENUM("AGC Release Time", agcrls_enum),

SOC_SINGLE_TLV("Noise Gate Threshold Volume", MAX9860_NOISEGATE,
        MAX9860_ANTH_SHIFT, MAX9860_ANTH_MAX, 0, anth_tlv),
SOC_SINGLE_TLV("AGC Signal Threshold Volume", MAX9860_NOISEGATE,
        MAX9860_AGCTH_SHIFT, MAX9860_AGCTH_MIN, 1, agcth_tlv),

SOC_SINGLE_TLV("Mic PGA Volume", MAX9860_MICGAIN,
        MAX9860_PGAM_SHIFT, MAX9860_PGAM_MIN, 1, pgam_tlv),
SOC_SINGLE_TLV("Mic Preamp Volume", MAX9860_MICGAIN,
        MAX9860_PAM_SHIFT, MAX9860_PAM_MAX, 0, pam_tlv),

SOC_ENUM("ADC Filter", avflt_enum),
SOC_ENUM("DAC Filter", dvflt_enum),
};

static const struct snd_soc_dapm_widget max9860_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("MICL"),
SND_SOC_DAPM_INPUT("MICR"),

SND_SOC_DAPM_ADC("ADCL", NULL, MAX9860_PWRMAN, MAX9860_ADCLEN_SHIFT, 0),
SND_SOC_DAPM_ADC("ADCR", NULL, MAX9860_PWRMAN, MAX9860_ADCREN_SHIFT, 0),

SND_SOC_DAPM_AIF_OUT("AIFOUTL", "Capture", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("AIFOUTR", "Capture", 1, SND_SOC_NOPM, 0, 0),

SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0),

SND_SOC_DAPM_DAC("DAC", NULL, MAX9860_PWRMAN, MAX9860_DACEN_SHIFT, 0),

SND_SOC_DAPM_OUTPUT("OUT"),

SND_SOC_DAPM_SUPPLY("Supply", SND_SOC_NOPM, 0, 0,
      NULL, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_REGULATOR_SUPPLY("AVDD", 0, 0),
SND_SOC_DAPM_REGULATOR_SUPPLY("DVDD", 0, 0),
SND_SOC_DAPM_CLOCK_SUPPLY("mclk"),
};

static const struct snd_soc_dapm_route max9860_dapm_routes[] = {
 { "ADCL", NULL, "MICL" },
 { "ADCR", NULL, "MICR" },
 { "AIFOUTL", NULL, "ADCL" },
 { "AIFOUTR", NULL, "ADCR" },

 { "DAC", NULL, "AIFINL" },
 { "DAC", NULL, "AIFINR" },
 { "OUT", NULL, "DAC" },

 { "Supply", NULL, "AVDD" },
 { "Supply", NULL, "DVDD" },
 { "Supply", NULL, "mclk" },

 { "DAC", NULL, "Supply" },
 { "ADCL", NULL, "Supply" },
 { "ADCR", NULL, "Supply" },
};

static int max9860_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 max9860_priv *max9860 = snd_soc_component_get_drvdata(component);
 u8 master;
 u8 ifc1a = 0;
 u8 ifc1b = 0;
 u8 sysclk = 0;
 unsigned long n;
 int ret;

 dev_dbg(component->dev, "hw_params %u Hz, %u channels\n",
  params_rate(params),
  params_channels(params));

 if (params_channels(params) == 2)
  ifc1b |= MAX9860_ST;

 switch (max9860->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
 case SND_SOC_DAIFMT_CBC_CFC:
  master = 0;
  break;
 case SND_SOC_DAIFMT_CBP_CFP:
  master = MAX9860_MASTER;
  break;
 default:
  return -EINVAL;
 }
 ifc1a |= master;

 if (master) {
  if (params_width(params) * params_channels(params) > 48)
   ifc1b |= MAX9860_BSEL_64X;
  else
   ifc1b |= MAX9860_BSEL_48X;
 }

 switch (max9860->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 case SND_SOC_DAIFMT_I2S:
  ifc1a |= MAX9860_DDLY;
  ifc1b |= MAX9860_ADLY;
  break;
 case SND_SOC_DAIFMT_LEFT_J:
  ifc1a |= MAX9860_WCI;
  break;
 case SND_SOC_DAIFMT_DSP_A:
  if (params_width(params) != 16) {
   dev_err(component->dev,
    "DSP_A works for 16 bits per sample only.\n");
   return -EINVAL;
  }
  ifc1a |= MAX9860_DDLY | MAX9860_WCI | MAX9860_HIZ | MAX9860_TDM;
  ifc1b |= MAX9860_ADLY;
  break;
 case SND_SOC_DAIFMT_DSP_B:
  if (params_width(params) != 16) {
   dev_err(component->dev,
    "DSP_B works for 16 bits per sample only.\n");
   return -EINVAL;
  }
  ifc1a |= MAX9860_WCI | MAX9860_HIZ | MAX9860_TDM;
  break;
 default:
  return -EINVAL;
 }

 switch (max9860->fmt & SND_SOC_DAIFMT_INV_MASK) {
 case SND_SOC_DAIFMT_NB_NF:
  break;
 case SND_SOC_DAIFMT_NB_IF:
  switch (max9860->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
  case SND_SOC_DAIFMT_DSP_A:
  case SND_SOC_DAIFMT_DSP_B:
   return -EINVAL;
  }
  ifc1a ^= MAX9860_WCI;
  break;
 case SND_SOC_DAIFMT_IB_IF:
  switch (max9860->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
  case SND_SOC_DAIFMT_DSP_A:
  case SND_SOC_DAIFMT_DSP_B:
   return -EINVAL;
  }
  ifc1a ^= MAX9860_WCI;
  fallthrough;
 case SND_SOC_DAIFMT_IB_NF:
  ifc1a ^= MAX9860_DBCI;
  ifc1b ^= MAX9860_ABCI;
  break;
 default:
  return -EINVAL;
 }

 dev_dbg(component->dev, "IFC1A  %02x\n", ifc1a);
 ret = regmap_write(max9860->regmap, MAX9860_IFC1A, ifc1a);
 if (ret) {
  dev_err(component->dev, "Failed to set IFC1A: %d\n", ret);
  return ret;
 }
 dev_dbg(component->dev, "IFC1B  %02x\n", ifc1b);
 ret = regmap_write(max9860->regmap, MAX9860_IFC1B, ifc1b);
 if (ret) {
  dev_err(component->dev, "Failed to set IFC1B: %d\n", ret);
  return ret;
 }

 /*
  * Check if Integer Clock Mode is possible, but avoid it in slave mode
  * since we then do not know if lrclk is derived from pclk and the
  * datasheet mentions that the frequencies have to match exactly in
  * order for this to work.
 */

 if (params_rate(params) == 8000 || params_rate(params) == 16000) {
  if (master) {
   switch (max9860->pclk_rate) {
   case 12000000:
    sysclk = MAX9860_FREQ_12MHZ;
    break;
   case 13000000:
    sysclk = MAX9860_FREQ_13MHZ;
    break;
   case 19200000:
    sysclk = MAX9860_FREQ_19_2MHZ;
    break;
   default:
    /*
     * Integer Clock Mode not possible. Leave
    *sysclk at zero and fall  to the
     * code below for PLL mode.
 */

    break;
   }

   if (sysclk && params_rate(params) == 16000)
    sysclk |= MAX9860_16KHZ;
  }
 }

 /*
  * Largest possible n:
  *    65536 * 96 * 48kHz / 10MHz -> 30199
  * Smallest possible n:
  *    65536 
 bits,   to apply any mask.
 */

 n = DIV_ROUND_CLOSEST_ULL(65536ULL * 96 * params_rate(params),
      max9860->pclk_rate);

 if (!sysclk) {
  /* PLL mode */
  if (params_rate(params) > 24000)
   sysclk |= MAX9860_16KHZ;

 if (!aster)
   n |= 1; /* trigger rapid pll lock mode */
 }

sysclk |->;
 (component-dev," %xn" sysclk)
 =regmap_writemax9860>egmap,
   MAX9860_SYSCLKsysclk;
 if#nclude linuxsoundwiresdw_type>
  dev_err(component->dev, #nclude <soundsoc.>
  return;
 }  rt711_sdca_priv {
 dev_dbg(component->dev, "N %lu\n", n);
 et=regmap_writemax9860-regmapjava.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36
AX9860_AUDIOCLKHIGH, >8)
 if (ret) {
  dev_err(component->dev, "Failed to set NHI: %d\n", ret)structmutexcalibrate_mutex /* for headset calibration */
  return ret;
 }
 ret = regmap_write(max9860->regmap,
  MAX9860_AUDIOCLKLOW n &0xff
  {
  bool,fu0f_mixer_l_mute java.lang.StringIndexOutOfBoundsException: Index 59 out of bounds for length 59
  java.lang.StringIndexOutOfBoundsException: Index 8 out of bounds for length 2
 }

 if !master){
  dev_dbg(component->dev, "Enable PLL\n");
  ret(max9860>,MAX9860_AUDIOCLKHIGH
   MAX9860_PLL MAX9860_PLL);
   (ret){
   dev_err(component->dev, "Failed to enable PLL: %d\n",
    ret);
  return ;
  }
 }

  0;
}

#define
{
 struct snd_soc_component *component = daidRT711_MIXER_IN1 022
 struct max9860_privdefineRT711_MIXER_IN2 0java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 32

switch fmt &SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK

 caseSND_SOC_DAIFMT_CBC_CFC

  return java.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 11

 :
  return -EINVAL;
 }
}

static const struct snd_soc_dai_ops max9860_dai_ops = # RT711_PARA_VERB_CTL  0a
 .w_params= ,
 .set_fmt = max9860_set_fmt,
};

static struct snd_soc_dai_driver max9860_daid   0
. ="h",
 .playback    
  #efineRT711_VREFOUT_CTL xb
  .channels_min = 1,
  .channels_max#    0
  .rates = define RT711_IRQ_FLAG_TABLE1x80
 . =8000,
  .rate_max = 48000,
  .#definejava.lang.StringIndexOutOfBoundsException: Range [8, 7) out of bounds for length 37
  |
   dRT711_FILTER_SRC_SEL  x
 },
 .capture = {
  .java.lang.StringIndexOutOfBoundsException: Range [21, 8) out of bounds for length 21
  . =1java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 20
  .channels_max # RT711_HP_IMS_RESULT_L  020
  .rates = #define RT711_HP_IMS_RESULT_R
  . =8000,
  .rate_max = 48000,
  .java.lang.StringIndexOutOfBoundsException: Range [0, 10) out of bounds for length 0
       |
java.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 21
 ,
java.lang.StringIndexOutOfBoundsException: Range [35, 25) out of bounds for length 25
 .#define 0
};

static int dRT711_PUSH_BTN_INT_CTL1 xjava.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 39
      enum snd_soc_bias_leveldefinejava.lang.StringIndexOutOfBoundsException: Range [32, 31) out of bounds for length 39
{
 structdefine  (x1< java.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 45
 int ret;

 switch (level) {
 case java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 0
 case SND_SOC_BIAS_PREPARE:
  #defineRT711_JD2_2PORT_200K_DECODE_HP< )

 case SND_SOC_BIAS_STANDBY:
  ret = regmap_update_bits(max9860->regmap# RT711_HP_JD_SEL_JD10 < )
      MAX9860_SHDN, MAX9860_SHDN);
  if (ret#  (0x1<10)
  SHDN:%\"
   ret)java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
    retjava.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 14
  }
  break;

 case java.lang.StringIndexOutOfBoundsException: Index 8 out of bounds for length 0
  ret = regmap_update_bits(max9860->regmap1RT711_COMBOJACK_AUTO_DET_TRS0x1 <10)
     , )
   (){
   dev_err(component->dev, "Failed to request SHDN: %d\n",
    ret#efine   (x0 <0
    ret;
  }
  break;
 }

 return 0;
}

static  struct snd_soc_component_driver = {
 .set_bias_level  = max9860_set_bias_level,
 .controls  = java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 0
 .num_controls  = #efine   (x1 <<java.lang.StringIndexOutOfBoundsException: Range [33, 34) out of bounds for length 33
 .java.lang.StringIndexOutOfBoundsException: Range [29, 14) out of bounds for length 39
java.lang.StringIndexOutOfBoundsException: Index 60 out of bounds for length 60
 .dapm_routes  = max9860_dapm_routesRT711_DIR_OUT_SFT  7
 .num_dapm_routes      0
 .use_pmdown_time = 1,
 .endianness  = 1,
};

static int max9860_suspend(struct
{
  max9860_priv*ax9860  dev_get_drvdata(ev;
 int ret;

 #efine FUNC_NUM_MIC_ARRAYx02
, MAX9860_PSCLK_OFF;
 if (et {
 dev_err(,"Failed to disableclock: %d\" )java.lang.StringIndexOutOfBoundsException: Range [53, 54) out of bounds for length 53
  return #define RT7110
 }

 regulator_disable(max9860->dvddio);

 return 0;
}

java.lang.StringIndexOutOfBoundsException: Range [32, 6) out of bounds for length 45
{
 struct max9860_priv *#define RT711_SDCA_ENT_CS11 0
 int ret;

 ret = regulator_enable(max9860->dvddio);
 if(ret){
  dev_err(dev, "Failed to enable DVDDIO#efineRT711_SDCA_ENT_LINE2 0x31
  return ret;
 }

 java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 0
 define java.lang.StringIndexOutOfBoundsException: Range [35, 33) out of bounds for length 38
 java.lang.StringIndexOutOfBoundsException: Range [8, 3) out of bounds for length 11
  dev_errdefine  0x11
  java.lang.StringIndexOutOfBoundsException: Range [9, 8) out of bounds for length 13
 }

#RT711_SDCA_CTL_DETECTED_MODEx02
   MAX9860_PSCLK,max9860-psclk;
 if (et {
 java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 24
  return ret;
 }

 return 0;
}

static const struct dev_pm_ops max9860_pm_ops = {define   0x0b
 RUNTIME_PM_OPS(max9860_suspend
};

java.lang.StringIndexOutOfBoundsException: Range [10, 6) out of bounds for length 48
{
 struct deviceRT711_JD_NULL,
 struct max9860_priv *max9860;
 int ret;
 struct clk *mclk;
 unsigned long mclk_rate;
 int i;
 int intr;

 max9860 = devm_kzallocdev sizeof(truct max9860_priv) );
 if (!max9860)
  return -ENOMEM;

 max9860}
  (S_ERRmax9860-dvddio)
obed,PTR_ERRm-dvddio)java.lang.StringIndexOutOfBoundsException: Index 53 out of bounds for length 53
         "Failed to java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0

 max9860->dvddio_nb#/* __RT711_SDCA_H__ */

 ret = devm_regulator_register_notifier(max9860->dvddio,
            &max9860->dvddio_nb);
 if (ret)
  dev_err(dev, "Failed to register DVDDIO notifier: %d\n", ret);

 ret = regulator_enable(max9860->dvddio);
 if (ret != 0) {
  dev_err(dev, "Failed to enable DVDDIO: %d\n", ret);
  return ret;
 }

 max9860->regmap = devm_regmap_init_i2c(i2c, &max9860_regmap);
 if (IS_ERR(max9860->regmap)) {
  ret = PTR_ERR(max9860->regmap);
  goto err_regulator;
 }

 dev_set_drvdata(dev, max9860);

 /*
  * mclk has to be in the 10MHz to 60MHz range.
  * psclk is used to scale mclk into pclk so that
  * pclk is in the 10MHz to 20MHz range.
 */

 mclk = clk_get(dev, "mclk");

 if (IS_ERR(mclk)) {
  ret = PTR_ERR(mclk);
  dev_err_probe(dev, ret, "Failed to get MCLK\n");
  goto err_regulator;
 }

 mclk_rate = clk_get_rate(mclk);
 clk_put(mclk);

 if (mclk_rate > 60000000 || mclk_rate < 10000000) {
  dev_err(dev, "Bad mclk %luHz (needs 10MHz - 60MHz)\n",
   mclk_rate);
  ret = -EINVAL;
  goto err_regulator;
 }
 if (mclk_rate >= 40000000)
  max9860->psclk = 3;
 else if (mclk_rate >= 20000000)
  max9860->psclk = 2;
 else
  max9860->psclk = 1;
 max9860->pclk_rate = mclk_rate >> (max9860->psclk - 1);
 max9860->psclk <<= MAX9860_PSCLK_SHIFT;
 dev_dbg(dev, "mclk %lu pclk %lu\n", mclk_rate, max9860->pclk_rate);

 regcache_cache_bypass(max9860->regmap, true);
 for (i = 0; i < max9860_regmap.num_reg_defaults; ++i) {
  ret = regmap_write(max9860->regmap,
       max9860_regmap.reg_defaults[i].reg,
       max9860_regmap.reg_defaults[i].def);
  if (ret) {
   dev_err(dev, "Failed to initialize register %u: %d\n",
    max9860_regmap.reg_defaults[i].reg, ret);
   goto err_regulator;
  }
 }
 regcache_cache_bypass(max9860->regmap, false);

 ret = regmap_read(max9860->regmap, MAX9860_INTRSTATUS, &intr);
 if (ret) {
  dev_err(dev, "Failed to clear INTRSTATUS: %d\n", ret);
  goto err_regulator;
 }

 pm_runtime_set_active(dev);
 pm_runtime_enable(dev);
 pm_runtime_idle(dev);

 ret = devm_snd_soc_register_component(dev, &max9860_component_driver,
           &max9860_dai, 1);
 if (ret) {
  dev_err(dev, "Failed to register CODEC: %d\n", ret);
  goto err_pm;
 }

 return 0;

err_pm:
 pm_runtime_disable(dev);
err_regulator:
 regulator_disable(max9860->dvddio);
 return ret;
}

static void max9860_remove(struct i2c_client *i2c)
{
 struct device *dev = &i2c->dev;
 struct max9860_priv *max9860 = dev_get_drvdata(dev);

 pm_runtime_disable(dev);
 regulator_disable(max9860->dvddio);
}

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

static const struct of_device_id max9860_of_match[] = {
 { .compatible = "maxim,max9860", },
 { }
};
MODULE_DEVICE_TABLE(of, max9860_of_match);

static struct i2c_driver max9860_i2c_driver = {
 .probe          = max9860_probe,
 .remove         = max9860_remove,
 .id_table       = max9860_i2c_id,
 .driver         = {
  .name           = "max9860",
  .of_match_table = max9860_of_match,
  .pm             = pm_ptr(&max9860_pm_ops),
 },
};

module_i2c_driver(max9860_i2c_driver);

MODULE_DESCRIPTION("ASoC MAX9860 Mono Audio Voice Codec driver");
MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
MODULE_LICENSE("GPL v2");

Messung V0.5 in Prozent
C=95 H=97 G=95

¤ Dauer der Verarbeitung: 0.143 Sekunden  (vorverarbeitet am  2026-10-14) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

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

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=234296
#Domains=75352