Chinaunix首页 | 论坛 | 博客
  • 博客访问: 54845
  • 博文数量: 26
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 0
  • 用 户 组: 普通用户
  • 注册时间: 2016-07-13 16:05
文章分类
文章存档

2017年(9)

2016年(17)

我的朋友

分类: LINUX

2017-01-13 11:20:32

经过了前面两节的学习,现在到了这个环节了,spi驱动的完整工作过程渐渐明朗起来
不多说废话了,直接进主题,大家共同学习,共同进步

首先,还是先唠叨以下,以方便接下来对bitbang机制的学习,那就是spi 的工作时序,这里直接转载自己看到的一篇文章
这里也同时感谢楼主的分享

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 /* clock phase 同步*/
  5. #define SPI_CPOL 0x02 /* clock polarity */
  6. #define SPI_MODE_0 (0|0) /* (original MicroWire) */
  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.     spinlock_t        lock;
  5.     struct list_head    queue;
  6.     u8            busy;
  7.     u8            use_dma;
  8.     u8            flags;        /* extra spi->mode support */

  9.     struct spi_master    *master;

  10.     /* setup_transfer() changes clock and/or wordsize to match settings
  11.      * for this transfer; zeroes restore defaults from spi_device.
  12.      */
  13.     int    (*setup_transfer)(struct spi_device *spi,
  14.             struct spi_transfer *t);

  15.     void    (*chipselect)(struct spi_device *spi, int is_on);
  16. #define    BITBANG_CS_ACTIVE    1    /* normally nCS, active low */
  17. #define    BITBANG_CS_INACTIVE    0

  18.     /* txrx_bufs() may handle dma mapping for transfers that don't
  19.      * already have one (transfer.{tx,rx}_dma is zero), or use PIO
  20.      */
  21.     int    (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t);

  22.     /* txrx_word[SPI_MODE_*]() just looks like a shift register */
  23.     u32    (*txrx_word[4])(struct spi_device *spi,
  24.             unsigned nsecs,
  25.             u32 word, u8 bits);
  26. };
这里我们只对加底纹部分做以下说明:
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.     if (!bitbang->master || !bitbang->chipselect)
  5.         return -EINVAL;

  6.     INIT_WORK(&bitbang->work, bitbang_work);
  7.     spin_lock_init(&bitbang->lock);
  8.     INIT_LIST_HEAD(&bitbang->queue);

  9.     if (!bitbang->master->mode_bits)//此处在s3c24xx_spi_probe方法中已定义,采用s3c24xx_spi_probe的设置
  10.         bitbang->master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;

  11.     if (!bitbang->master->transfer)//此处在s3c24xx_spi_probe方法中没有定义,所以使用这里设置的方法
  12.         bitbang->master->transfer = spi_bitbang_transfer;//之后发送数据的时候会用到这个接口

  13.     if (!bitbang->txrx_bufs) {//此处在s3c24xx_spi_probe方法中已定义,采用s3c24xx_spi_probe的设置
  14.         bitbang->use_dma = 0;
  15.         bitbang->txrx_bufs = spi_bitbang_bufs;
  16.         if (!bitbang->master->setup) {
  17.             if (!bitbang->setup_transfer)
  18.                 bitbang->setup_transfer =
  19.                      spi_bitbang_setup_transfer;
  20.             bitbang->master->setup = spi_bitbang_setup;
  21.             bitbang->master->cleanup = spi_bitbang_cleanup;
  22.         }
  23.     } else if (!bitbang->master->setup)//此处在s3c24xx_spi_probe方法中已定义,从这里看来bitbang->master->setup必须定义,不可遗漏
  24.         return -EINVAL;

  25.     /* this task is the only thing to touch the SPI bits */
  26.     bitbang->busy = 0;
  27.     bitbang->workqueue = create_singlethread_workqueue(
  28.             dev_name(bitbang->master->dev.parent));
  29.     if (bitbang->workqueue == NULL) {
  30.         status = -EBUSY;
  31.         goto err1;
  32.     }

  33.     /* driver may get busy before register() returns, especially
  34.      * if someone registered boardinfo for devices
  35.      */
  36.     status = spi_register_master(bitbang->master);
  37.     if (status < 0)
  38.         goto err2;

  39.     return status;

  40. err2:
  41.     destroy_workqueue(bitbang->workqueue);
  42. err1:
  43.     return status;
  44. }
  45. 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.     if (!dev)
  8.         return -ENODEV;

  9.     /* even if it's just one always-selected device, there must
  10.      * be at least one chipselect
  11.      */
  12.     if (master->num_chipselect == 0)
  13.         return -EINVAL;

  14.     /* convention: dynamically assigned bus IDs count down from the max */
  15.     if (master->bus_num < 0) {
  16.         /* FIXME switch to an IDR based scheme, something like
  17.          * I2C now uses, so we can't run out of "dynamic" IDs
  18.          */
  19.         master->bus_num = atomic_dec_return(&dyn_bus_id);
  20.         dynamic = 1;
  21.     }

  22.     /* register the device, then userspace will see it.
  23.      * registration fails if the bus ID is in use.
  24.      */
  25.     dev_set_name(&master->dev, "spi%u", master->bus_num);
  26.     status = device_add(&master->dev);//添加设备
  27.     if (status < 0)
  28.         goto done;
  29.     dev_dbg(dev, "registered master %s%sn", dev_name(&master->dev),
  30.             dynamic ? " (dynamic)" : "");

  31.     /* populate children from any spi device tables */
  32.     scan_boardinfo(master);
  33.     status = 0;
  34. done:
  35.     return status;
  36. }
  37. EXPORT_SYMBOL_GPL(spi_register_master);
