可以看到,他和s3c_device_i2c0是类似的:
static struct resource s3c_spi0_resource[] = {
[0] = DEFINE_RES_MEM(S3C24XX_PA_SPI, SZ_32),
[1] = DEFINE_RES_IRQ(IRQ_SPI0),
};
struct platform_device s3c_device_spi0 = {
.name = "s3c2410-spi",
.id = 0,
.num_resources = ARRAY_SIZE(s3c_spi0_resource),
.resource = s3c_spi0_resource,
.dev = {
.dma_mask = &samsung_device_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
}
};
name为”s3c2410-spi”。
接着看spi-s3c24xx.c文件:
static struct platform_driver s3c24xx_spi_driver = {
.probe = s3c24xx_spi_probe,
.remove = s3c24xx_spi_remove,
.driver = {
.name = "s3c2410-spi",
.pm = S3C24XX_SPI_PMOPS,
},
};
module_platform_driver(s3c24xx_spi_driver);
这里名字匹配,会调用probe函数:
static int s3c24xx_spi_probe(struct platform_device *pdev)
{
/*省略......*/
master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));
if (master ==NULL) {
dev_err(&pdev->dev, "No memory for spi_master
");
return-ENOMEM;
}
hw = spi_master_get_devdata(master);
hw->master = master;
hw->pdata = pdata = dev_get_platdata(&pdev->dev);
hw->dev =&pdev->dev;
/*省略......*//* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->num_chipselect = hw->pdata->num_cs;
master->bus_num = pdata->bus_num;
master->bits_per_word_mask = SPI_BPW_MASK(8);
/* setup the state for the bitbang driver */
hw->bitbang.master = hw->master;
hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer;
hw->bitbang.chipselect = s3c24xx_spi_chipsel;
hw->bitbang.txrx_bufs = s3c24xx_spi_txrx;
hw->master->setup = s3c24xx_spi_setup;
/*省略......*/
err = devm_request_irq(&pdev->dev, hw->irq, s3c24xx_spi_irq, 0,
pdev->name, hw);
/*省略......*/
s3c24xx_spi_initialsetup(hw);
/* register our spi controller */
err = spi_bitbang_start(&hw->bitbang);
if (err) {
dev_err(&pdev->dev, "Failed to register SPI master
");
goto err_register;
}
return0;
}
这里就涉及到spi_master了,SPI控制器负责按照设定的物理信号格式在主控和spi设备之间交换数据,SPI控制器数据是如何被传输的,而不关心数据的内容。SPI通用接口层用spi_master结构来表示一个spi控制器。
probe里会对master里的各种数据和回调函数进行填充,如:
hw->bitbang.setup_transfer:计算预分频系数并写入寄存器
master->num_chipselect:控制器支持的片选数量,即能支持多少个spi设备
hw->bitbang.chipselect:对硬件的设置,禁止或使能CS信号
hw->master->setup:设置SPI模式
以及设置中断:s3c24xx_spi_irq
注意这一句:hw->bitbang.txrx_bufs = s3c24xx_spi_txrx;
也就是s3c24xx_spi_txrx函数,注意一下,这个我们待会讲。
之后主要就是调用spi_bitbang_start进行register SPI master了:
int spi_bitbang_start(struct spi_bitbang *bitbang)
{
struct spi_master *master = bitbang->master;
int ret;
if (!master ||!bitbang->chipselect)
return-EINVAL;
mutex_init(&bitbang->lock);
if (!master->mode_bits)
master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
if (master->transfer || master->transfer_one_message)
return-EINVAL;
master->prepare_transfer_hardware = spi_bitbang_prepare_hardware;
master->unprepare_transfer_hardware = spi_bitbang_unprepare_hardware;
master->transfer_one = spi_bitbang_transfer_one;
master->set_cs = spi_bitbang_set_cs;
if (!bitbang->txrx_bufs) {
bitbang->use_dma =0;
bitbang->txrx_bufs = spi_bitbang_bufs;
if (!master->setup) {
if (!bitbang->setup_transfer)
bitbang->setup_transfer =
spi_bitbang_setup_transfer;
master->setup = spi_bitbang_setup;
master->cleanup = spi_bitbang_cleanup;
}
}
/* driver may get busy before register() returns, especially
* if someone registered boardinfo for devices
*/
ret = spi_register_master(spi_master_get(master));
if (ret)
spi_master_put(master);
return0;
}
这里就是开始对master进行设置了:
master->prepare_transfer_hardware:在发起一个数据传送过程前,给控制器驱动一个机会,申请或释放某些必要的硬件资源。
master->unprepare_transfer_hardware:在发起一个数据传送过程后,清理回调函数。
master->setup:修改控制器的工作模式或参数
bitbang->setup_transfer:设置数据传输速率。
master->cleanup:SPI从设备被释放时,该回调函数会被调用,以便释放该从设备所占用的硬件资源。
等等……
这里也要注意一个:master->transfer_one = spi_bitbang_transfer_one;
这个master->transfer_one和master->transfer_one_message很像,不要搞混了。先留意一下spi_bitbang_transfer_one这个函数。
这里注意了,不要对master->transfer || master->transfer_one_message进行回调函数填充!
接着调用spi_register_master函数:
int spi_register_master(struct spi_master *master)
{
/*省略......*//* convention: dynamically assigned bus IDs count down from the max */if (master->bus_num <0) {
/* FIXME switch to an IDR based scheme, something like
* I2C now uses, so we can't run out of "dynamic" IDs
*/
master->bus_num = atomic_dec_return(&dyn_bus_id);
dynamic =1;
}
INIT_LIST_HEAD(&master->queue);
spin_lock_init(&master->queue_lock);
spin_lock_init(&master->bus_lock_spinlock);
mutex_init(&master->bus_lock_mutex);
mutex_init(&master->io_mutex);
master->bus_lock_flag =0;
init_completion(&master->xfer_completion);
if (!master->max_dma_len)
master->max_dma_len = INT_MAX;
/* register the device, then userspace will see it.
* registration fails if the bus ID is in use.
*/
dev_set_name(&master->dev, "spi%u", master->bus_num);
status = device_add(&master->dev);
if (status <0)
goto done;
dev_dbg(dev, "registered master %s%s
", dev_name(&master->dev),
dynamic ?" (dynamic)" : "");
/* If we're using a queued driver, start the queue */if (master->transfer)
dev_info(dev, "master is unqueued, this is deprecated
");
else {
status = spi_master_initialize_queue(master);
if (status) {
device_del(&master->dev);
goto done;
}
}
/* add statistics */
spin_lock_init(&master->statistics.lock);
mutex_lock(&board_lock);
list_add_tail(&master->list, &spi_master_list);
list_for_each_entry(bi, &board_list, list)
spi_match_master_to_boardinfo(master, &bi->board_info);
mutex_unlock(&board_lock);
/* Register devices from the device tree and ACPI */
of_register_spi_devices(master);
acpi_register_spi_devices(master);
done:
return status;
}
这算是一个比较关键的函数,里面:
master->bus_num,代表的是挂在哪条总线上,spi0或者spi1之类的。
接着初始化master->queue,这里,queue,队列!为什么会有队列呢?
为了解决多个不同的SPI设备共享SPI控制器而带来的访问冲突,spi_bitbang使用内核提供的工作队列(workqueue)。workqueue是Linux内核中定义的一种回调处理方式。采用这种方式需要传输数据时,不直接完成数据的传输,而是将要传输的工作分装成相应的消息(spi_message),发送给对应的workqueue,由与workqueue关联的内核守护线程(daemon)负责具体的执行。由于workqueue会将收到的消息按时间先后顺序排列,这样就是对设备的访问严格串行化,解决了冲突。
所以SPI的通信是通过消息队列机制。
接着设置名字:dev_set_name(&master->dev, “spi%u”, master->bus_num);
就是刚刚说的spi0、spi1……
然后,
if (master->transfer)
dev_info(dev, “master is unqueued, this is deprecated
”);
else {
status = spi_master_initialize_queue(master);
if (status) {
device_del(&master->dev);
goto done;
}
}