您的位置:首页 > 运维架构 > Linux

linux spi 设备驱动简析 一(基于s5pv210)

2013-11-27 22:49 447 查看
一:相关结体

/**
* struct s3c64xx_spi_csinfo - ChipSelect description
* @fb_delay: Slave specific feedback delay.
*            Refer to FB_CLK_SEL register definition in SPI chapter.
* @line: Custom 'identity' of the CS line.
* @set_level: CS line control.
*
* This is per SPI-Slave Chipselect information.
* Allocate and initialize one in machine init code and make the
* spi_board_info.controller_data point to it.
*/
struct s3c64xx_spi_csinfo {
u8 fb_delay;
unsigned line;
void (*set_level)(unsigned line_id, int lvl);
};


/**
* struct s3c64xx_spi_info - SPI Controller defining structure
* @src_clk_nr: Clock source index for the CLK_CFG[SPI_CLKSEL] field.
* @src_clk_name: Platform name of the corresponding clock.
* @num_cs: Number of CS this controller emulates.
* @cfg_gpio: Configure pins for this SPI controller.
* @fifo_lvl_mask: All tx fifo_lvl fields start at offset-6
* @rx_lvl_offset: Depends on tx fifo_lvl field and bus number
* @high_speed: If the controller supports HIGH_SPEED_EN bit
*/
struct s3c64xx_spi_info {
int src_clk_nr;
char *src_clk_name;

int num_cs;

int (*cfg_gpio)(struct platform_device *pdev);

/* Following two fields are for future compatibility */
int fifo_lvl_mask;
int rx_lvl_offset;
int high_speed;
};
/**
* struct spi_device - Master side proxy for an SPI slave device
* @dev: Driver model representation of the device.
* @master: SPI controller used with the device.
* @max_speed_hz: Maximum clock rate to be used with this chip
*    (on this board); may be changed by the device's driver.
*    The spi_transfer.speed_hz can override this for each transfer.
* @chip_select: Chipselect, distinguishing chips handled by @master.
* @mode: The spi mode defines how data is clocked out and in.
*    This may be changed by the device's driver.
*    The "active low" default for chipselect mode can be overridden
*    (by specifying SPI_CS_HIGH) as can the "MSB first" default for
*    each word in a transfer (by specifying SPI_LSB_FIRST).
* @bits_per_word: Data transfers involve one or more words; word sizes
*    like eight or 12 bits are common.  In-memory wordsizes are
*    powers of two bytes (e.g. 20 bit samples use 32 bits).
*    This may be changed by the device's driver, or left at the
*    default (0) indicating protocol words are eight bit bytes.
*    The spi_transfer.bits_per_word can override this for each transfer.
* @irq: Negative, or the number passed to request_irq() to receive
*    interrupts from this device.
* @controller_state: Controller's runtime state
* @controller_data: Board-specific definitions for controller, such as
*    FIFO initialization parameters; from board_info.controller_data
* @modalias: Name of the driver to use with this device, or an alias
*    for that name.  This appears in the sysfs "modalias" attribute
*    for driver coldplugging, and in uevents used for hotplugging
*
* A @spi_device is used to interchange data between an SPI slave
* (usually a discrete chip) and CPU memory.
*
* In @dev, the platform_data is used to hold information about this
* device that's meaningful to the device's protocol driver, but not
* to its controller.  One example might be an identifier for a chip
* variant with slightly different functionality; another might be
* information about how this particular board wires the chip's pins.
*/struct spi_device {
struct device		dev;
struct spi_master	*master;
u32			max_speed_hz;
u8			chip_select;
u8			mode;
#define	SPI_CPHA	0x01			/* clock phase */
#define	SPI_CPOL	0x02			/* clock polarity */
#define	SPI_MODE_0	(0|0)			/* (original MicroWire) */
#define	SPI_MODE_1	(0|SPI_CPHA)
#define	SPI_MODE_2	(SPI_CPOL|0)
#define	SPI_MODE_3	(SPI_CPOL|SPI_CPHA)
#define	SPI_CS_HIGH	0x04			/* chipselect active high? */
#define	SPI_LSB_FIRST	0x08			/* per-word bits-on-wire */
#define	SPI_3WIRE	0x10			/* SI/SO signals shared */
#define	SPI_LOOP	0x20			/* loopback mode */
#define	SPI_NO_CS	0x40			/* 1 dev/bus, no chipselect */
#define	SPI_READY	0x80			/* slave pulls low to pause */
u8			bits_per_word;
int			irq;
void			*controller_state;
void			*controller_data;
char			modalias[SPI_NAME_SIZE];

/*
* likely need more hooks for more protocol options affecting how
* the controller talks to each chip, like:
*  - memory packing (12 bit samples into low bits, others zeroed)
*  - priority
*  - drop chipselect after each word
*  - chipselect delays
*  - ...
*/
};


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


