spi.c是spi子系统初始化的核心代码,由内核负责初始化
spidev.c是spi用户接口初始化的代码,编译的时候需要选择该模块
spi_sam.c是平台驱动的初始化代码,编译时需要选择spi s3c64xx模块
//
obj-
(
C
O
N
F
I
G
H
S
S
P
I
S
3
C
6410
)
+
=
s
p
i
s
a
m
.
o
o
b
j
−
(CONFIG_HS_SPI_S3C6410) += spi_sam.o obj-
(CONFIGHSSPIS3C6410)+=spisam.oobj−(CONFIG_SPI_MASTER) += spi.o
obj-$(CONFIG_SPI_SPIDEV) += spidev.o
//
<.config>
CONFIG_SPI=y
CONFIG_SPI_DEBUG=y
CONFIG_SPI_MASTER=y
CONFIG_HS_SPI_S3C6410=y
CONFIG_SPI_SPIDEV=y
//
module_init(sam_spi_init);
static int __init sam_spi_init(void)
{
dbg_printk(“%s:%s:%d\n”, FILE, func, LINE);
//在match函数匹配成功的情况下, 系统将调用相应的probe函数,此处是直接在模块初始化时直接调用probe?
return platform_driver_probe(&sam_spi_driver, samspi_probe);
}
//
//见
//struct platform_device s3c_device_spi0 = { .name = “sam-spi”,
static struct platform_driver sam_spi_driver = {
.driver = {
.name = “sam-spi”,
.owner = THIS_MODULE,
.bus = &platform_bus_type,
},
};
struct bus_type platform_bus_type = {
.name = “platform”,
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = PLATFORM_PM_OPS_PTR,
};
//
当 .name = “sam-spi”,的设备和驱动匹配到的时候会调用samspi_probe函数
static int __init samspi_probe(struct platform_device *pdev)
{
struct spi_master *master;
struct samspi_bus *sspi;
int ret = -ENODEV;
dbg_printk("%s:%s:%d ID=%d\n", __FILE__, __func__, __LINE__, pdev->id);
//分配 SPI控制器struct spi_master *master;空间
//实际申请的内存大小为一个struct master + struct samspi_bus,并用master->dev->driver_data 指向这个多出来的 struct samspi_bus 空间,用来存放 master 的中断 、寄存器等东西。
//分配struct spi_master+struct samspi_bus大小的数据,把samspi_bus设为spi_master的私有数据
master = spi_alloc_master(&pdev->dev, sizeof(struct samspi_bus)); /* Allocate contiguous SPI controller /
if (master == NULL)
return ret;
///从master中获得samspi_bus/
sspi = spi_master_get_devdata(master);
sspi->pdev = pdev;
sspi->master = master;
/ 将 Master 放入 pdev->dev->driver_data 里*/
/*设置平台的私有数据为master
platform_set_drvdata(pdev, master);
//初始化工作队列并将其与处理函数绑定
INIT_WORK(&sspi->work, samspi_work);
spin_lock_init(&sspi->lock);
INIT_LIST_HEAD(&sspi->queue);
//初始化 完成量
init_completion(&sspi->xfer_completion);
sspi->clk = clk_get(&pdev->dev, "spi");
if (IS_ERR(sspi->clk)) {
sspi->clk = NULL;
dev_err(&pdev->dev, "cannot acquire clock \n");
ret = -EBUSY;
goto lb1;
}
ret = clk_enable(sspi->clk);
if (ret) {
clk_put(sspi->clk);
sspi->clk = NULL;
dev_err(&pdev->dev, "cannot enable clock \n");
ret = -EBUSY;
goto lb2;
}
sspi->cur_mode = SPI_SLAVE; /* Start in Slave mode */
sspi->cur_bpw = 8;
sspi->max_speed = clk_get_rate(sspi->clk) / 2 / (0x0 + 1);
sspi->min_speed = clk_get_rate(sspi->clk) / 2 / (0xff + 1);
/* Get and Map Resources */
sspi->iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (sspi->iores == NULL) {
dev_err(&pdev->dev, "cannot find IO resource\n");
ret = -ENOENT;
goto lb3;
}
sspi->ioarea = request_mem_region(sspi->iores->start, sspi->iores->end - sspi->iores->start + 1, pdev->name);
if (sspi->ioarea == NULL) {
dev_err(&pdev->dev, "cannot request IO\n");
ret = -ENXIO;
goto lb4;
}
sspi->regs = ioremap(sspi->iores->start, sspi->iores->end - sspi->iores->start + 1);
if (sspi->regs == NULL) {
dev_err(&pdev->dev, "cannot map IO\n");
ret = -ENXIO;
goto lb5;
}
sspi->tx_dma_cpu = dma_alloc_coherent(&pdev->dev, SAMSPI_DMABUF_LEN, &sspi->tx_dma_phys, GFP_KERNEL | GFP_DMA);
if(sspi->tx_dma_cpu == NULL){
dev_err(&pdev->dev, "Unable to allocate TX DMA buffers\n");
ret = -ENOMEM;
goto lb6;
}
sspi->rx_dma_cpu = dma_alloc_coherent(&pdev->dev, SAMSPI_DMABUF_LEN, &sspi->rx_dma_phys, GFP_KERNEL | GFP_DMA);
if(sspi->rx_dma_cpu == NULL){
dev_err(&pdev->dev, "Unable to allocate RX DMA buffers\n");
ret = -ENOMEM;
goto lb7;
}
sspi->irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if(sspi->irqres == NULL){
dev_err(&pdev->dev, "cannot find IRQ\n");
ret = -ENOENT;
goto lb8;
}
ret = request_irq(sspi->irqres->start, samspi_interrupt, IRQF_DISABLED,
pdev->name, sspi);
if(ret){
dev_err(&pdev->dev, "cannot acquire IRQ\n");
ret = -EBUSY;
goto lb9;
}
//用于创建workqueue,只创建一个内核线程( 不管几个核)
sspi->workqueue = create_singlethread_workqueue(master->dev.parent->bus_id);
if(!sspi->workqueue){
dev_err(&pdev->dev, “cannot create workqueue\n”);
ret = -EBUSY;
goto lb10;
}
master->bus_num = pdev->id;
master->setup = samspi_setup;
master->transfer = samspi_transfer;
master->cleanup = samspi_cleanup;
master->num_chipselect = 1; /* Only 1 Slave connected on SMDK */
//register SPI master controller
//spi_register_master调用了 device_add(&master->dev);将master注册到内核中去
//spi_register_master调用了 scan_boardinfo(master)扫描spi设备信息,创建设备
//创建了一个设备名字是 .modalias = “spidev”, /* Test Interface /的设备device
//会和 static struct spi_driver spidev_spi这个driver驱动匹配。
//
//static struct spi_board_info __initdata sam_spi_devs[] = {
//.modalias = “spidev”, / Test Interface */
if(spi_register_master(master)){
dev_err(&pdev->dev, “cannot register SPI master\n”);
ret = -EBUSY;
goto lb11;
}
/* Configure GPIOs */
if(pdev->id == 0)
SETUP_SPI(sspi, 0);
else if(pdev->id == 1)
SETUP_SPI(sspi, 1);
if(s3c2410_dma_request(sspi->rx_dmach, &samspi_dma_client, NULL)){
dev_err(&pdev->dev, "cannot get RxDMA\n");
ret = -EBUSY;
goto lb12;
}
s3c2410_dma_set_buffdone_fn(sspi->rx_dmach, samspi_dma_rxcb);
s3c2410_dma_devconfig(sspi->rx_dmach, S3C2410_DMASRC_HW, 0, sspi->sfr_phyaddr + SAMSPI_SPI_RX_DATA);
s3c2410_dma_config(sspi->rx_dmach, sspi->cur_bpw/8, 0);
s3c2410_dma_setflags(sspi->rx_dmach, S3C2410_DMAF_AUTOSTART);
if(s3c2410_dma_request(sspi->tx_dmach, &samspi_dma_client, NULL)){
dev_err(&pdev->dev, "cannot get TxDMA\n");
ret = -EBUSY;
goto lb13;
}
s3c2410_dma_set_buffdone_fn(sspi->tx_dmach, samspi_dma_txcb);
s3c2410_dma_devconfig(sspi->tx_dmach, S3C2410_DMASRC_MEM, 0, sspi->sfr_phyaddr + SAMSPI_SPI_TX_DATA);
s3c2410_dma_config(sspi->tx_dmach, sspi->cur_bpw/8, 0);
s3c2410_dma_setflags(sspi->tx_dmach, S3C2410_DMAF_AUTOSTART);
/* Setup Deufult Mode */
samspi_hwinit(sspi, pdev->id);
printk("Samsung SoC SPI Driver loaded for SPI-%d\n", pdev->id);
printk("\tMax,Min-Speed [%d, %d]Hz\n", sspi->max_speed, sspi->min_speed);
printk("\tIrq=%d\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n",
sspi->irqres->start,
sspi->iores->end, sspi->iores->start,
sspi->rx_dmach, sspi->tx_dmach);
return 0;
lb13:
s3c2410_dma_free(sspi->rx_dmach, &samspi_dma_client);
lb12:
spi_unregister_master(master);
lb11:
destroy_workqueue(sspi->workqueue);
lb10:
free_irq(sspi->irqres->start, sspi);
lb9:
lb8:
dma_free_coherent(&pdev->dev, SAMSPI_DMABUF_LEN, sspi->rx_dma_cpu, sspi->rx_dma_phys);
lb7:
dma_free_coherent(&pdev->dev, SAMSPI_DMABUF_LEN, sspi->tx_dma_cpu, sspi->tx_dma_phys);
lb6:
iounmap((void *) sspi->regs);
lb5:
release_mem_region(sspi->iores->start, sspi->iores->end - sspi->iores->start + 1);
lb4:
lb3:
clk_disable(sspi->clk);
lb2:
clk_put(sspi->clk);
lb1:
platform_set_drvdata(pdev, NULL);
spi_master_put(master);
return ret;
}
//
//static int __init samspi_probe(struct platform_device *pdev)函数中调用
//初始化工作队列并将其与处理函数绑定
// INIT_WORK(&sspi->work, samspi_work);
static void samspi_work(struct work_struct *work)
{
//通过链表节点拿到包含这个链表节点的解构体的头地址
struct samspi_bus *sspi = container_of(work, struct samspi_bus, work);
unsigned long flags;
spin_lock_irqsave(&sspi->lock, flags);
while (!list_empty(&sspi->queue)) {
struct spi_message *msg;
msg = container_of(sspi->queue.next, struct spi_message, queue);
list_del_init(&msg->queue);
spin_unlock_irqrestore(&sspi->lock, flags);
handle_msg(sspi, msg);
spin_lock_irqsave(&sspi->lock, flags);
}
spin_unlock_irqrestore(&sspi->lock, flags);
}
///
static void handle_msg(struct samspi_bus *sspi, struct spi_message *msg)
{
u8 bpw;
u32 speed, val;
int status = 0;
struct spi_transfer *xfer;
struct spi_device *spi = msg->spi;
config_sspi(sspi);
dump_regs(sspi);
list_for_each_entry (xfer, &msg->transfers, transfer_list) {
if(!msg->is_dma_mapped && samspi_map_xfer(sspi, xfer)){
dev_err(&spi->dev, "Xfer: Unable to allocate DMA buffer!\n");
status = -ENOMEM;
goto out;
}
INIT_COMPLETION(sspi->xfer_completion);
/* Only BPW and Speed may change across transfers */
bpw = xfer->bits_per_word ? : spi->bits_per_word;
speed = xfer->speed_hz ? : spi->max_speed_hz;
if(sspi->cur_bpw != bpw || sspi->cur_speed != speed){
sspi->cur_bpw = bpw;
sspi->cur_speed = speed;
config_sspi(sspi);
}
/* Pending only which is to be done */
sspi->rx_done = PASS;
sspi->tx_done = PASS;
sspi->state = RUNNING;
/* Enable Interrupts */
enable_spiintr(sspi, xfer);
/* Enqueue data on DMA */
enable_spienqueue(sspi, xfer);
/* Enable DMA */
enable_spidma(sspi, xfer);
/* Enable TX/RX */
enable_spichan(sspi, xfer);
/* Slave Select */
enable_spics(sspi, xfer);
dump_regs(sspi);
status = wait_for_xfer(sspi, xfer);
/**************
* Block Here *
**************/
if(status == -ETIMEDOUT){
dev_err(&spi->dev, "Xfer: Timeout!\n");
dump_regs(sspi);
sspi->state = STOPPED;
/* DMA Disable*/
val = readl(sspi->regs + SAMSPI_MODE_CFG);
val &= ~(SPI_MODE_TXDMA_ON | SPI_MODE_RXDMA_ON);
writel(val, sspi->regs + SAMSPI_MODE_CFG);
flush_dma(sspi, xfer);
flush_spi(sspi);
if(!msg->is_dma_mapped)
samspi_unmap_xfer(sspi, xfer);
goto out;
}
if(status == -EINTR){
dev_err(&spi->dev, "Xfer: Interrupted!\n");
dump_regs(sspi);
sspi->state = STOPPED;
/* DMA Disable*/
val = readl(sspi->regs + SAMSPI_MODE_CFG);
val &= ~(SPI_MODE_TXDMA_ON | SPI_MODE_RXDMA_ON);
writel(val, sspi->regs + SAMSPI_MODE_CFG);
flush_dma(sspi, xfer);
flush_spi(sspi);
if(!msg->is_dma_mapped)
samspi_unmap_xfer(sspi, xfer);
goto out;
}
if(status == -EIO){ /* Some Xfer failed */
dev_err(&spi->dev, "Xfer: Failed!\n");
dump_regs(sspi);
sspi->state = STOPPED;
/* DMA Disable*/
val = readl(sspi->regs + SAMSPI_MODE_CFG);
val &= ~(SPI_MODE_TXDMA_ON | SPI_MODE_RXDMA_ON);
writel(val, sspi->regs + SAMSPI_MODE_CFG);
flush_dma(sspi, xfer);
flush_spi(sspi);
if(!msg->is_dma_mapped)
samspi_unmap_xfer(sspi, xfer);
goto out;
}
if(xfer->delay_usecs){
udelay(xfer->delay_usecs);
dbg_printk("xfer-delay=%u\n", xfer->delay_usecs);
}
if(xfer->cs_change && !(sspi->cur_mode & SPI_SLAVE)){
writel(readl(sspi->regs + SAMSPI_SLAVE_SEL) | SPI_SLAVE_SIG_INACT,
sspi->regs + SAMSPI_SLAVE_SEL);
dbg_printk("xfer-cs_chng=%u\n", xfer->cs_change);
}
msg->actual_length += xfer->len;
if(!msg->is_dma_mapped)
samspi_unmap_xfer(sspi, xfer);
}
out:
/* Slave Deselect */
val = readl(sspi->regs + SAMSPI_SLAVE_SEL);
val &= ~SPI_SLAVE_AUTO;
val |= SPI_SLAVE_SIG_INACT;
writel(val, sspi->regs + SAMSPI_SLAVE_SEL);
/* Disable Interrupts */
writel(0, sspi->regs + SAMSPI_SPI_INT_EN);
/* Tx/Rx Disable */
val = readl(sspi->regs + SAMSPI_CH_CFG);
val &= ~(SPI_CH_RXCH_ON | SPI_CH_TXCH_ON);
writel(val, sspi->regs + SAMSPI_CH_CFG);
/* DMA Disable*/
val = readl(sspi->regs + SAMSPI_MODE_CFG);
val &= ~(SPI_MODE_TXDMA_ON | SPI_MODE_RXDMA_ON);
writel(val, sspi->regs + SAMSPI_MODE_CFG);
msg->status = status;
//
//spidev_sync(struct spidev_data *spidev, struct spi_message *message)函数
//有一行 message->complete = spidev_complete;
//所以此处调用的是spidev_complete函数,其实spidev_complete(arg)也就是直接调用complete(arg);
//唤醒 spidev_sync函数的 wait_for_completion(&done);这行往下执行
if(msg->complete)
msg->complete(msg->context);
}
//
spidev_write函数调用----->spidev_sync_write(spidev, count);------->spidev_sync(spidev, &m);
---------->spi_async(spidev->spi, message);
-------------->
static inline int
spi_async(struct spi_device *spi, struct spi_message *message)
{
message->spi = spi;
//看看.name = "spidev"的这对设备和驱动
//在这里与.name = “sam-spi”,的一对平台设备和驱动联系起来
//module_init(spidev_init);与
// module_init(sam_spi_init);这两个模块的连接点在这行程序里体现
//struct spi_device里的master成员是什么时候赋值过去的?
//samspi_probe(struct platform_device *pdev)------>spi_register_master(master);
//---------->scan_boardinfo(master);------->spi_new_device(master, chip);--------->proxy = spi_alloc_device(master);
///在spi_alloc_device函数里有一行spi->master = master;,返回值 return spi;
/这个便是调用samspi_transfer函数了。数据的发送传输
return spi->master->transfer(spi, message);
}
//
static int samspi_transfer(struct spi_device *spi, struct spi_message *msg)
{
struct spi_master *master = spi->master;
struct samspi_bus *sspi = spi_master_get_devdata(master);
unsigned long flags;
spin_lock_irqsave(&sspi->lock, flags);
msg->actual_length = 0;
//将struct spi_message *msg通过queue链表节点成员加入sspi->queue这个链表头
list_add_tail(&msg->queue, &sspi->queue);
//调度执行一个指定workqueue中的任务。输入参数:
//@ workqueue_struct:指定的workqueue指针
//@work_struct:具体任务对象指针
//static int __init samspi_probe(struct platform_device *pdev)函数中调用
//初始化工作队列并将其与处理函数绑定
//INIT_WORK(&sspi->work, samspi_work);
//将sspi->work加入sspi->workqueue中调度运行
queue_work(sspi->workqueue, &sspi->work);
spin_unlock_irqrestore(&sspi->lock, flags);
return 0;
}
///
/**
-
spi_register_master - register SPI master controller
-
@master: initialized master, originally from spi_alloc_master()
-
Context: can sleep
-
SPI master controllers connect to their drivers using some non-SPI bus,
-
such as the platform bus. The final stage of probe() in that code
-
includes calling spi_register_master() to hook up to this SPI bus glue.
-
SPI controllers use board specific (often SOC specific) bus numbers,
-
and board-specific addressing for SPI devices combines those numbers
-
with chip select numbers. Since SPI does not directly support dynamic
-
device identification, boards need configuration tables telling which
-
chip is at which address.
-
This must be called from context that can sleep. It returns zero on
-
success, else a negative error code (dropping the master’s refcount).
-
After a successful return, the caller is responsible for calling
-
spi_unregister_master().
*/
int spi_register_master(struct spi_master *master)
{
static atomic_t dyn_bus_id = ATOMIC_INIT((1<<15) - 1);
struct device *dev = master->dev.parent;
int status = -ENODEV;
int dynamic = 0;if (!dev)
return -ENODEV;/* even if it’s just one always-selected device, there must
- be at least one chipselect
*/
if (master->num_chipselect == 0)
return -EINVAL;
/* 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;
}/* register the device, then userspace will see it.
- registration fails if the bus ID is in use.
*/
//此处有device_add 后面scan_boardinfo ----》spi_new_device------》spi_add_device
status = device_add(&master->dev);
if (status < 0)
goto done;
/* populate children from any spi device tables */
scan_boardinfo(master);
status = 0;
done:
return status;
}
- be at least one chipselect
/* FIXME someone should add support for a __setup(“spi”, …) that
- creates board info from kernel command lines
*/
static void scan_boardinfo(struct spi_master *master)
{
struct boardinfo *bi;
mutex_lock(&board_lock);
//遍历所有挂在board_list上的struct boardinfo 实例
list_for_each_entry(bi, &board_list, list) {
struct spi_board_info chip = bi->board_info;
unsigned n;
//遍历每个 boardinfo 管理的spi_board_info类型子成员,如果设备的总线号与控制器的总线号相等,则创建新设备
for (n = bi->n_board_info; n > 0; n–, chip++) {
if (chip->bus_num != master->bus_num)
continue;
/ NOTE: this relies on spi_new_device to
* issue diagnostics when given bogus inputs
*/
(void) spi_new_device(master, chip);
}
}
mutex_unlock(&board_lock);
}
//
/**
-
spi_new_device - instantiate one new SPI device
-
@master: Controller to which device is connected
-
@chip: Describes the SPI device
-
Context: can sleep
-
On typical mainboards, this is purely internal; and it’s not needed
-
after board init creates the hard-wired devices. Some development
-
platforms may not be able to use spi_register_board_info though, and
-
this is exported so that for example a USB or parport based adapter
-
driver could add devices (which it would learn about out-of-band).
-
Returns the new device, or NULL.
*/
struct spi_device *spi_new_device(struct spi_master *master,
struct spi_board_info *chip)
{
struct spi_device *proxy;
int status;/* NOTE: caller did any chip->bus_num checks necessary.
*- Also, unless we change the return value convention to use
- error-or-pointer (not NULL-or-pointer), troubleshootability
- suggests syslogged diagnostics are best here (ugh).
*/
proxy = spi_alloc_device(master);
if (!proxy)
return NULL;WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));
proxy->chip_select = chip->chip_select;
proxy->max_speed_hz = chip->max_speed_hz;
proxy->mode = chip->mode;
proxy->irq = chip->irq;
//这里获得了spi_device的名字,这个modalias也是在我们移植时
//在mach-smdk6410.c中的static struct spi_board_info __initdata sam_spi_devs[]中设定的
strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
proxy->dev.platform_data = (void *) chip->platform_data;
proxy->controller_data = chip->controller_data;
proxy->controller_state = NULL;status = spi_add_device(proxy);
if (status < 0) {
spi_dev_put(proxy);
return NULL;
}return proxy;
}
//
/**
-
spi_add_device - Add spi_device allocated with spi_alloc_device
-
@spi: spi_device to register
-
Companion function to spi_alloc_device. Devices allocated with
-
spi_alloc_device can be added onto the spi bus with this function.
-
Returns 0 on success; negative errno on failure
*/
int spi_add_device(struct spi_device *spi)
{
static DEFINE_MUTEX(spi_add_lock);
struct device *dev = spi->master->dev.parent;
int status;/* Chipselects are numbered 0…max; validate. */
//spi_device的片选号不能大于spi控制器的片选数
if (spi->chip_select >= spi->master->num_chipselect) {
dev_err(dev, “cs%d >= max %d\n”,
spi->chip_select,
spi->master->num_chipselect);
return -EINVAL;
}
//这里设置是spi_device在Linux设备驱动模型中的name,也就是图中的spi0.0,
//而在/dev/下设备节点的名字是proxy->modalias中的名字
/* Set the bus ID string */
snprintf(spi->dev.bus_id, sizeof spi->dev.bus_id,
“%s.%u”, spi->master->dev.bus_id,
spi->chip_select);
/* We need to make sure there's no other device with this
* chipselect **BEFORE** we call setup(), else we'll trash
* its configuration. Lock against concurrent add() calls.
*/
mutex_lock(&spi_add_lock);
//如果总线上挂的设备已经有这个名字,则设置状态忙碌,退出
if (bus_find_device_by_name(&spi_bus_type, NULL, spi->dev.bus_id)
!= NULL) {
dev_err(dev, “chipselect %d already in use\n”,
spi->chip_select);
status = -EBUSY;
goto done;
}
/* Drivers may modify this initial i/o setup, but will
* normally rely on the device being setup. Devices
* using SPI_CS_HIGH can't coexist well otherwise...
*/
status = spi->master->setup(spi);
if (status < 0) {
dev_err(dev, "can't %s %s, status %d\n",
"setup", spi->dev.bus_id, status);
goto done;
}
/* Device may be bound to an active driver when this returns */
//添加到内核
status = device_add(&spi->dev);
if (status < 0)
dev_err(dev, “can’t %s %s, status %d\n”,
“add”, spi->dev.bus_id, status);
else
dev_dbg(dev, “registered child %s\n”, spi->dev.bus_id);
done:
mutex_unlock(&spi_add_lock);
return status;
}
//
/**
-
spi_alloc_device - Allocate a new SPI device
-
@master: Controller to which device is connected
-
Context: can sleep
-
Allows a driver to allocate and initialize a spi_device without
-
registering it immediately. This allows a driver to directly
-
fill the spi_device with device parameters before calling
-
spi_add_device() on it.
-
Caller is responsible to call spi_add_device() on the returned
-
spi_device structure to add it to the SPI master. If the caller
-
needs to discard the spi_device without adding it, then it should
-
call spi_dev_put() on it.
-
Returns a pointer to the new device, or NULL.
*/
struct spi_device *spi_alloc_device(struct spi_master *master)
{
struct spi_device *spi;
struct device *dev = master->dev.parent;if (!spi_master_get(master))
return NULL;spi = kzalloc(sizeof *spi, GFP_KERNEL);
if (!spi) {
dev_err(dev, “cannot alloc spi_device\n”);
spi_master_put(master);
return NULL;
}spi->master = master;
//spi_device与spi_master是同一个父设备,这是在spi_new_device()–>spi_alloc_device函数中设定的,
//一般这个设备是一个物理设备
spi->dev.parent = dev;
//总线设置成spi_bus_type
spi->dev.bus = &spi_bus_type;
spi->dev.release = spidev_release;
device_initialize(&spi->dev);
return spi;
}
///
/**
-
struct spi_master - interface to SPI master controller
-
@dev: device interface to this driver
-
@bus_num: board-specific (and often SOC-specific) identifier for a
-
given SPI controller.
-
@num_chipselect: chipselects are used to distinguish individual
-
SPI slaves, and are numbered from zero to num_chipselects.
-
each slave has a chipselect signal, but it’s common that not
-
every chipselect is connected to a slave.
-
@setup: updates the device mode and clocking records used by a
-
device’s SPI controller; protocol code may call this. This
-
must fail if an unrecognized or unsupported mode is requested.
-
It’s always safe to call this unless transfers are pending on
-
the device whose settings are being modified.
-
@transfer: adds a message to the controller’s transfer queue.
-
@cleanup: frees controller-specific state
-
Each SPI master controller can communicate with one or more @spi_device
-
children. These make a small bus, sharing MOSI, MISO and SCK signals
-
but not chip select signals. Each device may be configured to use a
-
different clock rate, since those shared signals are ignored unless
-
the chip is selected.
-
The driver for an SPI controller manages access to those devices through
-
a queue of spi_message transactions, copying data between CPU memory and
-
an SPI slave device. For each such message it queues, it calls the
-
message’s completion function when the transaction completes.
*/
//SPI主控制器
struct spi_master {
驱动的设备接口
struct device dev;/* other than negative (== assign one dynamically), bus_num is fully
- board-specific. usually that simplifies to being SOC-specific.
- example: one SOC has three SPI controllers, numbered 0…2,
- and one board’s schematics might show it using SPI-2. software
- would normally use bus_num=2 for that controller.
*/
总线号
s16 bus_num;
/* chipselects will be integral to many controllers; some others
- might use board-specific GPIOs.
/
// //SPI设备的片选号
u16 num_chipselect;
更新SPI设备的模式和SPI设备的采样时钟
/ setup mode and clock, etc (spi driver may call many times) */
int (*setup)(struct spi_device *spi);
/* bidirectional bulk transfers
*-
- The transfer() method may not sleep; its main role is
- just to add the message to the queue.
-
- For now there’s no remove-from-queue operation, or
- any other request management
-
- To a given spi_device, message queueing is pure fifo
-
- The master’s main job is to process its message queue,
- selecting a chip then transferring data
-
- If there are multiple spi_device children, the i/o queue
- arbitration algorithm is unspecified (round robin, fifo,
- priority, reservations, preemption, etc)
-
- Chipselect stays active during the entire message
- (unless modified by spi_transfer.cs_change != 0).
-
- The message transfers use clock and SPI mode parameters
- previously established by setup() for this device
*/
// //添加一个消息到控制器的传输队列
//SPI的数据传输的方法
int (*transfer)(struct spi_device *spi,
struct spi_message *mesg);
/* called on release() to free memory provided by spi_master */
void (*cleanup)(struct spi_device *spi);
};