Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | // SPDX-License-Identifier: GPL-2.0+ /* * FB driver for the PCD8544 LCD Controller * * The display is monochrome and the video memory is RGB565. * Any pixel value except 0 turns the pixel on. * * Copyright (C) 2013 Noralf Tronnes */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/gpio/consumer.h> #include <linux/spi/spi.h> #include <linux/delay.h> #include "fbtft.h" #define DRVNAME "fb_pcd8544" #define WIDTH 84 #define HEIGHT 48 #define TXBUFLEN (84 * 6) #define DEFAULT_GAMMA "40" /* gamma controls the contrast in this driver */ static unsigned int tc; module_param(tc, uint, 0000); MODULE_PARM_DESC(tc, "TC[1:0] Temperature coefficient: 0-3 (default: 0)"); static unsigned int bs = 4; module_param(bs, uint, 0000); MODULE_PARM_DESC(bs, "BS[2:0] Bias voltage level: 0-7 (default: 4)"); static int init_display(struct fbtft_par *par) { par->fbtftops.reset(par); /* Function set * * 5:1 1 * 2:0 PD - Powerdown control: chip is active * 1:0 V - Entry mode: horizontal addressing * 0:1 H - Extended instruction set control: extended */ write_reg(par, 0x21); /* H=1 Temperature control * * 2:1 1 * 1:x TC1 - Temperature Coefficient: 0x10 * 0:x TC0 */ write_reg(par, 0x04 | (tc & 0x3)); /* H=1 Bias system * * 4:1 1 * 3:0 0 * 2:x BS2 - Bias System * 1:x BS1 * 0:x BS0 */ write_reg(par, 0x10 | (bs & 0x7)); /* Function set * * 5:1 1 * 2:0 PD - Powerdown control: chip is active * 1:1 V - Entry mode: vertical addressing * 0:0 H - Extended instruction set control: basic */ write_reg(par, 0x22); /* H=0 Display control * * 3:1 1 * 2:1 D - DE: 10=normal mode * 1:0 0 * 0:0 E */ write_reg(par, 0x08 | 4); return 0; } static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) { /* H=0 Set X address of RAM * * 7:1 1 * 6-0: X[6:0] - 0x00 */ write_reg(par, 0x80); /* H=0 Set Y address of RAM * * 7:0 0 * 6:1 1 * 2-0: Y[2:0] - 0x0 */ write_reg(par, 0x40); } static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) { u16 *vmem16 = (u16 *)par->info->screen_buffer; u8 *buf = par->txbuf.buf; int x, y, i; int ret = 0; for (x = 0; x < 84; x++) { for (y = 0; y < 6; y++) { *buf = 0x00; for (i = 0; i < 8; i++) *buf |= (vmem16[(y * 8 + i) * 84 + x] ? 1 : 0) << i; buf++; } } /* Write data */ gpiod_set_value(par->gpio.dc, 1); ret = par->fbtftops.write(par, par->txbuf.buf, 6 * 84); if (ret < 0) dev_err(par->info->device, "write failed and returned: %d\n", ret); return ret; } static int set_gamma(struct fbtft_par *par, u32 *curves) { /* apply mask */ curves[0] &= 0x7F; write_reg(par, 0x23); /* turn on extended instruction set */ write_reg(par, 0x80 | curves[0]); write_reg(par, 0x22); /* turn off extended instruction set */ return 0; } static struct fbtft_display display = { .regwidth = 8, .width = WIDTH, .height = HEIGHT, .txbuflen = TXBUFLEN, .gamma_num = 1, .gamma_len = 1, .gamma = DEFAULT_GAMMA, .fbtftops = { .init_display = init_display, .set_addr_win = set_addr_win, .write_vmem = write_vmem, .set_gamma = set_gamma, }, .backlight = 1, }; FBTFT_REGISTER_DRIVER(DRVNAME, "philips,pcd8544", &display); MODULE_ALIAS("spi:" DRVNAME); MODULE_ALIAS("spi:pcd8544"); MODULE_DESCRIPTION("FB driver for the PCD8544 LCD Controller"); MODULE_AUTHOR("Noralf Tronnes"); MODULE_LICENSE("GPL"); |