看看scan_boardinfo原型:

点击(此处)折叠或打开

  1. static void scan_boardinfo(struct spi_master *master)
  2. {
  3.     struct boardinfo    *bi;

  4.     mutex_lock(&board_lock);
  5.     list_for_each_entry(bi, &board_list, list) {
  6.         struct spi_board_info    *chip = bi->board_info;
  7.         unsigned        n;

  8.         for (n = bi->n_board_info; n > 0; n--, chip++) {
  9.             if (chip->bus_num != master->bus_num)
  10.                 continue;
  11.             /* NOTE: this relies on spi_new_device to
  12.              * issue diagnostics when given bogus inputs
  13.              */
  14.             (void) spi_new_device(master, chip);
  15.         }
  16.     }
  17.     mutex_unlock(&board_lock);
  18. }

点击(此处)折叠或打开

  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.     /* NOTE: caller did any chip->bus_num checks necessary.
  7.      *
  8.      * Also, unless we change the return value convention to use
  9.      * error-or-pointer (not NULL-or-pointer), troubleshootability
  10.      * suggests syslogged diagnostics are best here (ugh).
  11.      */

  12.     proxy = spi_alloc_device(master);
  13.     if (!proxy)
  14.         return NULL;

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

  16.     proxy->chip_select = chip->chip_select;
  17.     proxy->max_speed_hz = chip->max_speed_hz;
  18.     proxy->mode = chip->mode;
  19.     proxy->irq = chip->irq;
  20.     strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
  21.     proxy->dev.platform_data = (void *) chip->platform_data;
  22.     proxy->controller_data = chip->controller_data;
  23.     proxy->controller_state = NULL;

  24.     status = spi_add_device(proxy);
  25.     if (status < 0) {
  26.         spi_dev_put(proxy);
  27.         return NULL;
  28.     }

  29.     return proxy;
  30. }
  31. 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.     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_devicen");
  10.         spi_master_put(master);
  11.         return NULL;
  12.     }

  13.     spi->master = master;
  14.     spi->dev.parent = dev;
  15.     spi->dev.bus = &spi_bus_type;
  16.     spi->dev.release = spidev_release;
  17.     device_initialize(&spi->dev);
  18.     return spi;
  19. }
  20. 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.     /* Chipselects are numbered 0..max; validate. */
  7.     if (spi->chip_select >= spi->master->num_chipselect) {
  8.         dev_err(dev, "cs%d >= max %dn",
  9.             spi->chip_select,
  10.             spi->master->num_chipselect);
  11.         return -EINVAL;
  12.     }

  13.     /* Set the bus ID string */
  14.     dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->master->dev),
  15.             spi->chip_select);


  16.     /* We need to make sure there's no other device with this
  17.      * chipselect **BEFORE** we call setup(), else we'll trash
  18.      * its configuration. Lock against concurrent add() calls.
  19.      */
  20.     mutex_lock(&spi_add_lock);

  21.     if (bus_find_device_by_name(&spi_bus_type, NULL, dev_name(&spi->dev))
  22.             != NULL) {
  23.         dev_err(dev, "chipselect %d already in usen",
  24.                 spi->chip_select);
  25.         status = -EBUSY;
  26.         goto done;
  27.     }

  28.     /* Drivers may modify this initial i/o setup, but will
  29.      * normally rely on the device being setup. Devices
  30.      * using SPI_CS_HIGH can't coexist well otherwise...
  31.      */
  32.     status = spi_setup(spi);
  33.     if (status < 0) {
  34.         dev_err(dev, "can't %s %s, status %dn",
  35.                 "setup", dev_name(&spi->dev), status);
  36.         goto done;
  37.     }

  38.     /* Device may be bound to an active driver when this returns */
  39.     status = device_add(&spi->dev);
  40.     if (status < 0)
  41.         dev_err(dev, "can't %s %s, status %dn",
  42.                 "add", dev_name(&spi->dev), status);
  43.     else
  44.         dev_dbg(dev, "registered child %sn", dev_name(&spi->dev));

  45. done:
  46.     mutex_unlock(&spi_add_lock);
  47.     return status;
  48. }
  49. EXPORT_SYMBOL_GPL(spi_add_device);