/**
* struct spi_message - one multi-segment SPI transaction
* @transfers: list of transfer segments in this transaction
* @spi: SPI device to which the transaction is queued
* @is_dma_mapped: if true, the caller provided both dma and cpu virtual
*	addresses for each transfer buffer
* @complete: called to report transaction completions
* @context: the argument to complete() when it's called
* @actual_length: the total number of bytes that were transferred in all
*	successful segments
* @status: zero for success, else negative errno
* @queue: for use by whichever driver currently owns the message
* @state: for use by whichever driver currently owns the message
*
* A @spi_message is used to execute an atomic sequence of data transfers,
* each represented by a struct spi_transfer.  The sequence is "atomic"
* in the sense that no other spi_message may use that SPI bus until that
* sequence completes.  On some systems, many such sequences can execute as
* as single programmed DMA transfer.  On all systems, these messages are
* queued, and might complete after transactions to other devices.  Messages
* sent to a given spi_device are alway executed in FIFO order.
*
* The code that submits an spi_message (and its spi_transfers)
* to the lower layers is responsible for managing its memory.
* Zero-initialize every field you don't set up explicitly, to
* insulate against future API updates.  After you submit a message
* and its transfers, ignore them until its completion callback.
*/
struct spi_message {
struct list_head	transfers;

struct spi_device	*spi;

unsigned		is_dma_mapped:1;

/* REVISIT:  we might want a flag affecting the behavior of the
* last transfer ... allowing things like "read 16 bit length L"
* immediately followed by "read L bytes".  Basically imposing
* a specific message scheduling algorithm.
*
* Some controller drivers (message-at-a-time queue processing)
* could provide that as their default scheduling algorithm.  But
* others (with multi-message pipelines) could need a flag to
* tell them about such special cases.
*/

/* completion is reported through a callback */
void			(*complete)(void *context);
void			*context;
unsigned		actual_length;
int			status;

/* for optional use by whatever driver currently owns the
* spi_message ...  between calls to spi_async and then later
* complete(), that's the spi_master controller driver.
*/
struct list_head	queue;
void			*state;
};


/**
* struct spi_transfer - a read/write buffer pair
* @tx_buf: data to be written (dma-safe memory), or NULL
* @rx_buf: data to be read (dma-safe memory), or NULL
* @tx_dma: DMA address of tx_buf, if @spi_message.is_dma_mapped
* @rx_dma: DMA address of rx_buf, if @spi_message.is_dma_mapped
* @len: size of rx and tx buffers (in bytes)
* @speed_hz: Select a speed other than the device default for this
*      transfer. If 0 the default (from @spi_device) is used.
* @bits_per_word: select a bits_per_word other than the device default
*      for this transfer. If 0 the default (from @spi_device) is used.
* @cs_change: affects chipselect after this transfer completes
* @delay_usecs: microseconds to delay after this transfer before
*	(optionally) changing the chipselect status, then starting
*	the next transfer or completing this @spi_message.
* @transfer_list: transfers are sequenced through @spi_message.transfers
*
* SPI transfers always write the same number of bytes as they read.
* Protocol drivers should always provide @rx_buf and/or @tx_buf.
* In some cases, they may also want to provide DMA addresses for
* the data being transferred; that may reduce overhead, when the
* underlying driver uses dma.
*
* If the transmit buffer is null, zeroes will be shifted out
* while filling @rx_buf.  If the receive buffer is null, the data
* shifted in will be discarded.  Only "len" bytes shift out (or in).
* It's an error to try to shift out a partial word.  (For example, by
* shifting out three bytes with word size of sixteen or twenty bits;
* the former uses two bytes per word, the latter uses four bytes.)
*
* In-memory data values are always in native CPU byte order, translated
* from the wire byte order (big-endian except with SPI_LSB_FIRST).  So
* for example when bits_per_word is sixteen, buffers are 2N bytes long
* (@len = 2N) and hold N sixteen bit words in CPU byte order.
*
* When the word size of the SPI transfer is not a power-of-two multiple
* of eight bits, those in-memory words include extra bits.  In-memory
* words are always seen by protocol drivers as right-justified, so the
* undefined (rx) or unused (tx) bits are always the most significant bits.
*
* All SPI transfers start with the relevant chipselect active.  Normally
* it stays selected until after the last transfer in a message.  Drivers
* can affect the chipselect signal using cs_change.
*
* (i) If the transfer isn't the last one in the message, this flag is
* used to make the chipselect briefly go inactive in the middle of the
* message.  Toggling chipselect in this way may be needed to terminate
* a chip command, letting a single spi_message perform all of group of
* chip transactions together.
*
* (ii) When the transfer is the last one in the message, the chip may
* stay selected until the next transfer.  On multi-device SPI busses
* with nothing blocking messages going to other devices, this is just
* a performance hint; starting a message to another device deselects
* this one.  But in other cases, this can be used to ensure correctness.
* Some devices need protocol transactions to be built from a series of
* spi_message submissions, where the content of one message is determined
* by the results of previous messages and where the whole transaction
* ends when the chipselect goes intactive.
*
* The code that submits an spi_message (and its spi_transfers)
* to the lower layers is responsible for managing its memory.
* Zero-initialize every field you don't set up explicitly, to
* insulate against future API updates.  After you submit a message
* and its transfers, ignore them until its completion callback.
*/
struct spi_transfer {
/* it's ok if tx_buf == rx_buf (right?)
* for MicroWire, one buffer must be null
* buffers must work with dma_*map_single() calls, unless
*   spi_message.is_dma_mapped reports a pre-existing mapping
*/
const void	*tx_buf;
void		*rx_buf;
unsigned	len;

dma_addr_t	tx_dma;
dma_addr_t	rx_dma;

unsigned	cs_change:1;
u8		bits_per_word;
u16		delay_usecs;
u32		speed_hz;

struct list_head transfer_list;
};


