当SOC里的spi控制器不稳定,或者spi控制器不够用时,可以基于GPIO口扩展出SPI控制器.
在Linux内核里已提供了相应的代码,是一个平台驱动,只需写平台设备描述相关资源即可.
make menuconfig ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
Device Drivers --->
[*] SPI support --->
<*> GPIO-based bitbanging SPI Master
驱动源码在”drivers/spi/spi-gpio.c”
static struct platform_driver spi_gpio_driver = {
.driver.name = DRIVER_NAME, //spi_gpio, 按名字匹配平台设备
.driver.owner = THIS_MODULE,
.probe = spi_gpio_probe,
.remove = __devexit_p(spi_gpio_remove),
};
module_platform_driver(spi_gpio_driver);
//通过阅读平台驱动里的probe函数可以得知平台设备需要提供的参数
static int __devinit spi_gpio_probe(struct platform_device *pdev)
{
int status;
struct spi_master *master;
struct spi_gpio *spi_gpio;
struct spi_gpio_platform_data *pdata;
u16 master_flags = 0;
pdata = pdev->dev.platform_data;
...
status = spi_gpio_request(pdata, dev_name(&pdev->dev), &master_flags);
...
master = spi_alloc_master(&pdev->dev, sizeof *spi_gpio);
...
spi_gpio = spi_master_get_devdata(master);
platform_set_drvdata(pdev, spi_gpio);
spi_gpio->pdev = pdev;
master->flags = master_flags;
master->bus_num = pdev->id;
master->num_chipselect = SPI_N_CHIPSEL;
master->setup = spi_gpio_setup;
master->cleanup = spi_gpio_cleanup;
spi_gpio->bitbang.master = spi_master_get(master);
spi_gpio->bitbang.chipselect = spi_gpio_chipselect;
...
spi_gpio->bitbang.setup_transfer = spi_bitbang_setup_transfer;
status = spi_bitbang_start(&spi_gpio->bitbang);
...
return status;
}
平台数据所用的类型
"include/linux/spi/spi_gpio.h"
struct spi_gpio_platform_data {
unsigned sck; // SCL所用的IO口
unsigned mosi; // MOSI用的IO口
unsigned miso; // MISO用的IO口
u16 num_chipselect; //支持多少个spi设备
};
///////////////////////////////////
例如把 PA7, PA8, PA9分别作为SPI控制器的SCL, MOSI, MISO
myspi_pdev.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spi/spi_gpio.h>
#include <mach/gpio.h>
struct spi_gpio_platform_data pdata = {
GPIOA(7), GPIOA(8), GPIOA(9), 2
};
struct platform_device myspi_pdev = {
.name = "spi_gpio", //与平台驱动名一致
.id = 3, //控制器的编号3
.dev = {
.platform_data = &pdata,
},
};
module_driver(myspi_pdev, platform_device_register, platform_device_unregister);
MODULE_LICENSE("GPL");
///////////////////////////
加载模块后,在/sys/bus/platform/drivers/spi_gpio目录下是否有spi_gpio.3平台设备与之匹配