亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊(cè) 查看新帖 |

Chinaunix

  平臺(tái) 論壇 博客 文庫(kù)
最近訪(fǎng)問(wèn)板塊 發(fā)新帖
查看: 1075 | 回復(fù): 0
打印 上一主題 下一主題

SPI設(shè)備的驅(qū)動(dòng)(Z) [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報(bào)告]
發(fā)表于 2009-12-16 21:34 |只看該作者 |倒序?yàn)g覽
今天折騰了一天的SPI設(shè)備的驅(qū)動(dòng)加載,甚至動(dòng)用了邏輯分析儀來(lái)查看spi總線(xiàn)的波形,主要包括兩個(gè)SPI設(shè)備,at45db321d和mcp2515,一個(gè)是串行的dataflash,一個(gè)是can總線(xiàn)設(shè)備芯片。前者對(duì)于我們來(lái)說(shuō)非常重要,我們可以借助該設(shè)備對(duì)uboot和kernel以及根文件系統(tǒng)進(jìn)行更新。
    預(yù)備知識(shí):設(shè)備和驅(qū)動(dòng)是如何匹配的?系統(tǒng)的熱插拔是如何實(shí)現(xiàn)的?
    首先一點(diǎn),設(shè)備和驅(qū)動(dòng)是嚴(yán)格區(qū)分的,設(shè)備是設(shè)備,驅(qū)動(dòng)是驅(qū)動(dòng),設(shè)備通過(guò)struct device來(lái)定義,當(dāng)然用戶(hù)也可以將該結(jié)構(gòu)體封裝到自己定義的device結(jié)構(gòu)體中,例如,struct platform_device,這是我們采用platform_bus_type總線(xiàn)的設(shè)備定義的結(jié)構(gòu)體形式:
include/linux/platform_device.h文件中:
struct platform_device {
    const char    * name;
    u32        id;
    struct device    dev;
    u32        num_resources;
    struct resource    * resource;
};
只要是9260的外圍模塊,就像IIC硬件控制器,SPI硬件控制器,都被完全的定義成這種結(jié)構(gòu)體的格式,這種結(jié)構(gòu)體主要包含了硬件資源和名稱(chēng),硬件資源分為寄存器和IRQ兩種。platform_device通過(guò)向內(nèi)核注冊(cè)struct device dev這個(gè)結(jié)構(gòu)體來(lái)告訴內(nèi)核加載這個(gè)設(shè)備,
    方法就是  device_register(&platform_device->dev)   
內(nèi)核不關(guān)心你使用的是platform_device還是spi_device,內(nèi)核只關(guān)心你的struct device結(jié)構(gòu)體,內(nèi)核通過(guò)這個(gè)struct device結(jié)構(gòu)體自然能夠順藤摸瓜找到你是platform_device還是spi_device,這就是linux最引以為傲的contian_of()大法。
驅(qū)動(dòng)通過(guò)struct driver這個(gè)結(jié)構(gòu)體來(lái)定義,與struct device一致,你也可以用自己的結(jié)構(gòu)體去封裝:例如,struct platform_driver。
include/linux/platform_device.h文件中:
struct platform_driver {
    int (*probe)(struct platform_device *);
    int (*remove)(struct platform_device *);
    void (*shutdown)(struct platform_device *);
    int (*suspend)(struct platform_device *, pm_message_t state);
    int (*suspend_late)(struct platform_device *, pm_message_t state);
    int (*resume_early)(struct platform_device *);
    int (*resume)(struct platform_device *);
    struct device_driver driver;
};
與device一致,應(yīng)用程序通過(guò)driver_register(&platform_driver->driver)向內(nèi)核中注冊(cè)你當(dāng)前的驅(qū)動(dòng),而內(nèi)核不關(guān)心你封裝成的結(jié)構(gòu),而內(nèi)核搜索的方法還是同樣的contain_of大法。

