linux spi 设备驱动简析 一(基于s5pv210)
2013-11-27 22:49
447 查看
一:相关结体
二:spi控制器
spi0
spi0控制器信息,平台数据
设置gpio为spi口的函数,在平台驱动中调用
s5pv210引脚图:
spi0所用到的资源
向系统里添加spi0和spi1两个控制器设备
三:spi控制器驱动
在驱动文件来,spi_s3c64xx.c中
在该驱动中,注册了平台驱动
通过driver的name匹配设备,匹配成功,调用
如下,该函数是spi驱动的核心,在该函数中,做了很多设置,因此重点分析该函数
/** * 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; }
相关文章推荐
- linux E667 同步失败
- sshuttle全局代理的实现简析
- Linux中find常见用法示例
- Linux 经典书籍 推荐
- Linux Git从零开始(以Ubuntu12.04为例)
- linux下安装配置snmp服务
- windows 与Linux 互传文件
- CentOS下安装python-mysqldb(转)
- linux安装tar.gz中的sh文件和deb文件
- linux下socket通信,server和client例子
- linux命令(二):查看磁盘硬件信息hdparm,smartctl
- linux归档压缩及软件管理
- linux线程使用读写锁共享全局变量
- Linux线程实现
- linux命令-文件管理:cat
- linux reset 分析
- 时间子系统15_获取系统时间
- linux驱动内核学习
- linux fg bg ctrl + z jobs & 等命令
- CentOS VI常用命令