/**
* 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.
* @dma_alignment: SPI controller constraint on DMA buffers alignment.
* @mode_bits: flags understood by this controller driver
* @flags: other constraints relevant to this driver
* @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.
*/
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.
*/
u16			num_chipselect;

/* some SPI controllers pose alignment requirements on DMAable
* buffers; let protocol drivers know about these requirements.
*/
u16			dma_alignment;

/* spi_device.mode flags understood by this controller driver */
u16			mode_bits;

/* other constraints relevant to this driver */
u16			flags;
#define SPI_MASTER_HALF_DUPLEX	BIT(0)		/* can't do full duplex */
#define SPI_MASTER_NO_RX	BIT(1)		/* can't do buffer read */
#define SPI_MASTER_NO_TX	BIT(2)		/* can't do buffer write */

/* Setup mode and clock, etc (spi driver may call many times).
*
* IMPORTANT:  this may be called when transfers to another
* device are active.  DO NOT UPDATE SHARED REGISTERS in ways
* which could break those transfers.
*/
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
*/
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);
};


/**
* struct spi_driver - Host side "protocol" driver
* @id_table: List of SPI devices supported by this driver
* @probe: Binds this driver to the spi device.  Drivers can verify
*	that the device is actually present, and may need to configure
*	characteristics (such as bits_per_word) which weren't needed for
*	the initial configuration done during system setup.
* @remove: Unbinds this driver from the spi device
* @shutdown: Standard shutdown callback used during system state
*	transitions such as powerdown/halt and kexec
* @suspend: Standard suspend callback used during system state transitions
* @resume: Standard resume callback used during system state transitions
* @driver: SPI device drivers should initialize the name and owner
*	field of this structure.
*
* This represents the kind of device driver that uses SPI messages to
* interact with the hardware at the other end of a SPI link.  It's called
* a "protocol" driver because it works through messages rather than talking
* directly to SPI hardware (which is what the underlying SPI controller
* driver does to pass those messages).  These protocols are defined in the
* specification for the device(s) supported by the driver.
*
* As a rule, those device protocols represent the lowest level interface
* supported by a driver, and it will support upper level interfaces too.
* Examples of such upper levels include frameworks like MTD, networking,
* MMC, RTC, filesystem character device nodes, and hardware monitoring.
*/
struct spi_driver {
const struct spi_device_id *id_table;
int			(*probe)(struct spi_device *spi);
int			(*remove)(struct spi_device *spi);
void			(*shutdown)(struct spi_device *spi);
int			(*suspend)(struct spi_device *spi, pm_message_t mesg);
int			(*resume)(struct spi_device *spi);
struct device_driver	driver;
};


