Linux-libre 5.4.48-gnu
[librecmc/linux-libre.git] / drivers / video / fbdev / ssd1307fb.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Driver for the Solomon SSD1307 OLED controller
4  *
5  * Copyright 2012 Free Electrons
6  */
7
8 #include <linux/backlight.h>
9 #include <linux/delay.h>
10 #include <linux/fb.h>
11 #include <linux/gpio/consumer.h>
12 #include <linux/i2c.h>
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/of_device.h>
16 #include <linux/of_gpio.h>
17 #include <linux/pwm.h>
18 #include <linux/uaccess.h>
19 #include <linux/regulator/consumer.h>
20
21 #define SSD1307FB_DATA                  0x40
22 #define SSD1307FB_COMMAND               0x80
23
24 #define SSD1307FB_SET_ADDRESS_MODE      0x20
25 #define SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL   (0x00)
26 #define SSD1307FB_SET_ADDRESS_MODE_VERTICAL     (0x01)
27 #define SSD1307FB_SET_ADDRESS_MODE_PAGE         (0x02)
28 #define SSD1307FB_SET_COL_RANGE         0x21
29 #define SSD1307FB_SET_PAGE_RANGE        0x22
30 #define SSD1307FB_CONTRAST              0x81
31 #define SSD1307FB_SET_LOOKUP_TABLE      0x91
32 #define SSD1307FB_CHARGE_PUMP           0x8d
33 #define SSD1307FB_SEG_REMAP_ON          0xa1
34 #define SSD1307FB_DISPLAY_OFF           0xae
35 #define SSD1307FB_SET_MULTIPLEX_RATIO   0xa8
36 #define SSD1307FB_DISPLAY_ON            0xaf
37 #define SSD1307FB_START_PAGE_ADDRESS    0xb0
38 #define SSD1307FB_SET_DISPLAY_OFFSET    0xd3
39 #define SSD1307FB_SET_CLOCK_FREQ        0xd5
40 #define SSD1307FB_SET_AREA_COLOR_MODE   0xd8
41 #define SSD1307FB_SET_PRECHARGE_PERIOD  0xd9
42 #define SSD1307FB_SET_COM_PINS_CONFIG   0xda
43 #define SSD1307FB_SET_VCOMH             0xdb
44
45 #define MAX_CONTRAST 255
46
47 #define REFRESHRATE 1
48
49 static u_int refreshrate = REFRESHRATE;
50 module_param(refreshrate, uint, 0);
51
52 struct ssd1307fb_par;
53
54 struct ssd1307fb_deviceinfo {
55         u32 default_vcomh;
56         u32 default_dclk_div;
57         u32 default_dclk_frq;
58         int need_pwm;
59         int need_chargepump;
60 };
61
62 struct ssd1307fb_par {
63         unsigned area_color_enable : 1;
64         unsigned com_invdir : 1;
65         unsigned com_lrremap : 1;
66         unsigned com_seq : 1;
67         unsigned lookup_table_set : 1;
68         unsigned low_power : 1;
69         unsigned seg_remap : 1;
70         u32 com_offset;
71         u32 contrast;
72         u32 dclk_div;
73         u32 dclk_frq;
74         const struct ssd1307fb_deviceinfo *device_info;
75         struct i2c_client *client;
76         u32 height;
77         struct fb_info *info;
78         u8 lookup_table[4];
79         u32 page_offset;
80         u32 prechargep1;
81         u32 prechargep2;
82         struct pwm_device *pwm;
83         u32 pwm_period;
84         struct gpio_desc *reset;
85         struct regulator *vbat_reg;
86         u32 vcomh;
87         u32 width;
88 };
89
90 struct ssd1307fb_array {
91         u8      type;
92         u8      data[0];
93 };
94
95 static const struct fb_fix_screeninfo ssd1307fb_fix = {
96         .id             = "Solomon SSD1307",
97         .type           = FB_TYPE_PACKED_PIXELS,
98         .visual         = FB_VISUAL_MONO10,
99         .xpanstep       = 0,
100         .ypanstep       = 0,
101         .ywrapstep      = 0,
102         .accel          = FB_ACCEL_NONE,
103 };
104
105 static const struct fb_var_screeninfo ssd1307fb_var = {
106         .bits_per_pixel = 1,
107         .red = { .length = 1 },
108         .green = { .length = 1 },
109         .blue = { .length = 1 },
110 };
111
112 static struct ssd1307fb_array *ssd1307fb_alloc_array(u32 len, u8 type)
113 {
114         struct ssd1307fb_array *array;
115
116         array = kzalloc(sizeof(struct ssd1307fb_array) + len, GFP_KERNEL);
117         if (!array)
118                 return NULL;
119
120         array->type = type;
121
122         return array;
123 }
124
125 static int ssd1307fb_write_array(struct i2c_client *client,
126                                  struct ssd1307fb_array *array, u32 len)
127 {
128         int ret;
129
130         len += sizeof(struct ssd1307fb_array);
131
132         ret = i2c_master_send(client, (u8 *)array, len);
133         if (ret != len) {
134                 dev_err(&client->dev, "Couldn't send I2C command.\n");
135                 return ret;
136         }
137
138         return 0;
139 }
140
141 static inline int ssd1307fb_write_cmd(struct i2c_client *client, u8 cmd)
142 {
143         struct ssd1307fb_array *array;
144         int ret;
145
146         array = ssd1307fb_alloc_array(1, SSD1307FB_COMMAND);
147         if (!array)
148                 return -ENOMEM;
149
150         array->data[0] = cmd;
151
152         ret = ssd1307fb_write_array(client, array, 1);
153         kfree(array);
154
155         return ret;
156 }
157
158 static void ssd1307fb_update_display(struct ssd1307fb_par *par)
159 {
160         struct ssd1307fb_array *array;
161         u8 *vmem = par->info->screen_buffer;
162         unsigned int line_length = par->info->fix.line_length;
163         unsigned int pages = DIV_ROUND_UP(par->height, 8);
164         int i, j, k;
165
166         array = ssd1307fb_alloc_array(par->width * pages, SSD1307FB_DATA);
167         if (!array)
168                 return;
169
170         /*
171          * The screen is divided in pages, each having a height of 8
172          * pixels, and the width of the screen. When sending a byte of
173          * data to the controller, it gives the 8 bits for the current
174          * column. I.e, the first byte are the 8 bits of the first
175          * column, then the 8 bits for the second column, etc.
176          *
177          *
178          * Representation of the screen, assuming it is 5 bits
179          * wide. Each letter-number combination is a bit that controls
180          * one pixel.
181          *
182          * A0 A1 A2 A3 A4
183          * B0 B1 B2 B3 B4
184          * C0 C1 C2 C3 C4
185          * D0 D1 D2 D3 D4
186          * E0 E1 E2 E3 E4
187          * F0 F1 F2 F3 F4
188          * G0 G1 G2 G3 G4
189          * H0 H1 H2 H3 H4
190          *
191          * If you want to update this screen, you need to send 5 bytes:
192          *  (1) A0 B0 C0 D0 E0 F0 G0 H0
193          *  (2) A1 B1 C1 D1 E1 F1 G1 H1
194          *  (3) A2 B2 C2 D2 E2 F2 G2 H2
195          *  (4) A3 B3 C3 D3 E3 F3 G3 H3
196          *  (5) A4 B4 C4 D4 E4 F4 G4 H4
197          */
198
199         for (i = 0; i < pages; i++) {
200                 for (j = 0; j < par->width; j++) {
201                         int m = 8;
202                         u32 array_idx = i * par->width + j;
203                         array->data[array_idx] = 0;
204                         /* Last page may be partial */
205                         if (i + 1 == pages && par->height % 8)
206                                 m = par->height % 8;
207                         for (k = 0; k < m; k++) {
208                                 u8 byte = vmem[(8 * i + k) * line_length +
209                                                j / 8];
210                                 u8 bit = (byte >> (j % 8)) & 1;
211                                 array->data[array_idx] |= bit << k;
212                         }
213                 }
214         }
215
216         ssd1307fb_write_array(par->client, array, par->width * pages);
217         kfree(array);
218 }
219
220
221 static ssize_t ssd1307fb_write(struct fb_info *info, const char __user *buf,
222                 size_t count, loff_t *ppos)
223 {
224         struct ssd1307fb_par *par = info->par;
225         unsigned long total_size;
226         unsigned long p = *ppos;
227         void *dst;
228
229         total_size = info->fix.smem_len;
230
231         if (p > total_size)
232                 return -EINVAL;
233
234         if (count + p > total_size)
235                 count = total_size - p;
236
237         if (!count)
238                 return -EINVAL;
239
240         dst = info->screen_buffer + p;
241
242         if (copy_from_user(dst, buf, count))
243                 return -EFAULT;
244
245         ssd1307fb_update_display(par);
246
247         *ppos += count;
248
249         return count;
250 }
251
252 static int ssd1307fb_blank(int blank_mode, struct fb_info *info)
253 {
254         struct ssd1307fb_par *par = info->par;
255
256         if (blank_mode != FB_BLANK_UNBLANK)
257                 return ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_OFF);
258         else
259                 return ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON);
260 }
261
262 static void ssd1307fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
263 {
264         struct ssd1307fb_par *par = info->par;
265         sys_fillrect(info, rect);
266         ssd1307fb_update_display(par);
267 }
268
269 static void ssd1307fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
270 {
271         struct ssd1307fb_par *par = info->par;
272         sys_copyarea(info, area);
273         ssd1307fb_update_display(par);
274 }
275
276 static void ssd1307fb_imageblit(struct fb_info *info, const struct fb_image *image)
277 {
278         struct ssd1307fb_par *par = info->par;
279         sys_imageblit(info, image);
280         ssd1307fb_update_display(par);
281 }
282
283 static struct fb_ops ssd1307fb_ops = {
284         .owner          = THIS_MODULE,
285         .fb_read        = fb_sys_read,
286         .fb_write       = ssd1307fb_write,
287         .fb_blank       = ssd1307fb_blank,
288         .fb_fillrect    = ssd1307fb_fillrect,
289         .fb_copyarea    = ssd1307fb_copyarea,
290         .fb_imageblit   = ssd1307fb_imageblit,
291 };
292
293 static void ssd1307fb_deferred_io(struct fb_info *info,
294                                 struct list_head *pagelist)
295 {
296         ssd1307fb_update_display(info->par);
297 }
298
299 static int ssd1307fb_init(struct ssd1307fb_par *par)
300 {
301         int ret;
302         u32 precharge, dclk, com_invdir, compins;
303         struct pwm_args pargs;
304
305         if (par->device_info->need_pwm) {
306                 par->pwm = pwm_get(&par->client->dev, NULL);
307                 if (IS_ERR(par->pwm)) {
308                         dev_err(&par->client->dev, "Could not get PWM from device tree!\n");
309                         return PTR_ERR(par->pwm);
310                 }
311
312                 /*
313                  * FIXME: pwm_apply_args() should be removed when switching to
314                  * the atomic PWM API.
315                  */
316                 pwm_apply_args(par->pwm);
317
318                 pwm_get_args(par->pwm, &pargs);
319
320                 par->pwm_period = pargs.period;
321                 /* Enable the PWM */
322                 pwm_config(par->pwm, par->pwm_period / 2, par->pwm_period);
323                 pwm_enable(par->pwm);
324
325                 dev_dbg(&par->client->dev, "Using PWM%d with a %dns period.\n",
326                         par->pwm->pwm, par->pwm_period);
327         }
328
329         /* Set initial contrast */
330         ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CONTRAST);
331         if (ret < 0)
332                 return ret;
333
334         ret = ssd1307fb_write_cmd(par->client, par->contrast);
335         if (ret < 0)
336                 return ret;
337
338         /* Set segment re-map */
339         if (par->seg_remap) {
340                 ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SEG_REMAP_ON);
341                 if (ret < 0)
342                         return ret;
343         }
344
345         /* Set COM direction */
346         com_invdir = 0xc0 | par->com_invdir << 3;
347         ret = ssd1307fb_write_cmd(par->client,  com_invdir);
348         if (ret < 0)
349                 return ret;
350
351         /* Set multiplex ratio value */
352         ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_MULTIPLEX_RATIO);
353         if (ret < 0)
354                 return ret;
355
356         ret = ssd1307fb_write_cmd(par->client, par->height - 1);
357         if (ret < 0)
358                 return ret;
359
360         /* set display offset value */
361         ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_DISPLAY_OFFSET);
362         if (ret < 0)
363                 return ret;
364
365         ret = ssd1307fb_write_cmd(par->client, par->com_offset);
366         if (ret < 0)
367                 return ret;
368
369         /* Set clock frequency */
370         ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_CLOCK_FREQ);
371         if (ret < 0)
372                 return ret;
373
374         dclk = ((par->dclk_div - 1) & 0xf) | (par->dclk_frq & 0xf) << 4;
375         ret = ssd1307fb_write_cmd(par->client, dclk);
376         if (ret < 0)
377                 return ret;
378
379         /* Set Set Area Color Mode ON/OFF & Low Power Display Mode */
380         if (par->area_color_enable || par->low_power) {
381                 u32 mode;
382
383                 ret = ssd1307fb_write_cmd(par->client,
384                                           SSD1307FB_SET_AREA_COLOR_MODE);
385                 if (ret < 0)
386                         return ret;
387
388                 mode = (par->area_color_enable ? 0x30 : 0) |
389                         (par->low_power ? 5 : 0);
390                 ret = ssd1307fb_write_cmd(par->client, mode);
391                 if (ret < 0)
392                         return ret;
393         }
394
395         /* Set precharge period in number of ticks from the internal clock */
396         ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PRECHARGE_PERIOD);
397         if (ret < 0)
398                 return ret;
399
400         precharge = (par->prechargep1 & 0xf) | (par->prechargep2 & 0xf) << 4;
401         ret = ssd1307fb_write_cmd(par->client, precharge);
402         if (ret < 0)
403                 return ret;
404
405         /* Set COM pins configuration */
406         ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COM_PINS_CONFIG);
407         if (ret < 0)
408                 return ret;
409
410         compins = 0x02 | !par->com_seq << 4 | par->com_lrremap << 5;
411         ret = ssd1307fb_write_cmd(par->client, compins);
412         if (ret < 0)
413                 return ret;
414
415         /* Set VCOMH */
416         ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_VCOMH);
417         if (ret < 0)
418                 return ret;
419
420         ret = ssd1307fb_write_cmd(par->client, par->vcomh);
421         if (ret < 0)
422                 return ret;
423
424         /* Turn on the DC-DC Charge Pump */
425         ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CHARGE_PUMP);
426         if (ret < 0)
427                 return ret;
428
429         ret = ssd1307fb_write_cmd(par->client,
430                 BIT(4) | (par->device_info->need_chargepump ? BIT(2) : 0));
431         if (ret < 0)
432                 return ret;
433
434         /* Set lookup table */
435         if (par->lookup_table_set) {
436                 int i;
437
438                 ret = ssd1307fb_write_cmd(par->client,
439                                           SSD1307FB_SET_LOOKUP_TABLE);
440                 if (ret < 0)
441                         return ret;
442
443                 for (i = 0; i < ARRAY_SIZE(par->lookup_table); ++i) {
444                         u8 val = par->lookup_table[i];
445
446                         if (val < 31 || val > 63)
447                                 dev_warn(&par->client->dev,
448                                          "lookup table index %d value out of range 31 <= %d <= 63\n",
449                                          i, val);
450                         ret = ssd1307fb_write_cmd(par->client, val);
451                         if (ret < 0)
452                                 return ret;
453                 }
454         }
455
456         /* Switch to horizontal addressing mode */
457         ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_ADDRESS_MODE);
458         if (ret < 0)
459                 return ret;
460
461         ret = ssd1307fb_write_cmd(par->client,
462                                   SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL);
463         if (ret < 0)
464                 return ret;
465
466         /* Set column range */
467         ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COL_RANGE);
468         if (ret < 0)
469                 return ret;
470
471         ret = ssd1307fb_write_cmd(par->client, 0x0);
472         if (ret < 0)
473                 return ret;
474
475         ret = ssd1307fb_write_cmd(par->client, par->width - 1);
476         if (ret < 0)
477                 return ret;
478
479         /* Set page range */
480         ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PAGE_RANGE);
481         if (ret < 0)
482                 return ret;
483
484         ret = ssd1307fb_write_cmd(par->client, par->page_offset);
485         if (ret < 0)
486                 return ret;
487
488         ret = ssd1307fb_write_cmd(par->client,
489                                   par->page_offset +
490                                   DIV_ROUND_UP(par->height, 8) - 1);
491         if (ret < 0)
492                 return ret;
493
494         /* Clear the screen */
495         ssd1307fb_update_display(par);
496
497         /* Turn on the display */
498         ret = ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON);
499         if (ret < 0)
500                 return ret;
501
502         return 0;
503 }
504
505 static int ssd1307fb_update_bl(struct backlight_device *bdev)
506 {
507         struct ssd1307fb_par *par = bl_get_data(bdev);
508         int ret;
509         int brightness = bdev->props.brightness;
510
511         par->contrast = brightness;
512
513         ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CONTRAST);
514         if (ret < 0)
515                 return ret;
516         ret = ssd1307fb_write_cmd(par->client, par->contrast);
517         if (ret < 0)
518                 return ret;
519         return 0;
520 }
521
522 static int ssd1307fb_get_brightness(struct backlight_device *bdev)
523 {
524         struct ssd1307fb_par *par = bl_get_data(bdev);
525
526         return par->contrast;
527 }
528
529 static int ssd1307fb_check_fb(struct backlight_device *bdev,
530                                    struct fb_info *info)
531 {
532         return (info->bl_dev == bdev);
533 }
534
535 static const struct backlight_ops ssd1307fb_bl_ops = {
536         .options        = BL_CORE_SUSPENDRESUME,
537         .update_status  = ssd1307fb_update_bl,
538         .get_brightness = ssd1307fb_get_brightness,
539         .check_fb       = ssd1307fb_check_fb,
540 };
541
542 static struct ssd1307fb_deviceinfo ssd1307fb_ssd1305_deviceinfo = {
543         .default_vcomh = 0x34,
544         .default_dclk_div = 1,
545         .default_dclk_frq = 7,
546 };
547
548 static struct ssd1307fb_deviceinfo ssd1307fb_ssd1306_deviceinfo = {
549         .default_vcomh = 0x20,
550         .default_dclk_div = 1,
551         .default_dclk_frq = 8,
552         .need_chargepump = 1,
553 };
554
555 static struct ssd1307fb_deviceinfo ssd1307fb_ssd1307_deviceinfo = {
556         .default_vcomh = 0x20,
557         .default_dclk_div = 2,
558         .default_dclk_frq = 12,
559         .need_pwm = 1,
560 };
561
562 static struct ssd1307fb_deviceinfo ssd1307fb_ssd1309_deviceinfo = {
563         .default_vcomh = 0x34,
564         .default_dclk_div = 1,
565         .default_dclk_frq = 10,
566 };
567
568 static const struct of_device_id ssd1307fb_of_match[] = {
569         {
570                 .compatible = "solomon,ssd1305fb-i2c",
571                 .data = (void *)&ssd1307fb_ssd1305_deviceinfo,
572         },
573         {
574                 .compatible = "solomon,ssd1306fb-i2c",
575                 .data = (void *)&ssd1307fb_ssd1306_deviceinfo,
576         },
577         {
578                 .compatible = "solomon,ssd1307fb-i2c",
579                 .data = (void *)&ssd1307fb_ssd1307_deviceinfo,
580         },
581         {
582                 .compatible = "solomon,ssd1309fb-i2c",
583                 .data = (void *)&ssd1307fb_ssd1309_deviceinfo,
584         },
585         {},
586 };
587 MODULE_DEVICE_TABLE(of, ssd1307fb_of_match);
588
589 static int ssd1307fb_probe(struct i2c_client *client,
590                            const struct i2c_device_id *id)
591 {
592         struct backlight_device *bl;
593         char bl_name[12];
594         struct fb_info *info;
595         struct device_node *node = client->dev.of_node;
596         struct fb_deferred_io *ssd1307fb_defio;
597         u32 vmem_size;
598         struct ssd1307fb_par *par;
599         void *vmem;
600         int ret;
601
602         if (!node) {
603                 dev_err(&client->dev, "No device tree data found!\n");
604                 return -EINVAL;
605         }
606
607         info = framebuffer_alloc(sizeof(struct ssd1307fb_par), &client->dev);
608         if (!info)
609                 return -ENOMEM;
610
611         par = info->par;
612         par->info = info;
613         par->client = client;
614
615         par->device_info = of_device_get_match_data(&client->dev);
616
617         par->reset = devm_gpiod_get_optional(&client->dev, "reset",
618                                              GPIOD_OUT_LOW);
619         if (IS_ERR(par->reset)) {
620                 dev_err(&client->dev, "failed to get reset gpio: %ld\n",
621                         PTR_ERR(par->reset));
622                 ret = PTR_ERR(par->reset);
623                 goto fb_alloc_error;
624         }
625
626         par->vbat_reg = devm_regulator_get_optional(&client->dev, "vbat");
627         if (IS_ERR(par->vbat_reg)) {
628                 ret = PTR_ERR(par->vbat_reg);
629                 if (ret == -ENODEV) {
630                         par->vbat_reg = NULL;
631                 } else {
632                         dev_err(&client->dev, "failed to get VBAT regulator: %d\n",
633                                 ret);
634                         goto fb_alloc_error;
635                 }
636         }
637
638         if (of_property_read_u32(node, "solomon,width", &par->width))
639                 par->width = 96;
640
641         if (of_property_read_u32(node, "solomon,height", &par->height))
642                 par->height = 16;
643
644         if (of_property_read_u32(node, "solomon,page-offset", &par->page_offset))
645                 par->page_offset = 1;
646
647         if (of_property_read_u32(node, "solomon,com-offset", &par->com_offset))
648                 par->com_offset = 0;
649
650         if (of_property_read_u32(node, "solomon,prechargep1", &par->prechargep1))
651                 par->prechargep1 = 2;
652
653         if (of_property_read_u32(node, "solomon,prechargep2", &par->prechargep2))
654                 par->prechargep2 = 2;
655
656         if (!of_property_read_u8_array(node, "solomon,lookup-table",
657                                        par->lookup_table,
658                                        ARRAY_SIZE(par->lookup_table)))
659                 par->lookup_table_set = 1;
660
661         par->seg_remap = !of_property_read_bool(node, "solomon,segment-no-remap");
662         par->com_seq = of_property_read_bool(node, "solomon,com-seq");
663         par->com_lrremap = of_property_read_bool(node, "solomon,com-lrremap");
664         par->com_invdir = of_property_read_bool(node, "solomon,com-invdir");
665         par->area_color_enable =
666                 of_property_read_bool(node, "solomon,area-color-enable");
667         par->low_power = of_property_read_bool(node, "solomon,low-power");
668
669         par->contrast = 127;
670         par->vcomh = par->device_info->default_vcomh;
671
672         /* Setup display timing */
673         if (of_property_read_u32(node, "solomon,dclk-div", &par->dclk_div))
674                 par->dclk_div = par->device_info->default_dclk_div;
675         if (of_property_read_u32(node, "solomon,dclk-frq", &par->dclk_frq))
676                 par->dclk_frq = par->device_info->default_dclk_frq;
677
678         vmem_size = DIV_ROUND_UP(par->width, 8) * par->height;
679
680         vmem = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
681                                         get_order(vmem_size));
682         if (!vmem) {
683                 dev_err(&client->dev, "Couldn't allocate graphical memory.\n");
684                 ret = -ENOMEM;
685                 goto fb_alloc_error;
686         }
687
688         ssd1307fb_defio = devm_kzalloc(&client->dev, sizeof(*ssd1307fb_defio),
689                                        GFP_KERNEL);
690         if (!ssd1307fb_defio) {
691                 dev_err(&client->dev, "Couldn't allocate deferred io.\n");
692                 ret = -ENOMEM;
693                 goto fb_alloc_error;
694         }
695
696         ssd1307fb_defio->delay = HZ / refreshrate;
697         ssd1307fb_defio->deferred_io = ssd1307fb_deferred_io;
698
699         info->fbops = &ssd1307fb_ops;
700         info->fix = ssd1307fb_fix;
701         info->fix.line_length = DIV_ROUND_UP(par->width, 8);
702         info->fbdefio = ssd1307fb_defio;
703
704         info->var = ssd1307fb_var;
705         info->var.xres = par->width;
706         info->var.xres_virtual = par->width;
707         info->var.yres = par->height;
708         info->var.yres_virtual = par->height;
709
710         info->screen_buffer = vmem;
711         info->fix.smem_start = __pa(vmem);
712         info->fix.smem_len = vmem_size;
713
714         fb_deferred_io_init(info);
715
716         i2c_set_clientdata(client, info);
717
718         if (par->reset) {
719                 /* Reset the screen */
720                 gpiod_set_value_cansleep(par->reset, 1);
721                 udelay(4);
722                 gpiod_set_value_cansleep(par->reset, 0);
723                 udelay(4);
724         }
725
726         if (par->vbat_reg) {
727                 ret = regulator_enable(par->vbat_reg);
728                 if (ret) {
729                         dev_err(&client->dev, "failed to enable VBAT: %d\n",
730                                 ret);
731                         goto reset_oled_error;
732                 }
733         }
734
735         ret = ssd1307fb_init(par);
736         if (ret)
737                 goto regulator_enable_error;
738
739         ret = register_framebuffer(info);
740         if (ret) {
741                 dev_err(&client->dev, "Couldn't register the framebuffer\n");
742                 goto panel_init_error;
743         }
744
745         snprintf(bl_name, sizeof(bl_name), "ssd1307fb%d", info->node);
746         bl = backlight_device_register(bl_name, &client->dev, par,
747                                        &ssd1307fb_bl_ops, NULL);
748         if (IS_ERR(bl)) {
749                 ret = PTR_ERR(bl);
750                 dev_err(&client->dev, "unable to register backlight device: %d\n",
751                         ret);
752                 goto bl_init_error;
753         }
754
755         bl->props.brightness = par->contrast;
756         bl->props.max_brightness = MAX_CONTRAST;
757         info->bl_dev = bl;
758
759         dev_info(&client->dev, "fb%d: %s framebuffer device registered, using %d bytes of video memory\n", info->node, info->fix.id, vmem_size);
760
761         return 0;
762
763 bl_init_error:
764         unregister_framebuffer(info);
765 panel_init_error:
766         if (par->device_info->need_pwm) {
767                 pwm_disable(par->pwm);
768                 pwm_put(par->pwm);
769         }
770 regulator_enable_error:
771         if (par->vbat_reg)
772                 regulator_disable(par->vbat_reg);
773 reset_oled_error:
774         fb_deferred_io_cleanup(info);
775 fb_alloc_error:
776         framebuffer_release(info);
777         return ret;
778 }
779
780 static int ssd1307fb_remove(struct i2c_client *client)
781 {
782         struct fb_info *info = i2c_get_clientdata(client);
783         struct ssd1307fb_par *par = info->par;
784
785         ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_OFF);
786
787         backlight_device_unregister(info->bl_dev);
788
789         unregister_framebuffer(info);
790         if (par->device_info->need_pwm) {
791                 pwm_disable(par->pwm);
792                 pwm_put(par->pwm);
793         }
794         fb_deferred_io_cleanup(info);
795         __free_pages(__va(info->fix.smem_start), get_order(info->fix.smem_len));
796         framebuffer_release(info);
797
798         return 0;
799 }
800
801 static const struct i2c_device_id ssd1307fb_i2c_id[] = {
802         { "ssd1305fb", 0 },
803         { "ssd1306fb", 0 },
804         { "ssd1307fb", 0 },
805         { "ssd1309fb", 0 },
806         { }
807 };
808 MODULE_DEVICE_TABLE(i2c, ssd1307fb_i2c_id);
809
810 static struct i2c_driver ssd1307fb_driver = {
811         .probe = ssd1307fb_probe,
812         .remove = ssd1307fb_remove,
813         .id_table = ssd1307fb_i2c_id,
814         .driver = {
815                 .name = "ssd1307fb",
816                 .of_match_table = ssd1307fb_of_match,
817         },
818 };
819
820 module_i2c_driver(ssd1307fb_driver);
821
822 MODULE_DESCRIPTION("FB driver for the Solomon SSD1307 OLED controller");
823 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
824 MODULE_LICENSE("GPL");