日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

spi总线 上层调用_spi总线设备驱动分析

發布時間:2025/3/15 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 spi总线 上层调用_spi总线设备驱动分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

今天折騰了一天的SPI設備的驅動加載,甚至動用了邏輯分析儀來查看spi總線的波形,主要包括兩個SPI設備,at45db321d和mcp2515,一個是串行的dataflash,一個是can總線設備芯片。前者對于我們來說非常重要,我們可以借助該設備對uboot和kernel以及根文件系統進行更新。

預備知識:設備和驅動是如何匹配的?系統的熱插拔是如何實現的?

首先一點,設備和驅動是嚴格區分的,設備是設備,驅動是驅動,設備通過struct device來定義,當然用戶也可以將該結構體封裝到自己定義的device結構體中,例如,struct platform_device,這是我們采用platform_bus_type總線的設備定義的結構體形式:

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硬件控制器,都被完全的定義成這種結構體的格式,這種結構體主要包含了硬件資源和名稱,硬件資源分為寄存器和IRQ兩種。platform_device通過向內核注冊struct device dev這個結構體來告訴內核加載這個設備,

方法就是? device_register(&platform_device->dev)

內核不關心你使用的是platform_device還是spi_device,內核只關心你的struct device結構體,內核通過這個struct device結構體自然能夠順藤摸瓜找到你是platform_device還是spi_device,這就是linux最引以為傲的contian_of()大法。

驅動通過struct driver這個結構體來定義,與struct device一致,你也可以用自己的結構體去封裝:例如,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一致,應用程序通過driver_register(&platform_driver->driver)向內核中注冊你當前的驅動,而內核不關心你封裝成的結構,而內核搜索的方法還是同樣的contain_of大法。

系統如何將這兩者匹配上的?而不會將iic的設備加載到spi的驅動上面?不會將這個iic設備的驅動加載到那個iic設備上,設備和驅動之間是如何聯系的?總線,這就是總線的作用!

include/linux/device.h文件中有總線類型的定義。

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);

};

這個總線設備中最重要的可能是match成員,由于我們一般很少去建立一個新的總線,所以我們很少涉及總線的編程,我們就只關注我們所關注的。

總線如何將兩者關聯起來,熱插拔大家知道吧,當一個設備被通過device_register注冊到內核中時,會導致一個熱插拔事件產生,系統會遍歷該總線上的所有驅動程序,調用bus的match算法,來尋找與該設備相匹配的驅動程序,當一個驅動注冊到內核的時候,處理過程與此相似(這是我理解的阿,大家批評指正),而一般的macth算法都比較簡單,例如platform_bus的匹配算法就很簡單,就是比較platform_device和platform_driver的name成員,如果匹配成功,就加載相應的設備或者驅動!這就完成了一個連接的過程。。。

那么這兩種設備驅動中最重要的類型在linux中如何表現出來,那我們就有必要介紹一下從2.6開始實現的sys文件系統了,

/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

加載這個文件系統對于我們分析設備模型是非常有好處的。

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設備的文件夾。我們關心的是bus文件夾。

我們以spi設備為例:spi部分要包括兩種設備,一種是platform_device,一種是spi_device。

在arch/arm/mach-at91/at91sam9260_device.c文件中,定義的SPI硬件控制模塊設備,這我們不需要關心。

還有一種是spi_device,定義在arch/arm/mach-at91/board-sam9260ek.c文件中,這就是我們的dataflash和mcp2515設備,

所以如何設備加載成功的話,在bus下面的每個目錄里面,都存在devices和drivers兩個文件夾,分別對應設備和文件。

/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

驅動

/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

如果出現上面的這個情況,說明你的設備(兩路spi總線)和驅動都加載成功了,如果你的devices下面沒有spi.0設備和spi.1設備的話,說明

board-sam9260ek.c文件中的這個函數出錯:

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();

}

這里是設備注冊的地方,我們還應該在下面這個目錄下看到這兩個文件。

/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

這兩個鏈接說明我們的兩個spi設備注冊都被接受了,剩下來就是驅動的問題。有人看不懂這個sys文件系統的層次關系,其實這里比較好說明,就是spi0.1是atmel_spi.0設備的子設備嘛,很好理解的。

驅動:

platform_driver驅動:

/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

我們可以看到這個驅動只有一個atmel_spi,這個驅動是在哪加載的?

driver/spi/atmel_spi.c文件加載的。

spi_driver驅動:

/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

這是我們加載的兩個驅動,說明驅動也加載正常了。

下面我們來說說我們遇到的問題吧。

在設備和驅動都加載正常之后,出現與dataflash設備通信不上的情況,驅動加載的時候,讀取芯片的狀態字讀出是0xff,說明工作不正常,動用邏輯分析儀監控spi總線的通信,意外的發現,sck信號和cs信號正常,但是mosi無信號輸出,開始覺得可能是spi總線適配器有問題,后來仔細觀察原理圖之后,發現dataflash和mmc/sd是使用同樣的io口的,即pa0,pa1,pa2,而我的內核配置中打開了對mmc的支持,所以導致mosi不正常,所以可能9260的mmc與dataflash不能同時使用,但9263的可以。

解決辦法:make menuconfig

Device Drivers--->MMC/SD card support,取消其支持,問題解決!