系統(tǒng)如何將這兩者匹配上的?而不會(huì)將iic的設(shè)備加載到spi的驅(qū)動(dòng)上面?不會(huì)將這個(gè)iic設(shè)備的驅(qū)動(dòng)加載到那個(gè)iic設(shè)備上,設(shè)備和驅(qū)動(dòng)之間是如何聯(lián)系的?總線(xiàn),這就是總線(xiàn)的作用!
include/linux/device.h文件中有總線(xiàn)類(lèi)型的定義。
struct bus_type {
    const char        * name;
    struct subsystem    subsys;
    struct kset        drivers;
    struct kset        devices;
    struct klist        klist_devices;
    struct klist        klist_drivers;
    struct blocking_notifier_head bus_notifier;
    struct bus_attribute    * bus_attrs;
    struct device_attribute    * dev_attrs;
    struct driver_attribute    * drv_attrs;
    int        (*match)(struct device * dev, struct device_driver * drv);
    int        (*uevent)(struct device *dev, char **envp,
                  int num_envp, char *buffer, int buffer_size);
    int        (*probe)(struct device * dev);
    int        (*remove)(struct device * dev);
    void        (*shutdown)(struct device * dev);
    int (*suspend)(struct device * dev, pm_message_t state);
    int (*suspend_late)(struct device * dev, pm_message_t state);
    int (*resume_early)(struct device * dev);
    int (*resume)(struct device * dev);
};
這個(gè)總線(xiàn)設(shè)備中最重要的可能是match成員,由于我們一般很少去建立一個(gè)新的總線(xiàn),所以我們很少涉及總線(xiàn)的編程,我們就只關(guān)注我們所關(guān)注的。
總線(xiàn)如何將兩者關(guān)聯(lián)起來(lái),熱插拔大家知道吧,當(dāng)一個(gè)設(shè)備被通過(guò)device_register注冊(cè)到內(nèi)核中時(shí),會(huì)導(dǎo)致一個(gè)熱插拔事件產(chǎn)生,系統(tǒng)會(huì)遍歷該總線(xiàn)上的所有驅(qū)動(dòng)程序,調(diào)用bus的match算法,來(lái)尋找與該設(shè)備相匹配的驅(qū)動(dòng)程序,當(dāng)一個(gè)驅(qū)動(dòng)注冊(cè)到內(nèi)核的時(shí)候,處理過(guò)程與此相似(這是我理解的阿,大家批評(píng)指正),而一般的macth算法都比較簡(jiǎn)單,例如platform_bus的匹配算法就很簡(jiǎn)單,就是比較platform_device和platform_driver的name成員,如果匹配成功,就加載相應(yīng)的設(shè)備或者驅(qū)動(dòng)!這就完成了一個(gè)連接的過(guò)程。。。

