Alsa soc improvements on linux3.1

Source: Internet
Author: User

2012 has arrived. Whether or not the world will be destroyed, the days before that will continue.

Android has entered 4.0, and the corresponding Linux kernel has entered the era. The subsequent work is estimated to port the 2.6.32 driver to 3.x. So now let's take a look at ALSA's changes in this regard.

In general, a major change to the architecture is unlikely. Several key struct types in codec have not changed significantly. For example, snd_soc_dai_ops and snd_soc_dai_driver (equivalent to snd_soc_dai in 2.6.32) are defined as snd_soc_driver, which is the most obvious one.

Register the struct-snd_soc_codec_driver

2.6.32:

/* codec device */struct snd_soc_codec_device {int (*probe)(struct platform_device *pdev);int (*remove)(struct platform_device *pdev);int (*suspend)(struct platform_device *pdev, pm_message_t state);int (*resume)(struct platform_device *pdev);};

3.1.1:

/* codec driver */struct snd_soc_codec_driver {/* driver ops */int (*probe)(struct snd_soc_codec *);int (*remove)(struct snd_soc_codec *);int (*suspend)(struct snd_soc_codec *,pm_message_t state);int (*resume)(struct snd_soc_codec *);/* Default control and setup, added after probe() is run */const struct snd_kcontrol_new *controls;int num_controls;const struct snd_soc_dapm_widget *dapm_widgets;int num_dapm_widgets;const struct snd_soc_dapm_route *dapm_routes;int num_dapm_routes;/* codec wide operations */int (*set_sysclk)(struct snd_soc_codec *codec,  int clk_id, unsigned int freq, int dir);int (*set_pll)(struct snd_soc_codec *codec, int pll_id, int source,unsigned int freq_in, unsigned int freq_out);/* codec IO */unsigned int (*read)(struct snd_soc_codec *, unsigned int);int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);int (*display_register)(struct snd_soc_codec *, char *,size_t, unsigned int);int (*volatile_register)(struct snd_soc_codec *, unsigned int);int (*readable_register)(struct snd_soc_codec *, unsigned int);int (*writable_register)(struct snd_soc_codec *, unsigned int);short reg_cache_size;short reg_cache_step;short reg_word_size;const void *reg_cache_default;short reg_access_size;const struct snd_soc_reg_access *reg_access_default;enum snd_soc_compress_type compress_type;/* codec bias level */int (*set_bias_level)(struct snd_soc_codec *,      enum snd_soc_bias_level level);void (*seq_notifier)(struct snd_soc_dapm_context *,     enum snd_soc_dapm_type, int);/* probe ordering - for components with runtime dependencies */int probe_order;int remove_order;};

Some codec IO member functions and set_bias_level callback functions in snd_soc_codec_driver are originally placed in another struct snd_soc_codec. Now they are placed here. This is the result of source code structure adjustment. In fact, not many Members need to be set, as shown below:

static struct snd_soc_codec_driver soc_codec_dev_wm9713 = {.probe = wm9713_soc_probe,.remove = wm9713_soc_remove,.suspend =wm9713_soc_suspend,.resume = wm9713_soc_resume,.read = ac97_read,.write = ac97_write,.set_bias_level = wm9713_set_bias_level,.reg_cache_size = ARRAY_SIZE(wm9713_reg),.reg_word_size = sizeof(u16),.reg_cache_step = 2,.reg_cache_default = wm9713_reg,.dapm_widgets = wm9713_dapm_widgets,.num_dapm_widgets = ARRAY_SIZE(wm9713_dapm_widgets),.dapm_routes = wm9713_audio_map,.num_dapm_routes = ARRAY_SIZE(wm9713_audio_map),};

The volatile_register function determines whether the specified register is volatile. reg_cache_size is generally the number of registers, reg_word_size is the register length, and reg_cache_default is the default register configuration table.

Dapm_widgets and dapm_routes are sharp. The previous dapm widgets and routes are registered by using the functions snd_soc_dapm_new_controls and snd_soc_dapm_add_routes respectively (these interfaces are also retained). Now you can enter this struct and register it in SoC-core, saving a lot of effort:

