FILE
fb_sh1106.c
File preview with syntax highlighting.
linux-6.19.14/drivers/staging/fbtft/fb_sh1106.c
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * FB driver for the SH1106 OLED Controller 4 * Based on the SSD1306 driver by Noralf Tronnes 5 * 6 * Copyright (C) 2017 Heiner Kallweit 7 */ 8 9#include <linux/module.h> 10#include <linux/kernel.h> 11#include <linux/init.h> 12#include <linux/delay.h> 13 14#include "fbtft.h" 15 16#define DRVNAME "fb_sh1106" 17#define WIDTH 128 18#define HEIGHT 64 19 20/* Init sequence based on the Adafruit SSD1306 Arduino library */ 21static int init_display(struct fbtft_par *par) 22{ 23 if (!par->info->var.xres || par->info->var.xres > WIDTH || 24 !par->info->var.yres || par->info->var.yres > HEIGHT || 25 par->info->var.yres % 8) { 26 dev_err(par->info->device, "Invalid screen size\n"); 27 return -EINVAL; 28 } 29 30 if (par->info->var.rotate) { 31 dev_err(par->info->device, "Display rotation not supported\n"); 32 return -EINVAL; 33 } 34 35 par->fbtftops.reset(par); 36 37 /* Set Display OFF */ 38 write_reg(par, 0xAE); 39 40 /* Set Display Clock Divide Ratio/ Oscillator Frequency */ 41 write_reg(par, 0xD5, 0x80); 42 43 /* Set Multiplex Ratio */ 44 write_reg(par, 0xA8, par->info->var.yres - 1); 45 46 /* Set Display Offset */ 47 write_reg(par, 0xD3, 0x00); 48 49 /* Set Display Start Line */ 50 write_reg(par, 0x40 | 0x0); 51 52 /* Set Segment Re-map */ 53 /* column address 127 is mapped to SEG0 */ 54 write_reg(par, 0xA0 | 0x1); 55 56 /* Set COM Output Scan Direction */ 57 /* remapped mode. Scan from COM[N-1] to COM0 */ 58 write_reg(par, 0xC8); 59 60 /* Set COM Pins Hardware Configuration */ 61 if (par->info->var.yres == 64) 62 /* A[4]=1b, Alternative COM pin configuration */ 63 write_reg(par, 0xDA, 0x12); 64 else if (par->info->var.yres == 48) 65 /* A[4]=1b, Alternative COM pin configuration */ 66 write_reg(par, 0xDA, 0x12); 67 else 68 /* A[4]=0b, Sequential COM pin configuration */ 69 write_reg(par, 0xDA, 0x02); 70 71 /* Set Pre-charge Period */ 72 write_reg(par, 0xD9, 0xF1); 73 74 /* Set VCOMH Deselect Level */ 75 write_reg(par, 0xDB, 0x40); 76 77 /* Set Display ON */ 78 write_reg(par, 0xAF); 79 80 msleep(150); 81 82 return 0; 83} 84 85static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 86{ 87} 88 89static int blank(struct fbtft_par *par, bool on) 90{ 91 write_reg(par, on ? 0xAE : 0xAF); 92 93 return 0; 94} 95 96/* Gamma is used to control Contrast */ 97static int set_gamma(struct fbtft_par *par, u32 *curves) 98{ 99 /* apply mask */ 100 curves[0] &= 0xFF; 101 102 /* Set Contrast Control for BANK0 */ 103 write_reg(par, 0x81, curves[0]); 104 105 return 0; 106} 107 108static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) 109{ 110 u16 *vmem16 = (u16 *)par->info->screen_buffer; 111 u32 xres = par->info->var.xres; 112 int page, page_start, page_end, x, i, ret; 113 u8 *buf = par->txbuf.buf; 114 115 /* offset refers to vmem with 2 bytes element size */ 116 page_start = offset / (8 * 2 * xres); 117 page_end = DIV_ROUND_UP(offset + len, 8 * 2 * xres); 118 119 for (page = page_start; page < page_end; page++) { 120 /* set page and set column to 2 because of vidmem width 132 */ 121 write_reg(par, 0xb0 | page, 0x00 | 2, 0x10 | 0); 122 123 memset(buf, 0, xres); 124 for (x = 0; x < xres; x++) 125 for (i = 0; i < 8; i++) 126 if (vmem16[(page * 8 + i) * xres + x]) 127 buf[x] |= BIT(i); 128 129 /* Write data */ 130 ret = fbtft_write_buf_dc(par, buf, xres, 1); 131 if (ret < 0) 132 return ret; 133 } 134 135 return 0; 136} 137 138static void write_register(struct fbtft_par *par, int len, ...) 139{ 140 va_list args; 141 int i; 142 143 va_start(args, len); 144 145 for (i = 0; i < len; i++) 146 par->buf[i] = va_arg(args, unsigned int); 147 148 /* keep DC low for all command bytes to transfer */ 149 fbtft_write_buf_dc(par, par->buf, len, 0); 150 151 va_end(args); 152} 153 154static struct fbtft_display display = { 155 .regwidth = 8, 156 .width = WIDTH, 157 .height = HEIGHT, 158 .txbuflen = WIDTH, 159 .gamma_num = 1, 160 .gamma_len = 1, 161 /* set default contrast to 0xcd = 80% */ 162 .gamma = "cd", 163 .fbtftops = { 164 .write_vmem = write_vmem, 165 .write_register = write_register, 166 .init_display = init_display, 167 .set_addr_win = set_addr_win, 168 .blank = blank, 169 .set_gamma = set_gamma, 170 }, 171}; 172 173FBTFT_REGISTER_SPI_DRIVER(DRVNAME, "sinowealth", "sh1106", &display); 174 175MODULE_DESCRIPTION("SH1106 OLED Driver"); 176MODULE_AUTHOR("Heiner Kallweit"); 177MODULE_LICENSE("GPL");
~/
Read-only file preview.