那么這兩種設(shè)備驅(qū)動(dòng)中最重要的類(lèi)型在linux中如何表現(xiàn)出來(lái),那我們就有必要介紹一下從2.6開(kāi)始實(shí)現(xiàn)的sys文件系統(tǒng)了,
/sys/bus $ cat /etc/fstab
proc            /proc   proc    defaults    0   0
devpts   /dev/pts   devpts  defaults   0 0
tmpfs           /dev/shm         tmpfs  defaults        0       0
sysfs           /sys             sysfs          defaults        0       0
/dev/mtdblock2  /mnt/flash2     yaffs   defaults        0       0
加載這個(gè)文件系統(tǒng)對(duì)于我們分析設(shè)備模型是非常有好處的。
sys文件夾下一般有如下的目錄:
/sys $ ls -al
drwxr-xr-x   10 root     root            0 Jan  1  1970 .
drwxrwxrwx   11 1000     tao          4096 May 22 06:56 ..
drwxr-xr-x    7 root     root            0 Oct 27 14:09 block
drwxr-xr-x    8 root     root            0 Jan  1  1970 bus
drwxr-xr-x   21 root     root            0 Jan  1  1970 class
drwxr-xr-x    4 root     root            0 Jan  1  1970 devices
drwxr-xr-x    2 root     root            0 Jan  1  1970 firmware
drwxr-xr-x    2 root     root            0 Jan  1  1970 fs
drwxr-xr-x    2 root     root            0 Jan  1  1970 kernel
drwxr-xr-x   22 root     root            0 Oct 27 14:10 module
block是由于歷史原因形成的block設(shè)備的文件夾。我們關(guān)心的是bus文件夾。
我們以spi設(shè)備為例:spi部分要包括兩種設(shè)備,一種是platform_device,一種是spi_device。
在arch/arm/mach-at91/at91sam9260_device.c文件中,定義的SPI硬件控制模塊設(shè)備,這我們不需要關(guān)心。
還有一種是spi_device,定義在arch/arm/mach-at91/board-sam9260ek.c文件中,這就是我們的dataflash和mcp2515設(shè)備,
所以如何設(shè)備加載成功的話(huà),在bus下面的每個(gè)目錄里面,都存在devices和drivers兩個(gè)文件夾,分別對(duì)應(yīng)設(shè)備和文件。
/sys/bus/platform/devices $ ls -al
drwxr-xr-x    2 root     root            0 Oct 27 16:01 .
drwxr-xr-x    4 root     root            0 Jan  1  1970 ..
lrwxrwxrwx    1 root     root            0 Oct 27 16:01 at91_i2c -> ../../../devices/platform/at91_i2c
lrwxrwxrwx    1 root     root            0 Oct 27 16:01 at91_nand -> ../../../devices/platform/at91_nand
lrwxrwxrwx    1 root     root            0 Oct 27 16:01 at91_ohci -> ../../../devices/platform/at91_ohci
lrwxrwxrwx    1 root     root            0 Oct 27 16:01 atmel_spi.0 -> ../../../devices/platform/atmel_spi.0
lrwxrwxrwx    1 root     root            0 Oct 27 16:01 atmel_spi.1 -> ../../../devices/platform/atmel_spi.1
lrwxrwxrwx    1 root     root            0 Oct 27 16:01 atmel_usart.0 -> ../../../devices/platform/atmel_usart.0
lrwxrwxrwx    1 root     root            0 Oct 27 16:01 atmel_usart.1 -> ../../../devices/platform/atmel_usart.1
lrwxrwxrwx    1 root     root            0 Oct 27 16:01 atmel_usart.2 -> ../../../devices/platform/atmel_usart.2
lrwxrwxrwx    1 root     root            0 Oct 27 16:01 macb -> ../../../devices/platform/macb
驅(qū)動(dòng)
/sys/bus/platform/drivers/atmel_spi $ ls -al
drwxr-xr-x    2 root     root            0 Jan  1  1970 .
drwxr-xr-x    8 root     root            0 Jan  1  1970 ..
lrwxrwxrwx    1 root     root            0 Oct 27 16:10 atmel_spi.0 -> ../../../../devices/platform/atmel_spi.0
lrwxrwxrwx    1 root     root            0 Oct 27 16:10 atmel_spi.1 -> ../../../../devices/platform/atmel_spi.1
--w-------    1 root     root         4096 Oct 27 16:10 bind
--w-------    1 root     root         4096 Oct 27 16:10 unbind
如果出現(xiàn)上面的這個(gè)情況,說(shuō)明你的設(shè)備(兩路spi總線(xiàn))和驅(qū)動(dòng)都加載成功了,如果你的devices下面沒(méi)有spi.0設(shè)備和spi.1設(shè)備的話(huà),說(shuō)明
board-sam9260ek.c文件中的這個(gè)函數(shù)出錯(cuò):
static void __init ek_board_init(void)
{
    /* Serial */
    at91_add_device_serial();
    /* USB Host */
    at91_add_device_usbh(&ek_usbh_data);
    /* USB Device */
    at91_add_device_udc(&ek_udc_data);
    /* SPI */
    at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
    /* NAND */
    at91_add_device_nand(&ek_nand_data);
    /* Ethernet */
    at91_add_device_eth(&ek_macb_data);
    /* MMC */
    at91_add_device_mmc(0, &ek_mmc_data);
    /* I2C */
    at91_add_device_i2c();
}
這里是設(shè)備注冊(cè)的地方,我們還應(yīng)該在下面這個(gè)目錄下看到這兩個(gè)文件。
/sys/bus/spi/devices $ ls -al
drwxr-xr-x    2 root     root            0 Oct 27 14:09 .
drwxr-xr-x    4 root     root            0 Jan  1  1970 ..
lrwxrwxrwx    1 root     root            0 Oct 27 14:09 spi0.1 -> ../../../devices/platform/atmel_spi.0/spi0.1
lrwxrwxrwx    1 root     root            0 Oct 27 14:09 spi1.0 -> ../../../devices/platform/atmel_spi.1/spi1.0
這兩個(gè)鏈接說(shuō)明我們的兩個(gè)spi設(shè)備注冊(cè)都被接受了,剩下來(lái)就是驅(qū)動(dòng)的問(wèn)題。有人看不懂這個(gè)sys文件系統(tǒng)的層次關(guān)系,其實(shí)這里比較好說(shuō)明,就是spi0.1是atmel_spi.0設(shè)備的子設(shè)備嘛,很好理解的。
驅(qū)動(dòng):
platform_driver驅(qū)動(dòng):
/sys/bus/platform/drivers $ ls -al
drwxr-xr-x    8 root     root            0 Jan  1  1970 .
drwxr-xr-x    4 root     root            0 Jan  1  1970 ..
drwxr-xr-x    2 root     root            0 Jan  1  1970 at91_i2c
drwxr-xr-x    2 root     root            0 Jan  1  1970 at91_nand
drwxr-xr-x    2 root     root            0 Jan  1  1970 at91_ohci
drwxr-xr-x    2 root     root            0 Oct 27 16:10 atmel_spi
drwxr-xr-x    2 root     root            0 Jan  1  1970 atmel_usart
drwxr-xr-x    2 root     root            0 Jan  1  1970 macb
我們可以看到這個(gè)驅(qū)動(dòng)只有一個(gè)atmel_spi,這個(gè)驅(qū)動(dòng)是在哪加載的?
driver/spi/atmel_spi.c文件加載的。
spi_driver驅(qū)動(dòng):
/sys/bus/spi/drivers $ ls -al
drwxr-xr-x    4 root     root            0 Oct 27 14:10 .
drwxr-xr-x    4 root     root            0 Jan  1  1970 ..
drwxr-xr-x    2 root     root            0 Oct 27 14:10 mcp2515
drwxr-xr-x    2 root     root            0 Oct 27 14:09 mtd_dataflash
這是我們加載的兩個(gè)驅(qū)動(dòng),說(shuō)明驅(qū)動(dòng)也加載正常了。
下面我們來(lái)說(shuō)說(shuō)我們遇到的問(wèn)題吧。
在設(shè)備和驅(qū)動(dòng)都加載正常之后,出現(xiàn)與dataflash設(shè)備通信不上的情況,驅(qū)動(dòng)加載的時(shí)候,讀取芯片的狀態(tài)字讀出是0xff,說(shuō)明工作不正常,動(dòng)用邏輯分析儀監(jiān)控spi總線(xiàn)的通信,意外的發(fā)現(xiàn),sck信號(hào)和cs信號(hào)正常,但是mosi無(wú)信號(hào)輸出,開(kāi)始覺(jué)得可能是spi總線(xiàn)適配器有問(wèn)題,后來(lái)仔細(xì)觀察原理圖之后,發(fā)現(xiàn)dataflash和mmc/sd是使用同樣的io口的,即pa0,pa1,pa2,而我的內(nèi)核配置中打開(kāi)了對(duì)mmc的支持,所以導(dǎo)致mosi不正常,所以可能9260的mmc與dataflash不能同時(shí)使用,但9263的可以。
解決辦法:make menuconfig
Device Drivers--->MMC/SD card support,取消其支持,問(wèn)題解決!


