Linux 驱动开发5: SPI-LCD
2022-08-08 本文已影响0人
wjundong
#include <linux/module.h>
#include <linux/init.h>
#include <linux/spi/spi.h>
#include <linux/gpio.h>
#include <linux/delay.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 //灰色
MODULE_LICENSE("GPL");
#define DAT 1
#define CMD 0
#define MY_BUS_NUM 1
static struct spi_device *st7789_dev;
// pin 138 (PE10): (MUX UNCLAIMED) 1c20800.pinctrl:138
// pin 139 (PE11): (MUX UNCLAIMED) 1c20800.pinctrl:139
// pin 140 (PE12): (MUX UNCLAIMED) 1c20800.pinctrl:140
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;
#define GPIO_RES 138
#define GPIO_BLK 139
#define GPIO_DC 140
/* 向IPS写入一个字节 com: 1 数据 0:命令 */
void ips_write_byte(uint8_t com, uint8_t dat)
{
gpio_set_value(GPIO_DC, com ? 1 : 0);
spi_write(st7789_dev, &dat, 1);
}
static inline void ips_write_dat(uint8_t *dat, int len)
{
gpio_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));
}
/**
* @brief This function is called, when the module is loaded into the kernel
*/
static int __init mydev_init(void)
{
struct spi_master *master;
int i = 0;
/* Parameters for SPI device */
struct spi_board_info spi_device_info = {
.modalias = "st7789",
.max_speed_hz = 60*1000*1000,
.bus_num = MY_BUS_NUM,
.chip_select = 0,
.mode = 3,
};
/* Get access to spi bus */
master = spi_busnum_to_master(MY_BUS_NUM);
/* Check if we could get the master */
if (!master)
{
printk("There is no spi bus with Nr. %d\n", MY_BUS_NUM);
return -1;
}
/* Create new SPI device */
st7789_dev = spi_new_device(master, &spi_device_info);
if (!st7789_dev)
{
printk("Could not create device!\n");
return -1;
}
st7789_dev->bits_per_word = 8;
/* Setup the bus for device's parameters */
if (spi_setup(st7789_dev) != 0)
{
printk("Could not change bus setup!\n");
spi_unregister_device(st7789_dev);
return -1;
}
gpio_request(GPIO_RES, "");
gpio_direction_output(GPIO_RES, 1);
mdelay(200);
gpio_set_value(GPIO_RES, 0);
mdelay(200);
gpio_set_value(GPIO_RES, 1);
gpio_request(GPIO_DC, "");
gpio_direction_output(GPIO_DC, 0);
gpio_request(GPIO_BLK, "");
gpio_direction_output(GPIO_BLK, 1);
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}
};
for (; 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 void __exit mydev_exit(void)
{
if (st7789_dev)
spi_unregister_device(st7789_dev);
printk("Goodbye, Kernel\n");
}
module_init(mydev_init);
module_exit(mydev_exit);