Linux-libre 4.9.46-gnu
[librecmc/linux-libre.git] / drivers / staging / fbtft / fb_uc1701.c
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 static int init_display(struct fbtft_par *par)
73 {
74         par->fbtftops.reset(par);
75
76         /* softreset of LCD */
77         write_reg(par, LCD_RESET_CMD);
78         mdelay(10);
79
80         /* set startpoint */
81         write_reg(par, LCD_START_LINE);
82
83         /* select orientation BOTTOMVIEW */
84         write_reg(par, LCD_BOTTOMVIEW | 1);
85
86         /* output mode select (turns display upside-down) */
87         write_reg(par, LCD_SCAN_DIR | 0x00);
88
89         /* Normal Pixel mode */
90         write_reg(par, LCD_ALL_PIXEL | 0);
91
92         /* positive display */
93         write_reg(par, LCD_DISPLAY_INVERT | 0);
94
95         /* bias 1/9 */
96         write_reg(par, LCD_BIAS | 0);
97
98         /* power control mode: all features on */
99         write_reg(par, LCD_POWER_CONTROL | 0x07);
100
101         /* set voltage regulator R/R */
102         write_reg(par, LCD_VOLTAGE | 0x07);
103
104         /* volume mode set */
105         write_reg(par, LCD_VOLUME_MODE);
106         write_reg(par, 0x09);
107         write_reg(par, LCD_NO_OP);
108
109         /* advanced program control */
110         write_reg(par, LCD_ADV_PROG_CTRL);
111         write_reg(par, LCD_ADV_PROG_CTRL2 | LCD_TEMPCOMP_HIGH);
112
113         /* enable display */
114         write_reg(par, LCD_DISPLAY_ENABLE | 1);
115
116         return 0;
117 }
118
119 static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
120 {
121         /* goto address */
122         write_reg(par, LCD_PAGE_ADDRESS);
123         write_reg(par, 0x00);
124         write_reg(par, LCD_COL_ADDRESS);
125 }
126
127 static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
128 {
129         u16 *vmem16 = (u16 *)par->info->screen_buffer;
130         u8 *buf = par->txbuf.buf;
131         int x, y, i;
132         int ret = 0;
133
134         for (y = 0; y < PAGES; y++) {
135                 buf = par->txbuf.buf;
136                 for (x = 0; x < WIDTH; x++) {
137                         *buf = 0x00;
138                         for (i = 0; i < 8; i++)
139                                 *buf |= (vmem16[((y * 8 * WIDTH) +
140                                                  (i * WIDTH)) + x] ?
141                                          1 : 0) << i;
142                         buf++;
143                 }
144
145                 write_reg(par, LCD_PAGE_ADDRESS | (u8)y);
146                 write_reg(par, 0x00);
147                 write_reg(par, LCD_COL_ADDRESS);
148                 gpio_set_value(par->gpio.dc, 1);
149                 ret = par->fbtftops.write(par, par->txbuf.buf, WIDTH);
150                 gpio_set_value(par->gpio.dc, 0);
151         }
152
153         if (ret < 0)
154                 dev_err(par->info->device, "write failed and returned: %d\n",
155                         ret);
156
157         return ret;
158 }
159
160 static struct fbtft_display display = {
161         .regwidth = 8,
162         .width = WIDTH,
163         .height = HEIGHT,
164         .fbtftops = {
165                 .init_display = init_display,
166                 .set_addr_win = set_addr_win,
167                 .write_vmem = write_vmem,
168         },
169         .backlight = 1,
170 };
171
172 FBTFT_REGISTER_DRIVER(DRVNAME, "UltraChip,uc1701", &display);
173
174 MODULE_ALIAS("spi:" DRVNAME);
175 MODULE_ALIAS("spi:uc1701");
176
177 MODULE_DESCRIPTION("FB driver for the UC1701 LCD Controller");
178 MODULE_AUTHOR("Juergen Holzmann");
179 MODULE_LICENSE("GPL");