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