/**
* struct spi_device - Master side proxy for an SPI slave device
* @dev: Driver model representation of the device.
* @master: SPI controller used with the device.
* @max_speed_hz: Maximum clock rate to be used with this chip
*	(on this board); may be changed by the device's driver.
*	The spi_transfer.speed_hz can override this for each transfer.
* @chip_select: Chipselect, distinguishing chips handled by @master.
* @mode: The spi mode defines how data is clocked out and in.
*	This may be changed by the device's driver.
*	The "active low" default for chipselect mode can be overridden
*	(by specifying SPI_CS_HIGH) as can the "MSB first" default for
*	each word in a transfer (by specifying SPI_LSB_FIRST).
* @bits_per_word: Data transfers involve one or more words; word sizes
*	like eight or 12 bits are common.  In-memory wordsizes are
*	powers of two bytes (e.g. 20 bit samples use 32 bits).
*	This may be changed by the device's driver, or left at the
*	default (0) indicating protocol words are eight bit bytes.
*	The spi_transfer.bits_per_word can override this for each transfer.
* @irq: Negative, or the number passed to request_irq() to receive
*	interrupts from this device.
* @controller_state: Controller's runtime state
* @controller_data: Board-specific definitions for controller, such as
*	FIFO initialization parameters; from board_info.controller_data
* @modalias: Name of the driver to use with this device, or an alias
*	for that name.  This appears in the sysfs "modalias" attribute
*	for driver coldplugging, and in uevents used for hotplugging
*
* A @spi_device is used to interchange data between an SPI slave
* (usually a discrete chip) and CPU memory.
*
* In @dev, the platform_data is used to hold information about this
* device that's meaningful to the device's protocol driver, but not
* to its controller.  One example might be an identifier for a chip
* variant with slightly different functionality; another might be
* information about how this particular board wires the chip's pins.
*/
struct spi_device {
struct device		dev;
struct spi_master	*master;
u32			max_speed_hz;
u8			chip_select;
u8			mode;
#define	SPI_CPHA	0x01			/* clock phase */
#define	SPI_CPOL	0x02			/* clock polarity */
#define	SPI_MODE_0	(0|0)			/* (original MicroWire) */
#define	SPI_MODE_1	(0|SPI_CPHA)
#define	SPI_MODE_2	(SPI_CPOL|0)
#define	SPI_MODE_3	(SPI_CPOL|SPI_CPHA)
#define	SPI_CS_HIGH	0x04			/* chipselect active high? */
#define	SPI_LSB_FIRST	0x08			/* per-word bits-on-wire */
#define	SPI_3WIRE	0x10			/* SI/SO signals shared */
#define	SPI_LOOP	0x20			/* loopback mode */
#define	SPI_NO_CS	0x40			/* 1 dev/bus, no chipselect */
#define	SPI_READY	0x80			/* slave pulls low to pause */
u8			bits_per_word;
int			irq;
void			*controller_state;
void			*controller_data;
char			modalias[SPI_NAME_SIZE];

/*
* likely need more hooks for more protocol options affecting how
* the controller talks to each chip, like:
*  - memory packing (12 bit samples into low bits, others zeroed)
*  - priority
*  - drop chipselect after each word
*  - chipselect delays
*  - ...
*/
};


二:spi控制器

spi0

struct platform_device s5pv210_device_spi0 = {
.name          = "s3c64xx-spi",
.id          = 0,
.num_resources      = ARRAY_SIZE(s5pv210_spi0_resource),
.resource      = s5pv210_spi0_resource,
.dev = {
.dma_mask        = &spi_dmamask,
.coherent_dma_mask    = DMA_BIT_MASK(32),
.platform_data = &s5pv210_spi0_pdata,
},
};


spi0控制器信息,平台数据

static struct s3c64xx_spi_info s5pv210_spi0_pdata = {
.cfg_gpio = s5pv210_spi_cfg_gpio,
.fifo_lvl_mask = 0x1ff,
.rx_lvl_offset = 15,
.high_speed = 1,
};


设置gpio为spi口的函数,在平台驱动中调用

s5pv210引脚图:



static int s5pv210_spi_cfg_gpio(struct platform_device *pdev)
{
switch (pdev->id) {
case 0:
printk(KERN_DEBUG"s5pv210_spi_cfg_gpio(spi 0)\n");
s3c_gpio_cfgpin(S5PV210_GPB(0), S3C_GPIO_SFN(2));
s3c_gpio_cfgpin(S5PV210_GPB(1), S3C_GPIO_SFN(2));
s3c_gpio_cfgpin(S5PV210_GPB(2), S3C_GPIO_SFN(2));
s3c_gpio_cfgpin(S5PV210_GPB(3), S3C_GPIO_SFN(2));
s3c_gpio_setpull(S5PV210_GPB(0), S3C_GPIO_PULL_UP);
s3c_gpio_setpull(S5PV210_GPB(1), S3C_GPIO_PULL_UP);
s3c_gpio_setpull(S5PV210_GPB(2), S3C_GPIO_PULL_UP);
s3c_gpio_setpull(S5PV210_GPB(3), S3C_GPIO_PULL_UP);
break;

case 1:
printk(KERN_DEBUG"s5pv210_spi_cfg_gpio(spi 1)\n");
s3c_gpio_cfgpin(S5PV210_GPB(4), S3C_GPIO_SFN(2));
s3c_gpio_cfgpin(S5PV210_GPB(5), S3C_GPIO_SFN(2));
s3c_gpio_cfgpin(S5PV210_GPB(6), S3C_GPIO_SFN(2));
s3c_gpio_cfgpin(S5PV210_GPB(7), S3C_GPIO_SFN(2));
s3c_gpio_setpull(S5PV210_GPB(4), S3C_GPIO_PULL_UP);
s3c_gpio_setpull(S5PV210_GPB(5), S3C_GPIO_PULL_UP);
s3c_gpio_setpull(S5PV210_GPB(6), S3C_GPIO_PULL_UP);
s3c_gpio_setpull(S5PV210_GPB(7), S3C_GPIO_PULL_UP);
break;

default:
dev_err(&pdev->dev, "Invalid SPI Controller number!");
return -EINVAL;
}

return 0;
}


