drivers/spi/spi_test.c 这个文件可以细看,是详细分析spi驱动的好文件。
/
static void __init smdk6410_machine_init(void)
{
spi_register_board_info(sam_spi_devs, ARRAY_SIZE(sam_spi_devs));
platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));
}
/
第12章:和platform_driver对应这一个platform_device一样,spi_driver也对应着一个spi_device;platform_device需要在BSP的板文件中添加板信息数据,而spi_device也同样需要。spi_device的板信息用spi_board_info结构体描述,该结构记录着spi外设使用的主机控制器(spi_master)序号,片选序号,数据比特率,spi传输模式(CPOL,CPHA)
static struct spi_board_info __initdata sam_spi_devs[] = {
[0] = {
设备与驱动匹配的唯一标识
.modalias = “spidev”, /* Test Interface /
.mode = SPI_MODE_2, / CPOL=1, CPHA=0 /
.max_speed_hz = 2468013,
/ Connected to SPI-0 as 1st Slave */
.bus_num = 0,
.irq = IRQ_SPI0,
.chip_select = 0,
// .controller_data = (void *)&spidev_b0_cs0,
},
};
/
/---------------------------------------------------------------------------/
/*
- INTERFACE between board init code and SPI infrastructure.
- No SPI driver ever sees these SPI device table segments, but
- it’s how the SPI core (or adapters that get hotplugged) grows
- the driver model tree.
- As a rule, SPI devices can’t be probed. Instead, board init code
- provides a table listing the devices which are present, with enough
- information to bind and set up the device’s driver. There’s basic
- support for nonstatic configurations too; enough to handle adding
- parport adapters, or microcontrollers acting as USB-to-SPI bridges.
*/
/**
-
struct spi_board_info - board-specific template for a SPI device
-
@modalias: Initializes spi_device.modalias; identifies the driver.
-
@platform_data: Initializes spi_device.platform_data; the particular
-
data stored there is driver-specific.
-
@controller_data: Initializes spi_device.controller_data; some
-
controllers need hints about hardware setup, e.g. for DMA.
-
@irq: Initializes spi_device.irq; depends on how the board is wired.
-
@max_speed_hz: Initializes spi_device.max_speed_hz; based on limits
-
from the chip datasheet and board-specific signal quality issues.
-
@bus_num: Identifies which spi_master parents the spi_device; unused
-
by spi_new_device(), and otherwise depends on board wiring.
-
@chip_select: Initializes spi_device.chip_select; depends on how
-
the board is wired.
-
@mode: Initializes spi_device.mode; based on the chip datasheet, board
-
wiring (some devices support both 3WIRE and standard modes), and
-
possibly presence of an inverter in the chipselect path.
-
When adding new SPI devices to the device tree, these structures serve
-
as a partial device template. They hold information which can’t always
-
be determined by drivers. Information that probe() can establish (such
-
as the default transfer wordsize) is not included here.
-
These structures are used in two places. Their primary role is to
-
be stored in tables of board-specific device descriptors, which are
-
declared early in board initialization and then used (much later) to
-
populate a controller’s device tree after the that controller’s driver
-
initializes. A secondary (and atypical) role is as a parameter to
-
spi_new_device() call, which happens after those controller drivers
-
are active in some dynamic board configuration models.
/
struct spi_board_info {
/ the device name and module name are coupled, like platform_bus;- “modalias” is normally the driver name.
- platform_data goes to spi_device.dev.platform_data,
- controller_data goes to spi_device.controller_data,
- irq is copied too
*/
设备与驱动匹配的唯一标识
char modalias[32];
const void *platform_data;
void *controller_data;
int irq;
/* slower signaling on noisy or low voltage boards */
u32 max_speed_hz;/* bus_num is board specific and matches the bus_num of some
- spi_master that will probably be registered later.
- chip_select reflects how this chip is wired to that master;
- it’s less than num_chipselect.
*/
// //设备所归属的总线编号
u16 bus_num;
u16 chip_select;
/* mode becomes spi_device.mode, and is essential for chips
- where the default of SPI_CS_HIGH = 0 is wrong.
*/
u8 mode;
/* … may need additional spi_device chip config data here.
- avoid stuff protocol drivers can set; but include stuff
- needed to behave without being bound to a driver:
-
- quirks like clock rate mattering when not selected
*/
};
/
- quirks like clock rate mattering when not selected
static struct platform_device *smdk6410_devices[] __initdata = {
&s3c_device_i2c0,
&s3c_device_spi0,
&s3c_device_spi1,
&s3c_device_keypad,
&s3c_device_ts,
&s3c_device_dm9000_cs1,
&s3c_device_nand,
&s3c_device_usb,
};
/
/* SPI (0) */
static struct resource s3c_spi0_resource[] = {
[0] = {
.start = S3C_PA_SPI0,
.end = S3C_PA_SPI0 + S3C_SZ_SPI0 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_SPI0,
.end = IRQ_SPI0,
.flags = IORESOURCE_IRQ,
}
};
static u64 s3c_device_spi0_dmamask = 0xffffffffUL;
struct platform_device s3c_device_spi0 = {
.name = “sam-spi”,
.id = 0,
.num_resources = ARRAY_SIZE(s3c_spi0_resource),
.resource = s3c_spi0_resource,
.dev = {
.dma_mask = &s3c_device_spi0_dmamask,
.coherent_dma_mask = 0xffffffffUL
}
};
EXPORT_SYMBOL(s3c_device_spi0);
/* SPI (1) */
static struct resource s3c_spi1_resource[] = {
[0] = {
.start = S3C_PA_SPI1,
.end = S3C_PA_SPI1 + S3C_SZ_SPI1 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_SPI1,
.end = IRQ_SPI1,
.flags = IORESOURCE_IRQ,
}
};
static u64 s3c_device_spi1_dmamask = 0xffffffffUL;
struct platform_device s3c_device_spi1 = {
.name = “sam-spi”,
.id = 1,
.num_resources = ARRAY_SIZE(s3c_spi1_resource),
.resource = s3c_spi1_resource,
.dev = {
.dma_mask = &s3c_device_spi1_dmamask,
.coherent_dma_mask = 0xffffffffUL
}
};
/
#define S3C_PA_SPI S3C64XX_PA_SPI
#define S3C_PA_SPI0 S3C64XX_PA_SPI0
#define S3C_PA_SPI1 S3C64XX_PA_SPI1
#define S3C_SZ_SPI S3C64XX_SZ_SPI
#define S3C_SZ_SPI0 S3C64XX_SZ_SPI0
#define S3C_SZ_SPI1 S3C64XX_SZ_SPI1
图片
/* SPI */
#define S3C64XX_PA_SPI (0x7F00B000)
#define S3C64XX_PA_SPI0 (0x7F00B000)
#define S3C64XX_PA_SPI1 (0x7F00C000)
#define S3C64XX_SZ_SPI SZ_8K
#define S3C64XX_SZ_SPI0 SZ_4K
#define S3C64XX_SZ_SPI1 SZ_4K
/