点击(此处)折叠或打开

  1. int spi_setup(struct spi_device *spi)
  2. {
  3.     unsigned    bad_bits;
  4.     int        status;

  5.     /* help drivers fail *cleanly* when they need options
  6.      * that aren't supported with their current master
  7.      */
  8.     bad_bits = spi->mode & ~spi->master->mode_bits;
  9.     if (bad_bits) {
  10.         dev_dbg(&spi->dev, "setup: unsupported mode bits %xn",
  11.             bad_bits);
  12.         return -EINVAL;
  13.     }

  14.     if (!spi->bits_per_word)
  15.         spi->bits_per_word = 8;

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

  17.     dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s"
  18.                 "%u bits/w, %u Hz max --> %dn",
  19.             (int) (spi->mode & (SPI_CPOL | SPI_CPHA)),
  20.             (spi->mode & SPI_CS_HIGH) ? "cs_high, " : "",
  21.             (spi->mode & SPI_LSB_FIRST) ? "lsb, " : "",
  22.             (spi->mode & SPI_3WIRE) ? "3wire, " : "",
  23.             (spi->mode & SPI_LOOP) ? "loopback, " : "",
  24.             spi->bits_per_word, spi->max_speed_hz,
  25.             status);

  26.     return status;
  27. }
  28. 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.     /* allocate settings on the first call */
  7.     if (!cs) {
  8.         cs = kzalloc(sizeof(struct s3c24xx_spi_devstate), GFP_KERNEL);
  9.         if (!cs) {
  10.             dev_err(&spi->dev, "no memory for controller staten");
  11.             return -ENOMEM;
  12.         }

  13.         cs->spcon = SPCON_DEFAULT;
  14.         cs->hz = -1;
  15.         spi->controller_state = cs;
  16.     }

  17.     /* initialise the state from the device */
  18.     ret = s3c24xx_spi_update_state(spi, NULL);
  19.     if (ret)
  20.         return ret;

  21.     spin_lock(&hw->bitbang.lock);
  22.     if (!hw->bitbang.busy) {
  23.         hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);
  24.         /* need to ndelay for 0.5 clocktick ? */
  25.     }
  26.     spin_unlock(&hw->bitbang.lock);

  27.     return 0;
  28. }
好了,至此spi主控制器(驱动)和板上spi设备注册完毕,以后要使用spi来传输数据的话,只要先获得spi设备结构,然后就可以利用它来和spi驱动打交道了(就好像你要操作一个文件,先要获取文件句柄一样,明白吧^_^)

具体的数据传输过程将在下一节进行,待续.....
阅读(1284) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~