函数wcd_swr_ctrl_add_devices()分析

14 篇文章 2 订阅

函数wcd_swr_ctrl_add_devices()的主要作用是WCD device添加到platform device列表中,挂载在platform bus下。

此函数被wcd probe函数通过工作队列的方式呼叫,代码如下

	schedule_work(&tasha->swr_add_devices_work);

下面一起看看这个函数做了什么,

1. 首先,从work队列中讲tasha结构体指针找到(container_of可真是万能啊,神一样的万能)

	tasha = container_of(work, struct tasha_priv,
			     swr_add_devices_work);
	if (!tasha) {
		pr_err("%s: Memory for WCD9335 does not exist\n",
			__func__);
		return;
	}
而之所以能从work队列中找到tasha结构体,是因为wcd proble函数在队列初始化的时候”swr_add_devices_work“是结构体”tasha“的一员,所以container_of可以根据指针”swr_add_devices_work“找到tasha结构体的指针。

	INIT_WORK(&tasha->swr_add_devices_work, wcd_swr_ctrl_add_devices);
2. 下面是找到wcd9xxx结构体,并判断device node是否为空,如果为空,则返回;

	wcd9xxx = tasha->wcd9xxx;
	if (!wcd9xxx) {
		pr_err("%s: Memory for WCD9XXX does not exist\n",
			__func__);
		return;
	}
	if (!wcd9xxx->dev->of_node) {
		pr_err("%s: DT node for wcd9xxx does not exist\n",
			__func__);
		return;
	}
关于wcd9xxx这个结构体,也是蛮奇怪的,在wcd probe函数中,它是从device父节点的driver data获得,代码如下。问题是,wcd probe函数刚刚启动,谁又给device父节点的driver data赋值?

	tasha->wcd9xxx = dev_get_drvdata(pdev->dev.parent);
3. 下面是获取platform data

	platdata = &tasha->swr_plat_data;
在wcd probe函数中,swr_plat_data已经赋值如下(一大堆回调函数)

	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;
4. 下面是个循环,有多少个device node就有多少次循环

	for_each_child_of_node(wcd9xxx->dev->of_node, node) {
5. 申请并创建platform device,

		temp = krealloc(swr_ctrl_data,
			(ctrl_num + 1) * sizeof(struct tasha_swr_ctrl_data),
			GFP_KERNEL);
		if (!temp) {
			dev_err(wcd9xxx->dev, "out of memory\n");
			ret = -ENOMEM;
			goto err;
		}
		swr_ctrl_data = temp;
		swr_ctrl_data[ctrl_num].swr_pdev = NULL;
		pdev = platform_device_alloc("tasha_swr_ctrl", -1);
		if (!pdev) {
			dev_err(wcd9xxx->dev, "%s: pdev memory alloc failed\n",
				__func__);
			ret = -ENOMEM;
			goto err;
		}
6. platform device创建好后,初始化parent device和device node,如下
		pdev->dev.parent = tasha->dev;
		pdev->dev.of_node = node;
7. 向platform deivce中添加platform data,

		ret = platform_device_add_data(pdev, platdata,
					       sizeof(*platdata));
		if (ret) {
			dev_err(&pdev->dev, "%s: cannot add plat data for ctrl:%d\n",
				__func__, ctrl_num);
			goto fail_pdev_add;
		}
8. 这一步,终于将platform device添加到了device list,

		ret = platform_device_add(pdev);
		if (ret) {
			dev_err(&pdev->dev, "%s: Cannot add swr platform device\n",
				__func__);
			goto fail_pdev_add;
		}
9. 将platform device赋值给swr_ctrl_data结构体的swr_pdev,并将ctrl_num自增1;至此,一轮循环结束。

		swr_ctrl_data[ctrl_num].swr_pdev = pdev;
		ctrl_num++;
10. 循环结束后,更新ctrl_num的数量和tasha->swr_ctrl_data的指向地址;注意,swr_ctrl_data是数组的首地址,tasha->swr_ctrl_data也是地址。

	tasha->nr = ctrl_num;
	tasha->swr_ctrl_data = swr_ctrl_data;

至此,函数wcd_swr_ctrl_add_devices()运行结束。


好了,我们再回顾一下这个函数用了哪些重要的结构体,

1. 包含本驱动的私有数据结构体tasha_priv, 和本设备的结构体wcd9xxx;

2. 基本类型的结构体有platform_device和device_node,这个函数就是要添加为platform类型的device;

3. 本函数相关的结构体包括 tasha_swr_ctrl_data 和 wcd_swr_ctrl_platform_data,具体定义如下,

/* Hold instance to soundwire platform device */
struct tasha_swr_ctrl_data {
	struct platform_device *swr_pdev;
	/* struct ida swr_ida; */
};


struct wcd_swr_ctrl_platform_data {
	void *handle; /* holds codec private data */
	int (*read)(void *handle, int reg);
	int (*write)(void *handle, int reg, int val);
	int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len);
	int (*clk)(void *handle, bool enable);
	int (*handle_irq)(void *handle,
			  irqreturn_t (*swrm_irq_handler)(int irq,
							  void *data),
			  void *swrm_handle,
			  int action);
};













评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值