1/* 2 * Picvue PVC160206 display driver 3 * 4 * Brian Murphy <brian@murphy.dk> 5 * 6 */ 7#include <linux/kernel.h> 8#include <linux/delay.h> 9#include <asm/bootinfo.h> 10#include <asm/lasat/lasat.h> 11#include <linux/module.h> 12#include <linux/init.h> 13#include <linux/errno.h> 14#include <linux/string.h> 15 16#include "picvue.h" 17 18#define PVC_BUSY 0x80 19#define PVC_NLINES 2 20#define PVC_DISPMEM 80 21#define PVC_LINELEN PVC_DISPMEM / PVC_NLINES 22 23struct pvc_defs *picvue; 24 25static void pvc_reg_write(u32 val) 26{ 27 *picvue->reg = val; 28} 29 30static u32 pvc_reg_read(void) 31{ 32 u32 tmp = *picvue->reg; 33 return tmp; 34} 35 36static void pvc_write_byte(u32 data, u8 byte) 37{ 38 data |= picvue->e; 39 pvc_reg_write(data); 40 data &= ~picvue->data_mask; 41 data |= byte << picvue->data_shift; 42 pvc_reg_write(data); 43 ndelay(220); 44 pvc_reg_write(data & ~picvue->e); 45 ndelay(220); 46} 47 48static u8 pvc_read_byte(u32 data) 49{ 50 u8 byte; 51 52 data |= picvue->e; 53 pvc_reg_write(data); 54 ndelay(220); 55 byte = (pvc_reg_read() & picvue->data_mask) >> picvue->data_shift; 56 data &= ~picvue->e; 57 pvc_reg_write(data); 58 ndelay(220); 59 return byte; 60} 61 62static u8 pvc_read_data(void) 63{ 64 u32 data = pvc_reg_read(); 65 u8 byte; 66 data |= picvue->rw; 67 data &= ~picvue->rs; 68 pvc_reg_write(data); 69 ndelay(40); 70 byte = pvc_read_byte(data); 71 data |= picvue->rs; 72 pvc_reg_write(data); 73 return byte; 74} 75 76#define TIMEOUT 1000 77static int pvc_wait(void) 78{ 79 int i = TIMEOUT; 80 int err = 0; 81 82 while ((pvc_read_data() & PVC_BUSY) && i) 83 i--; 84 if (i == 0) 85 err = -ETIME; 86 87 return err; 88} 89 90#define MODE_INST 0 91#define MODE_DATA 1 92static void pvc_write(u8 byte, int mode) 93{ 94 u32 data = pvc_reg_read(); 95 data &= ~picvue->rw; 96 if (mode == MODE_DATA) 97 data |= picvue->rs; 98 else 99 data &= ~picvue->rs; 100 pvc_reg_write(data); 101 ndelay(40); 102 pvc_write_byte(data, byte); 103 if (mode == MODE_DATA) 104 data &= ~picvue->rs; 105 else 106 data |= picvue->rs; 107 pvc_reg_write(data); 108 pvc_wait(); 109} 110 111void pvc_write_string(const unsigned char *str, u8 addr, int line) 112{ 113 int i = 0; 114 115 if (line > 0 && (PVC_NLINES > 1)) 116 addr += 0x40 * line; 117 pvc_write(0x80 | addr, MODE_INST); 118 119 while (*str != 0 && i < PVC_LINELEN) { 120 pvc_write(*str++, MODE_DATA); 121 i++; 122 } 123} 124 125void pvc_write_string_centered(const unsigned char *str, int line) 126{ 127 int len = strlen(str); 128 u8 addr; 129 130 if (len > PVC_VISIBLE_CHARS) 131 addr = 0; 132 else 133 addr = (PVC_VISIBLE_CHARS - strlen(str))/2; 134 135 pvc_write_string(str, addr, line); 136} 137 138void pvc_dump_string(const unsigned char *str) 139{ 140 int len = strlen(str); 141 142 pvc_write_string(str, 0, 0); 143 if (len > PVC_VISIBLE_CHARS) 144 pvc_write_string(&str[PVC_VISIBLE_CHARS], 0, 1); 145} 146 147#define BM_SIZE 8 148#define MAX_PROGRAMMABLE_CHARS 8 149int pvc_program_cg(int charnum, u8 bitmap[BM_SIZE]) 150{ 151 int i; 152 int addr; 153 154 if (charnum > MAX_PROGRAMMABLE_CHARS) 155 return -ENOENT; 156 157 addr = charnum * 8; 158 pvc_write(0x40 | addr, MODE_INST); 159 160 for (i = 0; i < BM_SIZE; i++) 161 pvc_write(bitmap[i], MODE_DATA); 162 return 0; 163} 164 165#define FUNC_SET_CMD 0x20 166#define EIGHT_BYTE (1 << 4) 167#define FOUR_BYTE 0 168#define TWO_LINES (1 << 3) 169#define ONE_LINE 0 170#define LARGE_FONT (1 << 2) 171#define SMALL_FONT 0 172 173static void pvc_funcset(u8 cmd) 174{ 175 pvc_write(FUNC_SET_CMD | (cmd & (EIGHT_BYTE|TWO_LINES|LARGE_FONT)), 176 MODE_INST); 177} 178 179#define ENTRYMODE_CMD 0x4 180#define AUTO_INC (1 << 1) 181#define AUTO_DEC 0 182#define CURSOR_FOLLOWS_DISP (1 << 0) 183 184static void pvc_entrymode(u8 cmd) 185{ 186 pvc_write(ENTRYMODE_CMD | (cmd & (AUTO_INC|CURSOR_FOLLOWS_DISP)), 187 MODE_INST); 188} 189 190#define DISP_CNT_CMD 0x08 191#define DISP_OFF 0 192#define DISP_ON (1 << 2) 193#define CUR_ON (1 << 1) 194#define CUR_BLINK (1 << 0) 195void pvc_dispcnt(u8 cmd) 196{ 197 pvc_write(DISP_CNT_CMD | (cmd & (DISP_ON|CUR_ON|CUR_BLINK)), MODE_INST); 198} 199 200#define MOVE_CMD 0x10 201#define DISPLAY (1 << 3) 202#define CURSOR 0 203#define RIGHT (1 << 2) 204#define LEFT 0 205void pvc_move(u8 cmd) 206{ 207 pvc_write(MOVE_CMD | (cmd & (DISPLAY|RIGHT)), MODE_INST); 208} 209 210#define CLEAR_CMD 0x1 211void pvc_clear(void) 212{ 213 pvc_write(CLEAR_CMD, MODE_INST); 214} 215 216#define HOME_CMD 0x2 217void pvc_home(void) 218{ 219 pvc_write(HOME_CMD, MODE_INST); 220} 221 222int pvc_init(void) 223{ 224 u8 cmd = EIGHT_BYTE; 225 226 if (PVC_NLINES == 2) 227 cmd |= (SMALL_FONT|TWO_LINES); 228 else 229 cmd |= (LARGE_FONT|ONE_LINE); 230 pvc_funcset(cmd); 231 pvc_dispcnt(DISP_ON); 232 pvc_entrymode(AUTO_INC); 233 234 pvc_clear(); 235 pvc_write_string_centered("Display", 0); 236 pvc_write_string_centered("Initialized", 1); 237 238 return 0; 239} 240 241module_init(pvc_init); 242MODULE_LICENSE("GPL"); 243