1 /*
2  * FB driver for the UC1701 LCD Controller
3  *
4  * The display is monochrome and the video memory is RGB565.
5  * Any pixel value except 0 turns the pixel on.
6  *
7  * Copyright (C) 2014 Juergen Holzmann
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  */
19 
20 #include <linux/module.h>
21 #include <linux/kernel.h>
22 #include <linux/init.h>
23 #include <linux/gpio.h>
24 #include <linux/spi/spi.h>
25 #include <linux/delay.h>
26 
27 #include "fbtft.h"
28 
29 #define DRVNAME	"fb_uc1701"
30 #define WIDTH	  102
31 #define HEIGHT	 64
32 #define PAGES	  (HEIGHT/8)
33 
34 /* 1: Display on/off */
35 #define LCD_DISPLAY_ENABLE    0xAE
36 /* 2: display start line set */
37 #define LCD_START_LINE	0x40
38 /* 3: Page address set (lower 4 bits select one of the pages) */
39 #define LCD_PAGE_ADDRESS      0xB0
40 /* 4: column address */
41 #define LCD_COL_ADDRESS       0x10
42 /* 8: select orientation */
43 #define LCD_BOTTOMVIEW	0xA0
44 /* 9: inverted display */
45 #define LCD_DISPLAY_INVERT    0xA6
46 /* 10: show memory content or switch all pixels on */
47 #define LCD_ALL_PIXEL	 0xA4
48 /* 11: lcd bias set */
49 #define LCD_BIAS	      0xA2
50 /* 14: Reset Controller */
51 #define LCD_RESET_CMD	 0xE2
52 /* 15: output mode select (turns display upside-down) */
53 #define LCD_SCAN_DIR	  0xC0
54 /* 16: power control set */
55 #define LCD_POWER_CONTROL     0x28
56 /* 17: voltage regulator resistor ratio set */
57 #define LCD_VOLTAGE	   0x20
58 /* 18: Volume mode set */
59 #define LCD_VOLUME_MODE       0x81
60 /* 22: NOP command */
61 #define LCD_NO_OP	     0xE3
62 /* 25: advanced program control */
63 #define LCD_ADV_PROG_CTRL     0xFA
64 /* 25: advanced program control2 */
65 #define LCD_ADV_PROG_CTRL2    0x10
66 #define LCD_TEMPCOMP_HIGH     0x80
67 /* column offset for normal orientation */
68 #define SHIFT_ADDR_NORMAL     0
69 /* column offset for bottom view orientation */
70 #define SHIFT_ADDR_TOPVIEW    30
71 
72 
73 static int init_display(struct fbtft_par *par)
74 {
75 	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
76 
77 	par->fbtftops.reset(par);
78 
79 	/* softreset of LCD */
80 	write_reg(par, LCD_RESET_CMD);
81 	mdelay(10);
82 
83 	/* set startpoint */
84 	/* LCD_START_LINE | (pos & 0x3F) */
85 	write_reg(par, LCD_START_LINE);
86 
87 	/* select orientation BOTTOMVIEW */
88 	write_reg(par, LCD_BOTTOMVIEW | 1);
89 	/* output mode select (turns display upside-down) */
90 	write_reg(par, LCD_SCAN_DIR | 0x00);
91 
92 	/* Normal Pixel mode */
93 	write_reg(par, LCD_ALL_PIXEL | 0);
94 
95 	/* positive display */
96 	write_reg(par, LCD_DISPLAY_INVERT | 0);
97 
98 	/* bias 1/9 */
99 	write_reg(par, LCD_BIAS | 0);
100 
101 	/* power control mode: all features on */
102 	/* LCD_POWER_CONTROL | (val&0x07) */
103 	write_reg(par, LCD_POWER_CONTROL | 0x07);
104 
105 	/* set voltage regulator R/R */
106 	/* LCD_VOLTAGE | (val&0x07) */
107 	write_reg(par, LCD_VOLTAGE | 0x07);
108 
109 	/* volume mode set */
110 	/* LCD_VOLUME_MODE,val&0x3f,LCD_NO_OP */
111 	write_reg(par, LCD_VOLUME_MODE);
112 	/* LCD_VOLUME_MODE,val&0x3f,LCD_NO_OP */
113 	write_reg(par, 0x09);
114 	/* ???? */
115 	/* LCD_VOLUME_MODE,val&0x3f,LCD_NO_OP */
116 	write_reg(par, LCD_NO_OP);
117 
118 	/* advanced program control */
119 	write_reg(par, LCD_ADV_PROG_CTRL);
120 	write_reg(par, LCD_ADV_PROG_CTRL2|LCD_TEMPCOMP_HIGH);
121 
122 	/* enable display */
123 	write_reg(par, LCD_DISPLAY_ENABLE | 1);
124 
125 	return 0;
126 }
127 
128 static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
129 {
130 	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
131 
132 	/* goto address */
133 	/* LCD_PAGE_ADDRESS | ((page) & 0x1F),
134 	 (((col)+SHIFT_ADDR_NORMAL) & 0x0F),
135 	 LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */
136 	write_reg(par, LCD_PAGE_ADDRESS);
137 	/* LCD_PAGE_ADDRESS | ((page) & 0x1F),
138 	 (((col)+SHIFT_ADDR_NORMAL) & 0x0F),
139 	  LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */
140 	write_reg(par, 0x00);
141 	/* LCD_PAGE_ADDRESS | ((page) & 0x1F),
142 	 (((col)+SHIFT_ADDR_NORMAL) & 0x0F),
143 	  LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */
144 	write_reg(par, LCD_COL_ADDRESS);
145 }
146 
147 static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
148 {
149 	u16 *vmem16 = (u16 *)par->info->screen_base;
150 	u8 *buf = par->txbuf.buf;
151 	int x, y, i;
152 	int ret = 0;
153 
154 	fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__);
155 
156 	for (y = 0; y < PAGES; y++) {
157 		buf = par->txbuf.buf;
158 		for (x = 0; x < WIDTH; x++) {
159 			*buf = 0x00;
160 			for (i = 0; i < 8; i++)
161 				*buf |= (vmem16[((y*8*WIDTH)+(i*WIDTH))+x] ? 1 : 0) << i;
162 			buf++;
163 		}
164 		/* LCD_PAGE_ADDRESS | ((page) & 0x1F),
165 		 (((col)+SHIFT_ADDR_NORMAL) & 0x0F),
166 		  LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */
167 		write_reg(par, LCD_PAGE_ADDRESS|(u8)y);
168 		/* LCD_PAGE_ADDRESS | ((page) & 0x1F),
169 		 (((col)+SHIFT_ADDR_NORMAL) & 0x0F),
170 		  LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */
171 		write_reg(par, 0x00);
172 		/* LCD_PAGE_ADDRESS | ((page) & 0x1F),
173 		 (((col)+SHIFT_ADDR_NORMAL) & 0x0F),
174 		  LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */
175 		write_reg(par, LCD_COL_ADDRESS);
176 		gpio_set_value(par->gpio.dc, 1);
177 		ret = par->fbtftops.write(par, par->txbuf.buf, WIDTH);
178 		gpio_set_value(par->gpio.dc, 0);
179 	}
180 
181 	if (ret < 0)
182 		dev_err(par->info->device, "write failed and returned: %d\n",
183 			ret);
184 
185 	return ret;
186 }
187 
188 
189 static struct fbtft_display display = {
190 	.regwidth = 8,
191 	.width = WIDTH,
192 	.height = HEIGHT,
193 	.fbtftops = {
194 		.init_display = init_display,
195 		.set_addr_win = set_addr_win,
196 		.write_vmem = write_vmem,
197 	},
198 	.backlight = 1,
199 };
200 FBTFT_REGISTER_DRIVER(DRVNAME, "UltraChip,uc1701", &display);
201 
202 MODULE_ALIAS("spi:" DRVNAME);
203 MODULE_ALIAS("spi:uc1701");
204 
205 MODULE_DESCRIPTION("FB driver for the UC1701 LCD Controller");
206 MODULE_AUTHOR("Juergen Holzmann");
207 MODULE_LICENSE("GPL");
208