昨天其實還有一個問題可能大家沒有注意到,沒有解釋清楚,其實是有問題的,我們的at91_add_device_spi函數如下:

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結構體,也就是兩個spi設備的信息,注意,他們這里沒有使用spi_device結構體來做,而是使用一個板級信息體來完成。*/

for (i = 0; i < nr_devices; i++) {

/*該成員定義的就是cs引腳*/

if (devices[i].controller_data)

cs_pin = (unsigned long) devices[i].controller_data;

else if (devices[i].bus_num == 0)

cs_pin = spi0_standard_cs[devices[i].chip_select];

else

cs_pin = spi1_standard_cs[devices[i].chip_select];

/*根據需要加載的設備,確定需要打開哪幾個SPI控制器,我們系統中有兩個控制器,所以我們在以模塊的方式加載驅動的時候,我們的設備必須在剛開始就被初始化!*/

if (devices[i].bus_num == 0)

enable_spi0 = 1;

else

enable_spi1 = 1;

/* enable chip-select pin */

/*將片選引腳設置為輸出*/

at91_set_gpio_output(cs_pin, 1);

/* pass chip-select pin to driver */

devices[i].controller_data = (void *) cs_pin;

}

/*到此,循環執行完畢,向內核注冊這些板級信息體*/

spi_register_board_info(devices, nr_devices);

/* Configure SPI bus(es) */

/*如果發現spi0上有設備注冊,則打開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設備也是如此*/

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);

}

}

從上面這個函數我們可以看出,這個函數就完成了兩個功能:

1、向內核完成spi板級信息結構體的注冊

2、注冊了兩個platform_device:spi0與spi1,這兩個設備是spi總線控制器!

那么我們客戶端spi_device設備的注冊是如何完成的?不知道,呵呵

我今天仔細的看代碼才發現玄機所在。

內核的注釋很清晰的告訴我們,我們的spi設備是不允許熱插拔!!這是由于spi設備驅動的框架不允許,我們的spi_device設備注冊不是在板級初始化的時候完成的。

在spi控制器的驅動加載的時候,也就是platform_driver:atmel_spi驅動加載的時候,

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 < 0)

return 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注冊這個主控制器*/

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;

}

而這個spi_register_master位于driver/spi/spi.c文件中,該函數調用了scan_boardinfo(master),掃描該spi master下面設備。該函數就存在于該文件下:該函數調用了spi_new_device(master, chip),這個chip就是一個spi_board_info結構體,這就是at91_add_device_spi第一個作用的用處:向內核的鏈表注冊spi_board_info結構體的用處所在。我們來看函數的調用過程:

atmel_spi_probe----->spi_register_master----->scan_boardinfo

---->spi_new_device我們來看這個spi_new_device函數:

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結構體*/

proxy = kzalloc(sizeof *proxy, GFP_KERNEL);

if (!proxy) {

dev_err(dev, "can't alloc dev for cs%d\n",

chip->chip_select);

goto fail;

}

/*這就是將我們的信息體中的數據轉化為spi_device識別的數據*/

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設備是dataflash的話,保存的就是你的分區表!!!所以我們要返回去修改我們的spi_boardinfo結構體*/

proxy->dev.platform_data = (void *) chip->platform_data;

/*片選信號*/

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 < 0) {

dev_dbg(dev, "can't %s %s, status %d\n",

"setup", proxy->dev.bus_id, status);

goto fail;

}

/* driver core catches callers that misbehave by defining

* devices that already exist.

*/

/*看到這句話,大家放心了吧,大家也就知道怎么找到spi_driver驅動的。。。*/

status = device_register(&proxy->dev);

if (status < 0) {

dev_dbg(dev, "can't %s %s, status %d\n",

"add", proxy->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;

}

下面我們要解決最后的一個問題,dataflash的分區的問題,看了這么多,大家應該知道怎么解決了吧!

我們看mtd_dataflash.c文件中驅動加載函數調用了下面這個函數來添加flash設備。。

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結構體的platform_data成員指向一個我們需要的flash_platform_data數據!*/

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;

/*我們這里沒有定義該宏,所以不會在命令行傳遞分區表*/

#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 <= 0 && pdata && pdata->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;

}

所以我們需要修改這個文件:

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結構體:

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結構成員。

這里我們建立mtd_partition結構體要注意,由于dataflash是以528字節每頁的,其實,at45db321x芯片可以設置為512字節每頁,這個操作是不可以逆轉的,那個位是一個otp位,用過的人就應該知道,但是出廠的時候默認的528字節每頁。

如果我們不是以528個字節為單位的話,內核將出警告,強制將分區加載為readonly格式。

到此,分區加載成功,dmesg輸出如下信息:

<6>mtd_dataflash spi0.1: AT45DB321x (4224 KBytes)

<5>Creating 4 MTD partitions on "AT45DB321":

<5>0x00000000-0x00008400 : "U-boot ENV"

<5>0x00008400-0x0003bd00 : "U-BOOT"

<5>0x0003bd00-0x0023f700 : "Kernel"

<5>0x0023f700-0x00420000 : "Root fs"

linux簡直太偉大了,使用得越多,就越能體會到其思想的偉大!靈活!

總結

以上是生活随笔為你收集整理的spi总线 上层调用_spi总线设备驱动分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。