- //理解imx536的can驱动还是从probe开始吧,2.6版本内核can驱动是归属于网络驱动
- //所以我得先去把网络驱动几个重要结构体先找出来吧。前进吧!年轻人。
- static struct platform_driver flexcan_driver = {
- .driver = {
- .name = FLEXCAN_DEVICE_NAME,
- },
- .probe = flexcan_probe,
- .remove = flexcan_remove,
- .suspend = flexcan_suspend,
- .resume = flexcan_resume,
- };
下面看probe
[cpp]
view plain
copy
- static int flexcan_probe(struct platform_device *pdev)
- {
- //还是熟悉的struct net_device
- struct net_device *net;
- //这个函数估计得干大把大把的事吧,什么申请内存,什么初始化struct net_device及网络设备私有数据等
- net = flexcan_device_alloc(pdev, flexcan_setup);
- if (!net)
- return -ENOMEM;
- //注册网络设备
- if (register_netdev(net)) {
- flexcan_device_free(pdev);
- return -ENODEV;
- }
- return 0;
- }
probe中主要是调用了flexcan_device_alloc,继续看flexcan_device_alloc
[cpp]
view plain
copy
- struct net_device *flexcan_device_alloc(struct platform_device *pdev,
- void (*setup) (struct net_device *dev))
- {
- //can私有数据结构体
- struct flexcan_device *flexcan;
- struct net_device *net;
- int i, num;
- //申请内存,初始化net
- net = alloc_netdev(sizeof(*flexcan), "can%d", setup);
- if (net == NULL) {
- printk(KERN_ERR "Allocate netdevice for FlexCAN fail!\n");
- return NULL;
- }
- //flexcan指向net尾端,即私有数据结构体起始地址
- flexcan = netdev_priv(net);
- memset(flexcan, 0, sizeof(*flexcan));
- //互斥锁初始化
- mutex_init(&flexcan->mutex);
- //初始化内核定时器
- init_timer(&flexcan->timer);
- flexcan->dev = pdev;
- //注册中断,映射虚拟内存
- if (flexcan_device_attach(flexcan)) {
- printk(KERN_ERR "Attach FlexCAN fail!\n");
- free_netdev(net);
- return NULL;
- }
- //把板级配置文件中设置的struct flexcan_platform_data中的值,传递给flexcan
- flexcan_device_default(flexcan);
- //根据can的波特率去算br_presdiv,br_propseg,br_pseg1,br_pseg2这些变量的值
- //因为flexcan->bitrate值未确定,所以在我的板上,这个函数不起效果
- flexcan_set_bitrate(flexcan, flexcan->bitrate);
- //重新计算波特率,保存在flexcan
- flexcan_update_bitrate(flexcan);
- //ARRAY_SIZE作用是取数组元素个数
- num = ARRAY_SIZE(flexcan_dev_attr);
- //device_create_file,添加属性文件,我的理解最终会设置文件系统sys目录下一些设备属性文件
- //这些设备文件是在调用device_create时生成的。device_create这个函数什么时候调用的呢,这个就需要udev
- //udev是什么?udev是设备管理器,能自动生成设备节点。
- //在dm9000驱动里不知道为什么没看到这个函数?
- for (i = 0; i < num; i++) {
- if (device_create_file(&pdev->dev, flexcan_dev_attr + i)) {
- printk(KERN_ERR "Create attribute file fail!\n");
- break;
- }
- }
- //上面操作的反向操作
- if (i != num) {
- for (; i >= 0; i--)
- device_remove_file(&pdev->dev, flexcan_dev_attr + i);
- free_netdev(net);
- return NULL;
- }
- //保存net为设备私有数据
- dev_set_drvdata(&pdev->dev, net);
- return net;
- }
flexcan_device_alloc中最重要的几个函数flexcan_device_attach,flexcan_device_default,flexcan_set_bitratef,lexcan_update_bitrate
下面看看这个函数的代码,看它们都干了什么?
[cpp]
view plain
copy
- static void flexcan_set_bitrate(struct flexcan_device *flexcan, int bitrate)
- {
- /* TODO:: implement in future
- * based on the bitrate to get the timing of
- * presdiv, pseg1, pseg2, propseg
- */
- int i, rate, div;
- bool found = false;
- struct time_segment *segment;
- rate = clk_get_rate(flexcan->clk);
- if (!bitrate)
- bitrate = DEFAULT_BITRATE;
- //如果时钟正好是波特率的整数倍
- if (rate % bitrate == 0)
- {
- //根据时钟是波特率的倍数去推算br_presdiv,br_propseg,br_pseg1,br_pseg2
- div = rate / bitrate;
- for (i = TIME_SEGMENT_MID; i <= TIME_SEGMENT_MAX; i++)
- {
- if (div % i == 0) {
- found = true;
- break;
- }
- }
- if (!found) {
- for (i = TIME_SEGMENT_MID - 1;
- i >= TIME_SEGMENT_MIN; i--) {
- if (div % i == 0) {
- found = true;
- break;
- }
- }
- }
- }
- if (found) {
- //time_segments数组中列出了各种br_presdiv,br_propseg,br_pseg1,br_pseg2组合值
- //根据以上推算,确定i值,从而确定br_presdiv,br_propseg,br_pseg1,br_pseg2的值
- segment = &time_segments[i - TIME_SEGMENT_MIN];
- flexcan->br_presdiv = div/i - 1;
- flexcan->br_propseg = segment->propseg;
- flexcan->br_pseg1 = segment->pseg1;
- flexcan->br_pseg2 = segment->pseg2;
- flexcan->bitrate = bitrate;
- } else {
- pr_info("The bitrate %d can't supported with clock \
- rate of %d \n", bitrate, rate);
- }
- }
[cpp]
view plain
copy
- static void flexcan_update_bitrate(struct flexcan_device *flexcan)
- {
- int rate, div;
- //板级配置文件中设置的
- struct flexcan_platform_data *plat_data;
- plat_data = flexcan->dev->dev.platform_data;
- //如果板级配置文件中,struct flexcan_platform_data中root_clk_id配置了
- if (plat_data->root_clk_id)
- rate = clk_get_rate(flexcan->clk);
- else
- {
- //若struct flexcan_platform_data中root_clk_id未被配置,再看br_clksrc是否被配置成1
- if (flexcan->br_clksrc)
- rate = clk_get_rate(flexcan->clk);
- //在我的imx536项目中,以上两个变量都未被配置,所以会执行以下代码
- else
- {
- struct clk *clk;
- clk = clk_get(NULL, "ckih");
- if (!clk)
- return;
- //获取can时钟频率
- rate = clk_get_rate(clk);
- clk_put(clk);
- }
- }
- if (!rate)
- return;
- //计算can传输速率
- //其中br_presdiv,br_propseg,br_pseg1,br_pseg2,这些参数都是在板级配置文件中设置的
- //所以可以实现由用户自己配置CAN波特率
- div = (flexcan->br_presdiv + 1);
- div *=
- (flexcan->br_propseg + flexcan->br_pseg1 + flexcan->br_pseg2 + 4);
- flexcan->bitrate = (rate + div - 1) / div;
- }
[cpp]
view plain
copy
- static int flexcan_device_attach(struct flexcan_device *flexcan)
- {
- int ret;
- struct resource *res;
- struct platform_device *pdev = flexcan->dev;
- struct flexcan_platform_data *plat_data = (pdev->dev).platform_data;
- struct clk *can_root_clk;
- //看到了熟悉的身影了
- res = platform_get_resource(flexcan->dev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
- //内存映射
- flexcan->io_base = ioremap(res->start, res->end - res->start + 1);
- if (!flexcan->io_base)
- return -ENOMEM;
- //咋没直接注册中断?
- flexcan->irq = platform_get_irq(flexcan->dev, 0);
- if (!flexcan->irq) {
- ret = -ENODEV;
- goto no_irq_err;
- }
- ret = -EINVAL;
- if (plat_data) {
- if (plat_data->core_reg) {
- flexcan->core_reg = regulator_get(&pdev->dev,
- plat_data->core_reg);
- if (!flexcan->core_reg)
- goto plat_err;
- }
- if (plat_data->io_reg) {
- flexcan->io_reg = regulator_get(&pdev->dev,
- plat_data->io_reg);
- if (!flexcan->io_reg)
- goto plat_err;
- }
- }
- flexcan->clk = clk_get(&(flexcan->dev)->dev, "can_clk");
- //如果板级配置文件中root_clk_id被配置了,can时钟源变成了root_clk_id
- if (plat_data->root_clk_id)
- {
- can_root_clk = clk_get(NULL, plat_data->root_clk_id);
- clk_set_parent(flexcan->clk, can_root_clk);
- }
- flexcan->hwmb = (struct can_hw_mb *)(flexcan->io_base + CAN_MB_BASE);
- flexcan->rx_mask = (unsigned int *)(flexcan->io_base + CAN_RXMASK_BASE);
- return 0;
- //以后得多学学内核纠错处理了
- plat_err:
- if (flexcan->core_reg) {
- regulator_put(flexcan->core_reg);
- flexcan->core_reg = NULL;
- }
- no_irq_err:
- if (flexcan->io_base)
- iounmap(flexcan->io_base);
- return ret;
- }