This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TLV320AIC3254-Q1: TLV320AIC3254-Q1 bringup issue

Part Number: TLV320AIC3254-Q1
Other Parts Discussed in Thread: TLV320AIC3254

Hi Teams,

We use TI TLV320AIC3254-Q1 on the Qualcomm SA525M platform

Driver seems to have brought up

Using TERTIARY MI2S

But when playing the sound, a log like this will appear

Please help us for this log check, Thank you so much.

[  480.977973][ T1486] aic3x_hw_params(): unable to setup PLL

[  480.984100][ T1486] tlv320aic3x 2-0018: ASoC: error at snd_soc_dai_hw_params on tlv320aic3x-hifi: -22

[  480.994214][ T1486]  MI2S-LPAIF-RX-TERTIARY: ASoC: soc_pcm_hw_params() failed (-22)

  • Hi Application team :   

       May I know is any update for the issues? 

    thank you 

    Roy

  • Hi Lee,

    TLV320aic3254-Q1 have a more suitable driver in kernel, what you using currently might not support this device, please replace below driver and try again:

    https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/sound/soc/codecs

    Thanks

    Kevin

  • Dear 

    The patch is for new kernel version

    We use kernel 5.15 of yocto system under QC sa525m platform

    this patch use i2c_get_match_data, but it be added after KERNEL 6.5

    https://elixir.bootlin.com/linux/v6.5/source/include/linux/i2c.h#L370

    ttps://elixir.bootlin.com/linux/v6.4/source/include/linux/i2c.h#L367

    I had change to use tlv320aic32x4 driver, 

    Does the clock-names and clocks of dtsi  need to be config or not.

    Because we use slave mode, i remove the clock-names and clocks, and relation code.

    So far, device can not probe pass.

    It failed at regmap_write(regmap, AIC32X4_RESET, 0x01);

    Do you have another comment?

    Thank you very much

  • Dear 

    I can probe pass with some error log by mark some error code.

    please check the error log

    Thank you very much

    0425_tlv320aic32x4_log.txt

  • Dear 

    Could you please provide the uart log of probe pass under linux platform?

    Thank you very much 

  • Hi Daniel,

    Actually, we have kernel 5.15 has same driver in its path, we can just utilize without modification

    https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/sound/soc/codecs?h=v5.15.156

    Pls compile it

    Thanks

    Kevin

  • Dear 

    Thank you for your information.

    One more question, Could you provide the reference dtci config?

    Does these two node be necessary?

     // clocks = <&clks 201>;
    // clock-names = "mclk";

    We use the BLCK not MLCK, does it mean i can mark this two config.

    It i mark it, the probe will be failed at following

    ret = aic32x4_parse_dt(aic32x4, np); of aic32x4_probe

    	if (pdata) {
    		dev_err(dev, "111\n");
    		aic32x4->power_cfg = pdata->power_cfg;
    		aic32x4->swapdacs = pdata->swapdacs;
    		aic32x4->micpga_routing = pdata->micpga_routing;
    		aic32x4->rstn_gpio = pdata->rstn_gpio;
    		aic32x4->mclk_name = "mclk";
    	} else if (np) {
    		dev_err(dev, "222\n");
    		ret = aic32x4_parse_dt(aic32x4, np);
    		if (ret) {
    			dev_err(dev, "Failed to parse DT node\n");
    			return ret;
    		}
    	} else {
    		dev_err(dev, "333\n");
    		aic32x4->power_cfg = 0;
    		aic32x4->swapdacs = false;
    		aic32x4->micpga_routing = 0;
    		aic32x4->rstn_gpio = -1;
    		aic32x4->mclk_name = "mclk";
    	}

    Do you have pass log of this TLV320AIC3254?

    Thank you very much

  • Dear 

    I had fixed the "regmap_write" issue.

    However, i had follwoing error log

    bootup stage:

    [ 25.573066][ T1419] tlv320aic32x4 6-0018: ASoC: Failed to add MI2S Mode: -16

    playback stage:

    [ 161.077215][ T1558] tlv320aic32x4 6-0018: Could not set clocks to support sample rate.
    [ 324.725601][ T1558] tlv320aic32x4 6-0018: Could not set clocks to support sample rate.

    Do you have any comment about this two error?

    You can check the full log too

    Thank you very much

    0426_tlv320aic32x4_log_3.txt

    I add more log and i found the fmt was 0, not 1(SND_SOC_DAIFMT_I2S)
    [ 76.306491][ T1565] tlv320aic32x4 2-0018: aic32x4->fmt(0x0)
    [ 76.313054][ T1565] tlv320aic32x4 2-0018: Could not set clocks to support sample rate.

    Is it correct?
    0427_tlv320aic32x4_regmap_pass_log3.txt

  • Hi Daniel,

    You do not need to remove this two lines, the driver is default to use mclk, is you remove it, the probe process will be failed.

    I recommend you to do some small change in tlv320aic32x4-clk.c, just shown at below:

    static int clk_aic32x4_pll_set_parent(struct clk_hw *hw, u8 index)
    {
            struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
            
            index = 1;/* set pll parent to be BLCK*/
            return regmap_update_bits(pll->regmap,
                                    AIC32X4_CLKMUX,
                                    AIC32X4_PLL_CLKIN_MASK,
                                    index << AIC32X4_PLL_CLKIN_SHIFT);
    }
    Kindly let me know if it works.
    Thanks
    Daniel
  • Dear Kevin

    is you remove it, the probe process will be failed.

    ==> Yes, because we did not use MLCK as default, therefore i mark this link.

    I add following change to fix the build error

    static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4,
    		struct device_node *np)
    {
    	struct aic32x4_setup_data *aic32x4_setup;
    //	int ret;
    
    	aic32x4_setup = devm_kzalloc(aic32x4->dev, sizeof(*aic32x4_setup),
    							GFP_KERNEL);
    	if (!aic32x4_setup)
    		return -ENOMEM;
    
    //	ret = of_property_match_string(np, "clock-names", "mclk");
    //	if (ret < 0)
    //		return -EINVAL;
    	aic32x4->mclk_name = "mclk";//of_clk_get_parent_name(np, ret);

    Sofar, i meet following two error

    bootup:

    [ 25.365491][ T1401] tlv320aic32x4 2-0018: ASoC: Failed to add MI2S Mode: -16

    playback

    [ 76.306491][ T1565] tlv320aic32x4 2-0018: aic32x4->fmt(0x0)
    [ 76.313054][ T1565] tlv320aic32x4 2-0018: Could not set clocks to support sample rate.


    Does the fmt cause this error?

    Thank you very much

  • If you comment these lines, the devm_clk_bulk_get() will be failed, so you can't remove it, what's your format for I2S?

  • Dear Kevin, 

    However, our device does not have real mclk connect to host.

    There is no config to add it.

    just add following ?

      clocks = <&clks 201>;
      clock-names = "mclk";

    Another thing, i did not failed at the devm_clk_bulk_get()

    callflow didnot return following failed

    	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
    	if (ret)
    		return ret;

    what's your format for I2S

    ==> do you mean PCM?

  • Dear Kevin

    Another question

    i found the error is "Could not set clocks to support sample rate."

    however, the fmt is 0 at log 0427_tlv320aic32x4_regmap_pass_log3.txt

    The snd_soc_dai_ops of aic32x4 are as following

    static const struct snd_soc_dai_ops aic32x4_ops = {

    .hw_params = aic32x4_hw_params,

    .mute_stream = aic32x4_mute,

    .set_fmt = aic32x4_set_dai_fmt,

    .set_sysclk = aic32x4_set_dai_sysclk,

    .no_capture_mute = 1,

    };

     

    But i did not saw any function about .set_fmt = aic32x4_set_dai_fmt,

    Do you have any comment about this point?

    Thank you very much

  • Dear Kevin

    Do you have any update about "Could not set clocks to support sample rate."?

    Thank you very much

  • Dear Kevin, 

    What does the aic32x4_setup_clocks() task?

    Why so may for loop in it?

    Tthank you very much

    	for (nadc = max_nadc; nadc > 0; --nadc) {
    		adc_clock_rate = nadc * madc * aosr * sample_rate;
    		dev_err(component->dev, "adc_clock_rate(%d x %d x %d)(%d)\n", ndac, mdac, dosr, adc_clock_rate);
    		for (dosr = max_dosr; dosr >= min_dosr;
    				dosr -= dosr_increment) {
    			min_mdac = DIV_ROUND_UP((32 * dac_resource_class), dosr);
    			max_ndac = AIC32X4_MAX_CODEC_CLKIN_FREQ /
    					(min_mdac * dosr * sample_rate);
    			for (mdac = min_mdac; mdac <= 128; ++mdac) {
    				for (ndac = max_ndac; ndac > 0; --ndac) {
    					dac_clock_rate = ndac * mdac * dosr *
    							sample_rate;
    					if (dac_clock_rate == adc_clock_rate) {
    						dev_err(component->dev, "                                  dac_clock_rate(%d x %d x %d)(%d)\n", ndac, mdac, dosr, dac_clock_rate);
    						if (clk_round_rate(clocks[0].clk, dac_clock_rate) == 0)
    							continue;
    

  • Dear Kevin

    I update log for more information 

    0501_log_4.txt

    0385.tlv320aic32x4.c
    // SPDX-License-Identifier: GPL-2.0-or-later
    /*
     * linux/sound/soc/codecs/tlv320aic32x4.c
     *
     * Copyright 2011 Vista Silicon S.L.
     *
     * Author: Javier Martin <javier.martin@vista-silicon.com>
     *
     * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
     */
    
    #include <linux/module.h>
    #include <linux/moduleparam.h>
    #include <linux/init.h>
    #include <linux/delay.h>
    #include <linux/pm.h>
    #include <linux/gpio.h>
    #include <linux/of_gpio.h>
    #include <linux/cdev.h>
    #include <linux/slab.h>
    #include <linux/clk.h>
    #include <linux/of_clk.h>
    #include <linux/regulator/consumer.h>
    
    #include <sound/tlv320aic32x4.h>
    #include <sound/core.h>
    #include <sound/pcm.h>
    #include <sound/pcm_params.h>
    #include <sound/soc.h>
    #include <sound/soc-dapm.h>
    #include <sound/initval.h>
    #include <sound/tlv.h>
    
    #include "tlv320aic32x4.h"
    
    struct aic32x4_priv {
    	struct regmap *regmap;
    	u32 power_cfg;
    	u32 micpga_routing;
    	bool swapdacs;
    	int rstn_gpio;
    	const char *mclk_name;
    
    	struct regulator *supply_ldo;
    	struct regulator *supply_iov;
    	struct regulator *supply_dv;
    	struct regulator *supply_av;
    
    	struct aic32x4_setup_data *setup;
    	struct device *dev;
    	enum aic32x4_type type;
    
    	unsigned int fmt;
    };
    
    static int aic32x4_reset_adc(struct snd_soc_dapm_widget *w,
    			     struct snd_kcontrol *kcontrol, int event)
    {
    	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
    	u32 adc_reg;
    
    	/*
    	 * Workaround: the datasheet does not mention a required programming
    	 * sequence but experiments show the ADC needs to be reset after each
    	 * capture to avoid audible artifacts.
    	 */
    	switch (event) {
    	case SND_SOC_DAPM_POST_PMD:
    		adc_reg = snd_soc_component_read(component, AIC32X4_ADCSETUP);
    		snd_soc_component_write(component, AIC32X4_ADCSETUP, adc_reg |
    					AIC32X4_LADC_EN | AIC32X4_RADC_EN);
    		snd_soc_component_write(component, AIC32X4_ADCSETUP, adc_reg);
    		break;
    	}
    	return 0;
    };
    
    static int mic_bias_event(struct snd_soc_dapm_widget *w,
    	struct snd_kcontrol *kcontrol, int event)
    {
    	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
    
    	switch (event) {
    	case SND_SOC_DAPM_POST_PMU:
    		/* Change Mic Bias Registor */
    		snd_soc_component_update_bits(component, AIC32X4_MICBIAS,
    				AIC32x4_MICBIAS_MASK,
    				AIC32X4_MICBIAS_LDOIN |
    				AIC32X4_MICBIAS_2075V);
    		printk(KERN_DEBUG "%s: Mic Bias will be turned ON\n", __func__);
    		break;
    	case SND_SOC_DAPM_PRE_PMD:
    		snd_soc_component_update_bits(component, AIC32X4_MICBIAS,
    				AIC32x4_MICBIAS_MASK, 0);
    		printk(KERN_DEBUG "%s: Mic Bias will be turned OFF\n",
    				__func__);
    		break;
    	}
    
    	return 0;
    }
    
    
    static int aic32x4_get_mfp1_gpio(struct snd_kcontrol *kcontrol,
    	struct snd_ctl_elem_value *ucontrol)
    {
    	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
    	u8 val;
    
    	val = snd_soc_component_read(component, AIC32X4_DINCTL);
    
    	ucontrol->value.integer.value[0] = (val & 0x01);
    
    	return 0;
    };
    
    static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol,
    	struct snd_ctl_elem_value *ucontrol)
    {
    	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
    	u8 val;
    	u8 gpio_check;
    
    	val = snd_soc_component_read(component, AIC32X4_DOUTCTL);
    	gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED);
    	if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) {
    		printk(KERN_ERR "%s: MFP2 is not configure as a GPIO output\n",
    			__func__);
    		return -EINVAL;
    	}
    
    	if (ucontrol->value.integer.value[0] == (val & AIC32X4_MFP2_GPIO_OUT_HIGH))
    		return 0;
    
    	if (ucontrol->value.integer.value[0])
    		val |= ucontrol->value.integer.value[0];
    	else
    		val &= ~AIC32X4_MFP2_GPIO_OUT_HIGH;
    
    	snd_soc_component_write(component, AIC32X4_DOUTCTL, val);
    
    	return 0;
    };
    
    static int aic32x4_get_mfp3_gpio(struct snd_kcontrol *kcontrol,
    	struct snd_ctl_elem_value *ucontrol)
    {
    	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
    	u8 val;
    
    	val = snd_soc_component_read(component, AIC32X4_SCLKCTL);
    
    	ucontrol->value.integer.value[0] = (val & 0x01);
    
    	return 0;
    };
    
    static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol,
    	struct snd_ctl_elem_value *ucontrol)
    {
    	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
    	u8 val;
    	u8 gpio_check;
    
    	val = snd_soc_component_read(component, AIC32X4_MISOCTL);
    	gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED);
    	if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) {
    		printk(KERN_ERR "%s: MFP4 is not configure as a GPIO output\n",
    			__func__);
    		return -EINVAL;
    	}
    
    	if (ucontrol->value.integer.value[0] == (val & AIC32X4_MFP5_GPIO_OUT_HIGH))
    		return 0;
    
    	if (ucontrol->value.integer.value[0])
    		val |= ucontrol->value.integer.value[0];
    	else
    		val &= ~AIC32X4_MFP5_GPIO_OUT_HIGH;
    
    	snd_soc_component_write(component, AIC32X4_MISOCTL, val);
    
    	return 0;
    };
    
    static int aic32x4_get_mfp5_gpio(struct snd_kcontrol *kcontrol,
    	struct snd_ctl_elem_value *ucontrol)
    {
    	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
    	u8 val;
    
    	val = snd_soc_component_read(component, AIC32X4_GPIOCTL);
    	ucontrol->value.integer.value[0] = ((val & 0x2) >> 1);
    
    	return 0;
    };
    
    static int aic32x4_set_mfp5_gpio(struct snd_kcontrol *kcontrol,
    	struct snd_ctl_elem_value *ucontrol)
    {
    	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
    	u8 val;
    	u8 gpio_check;
    
    	val = snd_soc_component_read(component, AIC32X4_GPIOCTL);
    	gpio_check = (val & AIC32X4_MFP5_GPIO_OUTPUT);
    	if (gpio_check != AIC32X4_MFP5_GPIO_OUTPUT) {
    		printk(KERN_ERR "%s: MFP5 is not configure as a GPIO output\n",
    			__func__);
    		return -EINVAL;
    	}
    
    	if (ucontrol->value.integer.value[0] == (val & 0x1))
    		return 0;
    
    	if (ucontrol->value.integer.value[0])
    		val |= ucontrol->value.integer.value[0];
    	else
    		val &= 0xfe;
    
    	snd_soc_component_write(component, AIC32X4_GPIOCTL, val);
    
    	return 0;
    };
    
    static const struct snd_kcontrol_new aic32x4_mfp1[] = {
    	SOC_SINGLE_BOOL_EXT("MFP1 GPIO", 0, aic32x4_get_mfp1_gpio, NULL),
    };
    
    static const struct snd_kcontrol_new aic32x4_mfp2[] = {
    	SOC_SINGLE_BOOL_EXT("MFP2 GPIO", 0, NULL, aic32x4_set_mfp2_gpio),
    };
    
    static const struct snd_kcontrol_new aic32x4_mfp3[] = {
    	SOC_SINGLE_BOOL_EXT("MFP3 GPIO", 0, aic32x4_get_mfp3_gpio, NULL),
    };
    
    static const struct snd_kcontrol_new aic32x4_mfp4[] = {
    	SOC_SINGLE_BOOL_EXT("MFP4 GPIO", 0, NULL, aic32x4_set_mfp4_gpio),
    };
    
    static const struct snd_kcontrol_new aic32x4_mfp5[] = {
    	SOC_SINGLE_BOOL_EXT("MFP5 GPIO", 0, aic32x4_get_mfp5_gpio,
    		aic32x4_set_mfp5_gpio),
    };
    
    /* 0dB min, 0.5dB steps */
    static DECLARE_TLV_DB_SCALE(tlv_step_0_5, 0, 50, 0);
    /* -63.5dB min, 0.5dB steps */
    static DECLARE_TLV_DB_SCALE(tlv_pcm, -6350, 50, 0);
    /* -6dB min, 1dB steps */
    static DECLARE_TLV_DB_SCALE(tlv_driver_gain, -600, 100, 0);
    /* -12dB min, 0.5dB steps */
    static DECLARE_TLV_DB_SCALE(tlv_adc_vol, -1200, 50, 0);
    /* -6dB min, 1dB steps */
    static DECLARE_TLV_DB_SCALE(tlv_tas_driver_gain, -5850, 50, 0);
    static DECLARE_TLV_DB_SCALE(tlv_amp_vol, 0, 600, 1);
    
    static const char * const lo_cm_text[] = {
    	"Full Chip", "1.65V",
    };
    
    static SOC_ENUM_SINGLE_DECL(lo_cm_enum, AIC32X4_CMMODE, 3, lo_cm_text);
    
    static const char * const ptm_text[] = {
    	"P3", "P2", "P1",
    };
    
    static SOC_ENUM_SINGLE_DECL(l_ptm_enum, AIC32X4_LPLAYBACK, 2, ptm_text);
    static SOC_ENUM_SINGLE_DECL(r_ptm_enum, AIC32X4_RPLAYBACK, 2, ptm_text);
    
    static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
    	SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL,
    			AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm),
    	SOC_ENUM("DAC Left Playback PowerTune Switch", l_ptm_enum),
    	SOC_ENUM("DAC Right Playback PowerTune Switch", r_ptm_enum),
    	SOC_DOUBLE_R_S_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN,
    			AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0,
    			tlv_driver_gain),
    	SOC_DOUBLE_R_S_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN,
    			AIC32X4_LORGAIN, 0, -0x6, 0x1d, 5, 0,
    			tlv_driver_gain),
    	SOC_DOUBLE_R("HP DAC Playback Switch", AIC32X4_HPLGAIN,
    			AIC32X4_HPRGAIN, 6, 0x01, 1),
    	SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN,
    			AIC32X4_LORGAIN, 6, 0x01, 1),
    	SOC_ENUM("LO Playback Common Mode Switch", lo_cm_enum),
    	SOC_DOUBLE_R("Mic PGA Switch", AIC32X4_LMICPGAVOL,
    			AIC32X4_RMICPGAVOL, 7, 0x01, 1),
    
    	SOC_SINGLE("ADCFGA Left Mute Switch", AIC32X4_ADCFGA, 7, 1, 0),
    	SOC_SINGLE("ADCFGA Right Mute Switch", AIC32X4_ADCFGA, 3, 1, 0),
    
    	SOC_DOUBLE_R_S_TLV("ADC Level Volume", AIC32X4_LADCVOL,
    			AIC32X4_RADCVOL, 0, -0x18, 0x28, 6, 0, tlv_adc_vol),
    	SOC_DOUBLE_R_TLV("PGA Level Volume", AIC32X4_LMICPGAVOL,
    			AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5),
    
    	SOC_SINGLE("Auto-mute Switch", AIC32X4_DACMUTE, 4, 7, 0),
    
    	SOC_SINGLE("AGC Left Switch", AIC32X4_LAGC1, 7, 1, 0),
    	SOC_SINGLE("AGC Right Switch", AIC32X4_RAGC1, 7, 1, 0),
    	SOC_DOUBLE_R("AGC Target Level", AIC32X4_LAGC1, AIC32X4_RAGC1,
    			4, 0x07, 0),
    	SOC_DOUBLE_R("AGC Gain Hysteresis", AIC32X4_LAGC1, AIC32X4_RAGC1,
    			0, 0x03, 0),
    	SOC_DOUBLE_R("AGC Hysteresis", AIC32X4_LAGC2, AIC32X4_RAGC2,
    			6, 0x03, 0),
    	SOC_DOUBLE_R("AGC Noise Threshold", AIC32X4_LAGC2, AIC32X4_RAGC2,
    			1, 0x1F, 0),
    	SOC_DOUBLE_R("AGC Max PGA", AIC32X4_LAGC3, AIC32X4_RAGC3,
    			0, 0x7F, 0),
    	SOC_DOUBLE_R("AGC Attack Time", AIC32X4_LAGC4, AIC32X4_RAGC4,
    			3, 0x1F, 0),
    	SOC_DOUBLE_R("AGC Decay Time", AIC32X4_LAGC5, AIC32X4_RAGC5,
    			3, 0x1F, 0),
    	SOC_DOUBLE_R("AGC Noise Debounce", AIC32X4_LAGC6, AIC32X4_RAGC6,
    			0, 0x1F, 0),
    	SOC_DOUBLE_R("AGC Signal Debounce", AIC32X4_LAGC7, AIC32X4_RAGC7,
    			0, 0x0F, 0),
    };
    
    static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
    	SOC_DAPM_SINGLE("L_DAC Switch", AIC32X4_HPLROUTE, 3, 1, 0),
    	SOC_DAPM_SINGLE("IN1_L Switch", AIC32X4_HPLROUTE, 2, 1, 0),
    };
    
    static const struct snd_kcontrol_new hpr_output_mixer_controls[] = {
    	SOC_DAPM_SINGLE("R_DAC Switch", AIC32X4_HPRROUTE, 3, 1, 0),
    	SOC_DAPM_SINGLE("IN1_R Switch", AIC32X4_HPRROUTE, 2, 1, 0),
    };
    
    static const struct snd_kcontrol_new lol_output_mixer_controls[] = {
    	SOC_DAPM_SINGLE("L_DAC Switch", AIC32X4_LOLROUTE, 3, 1, 0),
    };
    
    static const struct snd_kcontrol_new lor_output_mixer_controls[] = {
    	SOC_DAPM_SINGLE("R_DAC Switch", AIC32X4_LORROUTE, 3, 1, 0),
    };
    
    static const char * const resistor_text[] = {
    	"Off", "10 kOhm", "20 kOhm", "40 kOhm",
    };
    
    /* Left mixer pins */
    static SOC_ENUM_SINGLE_DECL(in1l_lpga_p_enum, AIC32X4_LMICPGAPIN, 6, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in2l_lpga_p_enum, AIC32X4_LMICPGAPIN, 4, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in3l_lpga_p_enum, AIC32X4_LMICPGAPIN, 2, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in1r_lpga_p_enum, AIC32X4_LMICPGAPIN, 0, resistor_text);
    
    static SOC_ENUM_SINGLE_DECL(cml_lpga_n_enum, AIC32X4_LMICPGANIN, 6, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in2r_lpga_n_enum, AIC32X4_LMICPGANIN, 4, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in3r_lpga_n_enum, AIC32X4_LMICPGANIN, 2, resistor_text);
    
    static const struct snd_kcontrol_new in1l_to_lmixer_controls[] = {
    	SOC_DAPM_ENUM("IN1_L L+ Switch", in1l_lpga_p_enum),
    };
    static const struct snd_kcontrol_new in2l_to_lmixer_controls[] = {
    	SOC_DAPM_ENUM("IN2_L L+ Switch", in2l_lpga_p_enum),
    };
    static const struct snd_kcontrol_new in3l_to_lmixer_controls[] = {
    	SOC_DAPM_ENUM("IN3_L L+ Switch", in3l_lpga_p_enum),
    };
    static const struct snd_kcontrol_new in1r_to_lmixer_controls[] = {
    	SOC_DAPM_ENUM("IN1_R L+ Switch", in1r_lpga_p_enum),
    };
    static const struct snd_kcontrol_new cml_to_lmixer_controls[] = {
    	SOC_DAPM_ENUM("CM_L L- Switch", cml_lpga_n_enum),
    };
    static const struct snd_kcontrol_new in2r_to_lmixer_controls[] = {
    	SOC_DAPM_ENUM("IN2_R L- Switch", in2r_lpga_n_enum),
    };
    static const struct snd_kcontrol_new in3r_to_lmixer_controls[] = {
    	SOC_DAPM_ENUM("IN3_R L- Switch", in3r_lpga_n_enum),
    };
    
    /*	Right mixer pins */
    static SOC_ENUM_SINGLE_DECL(in1r_rpga_p_enum, AIC32X4_RMICPGAPIN, 6, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in2r_rpga_p_enum, AIC32X4_RMICPGAPIN, 4, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in3r_rpga_p_enum, AIC32X4_RMICPGAPIN, 2, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in2l_rpga_p_enum, AIC32X4_RMICPGAPIN, 0, resistor_text);
    static SOC_ENUM_SINGLE_DECL(cmr_rpga_n_enum, AIC32X4_RMICPGANIN, 6, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in1l_rpga_n_enum, AIC32X4_RMICPGANIN, 4, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in3l_rpga_n_enum, AIC32X4_RMICPGANIN, 2, resistor_text);
    
    static const struct snd_kcontrol_new in1r_to_rmixer_controls[] = {
    	SOC_DAPM_ENUM("IN1_R R+ Switch", in1r_rpga_p_enum),
    };
    static const struct snd_kcontrol_new in2r_to_rmixer_controls[] = {
    	SOC_DAPM_ENUM("IN2_R R+ Switch", in2r_rpga_p_enum),
    };
    static const struct snd_kcontrol_new in3r_to_rmixer_controls[] = {
    	SOC_DAPM_ENUM("IN3_R R+ Switch", in3r_rpga_p_enum),
    };
    static const struct snd_kcontrol_new in2l_to_rmixer_controls[] = {
    	SOC_DAPM_ENUM("IN2_L R+ Switch", in2l_rpga_p_enum),
    };
    static const struct snd_kcontrol_new cmr_to_rmixer_controls[] = {
    	SOC_DAPM_ENUM("CM_R R- Switch", cmr_rpga_n_enum),
    };
    static const struct snd_kcontrol_new in1l_to_rmixer_controls[] = {
    	SOC_DAPM_ENUM("IN1_L R- Switch", in1l_rpga_n_enum),
    };
    static const struct snd_kcontrol_new in3l_to_rmixer_controls[] = {
    	SOC_DAPM_ENUM("IN3_L R- Switch", in3l_rpga_n_enum),
    };
    
    static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = {
    	SND_SOC_DAPM_DAC("Left DAC", "Left Playback", AIC32X4_DACSETUP, 7, 0),
    	SND_SOC_DAPM_MIXER("HPL Output Mixer", SND_SOC_NOPM, 0, 0,
    			   &hpl_output_mixer_controls[0],
    			   ARRAY_SIZE(hpl_output_mixer_controls)),
    	SND_SOC_DAPM_PGA("HPL Power", AIC32X4_OUTPWRCTL, 5, 0, NULL, 0),
    
    	SND_SOC_DAPM_MIXER("LOL Output Mixer", SND_SOC_NOPM, 0, 0,
    			   &lol_output_mixer_controls[0],
    			   ARRAY_SIZE(lol_output_mixer_controls)),
    	SND_SOC_DAPM_PGA("LOL Power", AIC32X4_OUTPWRCTL, 3, 0, NULL, 0),
    
    	SND_SOC_DAPM_DAC("Right DAC", "Right Playback", AIC32X4_DACSETUP, 6, 0),
    	SND_SOC_DAPM_MIXER("HPR Output Mixer", SND_SOC_NOPM, 0, 0,
    			   &hpr_output_mixer_controls[0],
    			   ARRAY_SIZE(hpr_output_mixer_controls)),
    	SND_SOC_DAPM_PGA("HPR Power", AIC32X4_OUTPWRCTL, 4, 0, NULL, 0),
    	SND_SOC_DAPM_MIXER("LOR Output Mixer", SND_SOC_NOPM, 0, 0,
    			   &lor_output_mixer_controls[0],
    			   ARRAY_SIZE(lor_output_mixer_controls)),
    	SND_SOC_DAPM_PGA("LOR Power", AIC32X4_OUTPWRCTL, 2, 0, NULL, 0),
    
    	SND_SOC_DAPM_ADC("Right ADC", "Right Capture", AIC32X4_ADCSETUP, 6, 0),
    	SND_SOC_DAPM_MUX("IN1_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in1r_to_rmixer_controls),
    	SND_SOC_DAPM_MUX("IN2_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in2r_to_rmixer_controls),
    	SND_SOC_DAPM_MUX("IN3_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in3r_to_rmixer_controls),
    	SND_SOC_DAPM_MUX("IN2_L to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in2l_to_rmixer_controls),
    	SND_SOC_DAPM_MUX("CM_R to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
    			cmr_to_rmixer_controls),
    	SND_SOC_DAPM_MUX("IN1_L to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
    			in1l_to_rmixer_controls),
    	SND_SOC_DAPM_MUX("IN3_L to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
    			in3l_to_rmixer_controls),
    
    	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", AIC32X4_ADCSETUP, 7, 0),
    	SND_SOC_DAPM_MUX("IN1_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in1l_to_lmixer_controls),
    	SND_SOC_DAPM_MUX("IN2_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in2l_to_lmixer_controls),
    	SND_SOC_DAPM_MUX("IN3_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in3l_to_lmixer_controls),
    	SND_SOC_DAPM_MUX("IN1_R to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in1r_to_lmixer_controls),
    	SND_SOC_DAPM_MUX("CM_L to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
    			cml_to_lmixer_controls),
    	SND_SOC_DAPM_MUX("IN2_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
    			in2r_to_lmixer_controls),
    	SND_SOC_DAPM_MUX("IN3_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
    			in3r_to_lmixer_controls),
    
    	SND_SOC_DAPM_SUPPLY("Mic Bias", AIC32X4_MICBIAS, 6, 0, mic_bias_event,
    			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
    
    	SND_SOC_DAPM_POST("ADC Reset", aic32x4_reset_adc),
    
    	SND_SOC_DAPM_OUTPUT("HPL"),
    	SND_SOC_DAPM_OUTPUT("HPR"),
    	SND_SOC_DAPM_OUTPUT("LOL"),
    	SND_SOC_DAPM_OUTPUT("LOR"),
    	SND_SOC_DAPM_INPUT("IN1_L"),
    	SND_SOC_DAPM_INPUT("IN1_R"),
    	SND_SOC_DAPM_INPUT("IN2_L"),
    	SND_SOC_DAPM_INPUT("IN2_R"),
    	SND_SOC_DAPM_INPUT("IN3_L"),
    	SND_SOC_DAPM_INPUT("IN3_R"),
    	SND_SOC_DAPM_INPUT("CM_L"),
    	SND_SOC_DAPM_INPUT("CM_R"),
    };
    
    static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = {
    	/* Left Output */
    	{"HPL Output Mixer", "L_DAC Switch", "Left DAC"},
    	{"HPL Output Mixer", "IN1_L Switch", "IN1_L"},
    
    	{"HPL Power", NULL, "HPL Output Mixer"},
    	{"HPL", NULL, "HPL Power"},
    
    	{"LOL Output Mixer", "L_DAC Switch", "Left DAC"},
    
    	{"LOL Power", NULL, "LOL Output Mixer"},
    	{"LOL", NULL, "LOL Power"},
    
    	/* Right Output */
    	{"HPR Output Mixer", "R_DAC Switch", "Right DAC"},
    	{"HPR Output Mixer", "IN1_R Switch", "IN1_R"},
    
    	{"HPR Power", NULL, "HPR Output Mixer"},
    	{"HPR", NULL, "HPR Power"},
    
    	{"LOR Output Mixer", "R_DAC Switch", "Right DAC"},
    
    	{"LOR Power", NULL, "LOR Output Mixer"},
    	{"LOR", NULL, "LOR Power"},
    
    	/* Right Input */
    	{"Right ADC", NULL, "IN1_R to Right Mixer Positive Resistor"},
    	{"IN1_R to Right Mixer Positive Resistor", "10 kOhm", "IN1_R"},
    	{"IN1_R to Right Mixer Positive Resistor", "20 kOhm", "IN1_R"},
    	{"IN1_R to Right Mixer Positive Resistor", "40 kOhm", "IN1_R"},
    
    	{"Right ADC", NULL, "IN2_R to Right Mixer Positive Resistor"},
    	{"IN2_R to Right Mixer Positive Resistor", "10 kOhm", "IN2_R"},
    	{"IN2_R to Right Mixer Positive Resistor", "20 kOhm", "IN2_R"},
    	{"IN2_R to Right Mixer Positive Resistor", "40 kOhm", "IN2_R"},
    
    	{"Right ADC", NULL, "IN3_R to Right Mixer Positive Resistor"},
    	{"IN3_R to Right Mixer Positive Resistor", "10 kOhm", "IN3_R"},
    	{"IN3_R to Right Mixer Positive Resistor", "20 kOhm", "IN3_R"},
    	{"IN3_R to Right Mixer Positive Resistor", "40 kOhm", "IN3_R"},
    
    	{"Right ADC", NULL, "IN2_L to Right Mixer Positive Resistor"},
    	{"IN2_L to Right Mixer Positive Resistor", "10 kOhm", "IN2_L"},
    	{"IN2_L to Right Mixer Positive Resistor", "20 kOhm", "IN2_L"},
    	{"IN2_L to Right Mixer Positive Resistor", "40 kOhm", "IN2_L"},
    
    	{"Right ADC", NULL, "CM_R to Right Mixer Negative Resistor"},
    	{"CM_R to Right Mixer Negative Resistor", "10 kOhm", "CM_R"},
    	{"CM_R to Right Mixer Negative Resistor", "20 kOhm", "CM_R"},
    	{"CM_R to Right Mixer Negative Resistor", "40 kOhm", "CM_R"},
    
    	{"Right ADC", NULL, "IN1_L to Right Mixer Negative Resistor"},
    	{"IN1_L to Right Mixer Negative Resistor", "10 kOhm", "IN1_L"},
    	{"IN1_L to Right Mixer Negative Resistor", "20 kOhm", "IN1_L"},
    	{"IN1_L to Right Mixer Negative Resistor", "40 kOhm", "IN1_L"},
    
    	{"Right ADC", NULL, "IN3_L to Right Mixer Negative Resistor"},
    	{"IN3_L to Right Mixer Negative Resistor", "10 kOhm", "IN3_L"},
    	{"IN3_L to Right Mixer Negative Resistor", "20 kOhm", "IN3_L"},
    	{"IN3_L to Right Mixer Negative Resistor", "40 kOhm", "IN3_L"},
    
    	/* Left Input */
    	{"Left ADC", NULL, "IN1_L to Left Mixer Positive Resistor"},
    	{"IN1_L to Left Mixer Positive Resistor", "10 kOhm", "IN1_L"},
    	{"IN1_L to Left Mixer Positive Resistor", "20 kOhm", "IN1_L"},
    	{"IN1_L to Left Mixer Positive Resistor", "40 kOhm", "IN1_L"},
    
    	{"Left ADC", NULL, "IN2_L to Left Mixer Positive Resistor"},
    	{"IN2_L to Left Mixer Positive Resistor", "10 kOhm", "IN2_L"},
    	{"IN2_L to Left Mixer Positive Resistor", "20 kOhm", "IN2_L"},
    	{"IN2_L to Left Mixer Positive Resistor", "40 kOhm", "IN2_L"},
    
    	{"Left ADC", NULL, "IN3_L to Left Mixer Positive Resistor"},
    	{"IN3_L to Left Mixer Positive Resistor", "10 kOhm", "IN3_L"},
    	{"IN3_L to Left Mixer Positive Resistor", "20 kOhm", "IN3_L"},
    	{"IN3_L to Left Mixer Positive Resistor", "40 kOhm", "IN3_L"},
    
    	{"Left ADC", NULL, "IN1_R to Left Mixer Positive Resistor"},
    	{"IN1_R to Left Mixer Positive Resistor", "10 kOhm", "IN1_R"},
    	{"IN1_R to Left Mixer Positive Resistor", "20 kOhm", "IN1_R"},
    	{"IN1_R to Left Mixer Positive Resistor", "40 kOhm", "IN1_R"},
    
    	{"Left ADC", NULL, "CM_L to Left Mixer Negative Resistor"},
    	{"CM_L to Left Mixer Negative Resistor", "10 kOhm", "CM_L"},
    	{"CM_L to Left Mixer Negative Resistor", "20 kOhm", "CM_L"},
    	{"CM_L to Left Mixer Negative Resistor", "40 kOhm", "CM_L"},
    
    	{"Left ADC", NULL, "IN2_R to Left Mixer Negative Resistor"},
    	{"IN2_R to Left Mixer Negative Resistor", "10 kOhm", "IN2_R"},
    	{"IN2_R to Left Mixer Negative Resistor", "20 kOhm", "IN2_R"},
    	{"IN2_R to Left Mixer Negative Resistor", "40 kOhm", "IN2_R"},
    
    	{"Left ADC", NULL, "IN3_R to Left Mixer Negative Resistor"},
    	{"IN3_R to Left Mixer Negative Resistor", "10 kOhm", "IN3_R"},
    	{"IN3_R to Left Mixer Negative Resistor", "20 kOhm", "IN3_R"},
    	{"IN3_R to Left Mixer Negative Resistor", "40 kOhm", "IN3_R"},
    };
    
    static const struct regmap_range_cfg aic32x4_regmap_pages[] = {
    	{
    		.selector_reg = 0,
    		.selector_mask	= 0xff,
    		.window_start = 0,
    		.window_len = 128,
    		.range_min = 0,
    		.range_max = AIC32X4_REFPOWERUP,
    	},
    };
    
    const struct regmap_config aic32x4_regmap_config = {
    	.max_register = AIC32X4_REFPOWERUP,
    	.ranges = aic32x4_regmap_pages,
    	.num_ranges = ARRAY_SIZE(aic32x4_regmap_pages),
    };
    EXPORT_SYMBOL(aic32x4_regmap_config);
    
    static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
    				  int clk_id, unsigned int freq, int dir)
    {
    	struct snd_soc_component *component = codec_dai->component;
    	struct clk *mclk;
    	struct clk *pll;
    	dev_err(component->dev, "%s:clk_id(%d), freq(%d)\n", __FUNCTION__, clk_id, freq);
    
    	pll = devm_clk_get(component->dev, "pll");
    	if (IS_ERR(pll))
    		return PTR_ERR(pll);
    
    	mclk = clk_get_parent(pll);
    
    	return clk_set_rate(mclk, freq);
    }
    
    static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
    {
    	struct snd_soc_component *component = codec_dai->component;
    	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
    	u8 iface_reg_1 = 0;
    	u8 iface_reg_2 = 0;
    	u8 iface_reg_3 = 0;
    	dev_err(component->dev, "%s: fmt(0x%x)\n", __FUNCTION__, fmt);
    
    	/* set master/slave audio interface */
    	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
    	case SND_SOC_DAIFMT_CBM_CFM:
    		iface_reg_1 |= AIC32X4_BCLKMASTER | AIC32X4_WCLKMASTER;
    		break;
    	case SND_SOC_DAIFMT_CBS_CFS:
    		break;
    	default:
    		printk(KERN_ERR "aic32x4: invalid DAI master/slave interface\n");
    		return -EINVAL;
    	}
    
    	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
    	case SND_SOC_DAIFMT_I2S:
    		break;
    	case SND_SOC_DAIFMT_DSP_A:
    		iface_reg_1 |= (AIC32X4_DSP_MODE <<
    				AIC32X4_IFACE1_DATATYPE_SHIFT);
    		iface_reg_3 |= AIC32X4_BCLKINV_MASK; /* invert bit clock */
    		iface_reg_2 = 0x01; /* add offset 1 */
    		break;
    	case SND_SOC_DAIFMT_DSP_B:
    		iface_reg_1 |= (AIC32X4_DSP_MODE <<
    				AIC32X4_IFACE1_DATATYPE_SHIFT);
    		iface_reg_3 |= AIC32X4_BCLKINV_MASK; /* invert bit clock */
    		break;
    	case SND_SOC_DAIFMT_RIGHT_J:
    		iface_reg_1 |= (AIC32X4_RIGHT_JUSTIFIED_MODE <<
    				AIC32X4_IFACE1_DATATYPE_SHIFT);
    		break;
    	case SND_SOC_DAIFMT_LEFT_J:
    		iface_reg_1 |= (AIC32X4_LEFT_JUSTIFIED_MODE <<
    				AIC32X4_IFACE1_DATATYPE_SHIFT);
    		break;
    	default:
    		printk(KERN_ERR "aic32x4: invalid DAI interface format\n");
    		return -EINVAL;
    	}
    
    	aic32x4->fmt = fmt;
    
    	snd_soc_component_update_bits(component, AIC32X4_IFACE1,
    				AIC32X4_IFACE1_DATATYPE_MASK |
    				AIC32X4_IFACE1_MASTER_MASK, iface_reg_1);
    	snd_soc_component_update_bits(component, AIC32X4_IFACE2,
    				AIC32X4_DATA_OFFSET_MASK, iface_reg_2);
    	snd_soc_component_update_bits(component, AIC32X4_IFACE3,
    				AIC32X4_BCLKINV_MASK, iface_reg_3);
    
    	return 0;
    }
    
    static int aic32x4_set_aosr(struct snd_soc_component *component, u8 aosr)
    {
    	return snd_soc_component_write(component, AIC32X4_AOSR, aosr);
    }
    
    static int aic32x4_set_dosr(struct snd_soc_component *component, u16 dosr)
    {
    	snd_soc_component_write(component, AIC32X4_DOSRMSB, dosr >> 8);
    	snd_soc_component_write(component, AIC32X4_DOSRLSB,
    		      (dosr & 0xff));
    
    	return 0;
    }
    
    static int aic32x4_set_processing_blocks(struct snd_soc_component *component,
    						u8 r_block, u8 p_block)
    {
    	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
    
    	if (aic32x4->type == AIC32X4_TYPE_TAS2505) {
    		if (r_block || p_block > 3)
    			return -EINVAL;
    
    		snd_soc_component_write(component, AIC32X4_DACSPB, p_block);
    	} else { /* AIC32x4 */
    		if (r_block > 18 || p_block > 25)
    			return -EINVAL;
    
    		snd_soc_component_write(component, AIC32X4_ADCSPB, r_block);
    		snd_soc_component_write(component, AIC32X4_DACSPB, p_block);
    	}
    
    	return 0;
    }
    
    static int aic32x4_setup_clocks(struct snd_soc_component *component,
    				unsigned int sample_rate, unsigned int channels,
    				unsigned int bit_depth)
    {
    	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
    	u8 aosr;
    	u16 dosr;
    	u8 adc_resource_class, dac_resource_class;
    	u8 madc, nadc, mdac, ndac, max_nadc, min_mdac, max_ndac;
    	u8 dosr_increment;
    	u16 max_dosr, min_dosr;
    	unsigned long adc_clock_rate, dac_clock_rate;
    	int ret;
    
    	static struct clk_bulk_data clocks[] = {
    		{ .id = "pll" },
    		{ .id = "nadc" },
    		{ .id = "madc" },
    		{ .id = "ndac" },
    		{ .id = "mdac" },
    		{ .id = "bdiv" },
    	};
    	dev_err(component->dev, "aic32x4_setup_clocks sample_rate(%d), channels(%d), bit_depth(%d)\n", sample_rate, channels, bit_depth);
    	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
    	if (ret)
    		return ret;
    	dev_err(component->dev, "clocks[0~5].clk(%d,%d,%d,%d,%d,%d)\n", clocks[0].clk, clocks[1].clk, clocks[2].clk, clocks[3].clk, clocks[4].clk, clocks[5].clk);
    
    	if (sample_rate <= 48000) {
    		aosr = 128;
    		adc_resource_class = 6;
    		dac_resource_class = 8;
    		dosr_increment = 8;
    		if (aic32x4->type == AIC32X4_TYPE_TAS2505)
    			aic32x4_set_processing_blocks(component, 0, 1);
    		else
    			aic32x4_set_processing_blocks(component, 1, 1);
    	} else if (sample_rate <= 96000) {
    		aosr = 64;
    		adc_resource_class = 6;
    		dac_resource_class = 8;
    		dosr_increment = 4;
    		if (aic32x4->type == AIC32X4_TYPE_TAS2505)
    			aic32x4_set_processing_blocks(component, 0, 1);
    		else
    			aic32x4_set_processing_blocks(component, 1, 9);
    	} else if (sample_rate == 192000) {
    		aosr = 32;
    		adc_resource_class = 3;
    		dac_resource_class = 4;
    		dosr_increment = 2;
    		if (aic32x4->type == AIC32X4_TYPE_TAS2505)
    			aic32x4_set_processing_blocks(component, 0, 1);
    		else
    			aic32x4_set_processing_blocks(component, 13, 19);
    	} else {
    		dev_err(component->dev, "Sampling rate not supported\n");
    		return -EINVAL;
    	}
    	dev_err(component->dev, "aic32x4->fmt(0x%x)\n", aic32x4->fmt );
    
    	/* PCM over I2S is always 2-channel */
    	if ((aic32x4->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S)
    		channels = 2;
    
    	madc = DIV_ROUND_UP((32 * adc_resource_class), aosr);
    	max_dosr = (AIC32X4_MAX_DOSR_FREQ / sample_rate / dosr_increment) *
    			dosr_increment;
    	min_dosr = (AIC32X4_MIN_DOSR_FREQ / sample_rate / dosr_increment) *
    			dosr_increment;
    	max_nadc = AIC32X4_MAX_CODEC_CLKIN_FREQ / (madc * aosr * sample_rate);
    
    	dev_err(component->dev, "aosr(%d), adc_resource_class(%d), dac_resource_class(%d), dosr_increment(%d)\n", aosr, adc_resource_class, dac_resource_class, dosr_increment);
    		
    	dev_err(component->dev, "madc(%d), max_dosr(%d), min_dosr(%d), max_nadc(%d)\n", madc, max_dosr, min_dosr, max_nadc);
    
    	for (nadc = max_nadc; nadc > 0; --nadc) {
    		adc_clock_rate = nadc * madc * aosr * sample_rate;
    		dev_err(component->dev, "adc_clock_rate(%d x %d x %d)(%d)\n", ndac, mdac, dosr, adc_clock_rate);
    		for (dosr = max_dosr; dosr >= min_dosr;
    				dosr -= dosr_increment) {
    			min_mdac = DIV_ROUND_UP((32 * dac_resource_class), dosr);
    			max_ndac = AIC32X4_MAX_CODEC_CLKIN_FREQ /
    					(min_mdac * dosr * sample_rate);
    			for (mdac = min_mdac; mdac <= 128; ++mdac) {
    				for (ndac = max_ndac; ndac > 0; --ndac) {
    					dac_clock_rate = ndac * mdac * dosr *
    							sample_rate;
    					if (dac_clock_rate == adc_clock_rate) {
    						dev_err(component->dev, "                                  dac_clock_rate(%d x %d x %d)(%d)\n", ndac, mdac, dosr, dac_clock_rate);
    						if (clk_round_rate(clocks[0].clk, dac_clock_rate) == 0)
    							continue;
    
    						clk_set_rate(clocks[0].clk,
    							dac_clock_rate);
    
    						clk_set_rate(clocks[1].clk,
    							sample_rate * aosr *
    							madc);
    						clk_set_rate(clocks[2].clk,
    							sample_rate * aosr);
    						aic32x4_set_aosr(component,
    							aosr);
    
    						clk_set_rate(clocks[3].clk,
    							sample_rate * dosr *
    							mdac);
    						clk_set_rate(clocks[4].clk,
    							sample_rate * dosr);
    						aic32x4_set_dosr(component,
    							dosr);
    
    						clk_set_rate(clocks[5].clk,
    							sample_rate * channels *
    							bit_depth);
    
    						return 0;
    					}
    				}
    			}
    		}
    	}
    
    	dev_err(component->dev,
    		"Could not set clocks to support sample rate.\n");
    	return -EINVAL;
    }
    
    static int aic32x4_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 aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
    	u8 iface1_reg = 0;
    	u8 dacsetup_reg = 0;
    	dev_err(component->dev, "%s:\n", __FUNCTION__ );
    	aic32x4_setup_clocks(component, params_rate(params),
    			     params_channels(params),
    			     params_physical_width(params));
    
    	switch (params_physical_width(params)) {
    	case 16:
    		iface1_reg |= (AIC32X4_WORD_LEN_16BITS <<
    				   AIC32X4_IFACE1_DATALEN_SHIFT);
    		break;
    	case 20:
    		iface1_reg |= (AIC32X4_WORD_LEN_20BITS <<
    				   AIC32X4_IFACE1_DATALEN_SHIFT);
    		break;
    	case 24:
    		iface1_reg |= (AIC32X4_WORD_LEN_24BITS <<
    				   AIC32X4_IFACE1_DATALEN_SHIFT);
    		break;
    	case 32:
    		iface1_reg |= (AIC32X4_WORD_LEN_32BITS <<
    				   AIC32X4_IFACE1_DATALEN_SHIFT);
    		break;
    	}
    	snd_soc_component_update_bits(component, AIC32X4_IFACE1,
    				AIC32X4_IFACE1_DATALEN_MASK, iface1_reg);
    
    	if (params_channels(params) == 1) {
    		dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN;
    	} else {
    		if (aic32x4->swapdacs)
    			dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2RCHN;
    		else
    			dacsetup_reg = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN;
    	}
    	snd_soc_component_update_bits(component, AIC32X4_DACSETUP,
    				AIC32X4_DAC_CHAN_MASK, dacsetup_reg);
    
    	return 0;
    }
    
    static int aic32x4_mute(struct snd_soc_dai *dai, int mute, int direction)
    {
    	struct snd_soc_component *component = dai->component;
    	dev_err(component->dev, "%s:\n", __FUNCTION__ );
    
    	snd_soc_component_update_bits(component, AIC32X4_DACMUTE,
    				AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0);
    
    	return 0;
    }
    
    static int aic32x4_set_bias_level(struct snd_soc_component *component,
    				  enum snd_soc_bias_level level)
    {
    	int ret;
    
    	static struct clk_bulk_data clocks[] = {
    		{ .id = "madc" },
    		{ .id = "mdac" },
    		{ .id = "bdiv" },
    	};
    	dev_err(component->dev, "%s:\n", __FUNCTION__ );
    
    	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
    	if (ret)
    		return ret;
    
    	switch (level) {
    	case SND_SOC_BIAS_ON:
    		ret = clk_bulk_prepare_enable(ARRAY_SIZE(clocks), clocks);
    		if (ret) {
    			dev_err(component->dev, "Failed to enable clocks\n");
    			return ret;
    		}
    		break;
    	case SND_SOC_BIAS_PREPARE:
    		break;
    	case SND_SOC_BIAS_STANDBY:
    		/* Initial cold start */
    		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
    			break;
    
    		clk_bulk_disable_unprepare(ARRAY_SIZE(clocks), clocks);
    		break;
    	case SND_SOC_BIAS_OFF:
    		break;
    	}
    	return 0;
    }
    
    #define AIC32X4_RATES	SNDRV_PCM_RATE_8000_192000
    #define AIC32X4_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 aic32x4_ops = {
    	.hw_params = aic32x4_hw_params,
    	.mute_stream = aic32x4_mute,
    	.set_fmt = aic32x4_set_dai_fmt,
    	.set_sysclk = aic32x4_set_dai_sysclk,
    	.no_capture_mute = 1,
    };
    
    static struct snd_soc_dai_driver aic32x4_dai = {
    	.name = "tlv320aic32x4-hifi",
    	.playback = {
    			 .stream_name = "Playback",
    			 .channels_min = 1,
    			 .channels_max = 2,
    			 .rates = AIC32X4_RATES,
    			 .formats = AIC32X4_FORMATS,},
    	.capture = {
    			.stream_name = "Capture",
    			.channels_min = 1,
    			.channels_max = 8,
    			.rates = AIC32X4_RATES,
    			.formats = AIC32X4_FORMATS,},
    	.ops = &aic32x4_ops,
    	.symmetric_rate = 1,
    };
    
    static void aic32x4_setup_gpios(struct snd_soc_component *component)
    {
    	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
    
    	/* setup GPIO functions */
    	/* MFP1 */
    	if (aic32x4->setup->gpio_func[0] != AIC32X4_MFPX_DEFAULT_VALUE) {
    		snd_soc_component_write(component, AIC32X4_DINCTL,
    			  aic32x4->setup->gpio_func[0]);
    		snd_soc_add_component_controls(component, aic32x4_mfp1,
    			ARRAY_SIZE(aic32x4_mfp1));
    	}
    
    	/* MFP2 */
    	if (aic32x4->setup->gpio_func[1] != AIC32X4_MFPX_DEFAULT_VALUE) {
    		snd_soc_component_write(component, AIC32X4_DOUTCTL,
    			  aic32x4->setup->gpio_func[1]);
    		snd_soc_add_component_controls(component, aic32x4_mfp2,
    			ARRAY_SIZE(aic32x4_mfp2));
    	}
    
    	/* MFP3 */
    	if (aic32x4->setup->gpio_func[2] != AIC32X4_MFPX_DEFAULT_VALUE) {
    		snd_soc_component_write(component, AIC32X4_SCLKCTL,
    			  aic32x4->setup->gpio_func[2]);
    		snd_soc_add_component_controls(component, aic32x4_mfp3,
    			ARRAY_SIZE(aic32x4_mfp3));
    	}
    
    	/* MFP4 */
    	if (aic32x4->setup->gpio_func[3] != AIC32X4_MFPX_DEFAULT_VALUE) {
    		snd_soc_component_write(component, AIC32X4_MISOCTL,
    			  aic32x4->setup->gpio_func[3]);
    		snd_soc_add_component_controls(component, aic32x4_mfp4,
    			ARRAY_SIZE(aic32x4_mfp4));
    	}
    
    	/* MFP5 */
    	if (aic32x4->setup->gpio_func[4] != AIC32X4_MFPX_DEFAULT_VALUE) {
    		snd_soc_component_write(component, AIC32X4_GPIOCTL,
    			  aic32x4->setup->gpio_func[4]);
    		snd_soc_add_component_controls(component, aic32x4_mfp5,
    			ARRAY_SIZE(aic32x4_mfp5));
    	}
    }
    
    static int aic32x4_component_probe(struct snd_soc_component *component)
    {
    	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
    	u32 tmp_reg;
    	int ret;
    
    	static struct clk_bulk_data clocks[] = {
    		{ .id = "codec_clkin" },
    		{ .id = "pll" },
    		{ .id = "bdiv" },
    		{ .id = "mdac" },
    	};
    	dev_err(component->dev, "%s:\n", __FUNCTION__ );
    
    	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
    	if (ret)
    		return ret;
    
    	if (aic32x4->setup)
    		aic32x4_setup_gpios(component);
    
    	clk_set_parent(clocks[0].clk, clocks[1].clk);
    	clk_set_parent(clocks[2].clk, clocks[3].clk);
    
    	/* Power platform configuration */
    	if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) {
    		snd_soc_component_write(component, AIC32X4_MICBIAS,
    				AIC32X4_MICBIAS_LDOIN | AIC32X4_MICBIAS_2075V);
    	}
    	if (aic32x4->power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE)
    		snd_soc_component_write(component, AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE);
    
    	tmp_reg = (aic32x4->power_cfg & AIC32X4_PWR_AIC32X4_LDO_ENABLE) ?
    			AIC32X4_LDOCTLEN : 0;
    	snd_soc_component_write(component, AIC32X4_LDOCTL, tmp_reg);
    
    	tmp_reg = snd_soc_component_read(component, AIC32X4_CMMODE);
    	if (aic32x4->power_cfg & AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36)
    		tmp_reg |= AIC32X4_LDOIN_18_36;
    	if (aic32x4->power_cfg & AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED)
    		tmp_reg |= AIC32X4_LDOIN2HP;
    	snd_soc_component_write(component, AIC32X4_CMMODE, tmp_reg);
    
    	/* Mic PGA routing */
    	if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K)
    		snd_soc_component_write(component, AIC32X4_LMICPGANIN,
    				AIC32X4_LMICPGANIN_IN2R_10K);
    	else
    		snd_soc_component_write(component, AIC32X4_LMICPGANIN,
    				AIC32X4_LMICPGANIN_CM1L_10K);
    	if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K)
    		snd_soc_component_write(component, AIC32X4_RMICPGANIN,
    				AIC32X4_RMICPGANIN_IN1L_10K);
    	else
    		snd_soc_component_write(component, AIC32X4_RMICPGANIN,
    				AIC32X4_RMICPGANIN_CM1R_10K);
    
    	/*
    	 * Workaround: for an unknown reason, the ADC needs to be powered up
    	 * and down for the first capture to work properly. It seems related to
    	 * a HW BUG or some kind of behavior not documented in the datasheet.
    	 */
    	tmp_reg = snd_soc_component_read(component, AIC32X4_ADCSETUP);
    	snd_soc_component_write(component, AIC32X4_ADCSETUP, tmp_reg |
    				AIC32X4_LADC_EN | AIC32X4_RADC_EN);
    	snd_soc_component_write(component, AIC32X4_ADCSETUP, tmp_reg);
    
    	/*
    	 * Enable the fast charging feature and ensure the needed 40ms ellapsed
    	 * before using the analog circuits.
    	 */
    	snd_soc_component_write(component, AIC32X4_REFPOWERUP,
    				AIC32X4_REFPOWERUP_40MS);
    	msleep(40);
    
    	return 0;
    }
    
    static const struct snd_soc_component_driver soc_component_dev_aic32x4 = {
    	.probe			= aic32x4_component_probe,
    	.set_bias_level		= aic32x4_set_bias_level,
    	.controls		= aic32x4_snd_controls,
    	.num_controls		= ARRAY_SIZE(aic32x4_snd_controls),
    	.dapm_widgets		= aic32x4_dapm_widgets,
    	.num_dapm_widgets	= ARRAY_SIZE(aic32x4_dapm_widgets),
    	.dapm_routes		= aic32x4_dapm_routes,
    	.num_dapm_routes	= ARRAY_SIZE(aic32x4_dapm_routes),
    	.suspend_bias_off	= 1,
    	.idle_bias_on		= 1,
    	.use_pmdown_time	= 1,
    	.endianness		= 1,
    	.non_legacy_dai_naming	= 1,
    };
    
    static const struct snd_kcontrol_new aic32x4_tas2505_snd_controls[] = {
    	SOC_SINGLE_S8_TLV("PCM Playback Volume",
    			  AIC32X4_LDACVOL, -0x7f, 0x30, tlv_pcm),
    	SOC_ENUM("DAC Playback PowerTune Switch", l_ptm_enum),
    
    	SOC_SINGLE_TLV("HP Driver Gain Volume",
    			AIC32X4_HPLGAIN, 0, 0x74, 1, tlv_tas_driver_gain),
    	SOC_SINGLE("HP DAC Playback Switch", AIC32X4_HPLGAIN, 6, 1, 1),
    
    	SOC_SINGLE_TLV("Speaker Driver Playback Volume",
    			TAS2505_SPKVOL1, 0, 0x74, 1, tlv_tas_driver_gain),
    	SOC_SINGLE_TLV("Speaker Amplifier Playback Volume",
    			TAS2505_SPKVOL2, 4, 5, 0, tlv_amp_vol),
    
    	SOC_SINGLE("Auto-mute Switch", AIC32X4_DACMUTE, 4, 7, 0),
    };
    
    static const struct snd_kcontrol_new hp_output_mixer_controls[] = {
    	SOC_DAPM_SINGLE("DAC Switch", AIC32X4_HPLROUTE, 3, 1, 0),
    };
    
    static const struct snd_soc_dapm_widget aic32x4_tas2505_dapm_widgets[] = {
    	SND_SOC_DAPM_DAC("DAC", "Playback", AIC32X4_DACSETUP, 7, 0),
    	SND_SOC_DAPM_MIXER("HP Output Mixer", SND_SOC_NOPM, 0, 0,
    			   &hp_output_mixer_controls[0],
    			   ARRAY_SIZE(hp_output_mixer_controls)),
    	SND_SOC_DAPM_PGA("HP Power", AIC32X4_OUTPWRCTL, 5, 0, NULL, 0),
    
    	SND_SOC_DAPM_PGA("Speaker Driver", TAS2505_SPK, 1, 0, NULL, 0),
    
    	SND_SOC_DAPM_OUTPUT("HP"),
    	SND_SOC_DAPM_OUTPUT("Speaker"),
    };
    
    static const struct snd_soc_dapm_route aic32x4_tas2505_dapm_routes[] = {
    	/* Left Output */
    	{"HP Output Mixer", "DAC Switch", "DAC"},
    
    	{"HP Power", NULL, "HP Output Mixer"},
    	{"HP", NULL, "HP Power"},
    
    	{"Speaker Driver", NULL, "DAC"},
    	{"Speaker", NULL, "Speaker Driver"},
    };
    
    static struct snd_soc_dai_driver aic32x4_tas2505_dai = {
    	.name = "tas2505-hifi",
    	.playback = {
    			 .stream_name = "Playback",
    			 .channels_min = 1,
    			 .channels_max = 2,
    			 .rates = SNDRV_PCM_RATE_8000_96000,
    			 .formats = AIC32X4_FORMATS,},
    	.ops = &aic32x4_ops,
    	.symmetric_rate = 1,
    };
    
    static int aic32x4_tas2505_component_probe(struct snd_soc_component *component)
    {
    	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
    	u32 tmp_reg;
    	int ret;
    
    	static struct clk_bulk_data clocks[] = {
    		{ .id = "codec_clkin" },
    		{ .id = "pll" },
    		{ .id = "bdiv" },
    		{ .id = "mdac" },
    	};
    
    	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
    	if (ret)
    		return ret;
    
    	if (aic32x4->setup)
    		aic32x4_setup_gpios(component);
    
    	clk_set_parent(clocks[0].clk, clocks[1].clk);
    	clk_set_parent(clocks[2].clk, clocks[3].clk);
    
    	/* Power platform configuration */
    	if (aic32x4->power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE)
    		snd_soc_component_write(component, AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE);
    
    	tmp_reg = (aic32x4->power_cfg & AIC32X4_PWR_AIC32X4_LDO_ENABLE) ?
    			AIC32X4_LDOCTLEN : 0;
    	snd_soc_component_write(component, AIC32X4_LDOCTL, tmp_reg);
    
    	tmp_reg = snd_soc_component_read(component, AIC32X4_CMMODE);
    	if (aic32x4->power_cfg & AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36)
    		tmp_reg |= AIC32X4_LDOIN_18_36;
    	if (aic32x4->power_cfg & AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED)
    		tmp_reg |= AIC32X4_LDOIN2HP;
    	snd_soc_component_write(component, AIC32X4_CMMODE, tmp_reg);
    
    	/*
    	 * Enable the fast charging feature and ensure the needed 40ms ellapsed
    	 * before using the analog circuits.
    	 */
    	snd_soc_component_write(component, TAS2505_REFPOWERUP,
    				AIC32X4_REFPOWERUP_40MS);
    	msleep(40);
    
    	return 0;
    }
    
    static const struct snd_soc_component_driver soc_component_dev_aic32x4_tas2505 = {
    	.probe			= aic32x4_tas2505_component_probe,
    	.set_bias_level		= aic32x4_set_bias_level,
    	.controls		= aic32x4_tas2505_snd_controls,
    	.num_controls		= ARRAY_SIZE(aic32x4_tas2505_snd_controls),
    	.dapm_widgets		= aic32x4_tas2505_dapm_widgets,
    	.num_dapm_widgets	= ARRAY_SIZE(aic32x4_tas2505_dapm_widgets),
    	.dapm_routes		= aic32x4_tas2505_dapm_routes,
    	.num_dapm_routes	= ARRAY_SIZE(aic32x4_tas2505_dapm_routes),
    	.suspend_bias_off	= 1,
    	.idle_bias_on		= 1,
    	.use_pmdown_time	= 1,
    	.endianness		= 1,
    	.non_legacy_dai_naming	= 1,
    };
    
    static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4,
    		struct device_node *np)
    {
    	struct aic32x4_setup_data *aic32x4_setup;
    //	int ret;
    
    	aic32x4_setup = devm_kzalloc(aic32x4->dev, sizeof(*aic32x4_setup),
    							GFP_KERNEL);
    	if (!aic32x4_setup)
    		return -ENOMEM;
    
    //	ret = of_property_match_string(np, "clock-names", "mclk");
    //	if (ret < 0)
    //		return -EINVAL;
    	aic32x4->mclk_name = "mclk";//of_clk_get_parent_name(np, ret);
    
    	aic32x4->swapdacs = false;
    	aic32x4->micpga_routing = 0;
    	aic32x4->rstn_gpio = of_get_named_gpio(np, "reset-gpios", 0);
    
    	if (of_property_read_u32_array(np, "aic32x4-gpio-func",
    				aic32x4_setup->gpio_func, 5) >= 0)
    		aic32x4->setup = aic32x4_setup;
    	return 0;
    }
    
    static void aic32x4_disable_regulators(struct aic32x4_priv *aic32x4)
    {
    	regulator_disable(aic32x4->supply_iov);
    
    	if (!IS_ERR(aic32x4->supply_ldo))
    		regulator_disable(aic32x4->supply_ldo);
    
    	if (!IS_ERR(aic32x4->supply_dv))
    		regulator_disable(aic32x4->supply_dv);
    
    	if (!IS_ERR(aic32x4->supply_av))
    		regulator_disable(aic32x4->supply_av);
    }
    
    static int aic32x4_setup_regulators(struct device *dev,
    		struct aic32x4_priv *aic32x4)
    {
    	int ret = 0;
    
    	aic32x4->supply_ldo = devm_regulator_get_optional(dev, "ldoin");
    	aic32x4->supply_iov = devm_regulator_get(dev, "iov");
    	aic32x4->supply_dv = devm_regulator_get_optional(dev, "dv");
    	aic32x4->supply_av = devm_regulator_get_optional(dev, "av");
    
    	/* Check if the regulator requirements are fulfilled */
    
    	if (IS_ERR(aic32x4->supply_iov)) {
    		dev_err(dev, "Missing supply 'iov'\n");
    		return PTR_ERR(aic32x4->supply_iov);
    	}
    
    	if (IS_ERR(aic32x4->supply_ldo)) {
    		if (PTR_ERR(aic32x4->supply_ldo) == -EPROBE_DEFER)
    			return -EPROBE_DEFER;
    
    		if (IS_ERR(aic32x4->supply_dv)) {
    			dev_err(dev, "Missing supply 'dv' or 'ldoin'\n");
    			return PTR_ERR(aic32x4->supply_dv);
    		}
    		if (IS_ERR(aic32x4->supply_av)) {
    			dev_err(dev, "Missing supply 'av' or 'ldoin'\n");
    			return PTR_ERR(aic32x4->supply_av);
    		}
    	} else {
    		if (PTR_ERR(aic32x4->supply_dv) == -EPROBE_DEFER)
    			return -EPROBE_DEFER;
    		if (PTR_ERR(aic32x4->supply_av) == -EPROBE_DEFER)
    			return -EPROBE_DEFER;
    	}
    
    	ret = regulator_enable(aic32x4->supply_iov);
    	if (ret) {
    		dev_err(dev, "Failed to enable regulator iov\n");
    		return ret;
    	}
    
    	if (!IS_ERR(aic32x4->supply_ldo)) {
    		ret = regulator_enable(aic32x4->supply_ldo);
    		if (ret) {
    			dev_err(dev, "Failed to enable regulator ldo\n");
    			goto error_ldo;
    		}
    	}
    
    	if (!IS_ERR(aic32x4->supply_dv)) {
    		ret = regulator_enable(aic32x4->supply_dv);
    		if (ret) {
    			dev_err(dev, "Failed to enable regulator dv\n");
    			goto error_dv;
    		}
    	}
    
    	if (!IS_ERR(aic32x4->supply_av)) {
    		ret = regulator_enable(aic32x4->supply_av);
    		if (ret) {
    			dev_err(dev, "Failed to enable regulator av\n");
    			goto error_av;
    		}
    	}
    
    	if (!IS_ERR(aic32x4->supply_ldo) && IS_ERR(aic32x4->supply_av))
    		aic32x4->power_cfg |= AIC32X4_PWR_AIC32X4_LDO_ENABLE;
    
    	return 0;
    
    error_av:
    	if (!IS_ERR(aic32x4->supply_dv))
    		regulator_disable(aic32x4->supply_dv);
    
    error_dv:
    	if (!IS_ERR(aic32x4->supply_ldo))
    		regulator_disable(aic32x4->supply_ldo);
    
    error_ldo:
    	regulator_disable(aic32x4->supply_iov);
    	return ret;
    }
    
    int aic32x4_probe(struct device *dev, struct regmap *regmap)
    {
    	struct aic32x4_priv *aic32x4;
    	struct aic32x4_pdata *pdata = dev->platform_data;
    	struct device_node *np = dev->of_node;
    	int ret;
    	dev_err(dev, "aic32x4_probe\n");
    	if (IS_ERR(regmap))
    		return PTR_ERR(regmap);
    
    	aic32x4 = devm_kzalloc(dev, sizeof(struct aic32x4_priv),
    				   GFP_KERNEL);
    	if (aic32x4 == NULL)
    		return -ENOMEM;
    
    	aic32x4->dev = dev;
    	aic32x4->type = (enum aic32x4_type)dev_get_drvdata(dev);
    
    	dev_set_drvdata(dev, aic32x4);
    
    	if (pdata) {
    		aic32x4->power_cfg = pdata->power_cfg;
    		aic32x4->swapdacs = pdata->swapdacs;
    		aic32x4->micpga_routing = pdata->micpga_routing;
    		aic32x4->rstn_gpio = pdata->rstn_gpio;
    		aic32x4->mclk_name = "mclk";
    	} else if (np) {
    		ret = aic32x4_parse_dt(aic32x4, np);
    		if (ret) {
    			dev_err(dev, "Failed to parse DT node\n");
    			return ret;
    		}
    	} else {
    		aic32x4->power_cfg = 0;
    		aic32x4->swapdacs = false;
    		aic32x4->micpga_routing = 0;
    		aic32x4->rstn_gpio = -1;
    		aic32x4->mclk_name = "mclk";
    	}
    	dev_err(dev, "aic32x4->rstn_gpio (%d)\n", aic32x4->rstn_gpio);
    	if (gpio_is_valid(aic32x4->rstn_gpio)) {
    		ret = devm_gpio_request_one(dev, aic32x4->rstn_gpio,
    				GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn");
    		if (ret != 0)
    			return ret;
    	}
    	dev_err(dev, "aic32x4_setup_regulators\n");
    	ret = aic32x4_setup_regulators(dev, aic32x4);
    	if (ret) {
    		dev_err(dev, "Failed to setup regulators\n");
    		return ret;
    	}
    
    	if (gpio_is_valid(aic32x4->rstn_gpio)) {
    		ndelay(10);
    		gpio_set_value_cansleep(aic32x4->rstn_gpio, 1);
    		mdelay(1);
    	}
    	dev_err(dev, "regmap_write AIC32X4_RESET\n");
    	ret = regmap_write(regmap, AIC32X4_RESET, 0x01);
    	if (ret){
    		dev_err(dev, "Failed to regmap_write AIC32X4_RESET\n");
    		goto err_disable_regulators;
    	}
    
    	ret = aic32x4_register_clocks(dev, aic32x4->mclk_name);
    	if (ret){
    		dev_err(dev, "Failed to aic32x4_register_clocks\n");
    		goto err_disable_regulators;
    	}
    
    	switch (aic32x4->type) {
    	case AIC32X4_TYPE_TAS2505:
    		ret = devm_snd_soc_register_component(dev,
    			&soc_component_dev_aic32x4_tas2505, &aic32x4_tas2505_dai, 1);
    		break;
    	default:
    		ret = devm_snd_soc_register_component(dev,
    			&soc_component_dev_aic32x4, &aic32x4_dai, 1);
    	}
    
    	if (ret) {
    		dev_err(dev, "Failed to register component\n");
    		goto err_disable_regulators;
    	}
    	dev_err(dev, "aic32x4_probe done\n");
    	return 0;
    
    err_disable_regulators:
    	aic32x4_disable_regulators(aic32x4);
    
    	return ret;
    }
    EXPORT_SYMBOL(aic32x4_probe);
    
    int aic32x4_remove(struct device *dev)
    {
    	struct aic32x4_priv *aic32x4 = dev_get_drvdata(dev);
    
    	aic32x4_disable_regulators(aic32x4);
    
    	return 0;
    }
    EXPORT_SYMBOL(aic32x4_remove);
    
    MODULE_DESCRIPTION("ASoC tlv320aic32x4 codec driver");
    MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
    MODULE_LICENSE("GPL");
    

    the following log is right?

    Thank you

     [ 160.233343][ T1635] tlv320aic32x4 2-0018: aic32x4_set_dai_fmt: fmt(0x1001)
    [ 160.249863][ T1635] tlv320aic32x4 2-0018: aic32x4_set_dai_sysclk:clk_id(1), freq(1536000)
    [ 160.258958][ T1635] tlv320aic32x4 2-0018: aic32x4_hw_params:
    [ 160.265416][ T1635] tlv320aic32x4 2-0018: aic32x4_setup_clocks sample_rate(48000), channels(2), bit_depth(16)
    [ 160.276144][ T1635] tlv320aic32x4 2-0018: clocks[0~5].clk(123533184,123535104,123531648,123532672,123534848,113750016)
    [ 160.290270][ T1635] tlv320aic32x4 2-0018: aic32x4->fmt(0x1001)

  • Dear Kevin

    I change back to use MLCK and check the waveform of MLCK/BLCK/WLCK

    there are 

    MCLK : 12MHz

    BCLK : 1.5 MHz

    WCLK : 48 kHz

    I add some log as attached source code

    1462.tlv320aic32x4.c
    // SPDX-License-Identifier: GPL-2.0-or-later
    /*
     * linux/sound/soc/codecs/tlv320aic32x4.c
     *
     * Copyright 2011 Vista Silicon S.L.
     *
     * Author: Javier Martin <javier.martin@vista-silicon.com>
     *
     * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
     */
    
    #include <linux/module.h>
    #include <linux/moduleparam.h>
    #include <linux/init.h>
    #include <linux/delay.h>
    #include <linux/pm.h>
    #include <linux/gpio.h>
    #include <linux/of_gpio.h>
    #include <linux/cdev.h>
    #include <linux/slab.h>
    #include <linux/clk.h>
    #include <linux/of_clk.h>
    #include <linux/regulator/consumer.h>
    
    #include <sound/tlv320aic32x4.h>
    #include <sound/core.h>
    #include <sound/pcm.h>
    #include <sound/pcm_params.h>
    #include <sound/soc.h>
    #include <sound/soc-dapm.h>
    #include <sound/initval.h>
    #include <sound/tlv.h>
    
    #include "tlv320aic32x4.h"
    
    struct aic32x4_priv {
    	struct regmap *regmap;
    	u32 power_cfg;
    	u32 micpga_routing;
    	bool swapdacs;
    	int rstn_gpio;
    	const char *mclk_name;
    
    	struct regulator *supply_ldo;
    	struct regulator *supply_iov;
    	struct regulator *supply_dv;
    	struct regulator *supply_av;
    
    	struct aic32x4_setup_data *setup;
    	struct device *dev;
    	enum aic32x4_type type;
    
    	unsigned int fmt;
    };
    
    static int aic32x4_reset_adc(struct snd_soc_dapm_widget *w,
    			     struct snd_kcontrol *kcontrol, int event)
    {
    	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
    	u32 adc_reg;
    
    	/*
    	 * Workaround: the datasheet does not mention a required programming
    	 * sequence but experiments show the ADC needs to be reset after each
    	 * capture to avoid audible artifacts.
    	 */
    	switch (event) {
    	case SND_SOC_DAPM_POST_PMD:
    		adc_reg = snd_soc_component_read(component, AIC32X4_ADCSETUP);
    		snd_soc_component_write(component, AIC32X4_ADCSETUP, adc_reg |
    					AIC32X4_LADC_EN | AIC32X4_RADC_EN);
    		snd_soc_component_write(component, AIC32X4_ADCSETUP, adc_reg);
    		break;
    	}
    	return 0;
    };
    
    static int mic_bias_event(struct snd_soc_dapm_widget *w,
    	struct snd_kcontrol *kcontrol, int event)
    {
    	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
    
    	switch (event) {
    	case SND_SOC_DAPM_POST_PMU:
    		/* Change Mic Bias Registor */
    		snd_soc_component_update_bits(component, AIC32X4_MICBIAS,
    				AIC32x4_MICBIAS_MASK,
    				AIC32X4_MICBIAS_LDOIN |
    				AIC32X4_MICBIAS_2075V);
    		printk(KERN_DEBUG "%s: Mic Bias will be turned ON\n", __func__);
    		break;
    	case SND_SOC_DAPM_PRE_PMD:
    		snd_soc_component_update_bits(component, AIC32X4_MICBIAS,
    				AIC32x4_MICBIAS_MASK, 0);
    		printk(KERN_DEBUG "%s: Mic Bias will be turned OFF\n",
    				__func__);
    		break;
    	}
    
    	return 0;
    }
    
    
    static int aic32x4_get_mfp1_gpio(struct snd_kcontrol *kcontrol,
    	struct snd_ctl_elem_value *ucontrol)
    {
    	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
    	u8 val;
    
    	val = snd_soc_component_read(component, AIC32X4_DINCTL);
    
    	ucontrol->value.integer.value[0] = (val & 0x01);
    
    	return 0;
    };
    
    static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol,
    	struct snd_ctl_elem_value *ucontrol)
    {
    	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
    	u8 val;
    	u8 gpio_check;
    
    	val = snd_soc_component_read(component, AIC32X4_DOUTCTL);
    	gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED);
    	if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) {
    		printk(KERN_ERR "%s: MFP2 is not configure as a GPIO output\n",
    			__func__);
    		return -EINVAL;
    	}
    
    	if (ucontrol->value.integer.value[0] == (val & AIC32X4_MFP2_GPIO_OUT_HIGH))
    		return 0;
    
    	if (ucontrol->value.integer.value[0])
    		val |= ucontrol->value.integer.value[0];
    	else
    		val &= ~AIC32X4_MFP2_GPIO_OUT_HIGH;
    
    	snd_soc_component_write(component, AIC32X4_DOUTCTL, val);
    
    	return 0;
    };
    
    static int aic32x4_get_mfp3_gpio(struct snd_kcontrol *kcontrol,
    	struct snd_ctl_elem_value *ucontrol)
    {
    	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
    	u8 val;
    
    	val = snd_soc_component_read(component, AIC32X4_SCLKCTL);
    
    	ucontrol->value.integer.value[0] = (val & 0x01);
    
    	return 0;
    };
    
    static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol,
    	struct snd_ctl_elem_value *ucontrol)
    {
    	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
    	u8 val;
    	u8 gpio_check;
    
    	val = snd_soc_component_read(component, AIC32X4_MISOCTL);
    	gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED);
    	if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) {
    		printk(KERN_ERR "%s: MFP4 is not configure as a GPIO output\n",
    			__func__);
    		return -EINVAL;
    	}
    
    	if (ucontrol->value.integer.value[0] == (val & AIC32X4_MFP5_GPIO_OUT_HIGH))
    		return 0;
    
    	if (ucontrol->value.integer.value[0])
    		val |= ucontrol->value.integer.value[0];
    	else
    		val &= ~AIC32X4_MFP5_GPIO_OUT_HIGH;
    
    	snd_soc_component_write(component, AIC32X4_MISOCTL, val);
    
    	return 0;
    };
    
    static int aic32x4_get_mfp5_gpio(struct snd_kcontrol *kcontrol,
    	struct snd_ctl_elem_value *ucontrol)
    {
    	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
    	u8 val;
    
    	val = snd_soc_component_read(component, AIC32X4_GPIOCTL);
    	ucontrol->value.integer.value[0] = ((val & 0x2) >> 1);
    
    	return 0;
    };
    
    static int aic32x4_set_mfp5_gpio(struct snd_kcontrol *kcontrol,
    	struct snd_ctl_elem_value *ucontrol)
    {
    	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
    	u8 val;
    	u8 gpio_check;
    
    	val = snd_soc_component_read(component, AIC32X4_GPIOCTL);
    	gpio_check = (val & AIC32X4_MFP5_GPIO_OUTPUT);
    	if (gpio_check != AIC32X4_MFP5_GPIO_OUTPUT) {
    		printk(KERN_ERR "%s: MFP5 is not configure as a GPIO output\n",
    			__func__);
    		return -EINVAL;
    	}
    
    	if (ucontrol->value.integer.value[0] == (val & 0x1))
    		return 0;
    
    	if (ucontrol->value.integer.value[0])
    		val |= ucontrol->value.integer.value[0];
    	else
    		val &= 0xfe;
    
    	snd_soc_component_write(component, AIC32X4_GPIOCTL, val);
    
    	return 0;
    };
    
    static const struct snd_kcontrol_new aic32x4_mfp1[] = {
    	SOC_SINGLE_BOOL_EXT("MFP1 GPIO", 0, aic32x4_get_mfp1_gpio, NULL),
    };
    
    static const struct snd_kcontrol_new aic32x4_mfp2[] = {
    	SOC_SINGLE_BOOL_EXT("MFP2 GPIO", 0, NULL, aic32x4_set_mfp2_gpio),
    };
    
    static const struct snd_kcontrol_new aic32x4_mfp3[] = {
    	SOC_SINGLE_BOOL_EXT("MFP3 GPIO", 0, aic32x4_get_mfp3_gpio, NULL),
    };
    
    static const struct snd_kcontrol_new aic32x4_mfp4[] = {
    	SOC_SINGLE_BOOL_EXT("MFP4 GPIO", 0, NULL, aic32x4_set_mfp4_gpio),
    };
    
    static const struct snd_kcontrol_new aic32x4_mfp5[] = {
    	SOC_SINGLE_BOOL_EXT("MFP5 GPIO", 0, aic32x4_get_mfp5_gpio,
    		aic32x4_set_mfp5_gpio),
    };
    
    /* 0dB min, 0.5dB steps */
    static DECLARE_TLV_DB_SCALE(tlv_step_0_5, 0, 50, 0);
    /* -63.5dB min, 0.5dB steps */
    static DECLARE_TLV_DB_SCALE(tlv_pcm, -6350, 50, 0);
    /* -6dB min, 1dB steps */
    static DECLARE_TLV_DB_SCALE(tlv_driver_gain, -600, 100, 0);
    /* -12dB min, 0.5dB steps */
    static DECLARE_TLV_DB_SCALE(tlv_adc_vol, -1200, 50, 0);
    /* -6dB min, 1dB steps */
    static DECLARE_TLV_DB_SCALE(tlv_tas_driver_gain, -5850, 50, 0);
    static DECLARE_TLV_DB_SCALE(tlv_amp_vol, 0, 600, 1);
    
    static const char * const lo_cm_text[] = {
    	"Full Chip", "1.65V",
    };
    
    static SOC_ENUM_SINGLE_DECL(lo_cm_enum, AIC32X4_CMMODE, 3, lo_cm_text);
    
    static const char * const ptm_text[] = {
    	"P3", "P2", "P1",
    };
    
    static SOC_ENUM_SINGLE_DECL(l_ptm_enum, AIC32X4_LPLAYBACK, 2, ptm_text);
    static SOC_ENUM_SINGLE_DECL(r_ptm_enum, AIC32X4_RPLAYBACK, 2, ptm_text);
    
    static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
    	SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL,
    			AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm),
    	SOC_ENUM("DAC Left Playback PowerTune Switch", l_ptm_enum),
    	SOC_ENUM("DAC Right Playback PowerTune Switch", r_ptm_enum),
    	SOC_DOUBLE_R_S_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN,
    			AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0,
    			tlv_driver_gain),
    	SOC_DOUBLE_R_S_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN,
    			AIC32X4_LORGAIN, 0, -0x6, 0x1d, 5, 0,
    			tlv_driver_gain),
    	SOC_DOUBLE_R("HP DAC Playback Switch", AIC32X4_HPLGAIN,
    			AIC32X4_HPRGAIN, 6, 0x01, 1),
    	SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN,
    			AIC32X4_LORGAIN, 6, 0x01, 1),
    	SOC_ENUM("LO Playback Common Mode Switch", lo_cm_enum),
    	SOC_DOUBLE_R("Mic PGA Switch", AIC32X4_LMICPGAVOL,
    			AIC32X4_RMICPGAVOL, 7, 0x01, 1),
    
    	SOC_SINGLE("ADCFGA Left Mute Switch", AIC32X4_ADCFGA, 7, 1, 0),
    	SOC_SINGLE("ADCFGA Right Mute Switch", AIC32X4_ADCFGA, 3, 1, 0),
    
    	SOC_DOUBLE_R_S_TLV("ADC Level Volume", AIC32X4_LADCVOL,
    			AIC32X4_RADCVOL, 0, -0x18, 0x28, 6, 0, tlv_adc_vol),
    	SOC_DOUBLE_R_TLV("PGA Level Volume", AIC32X4_LMICPGAVOL,
    			AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5),
    
    	SOC_SINGLE("Auto-mute Switch", AIC32X4_DACMUTE, 4, 7, 0),
    
    	SOC_SINGLE("AGC Left Switch", AIC32X4_LAGC1, 7, 1, 0),
    	SOC_SINGLE("AGC Right Switch", AIC32X4_RAGC1, 7, 1, 0),
    	SOC_DOUBLE_R("AGC Target Level", AIC32X4_LAGC1, AIC32X4_RAGC1,
    			4, 0x07, 0),
    	SOC_DOUBLE_R("AGC Gain Hysteresis", AIC32X4_LAGC1, AIC32X4_RAGC1,
    			0, 0x03, 0),
    	SOC_DOUBLE_R("AGC Hysteresis", AIC32X4_LAGC2, AIC32X4_RAGC2,
    			6, 0x03, 0),
    	SOC_DOUBLE_R("AGC Noise Threshold", AIC32X4_LAGC2, AIC32X4_RAGC2,
    			1, 0x1F, 0),
    	SOC_DOUBLE_R("AGC Max PGA", AIC32X4_LAGC3, AIC32X4_RAGC3,
    			0, 0x7F, 0),
    	SOC_DOUBLE_R("AGC Attack Time", AIC32X4_LAGC4, AIC32X4_RAGC4,
    			3, 0x1F, 0),
    	SOC_DOUBLE_R("AGC Decay Time", AIC32X4_LAGC5, AIC32X4_RAGC5,
    			3, 0x1F, 0),
    	SOC_DOUBLE_R("AGC Noise Debounce", AIC32X4_LAGC6, AIC32X4_RAGC6,
    			0, 0x1F, 0),
    	SOC_DOUBLE_R("AGC Signal Debounce", AIC32X4_LAGC7, AIC32X4_RAGC7,
    			0, 0x0F, 0),
    };
    
    static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
    	SOC_DAPM_SINGLE("L_DAC Switch", AIC32X4_HPLROUTE, 3, 1, 0),
    	SOC_DAPM_SINGLE("IN1_L Switch", AIC32X4_HPLROUTE, 2, 1, 0),
    };
    
    static const struct snd_kcontrol_new hpr_output_mixer_controls[] = {
    	SOC_DAPM_SINGLE("R_DAC Switch", AIC32X4_HPRROUTE, 3, 1, 0),
    	SOC_DAPM_SINGLE("IN1_R Switch", AIC32X4_HPRROUTE, 2, 1, 0),
    };
    
    static const struct snd_kcontrol_new lol_output_mixer_controls[] = {
    	SOC_DAPM_SINGLE("L_DAC Switch", AIC32X4_LOLROUTE, 3, 1, 0),
    };
    
    static const struct snd_kcontrol_new lor_output_mixer_controls[] = {
    	SOC_DAPM_SINGLE("R_DAC Switch", AIC32X4_LORROUTE, 3, 1, 0),
    };
    
    static const char * const resistor_text[] = {
    	"Off", "10 kOhm", "20 kOhm", "40 kOhm",
    };
    
    /* Left mixer pins */
    static SOC_ENUM_SINGLE_DECL(in1l_lpga_p_enum, AIC32X4_LMICPGAPIN, 6, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in2l_lpga_p_enum, AIC32X4_LMICPGAPIN, 4, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in3l_lpga_p_enum, AIC32X4_LMICPGAPIN, 2, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in1r_lpga_p_enum, AIC32X4_LMICPGAPIN, 0, resistor_text);
    
    static SOC_ENUM_SINGLE_DECL(cml_lpga_n_enum, AIC32X4_LMICPGANIN, 6, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in2r_lpga_n_enum, AIC32X4_LMICPGANIN, 4, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in3r_lpga_n_enum, AIC32X4_LMICPGANIN, 2, resistor_text);
    
    static const struct snd_kcontrol_new in1l_to_lmixer_controls[] = {
    	SOC_DAPM_ENUM("IN1_L L+ Switch", in1l_lpga_p_enum),
    };
    static const struct snd_kcontrol_new in2l_to_lmixer_controls[] = {
    	SOC_DAPM_ENUM("IN2_L L+ Switch", in2l_lpga_p_enum),
    };
    static const struct snd_kcontrol_new in3l_to_lmixer_controls[] = {
    	SOC_DAPM_ENUM("IN3_L L+ Switch", in3l_lpga_p_enum),
    };
    static const struct snd_kcontrol_new in1r_to_lmixer_controls[] = {
    	SOC_DAPM_ENUM("IN1_R L+ Switch", in1r_lpga_p_enum),
    };
    static const struct snd_kcontrol_new cml_to_lmixer_controls[] = {
    	SOC_DAPM_ENUM("CM_L L- Switch", cml_lpga_n_enum),
    };
    static const struct snd_kcontrol_new in2r_to_lmixer_controls[] = {
    	SOC_DAPM_ENUM("IN2_R L- Switch", in2r_lpga_n_enum),
    };
    static const struct snd_kcontrol_new in3r_to_lmixer_controls[] = {
    	SOC_DAPM_ENUM("IN3_R L- Switch", in3r_lpga_n_enum),
    };
    
    /*	Right mixer pins */
    static SOC_ENUM_SINGLE_DECL(in1r_rpga_p_enum, AIC32X4_RMICPGAPIN, 6, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in2r_rpga_p_enum, AIC32X4_RMICPGAPIN, 4, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in3r_rpga_p_enum, AIC32X4_RMICPGAPIN, 2, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in2l_rpga_p_enum, AIC32X4_RMICPGAPIN, 0, resistor_text);
    static SOC_ENUM_SINGLE_DECL(cmr_rpga_n_enum, AIC32X4_RMICPGANIN, 6, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in1l_rpga_n_enum, AIC32X4_RMICPGANIN, 4, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in3l_rpga_n_enum, AIC32X4_RMICPGANIN, 2, resistor_text);
    
    static const struct snd_kcontrol_new in1r_to_rmixer_controls[] = {
    	SOC_DAPM_ENUM("IN1_R R+ Switch", in1r_rpga_p_enum),
    };
    static const struct snd_kcontrol_new in2r_to_rmixer_controls[] = {
    	SOC_DAPM_ENUM("IN2_R R+ Switch", in2r_rpga_p_enum),
    };
    static const struct snd_kcontrol_new in3r_to_rmixer_controls[] = {
    	SOC_DAPM_ENUM("IN3_R R+ Switch", in3r_rpga_p_enum),
    };
    static const struct snd_kcontrol_new in2l_to_rmixer_controls[] = {
    	SOC_DAPM_ENUM("IN2_L R+ Switch", in2l_rpga_p_enum),
    };
    static const struct snd_kcontrol_new cmr_to_rmixer_controls[] = {
    	SOC_DAPM_ENUM("CM_R R- Switch", cmr_rpga_n_enum),
    };
    static const struct snd_kcontrol_new in1l_to_rmixer_controls[] = {
    	SOC_DAPM_ENUM("IN1_L R- Switch", in1l_rpga_n_enum),
    };
    static const struct snd_kcontrol_new in3l_to_rmixer_controls[] = {
    	SOC_DAPM_ENUM("IN3_L R- Switch", in3l_rpga_n_enum),
    };
    
    static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = {
    	SND_SOC_DAPM_DAC("Left DAC", "Left Playback", AIC32X4_DACSETUP, 7, 0),
    	SND_SOC_DAPM_MIXER("HPL Output Mixer", SND_SOC_NOPM, 0, 0,
    			   &hpl_output_mixer_controls[0],
    			   ARRAY_SIZE(hpl_output_mixer_controls)),
    	SND_SOC_DAPM_PGA("HPL Power", AIC32X4_OUTPWRCTL, 5, 0, NULL, 0),
    
    	SND_SOC_DAPM_MIXER("LOL Output Mixer", SND_SOC_NOPM, 0, 0,
    			   &lol_output_mixer_controls[0],
    			   ARRAY_SIZE(lol_output_mixer_controls)),
    	SND_SOC_DAPM_PGA("LOL Power", AIC32X4_OUTPWRCTL, 3, 0, NULL, 0),
    
    	SND_SOC_DAPM_DAC("Right DAC", "Right Playback", AIC32X4_DACSETUP, 6, 0),
    	SND_SOC_DAPM_MIXER("HPR Output Mixer", SND_SOC_NOPM, 0, 0,
    			   &hpr_output_mixer_controls[0],
    			   ARRAY_SIZE(hpr_output_mixer_controls)),
    	SND_SOC_DAPM_PGA("HPR Power", AIC32X4_OUTPWRCTL, 4, 0, NULL, 0),
    	SND_SOC_DAPM_MIXER("LOR Output Mixer", SND_SOC_NOPM, 0, 0,
    			   &lor_output_mixer_controls[0],
    			   ARRAY_SIZE(lor_output_mixer_controls)),
    	SND_SOC_DAPM_PGA("LOR Power", AIC32X4_OUTPWRCTL, 2, 0, NULL, 0),
    
    	SND_SOC_DAPM_ADC("Right ADC", "Right Capture", AIC32X4_ADCSETUP, 6, 0),
    	SND_SOC_DAPM_MUX("IN1_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in1r_to_rmixer_controls),
    	SND_SOC_DAPM_MUX("IN2_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in2r_to_rmixer_controls),
    	SND_SOC_DAPM_MUX("IN3_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in3r_to_rmixer_controls),
    	SND_SOC_DAPM_MUX("IN2_L to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in2l_to_rmixer_controls),
    	SND_SOC_DAPM_MUX("CM_R to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
    			cmr_to_rmixer_controls),
    	SND_SOC_DAPM_MUX("IN1_L to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
    			in1l_to_rmixer_controls),
    	SND_SOC_DAPM_MUX("IN3_L to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
    			in3l_to_rmixer_controls),
    
    	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", AIC32X4_ADCSETUP, 7, 0),
    	SND_SOC_DAPM_MUX("IN1_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in1l_to_lmixer_controls),
    	SND_SOC_DAPM_MUX("IN2_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in2l_to_lmixer_controls),
    	SND_SOC_DAPM_MUX("IN3_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in3l_to_lmixer_controls),
    	SND_SOC_DAPM_MUX("IN1_R to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in1r_to_lmixer_controls),
    	SND_SOC_DAPM_MUX("CM_L to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
    			cml_to_lmixer_controls),
    	SND_SOC_DAPM_MUX("IN2_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
    			in2r_to_lmixer_controls),
    	SND_SOC_DAPM_MUX("IN3_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
    			in3r_to_lmixer_controls),
    
    	SND_SOC_DAPM_SUPPLY("Mic Bias", AIC32X4_MICBIAS, 6, 0, mic_bias_event,
    			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
    
    	SND_SOC_DAPM_POST("ADC Reset", aic32x4_reset_adc),
    
    	SND_SOC_DAPM_OUTPUT("HPL"),
    	SND_SOC_DAPM_OUTPUT("HPR"),
    	SND_SOC_DAPM_OUTPUT("LOL"),
    	SND_SOC_DAPM_OUTPUT("LOR"),
    	SND_SOC_DAPM_INPUT("IN1_L"),
    	SND_SOC_DAPM_INPUT("IN1_R"),
    	SND_SOC_DAPM_INPUT("IN2_L"),
    	SND_SOC_DAPM_INPUT("IN2_R"),
    	SND_SOC_DAPM_INPUT("IN3_L"),
    	SND_SOC_DAPM_INPUT("IN3_R"),
    	SND_SOC_DAPM_INPUT("CM_L"),
    	SND_SOC_DAPM_INPUT("CM_R"),
    };
    
    static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = {
    	/* Left Output */
    	{"HPL Output Mixer", "L_DAC Switch", "Left DAC"},
    	{"HPL Output Mixer", "IN1_L Switch", "IN1_L"},
    
    	{"HPL Power", NULL, "HPL Output Mixer"},
    	{"HPL", NULL, "HPL Power"},
    
    	{"LOL Output Mixer", "L_DAC Switch", "Left DAC"},
    
    	{"LOL Power", NULL, "LOL Output Mixer"},
    	{"LOL", NULL, "LOL Power"},
    
    	/* Right Output */
    	{"HPR Output Mixer", "R_DAC Switch", "Right DAC"},
    	{"HPR Output Mixer", "IN1_R Switch", "IN1_R"},
    
    	{"HPR Power", NULL, "HPR Output Mixer"},
    	{"HPR", NULL, "HPR Power"},
    
    	{"LOR Output Mixer", "R_DAC Switch", "Right DAC"},
    
    	{"LOR Power", NULL, "LOR Output Mixer"},
    	{"LOR", NULL, "LOR Power"},
    
    	/* Right Input */
    	{"Right ADC", NULL, "IN1_R to Right Mixer Positive Resistor"},
    	{"IN1_R to Right Mixer Positive Resistor", "10 kOhm", "IN1_R"},
    	{"IN1_R to Right Mixer Positive Resistor", "20 kOhm", "IN1_R"},
    	{"IN1_R to Right Mixer Positive Resistor", "40 kOhm", "IN1_R"},
    
    	{"Right ADC", NULL, "IN2_R to Right Mixer Positive Resistor"},
    	{"IN2_R to Right Mixer Positive Resistor", "10 kOhm", "IN2_R"},
    	{"IN2_R to Right Mixer Positive Resistor", "20 kOhm", "IN2_R"},
    	{"IN2_R to Right Mixer Positive Resistor", "40 kOhm", "IN2_R"},
    
    	{"Right ADC", NULL, "IN3_R to Right Mixer Positive Resistor"},
    	{"IN3_R to Right Mixer Positive Resistor", "10 kOhm", "IN3_R"},
    	{"IN3_R to Right Mixer Positive Resistor", "20 kOhm", "IN3_R"},
    	{"IN3_R to Right Mixer Positive Resistor", "40 kOhm", "IN3_R"},
    
    	{"Right ADC", NULL, "IN2_L to Right Mixer Positive Resistor"},
    	{"IN2_L to Right Mixer Positive Resistor", "10 kOhm", "IN2_L"},
    	{"IN2_L to Right Mixer Positive Resistor", "20 kOhm", "IN2_L"},
    	{"IN2_L to Right Mixer Positive Resistor", "40 kOhm", "IN2_L"},
    
    	{"Right ADC", NULL, "CM_R to Right Mixer Negative Resistor"},
    	{"CM_R to Right Mixer Negative Resistor", "10 kOhm", "CM_R"},
    	{"CM_R to Right Mixer Negative Resistor", "20 kOhm", "CM_R"},
    	{"CM_R to Right Mixer Negative Resistor", "40 kOhm", "CM_R"},
    
    	{"Right ADC", NULL, "IN1_L to Right Mixer Negative Resistor"},
    	{"IN1_L to Right Mixer Negative Resistor", "10 kOhm", "IN1_L"},
    	{"IN1_L to Right Mixer Negative Resistor", "20 kOhm", "IN1_L"},
    	{"IN1_L to Right Mixer Negative Resistor", "40 kOhm", "IN1_L"},
    
    	{"Right ADC", NULL, "IN3_L to Right Mixer Negative Resistor"},
    	{"IN3_L to Right Mixer Negative Resistor", "10 kOhm", "IN3_L"},
    	{"IN3_L to Right Mixer Negative Resistor", "20 kOhm", "IN3_L"},
    	{"IN3_L to Right Mixer Negative Resistor", "40 kOhm", "IN3_L"},
    
    	/* Left Input */
    	{"Left ADC", NULL, "IN1_L to Left Mixer Positive Resistor"},
    	{"IN1_L to Left Mixer Positive Resistor", "10 kOhm", "IN1_L"},
    	{"IN1_L to Left Mixer Positive Resistor", "20 kOhm", "IN1_L"},
    	{"IN1_L to Left Mixer Positive Resistor", "40 kOhm", "IN1_L"},
    
    	{"Left ADC", NULL, "IN2_L to Left Mixer Positive Resistor"},
    	{"IN2_L to Left Mixer Positive Resistor", "10 kOhm", "IN2_L"},
    	{"IN2_L to Left Mixer Positive Resistor", "20 kOhm", "IN2_L"},
    	{"IN2_L to Left Mixer Positive Resistor", "40 kOhm", "IN2_L"},
    
    	{"Left ADC", NULL, "IN3_L to Left Mixer Positive Resistor"},
    	{"IN3_L to Left Mixer Positive Resistor", "10 kOhm", "IN3_L"},
    	{"IN3_L to Left Mixer Positive Resistor", "20 kOhm", "IN3_L"},
    	{"IN3_L to Left Mixer Positive Resistor", "40 kOhm", "IN3_L"},
    
    	{"Left ADC", NULL, "IN1_R to Left Mixer Positive Resistor"},
    	{"IN1_R to Left Mixer Positive Resistor", "10 kOhm", "IN1_R"},
    	{"IN1_R to Left Mixer Positive Resistor", "20 kOhm", "IN1_R"},
    	{"IN1_R to Left Mixer Positive Resistor", "40 kOhm", "IN1_R"},
    
    	{"Left ADC", NULL, "CM_L to Left Mixer Negative Resistor"},
    	{"CM_L to Left Mixer Negative Resistor", "10 kOhm", "CM_L"},
    	{"CM_L to Left Mixer Negative Resistor", "20 kOhm", "CM_L"},
    	{"CM_L to Left Mixer Negative Resistor", "40 kOhm", "CM_L"},
    
    	{"Left ADC", NULL, "IN2_R to Left Mixer Negative Resistor"},
    	{"IN2_R to Left Mixer Negative Resistor", "10 kOhm", "IN2_R"},
    	{"IN2_R to Left Mixer Negative Resistor", "20 kOhm", "IN2_R"},
    	{"IN2_R to Left Mixer Negative Resistor", "40 kOhm", "IN2_R"},
    
    	{"Left ADC", NULL, "IN3_R to Left Mixer Negative Resistor"},
    	{"IN3_R to Left Mixer Negative Resistor", "10 kOhm", "IN3_R"},
    	{"IN3_R to Left Mixer Negative Resistor", "20 kOhm", "IN3_R"},
    	{"IN3_R to Left Mixer Negative Resistor", "40 kOhm", "IN3_R"},
    };
    
    static const struct regmap_range_cfg aic32x4_regmap_pages[] = {
    	{
    		.selector_reg = 0,
    		.selector_mask	= 0xff,
    		.window_start = 0,
    		.window_len = 128,
    		.range_min = 0,
    		.range_max = AIC32X4_REFPOWERUP,
    	},
    };
    
    const struct regmap_config aic32x4_regmap_config = {
    	.max_register = AIC32X4_REFPOWERUP,
    	.ranges = aic32x4_regmap_pages,
    	.num_ranges = ARRAY_SIZE(aic32x4_regmap_pages),
    };
    EXPORT_SYMBOL(aic32x4_regmap_config);
    
    static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
    				  int clk_id, unsigned int freq, int dir)
    {
    	struct snd_soc_component *component = codec_dai->component;
    	struct clk *mclk;
    	struct clk *pll;
    	dev_err(component->dev, "%s:clk_id(%d), freq(%d)\n", __FUNCTION__, clk_id, freq);
    
    	pll = devm_clk_get(component->dev, "pll");
    	if (IS_ERR(pll))
    		return PTR_ERR(pll);
    
    	mclk = clk_get_parent(pll);
    
    	return clk_set_rate(mclk, freq);
    }
    
    static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
    {
    	struct snd_soc_component *component = codec_dai->component;
    	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
    	u8 iface_reg_1 = 0;
    	u8 iface_reg_2 = 0;
    	u8 iface_reg_3 = 0;
    	dev_err(component->dev, "%s: fmt(0x%x)\n", __FUNCTION__, fmt);
    
    	/* set master/slave audio interface */
    	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
    	case SND_SOC_DAIFMT_CBM_CFM:
    		iface_reg_1 |= AIC32X4_BCLKMASTER | AIC32X4_WCLKMASTER;
    		break;
    	case SND_SOC_DAIFMT_CBS_CFS:
    		break;
    	default:
    		printk(KERN_ERR "aic32x4: invalid DAI master/slave interface\n");
    		return -EINVAL;
    	}
    
    	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
    	case SND_SOC_DAIFMT_I2S:
    		break;
    	case SND_SOC_DAIFMT_DSP_A:
    		iface_reg_1 |= (AIC32X4_DSP_MODE <<
    				AIC32X4_IFACE1_DATATYPE_SHIFT);
    		iface_reg_3 |= AIC32X4_BCLKINV_MASK; /* invert bit clock */
    		iface_reg_2 = 0x01; /* add offset 1 */
    		break;
    	case SND_SOC_DAIFMT_DSP_B:
    		iface_reg_1 |= (AIC32X4_DSP_MODE <<
    				AIC32X4_IFACE1_DATATYPE_SHIFT);
    		iface_reg_3 |= AIC32X4_BCLKINV_MASK; /* invert bit clock */
    		break;
    	case SND_SOC_DAIFMT_RIGHT_J:
    		iface_reg_1 |= (AIC32X4_RIGHT_JUSTIFIED_MODE <<
    				AIC32X4_IFACE1_DATATYPE_SHIFT);
    		break;
    	case SND_SOC_DAIFMT_LEFT_J:
    		iface_reg_1 |= (AIC32X4_LEFT_JUSTIFIED_MODE <<
    				AIC32X4_IFACE1_DATATYPE_SHIFT);
    		break;
    	default:
    		printk(KERN_ERR "aic32x4: invalid DAI interface format\n");
    		return -EINVAL;
    	}
    
    	aic32x4->fmt = fmt;
    
    	snd_soc_component_update_bits(component, AIC32X4_IFACE1,
    				AIC32X4_IFACE1_DATATYPE_MASK |
    				AIC32X4_IFACE1_MASTER_MASK, iface_reg_1);
    	snd_soc_component_update_bits(component, AIC32X4_IFACE2,
    				AIC32X4_DATA_OFFSET_MASK, iface_reg_2);
    	snd_soc_component_update_bits(component, AIC32X4_IFACE3,
    				AIC32X4_BCLKINV_MASK, iface_reg_3);
    
    	return 0;
    }
    
    static int aic32x4_set_aosr(struct snd_soc_component *component, u8 aosr)
    {
    	return snd_soc_component_write(component, AIC32X4_AOSR, aosr);
    }
    
    static int aic32x4_set_dosr(struct snd_soc_component *component, u16 dosr)
    {
    	snd_soc_component_write(component, AIC32X4_DOSRMSB, dosr >> 8);
    	snd_soc_component_write(component, AIC32X4_DOSRLSB,
    		      (dosr & 0xff));
    
    	return 0;
    }
    
    static int aic32x4_set_processing_blocks(struct snd_soc_component *component,
    						u8 r_block, u8 p_block)
    {
    	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
    
    	if (aic32x4->type == AIC32X4_TYPE_TAS2505) {
    		if (r_block || p_block > 3)
    			return -EINVAL;
    
    		snd_soc_component_write(component, AIC32X4_DACSPB, p_block);
    	} else { /* AIC32x4 */
    		if (r_block > 18 || p_block > 25)
    			return -EINVAL;
    
    		snd_soc_component_write(component, AIC32X4_ADCSPB, r_block);
    		snd_soc_component_write(component, AIC32X4_DACSPB, p_block);
    	}
    
    	return 0;
    }
    
    static int aic32x4_setup_clocks(struct snd_soc_component *component,
    				unsigned int sample_rate, unsigned int channels,
    				unsigned int bit_depth)
    {
    	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
    	u8 aosr;
    	u16 dosr;
    	u8 adc_resource_class, dac_resource_class;
    	u8 madc, nadc, mdac, ndac, max_nadc, min_mdac, max_ndac;
    	u8 dosr_increment;
    	u16 max_dosr, min_dosr;
    	unsigned long adc_clock_rate, dac_clock_rate;
    	int ret;
    
    	static struct clk_bulk_data clocks[] = {
    		{ .id = "pll" },
    		{ .id = "nadc" },
    		{ .id = "madc" },
    		{ .id = "ndac" },
    		{ .id = "mdac" },
    		{ .id = "bdiv" },
    	};
    	dev_err(component->dev, "aic32x4_setup_clocks sample_rate(%d), channels(%d), bit_depth(%d)\n", sample_rate, channels, bit_depth);
    	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
    	if (ret)
    		return ret;
    	dev_err(component->dev, "clocks[0~5].clk(%d,%d,%d,%d,%d,%d)\n", clocks[0].clk, clocks[1].clk, clocks[2].clk, clocks[3].clk, clocks[4].clk, clocks[5].clk);
    
    	if (sample_rate <= 48000) {
    		aosr = 128;
    		adc_resource_class = 6;
    		dac_resource_class = 8;
    		dosr_increment = 8;
    		if (aic32x4->type == AIC32X4_TYPE_TAS2505)
    			aic32x4_set_processing_blocks(component, 0, 1);
    		else
    			aic32x4_set_processing_blocks(component, 1, 1);
    	} else if (sample_rate <= 96000) {
    		aosr = 64;
    		adc_resource_class = 6;
    		dac_resource_class = 8;
    		dosr_increment = 4;
    		if (aic32x4->type == AIC32X4_TYPE_TAS2505)
    			aic32x4_set_processing_blocks(component, 0, 1);
    		else
    			aic32x4_set_processing_blocks(component, 1, 9);
    	} else if (sample_rate == 192000) {
    		aosr = 32;
    		adc_resource_class = 3;
    		dac_resource_class = 4;
    		dosr_increment = 2;
    		if (aic32x4->type == AIC32X4_TYPE_TAS2505)
    			aic32x4_set_processing_blocks(component, 0, 1);
    		else
    			aic32x4_set_processing_blocks(component, 13, 19);
    	} else {
    		dev_err(component->dev, "Sampling rate not supported\n");
    		return -EINVAL;
    	}
    	dev_err(component->dev, "aic32x4->fmt(0x%x)\n", aic32x4->fmt );
    
    	/* PCM over I2S is always 2-channel */
    	if ((aic32x4->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S)
    		channels = 2;
    
    	madc = DIV_ROUND_UP((32 * adc_resource_class), aosr);
    	max_dosr = (AIC32X4_MAX_DOSR_FREQ / sample_rate / dosr_increment) *
    			dosr_increment;
    	min_dosr = (AIC32X4_MIN_DOSR_FREQ / sample_rate / dosr_increment) *
    			dosr_increment;
    	max_nadc = AIC32X4_MAX_CODEC_CLKIN_FREQ / (madc * aosr * sample_rate);
    
    	dev_err(component->dev, "aosr(%d), adc_resource_class(%d), dac_resource_class(%d), dosr_increment(%d)\n", aosr, adc_resource_class, dac_resource_class, dosr_increment);
    		
    	dev_err(component->dev, "madc(%d), max_dosr(%d), min_dosr(%d), max_nadc(%d)\n", madc, max_dosr, min_dosr, max_nadc);
    
    	for (nadc = max_nadc; nadc > 0; --nadc) {
    		adc_clock_rate = nadc * madc * aosr * sample_rate;
    		dev_err(component->dev, "adc_clock_rate(%d x %d x %d)(%d)\n", nadc, madc, aosr, adc_clock_rate);
    		for (dosr = max_dosr; dosr >= min_dosr;
    				dosr -= dosr_increment) {
    			min_mdac = DIV_ROUND_UP((32 * dac_resource_class), dosr);
    			max_ndac = AIC32X4_MAX_CODEC_CLKIN_FREQ /
    					(min_mdac * dosr * sample_rate);
    			dev_err(component->dev, "min_mdac %d=DIV_ROUND_UP((32 * %d), %d)=\n", min_mdac, dac_resource_class, dosr);
    			dev_err(component->dev, "max_ndac %d= %d /(%d * %d * %d)\n", max_ndac,AIC32X4_MAX_CODEC_CLKIN_FREQ, min_mdac, dosr, sample_rate);
    			for (mdac = min_mdac; mdac <= 128; ++mdac) {
    				for (ndac = max_ndac; ndac > 0; --ndac) {
    					dac_clock_rate = ndac * mdac * dosr *
    							sample_rate;
    					if (dac_clock_rate == adc_clock_rate) {
    						dev_err(component->dev, "                                  dac_clock_rate(%d x %d x %d)(%d)\n", ndac, mdac, dosr, dac_clock_rate);
    						if (clk_round_rate(clocks[0].clk, dac_clock_rate) == 0)
    							continue;
    
    						clk_set_rate(clocks[0].clk,
    							dac_clock_rate);
    
    						clk_set_rate(clocks[1].clk,
    							sample_rate * aosr *
    							madc);
    						clk_set_rate(clocks[2].clk,
    							sample_rate * aosr);
    						aic32x4_set_aosr(component,
    							aosr);
    
    						clk_set_rate(clocks[3].clk,
    							sample_rate * dosr *
    							mdac);
    						clk_set_rate(clocks[4].clk,
    							sample_rate * dosr);
    						aic32x4_set_dosr(component,
    							dosr);
    
    						clk_set_rate(clocks[5].clk,
    							sample_rate * channels *
    							bit_depth);
    
    						return 0;
    					}
    				}
    			}
    		}
    	}
    
    	dev_err(component->dev,
    		"Could not set clocks to support sample rate.\n");
    	return -EINVAL;
    }
    
    static int aic32x4_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 aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
    	u8 iface1_reg = 0;
    	u8 dacsetup_reg = 0;
    	dev_err(component->dev, "%s:\n", __FUNCTION__ );
    	aic32x4_setup_clocks(component, params_rate(params),
    			     params_channels(params),
    			     params_physical_width(params));
    
    	switch (params_physical_width(params)) {
    	case 16:
    		iface1_reg |= (AIC32X4_WORD_LEN_16BITS <<
    				   AIC32X4_IFACE1_DATALEN_SHIFT);
    		break;
    	case 20:
    		iface1_reg |= (AIC32X4_WORD_LEN_20BITS <<
    				   AIC32X4_IFACE1_DATALEN_SHIFT);
    		break;
    	case 24:
    		iface1_reg |= (AIC32X4_WORD_LEN_24BITS <<
    				   AIC32X4_IFACE1_DATALEN_SHIFT);
    		break;
    	case 32:
    		iface1_reg |= (AIC32X4_WORD_LEN_32BITS <<
    				   AIC32X4_IFACE1_DATALEN_SHIFT);
    		break;
    	}
    	snd_soc_component_update_bits(component, AIC32X4_IFACE1,
    				AIC32X4_IFACE1_DATALEN_MASK, iface1_reg);
    
    	if (params_channels(params) == 1) {
    		dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN;
    	} else {
    		if (aic32x4->swapdacs)
    			dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2RCHN;
    		else
    			dacsetup_reg = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN;
    	}
    	snd_soc_component_update_bits(component, AIC32X4_DACSETUP,
    				AIC32X4_DAC_CHAN_MASK, dacsetup_reg);
    
    	return 0;
    }
    
    static int aic32x4_mute(struct snd_soc_dai *dai, int mute, int direction)
    {
    	struct snd_soc_component *component = dai->component;
    	dev_err(component->dev, "%s:\n", __FUNCTION__ );
    
    	snd_soc_component_update_bits(component, AIC32X4_DACMUTE,
    				AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0);
    
    	return 0;
    }
    
    static int aic32x4_set_bias_level(struct snd_soc_component *component,
    				  enum snd_soc_bias_level level)
    {
    	int ret;
    
    	static struct clk_bulk_data clocks[] = {
    		{ .id = "madc" },
    		{ .id = "mdac" },
    		{ .id = "bdiv" },
    	};
    	dev_err(component->dev, "%s:\n", __FUNCTION__ );
    
    	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
    	if (ret)
    		return ret;
    
    	switch (level) {
    	case SND_SOC_BIAS_ON:
    		ret = clk_bulk_prepare_enable(ARRAY_SIZE(clocks), clocks);
    		if (ret) {
    			dev_err(component->dev, "Failed to enable clocks\n");
    			return ret;
    		}
    		break;
    	case SND_SOC_BIAS_PREPARE:
    		break;
    	case SND_SOC_BIAS_STANDBY:
    		/* Initial cold start */
    		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
    			break;
    
    		clk_bulk_disable_unprepare(ARRAY_SIZE(clocks), clocks);
    		break;
    	case SND_SOC_BIAS_OFF:
    		break;
    	}
    	return 0;
    }
    
    #define AIC32X4_RATES	SNDRV_PCM_RATE_8000_192000
    #define AIC32X4_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 aic32x4_ops = {
    	.hw_params = aic32x4_hw_params,
    	.mute_stream = aic32x4_mute,
    	.set_fmt = aic32x4_set_dai_fmt,
    	.set_sysclk = aic32x4_set_dai_sysclk,
    	.no_capture_mute = 1,
    };
    
    static struct snd_soc_dai_driver aic32x4_dai = {
    	.name = "tlv320aic32x4-hifi",
    	.playback = {
    			 .stream_name = "Playback",
    			 .channels_min = 1,
    			 .channels_max = 2,
    			 .rates = AIC32X4_RATES,
    			 .formats = AIC32X4_FORMATS,},
    	.capture = {
    			.stream_name = "Capture",
    			.channels_min = 1,
    			.channels_max = 8,
    			.rates = AIC32X4_RATES,
    			.formats = AIC32X4_FORMATS,},
    	.ops = &aic32x4_ops,
    	.symmetric_rate = 1,
    };
    
    static void aic32x4_setup_gpios(struct snd_soc_component *component)
    {
    	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
    
    	/* setup GPIO functions */
    	/* MFP1 */
    	if (aic32x4->setup->gpio_func[0] != AIC32X4_MFPX_DEFAULT_VALUE) {
    		snd_soc_component_write(component, AIC32X4_DINCTL,
    			  aic32x4->setup->gpio_func[0]);
    		snd_soc_add_component_controls(component, aic32x4_mfp1,
    			ARRAY_SIZE(aic32x4_mfp1));
    	}
    
    	/* MFP2 */
    	if (aic32x4->setup->gpio_func[1] != AIC32X4_MFPX_DEFAULT_VALUE) {
    		snd_soc_component_write(component, AIC32X4_DOUTCTL,
    			  aic32x4->setup->gpio_func[1]);
    		snd_soc_add_component_controls(component, aic32x4_mfp2,
    			ARRAY_SIZE(aic32x4_mfp2));
    	}
    
    	/* MFP3 */
    	if (aic32x4->setup->gpio_func[2] != AIC32X4_MFPX_DEFAULT_VALUE) {
    		snd_soc_component_write(component, AIC32X4_SCLKCTL,
    			  aic32x4->setup->gpio_func[2]);
    		snd_soc_add_component_controls(component, aic32x4_mfp3,
    			ARRAY_SIZE(aic32x4_mfp3));
    	}
    
    	/* MFP4 */
    	if (aic32x4->setup->gpio_func[3] != AIC32X4_MFPX_DEFAULT_VALUE) {
    		snd_soc_component_write(component, AIC32X4_MISOCTL,
    			  aic32x4->setup->gpio_func[3]);
    		snd_soc_add_component_controls(component, aic32x4_mfp4,
    			ARRAY_SIZE(aic32x4_mfp4));
    	}
    
    	/* MFP5 */
    	if (aic32x4->setup->gpio_func[4] != AIC32X4_MFPX_DEFAULT_VALUE) {
    		snd_soc_component_write(component, AIC32X4_GPIOCTL,
    			  aic32x4->setup->gpio_func[4]);
    		snd_soc_add_component_controls(component, aic32x4_mfp5,
    			ARRAY_SIZE(aic32x4_mfp5));
    	}
    }
    
    static int aic32x4_component_probe(struct snd_soc_component *component)
    {
    	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
    	u32 tmp_reg;
    	int ret;
    
    	static struct clk_bulk_data clocks[] = {
    		{ .id = "codec_clkin" },
    		{ .id = "pll" },
    		{ .id = "bdiv" },
    		{ .id = "mdac" },
    	};
    	dev_err(component->dev, "%s:\n", __FUNCTION__ );
    
    	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
    	if (ret)
    		return ret;
    
    	if (aic32x4->setup)
    		aic32x4_setup_gpios(component);
    
    	clk_set_parent(clocks[0].clk, clocks[1].clk);
    	clk_set_parent(clocks[2].clk, clocks[3].clk);
    
    	/* Power platform configuration */
    	if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) {
    		snd_soc_component_write(component, AIC32X4_MICBIAS,
    				AIC32X4_MICBIAS_LDOIN | AIC32X4_MICBIAS_2075V);
    	}
    	if (aic32x4->power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE)
    		snd_soc_component_write(component, AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE);
    
    	tmp_reg = (aic32x4->power_cfg & AIC32X4_PWR_AIC32X4_LDO_ENABLE) ?
    			AIC32X4_LDOCTLEN : 0;
    	snd_soc_component_write(component, AIC32X4_LDOCTL, tmp_reg);
    
    	tmp_reg = snd_soc_component_read(component, AIC32X4_CMMODE);
    	if (aic32x4->power_cfg & AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36)
    		tmp_reg |= AIC32X4_LDOIN_18_36;
    	if (aic32x4->power_cfg & AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED)
    		tmp_reg |= AIC32X4_LDOIN2HP;
    	snd_soc_component_write(component, AIC32X4_CMMODE, tmp_reg);
    
    	/* Mic PGA routing */
    	if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K)
    		snd_soc_component_write(component, AIC32X4_LMICPGANIN,
    				AIC32X4_LMICPGANIN_IN2R_10K);
    	else
    		snd_soc_component_write(component, AIC32X4_LMICPGANIN,
    				AIC32X4_LMICPGANIN_CM1L_10K);
    	if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K)
    		snd_soc_component_write(component, AIC32X4_RMICPGANIN,
    				AIC32X4_RMICPGANIN_IN1L_10K);
    	else
    		snd_soc_component_write(component, AIC32X4_RMICPGANIN,
    				AIC32X4_RMICPGANIN_CM1R_10K);
    
    	/*
    	 * Workaround: for an unknown reason, the ADC needs to be powered up
    	 * and down for the first capture to work properly. It seems related to
    	 * a HW BUG or some kind of behavior not documented in the datasheet.
    	 */
    	tmp_reg = snd_soc_component_read(component, AIC32X4_ADCSETUP);
    	snd_soc_component_write(component, AIC32X4_ADCSETUP, tmp_reg |
    				AIC32X4_LADC_EN | AIC32X4_RADC_EN);
    	snd_soc_component_write(component, AIC32X4_ADCSETUP, tmp_reg);
    
    	/*
    	 * Enable the fast charging feature and ensure the needed 40ms ellapsed
    	 * before using the analog circuits.
    	 */
    	snd_soc_component_write(component, AIC32X4_REFPOWERUP,
    				AIC32X4_REFPOWERUP_40MS);
    	msleep(40);
    
    	return 0;
    }
    
    static const struct snd_soc_component_driver soc_component_dev_aic32x4 = {
    	.probe			= aic32x4_component_probe,
    	.set_bias_level		= aic32x4_set_bias_level,
    	.controls		= aic32x4_snd_controls,
    	.num_controls		= ARRAY_SIZE(aic32x4_snd_controls),
    	.dapm_widgets		= aic32x4_dapm_widgets,
    	.num_dapm_widgets	= ARRAY_SIZE(aic32x4_dapm_widgets),
    	.dapm_routes		= aic32x4_dapm_routes,
    	.num_dapm_routes	= ARRAY_SIZE(aic32x4_dapm_routes),
    	.suspend_bias_off	= 1,
    	.idle_bias_on		= 1,
    	.use_pmdown_time	= 1,
    	.endianness		= 1,
    	.non_legacy_dai_naming	= 1,
    };
    
    static const struct snd_kcontrol_new aic32x4_tas2505_snd_controls[] = {
    	SOC_SINGLE_S8_TLV("PCM Playback Volume",
    			  AIC32X4_LDACVOL, -0x7f, 0x30, tlv_pcm),
    	SOC_ENUM("DAC Playback PowerTune Switch", l_ptm_enum),
    
    	SOC_SINGLE_TLV("HP Driver Gain Volume",
    			AIC32X4_HPLGAIN, 0, 0x74, 1, tlv_tas_driver_gain),
    	SOC_SINGLE("HP DAC Playback Switch", AIC32X4_HPLGAIN, 6, 1, 1),
    
    	SOC_SINGLE_TLV("Speaker Driver Playback Volume",
    			TAS2505_SPKVOL1, 0, 0x74, 1, tlv_tas_driver_gain),
    	SOC_SINGLE_TLV("Speaker Amplifier Playback Volume",
    			TAS2505_SPKVOL2, 4, 5, 0, tlv_amp_vol),
    
    	SOC_SINGLE("Auto-mute Switch", AIC32X4_DACMUTE, 4, 7, 0),
    };
    
    static const struct snd_kcontrol_new hp_output_mixer_controls[] = {
    	SOC_DAPM_SINGLE("DAC Switch", AIC32X4_HPLROUTE, 3, 1, 0),
    };
    
    static const struct snd_soc_dapm_widget aic32x4_tas2505_dapm_widgets[] = {
    	SND_SOC_DAPM_DAC("DAC", "Playback", AIC32X4_DACSETUP, 7, 0),
    	SND_SOC_DAPM_MIXER("HP Output Mixer", SND_SOC_NOPM, 0, 0,
    			   &hp_output_mixer_controls[0],
    			   ARRAY_SIZE(hp_output_mixer_controls)),
    	SND_SOC_DAPM_PGA("HP Power", AIC32X4_OUTPWRCTL, 5, 0, NULL, 0),
    
    	SND_SOC_DAPM_PGA("Speaker Driver", TAS2505_SPK, 1, 0, NULL, 0),
    
    	SND_SOC_DAPM_OUTPUT("HP"),
    	SND_SOC_DAPM_OUTPUT("Speaker"),
    };
    
    static const struct snd_soc_dapm_route aic32x4_tas2505_dapm_routes[] = {
    	/* Left Output */
    	{"HP Output Mixer", "DAC Switch", "DAC"},
    
    	{"HP Power", NULL, "HP Output Mixer"},
    	{"HP", NULL, "HP Power"},
    
    	{"Speaker Driver", NULL, "DAC"},
    	{"Speaker", NULL, "Speaker Driver"},
    };
    
    static struct snd_soc_dai_driver aic32x4_tas2505_dai = {
    	.name = "tas2505-hifi",
    	.playback = {
    			 .stream_name = "Playback",
    			 .channels_min = 1,
    			 .channels_max = 2,
    			 .rates = SNDRV_PCM_RATE_8000_96000,
    			 .formats = AIC32X4_FORMATS,},
    	.ops = &aic32x4_ops,
    	.symmetric_rate = 1,
    };
    
    static int aic32x4_tas2505_component_probe(struct snd_soc_component *component)
    {
    	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
    	u32 tmp_reg;
    	int ret;
    
    	static struct clk_bulk_data clocks[] = {
    		{ .id = "codec_clkin" },
    		{ .id = "pll" },
    		{ .id = "bdiv" },
    		{ .id = "mdac" },
    	};
    
    	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
    	if (ret)
    		return ret;
    
    	if (aic32x4->setup)
    		aic32x4_setup_gpios(component);
    
    	clk_set_parent(clocks[0].clk, clocks[1].clk);
    	clk_set_parent(clocks[2].clk, clocks[3].clk);
    
    	/* Power platform configuration */
    	if (aic32x4->power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE)
    		snd_soc_component_write(component, AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE);
    
    	tmp_reg = (aic32x4->power_cfg & AIC32X4_PWR_AIC32X4_LDO_ENABLE) ?
    			AIC32X4_LDOCTLEN : 0;
    	snd_soc_component_write(component, AIC32X4_LDOCTL, tmp_reg);
    
    	tmp_reg = snd_soc_component_read(component, AIC32X4_CMMODE);
    	if (aic32x4->power_cfg & AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36)
    		tmp_reg |= AIC32X4_LDOIN_18_36;
    	if (aic32x4->power_cfg & AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED)
    		tmp_reg |= AIC32X4_LDOIN2HP;
    	snd_soc_component_write(component, AIC32X4_CMMODE, tmp_reg);
    
    	/*
    	 * Enable the fast charging feature and ensure the needed 40ms ellapsed
    	 * before using the analog circuits.
    	 */
    	snd_soc_component_write(component, TAS2505_REFPOWERUP,
    				AIC32X4_REFPOWERUP_40MS);
    	msleep(40);
    
    	return 0;
    }
    
    static const struct snd_soc_component_driver soc_component_dev_aic32x4_tas2505 = {
    	.probe			= aic32x4_tas2505_component_probe,
    	.set_bias_level		= aic32x4_set_bias_level,
    	.controls		= aic32x4_tas2505_snd_controls,
    	.num_controls		= ARRAY_SIZE(aic32x4_tas2505_snd_controls),
    	.dapm_widgets		= aic32x4_tas2505_dapm_widgets,
    	.num_dapm_widgets	= ARRAY_SIZE(aic32x4_tas2505_dapm_widgets),
    	.dapm_routes		= aic32x4_tas2505_dapm_routes,
    	.num_dapm_routes	= ARRAY_SIZE(aic32x4_tas2505_dapm_routes),
    	.suspend_bias_off	= 1,
    	.idle_bias_on		= 1,
    	.use_pmdown_time	= 1,
    	.endianness		= 1,
    	.non_legacy_dai_naming	= 1,
    };
    
    static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4,
    		struct device_node *np)
    {
    	struct aic32x4_setup_data *aic32x4_setup;
    //	int ret;
    
    	aic32x4_setup = devm_kzalloc(aic32x4->dev, sizeof(*aic32x4_setup),
    							GFP_KERNEL);
    	if (!aic32x4_setup)
    		return -ENOMEM;
    
    //	ret = of_property_match_string(np, "clock-names", "mclk");
    //	if (ret < 0)
    //		return -EINVAL;
    	aic32x4->mclk_name = "mclk";//of_clk_get_parent_name(np, ret);
    
    	aic32x4->swapdacs = false;
    	aic32x4->micpga_routing = 0;
    	aic32x4->rstn_gpio = of_get_named_gpio(np, "reset-gpios", 0);
    
    	if (of_property_read_u32_array(np, "aic32x4-gpio-func",
    				aic32x4_setup->gpio_func, 5) >= 0)
    		aic32x4->setup = aic32x4_setup;
    	return 0;
    }
    
    static void aic32x4_disable_regulators(struct aic32x4_priv *aic32x4)
    {
    	regulator_disable(aic32x4->supply_iov);
    
    	if (!IS_ERR(aic32x4->supply_ldo))
    		regulator_disable(aic32x4->supply_ldo);
    
    	if (!IS_ERR(aic32x4->supply_dv))
    		regulator_disable(aic32x4->supply_dv);
    
    	if (!IS_ERR(aic32x4->supply_av))
    		regulator_disable(aic32x4->supply_av);
    }
    
    static int aic32x4_setup_regulators(struct device *dev,
    		struct aic32x4_priv *aic32x4)
    {
    	int ret = 0;
    
    	aic32x4->supply_ldo = devm_regulator_get_optional(dev, "ldoin");
    	aic32x4->supply_iov = devm_regulator_get(dev, "iov");
    	aic32x4->supply_dv = devm_regulator_get_optional(dev, "dv");
    	aic32x4->supply_av = devm_regulator_get_optional(dev, "av");
    
    	/* Check if the regulator requirements are fulfilled */
    
    	if (IS_ERR(aic32x4->supply_iov)) {
    		dev_err(dev, "Missing supply 'iov'\n");
    		return PTR_ERR(aic32x4->supply_iov);
    	}
    
    	if (IS_ERR(aic32x4->supply_ldo)) {
    		if (PTR_ERR(aic32x4->supply_ldo) == -EPROBE_DEFER)
    			return -EPROBE_DEFER;
    
    		if (IS_ERR(aic32x4->supply_dv)) {
    			dev_err(dev, "Missing supply 'dv' or 'ldoin'\n");
    			return PTR_ERR(aic32x4->supply_dv);
    		}
    		if (IS_ERR(aic32x4->supply_av)) {
    			dev_err(dev, "Missing supply 'av' or 'ldoin'\n");
    			return PTR_ERR(aic32x4->supply_av);
    		}
    	} else {
    		if (PTR_ERR(aic32x4->supply_dv) == -EPROBE_DEFER)
    			return -EPROBE_DEFER;
    		if (PTR_ERR(aic32x4->supply_av) == -EPROBE_DEFER)
    			return -EPROBE_DEFER;
    	}
    
    	ret = regulator_enable(aic32x4->supply_iov);
    	if (ret) {
    		dev_err(dev, "Failed to enable regulator iov\n");
    		return ret;
    	}
    
    	if (!IS_ERR(aic32x4->supply_ldo)) {
    		ret = regulator_enable(aic32x4->supply_ldo);
    		if (ret) {
    			dev_err(dev, "Failed to enable regulator ldo\n");
    			goto error_ldo;
    		}
    	}
    
    	if (!IS_ERR(aic32x4->supply_dv)) {
    		ret = regulator_enable(aic32x4->supply_dv);
    		if (ret) {
    			dev_err(dev, "Failed to enable regulator dv\n");
    			goto error_dv;
    		}
    	}
    
    	if (!IS_ERR(aic32x4->supply_av)) {
    		ret = regulator_enable(aic32x4->supply_av);
    		if (ret) {
    			dev_err(dev, "Failed to enable regulator av\n");
    			goto error_av;
    		}
    	}
    
    	if (!IS_ERR(aic32x4->supply_ldo) && IS_ERR(aic32x4->supply_av))
    		aic32x4->power_cfg |= AIC32X4_PWR_AIC32X4_LDO_ENABLE;
    
    	return 0;
    
    error_av:
    	if (!IS_ERR(aic32x4->supply_dv))
    		regulator_disable(aic32x4->supply_dv);
    
    error_dv:
    	if (!IS_ERR(aic32x4->supply_ldo))
    		regulator_disable(aic32x4->supply_ldo);
    
    error_ldo:
    	regulator_disable(aic32x4->supply_iov);
    	return ret;
    }
    
    int aic32x4_probe(struct device *dev, struct regmap *regmap)
    {
    	struct aic32x4_priv *aic32x4;
    	struct aic32x4_pdata *pdata = dev->platform_data;
    	struct device_node *np = dev->of_node;
    	int ret;
    	dev_err(dev, "aic32x4_probe\n");
    	if (IS_ERR(regmap))
    		return PTR_ERR(regmap);
    
    	aic32x4 = devm_kzalloc(dev, sizeof(struct aic32x4_priv),
    				   GFP_KERNEL);
    	if (aic32x4 == NULL)
    		return -ENOMEM;
    
    	aic32x4->dev = dev;
    	aic32x4->type = (enum aic32x4_type)dev_get_drvdata(dev);
    
    	dev_set_drvdata(dev, aic32x4);
    
    	if (pdata) {
    		aic32x4->power_cfg = pdata->power_cfg;
    		aic32x4->swapdacs = pdata->swapdacs;
    		aic32x4->micpga_routing = pdata->micpga_routing;
    		aic32x4->rstn_gpio = pdata->rstn_gpio;
    		aic32x4->mclk_name = "mclk";
    	} else if (np) {
    		ret = aic32x4_parse_dt(aic32x4, np);
    		if (ret) {
    			dev_err(dev, "Failed to parse DT node\n");
    			return ret;
    		}
    	} else {
    		aic32x4->power_cfg = 0;
    		aic32x4->swapdacs = false;
    		aic32x4->micpga_routing = 0;
    		aic32x4->rstn_gpio = -1;
    		aic32x4->mclk_name = "mclk";
    	}
    	dev_err(dev, "aic32x4->rstn_gpio (%d)\n", aic32x4->rstn_gpio);
    	if (gpio_is_valid(aic32x4->rstn_gpio)) {
    		ret = devm_gpio_request_one(dev, aic32x4->rstn_gpio,
    				GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn");
    		if (ret != 0)
    			return ret;
    	}
    	dev_err(dev, "aic32x4_setup_regulators\n");
    	ret = aic32x4_setup_regulators(dev, aic32x4);
    	if (ret) {
    		dev_err(dev, "Failed to setup regulators\n");
    		return ret;
    	}
    
    	if (gpio_is_valid(aic32x4->rstn_gpio)) {
    		ndelay(10);
    		gpio_set_value_cansleep(aic32x4->rstn_gpio, 1);
    		mdelay(1);
    	}
    	dev_err(dev, "regmap_write AIC32X4_RESET\n");
    	ret = regmap_write(regmap, AIC32X4_RESET, 0x01);
    	if (ret){
    		dev_err(dev, "Failed to regmap_write AIC32X4_RESET\n");
    		goto err_disable_regulators;
    	}
    
    	ret = aic32x4_register_clocks(dev, aic32x4->mclk_name);
    	if (ret){
    		dev_err(dev, "Failed to aic32x4_register_clocks\n");
    		goto err_disable_regulators;
    	}
    
    	switch (aic32x4->type) {
    	case AIC32X4_TYPE_TAS2505:
    		ret = devm_snd_soc_register_component(dev,
    			&soc_component_dev_aic32x4_tas2505, &aic32x4_tas2505_dai, 1);
    		break;
    	default:
    		ret = devm_snd_soc_register_component(dev,
    			&soc_component_dev_aic32x4, &aic32x4_dai, 1);
    	}
    
    	if (ret) {
    		dev_err(dev, "Failed to register component\n");
    		goto err_disable_regulators;
    	}
    	dev_err(dev, "aic32x4_probe done\n");
    	return 0;
    
    err_disable_regulators:
    	aic32x4_disable_regulators(aic32x4);
    
    	return ret;
    }
    EXPORT_SYMBOL(aic32x4_probe);
    
    int aic32x4_remove(struct device *dev)
    {
    	struct aic32x4_priv *aic32x4 = dev_get_drvdata(dev);
    
    	aic32x4_disable_regulators(aic32x4);
    
    	return 0;
    }
    EXPORT_SYMBOL(aic32x4_remove);
    
    MODULE_DESCRIPTION("ASoC tlv320aic32x4 codec driver");
    MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
    MODULE_LICENSE("GPL");
    
    tlv320aic32x4-clk.c
    /* SPDX-License-Identifier: GPL-2.0
     *
     * Clock Tree for the Texas Instruments TLV320AIC32x4
     *
     * Copyright 2019 Annaliese McDermond
     *
     * Author: Annaliese McDermond <nh6z@nh6z.net>
     */
    
    #include <linux/clk-provider.h>
    #include <linux/clkdev.h>
    #include <linux/regmap.h>
    #include <linux/device.h>
    
    #include "tlv320aic32x4.h"
    
    #define to_clk_aic32x4(_hw) container_of(_hw, struct clk_aic32x4, hw)
    struct clk_aic32x4 {
    	struct clk_hw hw;
    	struct device *dev;
    	struct regmap *regmap;
    	unsigned int reg;
    };
    
    /*
     * struct clk_aic32x4_pll_muldiv - Multiplier/divider settings
     * @p:		Divider
     * @r:		first multiplier
     * @j:		integer part of second multiplier
     * @d:		decimal part of second multiplier
     */
    struct clk_aic32x4_pll_muldiv {
    	u8 p;
    	u16 r;
    	u8 j;
    	u16 d;
    };
    
    struct aic32x4_clkdesc {
    	const char *name;
    	const char * const *parent_names;
    	unsigned int num_parents;
    	const struct clk_ops *ops;
    	unsigned int reg;
    };
    
    static int clk_aic32x4_pll_prepare(struct clk_hw *hw)
    {
    	struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
    
    	dev_err(pll->dev, "%s\n", __FUNCTION__);
    	return regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
    				AIC32X4_PLLEN, AIC32X4_PLLEN);
    }
    
    static void clk_aic32x4_pll_unprepare(struct clk_hw *hw)
    {
    	struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
    
    	dev_err(pll->dev, "%s\n", __FUNCTION__);
    	regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
    				AIC32X4_PLLEN, 0);
    }
    
    static int clk_aic32x4_pll_is_prepared(struct clk_hw *hw)
    {
    	struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
    
    	unsigned int val;
    	int ret;
    
    	dev_err(pll->dev, "%s\n", __FUNCTION__);
    	ret = regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
    	if (ret < 0)
    		return ret;
    
    	return !!(val & AIC32X4_PLLEN);
    }
    
    static int clk_aic32x4_pll_get_muldiv(struct clk_aic32x4 *pll,
    			struct clk_aic32x4_pll_muldiv *settings)
    {
    	/*	Change to use regmap_bulk_read? */
    	unsigned int val;
    	int ret;
    
    	ret = regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
    	if (ret < 0)
    		return ret;
    	settings->r = val & AIC32X4_PLL_R_MASK;
    	settings->p = (val & AIC32X4_PLL_P_MASK) >> AIC32X4_PLL_P_SHIFT;
    
    	ret = regmap_read(pll->regmap, AIC32X4_PLLJ, &val);
    	if (ret < 0)
    		return ret;
    	settings->j = val;
    
    	ret = regmap_read(pll->regmap, AIC32X4_PLLDMSB, &val);
    	if (ret < 0)
    		return ret;
    	settings->d = val << 8;
    
    	ret = regmap_read(pll->regmap, AIC32X4_PLLDLSB,	 &val);
    	if (ret < 0)
    		return ret;
    	settings->d |= val;
    
    	return 0;
    }
    
    static int clk_aic32x4_pll_set_muldiv(struct clk_aic32x4 *pll,
    			struct clk_aic32x4_pll_muldiv *settings)
    {
    	int ret;
    	/*	Change to use regmap_bulk_write for some if not all? */
    
    	ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
    				AIC32X4_PLL_R_MASK, settings->r);
    	if (ret < 0)
    		return ret;
    
    	ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
    				AIC32X4_PLL_P_MASK,
    				settings->p << AIC32X4_PLL_P_SHIFT);
    	if (ret < 0)
    		return ret;
    
    	ret = regmap_write(pll->regmap, AIC32X4_PLLJ, settings->j);
    	if (ret < 0)
    		return ret;
    
    	ret = regmap_write(pll->regmap, AIC32X4_PLLDMSB, (settings->d >> 8));
    	if (ret < 0)
    		return ret;
    	ret = regmap_write(pll->regmap, AIC32X4_PLLDLSB, (settings->d & 0xff));
    	if (ret < 0)
    		return ret;
    
    	return 0;
    }
    
    static unsigned long clk_aic32x4_pll_calc_rate(
    			struct clk_aic32x4_pll_muldiv *settings,
    			unsigned long parent_rate)
    {
    	u64 rate;
    	/*
    	 * We scale j by 10000 to account for the decimal part of P and divide
    	 * it back out later.
    	 */
    	rate = (u64) parent_rate * settings->r *
    				((settings->j * 10000) + settings->d);
    
    	return (unsigned long) DIV_ROUND_UP_ULL(rate, settings->p * 10000);
    }
    
    static int clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv *settings,
    			unsigned long rate, unsigned long parent_rate)
    {
    	u64 multiplier;
    
    	settings->p = parent_rate / AIC32X4_MAX_PLL_CLKIN + 1;
    	if (settings->p > 8)
    		return -1;
    
    	/*
    	 * We scale this figure by 10000 so that we can get the decimal part
    	 * of the multiplier.	This is because we can't do floating point
    	 * math in the kernel.
    	 */
    	multiplier = (u64) rate * settings->p * 10000;
    	do_div(multiplier, parent_rate);
    
    	/*
    	 * J can't be over 64, so R can scale this.
    	 * R can't be greater than 4.
    	 */
    	settings->r = ((u32) multiplier / 640000) + 1;
    	if (settings->r > 4)
    		return -1;
    	do_div(multiplier, settings->r);
    
    	/*
    	 * J can't be < 1.
    	 */
    	if (multiplier < 10000)
    		return -1;
    
    	/* Figure out the integer part, J, and the fractional part, D. */
    	settings->j = (u32) multiplier / 10000;
    	settings->d = (u32) multiplier % 10000;
    
    	return 0;
    }
    
    static unsigned long clk_aic32x4_pll_recalc_rate(struct clk_hw *hw,
    			unsigned long parent_rate)
    {
    	struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
    	struct clk_aic32x4_pll_muldiv settings;
    	int ret;
    
    	dev_err(pll->dev, "%s, parent_rate(%d)\n", __FUNCTION__, parent_rate);
    	ret =  clk_aic32x4_pll_get_muldiv(pll, &settings);
    	if (ret < 0)
    		return 0;
    
    	return clk_aic32x4_pll_calc_rate(&settings, parent_rate);
    }
    
    static long clk_aic32x4_pll_round_rate(struct clk_hw *hw,
    			unsigned long rate,
    			unsigned long *parent_rate)
    {
    	struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
    	struct clk_aic32x4_pll_muldiv settings;
    	int ret;
    
    	dev_err(pll->dev, "%s, rate(%d), parent_rate(%d)\n", __FUNCTION__, rate, parent_rate);
    	ret = clk_aic32x4_pll_calc_muldiv(&settings, rate, *parent_rate);
    	if (ret < 0)
    		return 0;
    
    	return clk_aic32x4_pll_calc_rate(&settings, *parent_rate);
    }
    
    static int clk_aic32x4_pll_set_rate(struct clk_hw *hw,
    			unsigned long rate,
    			unsigned long parent_rate)
    {
    	struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
    	struct clk_aic32x4_pll_muldiv settings;
    	int ret;
    
    	dev_err(pll->dev, "%s, rate(%d), parent_rate(%d)\n", __FUNCTION__, rate, parent_rate);
    	ret = clk_aic32x4_pll_calc_muldiv(&settings, rate, parent_rate);
    	if (ret < 0)
    		return -EINVAL;
    
    	ret = clk_aic32x4_pll_set_muldiv(pll, &settings);
    	if (ret)
    		return ret;
    
    	/* 10ms is the delay to wait before the clocks are stable */
    	msleep(10);
    
    	return 0;
    }
    
    static int clk_aic32x4_pll_set_parent(struct clk_hw *hw, u8 index)
    {
    	struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
    
    	dev_err(pll->dev, "%s, index(%d)\n", __FUNCTION__, index);
    	//index = 1;/* set pll parent to be BLCK*/
    	return regmap_update_bits(pll->regmap,
    				AIC32X4_CLKMUX,
    				AIC32X4_PLL_CLKIN_MASK,
    				index << AIC32X4_PLL_CLKIN_SHIFT);
    }
    
    static u8 clk_aic32x4_pll_get_parent(struct clk_hw *hw)
    {
    	struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
    	unsigned int val;
    
    	regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
    	dev_err(pll->dev, "%s,%s index(%d)\n", __FUNCTION__, dev_name(pll->dev), (val & AIC32X4_PLL_CLKIN_MASK) >> AIC32X4_PLL_CLKIN_SHIFT);
    
    	return (val & AIC32X4_PLL_CLKIN_MASK) >> AIC32X4_PLL_CLKIN_SHIFT;
    }
    
    
    static const struct clk_ops aic32x4_pll_ops = {
    	.prepare = clk_aic32x4_pll_prepare,
    	.unprepare = clk_aic32x4_pll_unprepare,
    	.is_prepared = clk_aic32x4_pll_is_prepared,
    	.recalc_rate = clk_aic32x4_pll_recalc_rate,
    	.round_rate = clk_aic32x4_pll_round_rate,
    	.set_rate = clk_aic32x4_pll_set_rate,
    	.set_parent = clk_aic32x4_pll_set_parent,
    	.get_parent = clk_aic32x4_pll_get_parent,
    };
    
    static int clk_aic32x4_codec_clkin_set_parent(struct clk_hw *hw, u8 index)
    {
    	struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
    
    	dev_err(mux->dev, "%s, index(%d)\n", __FUNCTION__, index);
    	return regmap_update_bits(mux->regmap,
    		AIC32X4_CLKMUX,
    		AIC32X4_CODEC_CLKIN_MASK, index << AIC32X4_CODEC_CLKIN_SHIFT);
    }
    
    static u8 clk_aic32x4_codec_clkin_get_parent(struct clk_hw *hw)
    {
    	struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
    	unsigned int val;
    
    	regmap_read(mux->regmap, AIC32X4_CLKMUX, &val);
    	dev_err(mux->dev, "%s, index(%d)\n", __FUNCTION__, (val & AIC32X4_CODEC_CLKIN_MASK) >> AIC32X4_CODEC_CLKIN_SHIFT);
    
    	return (val & AIC32X4_CODEC_CLKIN_MASK) >> AIC32X4_CODEC_CLKIN_SHIFT;
    }
    
    static const struct clk_ops aic32x4_codec_clkin_ops = {
    	.set_parent = clk_aic32x4_codec_clkin_set_parent,
    	.get_parent = clk_aic32x4_codec_clkin_get_parent,
    };
    
    static int clk_aic32x4_div_prepare(struct clk_hw *hw)
    {
    	struct clk_aic32x4 *div = to_clk_aic32x4(hw);
    
    	return regmap_update_bits(div->regmap, div->reg,
    				AIC32X4_DIVEN, AIC32X4_DIVEN);
    }
    
    static void clk_aic32x4_div_unprepare(struct clk_hw *hw)
    {
    	struct clk_aic32x4 *div = to_clk_aic32x4(hw);
    
    	regmap_update_bits(div->regmap, div->reg,
    			AIC32X4_DIVEN, 0);
    }
    
    static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate,
    				unsigned long parent_rate)
    {
    	struct clk_aic32x4 *div = to_clk_aic32x4(hw);
    	u8 divisor;
    
    	divisor = DIV_ROUND_UP(parent_rate, rate);
    	if (divisor > 128)
    		return -EINVAL;
    
    	return regmap_update_bits(div->regmap, div->reg,
    				AIC32X4_DIV_MASK, divisor);
    }
    
    static long clk_aic32x4_div_round_rate(struct clk_hw *hw, unsigned long rate,
    				unsigned long *parent_rate)
    {
    	unsigned long divisor;
    
    	divisor = DIV_ROUND_UP(*parent_rate, rate);
    	if (divisor > 128)
    		return -EINVAL;
    
    	return DIV_ROUND_UP(*parent_rate, divisor);
    }
    
    static unsigned long clk_aic32x4_div_recalc_rate(struct clk_hw *hw,
    						unsigned long parent_rate)
    {
    	struct clk_aic32x4 *div = to_clk_aic32x4(hw);
    
    	unsigned int val;
    
    	regmap_read(div->regmap, div->reg, &val);
    
    	return DIV_ROUND_UP(parent_rate, val & AIC32X4_DIV_MASK);
    }
    
    static const struct clk_ops aic32x4_div_ops = {
    	.prepare = clk_aic32x4_div_prepare,
    	.unprepare = clk_aic32x4_div_unprepare,
    	.set_rate = clk_aic32x4_div_set_rate,
    	.round_rate = clk_aic32x4_div_round_rate,
    	.recalc_rate = clk_aic32x4_div_recalc_rate,
    };
    
    static int clk_aic32x4_bdiv_set_parent(struct clk_hw *hw, u8 index)
    {
    	struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
    
    	dev_err(mux->dev, "%s, index(%d)\n", __FUNCTION__, index);
    	return regmap_update_bits(mux->regmap, AIC32X4_IFACE3,
    				AIC32X4_BDIVCLK_MASK, index);
    }
    
    static u8 clk_aic32x4_bdiv_get_parent(struct clk_hw *hw)
    {
    	struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
    	unsigned int val;
    
    	regmap_read(mux->regmap, AIC32X4_IFACE3, &val);
    	dev_err(mux->dev, "%s, index(%d)\n", __FUNCTION__, val & AIC32X4_BDIVCLK_MASK);
    
    	return val & AIC32X4_BDIVCLK_MASK;
    }
    
    static const struct clk_ops aic32x4_bdiv_ops = {
    	.prepare = clk_aic32x4_div_prepare,
    	.unprepare = clk_aic32x4_div_unprepare,
    	.set_parent = clk_aic32x4_bdiv_set_parent,
    	.get_parent = clk_aic32x4_bdiv_get_parent,
    	.set_rate = clk_aic32x4_div_set_rate,
    	.round_rate = clk_aic32x4_div_round_rate,
    	.recalc_rate = clk_aic32x4_div_recalc_rate,
    };
    
    static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
    	{
    		.name = "pll",
    		.parent_names =
    			(const char* []) { "mclk", "bclk", "gpio", "din" },
    		.num_parents = 4,
    		.ops = &aic32x4_pll_ops,
    		.reg = 0,
    	},
    	{
    		.name = "codec_clkin",
    		.parent_names =
    			(const char *[]) { "mclk", "bclk", "gpio", "pll" },
    		.num_parents = 4,
    		.ops = &aic32x4_codec_clkin_ops,
    		.reg = 0,
    	},
    	{
    		.name = "ndac",
    		.parent_names = (const char * []) { "codec_clkin" },
    		.num_parents = 1,
    		.ops = &aic32x4_div_ops,
    		.reg = AIC32X4_NDAC,
    	},
    	{
    		.name = "mdac",
    		.parent_names = (const char * []) { "ndac" },
    		.num_parents = 1,
    		.ops = &aic32x4_div_ops,
    		.reg = AIC32X4_MDAC,
    	},
    	{
    		.name = "nadc",
    		.parent_names = (const char * []) { "codec_clkin" },
    		.num_parents = 1,
    		.ops = &aic32x4_div_ops,
    		.reg = AIC32X4_NADC,
    	},
    	{
    		.name = "madc",
    		.parent_names = (const char * []) { "nadc" },
    		.num_parents = 1,
    		.ops = &aic32x4_div_ops,
    		.reg = AIC32X4_MADC,
    	},
    	{
    		.name = "bdiv",
    		.parent_names =
    			(const char *[]) { "ndac", "mdac", "nadc", "madc" },
    		.num_parents = 4,
    		.ops = &aic32x4_bdiv_ops,
    		.reg = AIC32X4_BCLKN,
    	},
    };
    
    static struct clk *aic32x4_register_clk(struct device *dev,
    			struct aic32x4_clkdesc *desc)
    {
    	struct clk_init_data init;
    	struct clk_aic32x4 *priv;
    	const char *devname = dev_name(dev);
    
    	dev_err(dev, "%s, devname(%s)\n", __FUNCTION__, devname);
    	init.ops = desc->ops;
    	init.name = desc->name;
    	init.parent_names = desc->parent_names;
    	init.num_parents = desc->num_parents;
    	init.flags = 0;
    
    	priv = devm_kzalloc(dev, sizeof(struct clk_aic32x4), GFP_KERNEL);
    	if (priv == NULL)
    		return (struct clk *) -ENOMEM;
    
    	priv->dev = dev;
    	priv->hw.init = &init;
    	priv->regmap = dev_get_regmap(dev, NULL);
    	priv->reg = desc->reg;
    
    	clk_hw_register_clkdev(&priv->hw, desc->name, devname);
    	return devm_clk_register(dev, &priv->hw);
    }
    
    int aic32x4_register_clocks(struct device *dev, const char *mclk_name)
    {
    	int i;
    
    	/*
    	 * These lines are here to preserve the current functionality of
    	 * the driver with regard to the DT.  These should eventually be set
    	 * by DT nodes so that the connections can be set up in configuration
    	 * rather than code.
    	 */
    	dev_err(dev, "%s %s\n", __FUNCTION__, mclk_name);
    	aic32x4_clkdesc_array[0].parent_names =
    			(const char* []) { mclk_name, "bclk", "gpio", "din" };
    	aic32x4_clkdesc_array[1].parent_names =
    			(const char *[]) { mclk_name, "bclk", "gpio", "pll" };
    
    	for (i = 0; i < ARRAY_SIZE(aic32x4_clkdesc_array); ++i)
    		aic32x4_register_clk(dev, &aic32x4_clkdesc_array[i]);
    
    	return 0;
    }
    EXPORT_SYMBOL_GPL(aic32x4_register_clocks);
    

    Please check the following log is correct or not

    0503_log_3_mclk.txt

    [   97.869662][ T1631] tlv320aic32x4 2-0018: aic32x4_set_dai_fmt: fmt(0x1001)
    [   97.884755][ T1631] tlv320aic32x4 2-0018: aic32x4_set_dai_sysclk:clk_id(0), freq(12288000)
    [   97.893756][ T1631] tlv320aic32x4 2-0018: aic32x4_hw_params:
    [   97.900118][ T1631] tlv320aic32x4 2-0018: aic32x4_setup_clocks sample_rate(48000), channels(2), bit_depth(16)
    [   97.911174][ T1631] tlv320aic32x4 2-0018: clocks[0~5].clk(63480832,63483520,81642880,81642368,81643520,81641856)
    [   97.923970][ T1631] tlv320aic32x4 2-0018: aic32x4->fmt(0x1001)
    [   97.930426][ T1631] tlv320aic32x4 2-0018: aosr(128), adc_resource_class(6), dac_resource_class(8), dosr_increment(8)
    [   97.942532][ T1631] tlv320aic32x4 2-0018: madc(2), max_dosr(128), min_dosr(56), max_nadc(8)

    What is the parent_rate mean? it is 205273320

    Thank you very much

  • Dear Kevin, 

    Please help to check these comments and reply ASAP.

    Thank you very much

  • Hi Daniel,

    For PLL calculation, you can compare the PLL setting with GUI's setting. PUREPATHSTDIO is available for PLL calculation.

    https://www.ti.com/tool/AICPUREPATH_STUDIO

    The parent_rate is the rate of PLL_CLKIN, it depends on the PLL source which you select.

    From the logs, I think the PLL setting is not correct, if you change the clock source to be MCLK, then pls check your dtsi, did you set the correct MCLK frequency?

    Thanks

    Kevin

  • Dear Kevin, 

    I set the MLCK to 12288000, you can check the waveform, too.
    does the log have any wrong?

    Why can not found out the clock setting?
    What do you mean "PLL setting is not correct"?

    "pls check your dtsi, did you set the correct MCLK frequency?"

    => Do you mean which dtsi node? Do you mean tlv320aic3254's node?

    Should i need to let tlv320aic3254 know this "12288000"?
    I had call aic32x4_set_dai_sysclk() to notify tlv320aic3254

    Thank you very much

  • Hi Daniel,

    the fmt (0x1001) means master mode and I2S mode,  In master mode, the BCLK & WCLK is output from codec, 

    if everything is OK, then the output BCLK & WCLK are 1.536Mhz and 48Khz. 

    From the logs, always blocked here, can you add more logs in this function to check?

    Kevin

  • The parent_rate is incorrect, I don't know why the value is 205273320, this causes initialization to fail

  • Dear Kevin

    "the fmt (0x1001) means master mode and I2S mode,  In master mode, the BCLK & WCLK is output from codec"

    Does it mean that codec is master mode and SOC is slave mode?

    I would like to set SOC as master mode and codec as slave mode because the SOC was config to master mode.

    I will try to config to SND_SOC_DAIFMT_CBS_CFS and let you know the result

  • "Does it mean that codec is master mode and SOC is slave mode?"

    -- Yes

  • What should the parent_rate be?

    Thank you 

  • Dear Kevin

    Please check the new log and source code

    I add some log

    0507_log_2_mclk.txt

    0654.tlv320aic32x4-clk.c
    /* SPDX-License-Identifier: GPL-2.0
     *
     * Clock Tree for the Texas Instruments TLV320AIC32x4
     *
     * Copyright 2019 Annaliese McDermond
     *
     * Author: Annaliese McDermond <nh6z@nh6z.net>
     */
    
    #include <linux/clk-provider.h>
    #include <linux/clkdev.h>
    #include <linux/regmap.h>
    #include <linux/device.h>
    
    #include "tlv320aic32x4.h"
    
    #define to_clk_aic32x4(_hw) container_of(_hw, struct clk_aic32x4, hw)
    struct clk_aic32x4 {
    	struct clk_hw hw;
    	struct device *dev;
    	struct regmap *regmap;
    	unsigned int reg;
    };
    
    /*
     * struct clk_aic32x4_pll_muldiv - Multiplier/divider settings
     * @p:		Divider
     * @r:		first multiplier
     * @j:		integer part of second multiplier
     * @d:		decimal part of second multiplier
     */
    struct clk_aic32x4_pll_muldiv {
    	u8 p;
    	u16 r;
    	u8 j;
    	u16 d;
    };
    
    struct aic32x4_clkdesc {
    	const char *name;
    	const char * const *parent_names;
    	unsigned int num_parents;
    	const struct clk_ops *ops;
    	unsigned int reg;
    };
    
    static int clk_aic32x4_pll_prepare(struct clk_hw *hw)
    {
    	struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
    
    	dev_err(pll->dev, "%s\n", __FUNCTION__);
    	return regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
    				AIC32X4_PLLEN, AIC32X4_PLLEN);
    }
    
    static void clk_aic32x4_pll_unprepare(struct clk_hw *hw)
    {
    	struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
    
    	dev_err(pll->dev, "%s\n", __FUNCTION__);
    	regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
    				AIC32X4_PLLEN, 0);
    }
    
    static int clk_aic32x4_pll_is_prepared(struct clk_hw *hw)
    {
    	struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
    
    	unsigned int val;
    	int ret;
    
    	dev_err(pll->dev, "%s\n", __FUNCTION__);
    	ret = regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
    	if (ret < 0)
    		return ret;
    
    	return !!(val & AIC32X4_PLLEN);
    }
    
    static int clk_aic32x4_pll_get_muldiv(struct clk_aic32x4 *pll,
    			struct clk_aic32x4_pll_muldiv *settings)
    {
    	/*	Change to use regmap_bulk_read? */
    	unsigned int val;
    	int ret;
    
    	ret = regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
    	if (ret < 0)
    		return ret;
    	settings->r = val & AIC32X4_PLL_R_MASK;
    	settings->p = (val & AIC32X4_PLL_P_MASK) >> AIC32X4_PLL_P_SHIFT;
    
    	ret = regmap_read(pll->regmap, AIC32X4_PLLJ, &val);
    	if (ret < 0)
    		return ret;
    	settings->j = val;
    
    	ret = regmap_read(pll->regmap, AIC32X4_PLLDMSB, &val);
    	if (ret < 0)
    		return ret;
    	settings->d = val << 8;
    
    	ret = regmap_read(pll->regmap, AIC32X4_PLLDLSB,	 &val);
    	if (ret < 0)
    		return ret;
    	settings->d |= val;
    
    	return 0;
    }
    
    static int clk_aic32x4_pll_set_muldiv(struct clk_aic32x4 *pll,
    			struct clk_aic32x4_pll_muldiv *settings)
    {
    	int ret;
    	/*	Change to use regmap_bulk_write for some if not all? */
    
    	ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
    				AIC32X4_PLL_R_MASK, settings->r);
    	if (ret < 0)
    		return ret;
    
    	ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
    				AIC32X4_PLL_P_MASK,
    				settings->p << AIC32X4_PLL_P_SHIFT);
    	if (ret < 0)
    		return ret;
    
    	ret = regmap_write(pll->regmap, AIC32X4_PLLJ, settings->j);
    	if (ret < 0)
    		return ret;
    
    	ret = regmap_write(pll->regmap, AIC32X4_PLLDMSB, (settings->d >> 8));
    	if (ret < 0)
    		return ret;
    	ret = regmap_write(pll->regmap, AIC32X4_PLLDLSB, (settings->d & 0xff));
    	if (ret < 0)
    		return ret;
    
    	return 0;
    }
    
    static unsigned long clk_aic32x4_pll_calc_rate(
    			struct clk_aic32x4_pll_muldiv *settings,
    			unsigned long parent_rate)
    {
    	u64 rate;
    	/*
    	 * We scale j by 10000 to account for the decimal part of P and divide
    	 * it back out later.
    	 */
    	rate = (u64) parent_rate * settings->r *
    				((settings->j * 10000) + settings->d);
    
    	return (unsigned long) DIV_ROUND_UP_ULL(rate, settings->p * 10000);
    }
    
    static int clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv *settings,
    			unsigned long rate, unsigned long parent_rate)
    {
    	u64 multiplier;
    
    	settings->p = parent_rate / AIC32X4_MAX_PLL_CLKIN + 1;
    	if (settings->p > 8)
    		return -1;
    
    	/*
    	 * We scale this figure by 10000 so that we can get the decimal part
    	 * of the multiplier.	This is because we can't do floating point
    	 * math in the kernel.
    	 */
    	multiplier = (u64) rate * settings->p * 10000;
    	do_div(multiplier, parent_rate);
    
    	/*
    	 * J can't be over 64, so R can scale this.
    	 * R can't be greater than 4.
    	 */
    	settings->r = ((u32) multiplier / 640000) + 1;
    	if (settings->r > 4)
    		return -1;
    	do_div(multiplier, settings->r);
    
    	/*
    	 * J can't be < 1.
    	 */
    	if (multiplier < 10000)
    		return -1;
    
    	/* Figure out the integer part, J, and the fractional part, D. */
    	settings->j = (u32) multiplier / 10000;
    	settings->d = (u32) multiplier % 10000;
    
    	return 0;
    }
    
    static unsigned long clk_aic32x4_pll_recalc_rate(struct clk_hw *hw,
    			unsigned long parent_rate)
    {
    	struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
    	struct clk_aic32x4_pll_muldiv settings;
    	int ret;
    
    	dev_err(pll->dev, "%s, parent_rate(%d)\n", __FUNCTION__, parent_rate);
    	ret =  clk_aic32x4_pll_get_muldiv(pll, &settings);
    	if (ret < 0)
    		return 0;
    
    	return clk_aic32x4_pll_calc_rate(&settings, parent_rate);
    }
    
    static long clk_aic32x4_pll_round_rate(struct clk_hw *hw,
    			unsigned long rate,
    			unsigned long *parent_rate)
    {
    	struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
    	struct clk_aic32x4_pll_muldiv settings;
    	unsigned long calc_rate;
    	int ret;
    
    	ret = clk_aic32x4_pll_calc_muldiv(&settings, rate, *parent_rate);
    	dev_err(pll->dev, "%s, rate(%d), parent_rate(%d)\n", __FUNCTION__, rate, *parent_rate);
    	if (ret < 0){
    		dev_err(pll->dev, "%s, clk_aic32x4_pll_calc_muldiv ret(%d)\n", __FUNCTION__, ret);
    		return 0;
    	}
    	calc_rate = clk_aic32x4_pll_calc_rate(&settings, *parent_rate);
    	return calc_rate;//clk_aic32x4_pll_calc_rate(&settings, *parent_rate);
    }
    
    static int clk_aic32x4_pll_set_rate(struct clk_hw *hw,
    			unsigned long rate,
    			unsigned long parent_rate)
    {
    	struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
    	struct clk_aic32x4_pll_muldiv settings;
    	int ret;
    
    	dev_err(pll->dev, "%s, rate(%d), parent_rate(%d)\n", __FUNCTION__, rate, parent_rate);
    	ret = clk_aic32x4_pll_calc_muldiv(&settings, rate, parent_rate);
    	if (ret < 0)
    		return -EINVAL;
    
    	ret = clk_aic32x4_pll_set_muldiv(pll, &settings);
    	if (ret)
    		return ret;
    
    	/* 10ms is the delay to wait before the clocks are stable */
    	msleep(10);
    
    	return 0;
    }
    
    static int clk_aic32x4_pll_set_parent(struct clk_hw *hw, u8 index)
    {
    	struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
    
    	dev_err(pll->dev, "%s, index(%d)\n", __FUNCTION__, index);
    	//index = 1;/* set pll parent to be BLCK*/
    	return regmap_update_bits(pll->regmap,
    				AIC32X4_CLKMUX,
    				AIC32X4_PLL_CLKIN_MASK,
    				index << AIC32X4_PLL_CLKIN_SHIFT);
    }
    
    static u8 clk_aic32x4_pll_get_parent(struct clk_hw *hw)
    {
    	struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
    	unsigned int val;
    
    	regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
    	dev_err(pll->dev, "%s,%s index(%d)\n", __FUNCTION__, dev_name(pll->dev), (val & AIC32X4_PLL_CLKIN_MASK) >> AIC32X4_PLL_CLKIN_SHIFT);
    
    	return (val & AIC32X4_PLL_CLKIN_MASK) >> AIC32X4_PLL_CLKIN_SHIFT;
    }
    
    
    static const struct clk_ops aic32x4_pll_ops = {
    	.prepare = clk_aic32x4_pll_prepare,
    	.unprepare = clk_aic32x4_pll_unprepare,
    	.is_prepared = clk_aic32x4_pll_is_prepared,
    	.recalc_rate = clk_aic32x4_pll_recalc_rate,
    	.round_rate = clk_aic32x4_pll_round_rate,
    	.set_rate = clk_aic32x4_pll_set_rate,
    	.set_parent = clk_aic32x4_pll_set_parent,
    	.get_parent = clk_aic32x4_pll_get_parent,
    };
    
    static int clk_aic32x4_codec_clkin_set_parent(struct clk_hw *hw, u8 index)
    {
    	struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
    
    	dev_err(mux->dev, "%s, index(%d)\n", __FUNCTION__, index);
    	return regmap_update_bits(mux->regmap,
    		AIC32X4_CLKMUX,
    		AIC32X4_CODEC_CLKIN_MASK, index << AIC32X4_CODEC_CLKIN_SHIFT);
    }
    
    static u8 clk_aic32x4_codec_clkin_get_parent(struct clk_hw *hw)
    {
    	struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
    	unsigned int val;
    
    	regmap_read(mux->regmap, AIC32X4_CLKMUX, &val);
    	dev_err(mux->dev, "%s, index(%d)\n", __FUNCTION__, (val & AIC32X4_CODEC_CLKIN_MASK) >> AIC32X4_CODEC_CLKIN_SHIFT);
    
    	return (val & AIC32X4_CODEC_CLKIN_MASK) >> AIC32X4_CODEC_CLKIN_SHIFT;
    }
    
    static const struct clk_ops aic32x4_codec_clkin_ops = {
    	.set_parent = clk_aic32x4_codec_clkin_set_parent,
    	.get_parent = clk_aic32x4_codec_clkin_get_parent,
    };
    
    static int clk_aic32x4_div_prepare(struct clk_hw *hw)
    {
    	struct clk_aic32x4 *div = to_clk_aic32x4(hw);
    
    	return regmap_update_bits(div->regmap, div->reg,
    				AIC32X4_DIVEN, AIC32X4_DIVEN);
    }
    
    static void clk_aic32x4_div_unprepare(struct clk_hw *hw)
    {
    	struct clk_aic32x4 *div = to_clk_aic32x4(hw);
    
    	regmap_update_bits(div->regmap, div->reg,
    			AIC32X4_DIVEN, 0);
    }
    
    static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate,
    				unsigned long parent_rate)
    {
    	struct clk_aic32x4 *div = to_clk_aic32x4(hw);
    	u8 divisor;
    
    	divisor = DIV_ROUND_UP(parent_rate, rate);
    	if (divisor > 128)
    		return -EINVAL;
    
    	return regmap_update_bits(div->regmap, div->reg,
    				AIC32X4_DIV_MASK, divisor);
    }
    
    static long clk_aic32x4_div_round_rate(struct clk_hw *hw, unsigned long rate,
    				unsigned long *parent_rate)
    {
    	unsigned long divisor;
    
    	divisor = DIV_ROUND_UP(*parent_rate, rate);
    	if (divisor > 128)
    		return -EINVAL;
    
    	return DIV_ROUND_UP(*parent_rate, divisor);
    }
    
    static unsigned long clk_aic32x4_div_recalc_rate(struct clk_hw *hw,
    						unsigned long parent_rate)
    {
    	struct clk_aic32x4 *div = to_clk_aic32x4(hw);
    
    	unsigned int val;
    
    	regmap_read(div->regmap, div->reg, &val);
    
    	return DIV_ROUND_UP(parent_rate, val & AIC32X4_DIV_MASK);
    }
    
    static const struct clk_ops aic32x4_div_ops = {
    	.prepare = clk_aic32x4_div_prepare,
    	.unprepare = clk_aic32x4_div_unprepare,
    	.set_rate = clk_aic32x4_div_set_rate,
    	.round_rate = clk_aic32x4_div_round_rate,
    	.recalc_rate = clk_aic32x4_div_recalc_rate,
    };
    
    static int clk_aic32x4_bdiv_set_parent(struct clk_hw *hw, u8 index)
    {
    	struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
    
    	dev_err(mux->dev, "%s, index(%d)\n", __FUNCTION__, index);
    	return regmap_update_bits(mux->regmap, AIC32X4_IFACE3,
    				AIC32X4_BDIVCLK_MASK, index);
    }
    
    static u8 clk_aic32x4_bdiv_get_parent(struct clk_hw *hw)
    {
    	struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
    	unsigned int val;
    
    	regmap_read(mux->regmap, AIC32X4_IFACE3, &val);
    	dev_err(mux->dev, "%s, index(%d)\n", __FUNCTION__, val & AIC32X4_BDIVCLK_MASK);
    
    	return val & AIC32X4_BDIVCLK_MASK;
    }
    
    static const struct clk_ops aic32x4_bdiv_ops = {
    	.prepare = clk_aic32x4_div_prepare,
    	.unprepare = clk_aic32x4_div_unprepare,
    	.set_parent = clk_aic32x4_bdiv_set_parent,
    	.get_parent = clk_aic32x4_bdiv_get_parent,
    	.set_rate = clk_aic32x4_div_set_rate,
    	.round_rate = clk_aic32x4_div_round_rate,
    	.recalc_rate = clk_aic32x4_div_recalc_rate,
    };
    
    static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
    	{
    		.name = "pll",
    		.parent_names =
    			(const char* []) { "mclk", "bclk", "gpio", "din" },
    		.num_parents = 4,
    		.ops = &aic32x4_pll_ops,
    		.reg = 0,
    	},
    	{
    		.name = "codec_clkin",
    		.parent_names =
    			(const char *[]) { "mclk", "bclk", "gpio", "pll" },
    		.num_parents = 4,
    		.ops = &aic32x4_codec_clkin_ops,
    		.reg = 0,
    	},
    	{
    		.name = "ndac",
    		.parent_names = (const char * []) { "codec_clkin" },
    		.num_parents = 1,
    		.ops = &aic32x4_div_ops,
    		.reg = AIC32X4_NDAC,
    	},
    	{
    		.name = "mdac",
    		.parent_names = (const char * []) { "ndac" },
    		.num_parents = 1,
    		.ops = &aic32x4_div_ops,
    		.reg = AIC32X4_MDAC,
    	},
    	{
    		.name = "nadc",
    		.parent_names = (const char * []) { "codec_clkin" },
    		.num_parents = 1,
    		.ops = &aic32x4_div_ops,
    		.reg = AIC32X4_NADC,
    	},
    	{
    		.name = "madc",
    		.parent_names = (const char * []) { "nadc" },
    		.num_parents = 1,
    		.ops = &aic32x4_div_ops,
    		.reg = AIC32X4_MADC,
    	},
    	{
    		.name = "bdiv",
    		.parent_names =
    			(const char *[]) { "ndac", "mdac", "nadc", "madc" },
    		.num_parents = 4,
    		.ops = &aic32x4_bdiv_ops,
    		.reg = AIC32X4_BCLKN,
    	},
    };
    
    static struct clk *aic32x4_register_clk(struct device *dev,
    			struct aic32x4_clkdesc *desc)
    {
    	struct clk_init_data init;
    	struct clk_aic32x4 *priv;
    	const char *devname = dev_name(dev);
    
    	dev_err(dev, "%s, devname(%s)\n", __FUNCTION__, devname);
    	init.ops = desc->ops;
    	init.name = desc->name;
    	init.parent_names = desc->parent_names;
    	init.num_parents = desc->num_parents;
    	init.flags = 0;
    
    	priv = devm_kzalloc(dev, sizeof(struct clk_aic32x4), GFP_KERNEL);
    	if (priv == NULL)
    		return (struct clk *) -ENOMEM;
    
    	priv->dev = dev;
    	priv->hw.init = &init;
    	priv->regmap = dev_get_regmap(dev, NULL);
    	priv->reg = desc->reg;
    
    	clk_hw_register_clkdev(&priv->hw, desc->name, devname);
    	return devm_clk_register(dev, &priv->hw);
    }
    
    int aic32x4_register_clocks(struct device *dev, const char *mclk_name)
    {
    	int i;
    
    	/*
    	 * These lines are here to preserve the current functionality of
    	 * the driver with regard to the DT.  These should eventually be set
    	 * by DT nodes so that the connections can be set up in configuration
    	 * rather than code.
    	 */
    	dev_err(dev, "%s %s\n", __FUNCTION__, mclk_name);
    	aic32x4_clkdesc_array[0].parent_names =
    			(const char* []) { mclk_name, "bclk", "gpio", "din" };
    	aic32x4_clkdesc_array[1].parent_names =
    			(const char *[]) { mclk_name, "bclk", "gpio", "pll" };
    
    	for (i = 0; i < ARRAY_SIZE(aic32x4_clkdesc_array); ++i)
    		aic32x4_register_clk(dev, &aic32x4_clkdesc_array[i]);
    
    	return 0;
    }
    EXPORT_SYMBOL_GPL(aic32x4_register_clocks);
    

    The *parent_rate was always 0.

    (205273320 should be address not value at previous image)

    clk_aic32x4_pll_calc_muldiv will return -1

    I found the parent is 0 at initial, too

    [    6.785024][   T41] tlv320aic32x4 2-0018: clk_aic32x4_pll_recalc_rate, parent_rate(0)

    Who need to config the parent_rate ?

    Thank you very much

  • Dear Kevin

    What does the "parent_rate" mean? MLCK or others ?

  • Hi Daniel,

    Actually I'm not sure how to config parent_rate, because the driver is not designed by me, I'm still checking in it.

    Before that I have an advice for you to confirm the dtsi configuration, 

    Here's a reference dts which you can compare with yours

    udrc-overlay.dts

    Thanks

  • Dear Kevin, 

    I found the log did not call function clk_aic32x4_pll_set_parent()

    Is it possible a issue?

    Does the parent mean mlck clock?

    Where and how the driver got it?

    Thank you very much

  • Hi Daniel,

    Yes, that's correct, the driver didn't call clk_set_parent() to set pll parent rate. we did notice the driver the MCLK is 12.288Mhz, but we didn't set it as PLL's parent rate

    Maybe we can do some experiment, modify the function of aic32x4_set_dai_sysclk(), add below contents between line 611 ~ 616, 

    What you think of this way? could you have a try?

    Thanks

  • Dear Kevin

    Could you please provide the patch file?

    Thank you very much

  • Hi Daniel,

    I just modify it based on your code, that's not final modification, so I can't generate patch

    Thanks

  • Dear Kevin

    Does the sequence is right about this part

    	mclk = clk_get_parent(pll);
    
    ...
    
    	clk_set_parent(clocks[0].clk, mclk);

  • Sorry, there's a mistake, OK now I understand, 

    clk_aic32x4_pll_set_rate() was not be called at all, we should call it first,  if clk_set_rate() worked, then clk_aic32x4_pll_set_rate() should be called, but from the logs, it hasn't, please try clk_set_rate(pll, freq); Thanks!
    static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
    				  int clk_id, unsigned int freq, int dir)
    {
    	struct snd_soc_component *component = codec_dai->component;
    	struct clk *mclk;
    	struct clk *pll;
    	dev_err(component->dev, "%s:clk_id(%d), freq(%d)\n", __FUNCTION__, clk_id, freq);
    
    	pll = devm_clk_get(component->dev, "pll");
    	if (IS_ERR(pll))
    		return PTR_ERR(pll);
    
    	mclk = clk_get_parent(pll);
        /* for debug */
    	return clk_set_rate(pll, freq);
    }
  • Dear Kevin, 

    Even do this change, the result still failed

    static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
    				  int clk_id, unsigned int freq, int dir)
    {
    	struct snd_soc_component *component = codec_dai->component;
    	struct clk *mclk;
    	struct clk *pll;
    	int ret;
    	dev_err(component->dev, "%s:clk_id(%d), freq(%d)\n", __FUNCTION__, clk_id, freq);
    
    	pll = devm_clk_get(component->dev, "pll");
    	if (IS_ERR(pll)){
    		dev_err(component->dev, "%s:IS_ERR(pll)(%d)\n", __FUNCTION__, IS_ERR(pll));
    		return PTR_ERR(pll);
    	}
    	mclk = clk_get_parent(pll);
    
    	//ret=clk_set_rate(mclk, freq);
    	/* for debug */
    	ret=clk_set_rate(pll, freq);
    	dev_err(component->dev, "%s:clk_set_rate(pll, %d) ret(%d)\n", __FUNCTION__, freq, ret);
    	return ret;//clk_set_rate(mclk, freq);
    }
    

    0508_log_1_mclk.txt

    [  457.829407][ T1601] tlv320aic32x4 2-0018: aic32x4_set_dai_sysclk:clk_id(0), freq(12288000)
    [  457.839180][ T1601] tlv320aic32x4 2-0018: clk_aic32x4_pll_round_rate, rate(12288000), parent_rate(0)
    [  457.849210][ T1601] tlv320aic32x4 2-0018: clk_aic32x4_pll_round_rate, clk_aic32x4_pll_calc_muldiv err ret(-1)
    [  457.859845][ T1601] tlv320aic32x4 2-0018: aic32x4_set_dai_sysclk:clk_set_rate(pll, 12288000) ret(0)

    What does clk_aic32x4_pll_calc_muldiv() do.

    I always return -1 failed

  • clk_aic32x4_pll_calc_muldiv() is a part of PLL calculation, it have to be processed,

    if the attempts are still fail, I think the devm_clk_get() didn't return the correct struct pointer of PLL, as clk_get_parent(pll) and clk_set_rate(pll, freq) are both not working. 

    I think we should use  devm_clk_bulk_get(), here's the reference code

    static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
    				  int clk_id, unsigned int freq, int dir)
    {
    	struct snd_soc_component *component = codec_dai->component;
    	struct clk *pll;
    	int ret = -1;
    	dev_err(component->dev, "%s:clk_id(%d), freq(%d)\n", __FUNCTION__, clk_id, freq);
    
    	static struct clk_bulk_data clocks[] = {
    		{ .id = "pll" },
    	};
    
    	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
    	if (ret)
    		return ret;
    	pll = clocks[0].clk;
    
    	return clk_set_rate(pll, freq);
    }

     

  • Dear Kevin

    Please check the log and still failed

    0508_log_2_mclk.txt

    static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
    				  int clk_id, unsigned int freq, int dir)
    {
    	struct snd_soc_component *component = codec_dai->component;
    	//struct clk *mclk;
    	struct clk *pll;
    	static struct clk_bulk_data clocks[] = {
    		{ .id = "pll" },	
    	};
    	int ret = -1;
    	dev_err(component->dev, "%s:clk_id(%d), freq(%d)\n", __FUNCTION__, clk_id, freq);
    #if 0
    	pll = devm_clk_get(component->dev, "pll");
    	if (IS_ERR(pll)){
    		dev_err(component->dev, "%s:IS_ERR(pll)(%d)\n", __FUNCTION__, IS_ERR(pll));
    		return PTR_ERR(pll);
    	}
    	mclk = clk_get_parent(pll);
    #else
    	dev_err(component->dev, "%s:devm_clk_bulk_get \n", __FUNCTION__);
    	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);	
    	if (ret){	
    		dev_err(component->dev, "%s:devm_clk_bulk_get error ret(%d)\n", __FUNCTION__, ret);
    		return ret;	
    	}
    	pll = clocks[0].clk;
    #endif
    	//ret=clk_set_rate(mclk, freq);
    	/* for debug */
    	ret=clk_set_rate(pll, freq);
    	dev_err(component->dev, "%s:clk_set_rate(pll, %d) ret(%d)\n", __FUNCTION__, freq, ret);
    	return ret;//clk_set_rate(mclk, freq);
    }

    part log

    [  150.949678][ T1521] tlv320aic32x4 2-0018: aic32x4_set_dai_fmt: fmt(0x4001)
    [  150.963357][ T1521] tlv320aic32x4 2-0018: aic32x4_set_dai_sysclk:clk_id(0), freq(12288000)
    [  150.971919][ T1521] tlv320aic32x4 2-0018: aic32x4_set_dai_sysclk:devm_clk_bulk_get
    [  150.981982][ T1521] tlv320aic32x4 2-0018: clk_aic32x4_pll_round_rate, rate(12288000), parent_rate(0)
    [  150.991958][ T1521] tlv320aic32x4 2-0018: clk_aic32x4_pll_round_rate, clk_aic32x4_pll_calc_muldiv err ret(-1)
    [  151.002610][ T1521] tlv320aic32x4 2-0018: aic32x4_set_dai_sysclk:clk_set_rate(pll, 12288000) ret(0)
    [  151.012655][ T1521] tlv320aic32x4 2-0018: aic32x4_hw_params:
    [  151.018912][ T1521] tlv320aic32x4 2-0018: aic32x4_setup_clocks sample_rate(48000), channels(2), bit_depth(16)
    [  151.029468][ T1521] tlv320aic32x4 2-0018: clocks[0~5].clk(925117184,925116672,789276288,97731968,931314688,931312896)
    [  151.046687][ T1521] tlv320aic32x4 2-0018: aic32x4->fmt(0x4001)

    Is the target to make the clocks[0~5].clk(925117184 ...)become 12288000 ?

  • does the target it make the clocks[0~5].clk(925117184 ...)become 12288000 ?” -- Only for PLL parent_rate

    static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
    				  int clk_id, unsigned int freq, int dir)
    {
    	struct snd_soc_component *component = codec_dai->component;
    	struct clk *pll;
    	int ret = -1;
    	dev_err(component->dev, "%s:clk_id(%d), freq(%d)\n", __FUNCTION__, clk_id, freq);
    
    	static struct clk_bulk_data clocks[] = {
    		{ .id = "pll" },
    	};
    
    	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
    	if (ret)
    		return ret;
    	pll = clocks[0].clk;
    	pll->core->parent->rate = freq;
    	pll->core->new_parent->rate = freq;
    
    	return clk_set_rate(pll, freq);
    }

    How about force set parent_rate as 12288000 ? 

    Thanks

  • Dear Kevin

    I have a question, where is the driver to get mlck clock?

    I did not saw any function like clk_get() 

    Thank you very much

  • Build error

    /home/fihtdc/Workspace1/Daniel/RTCU/SA525M_apps/apps_proc/src/kernel-5.15/kernel_platform/msm-kernel/sound/soc/codecs/tlv320aic32x4.c:626:5: error: incomplete definition of type 'struct clk'
            pll->core->parent->rate = freq; 
            ~~~^
    /home/fihtdc/Workspace1/Daniel/RTCU/SA525M_apps/apps_proc/src/kernel-5.15/kernel_platform/msm-kernel/include/linux/clk.h:17:8: note: forward declaration of 'struct clk'
    struct clk;
           ^
    /home/fihtdc/Workspace1/Daniel/RTCU/SA525M_apps/apps_proc/src/kernel-5.15/kernel_platform/msm-kernel/sound/soc/codecs/tlv320aic32x4.c:627:5: error: incomplete definition of type 'struct clk'
            pll->core->new_parent->rate = freq;
            ~~~^
    /home/fihtdc/Workspace1/Daniel/RTCU/SA525M_apps/apps_proc/src/kernel-5.15/kernel_platform/msm-kernel/include/linux/clk.h:17:8: note: forward declaration of 'struct clk'
    struct clk;
           ^

  • Dear Kevin

    I force to set 12288000 on aic32x4_setup_clocks().

    4846.tlv320aic32x4.c
    // SPDX-License-Identifier: GPL-2.0-or-later
    /*
     * linux/sound/soc/codecs/tlv320aic32x4.c
     *
     * Copyright 2011 Vista Silicon S.L.
     *
     * Author: Javier Martin <javier.martin@vista-silicon.com>
     *
     * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
     */
    
    #include <linux/module.h>
    #include <linux/moduleparam.h>
    #include <linux/init.h>
    #include <linux/delay.h>
    #include <linux/pm.h>
    #include <linux/gpio.h>
    #include <linux/of_gpio.h>
    #include <linux/cdev.h>
    #include <linux/slab.h>
    #include <linux/clk.h>
    #include <linux/of_clk.h>
    #include <linux/regulator/consumer.h>
    
    #include <sound/tlv320aic32x4.h>
    #include <sound/core.h>
    #include <sound/pcm.h>
    #include <sound/pcm_params.h>
    #include <sound/soc.h>
    #include <sound/soc-dapm.h>
    #include <sound/initval.h>
    #include <sound/tlv.h>
    
    #include "tlv320aic32x4.h"
    
    struct aic32x4_priv {
    	struct regmap *regmap;
    	u32 power_cfg;
    	u32 micpga_routing;
    	bool swapdacs;
    	int rstn_gpio;
    	const char *mclk_name;
    
    	struct regulator *supply_ldo;
    	struct regulator *supply_iov;
    	struct regulator *supply_dv;
    	struct regulator *supply_av;
    
    	struct aic32x4_setup_data *setup;
    	struct device *dev;
    	enum aic32x4_type type;
    
    	unsigned int fmt;
    };
    
    static int aic32x4_reset_adc(struct snd_soc_dapm_widget *w,
    			     struct snd_kcontrol *kcontrol, int event)
    {
    	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
    	u32 adc_reg;
    
    	/*
    	 * Workaround: the datasheet does not mention a required programming
    	 * sequence but experiments show the ADC needs to be reset after each
    	 * capture to avoid audible artifacts.
    	 */
    	switch (event) {
    	case SND_SOC_DAPM_POST_PMD:
    		adc_reg = snd_soc_component_read(component, AIC32X4_ADCSETUP);
    		snd_soc_component_write(component, AIC32X4_ADCSETUP, adc_reg |
    					AIC32X4_LADC_EN | AIC32X4_RADC_EN);
    		snd_soc_component_write(component, AIC32X4_ADCSETUP, adc_reg);
    		break;
    	}
    	return 0;
    };
    
    static int mic_bias_event(struct snd_soc_dapm_widget *w,
    	struct snd_kcontrol *kcontrol, int event)
    {
    	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
    
    	switch (event) {
    	case SND_SOC_DAPM_POST_PMU:
    		/* Change Mic Bias Registor */
    		snd_soc_component_update_bits(component, AIC32X4_MICBIAS,
    				AIC32x4_MICBIAS_MASK,
    				AIC32X4_MICBIAS_LDOIN |
    				AIC32X4_MICBIAS_2075V);
    		printk(KERN_DEBUG "%s: Mic Bias will be turned ON\n", __func__);
    		break;
    	case SND_SOC_DAPM_PRE_PMD:
    		snd_soc_component_update_bits(component, AIC32X4_MICBIAS,
    				AIC32x4_MICBIAS_MASK, 0);
    		printk(KERN_DEBUG "%s: Mic Bias will be turned OFF\n",
    				__func__);
    		break;
    	}
    
    	return 0;
    }
    
    
    static int aic32x4_get_mfp1_gpio(struct snd_kcontrol *kcontrol,
    	struct snd_ctl_elem_value *ucontrol)
    {
    	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
    	u8 val;
    
    	val = snd_soc_component_read(component, AIC32X4_DINCTL);
    
    	ucontrol->value.integer.value[0] = (val & 0x01);
    
    	return 0;
    };
    
    static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol,
    	struct snd_ctl_elem_value *ucontrol)
    {
    	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
    	u8 val;
    	u8 gpio_check;
    
    	val = snd_soc_component_read(component, AIC32X4_DOUTCTL);
    	gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED);
    	if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) {
    		printk(KERN_ERR "%s: MFP2 is not configure as a GPIO output\n",
    			__func__);
    		return -EINVAL;
    	}
    
    	if (ucontrol->value.integer.value[0] == (val & AIC32X4_MFP2_GPIO_OUT_HIGH))
    		return 0;
    
    	if (ucontrol->value.integer.value[0])
    		val |= ucontrol->value.integer.value[0];
    	else
    		val &= ~AIC32X4_MFP2_GPIO_OUT_HIGH;
    
    	snd_soc_component_write(component, AIC32X4_DOUTCTL, val);
    
    	return 0;
    };
    
    static int aic32x4_get_mfp3_gpio(struct snd_kcontrol *kcontrol,
    	struct snd_ctl_elem_value *ucontrol)
    {
    	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
    	u8 val;
    
    	val = snd_soc_component_read(component, AIC32X4_SCLKCTL);
    
    	ucontrol->value.integer.value[0] = (val & 0x01);
    
    	return 0;
    };
    
    static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol,
    	struct snd_ctl_elem_value *ucontrol)
    {
    	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
    	u8 val;
    	u8 gpio_check;
    
    	val = snd_soc_component_read(component, AIC32X4_MISOCTL);
    	gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED);
    	if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) {
    		printk(KERN_ERR "%s: MFP4 is not configure as a GPIO output\n",
    			__func__);
    		return -EINVAL;
    	}
    
    	if (ucontrol->value.integer.value[0] == (val & AIC32X4_MFP5_GPIO_OUT_HIGH))
    		return 0;
    
    	if (ucontrol->value.integer.value[0])
    		val |= ucontrol->value.integer.value[0];
    	else
    		val &= ~AIC32X4_MFP5_GPIO_OUT_HIGH;
    
    	snd_soc_component_write(component, AIC32X4_MISOCTL, val);
    
    	return 0;
    };
    
    static int aic32x4_get_mfp5_gpio(struct snd_kcontrol *kcontrol,
    	struct snd_ctl_elem_value *ucontrol)
    {
    	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
    	u8 val;
    
    	val = snd_soc_component_read(component, AIC32X4_GPIOCTL);
    	ucontrol->value.integer.value[0] = ((val & 0x2) >> 1);
    
    	return 0;
    };
    
    static int aic32x4_set_mfp5_gpio(struct snd_kcontrol *kcontrol,
    	struct snd_ctl_elem_value *ucontrol)
    {
    	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
    	u8 val;
    	u8 gpio_check;
    
    	val = snd_soc_component_read(component, AIC32X4_GPIOCTL);
    	gpio_check = (val & AIC32X4_MFP5_GPIO_OUTPUT);
    	if (gpio_check != AIC32X4_MFP5_GPIO_OUTPUT) {
    		printk(KERN_ERR "%s: MFP5 is not configure as a GPIO output\n",
    			__func__);
    		return -EINVAL;
    	}
    
    	if (ucontrol->value.integer.value[0] == (val & 0x1))
    		return 0;
    
    	if (ucontrol->value.integer.value[0])
    		val |= ucontrol->value.integer.value[0];
    	else
    		val &= 0xfe;
    
    	snd_soc_component_write(component, AIC32X4_GPIOCTL, val);
    
    	return 0;
    };
    
    static const struct snd_kcontrol_new aic32x4_mfp1[] = {
    	SOC_SINGLE_BOOL_EXT("MFP1 GPIO", 0, aic32x4_get_mfp1_gpio, NULL),
    };
    
    static const struct snd_kcontrol_new aic32x4_mfp2[] = {
    	SOC_SINGLE_BOOL_EXT("MFP2 GPIO", 0, NULL, aic32x4_set_mfp2_gpio),
    };
    
    static const struct snd_kcontrol_new aic32x4_mfp3[] = {
    	SOC_SINGLE_BOOL_EXT("MFP3 GPIO", 0, aic32x4_get_mfp3_gpio, NULL),
    };
    
    static const struct snd_kcontrol_new aic32x4_mfp4[] = {
    	SOC_SINGLE_BOOL_EXT("MFP4 GPIO", 0, NULL, aic32x4_set_mfp4_gpio),
    };
    
    static const struct snd_kcontrol_new aic32x4_mfp5[] = {
    	SOC_SINGLE_BOOL_EXT("MFP5 GPIO", 0, aic32x4_get_mfp5_gpio,
    		aic32x4_set_mfp5_gpio),
    };
    
    /* 0dB min, 0.5dB steps */
    static DECLARE_TLV_DB_SCALE(tlv_step_0_5, 0, 50, 0);
    /* -63.5dB min, 0.5dB steps */
    static DECLARE_TLV_DB_SCALE(tlv_pcm, -6350, 50, 0);
    /* -6dB min, 1dB steps */
    static DECLARE_TLV_DB_SCALE(tlv_driver_gain, -600, 100, 0);
    /* -12dB min, 0.5dB steps */
    static DECLARE_TLV_DB_SCALE(tlv_adc_vol, -1200, 50, 0);
    /* -6dB min, 1dB steps */
    static DECLARE_TLV_DB_SCALE(tlv_tas_driver_gain, -5850, 50, 0);
    static DECLARE_TLV_DB_SCALE(tlv_amp_vol, 0, 600, 1);
    
    static const char * const lo_cm_text[] = {
    	"Full Chip", "1.65V",
    };
    
    static SOC_ENUM_SINGLE_DECL(lo_cm_enum, AIC32X4_CMMODE, 3, lo_cm_text);
    
    static const char * const ptm_text[] = {
    	"P3", "P2", "P1",
    };
    
    static SOC_ENUM_SINGLE_DECL(l_ptm_enum, AIC32X4_LPLAYBACK, 2, ptm_text);
    static SOC_ENUM_SINGLE_DECL(r_ptm_enum, AIC32X4_RPLAYBACK, 2, ptm_text);
    
    static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
    	SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL,
    			AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm),
    	SOC_ENUM("DAC Left Playback PowerTune Switch", l_ptm_enum),
    	SOC_ENUM("DAC Right Playback PowerTune Switch", r_ptm_enum),
    	SOC_DOUBLE_R_S_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN,
    			AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0,
    			tlv_driver_gain),
    	SOC_DOUBLE_R_S_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN,
    			AIC32X4_LORGAIN, 0, -0x6, 0x1d, 5, 0,
    			tlv_driver_gain),
    	SOC_DOUBLE_R("HP DAC Playback Switch", AIC32X4_HPLGAIN,
    			AIC32X4_HPRGAIN, 6, 0x01, 1),
    	SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN,
    			AIC32X4_LORGAIN, 6, 0x01, 1),
    	SOC_ENUM("LO Playback Common Mode Switch", lo_cm_enum),
    	SOC_DOUBLE_R("Mic PGA Switch", AIC32X4_LMICPGAVOL,
    			AIC32X4_RMICPGAVOL, 7, 0x01, 1),
    
    	SOC_SINGLE("ADCFGA Left Mute Switch", AIC32X4_ADCFGA, 7, 1, 0),
    	SOC_SINGLE("ADCFGA Right Mute Switch", AIC32X4_ADCFGA, 3, 1, 0),
    
    	SOC_DOUBLE_R_S_TLV("ADC Level Volume", AIC32X4_LADCVOL,
    			AIC32X4_RADCVOL, 0, -0x18, 0x28, 6, 0, tlv_adc_vol),
    	SOC_DOUBLE_R_TLV("PGA Level Volume", AIC32X4_LMICPGAVOL,
    			AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5),
    
    	SOC_SINGLE("Auto-mute Switch", AIC32X4_DACMUTE, 4, 7, 0),
    
    	SOC_SINGLE("AGC Left Switch", AIC32X4_LAGC1, 7, 1, 0),
    	SOC_SINGLE("AGC Right Switch", AIC32X4_RAGC1, 7, 1, 0),
    	SOC_DOUBLE_R("AGC Target Level", AIC32X4_LAGC1, AIC32X4_RAGC1,
    			4, 0x07, 0),
    	SOC_DOUBLE_R("AGC Gain Hysteresis", AIC32X4_LAGC1, AIC32X4_RAGC1,
    			0, 0x03, 0),
    	SOC_DOUBLE_R("AGC Hysteresis", AIC32X4_LAGC2, AIC32X4_RAGC2,
    			6, 0x03, 0),
    	SOC_DOUBLE_R("AGC Noise Threshold", AIC32X4_LAGC2, AIC32X4_RAGC2,
    			1, 0x1F, 0),
    	SOC_DOUBLE_R("AGC Max PGA", AIC32X4_LAGC3, AIC32X4_RAGC3,
    			0, 0x7F, 0),
    	SOC_DOUBLE_R("AGC Attack Time", AIC32X4_LAGC4, AIC32X4_RAGC4,
    			3, 0x1F, 0),
    	SOC_DOUBLE_R("AGC Decay Time", AIC32X4_LAGC5, AIC32X4_RAGC5,
    			3, 0x1F, 0),
    	SOC_DOUBLE_R("AGC Noise Debounce", AIC32X4_LAGC6, AIC32X4_RAGC6,
    			0, 0x1F, 0),
    	SOC_DOUBLE_R("AGC Signal Debounce", AIC32X4_LAGC7, AIC32X4_RAGC7,
    			0, 0x0F, 0),
    };
    
    static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
    	SOC_DAPM_SINGLE("L_DAC Switch", AIC32X4_HPLROUTE, 3, 1, 0),
    	SOC_DAPM_SINGLE("IN1_L Switch", AIC32X4_HPLROUTE, 2, 1, 0),
    };
    
    static const struct snd_kcontrol_new hpr_output_mixer_controls[] = {
    	SOC_DAPM_SINGLE("R_DAC Switch", AIC32X4_HPRROUTE, 3, 1, 0),
    	SOC_DAPM_SINGLE("IN1_R Switch", AIC32X4_HPRROUTE, 2, 1, 0),
    };
    
    static const struct snd_kcontrol_new lol_output_mixer_controls[] = {
    	SOC_DAPM_SINGLE("L_DAC Switch", AIC32X4_LOLROUTE, 3, 1, 0),
    };
    
    static const struct snd_kcontrol_new lor_output_mixer_controls[] = {
    	SOC_DAPM_SINGLE("R_DAC Switch", AIC32X4_LORROUTE, 3, 1, 0),
    };
    
    static const char * const resistor_text[] = {
    	"Off", "10 kOhm", "20 kOhm", "40 kOhm",
    };
    
    /* Left mixer pins */
    static SOC_ENUM_SINGLE_DECL(in1l_lpga_p_enum, AIC32X4_LMICPGAPIN, 6, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in2l_lpga_p_enum, AIC32X4_LMICPGAPIN, 4, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in3l_lpga_p_enum, AIC32X4_LMICPGAPIN, 2, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in1r_lpga_p_enum, AIC32X4_LMICPGAPIN, 0, resistor_text);
    
    static SOC_ENUM_SINGLE_DECL(cml_lpga_n_enum, AIC32X4_LMICPGANIN, 6, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in2r_lpga_n_enum, AIC32X4_LMICPGANIN, 4, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in3r_lpga_n_enum, AIC32X4_LMICPGANIN, 2, resistor_text);
    
    static const struct snd_kcontrol_new in1l_to_lmixer_controls[] = {
    	SOC_DAPM_ENUM("IN1_L L+ Switch", in1l_lpga_p_enum),
    };
    static const struct snd_kcontrol_new in2l_to_lmixer_controls[] = {
    	SOC_DAPM_ENUM("IN2_L L+ Switch", in2l_lpga_p_enum),
    };
    static const struct snd_kcontrol_new in3l_to_lmixer_controls[] = {
    	SOC_DAPM_ENUM("IN3_L L+ Switch", in3l_lpga_p_enum),
    };
    static const struct snd_kcontrol_new in1r_to_lmixer_controls[] = {
    	SOC_DAPM_ENUM("IN1_R L+ Switch", in1r_lpga_p_enum),
    };
    static const struct snd_kcontrol_new cml_to_lmixer_controls[] = {
    	SOC_DAPM_ENUM("CM_L L- Switch", cml_lpga_n_enum),
    };
    static const struct snd_kcontrol_new in2r_to_lmixer_controls[] = {
    	SOC_DAPM_ENUM("IN2_R L- Switch", in2r_lpga_n_enum),
    };
    static const struct snd_kcontrol_new in3r_to_lmixer_controls[] = {
    	SOC_DAPM_ENUM("IN3_R L- Switch", in3r_lpga_n_enum),
    };
    
    /*	Right mixer pins */
    static SOC_ENUM_SINGLE_DECL(in1r_rpga_p_enum, AIC32X4_RMICPGAPIN, 6, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in2r_rpga_p_enum, AIC32X4_RMICPGAPIN, 4, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in3r_rpga_p_enum, AIC32X4_RMICPGAPIN, 2, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in2l_rpga_p_enum, AIC32X4_RMICPGAPIN, 0, resistor_text);
    static SOC_ENUM_SINGLE_DECL(cmr_rpga_n_enum, AIC32X4_RMICPGANIN, 6, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in1l_rpga_n_enum, AIC32X4_RMICPGANIN, 4, resistor_text);
    static SOC_ENUM_SINGLE_DECL(in3l_rpga_n_enum, AIC32X4_RMICPGANIN, 2, resistor_text);
    
    static const struct snd_kcontrol_new in1r_to_rmixer_controls[] = {
    	SOC_DAPM_ENUM("IN1_R R+ Switch", in1r_rpga_p_enum),
    };
    static const struct snd_kcontrol_new in2r_to_rmixer_controls[] = {
    	SOC_DAPM_ENUM("IN2_R R+ Switch", in2r_rpga_p_enum),
    };
    static const struct snd_kcontrol_new in3r_to_rmixer_controls[] = {
    	SOC_DAPM_ENUM("IN3_R R+ Switch", in3r_rpga_p_enum),
    };
    static const struct snd_kcontrol_new in2l_to_rmixer_controls[] = {
    	SOC_DAPM_ENUM("IN2_L R+ Switch", in2l_rpga_p_enum),
    };
    static const struct snd_kcontrol_new cmr_to_rmixer_controls[] = {
    	SOC_DAPM_ENUM("CM_R R- Switch", cmr_rpga_n_enum),
    };
    static const struct snd_kcontrol_new in1l_to_rmixer_controls[] = {
    	SOC_DAPM_ENUM("IN1_L R- Switch", in1l_rpga_n_enum),
    };
    static const struct snd_kcontrol_new in3l_to_rmixer_controls[] = {
    	SOC_DAPM_ENUM("IN3_L R- Switch", in3l_rpga_n_enum),
    };
    
    static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = {
    	SND_SOC_DAPM_DAC("Left DAC", "Left Playback", AIC32X4_DACSETUP, 7, 0),
    	SND_SOC_DAPM_MIXER("HPL Output Mixer", SND_SOC_NOPM, 0, 0,
    			   &hpl_output_mixer_controls[0],
    			   ARRAY_SIZE(hpl_output_mixer_controls)),
    	SND_SOC_DAPM_PGA("HPL Power", AIC32X4_OUTPWRCTL, 5, 0, NULL, 0),
    
    	SND_SOC_DAPM_MIXER("LOL Output Mixer", SND_SOC_NOPM, 0, 0,
    			   &lol_output_mixer_controls[0],
    			   ARRAY_SIZE(lol_output_mixer_controls)),
    	SND_SOC_DAPM_PGA("LOL Power", AIC32X4_OUTPWRCTL, 3, 0, NULL, 0),
    
    	SND_SOC_DAPM_DAC("Right DAC", "Right Playback", AIC32X4_DACSETUP, 6, 0),
    	SND_SOC_DAPM_MIXER("HPR Output Mixer", SND_SOC_NOPM, 0, 0,
    			   &hpr_output_mixer_controls[0],
    			   ARRAY_SIZE(hpr_output_mixer_controls)),
    	SND_SOC_DAPM_PGA("HPR Power", AIC32X4_OUTPWRCTL, 4, 0, NULL, 0),
    	SND_SOC_DAPM_MIXER("LOR Output Mixer", SND_SOC_NOPM, 0, 0,
    			   &lor_output_mixer_controls[0],
    			   ARRAY_SIZE(lor_output_mixer_controls)),
    	SND_SOC_DAPM_PGA("LOR Power", AIC32X4_OUTPWRCTL, 2, 0, NULL, 0),
    
    	SND_SOC_DAPM_ADC("Right ADC", "Right Capture", AIC32X4_ADCSETUP, 6, 0),
    	SND_SOC_DAPM_MUX("IN1_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in1r_to_rmixer_controls),
    	SND_SOC_DAPM_MUX("IN2_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in2r_to_rmixer_controls),
    	SND_SOC_DAPM_MUX("IN3_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in3r_to_rmixer_controls),
    	SND_SOC_DAPM_MUX("IN2_L to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in2l_to_rmixer_controls),
    	SND_SOC_DAPM_MUX("CM_R to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
    			cmr_to_rmixer_controls),
    	SND_SOC_DAPM_MUX("IN1_L to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
    			in1l_to_rmixer_controls),
    	SND_SOC_DAPM_MUX("IN3_L to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
    			in3l_to_rmixer_controls),
    
    	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", AIC32X4_ADCSETUP, 7, 0),
    	SND_SOC_DAPM_MUX("IN1_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in1l_to_lmixer_controls),
    	SND_SOC_DAPM_MUX("IN2_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in2l_to_lmixer_controls),
    	SND_SOC_DAPM_MUX("IN3_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in3l_to_lmixer_controls),
    	SND_SOC_DAPM_MUX("IN1_R to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
    			in1r_to_lmixer_controls),
    	SND_SOC_DAPM_MUX("CM_L to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
    			cml_to_lmixer_controls),
    	SND_SOC_DAPM_MUX("IN2_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
    			in2r_to_lmixer_controls),
    	SND_SOC_DAPM_MUX("IN3_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
    			in3r_to_lmixer_controls),
    
    	SND_SOC_DAPM_SUPPLY("Mic Bias", AIC32X4_MICBIAS, 6, 0, mic_bias_event,
    			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
    
    	SND_SOC_DAPM_POST("ADC Reset", aic32x4_reset_adc),
    
    	SND_SOC_DAPM_OUTPUT("HPL"),
    	SND_SOC_DAPM_OUTPUT("HPR"),
    	SND_SOC_DAPM_OUTPUT("LOL"),
    	SND_SOC_DAPM_OUTPUT("LOR"),
    	SND_SOC_DAPM_INPUT("IN1_L"),
    	SND_SOC_DAPM_INPUT("IN1_R"),
    	SND_SOC_DAPM_INPUT("IN2_L"),
    	SND_SOC_DAPM_INPUT("IN2_R"),
    	SND_SOC_DAPM_INPUT("IN3_L"),
    	SND_SOC_DAPM_INPUT("IN3_R"),
    	SND_SOC_DAPM_INPUT("CM_L"),
    	SND_SOC_DAPM_INPUT("CM_R"),
    };
    
    static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = {
    	/* Left Output */
    	{"HPL Output Mixer", "L_DAC Switch", "Left DAC"},
    	{"HPL Output Mixer", "IN1_L Switch", "IN1_L"},
    
    	{"HPL Power", NULL, "HPL Output Mixer"},
    	{"HPL", NULL, "HPL Power"},
    
    	{"LOL Output Mixer", "L_DAC Switch", "Left DAC"},
    
    	{"LOL Power", NULL, "LOL Output Mixer"},
    	{"LOL", NULL, "LOL Power"},
    
    	/* Right Output */
    	{"HPR Output Mixer", "R_DAC Switch", "Right DAC"},
    	{"HPR Output Mixer", "IN1_R Switch", "IN1_R"},
    
    	{"HPR Power", NULL, "HPR Output Mixer"},
    	{"HPR", NULL, "HPR Power"},
    
    	{"LOR Output Mixer", "R_DAC Switch", "Right DAC"},
    
    	{"LOR Power", NULL, "LOR Output Mixer"},
    	{"LOR", NULL, "LOR Power"},
    
    	/* Right Input */
    	{"Right ADC", NULL, "IN1_R to Right Mixer Positive Resistor"},
    	{"IN1_R to Right Mixer Positive Resistor", "10 kOhm", "IN1_R"},
    	{"IN1_R to Right Mixer Positive Resistor", "20 kOhm", "IN1_R"},
    	{"IN1_R to Right Mixer Positive Resistor", "40 kOhm", "IN1_R"},
    
    	{"Right ADC", NULL, "IN2_R to Right Mixer Positive Resistor"},
    	{"IN2_R to Right Mixer Positive Resistor", "10 kOhm", "IN2_R"},
    	{"IN2_R to Right Mixer Positive Resistor", "20 kOhm", "IN2_R"},
    	{"IN2_R to Right Mixer Positive Resistor", "40 kOhm", "IN2_R"},
    
    	{"Right ADC", NULL, "IN3_R to Right Mixer Positive Resistor"},
    	{"IN3_R to Right Mixer Positive Resistor", "10 kOhm", "IN3_R"},
    	{"IN3_R to Right Mixer Positive Resistor", "20 kOhm", "IN3_R"},
    	{"IN3_R to Right Mixer Positive Resistor", "40 kOhm", "IN3_R"},
    
    	{"Right ADC", NULL, "IN2_L to Right Mixer Positive Resistor"},
    	{"IN2_L to Right Mixer Positive Resistor", "10 kOhm", "IN2_L"},
    	{"IN2_L to Right Mixer Positive Resistor", "20 kOhm", "IN2_L"},
    	{"IN2_L to Right Mixer Positive Resistor", "40 kOhm", "IN2_L"},
    
    	{"Right ADC", NULL, "CM_R to Right Mixer Negative Resistor"},
    	{"CM_R to Right Mixer Negative Resistor", "10 kOhm", "CM_R"},
    	{"CM_R to Right Mixer Negative Resistor", "20 kOhm", "CM_R"},
    	{"CM_R to Right Mixer Negative Resistor", "40 kOhm", "CM_R"},
    
    	{"Right ADC", NULL, "IN1_L to Right Mixer Negative Resistor"},
    	{"IN1_L to Right Mixer Negative Resistor", "10 kOhm", "IN1_L"},
    	{"IN1_L to Right Mixer Negative Resistor", "20 kOhm", "IN1_L"},
    	{"IN1_L to Right Mixer Negative Resistor", "40 kOhm", "IN1_L"},
    
    	{"Right ADC", NULL, "IN3_L to Right Mixer Negative Resistor"},
    	{"IN3_L to Right Mixer Negative Resistor", "10 kOhm", "IN3_L"},
    	{"IN3_L to Right Mixer Negative Resistor", "20 kOhm", "IN3_L"},
    	{"IN3_L to Right Mixer Negative Resistor", "40 kOhm", "IN3_L"},
    
    	/* Left Input */
    	{"Left ADC", NULL, "IN1_L to Left Mixer Positive Resistor"},
    	{"IN1_L to Left Mixer Positive Resistor", "10 kOhm", "IN1_L"},
    	{"IN1_L to Left Mixer Positive Resistor", "20 kOhm", "IN1_L"},
    	{"IN1_L to Left Mixer Positive Resistor", "40 kOhm", "IN1_L"},
    
    	{"Left ADC", NULL, "IN2_L to Left Mixer Positive Resistor"},
    	{"IN2_L to Left Mixer Positive Resistor", "10 kOhm", "IN2_L"},
    	{"IN2_L to Left Mixer Positive Resistor", "20 kOhm", "IN2_L"},
    	{"IN2_L to Left Mixer Positive Resistor", "40 kOhm", "IN2_L"},
    
    	{"Left ADC", NULL, "IN3_L to Left Mixer Positive Resistor"},
    	{"IN3_L to Left Mixer Positive Resistor", "10 kOhm", "IN3_L"},
    	{"IN3_L to Left Mixer Positive Resistor", "20 kOhm", "IN3_L"},
    	{"IN3_L to Left Mixer Positive Resistor", "40 kOhm", "IN3_L"},
    
    	{"Left ADC", NULL, "IN1_R to Left Mixer Positive Resistor"},
    	{"IN1_R to Left Mixer Positive Resistor", "10 kOhm", "IN1_R"},
    	{"IN1_R to Left Mixer Positive Resistor", "20 kOhm", "IN1_R"},
    	{"IN1_R to Left Mixer Positive Resistor", "40 kOhm", "IN1_R"},
    
    	{"Left ADC", NULL, "CM_L to Left Mixer Negative Resistor"},
    	{"CM_L to Left Mixer Negative Resistor", "10 kOhm", "CM_L"},
    	{"CM_L to Left Mixer Negative Resistor", "20 kOhm", "CM_L"},
    	{"CM_L to Left Mixer Negative Resistor", "40 kOhm", "CM_L"},
    
    	{"Left ADC", NULL, "IN2_R to Left Mixer Negative Resistor"},
    	{"IN2_R to Left Mixer Negative Resistor", "10 kOhm", "IN2_R"},
    	{"IN2_R to Left Mixer Negative Resistor", "20 kOhm", "IN2_R"},
    	{"IN2_R to Left Mixer Negative Resistor", "40 kOhm", "IN2_R"},
    
    	{"Left ADC", NULL, "IN3_R to Left Mixer Negative Resistor"},
    	{"IN3_R to Left Mixer Negative Resistor", "10 kOhm", "IN3_R"},
    	{"IN3_R to Left Mixer Negative Resistor", "20 kOhm", "IN3_R"},
    	{"IN3_R to Left Mixer Negative Resistor", "40 kOhm", "IN3_R"},
    };
    
    static const struct regmap_range_cfg aic32x4_regmap_pages[] = {
    	{
    		.selector_reg = 0,
    		.selector_mask	= 0xff,
    		.window_start = 0,
    		.window_len = 128,
    		.range_min = 0,
    		.range_max = AIC32X4_REFPOWERUP,
    	},
    };
    
    const struct regmap_config aic32x4_regmap_config = {
    	.max_register = AIC32X4_REFPOWERUP,
    	.ranges = aic32x4_regmap_pages,
    	.num_ranges = ARRAY_SIZE(aic32x4_regmap_pages),
    };
    EXPORT_SYMBOL(aic32x4_regmap_config);
    
    static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
    				  int clk_id, unsigned int freq, int dir)
    {
    	struct snd_soc_component *component = codec_dai->component;
    	//struct clk *mclk;
    	struct clk *pll;
    	int ret = -1;
    	static struct clk_bulk_data clocks[] = {
    		{ .id = "pll" },	
    	};
    	dev_err(component->dev, "%s:clk_id(%d), freq(%d), dir(%d)\n", __FUNCTION__, clk_id, freq, dir);
    #if 0
    	pll = devm_clk_get(component->dev, "pll");
    	if (IS_ERR(pll)){
    		dev_err(component->dev, "%s:IS_ERR(pll)(%d)\n", __FUNCTION__, IS_ERR(pll));
    		return PTR_ERR(pll);
    	}
    	mclk = clk_get_parent(pll);
    #else
    	dev_err(component->dev, "%s:devm_clk_bulk_get \n", __FUNCTION__);
    	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);	
    	if (ret){	
    		dev_err(component->dev, "%s:devm_clk_bulk_get error ret(%d)\n", __FUNCTION__, ret);
    		return ret;	
    	}
    #endif
    	//ret=clk_set_rate(mclk, freq);
    	/* for debug */
    	pll = clocks[0].clk;
    	//pll->core->parent->rate = freq;
    	//pll->core->new_parent->rate = freq;
    	ret=clk_set_rate(pll, freq);
    	dev_err(component->dev, "%s:clk_set_rate(pll, %d) ret(%d)\n", __FUNCTION__, freq, ret);
    	return ret;//clk_set_rate(mclk, freq);
    }
    
    static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
    {
    	struct snd_soc_component *component = codec_dai->component;
    	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
    	u8 iface_reg_1 = 0;
    	u8 iface_reg_2 = 0;
    	u8 iface_reg_3 = 0;
    	dev_err(component->dev, "%s: fmt(0x%x)\n", __FUNCTION__, fmt);
    
    	/* set master/slave audio interface */
    	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
    	case SND_SOC_DAIFMT_CBM_CFM:
    		iface_reg_1 |= AIC32X4_BCLKMASTER | AIC32X4_WCLKMASTER;
    		break;
    	case SND_SOC_DAIFMT_CBS_CFS:
    		break;
    	default:
    		printk(KERN_ERR "aic32x4: invalid DAI master/slave interface\n");
    		return -EINVAL;
    	}
    
    	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
    	case SND_SOC_DAIFMT_I2S:
    		break;
    	case SND_SOC_DAIFMT_DSP_A:
    		iface_reg_1 |= (AIC32X4_DSP_MODE <<
    				AIC32X4_IFACE1_DATATYPE_SHIFT);
    		iface_reg_3 |= AIC32X4_BCLKINV_MASK; /* invert bit clock */
    		iface_reg_2 = 0x01; /* add offset 1 */
    		break;
    	case SND_SOC_DAIFMT_DSP_B:
    		iface_reg_1 |= (AIC32X4_DSP_MODE <<
    				AIC32X4_IFACE1_DATATYPE_SHIFT);
    		iface_reg_3 |= AIC32X4_BCLKINV_MASK; /* invert bit clock */
    		break;
    	case SND_SOC_DAIFMT_RIGHT_J:
    		iface_reg_1 |= (AIC32X4_RIGHT_JUSTIFIED_MODE <<
    				AIC32X4_IFACE1_DATATYPE_SHIFT);
    		break;
    	case SND_SOC_DAIFMT_LEFT_J:
    		iface_reg_1 |= (AIC32X4_LEFT_JUSTIFIED_MODE <<
    				AIC32X4_IFACE1_DATATYPE_SHIFT);
    		break;
    	default:
    		printk(KERN_ERR "aic32x4: invalid DAI interface format\n");
    		return -EINVAL;
    	}
    
    	aic32x4->fmt = fmt;
    
    	snd_soc_component_update_bits(component, AIC32X4_IFACE1,
    				AIC32X4_IFACE1_DATATYPE_MASK |
    				AIC32X4_IFACE1_MASTER_MASK, iface_reg_1);
    	snd_soc_component_update_bits(component, AIC32X4_IFACE2,
    				AIC32X4_DATA_OFFSET_MASK, iface_reg_2);
    	snd_soc_component_update_bits(component, AIC32X4_IFACE3,
    				AIC32X4_BCLKINV_MASK, iface_reg_3);
    
    	return 0;
    }
    
    static int aic32x4_set_aosr(struct snd_soc_component *component, u8 aosr)
    {
    	return snd_soc_component_write(component, AIC32X4_AOSR, aosr);
    }
    
    static int aic32x4_set_dosr(struct snd_soc_component *component, u16 dosr)
    {
    	snd_soc_component_write(component, AIC32X4_DOSRMSB, dosr >> 8);
    	snd_soc_component_write(component, AIC32X4_DOSRLSB,
    		      (dosr & 0xff));
    
    	return 0;
    }
    
    static int aic32x4_set_processing_blocks(struct snd_soc_component *component,
    						u8 r_block, u8 p_block)
    {
    	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
    
    	if (aic32x4->type == AIC32X4_TYPE_TAS2505) {
    		if (r_block || p_block > 3)
    			return -EINVAL;
    
    		snd_soc_component_write(component, AIC32X4_DACSPB, p_block);
    	} else { /* AIC32x4 */
    		if (r_block > 18 || p_block > 25)
    			return -EINVAL;
    
    		snd_soc_component_write(component, AIC32X4_ADCSPB, r_block);
    		snd_soc_component_write(component, AIC32X4_DACSPB, p_block);
    	}
    
    	return 0;
    }
    
    static int aic32x4_setup_clocks(struct snd_soc_component *component,
    				unsigned int sample_rate, unsigned int channels,
    				unsigned int bit_depth)
    {
    	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
    	u8 aosr;
    	u16 dosr;
    	u8 adc_resource_class, dac_resource_class;
    	u8 madc, nadc, mdac, ndac, max_nadc, min_mdac, max_ndac;
    	u8 dosr_increment;
    	u16 max_dosr, min_dosr;
    	unsigned long adc_clock_rate, dac_clock_rate;
    	int ret;
    	struct clk *pll;
    
    	static struct clk_bulk_data clocks[] = {
    		{ .id = "pll" },
    		{ .id = "nadc" },
    		{ .id = "madc" },
    		{ .id = "ndac" },
    		{ .id = "mdac" },
    		{ .id = "bdiv" },
    	};
    	dev_err(component->dev, "aic32x4_setup_clocks sample_rate(%d), channels(%d), bit_depth(%d)\n", sample_rate, channels, bit_depth);
    	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
    
    	pll = clocks[0].clk;
    	ret=clk_set_rate(pll, 12288000);
    
    
    
    	if (ret)
    		return ret;
    	dev_err(component->dev, "clocks[0~5].clk(%d,%d,%d,%d,%d,%d)\n", clocks[0].clk->core->parent->rate, clocks[1].clk->core->parent->rate, 
    		clocks[2].clk->core->parent->rate, clocks[3].clk->core->parent->rate, clocks[4].clk->core->parent->rate, clocks[5].clk->core->parent->rate);
    
    	if (sample_rate <= 48000) {
    		aosr = 128;
    		adc_resource_class = 6;
    		dac_resource_class = 8;
    		dosr_increment = 8;
    		if (aic32x4->type == AIC32X4_TYPE_TAS2505)
    			aic32x4_set_processing_blocks(component, 0, 1);
    		else
    			aic32x4_set_processing_blocks(component, 1, 1);
    	} else if (sample_rate <= 96000) {
    		aosr = 64;
    		adc_resource_class = 6;
    		dac_resource_class = 8;
    		dosr_increment = 4;
    		if (aic32x4->type == AIC32X4_TYPE_TAS2505)
    			aic32x4_set_processing_blocks(component, 0, 1);
    		else
    			aic32x4_set_processing_blocks(component, 1, 9);
    	} else if (sample_rate == 192000) {
    		aosr = 32;
    		adc_resource_class = 3;
    		dac_resource_class = 4;
    		dosr_increment = 2;
    		if (aic32x4->type == AIC32X4_TYPE_TAS2505)
    			aic32x4_set_processing_blocks(component, 0, 1);
    		else
    			aic32x4_set_processing_blocks(component, 13, 19);
    	} else {
    		dev_err(component->dev, "Sampling rate not supported\n");
    		return -EINVAL;
    	}
    	dev_err(component->dev, "aic32x4->fmt(0x%x)\n", aic32x4->fmt );
    
    	/* PCM over I2S is always 2-channel */
    	if ((aic32x4->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S)
    		channels = 2;
    
    	madc = DIV_ROUND_UP((32 * adc_resource_class), aosr);
    	max_dosr = (AIC32X4_MAX_DOSR_FREQ / sample_rate / dosr_increment) *
    			dosr_increment;
    	min_dosr = (AIC32X4_MIN_DOSR_FREQ / sample_rate / dosr_increment) *
    			dosr_increment;
    	max_nadc = AIC32X4_MAX_CODEC_CLKIN_FREQ / (madc * aosr * sample_rate);
    
    	dev_err(component->dev, "aosr(%d), adc_resource_class(%d), dac_resource_class(%d), dosr_increment(%d)\n", aosr, adc_resource_class, dac_resource_class, dosr_increment);
    		
    	dev_err(component->dev, "madc(%d), max_dosr(%d), min_dosr(%d), max_nadc(%d)\n", madc, max_dosr, min_dosr, max_nadc);
    
    	for (nadc = max_nadc; nadc > 0; --nadc) {
    		adc_clock_rate = nadc * madc * aosr * sample_rate;
    		dev_err(component->dev, "adc_clock_rate(%d x %d x %d)(%d)\n", nadc, madc, aosr, adc_clock_rate);
    		for (dosr = max_dosr; dosr >= min_dosr;
    				dosr -= dosr_increment) {
    			min_mdac = DIV_ROUND_UP((32 * dac_resource_class), dosr);
    			max_ndac = AIC32X4_MAX_CODEC_CLKIN_FREQ /
    					(min_mdac * dosr * sample_rate);
    			dev_err(component->dev, "min_mdac %d=DIV_ROUND_UP((32 * %d), %d)=\n", min_mdac, dac_resource_class, dosr);
    			dev_err(component->dev, "max_ndac %d= %d /(%d * %d * %d)\n", max_ndac,AIC32X4_MAX_CODEC_CLKIN_FREQ, min_mdac, dosr, sample_rate);
    			for (mdac = min_mdac; mdac <= 128; ++mdac) {
    				for (ndac = max_ndac; ndac > 0; --ndac) {
    					dac_clock_rate = ndac * mdac * dosr *
    							sample_rate;
    					if (dac_clock_rate == adc_clock_rate) {
    						dev_err(component->dev, "                                  dac_clock_rate(%d x %d x %d)(%d)\n", ndac, mdac, dosr, dac_clock_rate);
    						if (clk_round_rate(clocks[0].clk, dac_clock_rate) == 0)
    							continue;
    
    						clk_set_rate(clocks[0].clk,
    							dac_clock_rate);
    
    						clk_set_rate(clocks[1].clk,
    							sample_rate * aosr *
    							madc);
    						clk_set_rate(clocks[2].clk,
    							sample_rate * aosr);
    						aic32x4_set_aosr(component,
    							aosr);
    
    						clk_set_rate(clocks[3].clk,
    							sample_rate * dosr *
    							mdac);
    						clk_set_rate(clocks[4].clk,
    							sample_rate * dosr);
    						aic32x4_set_dosr(component,
    							dosr);
    
    						clk_set_rate(clocks[5].clk,
    							sample_rate * channels *
    							bit_depth);
    
    						return 0;
    					}
    				}
    			}
    		}
    	}
    
    	dev_err(component->dev,
    		"Could not set clocks to support sample rate.\n");
    	return -EINVAL;
    }
    
    static int aic32x4_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 aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
    	u8 iface1_reg = 0;
    	u8 dacsetup_reg = 0;
    	dev_err(component->dev, "%s:\n", __FUNCTION__ );
    	aic32x4_setup_clocks(component, params_rate(params),
    			     params_channels(params),
    			     params_physical_width(params));
    
    	switch (params_physical_width(params)) {
    	case 16:
    		iface1_reg |= (AIC32X4_WORD_LEN_16BITS <<
    				   AIC32X4_IFACE1_DATALEN_SHIFT);
    		break;
    	case 20:
    		iface1_reg |= (AIC32X4_WORD_LEN_20BITS <<
    				   AIC32X4_IFACE1_DATALEN_SHIFT);
    		break;
    	case 24:
    		iface1_reg |= (AIC32X4_WORD_LEN_24BITS <<
    				   AIC32X4_IFACE1_DATALEN_SHIFT);
    		break;
    	case 32:
    		iface1_reg |= (AIC32X4_WORD_LEN_32BITS <<
    				   AIC32X4_IFACE1_DATALEN_SHIFT);
    		break;
    	}
    	snd_soc_component_update_bits(component, AIC32X4_IFACE1,
    				AIC32X4_IFACE1_DATALEN_MASK, iface1_reg);
    
    	if (params_channels(params) == 1) {
    		dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN;
    	} else {
    		if (aic32x4->swapdacs)
    			dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2RCHN;
    		else
    			dacsetup_reg = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN;
    	}
    	snd_soc_component_update_bits(component, AIC32X4_DACSETUP,
    				AIC32X4_DAC_CHAN_MASK, dacsetup_reg);
    
    	return 0;
    }
    
    static int aic32x4_mute(struct snd_soc_dai *dai, int mute, int direction)
    {
    	struct snd_soc_component *component = dai->component;
    	dev_err(component->dev, "%s:\n", __FUNCTION__ );
    
    	snd_soc_component_update_bits(component, AIC32X4_DACMUTE,
    				AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0);
    
    	return 0;
    }
    
    static int aic32x4_set_bias_level(struct snd_soc_component *component,
    				  enum snd_soc_bias_level level)
    {
    	int ret;
    
    	static struct clk_bulk_data clocks[] = {
    		{ .id = "madc" },
    		{ .id = "mdac" },
    		{ .id = "bdiv" },
    	};
    	dev_err(component->dev, "%s:\n", __FUNCTION__ );
    
    	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
    	if (ret)
    		return ret;
    
    	switch (level) {
    	case SND_SOC_BIAS_ON:
    		ret = clk_bulk_prepare_enable(ARRAY_SIZE(clocks), clocks);
    		if (ret) {
    			dev_err(component->dev, "Failed to enable clocks\n");
    			return ret;
    		}
    		break;
    	case SND_SOC_BIAS_PREPARE:
    		break;
    	case SND_SOC_BIAS_STANDBY:
    		/* Initial cold start */
    		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
    			break;
    
    		clk_bulk_disable_unprepare(ARRAY_SIZE(clocks), clocks);
    		break;
    	case SND_SOC_BIAS_OFF:
    		break;
    	}
    	return 0;
    }
    
    #define AIC32X4_RATES	SNDRV_PCM_RATE_8000_192000
    #define AIC32X4_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 aic32x4_ops = {
    	.hw_params = aic32x4_hw_params,
    	.mute_stream = aic32x4_mute,
    	.set_fmt = aic32x4_set_dai_fmt,
    	.set_sysclk = aic32x4_set_dai_sysclk,
    	.no_capture_mute = 1,
    };
    
    static struct snd_soc_dai_driver aic32x4_dai = {
    	.name = "tlv320aic32x4-hifi",
    	.playback = {
    			 .stream_name = "Playback",
    			 .channels_min = 1,
    			 .channels_max = 2,
    			 .rates = AIC32X4_RATES,
    			 .formats = AIC32X4_FORMATS,},
    	.capture = {
    			.stream_name = "Capture",
    			.channels_min = 1,
    			.channels_max = 8,
    			.rates = AIC32X4_RATES,
    			.formats = AIC32X4_FORMATS,},
    	.ops = &aic32x4_ops,
    	.symmetric_rate = 1,
    };
    
    static void aic32x4_setup_gpios(struct snd_soc_component *component)
    {
    	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
    
    	/* setup GPIO functions */
    	/* MFP1 */
    	if (aic32x4->setup->gpio_func[0] != AIC32X4_MFPX_DEFAULT_VALUE) {
    		snd_soc_component_write(component, AIC32X4_DINCTL,
    			  aic32x4->setup->gpio_func[0]);
    		snd_soc_add_component_controls(component, aic32x4_mfp1,
    			ARRAY_SIZE(aic32x4_mfp1));
    	}
    
    	/* MFP2 */
    	if (aic32x4->setup->gpio_func[1] != AIC32X4_MFPX_DEFAULT_VALUE) {
    		snd_soc_component_write(component, AIC32X4_DOUTCTL,
    			  aic32x4->setup->gpio_func[1]);
    		snd_soc_add_component_controls(component, aic32x4_mfp2,
    			ARRAY_SIZE(aic32x4_mfp2));
    	}
    
    	/* MFP3 */
    	if (aic32x4->setup->gpio_func[2] != AIC32X4_MFPX_DEFAULT_VALUE) {
    		snd_soc_component_write(component, AIC32X4_SCLKCTL,
    			  aic32x4->setup->gpio_func[2]);
    		snd_soc_add_component_controls(component, aic32x4_mfp3,
    			ARRAY_SIZE(aic32x4_mfp3));
    	}
    
    	/* MFP4 */
    	if (aic32x4->setup->gpio_func[3] != AIC32X4_MFPX_DEFAULT_VALUE) {
    		snd_soc_component_write(component, AIC32X4_MISOCTL,
    			  aic32x4->setup->gpio_func[3]);
    		snd_soc_add_component_controls(component, aic32x4_mfp4,
    			ARRAY_SIZE(aic32x4_mfp4));
    	}
    
    	/* MFP5 */
    	if (aic32x4->setup->gpio_func[4] != AIC32X4_MFPX_DEFAULT_VALUE) {
    		snd_soc_component_write(component, AIC32X4_GPIOCTL,
    			  aic32x4->setup->gpio_func[4]);
    		snd_soc_add_component_controls(component, aic32x4_mfp5,
    			ARRAY_SIZE(aic32x4_mfp5));
    	}
    }
    
    static int aic32x4_component_probe(struct snd_soc_component *component)
    {
    	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
    	u32 tmp_reg;
    	int ret;
    
    	static struct clk_bulk_data clocks[] = {
    		{ .id = "codec_clkin" },
    		{ .id = "pll" },
    		{ .id = "bdiv" },
    		{ .id = "mdac" },
    	};
    	dev_err(component->dev, "%s:\n", __FUNCTION__ );
    
    	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
    	if (ret)
    		return ret;
    
    	if (aic32x4->setup)
    		aic32x4_setup_gpios(component);
    
    	clk_set_parent(clocks[0].clk, clocks[1].clk);
    	clk_set_parent(clocks[2].clk, clocks[3].clk);
    
    	/* Power platform configuration */
    	if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) {
    		snd_soc_component_write(component, AIC32X4_MICBIAS,
    				AIC32X4_MICBIAS_LDOIN | AIC32X4_MICBIAS_2075V);
    	}
    	if (aic32x4->power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE)
    		snd_soc_component_write(component, AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE);
    
    	tmp_reg = (aic32x4->power_cfg & AIC32X4_PWR_AIC32X4_LDO_ENABLE) ?
    			AIC32X4_LDOCTLEN : 0;
    	snd_soc_component_write(component, AIC32X4_LDOCTL, tmp_reg);
    
    	tmp_reg = snd_soc_component_read(component, AIC32X4_CMMODE);
    	if (aic32x4->power_cfg & AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36)
    		tmp_reg |= AIC32X4_LDOIN_18_36;
    	if (aic32x4->power_cfg & AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED)
    		tmp_reg |= AIC32X4_LDOIN2HP;
    	snd_soc_component_write(component, AIC32X4_CMMODE, tmp_reg);
    
    	/* Mic PGA routing */
    	if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K)
    		snd_soc_component_write(component, AIC32X4_LMICPGANIN,
    				AIC32X4_LMICPGANIN_IN2R_10K);
    	else
    		snd_soc_component_write(component, AIC32X4_LMICPGANIN,
    				AIC32X4_LMICPGANIN_CM1L_10K);
    	if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K)
    		snd_soc_component_write(component, AIC32X4_RMICPGANIN,
    				AIC32X4_RMICPGANIN_IN1L_10K);
    	else
    		snd_soc_component_write(component, AIC32X4_RMICPGANIN,
    				AIC32X4_RMICPGANIN_CM1R_10K);
    
    	/*
    	 * Workaround: for an unknown reason, the ADC needs to be powered up
    	 * and down for the first capture to work properly. It seems related to
    	 * a HW BUG or some kind of behavior not documented in the datasheet.
    	 */
    	tmp_reg = snd_soc_component_read(component, AIC32X4_ADCSETUP);
    	snd_soc_component_write(component, AIC32X4_ADCSETUP, tmp_reg |
    				AIC32X4_LADC_EN | AIC32X4_RADC_EN);
    	snd_soc_component_write(component, AIC32X4_ADCSETUP, tmp_reg);
    
    	/*
    	 * Enable the fast charging feature and ensure the needed 40ms ellapsed
    	 * before using the analog circuits.
    	 */
    	snd_soc_component_write(component, AIC32X4_REFPOWERUP,
    				AIC32X4_REFPOWERUP_40MS);
    	msleep(40);
    
    	return 0;
    }
    
    static const struct snd_soc_component_driver soc_component_dev_aic32x4 = {
    	.probe			= aic32x4_component_probe,
    	.set_bias_level		= aic32x4_set_bias_level,
    	.controls		= aic32x4_snd_controls,
    	.num_controls		= ARRAY_SIZE(aic32x4_snd_controls),
    	.dapm_widgets		= aic32x4_dapm_widgets,
    	.num_dapm_widgets	= ARRAY_SIZE(aic32x4_dapm_widgets),
    	.dapm_routes		= aic32x4_dapm_routes,
    	.num_dapm_routes	= ARRAY_SIZE(aic32x4_dapm_routes),
    	.suspend_bias_off	= 1,
    	.idle_bias_on		= 1,
    	.use_pmdown_time	= 1,
    	.endianness		= 1,
    	.non_legacy_dai_naming	= 1,
    };
    
    static const struct snd_kcontrol_new aic32x4_tas2505_snd_controls[] = {
    	SOC_SINGLE_S8_TLV("PCM Playback Volume",
    			  AIC32X4_LDACVOL, -0x7f, 0x30, tlv_pcm),
    	SOC_ENUM("DAC Playback PowerTune Switch", l_ptm_enum),
    
    	SOC_SINGLE_TLV("HP Driver Gain Volume",
    			AIC32X4_HPLGAIN, 0, 0x74, 1, tlv_tas_driver_gain),
    	SOC_SINGLE("HP DAC Playback Switch", AIC32X4_HPLGAIN, 6, 1, 1),
    
    	SOC_SINGLE_TLV("Speaker Driver Playback Volume",
    			TAS2505_SPKVOL1, 0, 0x74, 1, tlv_tas_driver_gain),
    	SOC_SINGLE_TLV("Speaker Amplifier Playback Volume",
    			TAS2505_SPKVOL2, 4, 5, 0, tlv_amp_vol),
    
    	SOC_SINGLE("Auto-mute Switch", AIC32X4_DACMUTE, 4, 7, 0),
    };
    
    static const struct snd_kcontrol_new hp_output_mixer_controls[] = {
    	SOC_DAPM_SINGLE("DAC Switch", AIC32X4_HPLROUTE, 3, 1, 0),
    };
    
    static const struct snd_soc_dapm_widget aic32x4_tas2505_dapm_widgets[] = {
    	SND_SOC_DAPM_DAC("DAC", "Playback", AIC32X4_DACSETUP, 7, 0),
    	SND_SOC_DAPM_MIXER("HP Output Mixer", SND_SOC_NOPM, 0, 0,
    			   &hp_output_mixer_controls[0],
    			   ARRAY_SIZE(hp_output_mixer_controls)),
    	SND_SOC_DAPM_PGA("HP Power", AIC32X4_OUTPWRCTL, 5, 0, NULL, 0),
    
    	SND_SOC_DAPM_PGA("Speaker Driver", TAS2505_SPK, 1, 0, NULL, 0),
    
    	SND_SOC_DAPM_OUTPUT("HP"),
    	SND_SOC_DAPM_OUTPUT("Speaker"),
    };
    
    static const struct snd_soc_dapm_route aic32x4_tas2505_dapm_routes[] = {
    	/* Left Output */
    	{"HP Output Mixer", "DAC Switch", "DAC"},
    
    	{"HP Power", NULL, "HP Output Mixer"},
    	{"HP", NULL, "HP Power"},
    
    	{"Speaker Driver", NULL, "DAC"},
    	{"Speaker", NULL, "Speaker Driver"},
    };
    
    static struct snd_soc_dai_driver aic32x4_tas2505_dai = {
    	.name = "tas2505-hifi",
    	.playback = {
    			 .stream_name = "Playback",
    			 .channels_min = 1,
    			 .channels_max = 2,
    			 .rates = SNDRV_PCM_RATE_8000_96000,
    			 .formats = AIC32X4_FORMATS,},
    	.ops = &aic32x4_ops,
    	.symmetric_rate = 1,
    };
    
    static int aic32x4_tas2505_component_probe(struct snd_soc_component *component)
    {
    	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
    	u32 tmp_reg;
    	int ret;
    
    	static struct clk_bulk_data clocks[] = {
    		{ .id = "codec_clkin" },
    		{ .id = "pll" },
    		{ .id = "bdiv" },
    		{ .id = "mdac" },
    	};
    
    	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
    	if (ret)
    		return ret;
    
    	if (aic32x4->setup)
    		aic32x4_setup_gpios(component);
    
    	clk_set_parent(clocks[0].clk, clocks[1].clk);
    	clk_set_parent(clocks[2].clk, clocks[3].clk);
    
    	/* Power platform configuration */
    	if (aic32x4->power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE)
    		snd_soc_component_write(component, AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE);
    
    	tmp_reg = (aic32x4->power_cfg & AIC32X4_PWR_AIC32X4_LDO_ENABLE) ?
    			AIC32X4_LDOCTLEN : 0;
    	snd_soc_component_write(component, AIC32X4_LDOCTL, tmp_reg);
    
    	tmp_reg = snd_soc_component_read(component, AIC32X4_CMMODE);
    	if (aic32x4->power_cfg & AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36)
    		tmp_reg |= AIC32X4_LDOIN_18_36;
    	if (aic32x4->power_cfg & AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED)
    		tmp_reg |= AIC32X4_LDOIN2HP;
    	snd_soc_component_write(component, AIC32X4_CMMODE, tmp_reg);
    
    	/*
    	 * Enable the fast charging feature and ensure the needed 40ms ellapsed
    	 * before using the analog circuits.
    	 */
    	snd_soc_component_write(component, TAS2505_REFPOWERUP,
    				AIC32X4_REFPOWERUP_40MS);
    	msleep(40);
    
    	return 0;
    }
    
    static const struct snd_soc_component_driver soc_component_dev_aic32x4_tas2505 = {
    	.probe			= aic32x4_tas2505_component_probe,
    	.set_bias_level		= aic32x4_set_bias_level,
    	.controls		= aic32x4_tas2505_snd_controls,
    	.num_controls		= ARRAY_SIZE(aic32x4_tas2505_snd_controls),
    	.dapm_widgets		= aic32x4_tas2505_dapm_widgets,
    	.num_dapm_widgets	= ARRAY_SIZE(aic32x4_tas2505_dapm_widgets),
    	.dapm_routes		= aic32x4_tas2505_dapm_routes,
    	.num_dapm_routes	= ARRAY_SIZE(aic32x4_tas2505_dapm_routes),
    	.suspend_bias_off	= 1,
    	.idle_bias_on		= 1,
    	.use_pmdown_time	= 1,
    	.endianness		= 1,
    	.non_legacy_dai_naming	= 1,
    };
    
    static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4,
    		struct device_node *np)
    {
    	struct aic32x4_setup_data *aic32x4_setup;
    //	int ret;
    
    	aic32x4_setup = devm_kzalloc(aic32x4->dev, sizeof(*aic32x4_setup),
    							GFP_KERNEL);
    	if (!aic32x4_setup)
    		return -ENOMEM;
    
    //	ret = of_property_match_string(np, "clock-names", "mclk");
    //	if (ret < 0)
    //		return -EINVAL;
    	aic32x4->mclk_name = "mclk";//of_clk_get_parent_name(np, ret);
    
    	aic32x4->swapdacs = false;
    	aic32x4->micpga_routing = 0;
    	aic32x4->rstn_gpio = of_get_named_gpio(np, "reset-gpios", 0);
    
    	if (of_property_read_u32_array(np, "aic32x4-gpio-func",
    				aic32x4_setup->gpio_func, 5) >= 0)
    		aic32x4->setup = aic32x4_setup;
    	return 0;
    }
    
    static void aic32x4_disable_regulators(struct aic32x4_priv *aic32x4)
    {
    	regulator_disable(aic32x4->supply_iov);
    
    	if (!IS_ERR(aic32x4->supply_ldo))
    		regulator_disable(aic32x4->supply_ldo);
    
    	if (!IS_ERR(aic32x4->supply_dv))
    		regulator_disable(aic32x4->supply_dv);
    
    	if (!IS_ERR(aic32x4->supply_av))
    		regulator_disable(aic32x4->supply_av);
    }
    
    static int aic32x4_setup_regulators(struct device *dev,
    		struct aic32x4_priv *aic32x4)
    {
    	int ret = 0;
    
    	aic32x4->supply_ldo = devm_regulator_get_optional(dev, "ldoin");
    	aic32x4->supply_iov = devm_regulator_get(dev, "iov");
    	aic32x4->supply_dv = devm_regulator_get_optional(dev, "dv");
    	aic32x4->supply_av = devm_regulator_get_optional(dev, "av");
    
    	/* Check if the regulator requirements are fulfilled */
    
    	if (IS_ERR(aic32x4->supply_iov)) {
    		dev_err(dev, "Missing supply 'iov'\n");
    		return PTR_ERR(aic32x4->supply_iov);
    	}
    
    	if (IS_ERR(aic32x4->supply_ldo)) {
    		if (PTR_ERR(aic32x4->supply_ldo) == -EPROBE_DEFER)
    			return -EPROBE_DEFER;
    
    		if (IS_ERR(aic32x4->supply_dv)) {
    			dev_err(dev, "Missing supply 'dv' or 'ldoin'\n");
    			return PTR_ERR(aic32x4->supply_dv);
    		}
    		if (IS_ERR(aic32x4->supply_av)) {
    			dev_err(dev, "Missing supply 'av' or 'ldoin'\n");
    			return PTR_ERR(aic32x4->supply_av);
    		}
    	} else {
    		if (PTR_ERR(aic32x4->supply_dv) == -EPROBE_DEFER)
    			return -EPROBE_DEFER;
    		if (PTR_ERR(aic32x4->supply_av) == -EPROBE_DEFER)
    			return -EPROBE_DEFER;
    	}
    
    	ret = regulator_enable(aic32x4->supply_iov);
    	if (ret) {
    		dev_err(dev, "Failed to enable regulator iov\n");
    		return ret;
    	}
    
    	if (!IS_ERR(aic32x4->supply_ldo)) {
    		ret = regulator_enable(aic32x4->supply_ldo);
    		if (ret) {
    			dev_err(dev, "Failed to enable regulator ldo\n");
    			goto error_ldo;
    		}
    	}
    
    	if (!IS_ERR(aic32x4->supply_dv)) {
    		ret = regulator_enable(aic32x4->supply_dv);
    		if (ret) {
    			dev_err(dev, "Failed to enable regulator dv\n");
    			goto error_dv;
    		}
    	}
    
    	if (!IS_ERR(aic32x4->supply_av)) {
    		ret = regulator_enable(aic32x4->supply_av);
    		if (ret) {
    			dev_err(dev, "Failed to enable regulator av\n");
    			goto error_av;
    		}
    	}
    
    	if (!IS_ERR(aic32x4->supply_ldo) && IS_ERR(aic32x4->supply_av))
    		aic32x4->power_cfg |= AIC32X4_PWR_AIC32X4_LDO_ENABLE;
    
    	return 0;
    
    error_av:
    	if (!IS_ERR(aic32x4->supply_dv))
    		regulator_disable(aic32x4->supply_dv);
    
    error_dv:
    	if (!IS_ERR(aic32x4->supply_ldo))
    		regulator_disable(aic32x4->supply_ldo);
    
    error_ldo:
    	regulator_disable(aic32x4->supply_iov);
    	return ret;
    }
    
    int aic32x4_probe(struct device *dev, struct regmap *regmap)
    {
    	struct aic32x4_priv *aic32x4;
    	struct aic32x4_pdata *pdata = dev->platform_data;
    	struct device_node *np = dev->of_node;
    	int ret;
    	dev_err(dev, "aic32x4_probe\n");
    	if (IS_ERR(regmap))
    		return PTR_ERR(regmap);
    
    	aic32x4 = devm_kzalloc(dev, sizeof(struct aic32x4_priv),
    				   GFP_KERNEL);
    	if (aic32x4 == NULL)
    		return -ENOMEM;
    
    	aic32x4->dev = dev;
    	aic32x4->type = (enum aic32x4_type)dev_get_drvdata(dev);
    
    	dev_set_drvdata(dev, aic32x4);
    
    	if (pdata) {
    		aic32x4->power_cfg = pdata->power_cfg;
    		aic32x4->swapdacs = pdata->swapdacs;
    		aic32x4->micpga_routing = pdata->micpga_routing;
    		aic32x4->rstn_gpio = pdata->rstn_gpio;
    		aic32x4->mclk_name = "mclk";
    	} else if (np) {
    		ret = aic32x4_parse_dt(aic32x4, np);
    		if (ret) {
    			dev_err(dev, "Failed to parse DT node\n");
    			return ret;
    		}
    	} else {
    		aic32x4->power_cfg = 0;
    		aic32x4->swapdacs = false;
    		aic32x4->micpga_routing = 0;
    		aic32x4->rstn_gpio = -1;
    		aic32x4->mclk_name = "mclk";
    	}
    	dev_err(dev, "aic32x4->rstn_gpio (%d)\n", aic32x4->rstn_gpio);
    	if (gpio_is_valid(aic32x4->rstn_gpio)) {
    		ret = devm_gpio_request_one(dev, aic32x4->rstn_gpio,
    				GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn");
    		if (ret != 0)
    			return ret;
    	}
    	dev_err(dev, "aic32x4_setup_regulators\n");
    	ret = aic32x4_setup_regulators(dev, aic32x4);
    	if (ret) {
    		dev_err(dev, "Failed to setup regulators\n");
    		return ret;
    	}
    
    	if (gpio_is_valid(aic32x4->rstn_gpio)) {
    		ndelay(10);
    		gpio_set_value_cansleep(aic32x4->rstn_gpio, 1);
    		mdelay(1);
    	}
    	dev_err(dev, "regmap_write AIC32X4_RESET\n");
    	ret = regmap_write(regmap, AIC32X4_RESET, 0x01);
    	if (ret){
    		dev_err(dev, "Failed to regmap_write AIC32X4_RESET\n");
    		goto err_disable_regulators;
    	}
    
    	ret = aic32x4_register_clocks(dev, aic32x4->mclk_name);
    	if (ret){
    		dev_err(dev, "Failed to aic32x4_register_clocks\n");
    		goto err_disable_regulators;
    	}
    
    	switch (aic32x4->type) {
    	case AIC32X4_TYPE_TAS2505:
    		ret = devm_snd_soc_register_component(dev,
    			&soc_component_dev_aic32x4_tas2505, &aic32x4_tas2505_dai, 1);
    		break;
    	default:
    		ret = devm_snd_soc_register_component(dev,
    			&soc_component_dev_aic32x4, &aic32x4_dai, 1);
    	}
    
    	if (ret) {
    		dev_err(dev, "Failed to register component\n");
    		goto err_disable_regulators;
    	}
    	dev_err(dev, "aic32x4_probe done\n");
    	return 0;
    
    err_disable_regulators:
    	aic32x4_disable_regulators(aic32x4);
    
    	return ret;
    }
    EXPORT_SYMBOL(aic32x4_probe);
    
    int aic32x4_remove(struct device *dev)
    {
    	struct aic32x4_priv *aic32x4 = dev_get_drvdata(dev);
    
    	aic32x4_disable_regulators(aic32x4);
    
    	return 0;
    }
    EXPORT_SYMBOL(aic32x4_remove);
    
    MODULE_DESCRIPTION("ASoC tlv320aic32x4 codec driver");
    MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
    MODULE_LICENSE("GPL");
    

    There are no other error log.

    [   53.162581][ T1924] tlv320aic32x4 2-0018: aic32x4_set_dai_fmt: fmt(0x4001)
    [   53.178360][ T1924] tlv320aic32x4 2-0018: aic32x4_set_dai_sysclk:clk_id(0), freq(12288000), dir(1)
    [   53.187671][ T1924] tlv320aic32x4 2-0018: aic32x4_set_dai_sysclk:devm_clk_bulk_get
    [   53.195633][ T1924] tlv320aic32x4 2-0018: clk_aic32x4_pll_round_rate, rate(12288000), parent_rate(12288000)
    [   53.205726][ T1924] tlv320aic32x4 2-0018: clk_aic32x4_pll_round_rate, rate(12288000), calc_rate(12288000)
    [   53.215650][ T1924] tlv320aic32x4 2-0018: clk_aic32x4_pll_round_rate, rate(12288000), parent_rate(12288000)
    [   53.225716][ T1924] tlv320aic32x4 2-0018: clk_aic32x4_pll_round_rate, rate(12288000), calc_rate(12288000)
    [   53.241055][ T1924] tlv320aic32x4 2-0018: clk_aic32x4_pll_set_rate, rate(12288000), parent_rate(0)
    [   53.250390][ T1924] tlv320aic32x4 2-0018: clk_aic32x4_pll_recalc_rate, parent_rate(0)
    [   53.264877][ T1924] tlv320aic32x4 2-0018: clk_aic32x4_pll_recalc_rate, clk_aic32x4_pll_calc_rate ret(0)
    [   53.295146][ T1924] tlv320aic32x4 2-0018: aic32x4_set_dai_sysclk:clk_set_rate(pll, 12288000) ret(0)
    [   53.305355][ T1924] tlv320aic32x4 2-0018: aic32x4_hw_params:

    However, the sound does not output, too.

  • Hi Daniel,

    OK, if you force to set parent_rate without error, then could you check if you can get the correct BCLK & WCLK? and we also need regdump to check the configuration.(use i2cdump command)

    However, I don't think this should be the final solution, this driver should be able to support Slave mode, but it doesn't look like it is currently supported, we should use BCLK as PLL input source, no need to add MCLK, I checked with some other driver. and made some modification in aic32x4_set_dai_sysclk(), Can you revert your changes and use below codes? Let's see what will happen

    static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
    				  int clk_id, unsigned int freq, int dir)
    {
    	struct snd_soc_component *component = codec_dai->component;
    	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
    	struct clk *pll;
    	int ret = -1;
    	dev_err(component->dev, "%s:clk_id(%d), freq(%d)\n", __FUNCTION__, clk_id, freq);
    
    	static struct clk_bulk_data clocks[] = {
    		{ .id = "mclk" },
    		{ .id = "bclk" },
    		{ .id = "pll" }
    	};
    
    	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
    	if (ret)
    		return ret;
    
    	if (aic32x4->fmt & SND_SOC_DAIFMT_MASTER_MASK == SND_SOC_DAIFMT_CBS_CFS) { //slave mode
    		clk_set_rate(clocks[1].clk, 32*48000);
    		clk_set_parent(clocks[2].clk, clocks[1].clk);
    	} else { //Master mode
    		clk_set_rate(clocks[0].clk, freq);
    		clk_set_parent(clocks[2].clk, clocks[0].clk);
    	}
    
    	return 0;
    }
    

    Thanks

    Kevin

  • Dear Kevin

    Please provide the register that you need.

    Please give me the  i2cdump command

    Thank you very much

  • i2cdump command:

    #i2cdump -fy 2 0x18

  • under playback, please check it

    # i2cdump -fy 2 0x18
    No size specified (using byte-data access)
    WARNING! This program can confuse your I2C bus, cause data loss and worse!
    I will probe file /dev/i2c-2, address 0x18, mode byte
    Continue? [Y/n] y
         0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
    00: 00 00 60 00 03 11 04 00 00 00 00 00 00 00 80 02    ..`.???.......??
    10: 00 08 00 00 80 01 00 04 00 00 01 00 00 01 00 00    .?..??.?..?..?..
    20: 00 00 00 00 44 00 00 00 00 00 00 00 00 00 00 00    ....D...........
    30: 00 00 00 00 08 12 03 02 04 00 00 00 01 01 00 14    ....?????...??.?
    40: 00 00 00 00 6f 38 00 00 00 00 00 ee 10 d8 7e e3    ....o8.....???~?
    50: 00 00 88 00 00 00 00 00 7f 00 00 00 00 00 00 00    ..?.....?.......
    60: 7f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ?...............
    70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
    80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
    90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
    a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
    b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
    c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
    d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
    e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
    f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................

  • Dear Kevin

    What do you mean about "this driver should be able to support Slave mode, but it doesn't look like it is currently supported"?
    Does the other driver be for linux? Can it work?
    Thank you very much

  • No other driver for aic3254.

    I mean the current driver might have some issue cannot used under salve mode, so I want to make some changes in aic32x4_set_dai_sysclk(), to fix it, could you help to try?

    Thanks

    Kevin

  • From i2cdump, the DAC channel is not powered up... may need to config the path.

    Can you send me the logs through email, my email address is kevin-lu@ti.com, we can push the debug process to be quicker

  • here is some error after apply your patch

     About your comment

    “However, I don't think this should be the final solution, this driver should be able to support Slave mode, but it doesn't look like it is currently supported, we should use BCLK as PLL input source, no need to add MCLK”

     

    Do you mean that IC does not need MCLK under Slave mode?

    Therefore, we can ignore the mclk config, right?

    Thank you very much

    0509_log_2_mclk_failed.txt

  • Dear Kevin 

    Does the IC driver support Master mode ad default?