Commit | Line | Data |
---|---|---|
dc746091 TP |
1 | #include <linux/module.h> |
2 | #include <linux/kernel.h> | |
3 | #include <linux/init.h> | |
4 | #include <linux/gpio.h> | |
5 | #include <linux/spi/spi.h> | |
6 | #include <linux/delay.h> | |
7 | ||
8 | #include "fbtft.h" | |
9 | ||
10 | #define DRVNAME "fb_ssd1331" | |
11 | #define WIDTH 96 | |
12 | #define HEIGHT 64 | |
13 | #define GAMMA_NUM 1 | |
14 | #define GAMMA_LEN 63 | |
15 | #define DEFAULT_GAMMA "0 2 2 2 2 2 2 2 " \ | |
16 | "2 2 2 2 2 2 2 2 " \ | |
17 | "2 2 2 2 2 2 2 2 " \ | |
18 | "2 2 2 2 2 2 2 2 " \ | |
19 | "2 2 2 2 2 2 2 2 " \ | |
20 | "2 2 2 2 2 2 2 2 " \ | |
21 | "2 2 2 2 2 2 2 2 " \ | |
22 | "2 2 2 2 2 2 2" \ | |
23 | ||
24 | static int init_display(struct fbtft_par *par) | |
25 | { | |
dc746091 TP |
26 | par->fbtftops.reset(par); |
27 | ||
28 | write_reg(par, 0xae); /* Display Off */ | |
29 | write_reg(par, 0xa0, 0x70 | (par->bgr << 2)); /* Set Colour Depth */ | |
e64e0047 | 30 | write_reg(par, 0x72); /* RGB colour */ |
dc746091 TP |
31 | write_reg(par, 0xa1, 0x00); /* Set Display Start Line */ |
32 | write_reg(par, 0xa2, 0x00); /* Set Display Offset */ | |
33 | write_reg(par, 0xa4); /* NORMALDISPLAY */ | |
e64e0047 MY |
34 | write_reg(par, 0xa8, 0x3f); /* Set multiplex */ |
35 | write_reg(par, 0xad, 0x8e); /* Set master */ | |
36 | /* write_reg(par, 0xb0, 0x0b); Set power mode */ | |
37 | write_reg(par, 0xb1, 0x31); /* Precharge */ | |
38 | write_reg(par, 0xb3, 0xf0); /* Clock div */ | |
39 | write_reg(par, 0x8a, 0x64); /* Precharge A */ | |
40 | write_reg(par, 0x8b, 0x78); /* Precharge B */ | |
41 | write_reg(par, 0x8c, 0x64); /* Precharge C */ | |
42 | write_reg(par, 0xbb, 0x3a); /* Precharge level */ | |
43 | write_reg(par, 0xbe, 0x3e); /* vcomh */ | |
44 | write_reg(par, 0x87, 0x06); /* Master current */ | |
45 | write_reg(par, 0x81, 0x91); /* Contrast A */ | |
46 | write_reg(par, 0x82, 0x50); /* Contrast B */ | |
47 | write_reg(par, 0x83, 0x7d); /* Contrast C */ | |
dc746091 TP |
48 | write_reg(par, 0xaf); /* Set Sleep Mode Display On */ |
49 | ||
50 | return 0; | |
51 | } | |
52 | ||
53 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) | |
54 | { | |
dc746091 TP |
55 | write_reg(par, 0x15, xs, xe); |
56 | write_reg(par, 0x75, ys, ye); | |
57 | } | |
58 | ||
59 | static void write_reg8_bus8(struct fbtft_par *par, int len, ...) | |
60 | { | |
61 | va_list args; | |
62 | int i, ret; | |
f1092794 | 63 | u8 *buf = par->buf; |
dc746091 TP |
64 | |
65 | if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) { | |
66 | va_start(args, len); | |
0728b01c | 67 | for (i = 0; i < len; i++) |
dc746091 | 68 | buf[i] = (u8)va_arg(args, unsigned int); |
dc746091 TP |
69 | va_end(args); |
70 | fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, par->info->device, u8, buf, len, "%s: ", __func__); | |
71 | } | |
72 | ||
73 | va_start(args, len); | |
74 | ||
75 | *buf = (u8)va_arg(args, unsigned int); | |
76 | if (par->gpio.dc != -1) | |
77 | gpio_set_value(par->gpio.dc, 0); | |
78 | ret = par->fbtftops.write(par, par->buf, sizeof(u8)); | |
79 | if (ret < 0) { | |
80 | va_end(args); | |
aed1c72e HM |
81 | dev_err(par->info->device, |
82 | "write() failed and returned %d\n", ret); | |
dc746091 TP |
83 | return; |
84 | } | |
85 | len--; | |
86 | ||
87 | if (len) { | |
88 | i = len; | |
0728b01c | 89 | while (i--) |
dc746091 | 90 | *buf++ = (u8)va_arg(args, unsigned int); |
dc746091 TP |
91 | ret = par->fbtftops.write(par, par->buf, len * (sizeof(u8))); |
92 | if (ret < 0) { | |
93 | va_end(args); | |
aed1c72e HM |
94 | dev_err(par->info->device, |
95 | "write() failed and returned %d\n", ret); | |
dc746091 TP |
96 | return; |
97 | } | |
98 | } | |
99 | if (par->gpio.dc != -1) | |
100 | gpio_set_value(par->gpio.dc, 1); | |
101 | va_end(args); | |
102 | } | |
103 | ||
104 | /* | |
ba6ed643 AJ |
105 | * Grayscale Lookup Table |
106 | * GS1 - GS63 | |
107 | * The driver Gamma curve contains the relative values between the entries | |
108 | * in the Lookup table. | |
109 | * | |
110 | * From datasheet: | |
111 | * 8.8 Gray Scale Decoder | |
112 | * | |
113 | * there are total 180 Gamma Settings (Setting 0 to Setting 180) | |
114 | * available for the Gray Scale table. | |
115 | * | |
116 | * The gray scale is defined in incremental way, with reference | |
117 | * to the length of previous table entry: | |
118 | * Setting of GS1 has to be >= 0 | |
119 | * Setting of GS2 has to be > Setting of GS1 +1 | |
120 | * Setting of GS3 has to be > Setting of GS2 +1 | |
121 | * : | |
122 | * Setting of GS63 has to be > Setting of GS62 +1 | |
123 | * | |
124 | */ | |
dc746091 TP |
125 | static int set_gamma(struct fbtft_par *par, unsigned long *curves) |
126 | { | |
127 | unsigned long tmp[GAMMA_NUM * GAMMA_LEN]; | |
128 | int i, acc = 0; | |
129 | ||
dc746091 TP |
130 | for (i = 0; i < 63; i++) { |
131 | if (i > 0 && curves[i] < 2) { | |
132 | dev_err(par->info->device, | |
133 | "Illegal value in Grayscale Lookup Table at index %d. " \ | |
134 | "Must be greater than 1\n", i); | |
135 | return -EINVAL; | |
136 | } | |
137 | acc += curves[i]; | |
138 | tmp[i] = acc; | |
139 | if (acc > 180) { | |
140 | dev_err(par->info->device, | |
141 | "Illegal value(s) in Grayscale Lookup Table. " \ | |
142 | "At index=%d, the accumulated value has exceeded 180\n", i); | |
143 | return -EINVAL; | |
144 | } | |
145 | } | |
146 | ||
147 | write_reg(par, 0xB8, | |
148 | tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], | |
149 | tmp[8], tmp[9], tmp[10], tmp[11], tmp[12], tmp[13], tmp[14], tmp[15], | |
150 | tmp[16], tmp[17], tmp[18], tmp[19], tmp[20], tmp[21], tmp[22], tmp[23], | |
151 | tmp[24], tmp[25], tmp[26], tmp[27], tmp[28], tmp[29], tmp[30], tmp[31], | |
152 | tmp[32], tmp[33], tmp[34], tmp[35], tmp[36], tmp[37], tmp[38], tmp[39], | |
153 | tmp[40], tmp[41], tmp[42], tmp[43], tmp[44], tmp[45], tmp[46], tmp[47], | |
154 | tmp[48], tmp[49], tmp[50], tmp[51], tmp[52], tmp[53], tmp[54], tmp[55], | |
155 | tmp[56], tmp[57], tmp[58], tmp[59], tmp[60], tmp[61], tmp[62]); | |
156 | ||
157 | return 0; | |
158 | } | |
159 | ||
160 | static int blank(struct fbtft_par *par, bool on) | |
161 | { | |
162 | fbtft_par_dbg(DEBUG_BLANK, par, "%s(blank=%s)\n", | |
163 | __func__, on ? "true" : "false"); | |
164 | if (on) | |
165 | write_reg(par, 0xAE); | |
166 | else | |
167 | write_reg(par, 0xAF); | |
168 | return 0; | |
169 | } | |
170 | ||
dc746091 TP |
171 | static struct fbtft_display display = { |
172 | .regwidth = 8, | |
173 | .width = WIDTH, | |
174 | .height = HEIGHT, | |
175 | .gamma_num = GAMMA_NUM, | |
176 | .gamma_len = GAMMA_LEN, | |
177 | .gamma = DEFAULT_GAMMA, | |
178 | .fbtftops = { | |
179 | .write_register = write_reg8_bus8, | |
180 | .init_display = init_display, | |
181 | .set_addr_win = set_addr_win, | |
182 | .set_gamma = set_gamma, | |
183 | .blank = blank, | |
184 | }, | |
185 | }; | |
186 | ||
187 | FBTFT_REGISTER_DRIVER(DRVNAME, "solomon,ssd1331", &display); | |
188 | ||
189 | MODULE_ALIAS("spi:" DRVNAME); | |
190 | MODULE_ALIAS("platform:" DRVNAME); | |
191 | MODULE_ALIAS("spi:ssd1331"); | |
192 | MODULE_ALIAS("platform:ssd1331"); | |
193 | ||
194 | MODULE_DESCRIPTION("SSD1331 OLED Driver"); | |
195 | MODULE_AUTHOR("Alec Smecher (adapted from SSD1351 by James Davies)"); | |
196 | MODULE_LICENSE("GPL"); |