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 63 static 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 110 static 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 118 static 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 151 static 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 163 FBTFT_REGISTER_DRIVER(DRVNAME, "UltraChip,uc1701", &display); 164 165 MODULE_ALIAS("spi:" DRVNAME); 166 MODULE_ALIAS("spi:uc1701"); 167 168 MODULE_DESCRIPTION("FB driver for the UC1701 LCD Controller"); 169 MODULE_AUTHOR("Juergen Holzmann"); 170 MODULE_LICENSE("GPL"); 171