CM-X270: Linux: SPI support

From Compulab Mediawiki
Jump to: navigation, search

Overview

This is an explanatory document on enabling support for SPI protocol, using 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 --->

[*] 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)

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 arch/arm/mach-pxa/cm-x270.c as a "platform device". The master configuration is passed to the driver via a table found in include/asm-arm/arch-pxa/pxa2xx_spi.h:

struct pxa2xx_spi_master {
        enum pxa_ssp_type ssp_type;
        u32 clock_enable;
        u16 num_chipselect;
        u8 enable_dma;
};

The 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 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 pxa2xx_spi_master.num_chipselect field is used to determine the number of slave devices (chips) attached to this SPI master.

The 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 resource structure:

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,
	},
};

pxa2xx_spi_master structure:

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 */
};

platform_device structure (binding the SPI to PXA's SSP):

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 */
	},
};

Initializing device structure

The 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.

struct spi_board_info - board-specific template for a SPI device:

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 */
};
  • 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 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 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 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:

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" */
	},
};

Additional information on SPI structures can be found here: 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:

spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));

Where 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:

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 */
        ...
}

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


Admolition note.png In the example above, the ds1722.c module uses GPIO as DS1722 Chip Enable and drives it accordingly to device's IO operations.

See also