This source file includes following definitions.
- ssd1307fb_alloc_array
- ssd1307fb_write_array
- ssd1307fb_write_cmd
- ssd1307fb_update_display
- ssd1307fb_write
- ssd1307fb_blank
- ssd1307fb_fillrect
- ssd1307fb_copyarea
- ssd1307fb_imageblit
- ssd1307fb_deferred_io
- ssd1307fb_init
- ssd1307fb_update_bl
- ssd1307fb_get_brightness
- ssd1307fb_check_fb
- ssd1307fb_probe
- ssd1307fb_remove
1
2
3
4
5
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
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
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
314
315
316 pwm_apply_args(par->pwm);
317
318 pwm_get_args(par->pwm, &pargs);
319
320 par->pwm_period = pargs.period;
321
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
495 ssd1307fb_update_display(par);
496
497
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
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
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");