注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

LINUX驱动之SPI子系统之五spi_device的创建流程  

2012-10-25 21:37:27|  分类: LINUX内核驱动 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
 

LINUX驱动之SPI子系统之五spi_device的创建流程

上回已经讲到了,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驱动了,以及驱动如何与设备勾搭上。

慢慢来,要淡定。

  评论这张
 
阅读(4990)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017