spi0所用到的资源

static struct resource s5pv210_spi0_resource[] = {
[0] = {
.start = S5PV210_PA_SPI0,
.end   = S5PV210_PA_SPI0 + 0x100 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = DMACH_SPI0_TX,
.end   = DMACH_SPI0_TX,
.flags = IORESOURCE_DMA,
},
[2] = {
.start = DMACH_SPI0_RX,
.end   = DMACH_SPI0_RX,
.flags = IORESOURCE_DMA,
},
[3] = {
.start = IRQ_SPI0,
.end   = IRQ_SPI0,
.flags = IORESOURCE_IRQ,
},
};
spi1与spi0类似

向系统里添加spi0和spi1两个控制器设备

static struct platform_device *smdkc110_devices[] __initdata = {
...
&s5pv210_device_spi0,
&s5pv210_device_spi1,
...
}
通过下面,设备spi0和spi1就加入到系统了,接下来就是驱动去找到他们了,然后进行一系列的设置

static void __init smdkc110_machine_init(void)
{
.     ...
platform_add_devices(smdkc110_devices, ARRAY_SIZE(smdkc110_devices));
.....
}


三:spi控制器驱动

在驱动文件来,spi_s3c64xx.c中

在该驱动中,注册了平台驱动

static int __init s3c64xx_spi_init(void)
{
printk(KERN_DEBUG"s3c64xx_spi_init\n");
return platform_driver_probe(&s3c64xx_spi_driver, s3c64xx_spi_probe);
}
static struct platform_driver s3c64xx_spi_driver = {
.driver = {
.name	= "s3c64xx-spi",
.owner = THIS_MODULE,
},
.remove = s3c64xx_spi_remove,
.suspend = s3c64xx_spi_suspend,
.resume = s3c64xx_spi_resume,
};


通过driver的name匹配设备,匹配成功,调用
s3c64xx_spi_probe

如下,该函数是spi驱动的核心,在该函数中,做了很多设置,因此重点分析该函数

