美文网首页
Linux 驱动开发8: 设备树 IPS LCD

Linux 驱动开发8: 设备树 IPS LCD

作者: wjundong | 来源:发表于2022-08-15 08:11 被阅读0次
    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/spi/spi.h>
    #include <linux/gpio.h>
    #include <linux/delay.h>
    #include <linux/gpio/consumer.h>
    
    #define WIDTH   240
    #define HEIGHT  240
    
    //画笔颜色
    #define WHITE            0xFFFF
    #define BLACK            0x0000   
    #define BLUE             0x001F  
    #define BRED             0XF81F
    #define GRED             0XFFE0
    #define GBLUE            0X07FF
    #define RED              0xF800
    #define MAGENTA          0xF81F
    #define GREEN            0x07E0
    #define CYAN             0x7FFF
    #define YELLOW           0xFFE0
    #define BROWN            0XBC40 //棕色
    #define BRRED            0XFC07 //棕红色
    #define GRAY             0X8430 //灰色
    
    #define DAT 1
    #define CMD 0
    
    #define MY_BUS_NUM 1
    static struct spi_device *st7789_dev;
    
    
    typedef struct
    {
        uint8_t cmd;
        uint8_t data[16];
        uint8_t databytes; //The number of data in data[]; bit 7 = delay flag after set; 0xFF = end of cmds.
    } lcd_init_cmd_t;
    
    static struct gpio_desc *gpio_reset;
    static struct gpio_desc *gpio_dc;
    static struct gpio_desc *gpio_blk;
    
    /* 向IPS写入一个字节 com: 1 数据 0:命令 */
    void ips_write_byte(uint8_t com, uint8_t dat)
    {
        gpiod_set_value(gpio_dc, com ? 1 : 0);
    
        spi_write(st7789_dev, &dat, 1);
    }
    
    static inline void ips_write_dat(uint8_t *dat, int len)
    {
        gpiod_set_value(gpio_dc, DAT);
        spi_write(st7789_dev, dat, len);
    }
    
    void ips_pos_set(uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1)
    {
       uint8_t dat1[4] = {
           x0>>8, x0, x1>>8, x1
       };
    
        uint8_t dat2[4] = {
           y0>>8, y0, y1>>8, y1
       };
       
       ips_write_byte(CMD,0x2a);
       ips_write_dat(dat1, 4);
       ips_write_byte(CMD,0x2b);
       ips_write_dat(dat2, 4);
       ips_write_byte(CMD,0x2C);
    }
    
    static uint16_t buffer[WIDTH * HEIGHT];
    
    /* IPS清屏 */
    void ips_clear_all(uint16_t color)
    {
        uint16_t i,j;
        
        ips_pos_set(0,0,WIDTH-1,HEIGHT-1);
    
        for(i=0;i<WIDTH;i++)
          for (j=0;j<HEIGHT;j++)
          {
                buffer[i * WIDTH + j] = color >> 8 | color << 8;
          }
    
        ips_write_dat((uint8_t*)buffer, sizeof(buffer));
    }
    
    static lcd_init_cmd_t init_cmds[] = {
        {0x01, {0x00}, 0x80}, // Power Control 1
        {0x11, {0x00}, 0x80}, // Power Control 2
        {0x3A, {0x05}, 1},    // VCOM Control 1
        {0x36, {0x00}, 1},    // VCOM Control 2  // (C0/00/A0/60)
        {0x21, {0x00}, 0x80},                // Display Inversion OFF
        {0x13, {0x00}, 0x80},                // Frame Rate Control
        {0x2A, {0x00, 0x00, 0x00, 0xEF}, 4}, // Memory Access Control
        {0x2B, {0x00, 0x00, 0x00, 0xEF}, 4}, // Pixel Format Set
        {0x29, {0x00}, 0x80},                // Display ON
        {0, {0}, 0xff}
    };
    
    static int st7789v_probe(struct spi_device *spi)
    {
        int i;
        st7789_dev = spi;
    
        st7789_dev->bits_per_word = 8;
    
        gpio_reset = gpiod_get(&spi->dev, "reset", GPIOD_OUT_HIGH);
        if (IS_ERR(gpio_reset)) {
            dev_err(&spi->dev, "Couldn't get our reset line\n");
            return PTR_ERR(gpio_reset);
        }
    
        gpio_dc = gpiod_get(&spi->dev, "dc", GPIOD_OUT_HIGH);
        if (IS_ERR(gpio_dc)) {
            dev_err(&spi->dev, "Couldn't get our dc line\n");
            return PTR_ERR(gpio_dc);
        }
    
        gpio_blk = gpiod_get(&spi->dev, "blk", GPIOD_OUT_HIGH);
        if (IS_ERR(gpio_blk)) {
            dev_err(&spi->dev, "Couldn't get our blk line\n");
            return PTR_ERR(gpio_blk);
        }
    
        gpiod_set_value(gpio_reset, 1);
        mdelay(200);
        gpiod_set_value(gpio_reset, 0);
        mdelay(200);
        gpiod_set_value(gpio_reset, 1);
        mdelay(200);
        
        gpiod_set_value(gpio_blk, 1);
    
        for (i = 0; init_cmds[i].databytes != 0xff; i++)
        {
            ips_write_byte(CMD, init_cmds[i].cmd);
            if (init_cmds[i].databytes & 0x1F)
                ips_write_dat(init_cmds[i].data, init_cmds[i].databytes & 0x1F);
        }
    
        for ( i = 0; i < 100; i++)
        {
            ips_clear_all(RED);
            ips_clear_all(BLUE);
        }
    
        printk("Hello, Kernel!\n");
        
        return 0;
    }
    
    
    static int st7789v_remove(struct spi_device *spi) {
        
      return 0;
    }
    
    
    static const struct of_device_id st7789v_of_match[] = {
        { .compatible = "mydev,st7789v" },
        { }
    };
    MODULE_DEVICE_TABLE(of, st7789v_of_match);
    
    
    static struct spi_driver st7789v_driver = {
        .probe = st7789v_probe,
        .remove = st7789v_remove,
        .driver = {
            .name = "st7789v",
            .of_match_table = st7789v_of_match,
        },
    };
    module_spi_driver(st7789v_driver);
    MODULE_LICENSE("GPL");
    
    // 在 spi 节点下
    mydev@0 {
        compatible = "mydev,st7789v";
        reg = <0>;
        reset-gpios = <&pio 4 5 GPIO_ACTIVE_HIGH>;          /* PE5 */
        dc-gpios = <&pio 4 4 GPIO_ACTIVE_HIGH>;             /* PE4 */
        blk-gpios = <&pio 4 3 GPIO_ACTIVE_HIGH>;            /* PE3 */
        spi-max-frequency = <40000000>;
        spi-cpol;
        spi-cpha;
    };
    

    相关文章

      网友评论

          本文标题:Linux 驱动开发8: 设备树 IPS LCD

          本文链接:https://www.haomeiwen.com/subject/nadtgrtx.html