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