• Linux ALSA驱动之Platform源码分析(wm8350.c)


    1、Platform概述

            ASoC被分为Machine,Platform和Codec三大部件,Platform驱动的主要作用是完成音频数据的管理,最终通过CPU的数字音频接口(DA〉把音频数据传送给Codec进行处理,最终由Codec输出驱动耳机或者是喇叭的音频信号。在具体实现上,ASoC又把Platform驱动分为两个部分: platform_driver和snd_soc_dai_driver。其中,platform_driver负责管理音频数据,把音频数据通过dma或其他操作传送至cpudai中,dai_driver则主要完成cpu一侧的dai的参数配置,同时也会通过一定的途径把必要的dma等参数与platform_driver进行交互。

    cpu_dai_driver 部分:
            在嵌入式系统里面通常指SoC的I2S、PCM总线控制器,负责把音频数据从I2S tx FIFO搬运到CODEC(这是音频播放的情形,录制则方向相反)。cpu_dai通过snd_soc_register_dai()/devm_snd_soc_register_component()来注册。

            注:DAI是 Digital Audio Interface的简称,分为cpu_dai和codec_dai,这两者通过 I2S/PCM 总线连接,AIF 是 Audio Interface 的简称,嵌入式系统中一般是I2S和PCM接口。

    platform_driver部分:
            负责把dma buffer中的音频数据搬运到I2S tx FIFO。音频DMA驱动通过 platform_driver_register()/module_platform_driver() 来注册,故也常用platform来指代音频DMA驱动(这里的 platform 需要与 SoC Platform 区分开)。

    2、snd_soc_dai_driver

    2.1、snd_soc_dai_driver注册流程

            DAI驱动通常对应cpu的一个或几个I2S/PCM接口,实现一个DAI驱动大致可以分为以下几个步骤:

                    1、定义一个snd_soc_dai_driver结构的实例;
                    2、在对应的platform_driver中的probe回调中通过API: snd_soc_register_dai或者snd_soc_register_dais注册snd_soc_dai实例;
                    3、实现snd_soc_dai_driver结构中的probe、suspend等回调;
                    4、实现snd_soc_dai_driver结构中的snd_soc_dai_ops字段中的回调函数;

            具体代码流程如下(sound/soc/codecs/wm8350.c)

    1. /* snd_soc_dai_ops 结构体实例 */
    2. static const struct snd_soc_dai_ops wm8350_dai_ops = {
    3. .hw_params = wm8350_pcm_hw_params,
    4. .mute_stream = wm8350_mute,
    5. .set_fmt = wm8350_set_dai_fmt,
    6. .set_sysclk = wm8350_set_dai_sysclk,
    7. .set_pll = wm8350_set_fll,
    8. .set_clkdiv = wm8350_set_clkdiv,
    9. .no_capture_mute = 1,
    10. };
    11. /* snd_soc_dai_driver结构体实例 */
    12. static struct snd_soc_dai_driver wm8350_dai = {
    13. .name = "wm8350-hifi",
    14. .playback = {
    15. .stream_name = "Playback",
    16. .channels_min = 1,
    17. .channels_max = 2,
    18. .rates = WM8350_RATES,
    19. .formats = WM8350_FORMATS,
    20. },
    21. .capture = {
    22. .stream_name = "Capture",
    23. .channels_min = 1,
    24. .channels_max = 2,
    25. .rates = WM8350_RATES,
    26. .formats = WM8350_FORMATS,
    27. },
    28. .ops = &wm8350_dai_ops,
    29. };
    30. /* platform平台probe函数 */
    31. static int wm8350_probe(struct platform_device *pdev)
    32. {
    33. /* 注册component组件参数为soc_component_dev_wm8350 wm8350_dai*/
    34. return devm_snd_soc_register_component(&pdev->dev,
    35. &soc_component_dev_wm8350,
    36. &wm8350_dai, 1);
    37. }
    38. /**
    39. * devm_snd_soc_register_component - resource managed component registration
    40. * @dev: Device used to manage component
    41. * @cmpnt_drv: Component driver
    42. * @dai_drv: DAI driver
    43. * @num_dai: Number of DAIs to register
    44. *
    45. * Register a component with automatic unregistration when the device is
    46. * unregistered.
    47. */
    48. /* 进入devm_snd_soc_register_component函数 */
    49. int devm_snd_soc_register_component(struct device *dev,
    50. const struct snd_soc_component_driver *cmpnt_drv,
    51. struct snd_soc_dai_driver *dai_drv, int num_dai)
    52. {
    53. const struct snd_soc_component_driver **ptr;
    54. int ret;
    55. /* 申请devm_component_release空间 */
    56. ptr = devres_alloc(devm_component_release, sizeof(*ptr), GFP_KERNEL);
    57. if (!ptr)
    58. return -ENOMEM;
    59. /*调用snd_soc_register_component注册cmpnt_drv、 dai_drv */
    60. ret = snd_soc_register_component(dev, cmpnt_drv, dai_drv, num_dai);
    61. if (ret == 0) {
    62. *ptr = cmpnt_drv;
    63. devres_add(dev, ptr);
    64. } else {
    65. devres_free(ptr);
    66. }
    67. return ret;
    68. }
    69. EXPORT_SYMBOL_GPL(devm_snd_soc_register_component);
    70. /* 进入snd_soc_register_component函数 */
    71. int snd_soc_register_component(struct device *dev,
    72. const struct snd_soc_component_driver *component_driver,
    73. struct snd_soc_dai_driver *dai_drv,
    74. int num_dai)
    75. {
    76. struct snd_soc_component *component;
    77. int ret;
    78. /* 申请component空间 */
    79. component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL);
    80. if (!component)
    81. return -ENOMEM;
    82. /* 调用snd_soc_component_initialize函数注册component_driver */
    83. ret = snd_soc_component_initialize(component, component_driver, dev);
    84. if (ret < 0)
    85. return ret;
    86. /* 调用snd_soc_add_component注册 dai_drv */
    87. return snd_soc_add_component(component, dai_drv, num_dai);
    88. }
    89. EXPORT_SYMBOL_GPL(snd_soc_register_component);
    90. /* 进入snd_soc_add_component函数 */
    91. int snd_soc_add_component(struct snd_soc_component *component,
    92. struct snd_soc_dai_driver *dai_drv,
    93. int num_dai)
    94. {
    95. int ret;
    96. int i;
    97. mutex_lock(&client_mutex);
    98. if (component->driver->endianness) {
    99. for (i = 0; i < num_dai; i++) {
    100. convert_endianness_formats(&dai_drv[i].playback);
    101. convert_endianness_formats(&dai_drv[i].capture);
    102. }
    103. }
    104. /* 调用snd_soc_register_dais函数注册dai_drv */
    105. ret = snd_soc_register_dais(component, dai_drv, num_dai);
    106. if (ret < 0) {
    107. dev_err(component->dev, "ASoC: Failed to register DAIs: %d\n",
    108. ret);
    109. goto err_cleanup;
    110. }
    111. if (!component->driver->write && !component->driver->read) {
    112. if (!component->regmap)
    113. component->regmap = dev_get_regmap(component->dev,
    114. NULL);
    115. if (component->regmap)
    116. snd_soc_component_setup_regmap(component);
    117. }
    118. /* see for_each_component */
    119. list_add(&component->list, &component_list);
    120. err_cleanup:
    121. if (ret < 0)
    122. snd_soc_del_component_unlocked(component);
    123. mutex_unlock(&client_mutex);
    124. if (ret == 0)
    125. snd_soc_try_rebind_card();
    126. return ret;
    127. }
    128. EXPORT_SYMBOL_GPL(snd_soc_add_component);
    129. /**
    130. * snd_soc_register_dais - Register a DAI with the ASoC core
    131. *
    132. * @component: The component the DAIs are registered for
    133. * @dai_drv: DAI driver to use for the DAIs
    134. * @count: Number of DAIs
    135. */
    136. /* 进入snd_soc_register_dais函数 */
    137. static int snd_soc_register_dais(struct snd_soc_component *component,
    138. struct snd_soc_dai_driver *dai_drv,
    139. size_t count)
    140. {
    141. struct snd_soc_dai *dai;
    142. unsigned int i;
    143. int ret;
    144. for (i = 0; i < count; i++) {
    145. /* 最终调用snd_soc_register_dai函数注册dai_drv */
    146. dai = snd_soc_register_dai(component, dai_drv + i, count == 1 &&
    147. !component->driver->non_legacy_dai_naming);
    148. if (dai == NULL) {
    149. ret = -ENOMEM;
    150. goto err;
    151. }
    152. }
    153. return 0;
    154. err:
    155. snd_soc_unregister_dais(component);
    156. return ret;
    157. }
    158. /**
    159. * snd_soc_register_dai - Register a DAI dynamically & create its widgets
    160. *
    161. * @component: The component the DAIs are registered for
    162. * @dai_drv: DAI driver to use for the DAI
    163. * @legacy_dai_naming: if %true, use legacy single-name format;
    164. * if %false, use multiple-name format;
    165. *
    166. * Topology can use this API to register DAIs when probing a component.
    167. * These DAIs's widgets will be freed in the card cleanup and the DAIs
    168. * will be freed in the component cleanup.
    169. */
    170. /* 进入到snd_soc_register_dai函数 */
    171. struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component,
    172. struct snd_soc_dai_driver *dai_drv,
    173. bool legacy_dai_naming)
    174. {
    175. struct device *dev = component->dev;
    176. struct snd_soc_dai *dai;
    177. dev_dbg(dev, "ASoC: dynamically register DAI %s\n", dev_name(dev));
    178. lockdep_assert_held(&client_mutex);
    179. /* 申请dai空间 */
    180. dai = devm_kzalloc(dev, sizeof(*dai), GFP_KERNEL);
    181. if (dai == NULL)
    182. return NULL;
    183. /*
    184. * Back in the old days when we still had component-less DAIs,
    185. * instead of having a static name, component-less DAIs would
    186. * inherit the name of the parent device so it is possible to
    187. * register multiple instances of the DAI. We still need to keep
    188. * the same naming style even though those DAIs are not
    189. * component-less anymore.
    190. */
    191. if (legacy_dai_naming &&
    192. (dai_drv->id == 0 || dai_drv->name == NULL)) {
    193. dai->name = fmt_single_name(dev, &dai->id);
    194. } else {
    195. dai->name = fmt_multiple_name(dev, dai_drv);
    196. if (dai_drv->id)
    197. dai->id = dai_drv->id;
    198. else
    199. dai->id = component->num_dai;
    200. }
    201. if (!dai->name)
    202. return NULL;
    203. dai->component = component;
    204. dai->dev = dev;
    205. dai->driver = dai_drv;
    206. /* see for_each_component_dais */
    207. /* 将dai->list添加到component->dai_list中 */
    208. list_add_tail(&dai->list, &component->dai_list);
    209. component->num_dai++;
    210. dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
    211. return dai;
    212. }
    213. EXPORT_SYMBOL_GPL(snd_soc_register_dai);
    214. /* 至此cpu_dai添加完成 */

    2.2、snd_soc_dai结构体

    1. /*
    2. * Digital Audio Interface runtime data.
    3. *
    4. * Holds runtime data for a DAI.
    5. */
    6. struct snd_soc_dai {
    7. const char *name;
    8. int id;
    9. struct device *dev;
    10. /* driver ops */
    11. struct snd_soc_dai_driver *driver;
    12. /* DAI runtime info */
    13. unsigned int stream_active[SNDRV_PCM_STREAM_LAST + 1]; /* usage count */
    14. struct snd_soc_dapm_widget *playback_widget;
    15. struct snd_soc_dapm_widget *capture_widget;
    16. /* DAI DMA data */
    17. void *playback_dma_data;
    18. void *capture_dma_data;
    19. /* Symmetry data - only valid if symmetry is being enforced */
    20. unsigned int rate;
    21. unsigned int channels;
    22. unsigned int sample_bits;
    23. /* parent platform/codec */
    24. struct snd_soc_component *component;
    25. /* CODEC TDM slot masks and params (for fixup) */
    26. unsigned int tx_mask;
    27. unsigned int rx_mask;
    28. struct list_head list;
    29. /* function mark */
    30. struct snd_pcm_substream *mark_startup;
    31. struct snd_pcm_substream *mark_hw_params;
    32. struct snd_pcm_substream *mark_trigger;
    33. struct snd_compr_stream *mark_compr_startup;
    34. /* bit field */
    35. unsigned int probed:1;
    36. };

            snd_soc_dai该结构在snd_soc_register_dai函数中通过动态内存申请获得.简要介绍一下几个重要字段:

                    1、driver指向关联的snd_soc_dai_driver结构,由注册时通过参数传入。
                    2、playback_dma_data 用于保存该dai播放stream的dma信息目标地址,dma传送单元大小和通道号等。
                    3、capture_dma_data 同上,用于录音stream。
                    4、component指向关联的snd_soc_component结构体中。

    2.3、snd_soc_dai_driver结构体

    1. /*
    2. * Digital Audio Interface Driver.
    3. *
    4. * Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97
    5. * operations and capabilities. Codec and platform drivers will register this
    6. * structure for every DAI they have.
    7. *
    8. * This structure covers the clocking, formating and ALSA operations for each
    9. * interface.
    10. */
    11. struct snd_soc_dai_driver {
    12. /* DAI description */
    13. const char *name;
    14. unsigned int id;
    15. unsigned int base;
    16. struct snd_soc_dobj dobj;
    17. /* DAI driver callbacks */
    18. int (*probe)(struct snd_soc_dai *dai);
    19. int (*remove)(struct snd_soc_dai *dai);
    20. /* compress dai */
    21. int (*compress_new)(struct snd_soc_pcm_runtime *rtd, int num);
    22. /* Optional Callback used at pcm creation*/
    23. int (*pcm_new)(struct snd_soc_pcm_runtime *rtd,
    24. struct snd_soc_dai *dai);
    25. /* ops */
    26. const struct snd_soc_dai_ops *ops;
    27. const struct snd_soc_cdai_ops *cops;
    28. /* DAI capabilities */
    29. struct snd_soc_pcm_stream capture;
    30. struct snd_soc_pcm_stream playback;
    31. unsigned int symmetric_rate:1;
    32. unsigned int symmetric_channels:1;
    33. unsigned int symmetric_sample_bits:1;
    34. /* probe ordering - for components with runtime dependencies */
    35. int probe_order;
    36. int remove_order;
    37. };

            snd_soc_dai_driver结构体需要自己根据不同的soc芯片进行定义,这里只介绍几个关键字段:

                    1、probe、remove回调函数,分别在声卡加载和卸载时被调用。
                    2、ops指向snd_soc_dai_ops结构,用于配置和控制该dai,后面细讲。
                    3、playback snd_soc_pcm_stream结构,用于指出该dai支持的声道数,码率,数据格式等能力。
                    4、capture snd_soc_pcm_stream结构,用于指出该dai支持的声道数,码率,数据格式等能力。

    2.4、snd_soc_dai_ops结构体

            snd_soc_dai_driver结构体中的ops字段指向一个snd_soc_dai_ops结构体,该结构体实际上是一组回调函数的集合,dai的配置和控制几乎都是通过这些回调函数来实现的,这些回调函数基本可以分为3大类,驱动程序可以根据实际情况实现其中的一部分:

    1. struct snd_soc_dai_ops {
    2. /*
    3. * DAI clocking configuration, all optional.
    4. * Called by soc_card drivers, normally in their hw_params.
    5. */
    6. int (*set_sysclk)(struct snd_soc_dai *dai,
    7. int clk_id, unsigned int freq, int dir);
    8. int (*set_pll)(struct snd_soc_dai *dai, int pll_id, int source,
    9. unsigned int freq_in, unsigned int freq_out);
    10. int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div);
    11. int (*set_bclk_ratio)(struct snd_soc_dai *dai, unsigned int ratio);
    12. /*
    13. * DAI format configuration
    14. * Called by soc_card drivers, normally in their hw_params.
    15. */
    16. int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt);
    17. int (*xlate_tdm_slot_mask)(unsigned int slots,
    18. unsigned int *tx_mask, unsigned int *rx_mask);
    19. int (*set_tdm_slot)(struct snd_soc_dai *dai,
    20. unsigned int tx_mask, unsigned int rx_mask,
    21. int slots, int slot_width);
    22. int (*set_channel_map)(struct snd_soc_dai *dai,
    23. unsigned int tx_num, unsigned int *tx_slot,
    24. unsigned int rx_num, unsigned int *rx_slot);
    25. int (*get_channel_map)(struct snd_soc_dai *dai,
    26. unsigned int *tx_num, unsigned int *tx_slot,
    27. unsigned int *rx_num, unsigned int *rx_slot);
    28. int (*set_tristate)(struct snd_soc_dai *dai, int tristate);
    29. int (*set_stream)(struct snd_soc_dai *dai,
    30. void *stream, int direction);
    31. void *(*get_stream)(struct snd_soc_dai *dai, int direction);
    32. /*
    33. * DAI digital mute - optional.
    34. * Called by soc-core to minimise any pops.
    35. */
    36. int (*mute_stream)(struct snd_soc_dai *dai, int mute, int stream);
    37. /*
    38. * ALSA PCM audio operations - all optional.
    39. * Called by soc-core during audio PCM operations.
    40. */
    41. int (*startup)(struct snd_pcm_substream *,
    42. struct snd_soc_dai *);
    43. void (*shutdown)(struct snd_pcm_substream *,
    44. struct snd_soc_dai *);
    45. int (*hw_params)(struct snd_pcm_substream *,
    46. struct snd_pcm_hw_params *, struct snd_soc_dai *);
    47. int (*hw_free)(struct snd_pcm_substream *,
    48. struct snd_soc_dai *);
    49. int (*prepare)(struct snd_pcm_substream *,
    50. struct snd_soc_dai *);
    51. /*
    52. * NOTE: Commands passed to the trigger function are not necessarily
    53. * compatible with the current state of the dai. For example this
    54. * sequence of commands is possible: START STOP STOP.
    55. * So do not unconditionally use refcounting functions in the trigger
    56. * function, e.g. clk_enable/disable.
    57. */
    58. int (*trigger)(struct snd_pcm_substream *, int,
    59. struct snd_soc_dai *);
    60. int (*bespoke_trigger)(struct snd_pcm_substream *, int,
    61. struct snd_soc_dai *);
    62. /*
    63. * For hardware based FIFO caused delay reporting.
    64. * Optional.
    65. */
    66. snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,
    67. struct snd_soc_dai *);
    68. /*
    69. * Format list for auto selection.
    70. * Format will be increased if priority format was
    71. * not selected.
    72. * see
    73. * snd_soc_dai_get_fmt()
    74. */
    75. u64 *auto_selectable_formats;
    76. int num_auto_selectable_formats;
    77. /* bit field */
    78. unsigned int no_capture_mute:1;
    79. };

            工作时钟配置函数通常由machine驱动调用:

                    1、set_sysclk设置dai的主时钟。
                    2、set_pll设置PLL参数。
                    3、set_clkdiv设置分频系数。

            dai的格式配置参数,通常也由machine驱动调用:

                    1、set_fmt设置dai的格式。

                    2、set_tdm_slot如果dai支持时分复用,用于设置时分复用的slot、set_channel_map声道的时分复用映射设置。
                    3、set_tristate设置dai引脚的状态,当与其他dai并联使用同一引脚时需要使用该回调。

            标准的snd_soc_ops回调通常由soc-core在进行PCM操作时调用:

                    1、startup:打开设备,设备开始工作的时候回调
                    2、shutdown:关闭设备前调用
                    3、hw_params:设置硬件的相关参数
                    4、trigger:DAM开始时传输,结束传输,暂停传世,恢复传输的时候被回调。

    3、platform_driver

    3.1、platform_driver注册流程

    1. /* snd_soc_component_driver结构体实例化 */
    2. static const struct snd_soc_component_driver soc_component_dev_wm8350 = {
    3. .probe = wm8350_component_probe,
    4. .remove = wm8350_component_remove,
    5. .set_bias_level = wm8350_set_bias_level,
    6. .controls = wm8350_snd_controls,
    7. .num_controls = ARRAY_SIZE(wm8350_snd_controls),
    8. .dapm_widgets = wm8350_dapm_widgets,
    9. .num_dapm_widgets = ARRAY_SIZE(wm8350_dapm_widgets),
    10. .dapm_routes = wm8350_dapm_routes,
    11. .num_dapm_routes = ARRAY_SIZE(wm8350_dapm_routes),
    12. .suspend_bias_off = 1,
    13. .idle_bias_on = 1,
    14. .use_pmdown_time = 1,
    15. .endianness = 1,
    16. .non_legacy_dai_naming = 1,
    17. };
    18. /* 进入到wm8350_probe函数 */
    19. static int wm8350_probe(struct platform_device *pdev)
    20. {
    21. /* 通过devm_snd_soc_register_component函数注册soc_component_dev_wm8350 */
    22. return devm_snd_soc_register_component(&pdev->dev,
    23. &soc_component_dev_wm8350,
    24. &wm8350_dai, 1);
    25. }
    26. /* 进入platform_driver函数 */
    27. static struct platform_driver wm8350_codec_driver = {
    28. .driver = {
    29. .name = "wm8350-codec",
    30. },
    31. .probe = wm8350_probe,
    32. };
    33. /* 通过module_platform_driver宏来注册platform_driver */
    34. module_platform_driver(wm8350_codec_driver);

    3.2、platform_driver结构体

             在编写 platform 驱动的时候,首先定义一个platform_driver结构体变量,然后实现结构体中的各个成员变量,重点是实现匹配方法以及probe函数。当驱动和设备匹配成功以后 probe函数就会执行,具体的驱动程序在 probe 函数里面编写,比如字符设备驱动等等。

    1. struct platform_driver {
    2. int (*probe)(struct platform_device *);
    3. int (*remove)(struct platform_device *);
    4. void (*shutdown)(struct platform_device *);
    5. int (*suspend)(struct platform_device *, pm_message_t state);
    6. int (*resume)(struct platform_device *);
    7. struct device_driver driver;
    8. const struct platform_device_id *id_table;
    9. bool prevent_deferred_probe;
    10. /*
    11. * For most device drivers, no need to care about this flag as long as
    12. * all DMAs are handled through the kernel DMA API. For some special
    13. * ones, for example VFIO drivers, they know how to manage the DMA
    14. * themselves and set this flag so that the IOMMU layer will allow them
    15. * to setup and manage their own I/O address space.
    16. */
    17. bool driver_managed_dma;
    18. };

            platform_driver结构体用于注册驱动到Platform总线,此处只讲几个重点字段:

                    1、probe:当驱动与设备匹配成功以后probe函数就会执行。一般驱动的提供者会编写,如果自己要编写一个全新的驱动,那么 probe 就需要自行实现。
                    2、driver:device_driver 结构体变量,Linux 内核里面大量使用到了面向对象的思维, device_driver相当于基类,提供了最基础的驱动框架。 plaform_driver继承了这个基类,然后在此基础上又添加了一些特有的成员变量。

    3.3、snd_soc_component结构体

    1. struct snd_soc_component {
    2. /* device_driver->name 和snd_soc_component_driver->id有关, */
    3. const char *name;
    4. int id;
    5. const char *name_prefix;
    6. struct device *dev;
    7. struct snd_soc_card *card;
    8. unsigned int active;
    9. unsigned int suspended:1; /* is in suspend PM state */
    10. /* 用于把自己挂载到全局链表component_list下, component_list在soc-core中保持的全局变量 */
    11. struct list_head list;
    12. struct list_head card_aux_list; /* for auxiliary bound components */
    13. struct list_head card_list;
    14. /* 指向下属的snd_soc_component_driver, 该结构体一般由底层平台驱动实现 */
    15. const struct snd_soc_component_driver *driver;
    16. /* 链表头, 挂接snd_soc_dai->list list_add(&dai->list, &component->dai_list) */
    17. struct list_head dai_list;
    18. int num_dai;
    19. struct regmap *regmap;
    20. int val_bytes;
    21. struct mutex io_mutex;
    22. /* attached dynamic objects */
    23. struct list_head dobj_list;
    24. /*
    25. * DO NOT use any of the fields below in drivers, they are temporary and
    26. * are going to be removed again soon. If you use them in driver code
    27. * the driver will be marked as BROKEN when these fields are removed.
    28. */
    29. /* Don't use these, use snd_soc_component_get_dapm() */
    30. struct snd_soc_dapm_context dapm;
    31. /* machine specific init */
    32. int (*init)(struct snd_soc_component *component);
    33. /* function mark */
    34. void *mark_module;
    35. struct snd_pcm_substream *mark_open;
    36. struct snd_pcm_substream *mark_hw_params;
    37. struct snd_pcm_substream *mark_trigger;
    38. struct snd_compr_stream *mark_compr_open;
    39. void *mark_pm;
    40. struct dentry *debugfs_root;
    41. const char *debugfs_prefix;
    42. };

    3.4、snd_soc_component_driver结构体

    1. struct snd_soc_component_driver {
    2. const char *name;
    3. /* Default control and setup, added after probe() is run */
    4. const struct snd_kcontrol_new *controls;
    5. unsigned int num_controls;
    6. const struct snd_soc_dapm_widget *dapm_widgets;
    7. unsigned int num_dapm_widgets;
    8. const struct snd_soc_dapm_route *dapm_routes;
    9. unsigned int num_dapm_routes;
    10. int (*probe)(struct snd_soc_component *component);
    11. void (*remove)(struct snd_soc_component *component);
    12. int (*suspend)(struct snd_soc_component *component);
    13. int (*resume)(struct snd_soc_component *component);
    14. unsigned int (*read)(struct snd_soc_component *component,
    15. unsigned int reg);
    16. int (*write)(struct snd_soc_component *component,
    17. unsigned int reg, unsigned int val);
    18. /* pcm creation and destruction */
    19. int (*pcm_construct)(struct snd_soc_component *component,
    20. struct snd_soc_pcm_runtime *rtd);
    21. void (*pcm_destruct)(struct snd_soc_component *component,
    22. struct snd_pcm *pcm);
    23. /* component wide operations */
    24. int (*set_sysclk)(struct snd_soc_component *component,
    25. int clk_id, int source, unsigned int freq, int dir);
    26. int (*set_pll)(struct snd_soc_component *component, int pll_id,
    27. int source, unsigned int freq_in, unsigned int freq_out);
    28. int (*set_jack)(struct snd_soc_component *component,
    29. struct snd_soc_jack *jack, void *data);
    30. /* DT */
    31. int (*of_xlate_dai_name)(struct snd_soc_component *component,
    32. const struct of_phandle_args *args,
    33. const char **dai_name);
    34. int (*of_xlate_dai_id)(struct snd_soc_component *comment,
    35. struct device_node *endpoint);
    36. void (*seq_notifier)(struct snd_soc_component *component,
    37. enum snd_soc_dapm_type type, int subseq);
    38. int (*stream_event)(struct snd_soc_component *component, int event);
    39. int (*set_bias_level)(struct snd_soc_component *component,
    40. enum snd_soc_bias_level level);
    41. int (*open)(struct snd_soc_component *component,
    42. struct snd_pcm_substream *substream);
    43. int (*close)(struct snd_soc_component *component,
    44. struct snd_pcm_substream *substream);
    45. int (*ioctl)(struct snd_soc_component *component,
    46. struct snd_pcm_substream *substream,
    47. unsigned int cmd, void *arg);
    48. int (*hw_params)(struct snd_soc_component *component,
    49. struct snd_pcm_substream *substream,
    50. struct snd_pcm_hw_params *params);
    51. int (*hw_free)(struct snd_soc_component *component,
    52. struct snd_pcm_substream *substream);
    53. int (*prepare)(struct snd_soc_component *component,
    54. struct snd_pcm_substream *substream);
    55. int (*trigger)(struct snd_soc_component *component,
    56. struct snd_pcm_substream *substream, int cmd);
    57. int (*sync_stop)(struct snd_soc_component *component,
    58. struct snd_pcm_substream *substream);
    59. snd_pcm_uframes_t (*pointer)(struct snd_soc_component *component,
    60. struct snd_pcm_substream *substream);
    61. int (*get_time_info)(struct snd_soc_component *component,
    62. struct snd_pcm_substream *substream, struct timespec64 *system_ts,
    63. struct timespec64 *audio_ts,
    64. struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
    65. struct snd_pcm_audio_tstamp_report *audio_tstamp_report);
    66. int (*copy_user)(struct snd_soc_component *component,
    67. struct snd_pcm_substream *substream, int channel,
    68. unsigned long pos, void __user *buf,
    69. unsigned long bytes);
    70. struct page *(*page)(struct snd_soc_component *component,
    71. struct snd_pcm_substream *substream,
    72. unsigned long offset);
    73. int (*mmap)(struct snd_soc_component *component,
    74. struct snd_pcm_substream *substream,
    75. struct vm_area_struct *vma);
    76. int (*ack)(struct snd_soc_component *component,
    77. struct snd_pcm_substream *substream);
    78. snd_pcm_sframes_t (*delay)(struct snd_soc_component *component,
    79. struct snd_pcm_substream *substream);
    80. const struct snd_compress_ops *compress_ops;
    81. /* probe ordering - for components with runtime dependencies */
    82. int probe_order;
    83. int remove_order;
    84. /*
    85. * signal if the module handling the component should not be removed
    86. * if a pcm is open. Setting this would prevent the module
    87. * refcount being incremented in probe() but allow it be incremented
    88. * when a pcm is opened and decremented when it is closed.
    89. */
    90. unsigned int module_get_upon_open:1;
    91. /* bits */
    92. unsigned int idle_bias_on:1;
    93. unsigned int suspend_bias_off:1;
    94. unsigned int use_pmdown_time:1; /* care pmdown_time at stop */
    95. /*
    96. * Indicates that the component does not care about the endianness of
    97. * PCM audio data and the core will ensure that both LE and BE variants
    98. * of each used format are present. Typically this is because the
    99. * component sits behind a bus that abstracts away the endian of the
    100. * original data, ie. one for which the transmission endian is defined
    101. * (I2S/SLIMbus/SoundWire), or the concept of endian doesn't exist (PDM,
    102. * analogue).
    103. */
    104. unsigned int endianness:1;
    105. unsigned int non_legacy_dai_naming:1;
    106. /* this component uses topology and ignore machine driver FEs */
    107. const char *ignore_machine;
    108. const char *topology_name_prefix;
    109. int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd,
    110. struct snd_pcm_hw_params *params);
    111. bool use_dai_pcm_id; /* use DAI link PCM ID as PCM device number */
    112. int be_pcm_base; /* base device ID for all BE PCMs */
    113. #ifdef CONFIG_DEBUG_FS
    114. const char *debugfs_prefix;
    115. #endif
    116. };

            module_platform_driver函数的详解请参考《module_platform_driver源码分析
           

  • 相关阅读:
    bm8 bm9
    从零开始:使用Rust语言在STM32F4处理器上实现VGA风格视频输出的完整指南
    信噪比和比特误码率之间的关系通过matlab仿真计算出
    【JavaEE】_HTTP响应
    金九银十BAT互联网企业涨薪必备知识点:Jvm性能调优实战
    大数据在金融行业的深度应用与未来展望
    react(子传父、父传子)
    Web项目 - 登录注册业务逻辑
    sshpiper 在 Kubernetes 上的应用
    FPGA设计时序约束七、设置时钟不确定约束
  • 原文地址:https://blog.csdn.net/code_lyb/article/details/126583717