imx6q can驱动理解

  1. //理解imx536的can驱动还是从probe开始吧,2.6版本内核can驱动是归属于网络驱动  
  2. //所以我得先去把网络驱动几个重要结构体先找出来吧。前进吧!年轻人。  
  3. static struct platform_driver flexcan_driver = {  
  4.     .driver = {  
  5.            .name = FLEXCAN_DEVICE_NAME,  
  6.            },  
  7.     .probe = flexcan_probe,  
  8.     .remove = flexcan_remove,  
  9.     .suspend = flexcan_suspend,  
  10.     .resume = flexcan_resume,  
  11. };  

下面看probe

[cpp]  view plain copy
  1. static int flexcan_probe(struct platform_device *pdev)  
  2. {  
  3.     //还是熟悉的struct net_device  
  4.     struct net_device *net;  
  5.     //这个函数估计得干大把大把的事吧,什么申请内存,什么初始化struct net_device及网络设备私有数据等  
  6.     net = flexcan_device_alloc(pdev, flexcan_setup);  
  7.     if (!net)  
  8.         return -ENOMEM;  
  9.     //注册网络设备  
  10.     if (register_netdev(net)) {  
  11.         flexcan_device_free(pdev);  
  12.         return -ENODEV;  
  13.     }  
  14.     return 0;  
  15. }  

probe中主要是调用了flexcan_device_alloc,继续看flexcan_device_alloc

[cpp]  view plain copy
  1. struct net_device *flexcan_device_alloc(struct platform_device *pdev,  
  2.                     void (*setup) (struct net_device *dev))  
  3. {  
  4.     //can私有数据结构体  
  5.     struct flexcan_device *flexcan;  
  6.     struct net_device *net;  
  7.     int i, num;  
  8.     //申请内存,初始化net  
  9.     net = alloc_netdev(sizeof(*flexcan), "can%d", setup);  
  10.     if (net == NULL) {  
  11.         printk(KERN_ERR "Allocate netdevice for FlexCAN fail!\n");  
  12.         return NULL;  
  13.     }  
  14.     //flexcan指向net尾端,即私有数据结构体起始地址  
  15.     flexcan = netdev_priv(net);  
  16.     memset(flexcan, 0, sizeof(*flexcan));  
  17.     //互斥锁初始化  
  18.     mutex_init(&flexcan->mutex);  
  19.     //初始化内核定时器  
  20.     init_timer(&flexcan->timer);  
  21.   
  22.     flexcan->dev = pdev;  
  23.     //注册中断,映射虚拟内存  
  24.     if (flexcan_device_attach(flexcan)) {  
  25.         printk(KERN_ERR "Attach FlexCAN fail!\n");  
  26.         free_netdev(net);  
  27.         return NULL;  
  28.     }  
  29.     //把板级配置文件中设置的struct flexcan_platform_data中的值,传递给flexcan  
  30.     flexcan_device_default(flexcan);  
  31.     //根据can的波特率去算br_presdiv,br_propseg,br_pseg1,br_pseg2这些变量的值  
  32.     //因为flexcan->bitrate值未确定,所以在我的板上,这个函数不起效果  
  33.     flexcan_set_bitrate(flexcan, flexcan->bitrate);  
  34.     //重新计算波特率,保存在flexcan  
  35.     flexcan_update_bitrate(flexcan);  
  36.   
  37.     //ARRAY_SIZE作用是取数组元素个数  
  38.     num = ARRAY_SIZE(flexcan_dev_attr);  
  39.     //device_create_file,添加属性文件,我的理解最终会设置文件系统sys目录下一些设备属性文件  
  40.     //这些设备文件是在调用device_create时生成的。device_create这个函数什么时候调用的呢,这个就需要udev  
  41.     //udev是什么?udev是设备管理器,能自动生成设备节点。  
  42.     //在dm9000驱动里不知道为什么没看到这个函数?  
  43.     for (i = 0; i < num; i++) {  
  44.         if (device_create_file(&pdev->dev, flexcan_dev_attr + i)) {  
  45.             printk(KERN_ERR "Create attribute file fail!\n");  
  46.             break;  
  47.         }  
  48.     }  
  49.     //上面操作的反向操作  
  50.     if (i != num) {  
  51.         for (; i >= 0; i--)  
  52.             device_remove_file(&pdev->dev, flexcan_dev_attr + i);  
  53.         free_netdev(net);  
  54.         return NULL;  
  55.     }  
  56.     //保存net为设备私有数据  
  57.     dev_set_drvdata(&pdev->dev, net);  
  58.     return net;  
  59. }  