static int soc_probe_codec(struct snd_soc_card *card,   struct snd_soc_codec *codec){//...if (driver->dapm_widgets)snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets,  driver->num_dapm_widgets);//...if (driver->controls)snd_soc_add_controls(codec, driver->controls,     driver->num_controls);if (driver->dapm_routes)snd_soc_dapm_add_routes(&codec->dapm, driver->dapm_routes,driver->num_dapm_routes);//...}

At the same time, we can see that the dirver ops function parameters are different. Previously, it was struct platform_device * pdev. Now it is changed to struct snd_soc_codec * codec. This is related to the Register function snd_soc_register_codec of the device, the analysis is performed one by one.

Register the function-snd_soc_register_codec

For snd_soc_codec_driver, You Need To export_symbol_gpl (soc_codec_dev_wm9713) and register it elsewhere. Now you don't have to worry about it:

static __devinit int wm9713_probe(struct platform_device *pdev){return snd_soc_register_codec(&pdev->dev,&soc_codec_dev_wm9713, wm9713_dai, ARRAY_SIZE(wm9713_dai));}

Then you can register as if you were using a common platform device. Snd_soc_new_pcms is no longer required to register PCM and snd_soc_init_card.

Snd_soc_register_codec function prototype:

int snd_soc_register_codec(struct device *dev,const struct snd_soc_codec_driver *codec_drv,struct snd_soc_dai_driver *dai_drv, int num_dai);

Among them, snd_soc_dai_driver is similar to the previous snd_soc_dai, and there is no special note, such as initialization:

static struct snd_soc_dai_driver wm9713_dai[] = {{.name = "wm9713-hifi",.ac97_control = 1,.playback = {.stream_name = "HiFi Playback",.channels_min = 1,.channels_max = 2,.rates = WM9713_RATES,.formats = SND_SOC_STD_AC97_FMTS,},.capture = {.stream_name = "HiFi Capture",.channels_min = 1,.channels_max = 2,.rates = WM9713_RATES,.formats = SND_SOC_STD_AC97_FMTS,},.ops = &wm9713_dai_ops_hifi,},//...//...};

Note: Earlier snd_soc_dai also needed export_symbol_gpl, which was then registered elsewhere. Now, this has been improved to reduce the symbol of export, and the code architecture is clearer and more reliable.

Device private data-drvdata

In the codec Analysis of ALSA, it was mentioned that "starting to see socdev = platform_get_drvdata (pdev) is a bit confusing. Where is pdev initialized ?", This pdev is drvdata. This stuff is very important. It generally contains codec custom private data, such as control interface type (I2C/SPI/ac97), fll_in (FLL input frequency), fll_out (FLL
Output Frequency. Because each codec may define different private data bodies, and the Linux kernel prefers abstraction, drvdata is generated.

In the past, the logic of drvdata was A-to-loop bottle, but the current version is more intuitive and you can see the analysis:

static inline void snd_soc_codec_set_drvdata(struct snd_soc_codec *codec,void *data){dev_set_drvdata(codec->dev, data);}static inline void *snd_soc_codec_get_drvdata(struct snd_soc_codec *codec){return dev_get_drvdata(codec->dev);}

In Soc. H, two functions are implemented to set and obtain drvdata. Snd_soc_codec is the most commonly used struct In the codec driver. It can be seen in each operation function, so select it to associate with drvdata.

The usage is as follows:

static int wm9713_soc_probe(struct snd_soc_codec *codec){struct wm9713_priv *wm9713;int ret = 0, reg;wm9713 = kzalloc(sizeof(struct wm9713_priv), GFP_KERNEL);if (wm9713 == NULL)return -ENOMEM;snd_soc_codec_set_drvdata(codec, wm9713);//...}static int wm9713_soc_remove(struct snd_soc_codec *codec){struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);snd_soc_free_ac97_codec(codec);kfree(wm9713);return 0;}

Set the control interface-snd_soc_codec_set_cache_io

This function was also available in previous versions, but was not noticed at the time. It is found that this function is very practical. You only need to configure the Register address width, data width, and control interface type. The SoC-io module automatically selects the appropriate control interface function.

/** * snd_soc_codec_set_cache_io: Set up standard I/O functions. * * @codec: CODEC to configure. * @addr_bits: Number of bits of register address data. * @data_bits: Number of bits of data per register. * @control: Control bus used. * * Register formats are frequently shared between many I2C and SPI * devices.  In order to promote code reuse the ASoC core provides * some standard implementations of CODEC read and write operations * which can be set up using this function. * * The caller is responsible for allocating and initialising the * actual cache. * * Note that at present this code cannot be used by CODECs with * volatile registers. */int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,       int addr_bits, int data_bits,       enum snd_soc_control_type control){int i;for (i = 0; i < ARRAY_SIZE(io_types); i++)if (io_types[i].addr_bits == addr_bits &&    io_types[i].data_bits == data_bits)break;if (i == ARRAY_SIZE(io_types)) {printk(KERN_ERR       "No I/O functions for %d bit address %d bit data\n",       addr_bits, data_bits);return -EINVAL;}codec->write = io_types[i].write;codec->read = hw_read;codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;switch (control) {case SND_SOC_I2C:#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))codec->hw_write = (hw_write_t)i2c_master_send;#endifif (io_types[i].i2c_read)codec->hw_read = io_types[i].i2c_read;codec->control_data = container_of(codec->dev,   struct i2c_client,   dev);break;case SND_SOC_SPI:#ifdef CONFIG_SPI_MASTERcodec->hw_write = do_spi_write;#endifif (io_types[i].spi_read)codec->hw_read = io_types[i].spi_read;codec->control_data = container_of(codec->dev,   struct spi_device,   dev);break;}return 0;}EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.