|
|
(One intermediate revision by the same user not shown) |
Line 1: |
Line 1: |
− | == Overview ==
| + | #REDIRECT [[CM-X270: Linux: SPI support]] |
− | | |
− | This is an explanatory document on enabling support for SPI protocol, using {{parameter|pxa2xx-spi}} module, on Compulab's CM-x270.
| |
− | 2.6.24 kernel version and "Dallas Semiconductor Digital Thermometer DS1722" are used as an example.
| |
− | | |
− | == Enabling Kernel support for pxa2xx-spi driver ==
| |
− | | |
− | Using make menuconfig:
| |
− | | |
− | In ''Device Drivers'' ---> ''SPI support'' --->
| |
− | | |
− | <pre>
| |
− | [*] SPI support | |
− | [ ] Debug support for SPI drivers | |
− | *** SPI Master Controller Drivers ***
| |
− | <> Bitbanging SPI master
| |
− | <M> PXA2xx SSP SPI master
| |
− | *** SPI Protocol Masters ***
| |
− | <> SPI EEPROMs from most vendors
| |
− | <> User mode SPI device driver support
| |
− | <> Infineon TLE62X0 (for power switching)
| |
− | </pre>
| |
− | | |
− | It is not necessary to compile "PXA2xx SPP SPI master" as module but it is recommended at least at the development stage.
| |
− | | |
− | == Initializing the PXA's SSP and binding it to SPI ==
| |
− | | |
− | SPI master is defined in the {{filename|arch/arm/mach-pxa/cm-x270.c}} as a "platform device". The master configuration is passed to the driver via a table found in {{filename|include/asm-arm/arch-pxa/pxa2xx_spi.h}}:
| |
− | | |
− | <pre>
| |
− | struct pxa2xx_spi_master {
| |
− | enum pxa_ssp_type ssp_type;
| |
− | u32 clock_enable;
| |
− | u16 num_chipselect;
| |
− | u8 enable_dma;
| |
− | };
| |
− | </pre>
| |
− | | |
− | The {{parameter|pxa2xx_spi_master.ssp_type}} field must have a value between 1 and 3 and informs the driver which features a particular SSP supports.
| |
− | | |
− | The {{parameter|pxa2xx_spi_master.clock_enable}} field is used to enable/disable the corresponding SSP peripheral block in the "Clock Enable Register (CKEN)". See section "Clocks and Power Management" of the "PXA2xx Developer Manual" .
| |
− | | |
− | The {{parameter|pxa2xx_spi_master.num_chipselect}} field is used to determine the number of slave devices (chips) attached to this SPI master.
| |
− | | |
− | The {{parameter|pxa2xx_spi_master.enable_dma}} field informs the driver that SSP DMA should be used. This causes the driver to acquire two DMA channels: rx_channel and tx_channel.
| |
− | The rx_channel has a higher DMA service priority than the tx_channel. See section "DMA Controller" of the "PXA2xx Developer Manual".
| |
− | | |
− | Here is an example of structures initialization:
| |
− | SSP {{parameter|resource}} structure:
| |
− | | |
− | <pre>
| |
− | static struct resource pxa_ssp_resources[] = {
| |
− | [0] = { /* according to pxa270 developer manual: */
| |
− | .start = __PREG(SSCR0_P(1)), /* start address of the SSP1 register set */
| |
− | .end = __PREG(SSCR0_P(1)) + 0x40, /* range of the SSP1 register set */
| |
− | .flags = IORESOURCE_MEM,
| |
− | },
| |
− | [1] = {
| |
− | .start = IRQ_SSP,
| |
− | .end = IRQ_SSP,
| |
− | .flags = IORESOURCE_IRQ,
| |
− | },
| |
− | };
| |
− | </pre>
| |
− | | |
− | {{parameter|pxa2xx_spi_master}} structure:
| |
− | | |
− | <pre>
| |
− | static struct pxa2xx_spi_master pxa_ssp_master_info = {
| |
− | .ssp_type = PXA27x_SSP, /* Type of SSP, PXA27x_SSP included from "pxa2xx_spi.h" */
| |
− | .clock_enable = CKEN_SSP1, /* SSP Peripheral clock */
| |
− | .num_chipselect = 1, /* number of chips attached to this SSP */
| |
− | };
| |
− | </pre>
| |
− | | |
− | {{parameter|platform_device}} structure (binding the SPI to PXA's SSP):
| |
− | | |
− | <pre>
| |
− | static struct platform_device pxa_ssp = {
| |
− | .name = "pxa2xx-spi", /* MUST BE THIS VALUE, so device match driver */
| |
− | .id = 1, /* Bus number, MUST MATCH SSP number 1..n */
| |
− | .resource = pxa_ssp_resources, /* The struct resource declared above */
| |
− | .num_resources = ARRAY_SIZE(pxa_ssp_resources),
| |
− | .dev = {
| |
− | .platform_data = &pxa_ssp_master_info, /* struct pxa2xx_spi_master declared above */
| |
− | },
| |
− | };
| |
− | </pre>
| |
− | | |
− | == Initializing device structure ==
| |
− | | |
− | The {{parameter|struct spi_board_info}} structure serves as an interface between board initialization 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 initialization code provides a table listing the devices which are present, with enough
| |
− | information to bind and set up the device's driver.
| |
− | | |
− | {{parameter|struct spi_board_info}} - board-specific template for a SPI device:
| |
− | | |
− | <pre>
| |
− | struct spi_board_info {
| |
− | /* the device name and module name are coupled, like platform_bus; */
| |
− | char modalias[KOBJ_NAME_LEN]; /* "modalias" is normally the driver name. */
| |
− | const void *platform_data; /* platform_data goes to spi_device.dev.platform_data, */
| |
− | void *controller_data; /* controller_data goes to spi_device.controller_data, */
| |
− | int irq; /* irq is copied too */
| |
− | u32 max_speed_hz; /* slower signaling on noisy or low voltage boards */
| |
− | u16 bus_num; /* bus_num matches the bus_num of spi_master */
| |
− | u16 chip_select; /* chip_select reflects how this chip is wired to the master */
| |
− | u8 mode; /* mode becomes spi_device.mode */
| |
− | };
| |
− | </pre>
| |
− | | |
− | * {{parameter|modalias}} - Initializes {{parameter|spi_device.modalias}}; identifies the driver
| |
− | * {{parameter|platform_data}} - Initializes {{parameter|spi_device.platform_data}}; the particular data stored there is driver-specific.
| |
− | * {{parameter|controller_data}} - Initializes {{parameter|spi_device.controller_data}}; some controllers need hints about hardware setup, e.g. for DMA.
| |
− | * {{parameter|irq}} - Initializes {{parameter|spi_device.irq}}; depends on how the board is wired.
| |
− | * {{parameter|max_speed_hz}} - Initializes {{parameter|spi_device.max_speed_hz}}; based on limits from the chip datasheet and board-specific signal quality issues.
| |
− | * {{parameter|bus_num}} - Identifies which {{parameter|spi_master}} parents the {{parameter|spi_device}}; unused by {{parameter|spi_new_device()}}, and otherwise depends on board wiring.
| |
− | * {{parameter|chip_select}} - Initializes {{parameter|spi_device.chip_select}}; depends on how the board is wired.
| |
− | * {{parameter|mode}} - Initializes {{parameter|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 chip select 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 {{parameter|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 a typical) role is as a parameter to
| |
− | {{parameter|spi_new_device()}} call, which happens after those controller drivers are active in some dynamic board configuration models.
| |
− | | |
− | Here is the sample code for DS1722 Digital Thermometer:
| |
− | | |
− | <pre>
| |
− | static struct spi_board_info spi_board_info[] __initdata = {
| |
− | {
| |
− | .modalias = "ds1722_spi",
| |
− | /* .platform_data = &ds1722_info, */ /* Using default spi master initialization */
| |
− | /* .controller_data = &ds1722_hw, */ /* Using default spi master initialization */
| |
− | /* .irq = DS1722_IRQ, */ /* Using default spi master initialization */
| |
− | .max_speed_hz = 5000,
| |
− | .bus_num = 1,
| |
− | .chip_select = 0,
| |
− | .mode = SPI_MODE_1, /* Included from "spi.h" */
| |
− | },
| |
− | };
| |
− | </pre>
| |
− | | |
− | Additional information on SPI structures can be found here: [http://www.kernel-api.org/docs/online/2.6.17/da/dfa/linux_2spi_2spi_8h-source.html include/linux/spi/spi.h].
| |
− | | |
− | == Register the device structure with the SPI ==
| |
− | | |
− | The next thing is to register the device with the SPI.
| |
− | Add the following line to the board initialization proccess:
| |
− | | |
− | <pre>
| |
− | spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
| |
− | </pre>
| |
− | | |
− | Where {{parameter|spi_board_info}} is the structure discussed above.
| |
− | Also, it is recommended to check the return value, at least at the development stage.
| |
− | Here is the sample code for DS1722 Digital Thermometer:
| |
− | | |
− | <pre>
| |
− | static void __init cmx270_init(void)
| |
− | {
| |
− | int ret = 0;
| |
− | ...
| |
− | /* register spi thermometer */
| |
− | ret = spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
| |
− | printk(KERN_INFO "%s: spi_register_board_info = %d\n", __FUNCTION__, ret);
| |
− | /* spi thermometer registered */
| |
− | ...
| |
− | }
| |
− | </pre>
| |
− | | |
− | == Supply the device driver module ==
| |
− | | |
− | For the specific device to work properly, you are required to supply its device driver. The device driver may provide some APIs to abstract (standardize) the communication with the device for applications, or it can do something with the device by itself.
| |
− | Here is the sample code for DS1722 Digital Thermometer, it does not provide any API, just does some in/out operations and prints the results: '''[[ds1722.c]]'''
| |
− | | |
− | {{Note|In the example above, the {{filename|ds1722.c}} module uses GPIO as DS1722 Chip Enable and drives it accordingly to device's IO operations.}}
| |