源码位于kernel\sound\soc\codecs\Wcd9335.c
1. 模块初始化入口代码放在了module_platform_driver()这个函数中,关于这个函数的解析,请看博客链接如下,
http://blog.csdn.net/jgw2008/article/details/
module_platform_driver(tasha_codec_driver);
讯享网tasha_codec_driver结构体如下,模块加载入口从"tasha_probe"开始
讯享网static struct platform_driver tasha_codec_driver = { .probe = tasha_probe, .remove = tasha_remove, .shutdown = tasha_powershutdown, .driver = { .name = "tasha_codec", .owner = THIS_MODULE, #ifdef CONFIG_PM .pm = &tasha_pm_ops, #endif }, };
2. 下面分析函数"tasha_probe"
2.1 为tasha private data(私有数据)申请空间,并保存起来,
关于platform_set_drvdata的分析,请参见博文http://blog.csdn.net/jgw2008/article/details/
tasha = devm_kzalloc(&pdev->dev, sizeof(struct tasha_priv), GFP_KERNEL); if (!tasha) { dev_err(&pdev->dev, "%s: cannot create memory for wcd9335\n", __func__); return -ENOMEM; } platform_set_drvdata(pdev, tasha);2.2 下面是tasha结构体初始化
注意:
a. 初始了2了工作队列,一个是跟power有关;一个是跟control有关。
b. 初始了6个mutex。
关于队列的分析介绍,请参见博文http://blog.csdn.net/jgw2008/article/details/
关于devm_kzalloc的使用,参加博文http://blog.csdn.net/jgw2008/article/details/
讯享网 tasha->wcd9xxx = dev_get_drvdata(pdev->dev.parent); tasha->dev = &pdev->dev; INIT_DELAYED_WORK(&tasha->power_gate_work, tasha_codec_power_gate_work); mutex_init(&tasha->power_lock); mutex_init(&tasha->sido_lock); INIT_WORK(&tasha->swr_add_devices_work, wcd_swr_ctrl_add_devices); BLOCKING_INIT_NOTIFIER_HEAD(&tasha->notifier); mutex_init(&tasha->micb_lock); mutex_init(&tasha->swr_read_lock); mutex_init(&tasha->swr_write_lock); mutex_init(&tasha->swr_clk_lock); cdc_pwr = devm_kzalloc(&pdev->dev, sizeof(struct wcd9xxx_power_region), GFP_KERNEL); if (!cdc_pwr) { ret = -ENOMEM; goto cdc_pwr_fail; } tasha->wcd9xxx->wcd9xxx_pwr[WCD9XXX_DIG_CORE_REGION_1] = cdc_pwr; cdc_pwr->pwr_collapse_reg_min = TASHA_DIG_CORE_REG_MIN; cdc_pwr->pwr_collapse_reg_max = TASHA_DIG_CORE_REG_MAX; wcd9xxx_set_power_state(tasha->wcd9xxx, WCD_REGION_POWER_COLLAPSE_REMOVE, WCD9XXX_DIG_CORE_REGION_1);
2.3 向系统注册codec
if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS) { ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tasha, tasha_dai, ARRAY_SIZE(tasha_dai)); if (ret) { dev_err(&pdev->dev, "%s: Codec registration failed\n", __func__); goto cdc_reg_fail; } }
注意,snd_soc_register_codec的第二个参数"soc_codec_dev_tasha"的定义如下,其结构体成员将会赋值给结构体”snd_soc_codec“。
这个结构体里还有一个codec probe函数"tasha_codec_probe"不知道什么时候被呼叫,但无论如何,codec probe一定会被呼叫,而且是十分重要的函数。
关于codec probe函数"tasha_codec_probe"的分析,请参考博文http://blog.csdn.net/jgw2008/article/details/
讯享网static struct snd_soc_codec_driver soc_codec_dev_tasha = { .probe = tasha_codec_probe, .remove = tasha_codec_remove, .suspend = tasha_codec_suspend, .resume = tasha_codec_resume, .controls = tasha_snd_controls, .num_controls = ARRAY_SIZE(tasha_snd_controls), .dapm_widgets = tasha_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(tasha_dapm_widgets), .dapm_routes = audio_map, .num_dapm_routes = ARRAY_SIZE(audio_map), };
2.4 初始化资源管理器
/* * Init resource manager so that if child nodes such as SoundWire * requests for clock, resource manager can honor the request */ resmgr = wcd_resmgr_init(&tasha->wcd9xxx->core_res, NULL); if (IS_ERR(resmgr)) { ret = PTR_ERR(resmgr); dev_err(&pdev->dev, "%s: Failed to initialize wcd resmgr\n", __func__); goto unregister_codec; } tasha->resmgr = resmgr;2.5 初始化 读/写/中断等的回调函数,十分重要
讯享网 tasha->swr_plat_data.handle = (void *) tasha; tasha->swr_plat_data.read = tasha_swrm_read; tasha->swr_plat_data.write = tasha_swrm_write; tasha->swr_plat_data.bulk_write = tasha_swrm_bulk_write; tasha->swr_plat_data.clk = tasha_swrm_clock; tasha->swr_plat_data.handle_irq = tasha_swrm_handle_irq;2.6 注册clock
/* Register for Clock */ wcd_ext_clk = clk_get(tasha->wcd9xxx->dev, "wcd_clk"); if (IS_ERR(wcd_ext_clk)) { dev_err(tasha->wcd9xxx->dev, "%s: clk get %s failed\n", __func__, "wcd_ext_clk"); goto resmgr_remove; } tasha->wcd_ext_clk = wcd_ext_clk;2.7 tasha其他设置,如电压等
讯享网 tasha->sido_voltage = SIDO_VOLTAGE_NOMINAL_MV; set_bit(AUDIO_NOMINAL, &tasha->status_mask); tasha->sido_ccl_cnt = 0;2.8 更新code默认值
/* Update codec register default values */ tasha_update_reg_defaults(tasha);
2.9 添加设备(为什么要使用队列呢?)
关于添加设备到device list, 请见博文http://blog.csdn.net/jgw2008/article/details/
讯享网 schedule_work(&tasha->swr_add_devices_work);
2.10 获取codec版本
tasha_get_codec_ver(tasha);
至此,codec和DAIs(Digital Audio Interface)已经成功注册,probe函数跑完!
另外,研究一个驱动或者函数,其中涉及的结构体最为重要,在函数tasha_probe()中,主要涉及的结构体是"tasha_priv", 函数完成了对这个结构体的填充和初始化。
下面是结构体的定义
讯享网struct tasha_priv { struct device *dev; struct wcd9xxx *wcd9xxx; struct snd_soc_codec *codec; u32 adc_count; u32 rx_bias_count; s32 dmic_0_1_clk_cnt; s32 dmic_2_3_clk_cnt; s32 dmic_4_5_clk_cnt; s32 ldo_h_users; s32 micb_ref[TASHA_MAX_MICBIAS]; s32 pullup_ref[TASHA_MAX_MICBIAS]; u32 anc_slot; bool anc_func; /* Vbat module */ struct wcd_vbat vbat; /* cal info for codec */ struct fw_info *fw_data; /*track tasha interface type*/ u8 intf_type; /* num of slim ports required */ struct wcd9xxx_codec_dai_data dai[NUM_CODEC_DAIS]; /* SoundWire data structure */ struct tasha_swr_ctrl_data *swr_ctrl_data; int nr; /*compander*/ int comp_enabled[COMPANDER_MAX]; /* Maintain the status of AUX PGA */ int aux_pga_cnt; u8 aux_l_gain; u8 aux_r_gain; bool spkr_pa_widget_on; struct regulator *spkdrv_reg; struct regulator *spkdrv2_reg; bool mbhc_started; /* class h specific data */ struct wcd_clsh_cdc_data clsh_d; struct afe_param_cdc_slimbus_slave_cfg slimbus_slave_cfg; /* * list used to save/restore registers at start and * end of impedance measurement */ struct list_head reg_save_restore; /* handle to cpe core */ struct wcd_cpe_core *cpe_core; u32 current_cpe_clk_freq; enum tasha_sido_voltage sido_voltage; int sido_ccl_cnt; u32 ana_rx_supplies; /* Multiplication factor used for impedance detection */ int zdet_gain_mul_fact; /* to track the status */ unsigned long status_mask; struct work_struct swr_add_devices_work; struct wcd_swr_ctrl_platform_data swr_plat_data; /* Port values for Rx and Tx codec_dai */ unsigned int rx_port_value; unsigned int tx_port_value; unsigned int vi_feed_value; /* Tasha Interpolator Mode Select for EAR, HPH_L and HPH_R */ u32 hph_mode; u16 prim_int_users[TASHA_NUM_INTERPOLATORS]; int spl_src_users[SPLINE_SRC_MAX]; struct wcd9xxx_resmgr_v2 *resmgr; struct delayed_work power_gate_work; struct mutex power_lock; struct mutex sido_lock; /* mbhc module */ struct wcd_mbhc mbhc; struct blocking_notifier_head notifier; struct mutex micb_lock; struct clk *wcd_ext_clk; struct mutex swr_read_lock; struct mutex swr_write_lock; struct mutex swr_clk_lock; int swr_clk_users; int power_active_ref; int (*zdet_gpio_cb)(struct snd_soc_codec *codec, bool high); struct on_demand_supply on_demand_list[ON_DEMAND_SUPPLIES_MAX]; int (*machine_codec_event_cb)(struct snd_soc_codec *codec, enum wcd9335_codec_event); struct snd_info_entry *entry; struct snd_info_entry *version_entry; int spkr_gain_offset; int spkr_mode; struct hpf_work tx_hpf_work[TASHA_NUM_DECIMATORS]; struct tx_mute_work tx_mute_dwork[TASHA_NUM_DECIMATORS]; int hph_l_gain; int hph_r_gain; int rx_7_count; int rx_8_count; };

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/55260.html