static int __init s3c64xx_spi_probe(struct platform_device *pdev)
{
struct resource	*mem_res, *dmatx_res, *dmarx_res;//平台资源
struct s3c64xx_spi_driver_data *sdd;//spi私有机构体
struct s3c64xx_spi_info *sci;//私有数据
struct spi_master *master;//spi控制器实体
int ret;
/*
struct s3c64xx_spi_driver_data {
void __iomem                    *regs;
struct clk                      *clk;
struct clk                      *src_clk;
struct platform_device          *pdev;
struct spi_master               *master;
struct workqueue_struct            *workqueue;
struct s3c64xx_spi_info  *cntrlr_info;
struct spi_device               *tgl_spi;
struct work_struct              work;
struct list_head                queue;
spinlock_t                      lock;
enum dma_ch                     rx_dmach;
enum dma_ch                     tx_dmach;
unsigned long                   sfr_start;
struct completion               xfer_completion;
unsigned                        state;
unsigned                        cur_mode, cur_bpw;
unsigned                        cur_speed;
};
*/
if (pdev->id < 0) {
dev_err(&pdev->dev,
"Invalid platform device id-%d\n", pdev->id);
return -ENODEV;
}

if (pdev->dev.platform_data == NULL) {
dev_err(&pdev->dev, "platform_data missing!\n");
return -ENODEV;
}

/* Check for availability of necessary resource */
//获取平台数据
dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (dmatx_res == NULL) {
dev_err(&pdev->dev, "Unable to get SPI-Tx dma resource\n");
return -ENXIO;
}

dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (dmarx_res == NULL) {
dev_err(&pdev->dev, "Unable to get SPI-Rx dma resource\n");
return -ENXIO;
}

mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (mem_res == NULL) {
dev_err(&pdev->dev, "Unable to get SPI MEM resource\n");
return -ENXIO;
}
printk(KERN_DEBUG"mem_res->start=%x,mem_res->end=%x,mem_res->flags=%d\n",mem_res->start,mem_res->end,mem_res->flags);
master = spi_alloc_master(&pdev->dev,
sizeof(struct s3c64xx_spi_driver_data));//分配一个master,传输的主要控制者
if (master == NULL) {
dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
return -ENOMEM;
}
//将平台数据的私有数据取过来
sci = pdev->dev.platform_data;

platform_set_drvdata(pdev, master);//将master保存到平台私有数据

sdd = spi_master_get_devdata(master);//从上面分配的master中获取sdd并填充信息
sdd->master = master;
sdd->cntrlr_info = sci;
sdd->pdev = pdev;
sdd->sfr_start = mem_res->start;
sdd->tx_dmach = dmatx_res->start;
sdd->rx_dmach = dmarx_res->start;

sdd->cur_bpw = 8;

master->bus_num = pdev->id;//给master填充信息
master->setup = s3c64xx_spi_setup;
master->transfer = s3c64xx_spi_transfer;
master->num_chipselect = sci->num_cs;
master->dma_alignment = 8;
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;

if (request_mem_region(mem_res->start,
resource_size(mem_res), pdev->name) == NULL) {
dev_err(&pdev->dev, "Req mem region failed\n");
ret = -ENXIO;
goto err0;
}

sdd->regs = ioremap(mem_res->start, resource_size(mem_res));
if (sdd->regs == NULL) {
dev_err(&pdev->dev, "Unable to remap IO\n");
ret = -ENXIO;
goto err1;
}

if (sci->cfg_gpio == NULL || sci->cfg_gpio(pdev)) {
dev_err(&pdev->dev, "Unable to config gpio\n");
ret = -EBUSY;
goto err2;
}

/* Setup clocks */
sdd->clk = clk_get(&pdev->dev, "spi");
if (IS_ERR(sdd->clk)) {
dev_err(&pdev->dev, "Unable to acquire clock 'spi'\n");
ret = PTR_ERR(sdd->clk);
goto err3;
}

if (clk_enable(sdd->clk)) {
dev_err(&pdev->dev, "Couldn't enable clock 'spi'\n");
ret = -EBUSY;
goto err4;
}

sdd->src_clk = clk_get(&pdev->dev, sci->src_clk_name);
if (IS_ERR(sdd->src_clk)) {
dev_err(&pdev->dev,
"Unable to acquire clock '%s'\n", sci->src_clk_name);
ret = PTR_ERR(sdd->src_clk);
goto err5;
}

if (clk_enable(sdd->src_clk)) {
dev_err(&pdev->dev, "Couldn't enable clock '%s'\n",
sci->src_clk_name);
ret = -EBUSY;
goto err6;
}
//创建工作队列线程,用于处理spi消息的发送和接收
sdd->workqueue = create_singlethread_workqueue(
dev_name(master->dev.parent));
if (sdd->workqueue == NULL) {
dev_err(&pdev->dev, "Unable to create workqueue\n");
ret = -ENOMEM;
goto err7;
}
//硬件初始化
/* Setup Deufult Mode */
s3c64xx_spi_hwinit(sdd, pdev->id);

spin_lock_init(&sdd->lock);
init_completion(&sdd->xfer_completion);
INIT_WORK(&sdd->work, s3c64xx_spi_work);
INIT_LIST_HEAD(&sdd->queue);
//注册spimaster并扫描spi设备,如果有,就注册,使spi驱动能匹配上
if (spi_register_master(master)) {
dev_err(&pdev->dev, "cannot register SPI master\n");
ret = -EBUSY;
goto err8;
}

dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d "
"with %d Slaves attached\n",
pdev->id, master->num_chipselect);
dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n",
mem_res->end, mem_res->start,
sdd->rx_dmach, sdd->tx_dmach);

return 0;

err8:
destroy_workqueue(sdd->workqueue);
err7:
clk_disable(sdd->src_clk);
err6:
clk_put(sdd->src_clk);
err5:
clk_disable(sdd->clk);
err4:
clk_put(sdd->clk);
err3:
err2:
iounmap((void *) sdd->regs);
err1:
release_mem_region(mem_res->start, resource_size(mem_res));
err0:
platform_set_drvdata(pdev, NULL);
spi_master_put(master);

return ret;

}


master = spi_alloc_master(&pdev->dev,
sizeof(struct s3c64xx_spi_driver_data));//分配一个master,传输的主要控制者


