• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Linux ALSA驱动:Platform源码wm8350.c

武飞扬头像
Coder个人博客
帮助1

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

        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.  
     
  18.  
    /* DAI driver callbacks */
  19.  
    int (*probe)(struct snd_soc_dai *dai);
  20.  
    int (*remove)(struct snd_soc_dai *dai);
  21.  
    /* compress dai */
  22.  
    int (*compress_new)(struct snd_soc_pcm_runtime *rtd, int num);
  23.  
    /* Optional Callback used at pcm creation*/
  24.  
    int (*pcm_new)(struct snd_soc_pcm_runtime *rtd,
  25.  
    struct snd_soc_dai *dai);
  26.  
     
  27.  
    /* ops */
  28.  
    const struct snd_soc_dai_ops *ops;
  29.  
    const struct snd_soc_cdai_ops *cops;
  30.  
     
  31.  
    /* DAI capabilities */
  32.  
    struct snd_soc_pcm_stream capture;
  33.  
    struct snd_soc_pcm_stream playback;
  34.  
    unsigned int symmetric_rate:1;
  35.  
    unsigned int symmetric_channels:1;
  36.  
    unsigned int symmetric_sample_bits:1;
  37.  
     
  38.  
    /* probe ordering - for components with runtime dependencies */
  39.  
    int probe_order;
  40.  
    int remove_order;
  41.  
    };
学新通

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

        工作时钟配置函数通常由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.  
     
  19.  
    /* 进入到wm8350_probe函数 */
  20.  
    static int wm8350_probe(struct platform_device *pdev)
  21.  
    {
  22.  
    /* 通过devm_snd_soc_register_component函数注册soc_component_dev_wm8350 */
  23.  
    return devm_snd_soc_register_component(&pdev->dev,
  24.  
    &soc_component_dev_wm8350,
  25.  
    &wm8350_dai, 1);
  26.  
    }
  27.  
     
  28.  
    /* 进入platform_driver函数 */
  29.  
    static struct platform_driver wm8350_codec_driver = {
  30.  
    .driver = {
  31.  
    .name = "wm8350-codec",
  32.  
    },
  33.  
    .probe = wm8350_probe,
  34.  
    };
  35.  
     
  36.  
    /* 通过module_platform_driver宏来注册platform_driver */
  37.  
    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.  
     
  9.  
    unsigned int active;
  10.  
     
  11.  
    unsigned int suspended:1; /* is in suspend PM state */
  12.  
    /* 用于把自己挂载到全局链表component_list下, component_list在soc-core中保持的全局变量 */
  13.  
    struct list_head list;
  14.  
    struct list_head card_aux_list; /* for auxiliary bound components */
  15.  
    struct list_head card_list;
  16.  
     
  17.  
    /* 指向下属的snd_soc_component_driver, 该结构体一般由底层平台驱动实现 */
  18.  
    const struct snd_soc_component_driver *driver;
  19.  
     
  20.  
    /* 链表头, 挂接snd_soc_dai->list list_add(&dai->list, &component->dai_list) */
  21.  
    struct list_head dai_list;
  22.  
    int num_dai;
  23.  
     
  24.  
    struct regmap *regmap;
  25.  
    int val_bytes;
  26.  
     
  27.  
    struct mutex io_mutex;
  28.  
     
  29.  
    /* attached dynamic objects */
  30.  
    struct list_head dobj_list;
  31.  
     
  32.  
    /*
  33.  
    * DO NOT use any of the fields below in drivers, they are temporary and
  34.  
    * are going to be removed again soon. If you use them in driver code
  35.  
    * the driver will be marked as BROKEN when these fields are removed.
  36.  
    */
  37.  
     
  38.  
    /* Don't use these, use snd_soc_component_get_dapm() */
  39.  
    struct snd_soc_dapm_context dapm;
  40.  
     
  41.  
    /* machine specific init */
  42.  
    int (*init)(struct snd_soc_component *component);
  43.  
     
  44.  
    /* function mark */
  45.  
    void *mark_module;
  46.  
    struct snd_pcm_substream *mark_open;
  47.  
    struct snd_pcm_substream *mark_hw_params;
  48.  
    struct snd_pcm_substream *mark_trigger;
  49.  
    struct snd_compr_stream *mark_compr_open;
  50.  
    void *mark_pm;
  51.  
     
  52.  
    struct dentry *debugfs_root;
  53.  
    const char *debugfs_prefix;
  54.  
    };
学新通

3.4、snd_soc_component_driver结构体

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

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

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfhbhka
系列文章
更多 icon
同类精品
更多 icon
继续加载