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.

LM49352 Linux driver for OMAPl 138/AM1808

Other Parts Discussed in Thread: OMAPL138, OMAP-L138

Hi

I'm using OMAPl138 custom board and i'm using LM49352 audio IC i need Linux i2c driver for this audio chip.

I refer this link for Linux driver http://mailman.alsa-project.org/pipermail/alsa-devel/2011-March/037806.html

/* I2C driver structure for LM49352. */
static struct i2c_driver lm49352_i2c_driver = {
.driver = {
.name = "LM49352 I2C Codec",
.owner = THIS_MODULE,
},
.attach_adapter = lm49352_i2c_attach,
.detach_client = lm49352_i2c_detach,
.command = NULL,
};

/* I2C client structure for LM49352. */
static struct i2c_client client_template = {
.name = "LM49352",
.driver = &lm49352_i2c_driver,
};
#endif

This part is very confusing because its don't have .id_table for register the driver from board file and .name contains space so i'm confused regarding how to register this driver from my board file

I'm registering like this

static struct i2c_board_info __initdata omapl138_hawk_i2c_devices[] = {
{
I2C_BOARD_INFO("LM49352 I2C Codec", 0x34),
},
};

And also the driver not building its showing countless error because of version mismatching and i removed the #include <sound/driver.h>

Please help me to find the proper Linux driver for LM49352 audio device and check this i2c slave address is correct or not.

Thanks