struct spi_master *spi_alloc_master(struct device *dev, unsigned size)
{
struct spi_master	*master;

if (!dev)
return NULL;

master = kzalloc(size + sizeof *master, GFP_KERNEL);
if (!master)
return NULL;

device_initialize(&master->dev);
master->dev.class = &spi_master_class;
master->dev.parent = get_device(dev);
spi_master_set_devdata(master, &master[1]);//设置sdd为master的私有数据,为后面取出

return master;
}


if (spi_register_master(master)) {
dev_err(&pdev->dev, "cannot register SPI master\n");
ret = -EBUSY;
goto err8;
}
设置gpio口

if (sci->cfg_gpio == NULL || sci->cfg_gpio(pdev)) {
dev_err(&pdev->dev, "Unable to config gpio\n");
ret = -EBUSY;
goto err2;
}
即调用了板文件的设置gpio口

static int s5pv210_spi_cfg_gpio(struct platform_device *pdev)
{
switch (pdev->id) {
case 0:
printk(KERN_DEBUG"s5pv210_spi_cfg_gpio(spi 0)\n");
s3c_gpio_cfgpin(S5PV210_GPB(0), S3C_GPIO_SFN(2));
s3c_gpio_cfgpin(S5PV210_GPB(1), S3C_GPIO_SFN(2));
s3c_gpio_cfgpin(S5PV210_GPB(2), S3C_GPIO_SFN(2));
s3c_gpio_cfgpin(S5PV210_GPB(3), S3C_GPIO_SFN(2));
s3c_gpio_setpull(S5PV210_GPB(0), S3C_GPIO_PULL_UP);
s3c_gpio_setpull(S5PV210_GPB(1), S3C_GPIO_PULL_UP);
s3c_gpio_setpull(S5PV210_GPB(2), S3C_GPIO_PULL_UP);
s3c_gpio_setpull(S5PV210_GPB(3), S3C_GPIO_PULL_UP);
break;

case 1:
printk(KERN_DEBUG"s5pv210_spi_cfg_gpio(spi 1)\n");
s3c_gpio_cfgpin(S5PV210_GPB(4), S3C_GPIO_SFN(2));
s3c_gpio_cfgpin(S5PV210_GPB(5), S3C_GPIO_SFN(2));
s3c_gpio_cfgpin(S5PV210_GPB(6), S3C_GPIO_SFN(2));
s3c_gpio_cfgpin(S5PV210_GPB(7), S3C_GPIO_SFN(2));
s3c_gpio_setpull(S5PV210_GPB(4), S3C_GPIO_PULL_UP);
s3c_gpio_setpull(S5PV210_GPB(5), S3C_GPIO_PULL_UP);
s3c_gpio_setpull(S5PV210_GPB(6), S3C_GPIO_PULL_UP);
s3c_gpio_setpull(S5PV210_GPB(7), S3C_GPIO_PULL_UP);
break;

default:
dev_err(&pdev->dev, "Invalid SPI Controller number!");
return -EINVAL;
}

return 0;
}


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.
*/
dev_set_name(&master->dev, "spi%u", master->bus_num);
status = device_add(&master->dev);
if (status < 0)
goto done;
dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),
dynamic ? " (dynamic)" : "");

/* populate children from any spi device tables */
scan_boardinfo(master);//扫描spi设备
status = 0;
done:
return status;
}


static void scan_boardinfo(struct spi_master *master)
{
struct boardinfo	*bi;

printk(KERN_DEBUG"scan_boardinfo\n");
mutex_lock(&board_lock);
list_for_each_entry(bi, &board_list, list) {
struct spi_board_info	*chip = bi->board_info;
unsigned		n;
//如果为master锁在的控制器,就注册个spi设备,并从板文件获取设备信息
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);//注册spi设备,驱动回去匹配
}
}
mutex_unlock(&board_lock);
}


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

printk(KERN_DEBUG"spi_new_device\n");
proxy = spi_alloc_device(master);//分配spi设备
if (!proxy)
return NULL;

WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));
//将平台数据设置到刚分到的spi设备中
proxy->chip_select = chip->chip_select;
proxy->max_speed_hz = chip->max_speed_hz;
proxy->mode = chip->mode;
proxy->irq = chip->irq;
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);//将proxy添加到系统中
if (status < 0) {
spi_dev_put(proxy);
printk(KERN_DEBUG"spi new device :spi_add_device error!!!");
return NULL;
}

return proxy;
}


int spi_add_device(struct spi_device *spi)
{
static DEFINE_MUTEX(spi_add_lock);
struct device *dev = spi->master->dev.parent;
struct device *d;
int status;

/* Chipselects are numbered 0..max; validate. */
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;
}

