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