linux spi驱动开发学习(三)--…

分类: LINUX


  linux spi驱动开发学习(三)-----spi_bitbang.c详解
 
经过了前面两节的学习,现在到了这个环节了,spi驱动的完整工作过程渐渐明朗起来
  不多说废话了,直接进主题,大家共同学习,共同进步
 
首先,还是先唠叨以下,以方便接下来对bitbang机制的学习,那就是spi 的工作时序,
这里直接转载自己看到的一篇文章
  http://www.52rd.com/Blog/Detail_RD.Blog_yuwenxin_21678.html?#Flag_Comment
  这里也同时感谢楼主的分享
 

SPI时序图详解 
(2009-10-18 21:49) 
SPI接口在模式0下输出第一位数据的时刻
 
SPI接口有四种不同的数据传输时序,取决于CPOL和CPHL这两位的组合。图1
中表现了这四种时序,
  时序与CPOL、CPHL的关系也可以从图中看出。
 




图1 




CPOL是用来决定SCK时钟信号空闲时的电平,CPOL=0,空闲电平为低电平,CPOL=1时, 

空闲电平为高电平。CPHA是用来决定采样时刻的,CPHA=0
,在每个周期的第一个时钟沿采样, 

CPHA=1,在每个周期的第二个时钟沿采样。 



由于我使用的器件工作在模式0这种时序(CPOL=0,CPHA=0),所以将图1简化为图2,
  只关注模式0的时序。
 




图2 

我们来关注SCK的第一个时钟周期,在时钟的前沿采样数据(上升沿,第一个时钟沿),
 
在时钟的后沿输出数据(下降沿,第二个时钟沿)。首先来看主器件,主器件的输出口(
MOSI)输出的数据bit1,
  在时钟的前沿被从器件采样,那主器件是在何时刻输出bit1的呢?bit1
的输出时刻实际上在SCK信号有效以前,
  比 SCK的上升沿还要早半个时钟周期。bit1的输出时刻与SSEL
信号没有关系。再来看从器件,
  主器件的输入口MISO同样是在时钟的前沿采样从器件输出的bit1
的,那从器件又是在何时刻输出bit1的呢。
  从器件是在SSEL信号有效后,立即输出bit1,尽管此时SCK
信号还没有起效。关于上面的主器件
  和从器件输出bit1位的时刻,可以从图3、4中得到验证。
 




图3 

注意图3中,CS信号有效后(低电平有效,注意CS下降沿后发生的情况),故意用延时程序
  延时了一段时间,之后再向数据寄存器写入了要发送的数据,来观察主器件输出bit1
的情况(MOSI)。
  可以看出,bit1(值为1)是在SCK信号有效之前的半个时钟周期的时刻开始输出的(与
CS信号无关),
  到了SCK的第一个时钟周期的上升沿正好被从器件采样。
 




图4 

图4中,注意看CS和MISO信号。我们可以看出,CS信号有效后,从器件立刻输出了bit1
(值为1)。 



通常我们进行的spi操作都是16位的。图5
记录了第一个字节和第二个字节间的相互衔接的过程。
  第一个字节的最后一位在SCK的上升沿被采样,随后的SCK
下降沿,从器件就输出了第二个字节的第一位。
 




图5 
熟悉了spi 的工作时序,接着往下说

  注意: 

CPOL是用来决定SCK时钟信号空闲时的电平,CPOL=0,空闲电平为低电平,CPOL=1
时,空闲电平为高电平。
  CPHA是用来决定采样时刻的,
  CPHA=0,在每个周期的第一个时钟沿采样,
  CPHA=1,在每个周期的第二个时钟沿采样。


linux的SPI模型中重要的有如下几个结构体,位置include/linux/spi/spi.h 

struct spi_device {}   //Master side proxy for an SPI slave device 

struct spi_driver {}   //Host side "protocol" driver 

struct spi_master {}   //interface to SPI master controller 

struct spi_transfer{}   //a read/write buffer pair 

在这几个结构体中,我们只注意一下device结构体 


1.struct spi_device
 