/* Set the bus ID string */
dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->master->dev),
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);

d = bus_find_device_by_name(&spi_bus_type, NULL, dev_name(&spi->dev));
if (d != NULL) {
dev_err(dev, "chipselect %d already in use\n",
spi->chip_select);
put_device(d);
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_setup(spi);//设置控制器,在总线驱动中
if (status < 0) {
dev_err(dev, "can't %s %s, status %d\n",
"setup", dev_name(&spi->dev), 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", dev_name(&spi->dev), status);
else
dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));

done:
mutex_unlock(&spi_add_lock);
return status;
}


status = spi_setup(spi);


int spi_setup(struct spi_device *spi)
{
unsigned	bad_bits;
int		status;

/* help drivers fail *cleanly* when they need options
* that aren't supported with their current master
*/
bad_bits = spi->mode & ~spi->master->mode_bits;
if (bad_bits) {
dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
bad_bits);
return -EINVAL;
}

if (!spi->bits_per_word)
spi->bits_per_word = 8;

status = spi->master->setup(spi);//调用master的setup

dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s"
"%u bits/w, %u Hz max --> %d\n",
(int) (spi->mode & (SPI_CPOL | SPI_CPHA)),
(spi->mode & SPI_CS_HIGH) ? "cs_high, " : "",
(spi->mode & SPI_LSB_FIRST) ? "lsb, " : "",
(spi->mode & SPI_3WIRE) ? "3wire, " : "",
(spi->mode & SPI_LOOP) ? "loopback, " : "",
spi->bits_per_word, spi->max_speed_hz,
status);

return status;
}


status = spi->master->setup(spi);
master->setup = s3c64xx_spi_setup;
即:

static int s3c64xx_spi_setup(struct spi_device *spi)
{
struct s3c64xx_spi_csinfo *cs = spi->controller_data;
struct s3c64xx_spi_driver_data *sdd;
struct s3c64xx_spi_info *sci;
struct spi_message *msg;
u32 psr, speed;
unsigned long flags;
int err = 0;

printk(KERN_DEBUG"s3c64xx_spi_setup\n");
if (cs == NULL || cs->set_level == NULL) {
dev_err(&spi->dev, "No CS for SPI(%d)\n", spi->chip_select);
return -ENODEV;
}

sdd = spi_master_get_devdata(spi->master);
sci = sdd->cntrlr_info;

spin_lock_irqsave(&sdd->lock, flags);

list_for_each_entry(msg, &sdd->queue, queue) {
/* Is some mssg is already queued for this device */
if (msg->spi == spi) {
dev_err(&spi->dev,
"setup: attempt while mssg in queue!\n");
spin_unlock_irqrestore(&sdd->lock, flags);
return -EBUSY;
}
}

if (sdd->state & SUSPND) {
spin_unlock_irqrestore(&sdd->lock, flags);
dev_err(&spi->dev,
"setup: SPI-%d not active!\n", spi->master->bus_num);
return -ESHUTDOWN;
}

spin_unlock_irqrestore(&sdd->lock, flags);

if (spi->bits_per_word != 8
&& spi->bits_per_word != 16
&& spi->bits_per_word != 32) {
dev_err(&spi->dev, "setup: %dbits/wrd not supported!\n",
spi->bits_per_word);
err = -EINVAL;
goto setup_exit;
}

/* Check if we can provide the requested rate */
speed = clk_get_rate(sdd->src_clk) / 2 / (0 + 1); /* Max possible */
printk(KERN_DEBUG"speed=%d\n", speed);
printk(KERN_DEBUG"max_speed_hz=%d\n", spi->max_speed_hz);

if (spi->max_speed_hz > speed)
spi->max_speed_hz = speed;

psr = clk_get_rate(sdd->src_clk) / 2 / spi->max_speed_hz - 1;
printk(KERN_DEBUG"psr=%d\n",psr);
psr &= S3C64XX_SPI_PSR_MASK;
if (psr == S3C64XX_SPI_PSR_MASK)
psr--;

speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
printk(KERN_DEBUG"psr=%d, speed=%d\n",psr,speed);
if (spi->max_speed_hz < speed) {
if (psr+1 < S3C64XX_SPI_PSR_MASK) {
psr++;
} else {
err = -EINVAL;
printk(KERN_DEBUG"psr++ goto setup exit !error");
goto setup_exit;
}
}

speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
if (spi->max_speed_hz >= speed)
spi->max_speed_hz = speed;
else
err = -EINVAL;

setup_exit:

/* setup() returns with device de-selected */
disable_cs(sdd, spi);

return err;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: