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(*ssd1307fb_defio), 632 GFP_KERNEL); 633 if (!ssd1307fb_defio) { 634 dev_err(&client->dev, "Couldn't allocate deferred io.\n"); 635 ret = -ENOMEM; 636 goto fb_alloc_error; 637 } 638 639 ssd1307fb_defio->delay = HZ / refreshrate; 640 ssd1307fb_defio->deferred_io = ssd1307fb_deferred_io; 641 642 info->fbops = &ssd1307fb_ops; 643 info->fix = ssd1307fb_fix; 644 info->fix.line_length = par->width / 8; 645 info->fbdefio = ssd1307fb_defio; 646 647 info->var = ssd1307fb_var; 648 info->var.xres = par->width; 649 info->var.xres_virtual = par->width; 650 info->var.yres = par->height; 651 info->var.yres_virtual = par->height; 652 653 info->var.red.length = 1; 654 info->var.red.offset = 0; 655 info->var.green.length = 1; 656 info->var.green.offset = 0; 657 info->var.blue.length = 1; 658 info->var.blue.offset = 0; 659 660 info->screen_base = (u8 __force __iomem *)vmem; 661 info->fix.smem_start = __pa(vmem); 662 info->fix.smem_len = vmem_size; 663 664 fb_deferred_io_init(info); 665 666 i2c_set_clientdata(client, info); 667 668 if (par->reset) { 669 /* Reset the screen */ 670 gpiod_set_value_cansleep(par->reset, 1); 671 udelay(4); 672 gpiod_set_value_cansleep(par->reset, 0); 673 udelay(4); 674 } 675 676 if (par->vbat_reg) { 677 ret = regulator_enable(par->vbat_reg); 678 if (ret) { 679 dev_err(&client->dev, "failed to enable VBAT: %d\n", 680 ret); 681 goto reset_oled_error; 682 } 683 } 684 685 ret = ssd1307fb_init(par); 686 if (ret) 687 goto regulator_enable_error; 688 689 ret = register_framebuffer(info); 690 if (ret) { 691 dev_err(&client->dev, "Couldn't register the framebuffer\n"); 692 goto panel_init_error; 693 } 694 695 snprintf(bl_name, sizeof(bl_name), "ssd1307fb%d", info->node); 696 bl = backlight_device_register(bl_name, &client->dev, par, 697 &ssd1307fb_bl_ops, NULL); 698 if (IS_ERR(bl)) { 699 ret = PTR_ERR(bl); 700 dev_err(&client->dev, "unable to register backlight device: %d\n", 701 ret); 702 goto bl_init_error; 703 } 704 705 bl->props.brightness = par->contrast; 706 bl->props.max_brightness = MAX_CONTRAST; 707 info->bl_dev = bl; 708 709 dev_info(&client->dev, "fb%d: %s framebuffer device registered, using %d bytes of video memory\n", info->node, info->fix.id, vmem_size); 710 711 return 0; 712 713 bl_init_error: 714 unregister_framebuffer(info); 715 panel_init_error: 716 if (par->device_info->need_pwm) { 717 pwm_disable(par->pwm); 718 pwm_put(par->pwm); 719 }; 720 regulator_enable_error: 721 if (par->vbat_reg) 722 regulator_disable(par->vbat_reg); 723 reset_oled_error: 724 fb_deferred_io_cleanup(info); 725 fb_alloc_error: 726 framebuffer_release(info); 727 return ret; 728 } 729 730 static int ssd1307fb_remove(struct i2c_client *client) 731 { 732 struct fb_info *info = i2c_get_clientdata(client); 733 struct ssd1307fb_par *par = info->par; 734 735 ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_OFF); 736 737 backlight_device_unregister(info->bl_dev); 738 739 unregister_framebuffer(info); 740 if (par->device_info->need_pwm) { 741 pwm_disable(par->pwm); 742 pwm_put(par->pwm); 743 }; 744 fb_deferred_io_cleanup(info); 745 __free_pages(__va(info->fix.smem_start), get_order(info->fix.smem_len)); 746 framebuffer_release(info); 747 748 return 0; 749 } 750 751 static const struct i2c_device_id ssd1307fb_i2c_id[] = { 752 { "ssd1305fb", 0 }, 753 { "ssd1306fb", 0 }, 754 { "ssd1307fb", 0 }, 755 { "ssd1309fb", 0 }, 756 { } 757 }; 758 MODULE_DEVICE_TABLE(i2c, ssd1307fb_i2c_id); 759 760 static struct i2c_driver ssd1307fb_driver = { 761 .probe = ssd1307fb_probe, 762 .remove = ssd1307fb_remove, 763 .id_table = ssd1307fb_i2c_id, 764 .driver = { 765 .name = "ssd1307fb", 766 .of_match_table = ssd1307fb_of_match, 767 }, 768 }; 769 770 module_i2c_driver(ssd1307fb_driver); 771 772 MODULE_DESCRIPTION("FB driver for the Solomon SSD1307 OLED controller"); 773 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); 774 MODULE_LICENSE("GPL"); 775