2.{

3......

4. #define SPI_CPHA 0x01

5. #define SPI_CPOL 0x02

6. #define SPI_MODE_0 (0|0)

7. #define SPI_MODE_1 (0|SPI_CPHA)

8. #define SPI_MODE_2 (SPI_CPOL|0)

9. #define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)

10......

11.}
  注意如上定义的 SPI_CPHA和SPI_CPOL 
这个和一中的CPHA,以及CPOL是对应的,

  然后在次基础上定义了MODE?,到此,你是否能相像出SPI接口的数据传输过程? 

下面才是刚刚进入真正的主题
  以下是spi_bitbang结构体的定义
 



点击(此处)折叠或打开 

1.struct spi_bitbang {
 
2.     struct workqueue_struct     *workqueue;

3.     struct work_struct     work;

4.

5.     spinlock_t         lock;

6.     struct list_head     queue;

7.     u8             busy;

8.     u8             use_dma;

9.     u8             flags;        

10.

11.     struct spi_master     *master;

12.

13.    

16.     int     (*setup_transfer)(struct spi_device *spi,

17.             struct spi_transfer *t);

18.

19.     void     (*chipselect)(struct spi_device *spi, int is_on);

20. #define     BITBANG_CS_ACTIVE     1    

21. #define     BITBANG_CS_INACTIVE     0

22.

23.    

26.     int     (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t);

27.

28.    

29.     u32     (*txrx_word[4])(struct spi_device *spi,

30.             unsigned nsecs,

31.             u32 word, u8 bits);

32.};
  这里我们只对加底纹部分做以下说明:
  struct work_struct work;
  这个让我们想入菲菲--bit bang是按照workqueue队列的形式来工作的吗?
   
  worqueue这个是什么?简单地说,他就是一个队列,里面的每一个work
节点代表着一个需要调度的工作。
  具体可以百度,这个和tasklet有点相似的。以前自己有用过,经常用于中断的顶半部,
底半部机制
  既然是worqueue,那么我们可以猜想,spi是在每一个work中实现bit bang的。
  事实上确实如此,在/driver/spi/spi_bitbang.c#L267中,我们可以看到如下函数
  static void bitbang_work(struct work_struct *work){},
  在/driver/spi/spi_bitbang.c中,我们可以发现
  int spi_bitbang_start(struct spi_bitbang *bitbang);
  这里还是有必要看一下这个方法的实现过程,看他都干了些什么:
 



点击(此处)折叠或打开 

1.int spi_bitbang_start(struct spi_bitbang *bitbang)
 
2.{

3.     int     status;

4.

5.     if (!bitbang->master || !bitbang->chipselect)

6.         return -EINVAL;

7.

8.     INIT_WORK(&bitbang->work, bitbang_work);

9.     spin_lock_init(&bitbang->lock);

10.     INIT_LIST_HEAD(&bitbang->queue);

11.

12.     if (!bitbang->master->mode_bits)//此处在s3c24xx_spi_probe方法中已定义,
采用s3c24xx_spi_probe的设置

13.         bitbang->master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;

14.

15.     if (!bitbang->master->transfer)//此处在s3c24xx_spi_probe方法中没有定义
,所以使用这里设置的方法

16.         bitbang->master->transfer = spi_bitbang_transfer;
//之后发送数据的时候会用到这个接口

17.
 
18.     if (!bitbang->txrx_bufs) {//此处在s3c24xx_spi_probe方法中已定义,采用
s3c24xx_spi_probe的设置

19.         bitbang->use_dma = 0;

20.         bitbang->txrx_bufs = spi_bitbang_bufs;

21.         if (!bitbang->master->setup) {

22.             if (!bitbang->setup_transfer)

23.                 bitbang->setup_transfer =

24.                       spi_bitbang_setup_transfer;

25.             bitbang->master->setup = spi_bitbang_setup;

26.             bitbang->master->cleanup = spi_bitbang_cleanup;

27.         }

28.     } else if (!bitbang->master->setup)//此处在s3c24xx_spi_probe
方法中已定义,从这里看来bitbang->master->setup必须定义,不可遗漏

29.         return -EINVAL;

30.

31.    

32.     bitbang->busy = 0;

33.     bitbang->workqueue = create_singlethread_workqueue(

34.             dev_name(bitbang->master->dev.parent));

35.     if (bitbang->workqueue == NULL) {

36.         status = -EBUSY;

37.         goto err1;

38.     }

39.

40.    

43.     status = spi_register_master(bitbang->master);

44.     if (status < 0)

45.         goto err2;

46.

47.     return status;

48.

49. err2:

50.     destroy_workqueue(bitbang->workqueue);

51. err1:

52.     return status;

53.}