Sangily

  • Hi, Sangily,

    Due to the many different variables involved, we are unable to provide detailed support on drivers for our devices.

    The I2C address is shown on page 26 of the data sheet in the section titled, "TRANSFERRING DATA"

    -d2

  • Hi,

          Then what is the solution for Linux driver for LM49352 audio chip?

           

    Don Dapkus said:
    The I2C address is shown on page 26 of the data sheet in the section titled, "TRANSFERRING DATA"

    As per the datasheet I2C address is 0x34, please correct me if its wrong.

    Thanks

    Sangly

  • Hi, Sangly,

    You can see if you can find an Open Source Linux driver for this device, otherwise, you are going to have to develop your own.

    -d2

  • Hi 

         I'm modifying the lm49352 old driver to new one and here i've attached the driver file but its partially completed and i'm just checking it get register or not. But its not getting register with machine driver 

    /sound/soc/codec/lm49352.c

    static struct i2c_driver lm49352_i2c_driver = {
    .driver = {
    .name = "lm49352-codec",
    .owner = THIS_MODULE,
    },
    .probe = lm49352_i2c_probe,
    .remove = lm49352_i2c_remove,
    .id_table = lm49352_i2c_id,
    };

    static struct snd_soc_dai_driver lm49352_dai = {

    .name = "lm49352-hifi",
    .playback = {
    .stream_name = "Playback",
    .channels_min = 2,
    .channels_max = 2,
    .rates = SNDRV_PCM_RATE_8000_192000,
    .formats = LM49352_FORMATS,
    },
    .capture = {
    .stream_name = "Capture",
    .channels_min = 2,
    .channels_max = 2,
    .rates = SNDRV_PCM_RATE_8000_192000,
    .formats = LM49352_FORMATS,
    },
    .ops = &lm49352_dai_ops,

    };

    /sound/soc/davinci/davinci-evm.c

    static struct snd_soc_dai_link da850_evm_dai = {
    .name = "LM49352MONO",
    .stream_name = "LM49MONO",
    .cpu_dai_name= "davinci-mcasp.0",
    .codec_dai_name = "lm49352-hifi",
    .codec_name = "lm49352-codec",
    .platform_name = "davinci-pcm-audio",
    .init = evm_aic3x_init,
    .ops = &evm_ops,
    };

    but its not getting register it showing --no sound card-- but the driver getting register and i can see the log. 

    #include <linux/module.h>
    #include <linux/moduleparam.h>
    #include <linux/init.h>
    #include <linux/delay.h>
    #include <linux/pm.h>
    #include <linux/i2c.h>
    #include <linux/gpio.h>
    #include <linux/regulator/consumer.h>
    #include <linux/platform_device.h>
    #include <linux/slab.h>
    #include <sound/core.h>
    #include <sound/pcm.h>
    #include <sound/pcm_params.h>
    #include <sound/soc.h>
    #include <sound/initval.h>
    #include <sound/tlv.h>
    #include "lm49352.h"
    
    #define AUDIO_NAME "lm49352"
    #define LM49352_VERSION "0.1"
    #define LM49352_NUM_SUPPLIES	4
    
    /*******
     * Debug
     *******/
    
    static int attach_once;
    
    #ifdef LM49352_DEBUG
    #define dbg(format, arg...) \
           printk(KERN_DEBUG AUDIO_NAME ": " format , ## arg)
    #else
    #define dbg(format, arg...) do {} while (0)
    #endif
    #define err(format, arg...) \
           printk(KERN_ERR AUDIO_NAME ": " format , ## arg)
    #define info(format, arg...) \
           printk(KERN_INFO AUDIO_NAME ": " format , ## arg)
    #define warn(format, arg...) \
           printk(KERN_WARNING AUDIO_NAME ": " format , ## arg)
    
    static const char *lm49352_supply_names[LM49352_NUM_SUPPLIES] = {
    	"IOVDD",	/* I/O Voltage */
    	"DVDD",		/* Digital Core Voltage */
    	"AVDD",		/* Analog DAC Voltage */
    	"DRVDD",	/* ADC Analog and Output Driver Voltage */
    };
    struct lm49352_priv {
    	
    	enum snd_soc_control_type control_type;
    	struct regulator_bulk_data supplies[LM49352_NUM_SUPPLIES];
    	unsigned int sysclk;
    	void *control_data;
    };
    
    /* Register cache for LM49352 driver. */
    static const u16 lm49352_reg[] = {
           0x0121, 0x017e, 0x007d, 0x0014, /*R3*/
           0x0121, 0x017e, 0x007d, 0x0194, /*R7*/
           0x001c, 0x0002, 0x0002, 0x00c2, /*R11*/
           0x0182, 0x0082, 0x000a, 0x0024, /*R15*/
           0x0009, 0x0000, 0x00ff, 0x0000, /*R19*/
           0x00ff, 0x00ff, 0x00ff, 0x00ff, /*R23*/
           0x00ff, 0x00ff, 0x00ff, 0x00ff, /*R27*/
           0x01f0, 0x0040, 0x0000, 0x0000, /*R31(0x1F)*/
           0x0000, 0x0000, 0x0031, 0x000b, /*R35*/
           0x0039, 0x0000, 0x0010, 0x0032, /*R39*/
           0x0054, 0x0076, 0x0098, 0x0000, /*R43(0x2B)*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R47*/
           0x0000, 0x0000, 0x005e, 0x003e, /*R51(0x33)*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R55*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R59*/
           0x0000, 0x0000, 0x0000, 0x0000,  /*R63*/
           0x0000, 0x0000, 0x0000, 0x0000,  /*R67*/
           0x0000, 0x0000, 0x0000, 0x0000,  /*R71*/
           0x0000, 0x0000, 0x0000, 0x0000,  /*R75*/
           0x0000, 0x0000, 0x0000, 0x0000,  /*R79*/
           0x0000, 0x0000, 0x0000, 0x0000,  /*R83*/
           0x0000, 0x0000, 0x0000, 0x0000,  /*R87*/
           0x0000, 0x0000, 0x0000, 0x0000,  /*R91*/
           0x0000, 0x0000, 0x0000, 0x0000,  /*R95*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R99*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R103*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R107*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R111*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R115*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R119*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R123*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R127*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R131*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R135*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R139*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R143*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R147*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R151*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R155*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R159*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R163*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R167*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R171*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R175*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R179*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R183*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R187*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R191*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R193*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R197*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R201*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R205*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R209*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R213*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R217*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R221*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R225*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R229*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R233*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R237*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R241*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R245*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R249*/
           0x0000, 0x0000, 0x0000, 0x0000, /*R253*/
           0x0000, 0x0000,  /*R255*/
    };
    static int lm49352_set_bias_level(struct snd_soc_codec *codec,
    				  enum snd_soc_bias_level level)
    {
    	int ret;
    
    	switch (level) {
    	case SND_SOC_BIAS_ON:
    		break;
    	case SND_SOC_BIAS_PREPARE:
    		break;
    	case SND_SOC_BIAS_STANDBY:
    		/*if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
    			ret = snd_soc_cache_sync(codec);
    			if (ret) {
    				dev_err(codec->dev,
    					"Failed to sync cache: %d\n", ret);
    				return ret;
    			}
    		}*/
    		break;
    	case SND_SOC_BIAS_OFF:
    		break;
    	}
    	//codec->dapm.bias_level = level;
    	return 0;
    
    
    }
    static inline unsigned int
    lm49352_read_reg_cache(struct snd_soc_codec *codec, unsigned int reg)
    {
           dbg("in lm49352_read_reg_cache \n");
           u16 *cache = codec->reg_cache;
           BUG_ON(reg > ARRAY_SIZE(lm49352_reg));
           dbg("in lm49352_read_reg_cache %x\n", cache[reg]);
           return cache[reg];
    }
    /**************************************************************************
     * Name
     *     lm49352_write_reg_cache- Writes specific register value to reg
     *                              cache.
     * Synopsis
     *     static inline void lm49352_write_reg_cache(struct
     *             snd_soc_codec *codec,unsigned int reg, unsigned int value)
     * Arguments
     *     codec- Pointer to the struct snd_soc_codec
     *      reg- Specific register address
     *      value- The value that to be written to reg cache
     * Decription
     *     This function is called when a specific register is to be written
     *     with the given value. This function writes the value to reg cache.
     *************************************************************************/
    
    static inline void lm49352_write_reg_cache(struct snd_soc_codec *codec,
                                              unsigned int reg,
                                              unsigned int value)
    {
           u16 *cache = codec->reg_cache;
           dbg("in lm49352_write_reg_cache \n");
           dbg("value to be written is %x\n", value);
           cache[reg] = value;
    }
    
    /**************************************************************************
     * Name
     *     lm49352_out_vu- Sets the value of a single mixer control.
     * Synopsis
     *     static int lm49352_out_vu(struct snd_kcontrol *kcontrol,
     * Arguments
     *     kcontrol- Pointer to the struct snd_kcontrol
     *      ucontrol- Pointer to struct snd_ctl_elem_value
     * Decription
     *     This function is called when a single mixer control value is
     *     to be set.
     *************************************************************************/
    
    static int lm49352_out_vu(struct snd_kcontrol *kcontrol,
                             struct snd_ctl_elem_value *ucontrol)
    {
           struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
           int reg = kcontrol->private_value & 0xff;
           int ret;
           u16 val;
    
           /* Resetting the reg cache value. */
           lm49352_write_reg_cache(codec, reg, 0);
    
           /* Callback to set the value of a single mixer control. */
           ret = snd_soc_put_volsw(kcontrol, ucontrol);
    
           if (ret < 0)
                   return ret;
    
           /* Reading the written new value. */
           val = lm49352_read_reg_cache(codec, reg);
           /* Oring the value with 0x100 and writing back to reg cavhe. */
           return snd_soc_write(codec, reg, val | 0x0100);
    }
    static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
    /* Macro for defining and adding single mixer controls. */
    #define SOC_LM49352_OUT_SINGLE_R_TLV(xname, reg, shift, max, invert, tlv_array)\
    {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
           .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ \
                     | SNDRV_CTL_ELEM_ACCESS_READWRITE,\
           .tlv.p = (tlv_array), \
           .info = snd_soc_info_volsw, \
           .get = snd_soc_get_volsw, .put = lm49352_out_vu, \
           .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
    static const struct snd_kcontrol_new lm49352_snd_controls[] =
    {      /* Various controls of LM49352 Driver */
           SOC_LM49352_OUT_SINGLE_R_TLV("Left DAC1 Playback Volume",
                   LM49352_DIGITAL_ATTENUATION_DACL1, 0, 0x3f, 0, dac_tlv),
           SOC_LM49352_OUT_SINGLE_R_TLV("Right DAC1 Playback Volume",
                   LM49352_DIGITAL_ATTENUATION_DACR1, 0, 0x3f, 0, dac_tlv),
           SOC_LM49352_OUT_SINGLE_R_TLV("Headphone Playback Volume",
                   ANALOG_MIXER_OUTPUT_OPTIONS, 1, 7, 1, dac_tlv),
           SOC_LM49352_OUT_SINGLE_R_TLV("Aux Playback Volume",
                   ANALOG_MIXER_OUTPUT_OPTIONS, 4, 1, 0, dac_tlv),
           SOC_LM49352_OUT_SINGLE_R_TLV("PC Speaker Playback Volume",
                   ANALOG_MIXER_OUTPUT_OPTIONS, 6, 3, 0, dac_tlv),
           SOC_SINGLE("DAC1 Deemphasis Switch", LM49352_DAC_CONTROL3, 2, 1, 0),
           SOC_SINGLE("DAC1 Left Invert Switch", LM49352_DAC_CONTROL4, 0, 1, 0),
           SOC_SINGLE("DAC1 Right Invert Switch", LM49352_DAC_CONTROL4, 1, 1, 0),
           SOC_SINGLE("DAC ZC Switch", DAC_BASIC, 5, 1, 0),
           SOC_SINGLE("DAC Mute Switch", DAC_MUTE, 2, 1, 0),
           SOC_SINGLE("ADCL Mute Switch", LM49352_ADC_CONTROL1, 2, 1, 0),
           SOC_SINGLE("ADCR Mute Switch", LM49352_ADC_CONTROL1, 3, 1, 0),
    };
    
    //-------lm49352_init start---------
    
    static int lm49352_init(struct snd_soc_codec *codec)
    {
    int pmc_clk_d;
           snd_soc_write(codec, BASIC_SETUP_PMC_SETUP, 0x13);
           snd_soc_write(codec, BASIC_SETUP_PMC_CLOCK, 0x02);
           snd_soc_write(codec, PLL_CLK_SEL, 0x00);
           snd_soc_write(codec, ANALOG_MIXER_HEADPHONESL, 0x02);
           snd_soc_write(codec, ANALOG_MIXER_HEADPHONESR, 0x01);
           snd_soc_write(codec, ANALOG_MIXER_HP_SENSE, 0x00);
           snd_soc_write(codec, ADC_BASIC, 0x033);
           snd_soc_write(codec, ADC_CLOCK, 0x0b);
           snd_soc_write(codec, DAC_BASIC, 0x31);
           snd_soc_write(codec, DAC_IP_SELECT, 0x09);
           snd_soc_write(codec, AUDIO_PORT1_BASIC, 0x07);
           snd_soc_write(codec, PLL_M, 0x00);
           snd_soc_write(codec, PLL_N, 0xec);
           snd_soc_write(codec, PLL_N_MOD, 0x14);
           snd_soc_write(codec, PLL_P1, 0x0d);
           snd_soc_write(codec, ANALOG_MIXER_CLASSD, 0x03);
           snd_soc_write(codec, ANALOG_MIXER_AUX_OUT, 0x23);
           snd_soc_write(codec, ANALOG_MIXER_AUXL_LVL, 0x2b);
           snd_soc_write(codec, ADC_MIXER, 0x0f);
           snd_soc_write(codec, AUDIO_PORT1_IP, 0x05);
           snd_soc_write(codec, ADC_EFFECTS_HPF, 0x04);
           snd_soc_write(codec, ADC_EFFECTS_ADC_ALC4, 0x0a);
           snd_soc_write(codec, ADC_EFFECTS_ADC_ALC5, 0x0a);
           snd_soc_write(codec, ADC_EFFECTS_ADC_ALC6, 0x0a);
           snd_soc_write(codec, ADC_EFFECTS_ADC_ALC7, 0x1f);
           snd_soc_write(codec, ADC_EFFECTS_ADC_L_LEVEL, 0x33);
           snd_soc_write(codec, ADC_EFFECTS_ADC_R_LEVEL, 0x33);
           snd_soc_write(codec, DAC_EFFECTS_DAC_ALC1, 0x02);
           snd_soc_write(codec, DAC_EFFECTS_DAC_ALC4, 0x0a);
           snd_soc_write(codec, DAC_EFFECTS_DAC_ALC5, 0x0a);
           snd_soc_write(codec, DAC_EFFECTS_DAC_ALC6, 0x0a);
           snd_soc_write(codec, DAC_EFFECTS_DAC_ALC7, 0x33);
           snd_soc_write(codec, DAC_EFFECTS_DAC_L_LEVEL, 0x33);
           snd_soc_write(codec, DAC_EFFECTS_DAC_R_LEVEL, 0x33);
           snd_soc_write(codec, ANALOG_MIXER_MIC_LVL, 0x0f);
           snd_soc_write(codec, ANALOG_MIXER_ADC, 0x0c);
    
    	snd_soc_add_controls(codec, lm49352_snd_controls,
    			     ARRAY_SIZE(lm49352_snd_controls));
    
    	pmc_clk_d=snd_soc_read(codec, 0x02);
    	printk("I2C read of PMC_CLK_DIV:%d\n",pmc_clk_d);
    	return 0;
    }
    
    //--------lm49352_init end -----------
    
    //----lm49352_probe start-----------
    
    static int lm49352_probe(struct snd_soc_codec *codec)
    {
    	struct lm49352_priv *lm49352 = snd_soc_codec_get_drvdata(codec);
    	int ret, i;
    	codec->control_data = lm49352->control_data;
    	printk("lm49352_probe \n");
    
    	ret = snd_soc_codec_set_cache_io(codec, 8, 8, lm49352->control_type);
    	if (ret != 0) {
    		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
    		return ret;
    	}
    
    	lm49352_init(codec);
    
    
    }
    //----lm49352_probe end-----------
    
    //---- hw_params--------------------
    static int lm49352_hw_params(struct snd_pcm_substream *substream,
    			   struct snd_pcm_hw_params *params,
    			   struct snd_soc_dai *dai)
    {
    
    	struct snd_soc_pcm_runtime *rtd = substream->private_data;
    	struct snd_soc_codec *codec =rtd->codec;
    	struct lm49352_priv *lm49352 = snd_soc_codec_get_drvdata(codec);
    
    	printk("\n in lm49352_hw_params \n");
    
    
           /* Setting the DAC and ADC clock dividers based on substream
              sample rate. */
           switch (params_rate(params)) {
           case 8000:
                   snd_soc_write(codec, DAC_CLOCK, 0x17);
                   snd_soc_write(codec, ADC_CLOCK, 0x17);
                   break;
           case 11025:
                   snd_soc_write(codec, DAC_CLOCK, 0x10);
                   snd_soc_write(codec, ADC_CLOCK, 0x10);
                   break;
           case 16000:
                   snd_soc_write(codec, DAC_CLOCK, 0x0b);
                   snd_soc_write(codec, ADC_CLOCK, 0x0b);
                   break;
           case 22050:
                   snd_soc_write(codec, DAC_CLOCK, 0x08);
                   snd_soc_write(codec, ADC_CLOCK, 0x08);
                   break;
           case 32000:
                   snd_soc_write(codec, DAC_CLOCK, 0x05);
                   snd_soc_write(codec, ADC_CLOCK, 0x05);
                   break;
           case 44100:
                   snd_soc_write(codec, DAC_CLOCK, 0x03);
                   snd_soc_write(codec, ADC_CLOCK, 0x03);
                   break;
           case 48000:
                   snd_soc_write(codec, DAC_CLOCK, 0x03);
                   snd_soc_write(codec, ADC_CLOCK, 0x03);
                   break;
           case 96000:
                   snd_soc_write(codec, DAC_CLOCK, 0x01);
                   break;
           default:
                   snd_soc_write(codec, DAC_CLOCK, 0x01);
                   snd_soc_write(codec, ADC_CLOCK, 0x03);
                   break;
           }
    
           /* bit size */
           switch (params_format(params)) {
           case SNDRV_PCM_FORMAT_S16_LE:
                   dbg(KERN_CRIT "16 bit\n");
                   break;
           case SNDRV_PCM_FORMAT_S20_3LE:
                   dbg(KERN_CRIT "20 bit\n");
                   break;
           case SNDRV_PCM_FORMAT_S24_LE:
                   dbg(KERN_CRIT "24 bit\n");
                   break;
           case SNDRV_PCM_FORMAT_S32_LE:
                   dbg(KERN_CRIT "32 bit\n");
                  break;
           default:
                  return -EINVAL;
           }
    
           return 0;
    
    
    }
    
    /* Formates supported by LM49352 driver. */
    #define LM49352_FORMATS (SNDRV_PCM_FMTBIT_S16_LE   \
                            | SNDRV_PCM_FMTBIT_S20_3LE \
                            | SNDRV_PCM_FMTBIT_S24_LE  \
                            | SNDRV_PCM_FMTBIT_S32_LE)
    
    
    static struct snd_soc_dai_ops lm49352_dai_ops = {
    	.hw_params	= lm49352_hw_params,
    	//.set_sysclk	= aic3x_set_dai_sysclk,
    	//.set_fmt	= aic3x_set_dai_fmt,
    };
    
    static struct snd_soc_dai_driver lm49352_dai = {
    
                   .name = "lm49352-hifi",
                   .playback = {
                           .stream_name = "Playback",
                           .channels_min = 2,
                           .channels_max = 2,
                           .rates = SNDRV_PCM_RATE_8000_192000,
                           .formats = LM49352_FORMATS,
                   },
                   .capture = {
                           .stream_name = "Capture",
                           .channels_min = 2,
                           .channels_max = 2,
                           .rates = SNDRV_PCM_RATE_8000_192000,
                           .formats = LM49352_FORMATS,
                   },
                   .ops = &lm49352_dai_ops,             
           
    
    };
    
    static struct snd_soc_codec_driver soc_codec_dev_lm49352 = {
    	.set_bias_level 	= lm49352_set_bias_level,
    	.reg_cache_size 	= ARRAY_SIZE(lm49352_reg),
    	.reg_word_size 		= sizeof(u16),
    	.reg_cache_default	= lm49352_reg,
    	.probe 			= lm49352_probe,
    	//.remove 		= lm49352_remove,
    	//.suspend 		= lm49352_suspend,
    	//.resume 		= lm49352_resume,
    };
    // ----I2C_probe start----
    static int lm49352_i2c_probe(struct i2c_client *i2c,
    				      const struct i2c_device_id *id)
    {
    	struct lm49352_priv *lm49352;
    	int ret;
    	printk("probing I2C audio lm49352\n");
    	lm49352 = kzalloc(sizeof(struct lm49352_priv), GFP_KERNEL);
    	if (lm49352 == NULL) {
    		printk("failed to create lm49352_priv private data\n");
    		return -ENOMEM;
    	}
    
    	lm49352->control_type = SND_SOC_I2C;
    
    	i2c_set_clientdata(i2c, lm49352);
    
    	ret =  snd_soc_register_codec(&i2c->dev,
    			&soc_codec_dev_lm49352, &lm49352_dai, 1);
    	
    	if (ret < 0)
    		kfree(lm49352);
    	return ret;
    }
    //----I2C_probe end-------
    
    static int lm49352_i2c_remove(struct i2c_client *client)
    {
    	snd_soc_unregister_codec(&client->dev);
    	kfree(i2c_get_clientdata(client));
    	return 0;
    }
    
    static const struct i2c_device_id lm49352_i2c_id[] = {
    	{ "lm49352", 0 },
    	{ }
    };
    MODULE_DEVICE_TABLE(i2c, lm49352_i2c_id);
    
    static struct i2c_driver lm49352_i2c_driver = {
           .driver = {
                   .name = "lm49352-codec",
                   .owner = THIS_MODULE,
           },
            .probe	= lm49352_i2c_probe,
    	.remove = lm49352_i2c_remove,
    	.id_table = lm49352_i2c_id,
    };
    
    //Module init
    static int __init lm49352_modinit(void)
    {
    	int ret = 0;
    	printk(" lm49352_modinit \n");
    	ret = i2c_add_driver(&lm49352_i2c_driver);
    	if (ret != 0) {
    		printk(KERN_ERR "Failed to register lm49352 I2C driver: %d\n",ret);
    	}
    	return ret;
    
    }
    
    module_init(lm49352_modinit);
    
    //Module exit
    static void __exit lm49352_exit(void)
    {
    	i2c_del_driver(&lm49352_i2c_driver);
    }
    module_exit(lm49352_exit);
    
    MODULE_DESCRIPTION("ASoC LM49352 driver");
    MODULE_AUTHOR("Development Version 0.1");
    MODULE_LICENSE("GPL");
    

    0827.lm49352.h

    file name inside the /sound/soc/codec is tlv32aic3x.c because some problem in kconfig and make file so i didn't modify this files just renamed the file lm49352 to tlv32aic3x.c is this cause of problem?

    But its my first linux driver and i'm just modifying the lm49352 old driver for new version of ALSA in OMAPL138 LCDK kit. So there is may be lot of mistakes and noise so please correct me.

    Link for the original old version driver is 

    http://mailman.alsa-project.org/pipermail/alsa-devel/2011-March/037806.html

    Please help me to make this work.

    Thanks

    Sangly

  • Hi

    Successfully registered the codec with machine driver by changing .codec_name = "lm49352-codec", to .codec_name = "lm49352-codec.1-001a", 

    My sound card getting detect 

    ALSA device list:

     #0: DA850/OMAP-L138 EVM 

    but when i try to play the wave file by this command aplay 60.wav &  i got the following error

    root@omapl138-lcdk:/lm49# Playing WAVE '60s' : Signed 24 bit Little Endian in 3b
    ytes, Rate 48000 Hz, Mono
    asoc: machine hw_params failed
    aplay: set_params:1129: Unable to install hw params:
    ACCESS:  RW_INTERLEAVED
    FORMAT:  S24_3LE
    SUBFORMAT:  STD
    SAMPLE_BITS: 24
    FRAME_BITS: 24
    CHANNELS: 1
    RATE: 48000
    PERIOD_TIME: (21333 21334)
    PERIOD_SIZE: 1024
    PERIOD_BYTES: 3072
    PERIODS: 16
    BUFFER_TIME: (341333 341334)
    BUFFER_SIZE: 16384
    BUFFER_BYTES: 49152
    TICK_TIME: 0
    But i know i missed something in machine driver and codec driver also because its my first audio driver please check my driver and update me the issue
    Thanks
    Sangily