zoukankan      html  css  js  c++  java
  • msm codec 代码跟踪

    sound/soc/codecs/msm8x16-wcd.c

    static struct spmi_device_id msm8x16_wcd_spmi_id_table[] = {
    	{"wcd-spmi", MSM8X16_WCD_SPMI_DIGITAL},
    	{"wcd-spmi", MSM8X16_WCD_SPMI_ANALOG},
    	{}
    };
    
    static struct of_device_id msm8x16_wcd_spmi_of_match[] = {
    	{ .compatible = "qcom,msm8x16_wcd_codec",},
    	{ },
    };
    
    static struct spmi_driver wcd_spmi_driver = {
    	.driver                 = {
    		.owner          = THIS_MODULE,
    		.name           = "wcd-spmi-core",
    		.of_match_table = msm8x16_wcd_spmi_of_match
    	},
    #ifdef CONFIG_PM
    		.suspend = msm8x16_wcd_spmi_suspend,
    		.resume = msm8x16_wcd_spmi_resume,
    #endif
    	.id_table               = msm8x16_wcd_spmi_id_table,
    	.probe                  = msm8x16_wcd_spmi_probe,
    	.remove                 = msm8x16_wcd_spmi_remove,
    };
    
    static int __init msm8x16_wcd_codec_init(void)
    {
    	spmi_driver_register(&wcd_spmi_driver);
    	return 0;
    }
    
    static int msm8x16_wcd_spmi_probe(struct spmi_device *spmi)
    {
    	int ret = 0;
    	struct msm8x16_wcd *msm8x16 = NULL;
    	struct msm8x16_wcd_pdata *pdata;
    	struct resource *wcd_resource;
    	int adsp_state;
    	static int spmi_dev_registered_cnt;
    
    	dev_dbg(&spmi->dev, "%s(%d):slave ID = 0x%x
    ",
    		__func__, __LINE__,  spmi->sid);
    
    	adsp_state = apr_get_subsys_state();
    	if (adsp_state != APR_SUBSYS_LOADED) {
    		dev_dbg(&spmi->dev, "Adsp is not loaded yet %d
    ",
    				adsp_state);
    		return -EPROBE_DEFER;
    	}
    
    	wcd_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
    	if (!wcd_resource) {
    		dev_err(&spmi->dev, "Unable to get Tombak base address
    ");
    		return -ENXIO;
    	}
    
    	switch (wcd_resource->start) {
    	case TOMBAK_CORE_0_SPMI_ADDR:
    		msm8x16_wcd_modules[0].spmi = spmi;
    		msm8x16_wcd_modules[0].base = (spmi->sid << 16) +
    						wcd_resource->start;
    		wcd9xxx_spmi_set_dev(msm8x16_wcd_modules[0].spmi, 0);
    		device_init_wakeup(&spmi->dev, true);
    		break;
    	case TOMBAK_CORE_1_SPMI_ADDR:
    		msm8x16_wcd_modules[1].spmi = spmi;
    		msm8x16_wcd_modules[1].base = (spmi->sid << 16) +
    						wcd_resource->start;
    		wcd9xxx_spmi_set_dev(msm8x16_wcd_modules[1].spmi, 1);
    	if (wcd9xxx_spmi_irq_init()) {
    		dev_err(&spmi->dev,
    				"%s: irq initialization failed
    ", __func__);
    	} else {
    		dev_dbg(&spmi->dev,
    				"%s: irq initialization passed
    ", __func__);
    	}
    		spmi_dev_registered_cnt++;
    		goto register_codec;
    	default:
    		ret = -EINVAL;
    		goto rtn;
    	}
    
    
    	dev_dbg(&spmi->dev, "%s(%d):start addr = 0x%pK
    ",
    		__func__, __LINE__,  &wcd_resource->start);
    
    	if (wcd_resource->start != TOMBAK_CORE_0_SPMI_ADDR)
    		goto rtn;
    
    	if (spmi->dev.of_node) {
    		dev_dbg(&spmi->dev, "%s:Platform data from device tree
    ",
    			__func__);
    		// 解析设备树
    		pdata = msm8x16_wcd_populate_dt_pdata(&spmi->dev);
    		spmi->dev.platform_data = pdata;
    	} else {
    		dev_dbg(&spmi->dev, "%s:Platform data from board file
    ",
    			__func__);
    		pdata = spmi->dev.platform_data;
    	}
    	if (pdata == NULL) {
    		dev_err(&spmi->dev, "%s:Platform data failed to populate
    ",
    			__func__);
    		goto rtn;
    	}
    
    	msm8x16 = kzalloc(sizeof(struct msm8x16_wcd), GFP_KERNEL);
    	if (msm8x16 == NULL) {
    		ret = -ENOMEM;
    		goto rtn;
    	}
    
    	msm8x16->dev = &spmi->dev;
    	msm8x16->read_dev = __msm8x16_wcd_reg_read;
    	msm8x16->write_dev = __msm8x16_wcd_reg_write;
    	ret = msm8x16_wcd_init_supplies(msm8x16, pdata);
    	if (ret) {
    		dev_err(&spmi->dev, "%s: Fail to enable Codec supplies
    ",
    			__func__);
    		goto err_codec;
    	}
    
    	ret = msm8x16_wcd_enable_static_supplies(msm8x16, pdata);
    	if (ret) {
    		dev_err(&spmi->dev,
    			"%s: Fail to enable Codec pre-reset supplies
    ",
    			   __func__);
    		goto err_codec;
    	}
    	usleep_range(5, 6);
    
    	ret = msm8x16_wcd_device_init(msm8x16);
    	if (ret) {
    		dev_err(&spmi->dev,
    			"%s:msm8x16_wcd_device_init failed with error %d
    ",
    			__func__, ret);
    		goto err_supplies;
    	}
    	dev_set_drvdata(&spmi->dev, msm8x16);
    	spmi_dev_registered_cnt++;
    register_codec:
    	if ((spmi_dev_registered_cnt == MAX_MSM8X16_WCD_DEVICE) && (!ret)) {
    		if (msm8x16_wcd_modules[0].spmi) {
    			// 注册codec
    			ret = snd_soc_register_codec(
    					&msm8x16_wcd_modules[0].spmi->dev,
    					&soc_codec_dev_msm8x16_wcd,
    					msm8x16_wcd_i2s_dai,
    					ARRAY_SIZE(msm8x16_wcd_i2s_dai));
    			if (ret) {
    				dev_err(&spmi->dev,
    				"%s:snd_soc_register_codec failed with error %d
    ",
    				__func__, ret);
    				goto err_supplies;
    			}
    		}
    	}
    	return ret;
    err_supplies:
    	msm8x16_wcd_disable_supplies(msm8x16, pdata);
    err_codec:
    	kfree(msm8x16);
    rtn:
    	return ret;
    }
    
    // codec操作函数
    static struct snd_soc_codec_driver soc_codec_dev_msm8x16_wcd = {
    	.probe	= msm8x16_wcd_codec_probe,
    	.remove	= msm8x16_wcd_codec_remove,
    
    	.read = msm8x16_wcd_read,
    	.write = msm8x16_wcd_write,
    
    	.suspend = msm8x16_wcd_suspend,
    	.resume = msm8x16_wcd_resume,
    
    	.readable_register = msm8x16_wcd_readable,
    	.volatile_register = msm8x16_wcd_volatile,
    
    	.reg_cache_size = MSM8X16_WCD_CACHE_SIZE,
    	.reg_cache_default = msm8x16_wcd_reset_reg_defaults,
    	.reg_word_size = 1,
    
    	.controls = msm8x16_wcd_snd_controls,
    	.num_controls = ARRAY_SIZE(msm8x16_wcd_snd_controls),
    	.dapm_widgets = msm8x16_wcd_dapm_widgets,
    	.num_dapm_widgets = ARRAY_SIZE(msm8x16_wcd_dapm_widgets),
    	.dapm_routes = audio_map,
    	.num_dapm_routes = ARRAY_SIZE(audio_map),
    };
    
    static struct snd_soc_dai_driver msm8x16_wcd_i2s_dai[] = {
    	{
    		.name = "msm8x16_wcd_i2s_rx1",
    		.id = AIF1_PB,
    		.playback = {
    			.stream_name = "AIF1 Playback",
    			.rates = MSM8X16_WCD_RATES,
    			.formats = MSM8X16_WCD_FORMATS,
    			.rate_max = 192000,
    			.rate_min = 8000,
    			.channels_min = 1,
    			.channels_max = 3,
    		},
    		.ops = &msm8x16_wcd_dai_ops,
    	},
    	{
    		.name = "msm8x16_wcd_i2s_tx1",
    		.id = AIF1_CAP,
    		.capture = {
    			.stream_name = "AIF1 Capture",
    			.rates = MSM8X16_WCD_RATES,
    			.formats = MSM8X16_WCD_FORMATS,
    			.rate_max = 192000,
    			.rate_min = 8000,
    			.channels_min = 1,
    			.channels_max = 4,
    		},
    		.ops = &msm8x16_wcd_dai_ops,
    	},
    	{
    		.name = "cajon_vifeedback",
    		.id = AIF2_VIFEED,
    		.capture = {
    			.stream_name = "VIfeed",
    			.rates = MSM8X16_WCD_RATES,
    			.formats = MSM8X16_WCD_FORMATS,
    			.rate_max = 48000,
    			.rate_min = 48000,
    			.channels_min = 2,
    			.channels_max = 2,
    		},
    		.ops = &msm8x16_wcd_dai_ops,
    	},
    };
    

    sound/soc/soc-core.c

    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)
    {
    	struct snd_soc_codec *codec;
    	struct snd_soc_dai *dai;
    	int ret, i;
    
    	dev_dbg(dev, "codec register %s
    ", dev_name(dev));
    
    	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
    	if (codec == NULL)
    		return -ENOMEM;
    
    	codec->component.dapm_ptr = &codec->dapm;
    	codec->component.codec = codec;
    
    	ret = snd_soc_component_initialize(&codec->component,
    			&codec_drv->component_driver, dev);
    	if (ret)
    		goto err_free;
    	// 初始化
    	if (codec_drv->controls) {
    		codec->component.controls = codec_drv->controls;
    		codec->component.num_controls = codec_drv->num_controls;
    	}
    	if (codec_drv->dapm_widgets) {
    		codec->component.dapm_widgets = codec_drv->dapm_widgets;
    		codec->component.num_dapm_widgets = codec_drv->num_dapm_widgets;
    	}
    	if (codec_drv->dapm_routes) {
    		codec->component.dapm_routes = codec_drv->dapm_routes;
    		codec->component.num_dapm_routes = codec_drv->num_dapm_routes;
    	}
    
    	if (codec_drv->probe)
    		codec->component.probe = snd_soc_codec_drv_probe;
    	if (codec_drv->remove)
    		codec->component.remove = snd_soc_codec_drv_remove;
    	if (codec_drv->write)
    		codec->component.write = snd_soc_codec_drv_write;
    	if (codec_drv->read)
    		codec->component.read = snd_soc_codec_drv_read;
    	codec->volatile_register = codec_drv->volatile_register;
    	codec->readable_register = codec_drv->readable_register;
    	codec->writable_register = codec_drv->writable_register;
    	codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time;
    	codec->dapm.idle_bias_off = codec_drv->idle_bias_off;
    	codec->dapm.suspend_bias_off = codec_drv->suspend_bias_off;
    	if (codec_drv->seq_notifier)
    		codec->dapm.seq_notifier = codec_drv->seq_notifier;
    	if (codec_drv->set_bias_level)
    		codec->dapm.set_bias_level = snd_soc_codec_set_bias_level;
    	codec->dev = dev;
    	codec->driver = codec_drv;
    	codec->component.val_bytes = codec_drv->reg_word_size;
    	mutex_init(&codec->mutex);
    
    #ifdef CONFIG_DEBUG_FS
    	codec->component.init_debugfs = soc_init_codec_debugfs;
    	codec->component.debugfs_prefix = "codec";
    #endif
    
    	if (codec_drv->get_regmap)
    		codec->component.regmap = codec_drv->get_regmap(dev);
    
    	for (i = 0; i < num_dai; i++) {
    		fixup_codec_formats(&dai_drv[i].playback);
    		fixup_codec_formats(&dai_drv[i].capture);
    	}
    	// 注册codec的dai
    	ret = snd_soc_register_dais(&codec->component, dai_drv, num_dai, false);
    	if (ret < 0) {
    		dev_err(dev, "ASoC: Failed to regster DAIs: %d
    ", ret);
    		goto err_cleanup;
    	}
    
    	list_for_each_entry(dai, &codec->component.dai_list, list)
    		dai->codec = codec;
    
    	mutex_lock(&client_mutex);
    	snd_soc_component_add_unlocked(&codec->component);
    	list_add(&codec->list, &codec_list);
    	mutex_unlock(&client_mutex);
    
    	dev_dbg(codec->dev, "ASoC: Registered codec '%s'
    ",
    		codec->component.name);
    	return 0;
    
    err_cleanup:
    	snd_soc_component_cleanup(&codec->component);
    err_free:
    	kfree(codec);
    	return ret;
    }
    EXPORT_SYMBOL_GPL(snd_soc_register_codec);
    
    
    static int snd_soc_register_dais(struct snd_soc_component *component,
    	struct snd_soc_dai_driver *dai_drv, size_t count,
    	bool legacy_dai_naming)
    {
    	struct device *dev = component->dev;
    	struct snd_soc_dai *dai;
    	unsigned int i;
    	int ret;
    
    	dev_dbg(dev, "ASoC: dai register %s #%Zu
    ", dev_name(dev), count);
    
    	component->dai_drv = dai_drv;
    	component->num_dai = count;
    
    	for (i = 0; i < count; i++) {
    
    		dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
    		if (dai == NULL) {
    			ret = -ENOMEM;
    			goto err;
    		}
    
    		/*
    		 * 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 (count == 1 && legacy_dai_naming) {
    			dai->name = fmt_single_name(dev, &dai->id);
    		} else {
    			dai->name = fmt_multiple_name(dev, &dai_drv[i]);
    			if (dai_drv[i].id)
    				dai->id = dai_drv[i].id;
    			else
    				dai->id = i;
    		}
    		if (dai->name == NULL) {
    			kfree(dai);
    			ret = -ENOMEM;
    			goto err;
    		}
    
    		dai->component = component;
    		dai->dev = dev;
    		dai->driver = &dai_drv[i];
    		if (!dai->driver->ops)
    			dai->driver->ops = &null_dai_ops;
    
    		list_add(&dai->list, &component->dai_list);
    
    		dev_dbg(dev, "ASoC: Registered DAI '%s'
    ", dai->name);
    	}
    
    	return 0;
    
    err:
    	snd_soc_unregister_dais(component);
    
    	return ret;
    }
    
  • 相关阅读:
    解决CentOS 7 history命令不显示操作记录的时间和用户身份问题
    CentOS7关闭selinux
    Centos7下添加开机自启动服务和脚本
    快速查看一个文件的权限 stat -c %a
    修改centos7系统语言
    sudo
    chsh命令 修改用户登录shell
    忘记root开机密码及怎样开启密码远程连接模式
    centos7系统中添加 pstree 命令
    vim 多行添加注释,取消注释
  • 原文地址:https://www.cnblogs.com/helloworldtoyou/p/10499777.html
Copyright © 2011-2022 走看看