• 树莓派 -- oled



    硬件

    SPI0,CE0
    这里写图片描述

    SPI Master Driver

    设备树

    archarmootdtscm2710-rpi-3-b.dts

    &gpio {
        spi0_pins: spi0_pins {
            brcm,pins = <9 10 11>;
            brcm,function = <4>; /* alt0 */
        };
    
        spi0_cs_pins: spi0_cs_pins {
            brcm,pins = <8 7>;
            brcm,function = <1>; /* output */
        };
    }
    &spi0 {
        pinctrl-names = "default";
        pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
        cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
    
        spidev0: spidev@0{
            compatible = "spidev";
            reg = <0>;  /* CE0 */
            #address-cells = <1>;
            #size-cells = <0>;
            spi-max-frequency = <125000000>;
        };
    
        spidev1: spidev@1{
            compatible = "spidev";
            reg = <1>;  /* CE1 */
            #address-cells = <1>;
            #size-cells = <0>;
            spi-max-frequency = <125000000>;
        };
    };

    spi0

    archarmootdtscm283x.dtsi

        soc {
            compatible = "simple-bus";
            #address-cells = <1>;
            #size-cells = <1>;
    
            spi: spi@7e204000 {
                compatible = "brcm,bcm2835-spi";
                reg = <0x7e204000 0x1000>;
                interrupts = <2 22>;
                clocks = <&clocks BCM2835_CLOCK_VPU>;
                #address-cells = <1>;
                #size-cells = <0>;
                status = "disabled";
            };
    
        }

    archarmootdtscm270x.dtsi

        soc: soc {
            spi0: spi@7e204000 {
                /* Add alias */
                dmas = <&dma 6>, <&dma 7>;
                dma-names = "tx", "rx";
            };
        }

    bcm2835-spi

    driversspispi-bcm2835.c

    static struct platform_driver bcm2835_spi_driver = {
        .driver     = {
            .name       = DRV_NAME,
            .of_match_table = bcm2835_spi_match,
        },
        .probe      = bcm2835_spi_probe,
        .remove     = bcm2835_spi_remove,
    };

    compatible

    static const struct of_device_id bcm2835_spi_match[] = {
        { .compatible = "brcm,bcm2835-spi", },
        {}
    };

    probe函数

    static int bcm2835_spi_probe(struct platform_device *pdev)
    {
        struct spi_master *master;
        struct bcm2835_spi *bs;
        struct resource *res;
        int err;
    
        master = spi_alloc_master(&pdev->dev, sizeof(*bs));
        if (!master) {
            dev_err(&pdev->dev, "spi_alloc_master() failed
    ");
            return -ENOMEM;
        }
    
        platform_set_drvdata(pdev, master);
    
        master->mode_bits = BCM2835_SPI_MODE_BITS;
        master->bits_per_word_mask = SPI_BPW_MASK(8);
        master->num_chipselect = 3;
        master->setup = bcm2835_spi_setup;
        master->set_cs = bcm2835_spi_set_cs;
        master->transfer_one = bcm2835_spi_transfer_one;
        master->handle_err = bcm2835_spi_handle_err;
        master->prepare_message = bcm2835_spi_prepare_message;
        master->dev.of_node = pdev->dev.of_node;
    
        bs = spi_master_get_devdata(master);
    
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        bs->regs = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(bs->regs)) {
            err = PTR_ERR(bs->regs);
            goto out_master_put;
        }
    
        bs->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(bs->clk)) {
            err = PTR_ERR(bs->clk);
            dev_err(&pdev->dev, "could not get clk: %d
    ", err);
            goto out_master_put;
        }
    
        bs->irq = platform_get_irq(pdev, 0);
        if (bs->irq <= 0) {
            dev_err(&pdev->dev, "could not get IRQ: %d
    ", bs->irq);
            err = bs->irq ? bs->irq : -ENODEV;
            goto out_master_put;
        }
    
        clk_prepare_enable(bs->clk);
    
        bcm2835_dma_init(master, &pdev->dev);
    
        /* initialise the hardware with the default polarities */
        bcm2835_wr(bs, BCM2835_SPI_CS,
               BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
    
        err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, 0,
                       dev_name(&pdev->dev), master);
        if (err) {
            dev_err(&pdev->dev, "could not request IRQ: %d
    ", err);
            goto out_clk_disable;
        }
    
        err = devm_spi_register_master(&pdev->dev, master);
        if (err) {
            dev_err(&pdev->dev, "could not register SPI master: %d
    ", err);
            goto out_clk_disable;
        }
    
        return 0;
    
    out_clk_disable:
        clk_disable_unprepare(bs->clk);
    out_master_put:
        spi_master_put(master);
        return err;
    }

    在probe函数中调用了devm_spi_register_master
    spi device

    #define devm_spi_register_master(_dev, _ctlr) 
        devm_spi_register_controller(_dev, _ctlr)

    在drivers/spi/spi.c中,定义了devm_spi_register_controller

    /**
     * devm_spi_register_controller - register managed SPI master or slave
     *  controller
     * @dev:    device managing SPI controller
     * @ctlr: initialized controller, originally from spi_alloc_master() or
     *  spi_alloc_slave()
     * Context: can sleep
     *
     * Register a SPI device as with spi_register_controller() which will
     * automatically be unregistered and freed.
     *
     * Return: zero on success, else a negative error code.
     */
    int devm_spi_register_controller(struct device *dev,
                     struct spi_controller *ctlr)
    {
        struct spi_controller **ptr;
        int ret;
        ptr = devres_alloc(devm_spi_unregister, sizeof(*ptr), GFP_KERNEL);
        if (!ptr)
            return -ENOMEM;
        ret = spi_register_controller(ctlr);
        if (!ret) {
            *ptr = ctlr;
            devres_add(dev, ptr);
        } else {
            devres_free(ptr);
        }
        return ret;
    }

    在spi_register_controller中调用

        status = device_add(&ctlr->dev);

    spi device的file operations在drivers/spi/spidev.c中定义

    static const struct file_operations spidev_fops = {
        .owner =    THIS_MODULE,
        /* REVISIT switch to aio primitives, so that userspace
         * gets more complete API coverage.  It'll simplify things
         * too, except for the locking.
         */
        .write =    spidev_write,
        .read =     spidev_read,
        .unlocked_ioctl = spidev_ioctl,
        .compat_ioctl = spidev_compat_ioctl,
        .open =     spidev_open,
        .release =  spidev_release,
        .llseek =   no_llseek,
    };
    

    wiringPi oled例程

    wiringPi在用户空间通过SPI master device的API, open, release, ioctl, read, write来驱动oled.

    static const char       *spiDev0  = "/dev/spidev0.0" ;
    static const char       *spiDev1  = "/dev/spidev0.1" ;
    /*
     * wiringPiSPISetupMode:
     *  Open the SPI device, and set it up, with the mode, etc.
     *********************************************************************************
     */
    
    int wiringPiSPISetupMode (int channel, int speed, int mode)
    {
      int fd ;
    
      mode    &= 3 ;    // Mode is 0, 1, 2 or 3
      channel &= 1 ;    // Channel is 0 or 1
    
      if ((fd = open (channel == 0 ? spiDev0 : spiDev1, O_RDWR)) < 0)
        return wiringPiFailure (WPI_ALMOST, "Unable to open SPI device: %s
    ", strerror (errno)) ;
    
      spiSpeeds [channel] = speed ;
      spiFds    [channel] = fd ;
    
    // Set SPI parameters.
    
      if (ioctl (fd, SPI_IOC_WR_MODE, &mode)            < 0)
        return wiringPiFailure (WPI_ALMOST, "SPI Mode Change failure: %s
    ", strerror (errno)) ;
    
      if (ioctl (fd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) < 0)
        return wiringPiFailure (WPI_ALMOST, "SPI BPW Change failure: %s
    ", strerror (errno)) ;
    
      if (ioctl (fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed)   < 0)
        return wiringPiFailure (WPI_ALMOST, "SPI Speed Change failure: %s
    ", strerror (errno)) ;
    
      return fd ;
    }

    树莓派 devfs sysfs中SPI设备

    查看/dev

    pi@raspberrypi:~ $ ls /dev | grep spi
    spidev0.0
    spidev0.1
    

    查看/sys/class

    pi@raspberrypi:/sys/class/spi_master $ ls
    spi0
    pi@raspberrypi:/sys/class/spi_master $ cd spi0
    pi@raspberrypi:/sys/class/spi_master/spi0 $ ls
    device  of_node  power  spi0.0  spi0.1  statistics  subsystem  uevent
    pi@raspberrypi:/sys/class/spi_master/spi0 $ cd of_node
    pi@raspberrypi:/sys/class/spi_master/spi0/of_node $ ls
    #address-cells  cs-gpios   interrupts  pinctrl-0      #size-cells  status
    clocks          dma-names  name        pinctrl-names  spidev@0
    compatible      dmas       phandle     reg            spidev@1
    pi@raspberrypi:/sys/class/spi_master/spi0/of_node $ cat compatible 
    brcm,bcm2835-spi
    pi@raspberrypi:/sys/class/spi_master/spi0/of_node $ cd spidev@0
    pi@raspberrypi:/sys/class/spi_master/spi0/of_node/spidev@0 $ ls
    #address-cells  compatible  name  phandle  reg  #size-cells  spi-max-frequency
    pi@raspberrypi:/sys/class/spi_master/spi0/of_node/spidev@0 $ cat compatible 
    spidev
  • 相关阅读:
    Qwt的安装与使用
    深入浅出分析Linux设备驱动程序中断
    QT连接数据库的基本操作
    linux下摄像头抓图源码
    QTE 触控屏支持
    linux网络多线程编程实例
    wubi (windows下硬盘安装Linux)
    快速体验Linux的3种方式
    在Visual Studio 2005中安装Qt 4.3.2
    Enterprise Architect 字体
  • 原文地址:https://www.cnblogs.com/feiwatson/p/9478204.html
Copyright © 2020-2023  润新知