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

来源:互联网 发布:淘宝怎么卖酒 编辑:程序博客网 时间:2024/06/08 16:14

一:相关结体


/** * 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 devicedev;struct spi_master*master;u32max_speed_hz;u8chip_select;u8mode;#defineSPI_CPHA0x01/* clock phase */#defineSPI_CPOL0x02/* clock polarity */#defineSPI_MODE_0(0|0)/* (original MicroWire) */#defineSPI_MODE_1(0|SPI_CPHA)#defineSPI_MODE_2(SPI_CPOL|0)#defineSPI_MODE_3(SPI_CPOL|SPI_CPHA)#defineSPI_CS_HIGH0x04/* chipselect active high? */#defineSPI_LSB_FIRST0x08/* per-word bits-on-wire */#defineSPI_3WIRE0x10/* SI/SO signals shared */#defineSPI_LOOP0x20/* loopback mode */#defineSPI_NO_CS0x40/* 1 dev/bus, no chipselect */#defineSPI_READY0x80/* slave pulls low to pause */u8bits_per_word;intirq;void*controller_state;void*controller_data;charmodalias[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 */charmodalias[SPI_NAME_SIZE];const void*platform_data;void*controller_data;intirq;/* slower signaling on noisy or low voltage boards */u32max_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. */u16bus_num;u16chip_select;/* mode becomes spi_device.mode, and is essential for chips * where the default of SPI_CS_HIGH = 0 is wrong. */u8mode;/* ... 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_headtransfers;struct spi_device*spi;unsignedis_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;unsignedactual_length;intstatus;/* 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_headqueue;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;unsignedlen;dma_addr_ttx_dma;dma_addr_trx_dma;unsignedcs_change:1;u8bits_per_word;u16delay_usecs;u32speed_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 devicedev;/* 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. */s16bus_num;/* chipselects will be integral to many controllers; some others * might use board-specific GPIOs. */u16num_chipselect;/* some SPI controllers pose alignment requirements on DMAable * buffers; let protocol drivers know about these requirements. */u16dma_alignment;/* spi_device.mode flags understood by this controller driver */u16mode_bits;/* other constraints relevant to this driver */u16flags;#define SPI_MASTER_HALF_DUPLEXBIT(0)/* can't do full duplex */#define SPI_MASTER_NO_RXBIT(1)/* can't do buffer read */#define SPI_MASTER_NO_TXBIT(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_driverdriver;};

/** * 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 devicedev;struct spi_master*master;u32max_speed_hz;u8chip_select;u8mode;#defineSPI_CPHA0x01/* clock phase */#defineSPI_CPOL0x02/* clock polarity */#defineSPI_MODE_0(0|0)/* (original MicroWire) */#defineSPI_MODE_1(0|SPI_CPHA)#defineSPI_MODE_2(SPI_CPOL|0)#defineSPI_MODE_3(SPI_CPOL|SPI_CPHA)#defineSPI_CS_HIGH0x04/* chipselect active high? */#defineSPI_LSB_FIRST0x08/* per-word bits-on-wire */#defineSPI_3WIRE0x10/* SI/SO signals shared */#defineSPI_LOOP0x20/* loopback mode */#defineSPI_NO_CS0x40/* 1 dev/bus, no chipselect */#defineSPI_READY0x80/* slave pulls low to pause */u8bits_per_word;intirq;void*controller_state;void*controller_data;charmodalias[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_tdyn_bus_id = ATOMIC_INIT((1<<15) - 1);struct device*dev = master->dev.parent;intstatus = -ENODEV;intdynamic = 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;unsignedn;//如果为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;intstatus;/* 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);elsedev_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){unsignedbad_bits;intstatus;/* 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的setupdev_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;elseerr = -EINVAL;setup_exit:/* setup() returns with device de-selected */disable_cs(sdd, spi);return err;}

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 药卡在气管里怎么办 胶囊药卡在气管怎么办 被胶囊卡在喉咙怎么办 药卡在食道里怎么办 胶囊黏在喉咙里怎么办 要一直卡在喉咙怎么办 胃老是往上反气怎么办 有口气憋在喉咙怎么办 肛裂伤口不愈合怎么办 肛裂口子不愈合怎么办 宝宝胃食道反流怎么办 去角质后脸发红怎么办 红烧肉做的太甜怎么办 红烧排骨太甜了怎么办 唱歌时嗓子有痰怎么办 一唱歌喉咙有痰怎么办 鼻子老是打喷嚏还流鼻涕怎么办 鼻涕流到喉咙里怎么办 鼻塞怎么办怎样让鼻通气 流清鼻涕嗓子疼怎么办 喉咙疼咳嗽有痰怎么办 扁桃体发炎痛得厉害怎么办 腭垂掉下来了怎么办 喉咙干有异物感怎么办 嗓子干有异物感怎么办 输液的时候手疼怎么办 一感冒就嗓子哑怎么办 4岁儿童喉咙沙哑怎么办 嗓子老有异物感怎么办 喉咙咽口水都疼怎么办? 舌头上长了溃疡怎么办 包包的拉链坏了怎么办 做试管取精困难怎么办 sw过膝靴往下掉怎么办 如果被绑架了该怎么办 怀孕了%2c怎么办%3f 狗狗拉肚子怎么办带血 同学们不和我玩怎么办 懒癌和拖延症怎么办 有严重的拖延症怎么办 有拖延症的人怎么办