美文网首页
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