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