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>
10 #define DRVNAME "fb_ssd1351"
15 #define DEFAULT_GAMMA "0 2 2 2 2 2 2 2 " \
24 static void register_onboard_backlight(struct fbtft_par *par);
26 static int init_display(struct fbtft_par
*par
)
29 && par
->pdata
->display
.backlight
== FBTFT_ONBOARD_BACKLIGHT
) {
30 /* module uses onboard GPIO for panel power */
31 par
->fbtftops
.register_backlight
= register_onboard_backlight
;
34 par
->fbtftops
.reset(par
);
36 write_reg(par
, 0xfd, 0x12); /* Command Lock */
37 write_reg(par
, 0xfd, 0xb1); /* Command Lock */
38 write_reg(par
, 0xae); /* Display Off */
39 write_reg(par
, 0xb3, 0xf1); /* Front Clock Div */
40 write_reg(par
, 0xca, 0x7f); /* Set Mux Ratio */
41 write_reg(par
, 0x15, 0x00, 0x7f); /* Set Column Address */
42 write_reg(par
, 0x75, 0x00, 0x7f); /* Set Row Address */
43 write_reg(par
, 0xa1, 0x00); /* Set Display Start Line */
44 write_reg(par
, 0xa2, 0x00); /* Set Display Offset */
45 write_reg(par
, 0xb5, 0x00); /* Set GPIO */
46 write_reg(par
, 0xab, 0x01); /* Set Function Selection */
47 write_reg(par
, 0xb1, 0x32); /* Set Phase Length */
48 write_reg(par
, 0xb4, 0xa0, 0xb5, 0x55); /* Set Segment Low Voltage */
49 write_reg(par
, 0xbb, 0x17); /* Set Precharge Voltage */
50 write_reg(par
, 0xbe, 0x05); /* Set VComH Voltage */
51 write_reg(par
, 0xc1, 0xc8, 0x80, 0xc8); /* Set Contrast */
52 write_reg(par
, 0xc7, 0x0f); /* Set Master Contrast */
53 write_reg(par
, 0xb6, 0x01); /* Set Second Precharge Period */
54 write_reg(par
, 0xa6); /* Set Display Mode Reset */
55 write_reg(par
, 0xaf); /* Set Sleep Mode Display On */
60 static void set_addr_win(struct fbtft_par
*par
, int xs
, int ys
, int xe
, int ye
)
62 write_reg(par
, 0x15, xs
, xe
);
63 write_reg(par
, 0x75, ys
, ye
);
67 static int set_var(struct fbtft_par
*par
)
71 if (par
->fbtftops
.init_display
!= init_display
) {
72 /* don't risk messing up register A0h */
73 fbtft_par_dbg(DEBUG_INIT_DISPLAY
, par
,
74 "%s: skipping since custom init_display() is used\n",
79 remap
= 0x60 | (par
->bgr
<< 2); /* Set Colour Depth */
81 switch (par
->info
->var
.rotate
) {
83 write_reg(par
, 0xA0, remap
| 0x00 | 1<<4);
86 write_reg(par
, 0xA0, remap
| 0x03 | 1<<4);
89 write_reg(par
, 0xA0, remap
| 0x02);
92 write_reg(par
, 0xA0, remap
| 0x01);
100 * Grayscale Lookup Table
102 * The driver Gamma curve contains the relative values between the entries
103 * in the Lookup table.
106 * 8.8 Gray Scale Decoder
108 * there are total 180 Gamma Settings (Setting 0 to Setting 180)
109 * available for the Gray Scale table.
111 * The gray scale is defined in incremental way, with reference
112 * to the length of previous table entry:
113 * Setting of GS1 has to be >= 0
114 * Setting of GS2 has to be > Setting of GS1 +1
115 * Setting of GS3 has to be > Setting of GS2 +1
117 * Setting of GS63 has to be > Setting of GS62 +1
120 static int set_gamma(struct fbtft_par
*par
, unsigned long *curves
)
122 unsigned long tmp
[GAMMA_NUM
* GAMMA_LEN
];
125 for (i
= 0; i
< 63; i
++) {
126 if (i
> 0 && curves
[i
] < 2) {
127 dev_err(par
->info
->device
,
128 "Illegal value in Grayscale Lookup Table at index %d. " \
129 "Must be greater than 1\n", i
);
135 dev_err(par
->info
->device
,
136 "Illegal value(s) in Grayscale Lookup Table. " \
137 "At index=%d, the accumulated value has exceeded 180\n", i
);
143 tmp
[0], tmp
[1], tmp
[2], tmp
[3], tmp
[4], tmp
[5], tmp
[6], tmp
[7],
144 tmp
[8], tmp
[9], tmp
[10], tmp
[11], tmp
[12], tmp
[13], tmp
[14], tmp
[15],
145 tmp
[16], tmp
[17], tmp
[18], tmp
[19], tmp
[20], tmp
[21], tmp
[22], tmp
[23],
146 tmp
[24], tmp
[25], tmp
[26], tmp
[27], tmp
[28], tmp
[29], tmp
[30], tmp
[31],
147 tmp
[32], tmp
[33], tmp
[34], tmp
[35], tmp
[36], tmp
[37], tmp
[38], tmp
[39],
148 tmp
[40], tmp
[41], tmp
[42], tmp
[43], tmp
[44], tmp
[45], tmp
[46], tmp
[47],
149 tmp
[48], tmp
[49], tmp
[50], tmp
[51], tmp
[52], tmp
[53], tmp
[54], tmp
[55],
150 tmp
[56], tmp
[57], tmp
[58], tmp
[59], tmp
[60], tmp
[61], tmp
[62]);
155 static int blank(struct fbtft_par
*par
, bool on
)
157 fbtft_par_dbg(DEBUG_BLANK
, par
, "%s(blank=%s)\n",
158 __func__
, on
? "true" : "false");
160 write_reg(par
, 0xAE);
162 write_reg(par
, 0xAF);
166 static struct fbtft_display display
= {
170 .gamma_num
= GAMMA_NUM
,
171 .gamma_len
= GAMMA_LEN
,
172 .gamma
= DEFAULT_GAMMA
,
174 .init_display
= init_display
,
175 .set_addr_win
= set_addr_win
,
177 .set_gamma
= set_gamma
,
182 #ifdef CONFIG_FB_BACKLIGHT
183 static int update_onboard_backlight(struct backlight_device
*bd
)
185 struct fbtft_par
*par
= bl_get_data(bd
);
188 fbtft_par_dbg(DEBUG_BACKLIGHT
, par
,
189 "%s: power=%d, fb_blank=%d\n",
190 __func__
, bd
->props
.power
, bd
->props
.fb_blank
);
192 on
= (bd
->props
.power
== FB_BLANK_UNBLANK
)
193 && (bd
->props
.fb_blank
== FB_BLANK_UNBLANK
);
194 /* Onboard backlight connected to GPIO0 on SSD1351, GPIO1 unused */
195 write_reg(par
, 0xB5, on
? 0x03 : 0x02);
200 static const struct backlight_ops bl_ops
= {
201 .update_status
= update_onboard_backlight
,
204 static void register_onboard_backlight(struct fbtft_par
*par
)
206 struct backlight_device
*bd
;
207 struct backlight_properties bl_props
= { 0, };
209 bl_props
.type
= BACKLIGHT_RAW
;
210 bl_props
.power
= FB_BLANK_POWERDOWN
;
212 bd
= backlight_device_register(dev_driver_string(par
->info
->device
),
213 par
->info
->device
, par
, &bl_ops
, &bl_props
);
215 dev_err(par
->info
->device
,
216 "cannot register backlight device (%ld)\n",
220 par
->info
->bl_dev
= bd
;
222 if (!par
->fbtftops
.unregister_backlight
)
223 par
->fbtftops
.unregister_backlight
= fbtft_unregister_backlight
;
226 static void register_onboard_backlight(struct fbtft_par
*par
) { };
229 FBTFT_REGISTER_DRIVER(DRVNAME
, "solomon,ssd1351", &display
);
231 MODULE_ALIAS("spi:" DRVNAME
);
232 MODULE_ALIAS("platform:" DRVNAME
);
233 MODULE_ALIAS("spi:ssd1351");
234 MODULE_ALIAS("platform:ssd1351");
236 MODULE_DESCRIPTION("SSD1351 OLED Driver");
237 MODULE_AUTHOR("James Davies");
238 MODULE_LICENSE("GPL");