LINUX驱动之SPI子系统之五spi_device的创建流程
来源:互联网 发布:qt编程软件 编辑:程序博客网 时间:2024/06/08 04:53
原文地址:http://fpcfjf.blog.163.com/blog/static/55469793201292593727739/
上回已经讲到了,scan_boardinfo调用spi_new_device来创建新的SPI设备,
1. struct spi_device spi_new_device(struct spi_master *master,
2. struct spi_board_info *chip)
3. {
4. struct spi_device *proxy;
5. int status;
6. proxy = spi_alloc_device(master);
7. if (!proxy)
8. return NULL;
9.
10.
11. WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));
12. /初始化spi_device的各个字段/
13. proxy->chipchip_select = chip->chip_select;
14. proxy->max_speed_hz = chip->max_speed_hz;
15. proxy->mode = chip->mode;
16. proxy->irq = chip->irq;
17. /这里获得了spi_device的名字,这个modalias也是在我们移植时在mach-smdk2440.c中的s3c2410_spi0_board中设定的/
18. strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
19. proxy->dev.platform_data = (void ) chip->platform_data;
20. proxy->controller_data = chip->controller_data;
21. proxy->controller_state = NULL;
22. /主要完成将spi_device添加到内核/
23. status = spi_add_device(proxy);
24. if (status < 0) {
25. spi_dev_put(proxy);
26. return NULL;
27. }
28.
29.
30. return proxy;
31. }
下面来看分配spi_alloc_device的函数,主要完成了分配spi_device,并初始化spi->dev的一些字段。
[cpp] view plaincopy
1. struct spi_device spi_alloc_device(struct spi_master *master)
2. {
3. struct spi_device *spi;
4. struct device *dev = master->dev.parent;
5. if (!spi_master_get(master))
6. return NULL;
7. spi = kzalloc(sizeof *spi, GFP_KERNEL);
8. if (!spi) {
9. dev_err(dev, “cannot alloc spi_device\n”);
10. spi_master_put(master);
11. return NULL;
12. }
13. spi->master = master;
14. spi->dev.parent = dev;
15. /设置总线是spi_bus_type,下面会讲到spi_device与spi_driver是怎样match上的/
16. spi->dev.bus = &spi_bus_type;
17. spi->dev.release = spidev_release;
18. device_initialize(&spi->dev);
19. return spi;
20. }
下面来看分配的这个spi_device是怎样注册进内核的:
[cpp] view plaincopy
1. int spi_add_device(struct spi_device *spi)
2. {
3. static DEFINE_MUTEX(spi_add_lock);
4. struct device *dev = spi->master->dev.parent;
5. int status;
6. /*spi_device的片选号不能大于spi控制器的片选数/
7. if (spi->chip_select >= spi->master->num_chipselect) {
8. dev_err(dev, “cs%d >= max %d\n”,
9. spi->chip_select,
10. spi->master->num_chipselect);
11. return -EINVAL;
12. }
13. /这里设置是spi_device在Linux设备驱动模型中的name,也就是图中的spi0.0,而在/dev/下设备节点的名字是proxy->modalias中的名字/
14. dev_set_name(&spi->dev, ”%s.%u”, dev_name(&spi->master->dev),
15. spi->chip_select);
16. mutex_lock(&spi_add_lock);
17. /如果总线上挂的设备已经有这个名字,则设置状态忙碌,并退出/
18. if (bus_find_device_by_name(&spi_bus_type, NULL, dev_name(&spi->dev))
19. != NULL) {
20. dev_err(dev, “chipselect %d already in use\n”,
21. spi->chip_select);
22. status = -EBUSY;
23. goto done;
24. }
25. /对spi_device的时钟等进行设置/
26. status = spi->master->setup(spi);
27. if (status < 0) {
28. dev_err(dev, “can’t %s %s, status %d\n”,
29. “setup”, dev_name(&spi->dev), status);
30. goto done;
31. }
32. /添加到内核/
33. status = device_add(&spi->dev);
34. if (status < 0)
35. dev_err(dev, “can’t %s %s, status %d\n”,
36. “add”, dev_name(&spi->dev), status);
37. else
38. dev_dbg(dev, “registered child %s\n”, dev_name(&spi->dev));
39.
40.
41. done:
42. mutex_unlock(&spi_add_lock);
43. return status;
44. }
45.
在上面的函数里调用了status = spi->master->setup(spi);大家在前边已经在s3c24xx_spi_probe看到,这个master->setup已经赋值为s3c24xx_spi_setup,所以看下面:
46. static int s3c24xx_spi_setup(struct spi_device spi)
47. {
48. 。。。。。。。。。。。。。。
49. ret = s3c24xx_spi_setupxfer(spi, NULL);
50. 。。。。。。。。。。。。。。
51. }
52.
53.
54. static int s3c24xx_spi_setupxfer(struct spi_device *spi,
55. struct spi_transfer *t)
56. {
57. struct s3c24xx_spi *hw = to_hw(spi);
58. unsigned int bpw;
59. unsigned int hz;
60. unsigned int div;
61. /设置了每字长的位数,发送速度/
62. bpw = t ? t->bits_per_word : spi->bits_per_word;
63. hz = t ? t->speed_hz : spi->max_speed_hz;
64.
65.
66. if (bpw != 8) {
67. dev_err(&spi->dev, “invalid bits-per-word (%d)\n”, bpw);
68. return -EINVAL;
69. }
70. /设置分频值/
71. div = clk_get_rate(hw->clk) / hz;
72.
73.
74. / is clk = pclk / (2 (pre+1)), or is it
75. clk = (pclk 2) / ( pre + 1) /
76.
77.
78. div /= 2;
79.
80.
81. if (div > 0)
82. div -= 1;
83.
84.
85. if (div > 255)
86. div = 255;
87.
88.
89. dev_dbg(&spi->dev, “setting pre-scaler to %d (hz %d)\n”, div, hz);
90. writeb(div, hw->regs + S3C2410_SPPRE);
91.
92.
93. spin_lock(&hw->bitbang.lock);
94. if (!hw->bitbang.busy) {
95. hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);
96. / need to ndelay for 0.5 clocktick ? /
97. }
98. spin_unlock(&hw->bitbang.lock);
99.
100.
101. return 0;
102.}
驱动通过spi_new_device调用spi_alloc_device和spi_add_device两个函数,最后通过device_add将新建立的设备注册到内核上。
今天讲了设备,明天该driver驱动了,以及驱动如何与设备勾搭上。
慢慢来,要淡定。
- LINUX驱动之SPI子系统之五spi_device的创建流程
- LINUX驱动之SPI子系统之四spi_master的注册流程
- LINUX驱动之SPI子系统之六spi_driver的注册和挂载流程
- LINUX驱动之SPI子系统之四spi_master的注册流程
- LINUX驱动之SPI子系统之三基本的调用流程
- LINUX驱动之SPI子系统之一概述
- Linux SPI 子系统驱动笔记之Linux spi设备驱动与SPI控制器驱动的匹配问题
- Linux内核驱动之spi子系统(一)spi协议
- LINUX驱动之SPI子系统之二SPI的基本数据结构2
- LINUX驱动之SPI子系统之二SPI的基本数据结构1
- Linux spi驱动框架之执行流程
- Linux spi驱动框架之执行流程
- Linux内核驱动之spi子系统(二)用户空间spi驱动
- SPI子系统分析之四:驱动模块
- SPI子系统分析之三:驱动模块
- Linux spi驱动框架之执行流程-nuc970-att7022
- linux设备模型之spi子系统
- linux设备模型之spi子系统
- OpenGL 纹理
- 在c++中,运算符和函数有什么区别?
- Java操作hbase总结
- EF 如何更新部分列
- Spring json和对象的自动转化
- LINUX驱动之SPI子系统之五spi_device的创建流程
- UE4中资源加载资源的方式
- leetcode 136. Single Number 位操作
- GUI_emWin 切换控件的焦点
- stm32滴答时钟SYStick的优先级设定方法详解
- SIGABRT的可能原因
- java项目实例图片上传
- postgresql initdb过程中大体做了什么
- [Unity 设计模式]桥接模式(BridgePattern)