fb_uc1701.c (4184B)
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * FB driver for the UC1701 LCD Controller 4 * 5 * The display is monochrome and the video memory is RGB565. 6 * Any pixel value except 0 turns the pixel on. 7 * 8 * Copyright (C) 2014 Juergen Holzmann 9 */ 10 11#include <linux/module.h> 12#include <linux/kernel.h> 13#include <linux/init.h> 14#include <linux/gpio/consumer.h> 15#include <linux/spi/spi.h> 16#include <linux/delay.h> 17 18#include "fbtft.h" 19 20#define DRVNAME "fb_uc1701" 21#define WIDTH 102 22#define HEIGHT 64 23#define PAGES (HEIGHT / 8) 24 25/* 1: Display on/off */ 26#define LCD_DISPLAY_ENABLE 0xAE 27/* 2: display start line set */ 28#define LCD_START_LINE 0x40 29/* 3: Page address set (lower 4 bits select one of the pages) */ 30#define LCD_PAGE_ADDRESS 0xB0 31/* 4: column address */ 32#define LCD_COL_ADDRESS 0x10 33/* 8: select orientation */ 34#define LCD_BOTTOMVIEW 0xA0 35/* 9: inverted display */ 36#define LCD_DISPLAY_INVERT 0xA6 37/* 10: show memory content or switch all pixels on */ 38#define LCD_ALL_PIXEL 0xA4 39/* 11: lcd bias set */ 40#define LCD_BIAS 0xA2 41/* 14: Reset Controller */ 42#define LCD_RESET_CMD 0xE2 43/* 15: output mode select (turns display upside-down) */ 44#define LCD_SCAN_DIR 0xC0 45/* 16: power control set */ 46#define LCD_POWER_CONTROL 0x28 47/* 17: voltage regulator resistor ratio set */ 48#define LCD_VOLTAGE 0x20 49/* 18: Volume mode set */ 50#define LCD_VOLUME_MODE 0x81 51/* 22: NOP command */ 52#define LCD_NO_OP 0xE3 53/* 25: advanced program control */ 54#define LCD_ADV_PROG_CTRL 0xFA 55/* 25: advanced program control2 */ 56#define LCD_ADV_PROG_CTRL2 0x10 57#define LCD_TEMPCOMP_HIGH 0x80 58/* column offset for normal orientation */ 59#define SHIFT_ADDR_NORMAL 0 60/* column offset for bottom view orientation */ 61#define SHIFT_ADDR_TOPVIEW 30 62 63static int init_display(struct fbtft_par *par) 64{ 65 par->fbtftops.reset(par); 66 67 /* softreset of LCD */ 68 write_reg(par, LCD_RESET_CMD); 69 mdelay(10); 70 71 /* set startpoint */ 72 write_reg(par, LCD_START_LINE); 73 74 /* select orientation BOTTOMVIEW */ 75 write_reg(par, LCD_BOTTOMVIEW | 1); 76 77 /* output mode select (turns display upside-down) */ 78 write_reg(par, LCD_SCAN_DIR | 0x00); 79 80 /* Normal Pixel mode */ 81 write_reg(par, LCD_ALL_PIXEL | 0); 82 83 /* positive display */ 84 write_reg(par, LCD_DISPLAY_INVERT | 0); 85 86 /* bias 1/9 */ 87 write_reg(par, LCD_BIAS | 0); 88 89 /* power control mode: all features on */ 90 write_reg(par, LCD_POWER_CONTROL | 0x07); 91 92 /* set voltage regulator R/R */ 93 write_reg(par, LCD_VOLTAGE | 0x07); 94 95 /* volume mode set */ 96 write_reg(par, LCD_VOLUME_MODE); 97 write_reg(par, 0x09); 98 write_reg(par, LCD_NO_OP); 99 100 /* advanced program control */ 101 write_reg(par, LCD_ADV_PROG_CTRL); 102 write_reg(par, LCD_ADV_PROG_CTRL2 | LCD_TEMPCOMP_HIGH); 103 104 /* enable display */ 105 write_reg(par, LCD_DISPLAY_ENABLE | 1); 106 107 return 0; 108} 109 110static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 111{ 112 /* goto address */ 113 write_reg(par, LCD_PAGE_ADDRESS); 114 write_reg(par, 0x00); 115 write_reg(par, LCD_COL_ADDRESS); 116} 117 118static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) 119{ 120 u16 *vmem16 = (u16 *)par->info->screen_buffer; 121 u8 *buf; 122 int x, y, i; 123 int ret = 0; 124 125 for (y = 0; y < PAGES; y++) { 126 buf = par->txbuf.buf; 127 for (x = 0; x < WIDTH; x++) { 128 *buf = 0x00; 129 for (i = 0; i < 8; i++) 130 *buf |= (vmem16[((y * 8 * WIDTH) + 131 (i * WIDTH)) + x] ? 132 1 : 0) << i; 133 buf++; 134 } 135 136 write_reg(par, LCD_PAGE_ADDRESS | (u8)y); 137 write_reg(par, 0x00); 138 write_reg(par, LCD_COL_ADDRESS); 139 gpiod_set_value(par->gpio.dc, 1); 140 ret = par->fbtftops.write(par, par->txbuf.buf, WIDTH); 141 gpiod_set_value(par->gpio.dc, 0); 142 } 143 144 if (ret < 0) 145 dev_err(par->info->device, "write failed and returned: %d\n", 146 ret); 147 148 return ret; 149} 150 151static struct fbtft_display display = { 152 .regwidth = 8, 153 .width = WIDTH, 154 .height = HEIGHT, 155 .fbtftops = { 156 .init_display = init_display, 157 .set_addr_win = set_addr_win, 158 .write_vmem = write_vmem, 159 }, 160 .backlight = 1, 161}; 162 163FBTFT_REGISTER_DRIVER(DRVNAME, "UltraChip,uc1701", &display); 164 165MODULE_ALIAS("spi:" DRVNAME); 166MODULE_ALIAS("spi:uc1701"); 167 168MODULE_DESCRIPTION("FB driver for the UC1701 LCD Controller"); 169MODULE_AUTHOR("Juergen Holzmann"); 170MODULE_LICENSE("GPL");