-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Practice_II_Display: Add framebuffer driver
Signed-off-by: Bekir <[email protected]>
- Loading branch information
1 parent
e6f5e90
commit 8473580
Showing
10 changed files
with
492 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,20 @@ | ||
obj-m += lcd_driver.o | ||
TARGET = lcd_module | ||
obj-m += $(TARGET).o | ||
OBJS = lcd_driver.o fb_lcd.o | ||
$(TARGET)-objs = $(OBJS) | ||
|
||
KERNEL_DIR := /home/bekir/Work/LinuxKernelCamp/linux/linux-stable | ||
|
||
COMPILE_FLAGS += CROSS_COMPILE=arm-linux-gnueabihf- CROSS=arm-linux-gnueabihf- ARCH=arm | ||
|
||
all: | ||
make -C $(KERNEL_DIR) M=$(PWD) $(COMPILE_FLAGS) modules | ||
|
||
$(TARGET).o: $(OBJS) | ||
ld -r -o $@ $(OBJS) | ||
|
||
clean: | ||
make -C $(KERNEL_DIR) M=$(PWD) $(COMPILE_FLAGS) clean | ||
|
||
install: | ||
make -C $(KERNEL_DIR) M=$(PWD) modules_install INSTALL_MOD_PATH=$(PWD)/build_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
/* | ||
* fb_lcd.c | ||
* Author: Bekir Bekirov | ||
* Email: [email protected] | ||
*/ | ||
|
||
#include "fb_lcd.h" | ||
#include "lcd_driver.h" | ||
|
||
static ssize_t st7735sfb_write(struct fb_info *info, const char __user *buf, | ||
size_t count, loff_t *ppos) | ||
{ | ||
unsigned long total_size; | ||
unsigned long p = *ppos; | ||
u8 __iomem *dst; | ||
|
||
total_size = info->fix.smem_len; | ||
|
||
if (p > total_size) | ||
return -EINVAL; | ||
|
||
if (count + p > total_size) | ||
count = total_size - p; | ||
|
||
if (!count) | ||
return -EINVAL; | ||
|
||
dst = (void __force *) (info->screen_base + p); | ||
|
||
if (copy_from_user(dst, buf, count)) | ||
return -EFAULT; | ||
|
||
lcd_update_screen(); | ||
|
||
*ppos += count; | ||
|
||
return count; | ||
} | ||
|
||
static int st7735sfb_blank(int blank_mode, struct fb_info *info) | ||
{ | ||
return 0; | ||
} | ||
|
||
static void st7735sfb_fillrect(struct fb_info *info, | ||
const struct fb_fillrect *rect) | ||
{ | ||
sys_fillrect(info, rect); | ||
lcd_update_screen(); | ||
} | ||
|
||
static void st7735sfb_copyarea(struct fb_info *info, | ||
const struct fb_copyarea *area) | ||
{ | ||
sys_copyarea(info, area); | ||
lcd_update_screen(); | ||
} | ||
|
||
static void st7735sfb_imageblit(struct fb_info *info, | ||
const struct fb_image *image) | ||
{ | ||
lcd_update_screen(); | ||
} | ||
|
||
static int vfb_mmap(struct fb_info *info, | ||
struct vm_area_struct *vma) | ||
{ | ||
return remap_vmalloc_range(vma, (void *)info->fix.smem_start, | ||
vma->vm_pgoff); | ||
} | ||
|
||
static struct fb_ops st7735sfb_ops = { | ||
.owner = THIS_MODULE, | ||
.fb_read = fb_sys_read, | ||
.fb_write = st7735sfb_write, | ||
.fb_blank = st7735sfb_blank, | ||
.fb_fillrect = st7735sfb_fillrect, | ||
.fb_copyarea = st7735sfb_copyarea, | ||
.fb_imageblit = st7735sfb_imageblit, | ||
.fb_mmap = vfb_mmap, | ||
}; | ||
|
||
int init_fb_lcd(struct spi_device *spi) | ||
{ | ||
struct lcd_data *ptr_lcddata; | ||
int ret; | ||
struct fb_info *info; | ||
u32 vmem_size; | ||
u8 *vmem; | ||
|
||
ptr_lcddata = spi_get_drvdata(spi); | ||
info = framebuffer_alloc(0, &spi->dev); | ||
|
||
if (!info) | ||
return -ENOMEM; | ||
|
||
pr_info("frame buffer is allocated\n"); | ||
ptr_lcddata->info = info; | ||
ptr_lcddata->width = ST7735S_WIDTH; | ||
ptr_lcddata->height = ST7735S_HEIGHT; | ||
|
||
vmem = (u8 *)(ptr_lcddata->frame_buffer); | ||
vmem_size = ptr_lcddata->width * ptr_lcddata->height * 2; | ||
|
||
info->fbops = &st7735sfb_ops; | ||
info->fix = st7735sfb_fix; | ||
info->fix.line_length = ptr_lcddata->width * 2; | ||
|
||
info->var = st7735sfb_var; | ||
info->var.xres = ptr_lcddata->width; | ||
info->var.xres_virtual = ptr_lcddata->width; | ||
info->var.yres = ptr_lcddata->height; | ||
info->var.yres_virtual = ptr_lcddata->height; | ||
|
||
info->var.red.length = 5; | ||
info->var.red.offset = 11; | ||
info->var.green.length = 6; | ||
info->var.green.offset = 5; | ||
info->var.blue.length = 5; | ||
info->var.blue.offset = 0; | ||
|
||
info->screen_base = (u8 __force __iomem *)vmem; | ||
info->fix.smem_start = __pa(vmem); | ||
info->fix.smem_len = vmem_size; | ||
info->par = NULL; | ||
info->flags = FBINFO_FLAG_DEFAULT; | ||
|
||
fb_alloc_cmap(&info->cmap, 256, 0); | ||
ptr_lcddata->info = info; | ||
|
||
ret = register_framebuffer(info); | ||
if (ret) { | ||
pr_info("Error: ret = %d\n", ret); | ||
return ret; | ||
} | ||
pr_info("frame buffer is registered\n"); | ||
return 0; | ||
} | ||
|
||
int deinit_fb_lcd(struct spi_device *spi) | ||
{ | ||
struct lcd_data *ptr_lcddata; | ||
|
||
ptr_lcddata = spi_get_drvdata(spi); | ||
unregister_framebuffer(ptr_lcddata->info); | ||
fb_dealloc_cmap(&ptr_lcddata->info->cmap); | ||
framebuffer_release(ptr_lcddata->info); | ||
|
||
if (!ptr_lcddata) | ||
return -ENODEV; | ||
|
||
pr_info("fb is unloaded!\n"); | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
#ifndef FB_LCD_H_ | ||
#define FB_LCD_H_ | ||
|
||
#include <linux/init.h> | ||
#include <linux/module.h> | ||
#include <linux/device.h> | ||
#include <linux/err.h> | ||
#include <linux/kobject.h> | ||
#include <linux/sysfs.h> | ||
|
||
#include <linux/spinlock.h> | ||
#include <linux/mutex.h> | ||
#include <linux/of.h> | ||
#include <linux/of_platform.h> | ||
#include <linux/platform_device.h> | ||
#include <linux/gpio.h> | ||
#include <linux/delay.h> | ||
#include <linux/spi/spi.h> | ||
#include <linux/fb.h> | ||
#include <linux/uaccess.h> | ||
|
||
static struct fb_fix_screeninfo st7735sfb_fix = { | ||
.id = "ST7735S", | ||
.type = FB_TYPE_PACKED_PIXELS, | ||
.visual = FB_VISUAL_TRUECOLOR, | ||
.xpanstep = 0, | ||
.ypanstep = 0, | ||
.ywrapstep = 0, | ||
.accel = FB_ACCEL_NONE, | ||
}; | ||
|
||
|
||
static struct fb_var_screeninfo st7735sfb_var = { | ||
.bits_per_pixel = 16, | ||
}; | ||
|
||
#endif /* FB_LCD_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,13 @@ | ||
#include "lcd_driver.h" | ||
|
||
#include <linux/init.h> | ||
#include <linux/module.h> | ||
#include <linux/device.h> | ||
#include <linux/err.h> | ||
#include <linux/kobject.h> | ||
#include <linux/sysfs.h> | ||
|
||
#include <linux/spinlock.h> | ||
#include <linux/mutex.h> | ||
#include <linux/of.h> | ||
#include <linux/of_platform.h> | ||
#include <linux/platform_device.h> | ||
#include <linux/gpio.h> | ||
#include <linux/delay.h> | ||
#include <linux/spi/spi.h> | ||
#include <linux/fb.h> | ||
#include <linux/uaccess.h> | ||
/* | ||
* lcd_driver.c | ||
* Author: Bekir Bekirov | ||
* Email: [email protected] | ||
*/ | ||
|
||
#include "lcd_driver.h" | ||
|
||
struct lcd_data { | ||
struct spi_device *spi; | ||
struct mutex mutex_sysfs; | ||
struct fb_info *info; | ||
u16 frame_buffer[ST7735S_WIDTH * ST7735S_HEIGHT]; | ||
}; | ||
extern int init_fb_lcd(struct spi_device *spi); | ||
extern int deinit_fb_lcd(struct spi_device *spi); | ||
|
||
static struct lcd_data *lcd_st7735s_data; | ||
|
||
|
@@ -162,7 +144,7 @@ static void lcd_set_adr_window(u8 x0, u8 y0, u8 x1, u8 y1) | |
lcd_write_command(ST7735S_RAMWR); | ||
} | ||
|
||
inline void lcd_update_screen(void) | ||
void lcd_update_screen(void) | ||
{ | ||
lcd_write_data((u8 *)lcd_st7735s_data->frame_buffer, | ||
sizeof(u16) * ST7735S_WIDTH * ST7735S_HEIGHT); | ||
|
@@ -171,13 +153,10 @@ inline void lcd_update_screen(void) | |
void lcd_draw_pixel(u16 x, u16 y, u16 color) | ||
{ | ||
if ((x >= ST7735S_WIDTH) || (y >= ST7735S_HEIGHT)) | ||
goto out; | ||
return; | ||
|
||
lcd_st7735s_data->frame_buffer[x + ST7735S_WIDTH * y] = color; | ||
lcd_update_screen(); | ||
|
||
out: | ||
return; | ||
} | ||
|
||
void lcd_fill_rect(u16 x, u16 y, u16 w, u16 h, u16 color) | ||
|
@@ -186,7 +165,7 @@ void lcd_fill_rect(u16 x, u16 y, u16 w, u16 h, u16 color) | |
u16 j; | ||
|
||
if ((x >= ST7735S_WIDTH) || (y >= ST7735S_HEIGHT)) | ||
goto out; | ||
return; | ||
|
||
if ((x + w - 1) > ST7735S_WIDTH) | ||
w = ST7735S_WIDTH - x; | ||
|
@@ -202,9 +181,6 @@ void lcd_fill_rect(u16 x, u16 y, u16 w, u16 h, u16 color) | |
} | ||
|
||
lcd_update_screen(); | ||
|
||
out: | ||
return; | ||
} | ||
|
||
void lcd_fill_screen(u16 color) | ||
|
@@ -244,12 +220,16 @@ static int st7735s_probe(struct spi_device *spi) | |
lcd_fill_rect(34, 60, 60, 40, 0x001f); | ||
lcd_fill_rect(34, 120, 60, 40, 0xf800); | ||
|
||
if (init_fb_lcd(spi)) | ||
return -EIO; | ||
|
||
return 0; | ||
} | ||
|
||
static int st7735s_remove(struct spi_device *spi) | ||
{ | ||
lcd_st7735s_data = spi_get_drvdata(spi); | ||
deinit_fb_lcd(spi); | ||
|
||
if (!lcd_st7735s_data) | ||
return -ENODEV; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,13 @@ | ||
root@orangepione:~# dmesg -w | ||
[ 4452.917936] lcd: device init completed | ||
[ 4453.028007] lcd: sysfs class created | ||
[ 4453.028023] lcd: module loaded | ||
[ 4830.316654] lcd: sysfs class attributes removed | ||
[ 4830.316739] lcd: sysfs class destroyed | ||
[ 4830.316885] lcd: module exited | ||
[21242.825872] lcd: device init completed | ||
[21242.935524] frame buffer is allocated | ||
[21242.936153] Console: switching to colour frame buffer device 16x20 | ||
[21243.811276] frame buffer is registered | ||
[21243.811561] lcd: sysfs class created | ||
[21243.811573] lcd: module loaded | ||
[21340.355414] Console: switching to colour dummy device 80x30 | ||
[21347.918165] lcd: sysfs class attributes removed | ||
[21347.918248] lcd: sysfs class destroyed | ||
[21347.918553] fb is unloaded! | ||
[21347.918648] lcd: module exited | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,13 @@ | ||
root@orangepione:/home/bekir# insmod lcd_driver.ko | ||
root@orangepione:/home/bekir# echo 0xf800 > /sys/class/lcd_st7735s/fill_screen | ||
root@orangepione:/home/bekir# echo 0x001f > /sys/class/lcd_st7735s/fill_screen | ||
root@orangepione:/home/bekir# echo 0x03e0 > /sys/class/lcd_st7735s/fill_screen | ||
root@orangepione:/home/bekir# echo "30 30 50 50 0x03e0" > /sys/class/lcd_st7735s/fill_rect | ||
root@orangepione:/home/bekir# echo "0x03e0 30 30 50 50" > /sys/class/lcd_st7735s/fill_rect | ||
root@orangepione:/home/bekir# echo 0x0000 > /sys/class/lcd_st7735s/fill_screen | ||
root@orangepione:/home/bekir# echo "0x03e0 30 30 50 50" > /sys/class/lcd_st7735s/fill_rect | ||
root@orangepione:/home/bekir# echo "0x03e0 30 30 50 50" > /sys/class/lcd_st7735s/fill_rect | ||
root@orangepione:/home/bekir# rmmod lcd_driver | ||
root@orangepione:/home/bekir# insmod lcd_module.ko | ||
root@orangepione:/home/bekir# ls /dev/ | ||
Display all 642 possibilities? (y or n) | ||
root@orangepione:/home/bekir# ls /dev/f | ||
fb0 fd/ full | ||
root@orangepione:/home/bekir# ls -l /dev/fb0 | ||
crw-rw---- 1 root video 29, 0 Dec 19 12:10 /dev/fb0 | ||
root@orangepione:/home/bekir# echo 0 > /sys/class/vtconsole/vtcon1/bind | ||
root@orangepione:/home/bekir# rmmod lcd_module | ||
root@orangepione:/home/bekir# ls -l /dev/fb0 | ||
ls: cannot access '/dev/fb0': No such file or directory | ||
root@orangepione:/home/bekir# | ||
|
Binary file not shown.
Oops, something went wrong.