flexcan_device_alloc中最重要的几个函数flexcan_device_attach,flexcan_device_default,flexcan_set_bitratef,lexcan_update_bitrate
下面看看这个函数的代码,看它们都干了什么?

[cpp]  view plain copy
  1. static void flexcan_set_bitrate(struct flexcan_device *flexcan, int bitrate)  
  2. {  
  3.     /* TODO:: implement in future 
  4.      * based on the bitrate to get the timing of 
  5.      * presdiv, pseg1, pseg2, propseg 
  6.      */  
  7.     int i, rate, div;  
  8.     bool found = false;  
  9.     struct time_segment *segment;  
  10.     rate = clk_get_rate(flexcan->clk);  
  11.   
  12.     if (!bitrate)  
  13.         bitrate = DEFAULT_BITRATE;  
  14.     //如果时钟正好是波特率的整数倍  
  15.     if (rate % bitrate == 0)   
  16.     {  
  17.         //根据时钟是波特率的倍数去推算br_presdiv,br_propseg,br_pseg1,br_pseg2  
  18.         div = rate / bitrate;  
  19.         for (i = TIME_SEGMENT_MID; i <= TIME_SEGMENT_MAX; i++)   
  20.         {  
  21.             if (div % i == 0) {  
  22.                 found = true;  
  23.                 break;  
  24.             }  
  25.         }  
  26.         if (!found) {  
  27.             for (i = TIME_SEGMENT_MID - 1;  
  28.                         i >= TIME_SEGMENT_MIN; i--) {  
  29.                 if (div % i == 0) {  
  30.                     found = true;  
  31.                     break;  
  32.                 }  
  33.             }  
  34.   
  35.         }  
  36.     }  
  37.   
  38.     if (found) {  
  39.         //time_segments数组中列出了各种br_presdiv,br_propseg,br_pseg1,br_pseg2组合值  
  40.         //根据以上推算,确定i值,从而确定br_presdiv,br_propseg,br_pseg1,br_pseg2的值  
  41.         segment = &time_segments[i - TIME_SEGMENT_MIN];  
  42.         flexcan->br_presdiv = div/i - 1;  
  43.         flexcan->br_propseg = segment->propseg;  
  44.         flexcan->br_pseg1 = segment->pseg1;  
  45.         flexcan->br_pseg2 = segment->pseg2;  
  46.         flexcan->bitrate = bitrate;  
  47.     } else {  
  48.         pr_info("The bitrate %d can't supported with clock \  
  49.                     rate of %d \n", bitrate, rate);  
  50.     }  
  51. }  

[cpp]  view plain copy
  1. static void flexcan_update_bitrate(struct flexcan_device *flexcan)  
  2. {  
  3.     int rate, div;  
  4.     //板级配置文件中设置的  
  5.     struct flexcan_platform_data *plat_data;  
  6.     plat_data = flexcan->dev->dev.platform_data;  
  7.     //如果板级配置文件中,struct flexcan_platform_data中root_clk_id配置了  
  8.     if (plat_data->root_clk_id)  
  9.         rate = clk_get_rate(flexcan->clk);  
  10.     else   
  11.     {  
  12.         //若struct flexcan_platform_data中root_clk_id未被配置,再看br_clksrc是否被配置成1    
  13.         if (flexcan->br_clksrc)  
  14.             rate = clk_get_rate(flexcan->clk);  
  15.         //在我的imx536项目中,以上两个变量都未被配置,所以会执行以下代码  
  16.         else   
  17.         {  
  18.             struct clk *clk;  
  19.             clk = clk_get(NULL, "ckih");  
  20.             if (!clk)  
  21.                 return;  
  22.             //获取can时钟频率  
  23.             rate = clk_get_rate(clk);  
  24.             clk_put(clk);  
  25.         }  
  26.     }  
  27.     if (!rate)  
  28.         return;  
  29.     //计算can传输速率  
  30.     //其中br_presdiv,br_propseg,br_pseg1,br_pseg2,这些参数都是在板级配置文件中设置的  
  31.     //所以可以实现由用户自己配置CAN波特率  
  32.     div = (flexcan->br_presdiv + 1);  
  33.     div *=  
  34.         (flexcan->br_propseg + flexcan->br_pseg1 + flexcan->br_pseg2 + 4);  
  35.     flexcan->bitrate = (rate + div - 1) / div;  
  36. }  

[cpp]  view plain copy
  1. static int flexcan_device_attach(struct flexcan_device *flexcan)  
  2. {  
  3.     int ret;  
  4.     struct resource *res;  
  5.     struct platform_device *pdev = flexcan->dev;  
  6.     struct flexcan_platform_data *plat_data = (pdev->dev).platform_data;  
  7.     struct clk *can_root_clk;  
  8.   
  9.     //看到了熟悉的身影了  
  10.     res = platform_get_resource(flexcan->dev, IORESOURCE_MEM, 0);  
  11.     if (!res)  
  12.         return -ENODEV;  
  13.     //内存映射  
  14.     flexcan->io_base = ioremap(res->start, res->end - res->start + 1);  
  15.     if (!flexcan->io_base)  
  16.         return -ENOMEM;  
  17.     //咋没直接注册中断?  
  18.     flexcan->irq = platform_get_irq(flexcan->dev, 0);  
  19.     if (!flexcan->irq) {  
  20.         ret = -ENODEV;  
  21.         goto no_irq_err;  
  22.     }  
  23.   
  24.     ret = -EINVAL;  
  25.     if (plat_data) {  
  26.         if (plat_data->core_reg) {  
  27.             flexcan->core_reg = regulator_get(&pdev->dev,  
  28.                               plat_data->core_reg);  
  29.             if (!flexcan->core_reg)  
  30.                 goto plat_err;  
  31.         }  
  32.   
  33.         if (plat_data->io_reg) {  
  34.             flexcan->io_reg = regulator_get(&pdev->dev,  
  35.                             plat_data->io_reg);  
  36.             if (!flexcan->io_reg)  
  37.                 goto plat_err;  
  38.         }  
  39.     }  
  40.     flexcan->clk = clk_get(&(flexcan->dev)->dev, "can_clk");  
  41.     //如果板级配置文件中root_clk_id被配置了,can时钟源变成了root_clk_id  
  42.     if (plat_data->root_clk_id)   
  43.     {  
  44.         can_root_clk = clk_get(NULL, plat_data->root_clk_id);  
  45.         clk_set_parent(flexcan->clk, can_root_clk);  
  46.     }  
  47.     flexcan->hwmb = (struct can_hw_mb *)(flexcan->io_base + CAN_MB_BASE);  
  48.     flexcan->rx_mask = (unsigned int *)(flexcan->io_base + CAN_RXMASK_BASE);  
  49.   
  50.     return 0;  
  51.     //以后得多学学内核纠错处理了  
  52.       plat_err:  
  53.     if (flexcan->core_reg) {  
  54.         regulator_put(flexcan->core_reg);  
  55.         flexcan->core_reg = NULL;  
  56.     }  
  57.       no_irq_err:  
  58.     if (flexcan->io_base)  
  59.         iounmap(flexcan->io_base);  
  60.     return ret;  
  61. }  

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值