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