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