54. EXPORT_SYMBOL_GPL(spi_bitbang_start);
  看看spi_register_master的实现过程:



点击(此处)折叠或打开 

1.int spi_register_master(struct spi_master *master)
 
2.{

3.     static atomic_t         dyn_bus_id = ATOMIC_INIT((1<<15) - 1);

4.     struct device         *dev = master->dev.parent;

5.     int             status = -ENODEV;

6.     int             dynamic = 0;

7.

8.     if (!dev)

9.         return -ENODEV;

10.

11.    

14.     if (master->num_chipselect == 0)

15.         return -EINVAL;

16.

17.    

18.     if (master->bus_num < 0) {

19.        

22.         master->bus_num = atomic_dec_return(&dyn_bus_id);

23.         dynamic = 1;

24.     }

25.

26.    

29.     dev_set_name(&master->dev, "spi%u", master->bus_num);

30.     status = device_add(&master->dev);//添加设备

31.     if (status < 0)

32.         goto done;

33.     dev_dbg(dev, "registered master %s%sn", dev_name(&master->dev),

34.             dynamic ? " (dynamic)" : "");

35.

36.    

37.     scan_boardinfo(master);

38.     status = 0;

39. done:

40.     return status;

41.}

42. EXPORT_SYMBOL_GPL(spi_register_master);
  看看scan_boardinfo原型:



点击(此处)折叠或打开 

1.static void scan_boardinfo(struct spi_master *master)
 
2.{

3.     struct boardinfo     *bi;

4.

5.     mutex_lock(&board_lock);

6.     list_for_each_entry(bi, &board_list, list) {

7.         struct spi_board_info     *chip = bi->board_info;

8.         unsigned         n;

9.

10.         for (n = bi->n_board_info; n > 0; n--, chip++) {

11.             if (chip->bus_num != master->bus_num)

12.                 continue;

13.            

16.             (void) spi_new_device(master, chip);

17.         }

18.     }

19.     mutex_unlock(&board_lock);

20.}
 



点击(此处)折叠或打开 

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.

7.    

13.

14.     proxy = spi_alloc_device(master);

15.     if (!proxy)

16.         return NULL;

17.

18.     WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));

19.

20.     proxy->chip_select = chip->chip_select;

21.     proxy->max_speed_hz = chip->max_speed_hz;

22.     proxy->mode = chip->mode;

23.     proxy->irq = chip->irq;

24.     strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));

25.     proxy->dev.platform_data = (void *) chip->platform_data;

26.     proxy->controller_data = chip->controller_data;

27.     proxy->controller_state = NULL;

28.

29.     status = spi_add_device(proxy);

30.     if (status < 0) {

31.         spi_dev_put(proxy);

32.         return NULL;

33.     }

34.

35.     return proxy;

36.}

37. EXPORT_SYMBOL_GPL(spi_new_device);
 



点击(此处)折叠或打开 

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.

6.     if (!spi_master_get(master))

7.         return NULL;

8.

9.     spi = kzalloc(sizeof *spi, GFP_KERNEL);

10.     if (!spi) {

11.         dev_err(dev, "cannot alloc spi_devicen");

12.         spi_master_put(master);

13.         return NULL;

14.     }

15.

16.     spi->master = master;

17.     spi->dev.parent = dev;

18.     spi->dev.bus = &spi_bus_type;

19.     spi->dev.release = spidev_release;

20.     device_initialize(&spi->dev);

21.     return spi;

22.}

23. EXPORT_SYMBOL_GPL(spi_alloc_device);
 



点击(此处)折叠或打开 

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.

7.    