昨天其實(shí)還有一個(gè)問(wèn)題可能大家沒(méi)有注意到,沒(méi)有解釋清楚,其實(shí)是有問(wèn)題的,我們的at91_add_device_spi函數(shù)如下:
static struct spi_board_info ek_spi_devices[] = {
#if !defined(CONFIG_MMC_AT91)
    {    /* DataFlash chip */
        .modalias    = "mtd_dataflash",
        .chip_select    = 1,
        .max_speed_hz    = 15 * 1000 * 1000,
        .bus_num    = 0,
    },
#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
    {    /* DataFlash card */
        .modalias    = "mtd_dataflash",
        .chip_select    = 0,
        .max_speed_hz    = 15 * 1000 * 1000,
        .bus_num    = 0,
    },
#endif
#endif
#if defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE)
    {    /* AT73C213 DAC */
        .modalias    = "at73c213",
        .chip_select    = 0,
        .max_speed_hz    = 10 * 1000 * 1000,
        .bus_num    = 1,
    },
#endif
/* spi can ,add by mrz */
#if defined(CONFIG_CAN_MCP2515_MODULE) ||defined(CONFIG_CAN_MCP2515)
//defined(CONFIG_CAN_MCP2515)  
    {
        .modalias = "mcp2515",
        .chip_select = 0,
//        .controller_data = AT91_PIN_PB3,
        .irq = AT91_PIN_PC6, //AT91SAM9260_ID_IRQ0,
        .platform_data = &mcp251x_data,
        .max_speed_hz = 10 * 1000 * 1000,
        .bus_num = 1,
        .mode = 0,
    },
    /*
    {
        .modalias = "mcp2515",
        .chip_select = 1,
//        .controller_data = AT91_PIN_PC5,
        .irq = AT91_PIN_PC7, //AT91SAM9260_ID_IRQ1,
        .platform_data = &mcp251x_data,
        .max_speed_hz = 10 * 1000 * 1000,
        .bus_num = 1,
        .mode = 0,
    },
*/
#elif defined(CONFIG_CAN_MCP251X)
    {
        .modalias = "mcp251x",
        .chip_select = 0,
//        .controller_data = AT91_PIN_PB3,
        .irq = AT91_PIN_PC6, //AT91SAM9260_ID_IRQ0,
        .platform_data = &mcp251x_data,
        .max_speed_hz = 10 * 1000 * 1000,
        .bus_num = 1,
        .mode = 0,
    },
    {
        .modalias = "mcp251x",
        .chip_select = 1,
//        .controller_data = AT91_PIN_PC5,
        .irq = AT91_PIN_PC7, //AT91SAM9260_ID_IRQ1,
        .platform_data = &mcp251x_data,
        .max_speed_hz = 10 * 1000 * 1000,
        .bus_num = 1,
        .mode = 0,
    },
#endif
}
void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
{
    int i;
    unsigned long cs_pin;
    short enable_spi0 = 0;
    short enable_spi1 = 0;
    /* Choose SPI chip-selects */
    /*這里加載我們定義的spi_board_info結(jié)構(gòu)體,也就是兩個(gè)spi設(shè)備的信息,注意,他們這里沒(méi)有使用spi_device結(jié)構(gòu)體來(lái)做,而是使用一個(gè)板級(jí)信息體來(lái)完成。*/
    for (i = 0; i
        /* enable chip-select pin */
      /*將片選引腳設(shè)置為輸出*/
        at91_set_gpio_output(cs_pin, 1);
        /* pass chip-select pin to driver */
        devices.controller_data = (void *) cs_pin;
    }
    /*到此,循環(huán)執(zhí)行完畢,向內(nèi)核注冊(cè)這些板級(jí)信息體*/
    spi_register_board_info(devices, nr_devices);
    /* Configure SPI bus(es) */
    /*如果發(fā)現(xiàn)spi0上有設(shè)備注冊(cè),則打開(kāi)spi0*/
    if (enable_spi0) {
        at91_set_A_periph(AT91_PIN_PA0, 0);    /* SPI0_MISO */
        at91_set_A_periph(AT91_PIN_PA1, 0);    /* SPI0_MOSI */
        at91_set_A_periph(AT91_PIN_PA2, 0);    /* SPI1_SPCK */
        at91_clock_associate("spi0_clk", &at91sam9260_spi0_device.dev, "spi_clk");
        platform_device_register(&at91sam9260_spi0_device);
    }
    /*spi0設(shè)備也是如此*/
    if (enable_spi1) {
        at91_set_A_periph(AT91_PIN_PB0, 0);    /* SPI1_MISO */
        at91_set_A_periph(AT91_PIN_PB1, 0);    /* SPI1_MOSI */
        at91_set_A_periph(AT91_PIN_PB2, 0);    /* SPI1_SPCK */
        at91_clock_associate("spi1_clk", &at91sam9260_spi1_device.dev, "spi_clk");
        platform_device_register(&at91sam9260_spi1_device);
    }
}
從上面這個(gè)函數(shù)我們可以看出,這個(gè)函數(shù)就完成了兩個(gè)功能:
1、向內(nèi)核完成spi板級(jí)信息結(jié)構(gòu)體的注冊(cè)
2、注冊(cè)了兩個(gè)platform_device:spi0與spi1,這兩個(gè)設(shè)備是spi總線(xiàn)控制器!
那么我們客戶(hù)端spi_device設(shè)備的注冊(cè)是如何完成的?不知道,呵呵
我今天仔細(xì)的看代碼才發(fā)現(xiàn)玄機(jī)所在。
內(nèi)核的注釋很清晰的告訴我們,我們的spi設(shè)備是不允許熱插拔。∵@是由于spi設(shè)備驅(qū)動(dòng)的框架不允許,我們的spi_device設(shè)備注冊(cè)不是在板級(jí)初始化的時(shí)候完成的。
在spi控制器的驅(qū)動(dòng)加載的時(shí)候,也就是platform_driver:atmel_spi驅(qū)動(dòng)加載的時(shí)候,
driver/spi/atmel_spi.c文件中:
static int __init atmel_spi_probe(struct platform_device *pdev)
{
    struct resource        *regs;
    int            irq;
    struct clk        *clk;
    int            ret;
    struct spi_master    *master;
    struct atmel_spi    *as;
    regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (!regs)
        return -ENXIO;
    irq = platform_get_irq(pdev, 0);
    if (irq
    clk = clk_get(&pdev->dev, "spi_clk");
    if (IS_ERR(clk))
        return PTR_ERR(clk);
/* setup spi core then atmel-specific driver state */
    ret = -ENOMEM;
    master = spi_alloc_master(&pdev->dev, sizeof *as);
    if (!master)
        goto out_free;
    master->bus_num = pdev->id;
    master->num_chipselect = 4;
    master->setup = atmel_spi_setup;
    master->transfer = atmel_spi_transfer;
    master->cleanup = atmel_spi_cleanup;
    platform_set_drvdata(pdev, master);
    as = spi_master_get_devdata(master);
    as->buffer = dma_alloc_coherent(&pdev->dev, BUFFER_SIZE,
                    &as->buffer_dma, GFP_KERNEL);
    if (!as->buffer)
        goto out_free;
    spin_lock_init(&as->lock);
    INIT_LIST_HEAD(&as->queue);
    as->pdev = pdev;
    as->regs = ioremap(regs->start, (regs->end - regs->start) + 1);
    if (!as->regs)
        goto out_free_buffer;
    as->irq = irq;
    as->clk = clk;
#ifdef CONFIG_ARCH_AT91
    if (!cpu_is_at91rm9200())
        as->new_1 = 1;
#endif
    ret = request_irq(irq, atmel_spi_interrupt, 0,
            pdev->dev.bus_id, master);
    if (ret)
        goto out_unmap_regs;
    /* Initialize the hardware */
    clk_enable(clk);
    spi_writel(as, CR, SPI_BIT(SWRST));
    spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS));
    spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
    spi_writel(as, CR, SPI_BIT(SPIEN));
    /* go! */
    dev_info(&pdev->dev, "Atmel SPI Controller at 0x%08lx (irq %d)\n",
            (unsigned long)regs->start, irq);
    /*spi注冊(cè)這個(gè)主控制器*/
    ret = spi_register_master(master);
    if (ret)
        goto out_reset_hw;
    return 0;
