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

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 1865 | 回復: 0
打印 上一主題 下一主題

Linux 2.6下SPI設備模型--------基于AT91RM9200分析[轉] [復制鏈接]

論壇徽章:
0
跳轉到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2010-02-02 11:58 |只看該作者 |倒序瀏覽

Linux 2.6下SPI設備模型
--------基于AT91RM9200分析
       Atmel公司的ARM AT系列,其SPI驅動在kernel 2.6.23里已經(jīng)包含。如果你打了at91-patch補丁的話,則在內(nèi)核配置時要小心。在Device Drivers---- > Character devices ---- >取消選中SPI Driver(legacy) for at91rm9200 processor 。同時Device Drivers---- >SPI Support ---- > 選中SPI Support ,Atmel SPI Controler,同時選中 User mode SPI device driver support 。
SPI Driver(legacy) for at91rm9200 processor是保留選項,為了兼容以前版本。如果同時選中SPI Driver(legacy) for at91rm9200 processor,則在/sys里無法注冊類spidev,也就無法將設備和驅動聯(lián)系在一起。與現(xiàn)有atmel spi驅動發(fā)生沖突。

各選項對應的編譯情況如下:
      
  • SPI support ---- Config_SPI  開啟SPI功能
          
  • Debug support for SPI drivers ---- config SPI_DEBUG   開啟SPI debug調試
           ----SPI Master Controller Drivers ---- depends on SPI_MASTER  生成spi.o
           Atmel SPI Controller ---- config SPI_ATMEL 生成atmel_spi.o
           Bitbanging SPI master ---- config SPI_BITBANG 生成spi_bitbang.o
           AT91RM9200 Bitbang SPI Master  ---- CONFIG_SPI_AT91  spi_at91_bitbang.o
           ---- SPI Protocol Masters ---- depends on SPI_MASTER
          SPI EEPROMs from most vendors ---- config SPI_AT25 生成at25.o
           User mode SPI device driver support ---- config SPI_SPIDEV 生成spidev.o
    總線
    注冊SPI總線
    #spi.c
           struct bus_type spi_bus_type = {
           .name             = "spi",   // spi總線名稱
           .dev_attrs       = spi_dev_attrs,
           .match           = spi_match_device,
           .uevent           = spi_uevent,
           .suspend  = spi_suspend,
           .resume          = spi_resume,
    };
    spi總線將在sysfs/bus下顯示。
    其bus_type 結構表示總線,它的定義在中,如下
    struct bus_type {
           const char             * name;
           struct module         * owner;

           struct kset             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;
           struct bus_attribute drivers_autoprobe_attr;
           struct bus_attribute drivers_probe_attr;

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

           unsigned int drivers_autoprobe:1;
    };
    其中,當一個總線上的新設備或者新驅動被添加時,*match 函數(shù)會被調用。如果指定的驅動程序能夠處理指定的設備,該函數(shù)返回非零值。
    對于spi總線,我們必須調用bus_register(&spi_bus_type)進行注冊。調用如果成功,SPI總線子系統(tǒng)將被添加到系統(tǒng)中,在sysfs的/sys/bus目錄下可以看到。然后,我們就可以向這個總線添加設備了。代碼見下:
    static int __init spi_init(void)
    {
           int    status;

           buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
           if (!buf) {
                  status = -ENOMEM;
                  goto err0;
           }

           status = bus_register(&spi_bus_type);
           if (status
                  goto err1;

           status = class_register(&spi_master_class);
           if (status
                  goto err2;
           return 0;

    err2:
           bus_unregister(&spi_bus_type);
    err1:
           kfree(buf);
           buf = NULL;
    err0:
           return status;
    }

    設備
    spi設備的結構如下:
    #spi.h
    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 */
           u8                  bits_per_word;
           int                  irq;
           void               *controller_state;
           void               *controller_data;
           const char             *modalias;

           /*
            * 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
            *  - ...
            */
    };
    device結構中包含了設備模型核心用來模擬系統(tǒng)的信息。spidev還有設備的其他信息,因此spi設備結構包含在spidev_data結構里。
    struct spidev_data {
           struct device          dev;
           struct spi_device    *spi;
           struct list_head       device_entry;

           struct mutex          buf_lock;
           unsigned         users;
           u8                  *buffer;
    };
    注冊spi設備,
    #spidev.c
    static int spidev_probe(struct spi_device *spi)
    {
           …
           …
    status = device_register(&spidev->dev);


    }
    完成這個調用之后,我們就可以在sysfs中看到它了。

    SPI設備驅動程序
    spi驅動程序結構如下:
    struct spi_driver {
           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;
    };
    spi驅動程序注冊函數(shù)如下:
    int spi_register_driver(struct spi_driver *sdrv)
    {
           sdrv->driver.bus = &spi_bus_type;
           if (sdrv->probe)
                  sdrv->driver.probe = spi_drv_probe;
           if (sdrv->remove)
                  sdrv->driver.remove = spi_drv_remove;
           if (sdrv->shutdown)
                  sdrv->driver.shutdown = spi_drv_shutdown;
           return driver_register(&sdrv->driver);
    }
    spidev的驅動名如下:
    static struct spi_driver spidev_spi = {
           .driver = {
                  .name =          "spidev",
                  .owner = THIS_MODULE,
           },
           .probe =  spidev_probe,
           .remove =       __devexit_p(spidev_remove),
    };
    一個spi_register_driver調用將spidev添加到系統(tǒng)中。一旦初始化完成,就可以在sysfs中看到驅動程序信息。

    spidev類結構如下:
    static struct class spidev_class = {
           .name             = "spidev",
           .owner           = THIS_MODULE,
           .dev_release    = spidev_classdev_release,
    };

    AT91RM9200 SPIDEV初始化
    AT91RM9200的spi驅動,對于EK板,原先的SPI是用于dataflash的。其代碼如下:
    static struct spi_board_info ek_spi_devices[] = {
           {     /* DataFlash chip */
                  .modalias = "mtd_dataflash",
                  .chip_select    = 0,
                  .max_speed_hz      = 15 * 1000 * 1000,
           },
    我們需要將.modalias改成我們自己的spi設備名
    在spi設備初始化代碼中,class_register(&spidev_class)注冊類,spi_register_driver(&spidev_spi)注冊spidev驅動。
    #drivers/spi/spidev.c
    static int __init spidev_init(void)
    {
           int status;

           /* Claim our 256 reserved device numbers.  Then register a class
            * that will key udev/mdev to add/remove /dev nodes.  Last, register
            * the driver which manages those device numbers.
            */
           BUILD_BUG_ON(N_SPI_MINORS > 256);
           status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);
           if (status
                  return status;

           status = class_register(&spidev_class);
           if (status
                  unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
                  return status;
           }

           status = spi_register_driver(&spidev_spi);
           if (status
                  class_unregister(&spidev_class);
                  unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
           }
           return status;
    }

    掛載/sys
    mount –t sysfs sysfs /sys
    可以看到有/sys/class/spidev/spidev0.0,表明設備已經(jīng)掛載在總線上了,同時與驅動聯(lián)系起來。
    使用mdev –s,可以在/dev下看到spidev0.0這個設備了。
    自此,spi設備驅動就可以工作了。

    測試程序:



    #include stdio.h>
    #include unistd.h>
    #include stdlib.h>
    #include fcntl.h>
    #include string.h>

    #include sys/ioctl.h>
    #include sys/types.h>
    #include sys/stat.h>

    #include linux/types.h>
    #include linux/spi/spidev.h>


    static int verbose;

    static void do_read(int fd, int len)
    {
           unsigned char buf[32], *bp;
           int status;

           /* read at least 2 bytes, no more than 32 */
           if (len  2)
                  len = 2;
           else if (len > sizeof(buf))
                  len = sizeof(buf);
           memset(buf, 0, sizeof buf);

           status = read(fd, buf, len);
           if (status  0) {
                  perror("read");
                  return;
           }
           if (status != len) {
                  fprintf(stderr, "short read\n");
                  return;
           }

           printf("read(%2d, %2d): %02x %02x,", len, status,
                  buf[0], buf[1]);
           status -= 2;
           bp = buf + 2;
           while (status-- > 0)
                  printf(" %02x", *bp++);
           printf("\n");
    }

    static void do_msg(int fd, int len)
    {
           struct spi_ioc_transfer xfer[2];
           unsigned char buf[32], *bp;
           int status;

           memset(xfer, 0, sizeof xfer);
           memset(buf, 0, sizeof buf);

           if (len > sizeof buf)
                  len = sizeof buf;

           buf[0] = 0xaa;
           xfer[0].tx_buf = (__u64) buf;
           xfer[0].len = 1;

           xfer[1].rx_buf = (__u64) buf;
           xfer[1].len = len;

           status = ioctl(fd, SPI_IOC_MESSAGE(2), xfer);
           if (status  0) {
                  perror("SPI_IOC_MESSAGE");
                  return;
           }

           printf("response(%2d, %2d): ", len, status);
           for (bp = buf; len; len--)
                  printf(" %02x", *bp++);
           printf("\n");
    }

    static void dumpstat(const char *name, int fd)
    {
           __u8 mode, lsb, bits;
           __u32 speed;

           if (ioctl(fd, SPI_IOC_RD_MODE, &mode)  0) {
                  perror("SPI rd_mode");
                  return;
           }
           if (ioctl(fd, SPI_IOC_RD_LSB_FIRST, &lsb)  0) {
                  perror("SPI rd_lsb_fist");
                  return;
           }
           if (ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits)  0) {
                  perror("SPI bits_per_word");
                  return;
           }
           if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed)  0) {
                  perror("SPI max_speed_hz");
                  return;
           }

           printf("%s: spi mode %d, %d bits %sper word, %d Hz max\n",
                  name, mode, bits, lsb ? "(lsb first) " : "", speed);
    }

    int main(int argc, char **argv)
    {
           int c;
           int readcount = 0;
           int msglen = 0;
           int fd;
           const char *name;

           while ((c = getopt(argc, argv, "hm:r:v")) != EOF) {
                  switch (c) {
                  case 'm':
                         msglen = atoi(optarg);
                         if (msglen  0)
                                goto usage;
                         continue;
                  case 'r':
                         readcount = atoi(optarg);
                         if (readcount  0)
                                goto usage;
                         continue;
                  case 'v':
                         verbose++;
                         continue;
                  case 'h':
                  case '?':
    usage:
                         fprintf(stderr,
                                "usage: %s [-h] [-m N] [-r N] /dev/spidevB.D\n",
                                argv[0]);
                         return 1;
                  }
           }

           if ((optind + 1) != argc)
                  goto usage;
           name = argv[optind];

           fd = open(name, O_RDWR);
           if (fd  0) {
                  perror("open");
                  return 1;
           }

           dumpstat(name, fd);

           if (msglen)
                  do_msg(fd, msglen);

           if (readcount)
                  do_read(fd, readcount);

           close(fd);
           return 0;
    }


    備注:
    如果要設置模式,速率等,則可仿照以下語句:
    speed      =10*1000*1000; //10MHz
    if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed)
                  perror("SPI max_speed_hz");
                  return;
           }
    默認spi_io_transfer時,每個字節(jié)之間有延時。在atmel_spi_setup.c文件里去掉該延時語句:
                  /* TODO: DLYBS and DLYBCT */
           //csr |= SPI_BF(DLYBS, 10);
           //csr |= SPI_BF(DLYBCT, 10);
    這樣就可以達到無間隙快速傳輸批量數(shù)據(jù)。
    標準read(),write()兩個函數(shù)僅適用于半雙工傳輸,。在傳輸之間不激活片選。而SPI_IOC_MESSAGE(N)則是全雙工傳輸,并且片選始終激活。
    SPI_IOC_MESSAGE傳輸長度有限制,默認是一頁的長度,但是可以更改。
    spi_ioc_transfer結構的spi長度 是字節(jié)長度,16位傳輸?shù)臅r候要注意。


    本文來自ChinaUnix博客,如果查看原文請點:http://blog.chinaunix.net/u3/110644/showart_2167176.html
  • 您需要登錄后才可以回帖 登錄 | 注冊

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

      

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

    清除 Cookies - ChinaUnix - Archiver - WAP - TOP