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)
-
/* snd_soc_dai_ops 结构体实例 */
-
static const struct snd_soc_dai_ops wm8350_dai_ops = {
-
.hw_params = wm8350_pcm_hw_params,
-
.mute_stream = wm8350_mute,
-
.set_fmt = wm8350_set_dai_fmt,
-
.set_sysclk = wm8350_set_dai_sysclk,
-
.set_pll = wm8350_set_fll,
-
.set_clkdiv = wm8350_set_clkdiv,
-
.no_capture_mute = 1,
-
};
-
-
/* snd_soc_dai_driver结构体实例 */
-
static struct snd_soc_dai_driver wm8350_dai = {
-
.name = "wm8350-hifi",
-
.playback = {
-
.stream_name = "Playback",
-
.channels_min = 1,
-
.channels_max = 2,
-
.rates = WM8350_RATES,
-
.formats = WM8350_FORMATS,
-
},
-
.capture = {
-
.stream_name = "Capture",
-
.channels_min = 1,
-
.channels_max = 2,
-
.rates = WM8350_RATES,
-
.formats = WM8350_FORMATS,
-
},
-
.ops = &wm8350_dai_ops,
-
};
-
-
/* platform平台probe函数 */
-
static int wm8350_probe(struct platform_device *pdev)
-
{
-
/* 注册component组件参数为soc_component_dev_wm8350 wm8350_dai*/
-
return devm_snd_soc_register_component(&pdev->dev,
-
&soc_component_dev_wm8350,
-
&wm8350_dai, 1);
-
}
-
-
/**
-
* devm_snd_soc_register_component - resource managed component registration
-
* @dev: Device used to manage component
-
* @cmpnt_drv: Component driver
-
* @dai_drv: DAI driver
-
* @num_dai: Number of DAIs to register
-
*
-
* Register a component with automatic unregistration when the device is
-
* unregistered.
-
*/
-
/* 进入devm_snd_soc_register_component函数 */
-
int devm_snd_soc_register_component(struct device *dev,
-
const struct snd_soc_component_driver *cmpnt_drv,
-
struct snd_soc_dai_driver *dai_drv, int num_dai)
-
{
-
const struct snd_soc_component_driver **ptr;
-
int ret;
-
-
/* 申请devm_component_release空间 */
-
ptr = devres_alloc(devm_component_release, sizeof(*ptr), GFP_KERNEL);
-
if (!ptr)
-
return -ENOMEM;
-
-
/*调用snd_soc_register_component注册cmpnt_drv、 dai_drv */
-
ret = snd_soc_register_component(dev, cmpnt_drv, dai_drv, num_dai);
-
if (ret == 0) {
-
*ptr = cmpnt_drv;
-
devres_add(dev, ptr);
-
} else {
-
devres_free(ptr);
-
}
-
-
return ret;
-
}
-
EXPORT_SYMBOL_GPL(devm_snd_soc_register_component);
-
-
/* 进入snd_soc_register_component函数 */
-
int snd_soc_register_component(struct device *dev,
-
const struct snd_soc_component_driver *component_driver,
-
struct snd_soc_dai_driver *dai_drv,
-
int num_dai)
-
{
-
struct snd_soc_component *component;
-
int ret;
-
-
/* 申请component空间 */
-
component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL);
-
if (!component)
-
return -ENOMEM;
-
-
/* 调用snd_soc_component_initialize函数注册component_driver */
-
ret = snd_soc_component_initialize(component, component_driver, dev);
-
if (ret < 0)
-
return ret;
-
-
/* 调用snd_soc_add_component注册 dai_drv */
-
return snd_soc_add_component(component, dai_drv, num_dai);
-
}
-
EXPORT_SYMBOL_GPL(snd_soc_register_component);
-
-
-
/* 进入snd_soc_add_component函数 */
-
int snd_soc_add_component(struct snd_soc_component *component,
-
struct snd_soc_dai_driver *dai_drv,
-
int num_dai)
-
{
-
int ret;
-
int i;
-
-
mutex_lock(&client_mutex);
-
-
if (component->driver->endianness) {
-
for (i = 0; i < num_dai; i ) {
-
convert_endianness_formats(&dai_drv[i].playback);
-
convert_endianness_formats(&dai_drv[i].capture);
-
}
-
}
-
-
/* 调用snd_soc_register_dais函数注册dai_drv */
-
ret = snd_soc_register_dais(component, dai_drv, num_dai);
-
if (ret < 0) {
-
dev_err(component->dev, "ASoC: Failed to register DAIs: %d\n",
-
ret);
-
goto err_cleanup;
-
}
-
-
if (!component->driver->write && !component->driver->read) {
-
if (!component->regmap)
-
component->regmap = dev_get_regmap(component->dev,
-
NULL);
-
if (component->regmap)
-
snd_soc_component_setup_regmap(component);
-
}
-
-
/* see for_each_component */
-
list_add(&component->list, &component_list);
-
-
err_cleanup:
-
if (ret < 0)
-
snd_soc_del_component_unlocked(component);
-
-
mutex_unlock(&client_mutex);
-
-
if (ret == 0)
-
snd_soc_try_rebind_card();
-
-
return ret;
-
}
-
EXPORT_SYMBOL_GPL(snd_soc_add_component);
-
-
/**
-
* snd_soc_register_dais - Register a DAI with the ASoC core
-
*
-
* @component: The component the DAIs are registered for
-
* @dai_drv: DAI driver to use for the DAIs
-
* @count: Number of DAIs
-
*/
-
/* 进入snd_soc_register_dais函数 */
-
static int snd_soc_register_dais(struct snd_soc_component *component,
-
struct snd_soc_dai_driver *dai_drv,
-
size_t count)
-
{
-
struct snd_soc_dai *dai;
-
unsigned int i;
-
int ret;
-
-
for (i = 0; i < count; i ) {
-
/* 最终调用snd_soc_register_dai函数注册dai_drv */
-
dai = snd_soc_register_dai(component, dai_drv i, count == 1 &&
-
!component->driver->non_legacy_dai_naming);
-
if (dai == NULL) {
-
ret = -ENOMEM;
-
goto err;
-
}
-
}
-
-
return 0;
-
-
err:
-
snd_soc_unregister_dais(component);
-
-
return ret;
-
}
-
-
/**
-
* snd_soc_register_dai - Register a DAI dynamically & create its widgets
-
*
-
* @component: The component the DAIs are registered for
-
* @dai_drv: DAI driver to use for the DAI
-
* @legacy_dai_naming: if %true, use legacy single-name format;
-
* if lse, use multiple-name format;
-
*
-
* Topology can use this API to register DAIs when probing a component.
-
* These DAIs's widgets will be freed in the card cleanup and the DAIs
-
* will be freed in the component cleanup.
-
*/
-
/* 进入到snd_soc_register_dai函数 */
-
struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component,
-
struct snd_soc_dai_driver *dai_drv,
-
bool legacy_dai_naming)
-
{
-
struct device *dev = component->dev;
-
struct snd_soc_dai *dai;
-
-
dev_dbg(dev, "ASoC: dynamically register DAI %s\n", dev_name(dev));
-
-
lockdep_assert_held(&client_mutex);
-
-
/* 申请dai空间 */
-
dai = devm_kzalloc(dev, sizeof(*dai), GFP_KERNEL);
-
if (dai == NULL)
-
return NULL;
-
-
/*
-
* Back in the old days when we still had component-less DAIs,
-
* instead of having a static name, component-less DAIs would
-
* inherit the name of the parent device so it is possible to
-
* register multiple instances of the DAI. We still need to keep
-
* the same naming style even though those DAIs are not
-
* component-less anymore.
-
*/
-
if (legacy_dai_naming &&
-
(dai_drv->id == 0 || dai_drv->name == NULL)) {
-
dai->name = fmt_single_name(dev, &dai->id);
-
} else {
-
dai->name = fmt_multiple_name(dev, dai_drv);
-
if (dai_drv->id)
-
dai->id = dai_drv->id;
-
else
-
dai->id = component->num_dai;
-
}
-
if (!dai->name)
-
return NULL;
-
-
dai->component = component;
-
dai->dev = dev;
-
dai->driver = dai_drv;
-
-
/* see for_each_component_dais */
-
/* 将dai->list添加到component->dai_list中 */
-
list_add_tail(&dai->list, &component->dai_list);
-
component->num_dai ;
-
-
dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
-
return dai;
-
}
-
EXPORT_SYMBOL_GPL(snd_soc_register_dai);
-
-
/* 至此cpu_dai添加完成 */
2.2、snd_soc_dai结构体
-
/*
-
* Digital Audio Interface runtime data.
-
*
-
* Holds runtime data for a DAI.
-
*/
-
struct snd_soc_dai {
-
const char *name;
-
int id;
-
struct device *dev;
-
-
/* driver ops */
-
struct snd_soc_dai_driver *driver;
-
-
/* DAI runtime info */
-
unsigned int stream_active[SNDRV_PCM_STREAM_LAST 1]; /* usage count */
-
-
struct snd_soc_dapm_widget *playback_widget;
-
struct snd_soc_dapm_widget *capture_widget;
-
-
/* DAI DMA data */
-
void *playback_dma_data;
-
void *capture_dma_data;
-
-
/* Symmetry data - only valid if symmetry is being enforced */
-
unsigned int rate;
-
unsigned int channels;
-
unsigned int sample_bits;
-
-
/* parent platform/codec */
-
struct snd_soc_component *component;
-
-
/* CODEC TDM slot masks and params (for fixup) */
-
unsigned int tx_mask;
-
unsigned int rx_mask;
-
-
struct list_head list;
-
-
/* function mark */
-
struct snd_pcm_substream *mark_startup;
-
struct snd_pcm_substream *mark_hw_params;
-
struct snd_pcm_substream *mark_trigger;
-
struct snd_compr_stream *mark_compr_startup;
-
-
/* bit field */
-
unsigned int probed:1;
-
};
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结构体
-
/*
-
* Digital Audio Interface Driver.
-
*
-
* Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97
-
* operations and capabilities. Codec and platform drivers will register this
-
* structure for every DAI they have.
-
*
-
* This structure covers the clocking, formating and ALSA operations for each
-
* interface.
-
*/
-
struct snd_soc_dai_driver {
-
/* DAI description */
-
const char *name;
-
unsigned int id;
-
unsigned int base;
-
struct snd_soc_dobj dobj;
-
-
/* DAI driver callbacks */
-
int (*probe)(struct snd_soc_dai *dai);
-
int (*remove)(struct snd_soc_dai *dai);
-
/* compress dai */
-
int (*compress_new)(struct snd_soc_pcm_runtime *rtd, int num);
-
/* Optional Callback used at pcm creation*/
-
int (*pcm_new)(struct snd_soc_pcm_runtime *rtd,
-
struct snd_soc_dai *dai);
-
-
/* ops */
-
const struct snd_soc_dai_ops *ops;
-
const struct snd_soc_cdai_ops *cops;
-
-
/* DAI capabilities */
-
struct snd_soc_pcm_stream capture;
-
struct snd_soc_pcm_stream playback;
-
unsigned int symmetric_rate:1;
-
unsigned int symmetric_channels:1;
-
unsigned int symmetric_sample_bits:1;
-
-
/* probe ordering - for components with runtime dependencies */
-
int probe_order;
-
int remove_order;
-
};
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大类,驱动程序可以根据实际情况实现其中的一部分:
-
struct snd_soc_dai_ops {
-
/*
-
* DAI clocking configuration, all optional.
-
* Called by soc_card drivers, normally in their hw_params.
-
*/
-
int (*set_sysclk)(struct snd_soc_dai *dai,
-
int clk_id, unsigned int freq, int dir);
-
int (*set_pll)(struct snd_soc_dai *dai, int pll_id, int source,
-
unsigned int freq_in, unsigned int freq_out);
-
int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div);
-
int (*set_bclk_ratio)(struct snd_soc_dai *dai, unsigned int ratio);
-
-
/*
-
* DAI format configuration
-
* Called by soc_card drivers, normally in their hw_params.
-
*/
-
int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt);
-
int (*xlate_tdm_slot_mask)(unsigned int slots,
-
unsigned int *tx_mask, unsigned int *rx_mask);
-
int (*set_tdm_slot)(struct snd_soc_dai *dai,
-
unsigned int tx_mask, unsigned int rx_mask,
-
int slots, int slot_width);
-
int (*set_channel_map)(struct snd_soc_dai *dai,
-
unsigned int tx_num, unsigned int *tx_slot,
-
unsigned int rx_num, unsigned int *rx_slot);
-
int (*get_channel_map)(struct snd_soc_dai *dai,
-
unsigned int *tx_num, unsigned int *tx_slot,
-
unsigned int *rx_num, unsigned int *rx_slot);
-
int (*set_tristate)(struct snd_soc_dai *dai, int tristate);
-
-
int (*set_stream)(struct snd_soc_dai *dai,
-
void *stream, int direction);
-
void *(*get_stream)(struct snd_soc_dai *dai, int direction);
-
-
/*
-
* DAI digital mute - optional.
-
* Called by soc-core to minimise any pops.
-
*/
-
int (*mute_stream)(struct snd_soc_dai *dai, int mute, int stream);
-
-
/*
-
* ALSA PCM audio operations - all optional.
-
* Called by soc-core during audio PCM operations.
-
*/
-
int (*startup)(struct snd_pcm_substream *,
-
struct snd_soc_dai *);
-
void (*shutdown)(struct snd_pcm_substream *,
-
struct snd_soc_dai *);
-
int (*hw_params)(struct snd_pcm_substream *,
-
struct snd_pcm_hw_params *, struct snd_soc_dai *);
-
int (*hw_free)(struct snd_pcm_substream *,
-
struct snd_soc_dai *);
-
int (*prepare)(struct snd_pcm_substream *,
-
struct snd_soc_dai *);
-
/*
-
* NOTE: Commands passed to the trigger function are not necessarily
-
* compatible with the current state of the dai. For example this
-
* sequence of commands is possible: START STOP STOP.
-
* So do not unconditionally use refcounting functions in the trigger
-
* function, e.g. clk_enable/disable.
-
*/
-
int (*trigger)(struct snd_pcm_substream *, int,
-
struct snd_soc_dai *);
-
int (*bespoke_trigger)(struct snd_pcm_substream *, int,
-
struct snd_soc_dai *);
-
/*
-
* For hardware based FIFO caused delay reporting.
-
* Optional.
-
*/
-
snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,
-
struct snd_soc_dai *);
-
-
/*
-
* Format list for auto selection.
-
* Format will be increased if priority format was
-
* not selected.
-
* see
-
* snd_soc_dai_get_fmt()
-
*/
-
u64 *auto_selectable_formats;
-
int num_auto_selectable_formats;
-
-
/* bit field */
-
unsigned int no_capture_mute:1;
-
};
工作时钟配置函数通常由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注册流程
-
/* snd_soc_component_driver结构体实例化 */
-
static const struct snd_soc_component_driver soc_component_dev_wm8350 = {
-
.probe = wm8350_component_probe,
-
.remove = wm8350_component_remove,
-
.set_bias_level = wm8350_set_bias_level,
-
.controls = wm8350_snd_controls,
-
.num_controls = ARRAY_SIZE(wm8350_snd_controls),
-
.dapm_widgets = wm8350_dapm_widgets,
-
.num_dapm_widgets = ARRAY_SIZE(wm8350_dapm_widgets),
-
.dapm_routes = wm8350_dapm_routes,
-
.num_dapm_routes = ARRAY_SIZE(wm8350_dapm_routes),
-
.suspend_bias_off = 1,
-
.idle_bias_on = 1,
-
.use_pmdown_time = 1,
-
.endianness = 1,
-
.non_legacy_dai_naming = 1,
-
};
-
-
/* 进入到wm8350_probe函数 */
-
static int wm8350_probe(struct platform_device *pdev)
-
{
-
/* 通过devm_snd_soc_register_component函数注册soc_component_dev_wm8350 */
-
return devm_snd_soc_register_component(&pdev->dev,
-
&soc_component_dev_wm8350,
-
&wm8350_dai, 1);
-
}
-
-
/* 进入platform_driver函数 */
-
static struct platform_driver wm8350_codec_driver = {
-
.driver = {
-
.name = "wm8350-codec",
-
},
-
.probe = wm8350_probe,
-
};
-
-
/* 通过module_platform_driver宏来注册platform_driver */
-
module_platform_driver(wm8350_codec_driver);
3.2、platform_driver结构体
在编写 platform 驱动的时候,首先定义一个platform_driver结构体变量,然后实现结构体中的各个成员变量,重点是实现匹配方法以及probe函数。当驱动和设备匹配成功以后 probe函数就会执行,具体的驱动程序在 probe 函数里面编写,比如字符设备驱动等等。
-
struct platform_driver {
-
int (*probe)(struct platform_device *);
-
int (*remove)(struct platform_device *);
-
void (*shutdown)(struct platform_device *);
-
int (*suspend)(struct platform_device *, pm_message_t state);
-
int (*resume)(struct platform_device *);
-
struct device_driver driver;
-
const struct platform_device_id *id_table;
-
bool prevent_deferred_probe;
-
/*
-
* For most device drivers, no need to care about this flag as long as
-
* all DMAs are handled through the kernel DMA API. For some special
-
* ones, for example VFIO drivers, they know how to manage the DMA
-
* themselves and set this flag so that the IOMMU layer will allow them
-
* to setup and manage their own I/O address space.
-
*/
-
bool driver_managed_dma;
-
};
platform_driver结构体用于注册驱动到Platform总线,此处只讲几个重点字段:
1、probe:当驱动与设备匹配成功以后probe函数就会执行。一般驱动的提供者会编写,如果自己要编写一个全新的驱动,那么 probe 就需要自行实现。
2、driver:device_driver 结构体变量,Linux 内核里面大量使用到了面向对象的思维, device_driver相当于基类,提供了最基础的驱动框架。 plaform_driver继承了这个基类,然后在此基础上又添加了一些特有的成员变量。
3.3、snd_soc_component结构体
-
struct snd_soc_component {
-
/* device_driver->name 和snd_soc_component_driver->id有关, */
-
const char *name;
-
int id;
-
const char *name_prefix;
-
struct device *dev;
-
struct snd_soc_card *card;
-
-
unsigned int active;
-
-
unsigned int suspended:1; /* is in suspend PM state */
-
/* 用于把自己挂载到全局链表component_list下, component_list在soc-core中保持的全局变量 */
-
struct list_head list;
-
struct list_head card_aux_list; /* for auxiliary bound components */
-
struct list_head card_list;
-
-
/* 指向下属的snd_soc_component_driver, 该结构体一般由底层平台驱动实现 */
-
const struct snd_soc_component_driver *driver;
-
-
/* 链表头, 挂接snd_soc_dai->list list_add(&dai->list, &component->dai_list) */
-
struct list_head dai_list;
-
int num_dai;
-
-
struct regmap *regmap;
-
int val_bytes;
-
-
struct mutex io_mutex;
-
-
/* attached dynamic objects */
-
struct list_head dobj_list;
-
-
/*
-
* DO NOT use any of the fields below in drivers, they are temporary and
-
* are going to be removed again soon. If you use them in driver code
-
* the driver will be marked as BROKEN when these fields are removed.
-
*/
-
-
/* Don't use these, use snd_soc_component_get_dapm() */
-
struct snd_soc_dapm_context dapm;
-
-
/* machine specific init */
-
int (*init)(struct snd_soc_component *component);
-
-
/* function mark */
-
void *mark_module;
-
struct snd_pcm_substream *mark_open;
-
struct snd_pcm_substream *mark_hw_params;
-
struct snd_pcm_substream *mark_trigger;
-
struct snd_compr_stream *mark_compr_open;
-
void *mark_pm;
-
-
struct dentry *debugfs_root;
-
const char *debugfs_prefix;
-
};
3.4、snd_soc_component_driver结构体
-
struct snd_soc_component_driver {
-
const char *name;
-
-
/* Default control and setup, added after probe() is run */
-
const struct snd_kcontrol_new *controls;
-
unsigned int num_controls;
-
const struct snd_soc_dapm_widget *dapm_widgets;
-
unsigned int num_dapm_widgets;
-
const struct snd_soc_dapm_route *dapm_routes;
-
unsigned int num_dapm_routes;
-
-
int (*probe)(struct snd_soc_component *component);
-
void (*remove)(struct snd_soc_component *component);
-
int (*suspend)(struct snd_soc_component *component);
-
int (*resume)(struct snd_soc_component *component);
-
-
unsigned int (*read)(struct snd_soc_component *component,
-
unsigned int reg);
-
int (*write)(struct snd_soc_component *component,
-
unsigned int reg, unsigned int val);
-
-
/* pcm creation and destruction */
-
int (*pcm_construct)(struct snd_soc_component *component,
-
struct snd_soc_pcm_runtime *rtd);
-
void (*pcm_destruct)(struct snd_soc_component *component,
-
struct snd_pcm *pcm);
-
-
/* component wide operations */
-
int (*set_sysclk)(struct snd_soc_component *component,
-
int clk_id, int source, unsigned int freq, int dir);
-
int (*set_pll)(struct snd_soc_component *component, int pll_id,
-
int source, unsigned int freq_in, unsigned int freq_out);
-
int (*set_jack)(struct snd_soc_component *component,
-
struct snd_soc_jack *jack, void *data);
-
-
/* DT */
-
int (*of_xlate_dai_name)(struct snd_soc_component *component,
-
const struct of_phandle_args *args,
-
const char **dai_name);
-
int (*of_xlate_dai_id)(struct snd_soc_component *comment,
-
struct device_node *endpoint);
-
void (*seq_notifier)(struct snd_soc_component *component,
-
enum snd_soc_dapm_type type, int subseq);
-
int (*stream_event)(struct snd_soc_component *component, int event);
-
int (*set_bias_level)(struct snd_soc_component *component,
-
enum snd_soc_bias_level level);
-
-
int (*open)(struct snd_soc_component *component,
-
struct snd_pcm_substream *substream);
-
int (*close)(struct snd_soc_component *component,
-
struct snd_pcm_substream *substream);
-
int (*ioctl)(struct snd_soc_component *component,
-
struct snd_pcm_substream *substream,
-
unsigned int cmd, void *arg);
-
int (*hw_params)(struct snd_soc_component *component,
-
struct snd_pcm_substream *substream,
-
struct snd_pcm_hw_params *params);
-
int (*hw_free)(struct snd_soc_component *component,
-
struct snd_pcm_substream *substream);
-
int (*prepare)(struct snd_soc_component *component,
-
struct snd_pcm_substream *substream);
-
int (*trigger)(struct snd_soc_component *component,
-
struct snd_pcm_substream *substream, int cmd);
-
int (*sync_stop)(struct snd_soc_component *component,
-
struct snd_pcm_substream *substream);
-
snd_pcm_uframes_t (*pointer)(struct snd_soc_component *component,
-
struct snd_pcm_substream *substream);
-
int (*get_time_info)(struct snd_soc_component *component,
-
struct snd_pcm_substream *substream, struct timespec64 *system_ts,
-
struct timespec64 *audio_ts,
-
struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
-
struct snd_pcm_audio_tstamp_report *audio_tstamp_report);
-
int (*copy_user)(struct snd_soc_component *component,
-
struct snd_pcm_substream *substream, int channel,
-
unsigned long pos, void __user *buf,
-
unsigned long bytes);
-
struct page *(*page)(struct snd_soc_component *component,
-
struct snd_pcm_substream *substream,
-
unsigned long offset);
-
int (*mmap)(struct snd_soc_component *component,
-
struct snd_pcm_substream *substream,
-
struct vm_area_struct *vma);
-
int (*ack)(struct snd_soc_component *component,
-
struct snd_pcm_substream *substream);
-
snd_pcm_sframes_t (*delay)(struct snd_soc_component *component,
-
struct snd_pcm_substream *substream);
-
-
const struct snd_compress_ops *compress_ops;
-
-
/* probe ordering - for components with runtime dependencies */
-
int probe_order;
-
int remove_order;
-
-
/*
-
* signal if the module handling the component should not be removed
-
* if a pcm is open. Setting this would prevent the module
-
* refcount being incremented in probe() but allow it be incremented
-
* when a pcm is opened and decremented when it is closed.
-
*/
-
unsigned int module_get_upon_open:1;
-
-
/* bits */
-
unsigned int idle_bias_on:1;
-
unsigned int suspend_bias_off:1;
-
unsigned int use_pmdown_time:1; /* care pmdown_time at stop */
-
/*
-
* Indicates that the component does not care about the endianness of
-
* PCM audio data and the core will ensure that both LE and BE variants
-
* of each used format are present. Typically this is because the
-
* component sits behind a bus that abstracts away the endian of the
-
* original data, ie. one for which the transmission endian is defined
-
* (I2S/SLIMbus/SoundWire), or the concept of endian doesn't exist (PDM,
-
* analogue).
-
*/
-
unsigned int endianness:1;
-
unsigned int non_legacy_dai_naming:1;
-
-
/* this component uses topology and ignore machine driver FEs */
-
const char *ignore_machine;
-
const char *topology_name_prefix;
-
int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd,
-
struct snd_pcm_hw_params *params);
-
bool use_dai_pcm_id; /* use DAI link PCM ID as PCM device number */
-
int be_pcm_base; /* base device ID for all BE PCMs */
-
-
-
const char *debugfs_prefix;
-
-
};
module_platform_driver函数的详解请参考《module_platform_driver源码分析》
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhfhbhka
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
photoshop蒙版画笔没反应怎么办
PHP中文网 06-24