out_reset_hw:
    spi_writel(as, CR, SPI_BIT(SWRST));
    clk_disable(clk);
    free_irq(irq, master);
out_unmap_regs:
    iounmap(as->regs);
out_free_buffer:
    dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
            as->buffer_dma);
out_free:
    clk_put(clk);
    spi_master_put(master);
    return ret;
}
而這個(gè)spi_register_master位于driver/spi/spi.c文件中,該函數(shù)調(diào)用了scan_boardinfo(master),掃描該spi master下面設(shè)備。該函數(shù)就存在于該文件下:該函數(shù)調(diào)用了spi_new_device(master, chip),這個(gè)chip就是一個(gè)spi_board_info結(jié)構(gòu)體,這就是at91_add_device_spi第一個(gè)作用的用處:向內(nèi)核的鏈表注冊(cè)spi_board_info結(jié)構(gòu)體的用處所在。我們來(lái)看函數(shù)的調(diào)用過(guò)程:
atmel_spi_probe----->spi_register_master----->scan_boardinfo
---->spi_new_device
我們來(lái)看這個(gè)spi_new_device函數(shù):
struct spi_device *spi_new_device(struct spi_master *master,
                  struct spi_board_info *chip)
{
    struct spi_device    *proxy;
    struct device        *dev = master->cdev.dev;
    int            status;
    /* NOTE:  caller did any chip->bus_num checks necessary */
    if (!spi_master_get(master))
        return NULL;
    /*靠,終于找到你了,先暴打一頓,舒服了。。這里就分配了我們重要的spi_device結(jié)構(gòu)體*/
    proxy = kzalloc(sizeof *proxy, GFP_KERNEL);
    if (!proxy) {
        dev_err(dev, "can't alloc dev for cs%d\n",
            chip->chip_select);
        goto fail;
    }
/*這就是將我們的信息體中的數(shù)據(jù)轉(zhuǎn)化為spi_device識(shí)別的數(shù)據(jù)*/
    proxy->master = master;
    proxy->chip_select = chip->chip_select;
    proxy->max_speed_hz = chip->max_speed_hz;
    proxy->mode = chip->mode;
    proxy->irq = chip->irq;
    proxy->modalias = chip->modalias;
    snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id,
            "%s.%u", master->cdev.class_id,
            chip->chip_select);
    proxy->dev.parent = dev;
    proxy->dev.bus = &spi_bus_type;
    /*這里很重要,如果你的spi設(shè)備是dataflash的話(huà),保存的就是你的分區(qū)表。!所以我們要返回去修改我們的spi_boardinfo結(jié)構(gòu)體*/
    proxy->dev.platform_data = (void *) chip->platform_data;
    /*片選信號(hào)*/
    proxy->controller_data = chip->controller_data;
    proxy->controller_state = NULL;
    proxy->dev.release = spidev_release;
    /* drivers may modify this default i/o setup */
    status = master->setup(proxy);
    if (status dev.bus_id, status);
        goto fail;
    }
    /* driver core catches callers that misbehave by defining
     * devices that already exist.
     */
    /*看到這句話(huà),大家放心了吧,大家也就知道怎么找到spi_driver驅(qū)動(dòng)的。。。*/
    status = device_register(&proxy->dev);
    if (status dev.bus_id, status);
        goto fail;
    }
    dev_dbg(dev, "registered child %s\n", proxy->dev.bus_id);
    return proxy;
