分类: LINUX
经过了前面两节的学习,现在到了这个环节了,spi驱动的完整工作过程渐渐明朗起来
首先,还是先唠叨以下,以方便接下来对bitbang机制的学习,那就是spi 的工作时序,
这里直接转载自己看到的一篇文章
SPI时序图详解
(2009-10-18 21:49)
SPI接口在模式0下输出第一位数据的时刻
SPI接口有四种不同的数据传输时序,取决于CPOL和CPHL这两位的组合。图1
中表现了这四种时序,
图1
CPOL是用来决定SCK时钟信号空闲时的电平,CPOL=0,空闲电平为低电平,CPOL=1时,
空闲电平为高电平。CPHA是用来决定采样时刻的,CPHA=0
,在每个周期的第一个时钟沿采样,
CPHA=1,在每个周期的第二个时钟沿采样。
由于我使用的器件工作在模式0这种时序(CPOL=0,CPHA=0),所以将图1简化为图2,
图2
我们来关注SCK的第一个时钟周期,在时钟的前沿采样数据(上升沿,第一个时钟沿),
在时钟的后沿输出数据(下降沿,第二个时钟沿)。首先来看主器件,主器件的输出口(
MOSI)输出的数据bit1,
的输出时刻实际上在SCK信号有效以前,
信号没有关系。再来看从器件,
的,那从器件又是在何时刻输出bit1的呢。
信号还没有起效。关于上面的主器件
图3
注意图3中,CS信号有效后(低电平有效,注意CS下降沿后发生的情况),故意用延时程序
的情况(MOSI)。
CS信号无关),
图4
图4中,注意看CS和MISO信号。我们可以看出,CS信号有效后,从器件立刻输出了bit1
(值为1)。
通常我们进行的spi操作都是16位的。图5
记录了第一个字节和第二个字节间的相互衔接的过程。
下降沿,从器件就输出了第二个字节的第一位。
图5
熟悉了spi 的工作时序,接着往下说
CPOL是用来决定SCK时钟信号空闲时的电平,CPOL=0,空闲电平为低电平,CPOL=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.}
这个和一中的CPHA,以及CPOL是对应的,
下面才是刚刚进入真正的主题
点击(此处)折叠或打开
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.};
节点代表着一个需要调度的工作。
底半部机制
点击(此处)折叠或打开
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);
点击(此处)折叠或打开
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);
点击(此处)折叠或打开
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驱动打交道了(
就好像你要操作一个文件,先要获取文件句柄一样,明白吧^_^)
具体的数据传输过程将在下一节进行,待续.....