8.     if (spi->chip_select >= spi->master->num_chipselect) {

9.         dev_err(dev, "cs%d >= max %dn",

10.             spi->chip_select,

11.             spi->master->num_chipselect);

12.         return -EINVAL;

13.     }

14.

15.    

16.     dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->master->dev),

17.             spi->chip_select);

18.

19.

20.    

24.     mutex_lock(&spi_add_lock);

25.

26.     if (bus_find_device_by_name(&spi_bus_type, NULL, dev_name(&spi->dev))

27.             != NULL) {

28.         dev_err(dev, "chipselect %d already in usen",

29.                 spi->chip_select);

30.         status = -EBUSY;

31.         goto done;

32.     }

33.

34.    

38.     status = spi_setup(spi);

39.     if (status < 0) {

40.         dev_err(dev, "can't %s %s, status %dn",

41.                 "setup", dev_name(&spi->dev), status);

42.         goto done;

43.     }

44.

45.    

46.     status = device_add(&spi->dev);

47.     if (status < 0)

48.         dev_err(dev, "can't %s %s, status %dn",

49.                 "add", dev_name(&spi->dev), status);

50.     else

51.         dev_dbg(dev, "registered child %sn", dev_name(&spi->dev));

52.

53. done:

54.     mutex_unlock(&spi_add_lock);

55.     return status;

56.}

57. EXPORT_SYMBOL_GPL(spi_add_device);
 



点击(此处)折叠或打开 

1.int spi_setup(struct spi_device *spi)
 
2.{

3.     unsigned     bad_bits;

4.     int         status;

5.

6.    

9.     bad_bits = spi->mode & ~spi->master->mode_bits;

10.     if (bad_bits) {

11.         dev_dbg(&spi->dev, "setup: unsupported mode bits %xn",

12.             bad_bits);

13.         return -EINVAL;

14.     }

15.

16.     if (!spi->bits_per_word)

17.         spi->bits_per_word = 8;

18.

19.     status = spi->master->setup(spi);//这里其实调用的就是s3c24xx_spi_probe
里填充的spi->master->setup

20.

21.     dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s"

22.                 "%u bits/w, %u Hz max --> %dn",

23.             (int) (spi->mode & (SPI_CPOL | SPI_CPHA)),

24.             (spi->mode & SPI_CS_HIGH) ? "cs_high, " : "",

25.             (spi->mode & SPI_LSB_FIRST) ? "lsb, " : "",

26.             (spi->mode & SPI_3WIRE) ? "3wire, " : "",

27.             (spi->mode & SPI_LOOP) ? "loopback, " : "",

28.             spi->bits_per_word, spi->max_speed_hz,

29.             status);

30.

31.     return status;

32.}

33. EXPORT_SYMBOL_GPL(spi_setup);
 



点击(此处)折叠或打开 

1.static int s3c24xx_spi_setup(struct spi_device *spi)
 
2.{

3.     struct s3c24xx_spi_devstate *cs = spi->controller_state;

4.     struct s3c24xx_spi *hw = to_hw(spi);

5.     int ret;

6.

7.    

8.     if (!cs) {

9.         cs = kzalloc(sizeof(struct s3c24xx_spi_devstate), GFP_KERNEL);

10.         if (!cs) {

11.             dev_err(&spi->dev, "no memory for controller staten");

12.             return -ENOMEM;

13.         }

14.

15.         cs->spcon = SPCON_DEFAULT;

16.         cs->hz = -1;

17.         spi->controller_state = cs;

18.     }

19.

20.    

21.     ret = s3c24xx_spi_update_state(spi, NULL);

22.     if (ret)

23.         return ret;

24.

25.     spin_lock(&hw->bitbang.lock);

26.     if (!hw->bitbang.busy) {

27.         hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);

28.        

29.     }

30.     spin_unlock(&hw->bitbang.lock);

31.

32.     return 0;

33.}
  好了,至此spi主控制器(驱动)和板上spi设备注册完毕,以后要使用spi
来传输数据的话,只要先获得spi设备结构,然后就可以利用它来和spi驱动打交道了(
就好像你要操作一个文件,先要获取文件句柄一样,明白吧^_^)
 
具体的数据传输过程将在下一节进行,待续.....
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值