fail:
    spi_master_put(master);
    kfree(proxy);
    return NULL;
}

下面我們要解決最后的一個(gè)問(wèn)題,dataflash的分區(qū)的問(wèn)題,看了這么多,大家應(yīng)該知道怎么解決了吧!
我們看mtd_dataflash.c文件中驅(qū)動(dòng)加載函數(shù)調(diào)用了下面這個(gè)函數(shù)來(lái)添加flash設(shè)備。。
static int __devinit
add_dataflash(struct spi_device *spi, char *name,
        int nr_pages, int pagesize, int pageoffset)
{
    struct dataflash        *priv;
    struct mtd_info            *device;
    /*這里就告訴我們要在spi_boardinfo結(jié)構(gòu)體的platform_data成員指向一個(gè)我們需要的flash_platform_data數(shù)據(jù)!*/
    struct flash_platform_data    *pdata = spi->dev.platform_data;
    priv = kzalloc(sizeof *priv, GFP_KERNEL);
    if (!priv)
        return -ENOMEM;
    init_MUTEX(&priv->lock);
    priv->spi = spi;
    priv->page_size = pagesize;
    priv->page_offset = pageoffset;
    /* name must be usable with cmdlinepart */
    sprintf(priv->name, "spi%d.%d-%s",
            spi->master->bus_num, spi->chip_select,
            name);
    device = &priv->mtd;
    device->name = (pdata && pdata->name) ? pdata->name : priv->name;
    device->size = nr_pages * pagesize;
    device->erasesize = pagesize;
    device->writesize = pagesize;
    device->owner = THIS_MODULE;
    device->type = MTD_DATAFLASH;
    device->flags = MTD_WRITEABLE;
    device->erase = dataflash_erase;
    device->read = dataflash_read;
    device->write = dataflash_write;
    device->priv = priv;
    dev_info(&spi->dev, "%s (%d KBytes)\n", name, device->size/1024);
    dev_set_drvdata(&spi->dev, priv);
    if (mtd_has_partitions()) {
        struct mtd_partition    *parts;
        int            nr_parts = 0;
    /*我們這里沒(méi)有定義該宏,所以不會(huì)在命令行傳遞分區(qū)表*/
#ifdef CONFIG_MTD_CMDLINE_PARTS
        static const char *part_probes[] = { "cmdlinepart", NULL, };
        nr_parts = parse_mtd_partitions(device, part_probes, &parts, 0);
#endif
        if (nr_parts parts) {
            parts = pdata->parts;
            nr_parts = pdata->nr_parts;
        }
        if (nr_parts > 0) {
            priv->partitioned = 1;
            return add_mtd_partitions(device, parts, nr_parts);
        }
    } else if (pdata && pdata->nr_parts)
        dev_warn(&spi->dev, "ignoring %d default partitions on %s\n",
                pdata->nr_parts, device->name);
    return add_mtd_device(device) == 1 ? -ENODEV : 0;
}

所以我們需要修改這個(gè)文件:
arch/arm/mach-at91/board-sam9260ek.c文件:
添加如下:
#if  !defined(CONFIG_MMC_AT91)
#define    SIZE_1PAGE    528
#define    SIZE_1M (unsigned long)(1024*1024)
static struct mtd_partition ek_dataflash_partition[] = {
    {
        .name    = "U-boot ENV",
        .offset    = 0,
        .size    = 64*SIZE_1PAGE,
    },
    {
        .name    = "U-BOOT",
        .offset    = 64*SIZE_1PAGE,
        .size    = 400*SIZE_1PAGE,
    },
    {
        .name ="Kernel",
        .offset=464*SIZE_1PAGE,
        .size    = 4000*SIZE_1PAGE,
    },
    {
        .name ="Root fs",
        .offset=4464*SIZE_1PAGE,
        .size    = (8192-4464)*SIZE_1PAGE,
    },
};
struct flash_platform_data dataflash_atmel={
    .name="AT45DB321",
    .parts=ek_dataflash_partition,
    .nr_parts=ARRAY_SIZE(ek_dataflash_partition),
};
#endif
修改spi_boardinfo結(jié)構(gòu)體:
static struct spi_board_info ek_spi_devices[] = {
#if !defined(CONFIG_MMC_AT91)
    {    /* DataFlash chip */
        .modalias    = "mtd_dataflash",
        .chip_select    = 1,
        .max_speed_hz    = 15 * 1000 * 1000,
        .bus_num    = 0,
        .platform_data=&dataflash_atmel,
    },
添加platform_data結(jié)構(gòu)成員。
這里我們建立mtd_partition結(jié)構(gòu)體要注意,由于dataflash是以528字節(jié)每頁(yè)的,其實(shí),at45db321x芯片可以設(shè)置為512字節(jié)每頁(yè),這個(gè)操作是不可以逆轉(zhuǎn)的,那個(gè)位是一個(gè)otp位,用過(guò)的人就應(yīng)該知道,但是出廠(chǎng)的時(shí)候默認(rèn)的528字節(jié)每頁(yè)。
如果我們不是以528個(gè)字節(jié)為單位的話(huà),內(nèi)核將出警告,強(qiáng)制將分區(qū)加載為readonly格式。
到此,分區(qū)加載成功,dmesg輸出如下信息:
mtd_dataflash spi0.1: AT45DB321x (4224 KBytes)
Creating 4 MTD partitions on "AT45DB321":
0x00000000-0x00008400 : "U-boot ENV"
0x00008400-0x0003bd00 : "U-BOOT"
0x0003bd00-0x0023f700 : "Kernel"
0x0023f700-0x00420000 : "Root fs"
linux簡(jiǎn)直太偉大了,使用得越多,就越能體會(huì)到其思想的偉大!靈活!

文章出處:DIY部落(
http://www.diybl.com/course/6_system/linux/Linuxjs/200868/123621_3.html
)



本文來(lái)自ChinaUnix博客,如果查看原文請(qǐng)點(diǎn):http://blog.chinaunix.net/u3/101356/showart_2123234.html
您需要登錄后才可以回帖 登錄 | 注冊(cè)

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號(hào)-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號(hào):11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專(zhuān)區(qū)
中國(guó)互聯(lián)網(wǎng)協(xié)會(huì)會(huì)員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過(guò)ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請(qǐng)注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP