linux/drivers/video/fbdev/ssd1307fb.c
<<
>>
Prefs
   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
  48static u_int refreshrate = REFRESHRATE;
  49module_param(refreshrate, uint, 0);
  50
  51struct ssd1307fb_par;
  52
  53struct 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
  61struct 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
  85struct ssd1307fb_array {
  86        u8      type;
  87        u8      data[0];
  88};
  89
  90static 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
 100static const struct fb_var_screeninfo ssd1307fb_var = {
 101        .bits_per_pixel = 1,
 102};
 103
 104static 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
 117static 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
 133static 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
 150static 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
 210static 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
 241static 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
 251static 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
 258static 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
 265static 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
 272static 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
 282static void ssd1307fb_deferred_io(struct fb_info *info,
 283                                struct list_head *pagelist)
 284{
 285        ssd1307fb_update_display(info->par);
 286}
 287
 288static 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, par->page_offset);
 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
 456static 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
 473static 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
 480static int ssd1307fb_check_fb(struct backlight_device *bdev,
 481                                   struct fb_info *info)
 482{
 483        return (info->bl_dev == bdev);
 484}
 485
 486static 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
 493static struct ssd1307fb_deviceinfo ssd1307fb_ssd1305_deviceinfo = {
 494        .default_vcomh = 0x34,
 495        .default_dclk_div = 1,
 496        .default_dclk_frq = 7,
 497};
 498
 499static 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
 506static 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
 513static struct ssd1307fb_deviceinfo ssd1307fb_ssd1309_deviceinfo = {
 514        .default_vcomh = 0x34,
 515        .default_dclk_div = 1,
 516        .default_dclk_frq = 10,
 517};
 518
 519static 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};
 538MODULE_DEVICE_TABLE(of, ssd1307fb_of_match);
 539
 540static 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(par->reset, 0);
 671                udelay(4);
 672                gpiod_set_value(par->reset, 1);
 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
 713bl_init_error:
 714        unregister_framebuffer(info);
 715panel_init_error:
 716        if (par->device_info->need_pwm) {
 717                pwm_disable(par->pwm);
 718                pwm_put(par->pwm);
 719        };
 720regulator_enable_error:
 721        if (par->vbat_reg)
 722                regulator_disable(par->vbat_reg);
 723reset_oled_error:
 724        fb_deferred_io_cleanup(info);
 725fb_alloc_error:
 726        framebuffer_release(info);
 727        return ret;
 728}
 729
 730static 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
 751static const struct i2c_device_id ssd1307fb_i2c_id[] = {
 752        { "ssd1305fb", 0 },
 753        { "ssd1306fb", 0 },
 754        { "ssd1307fb", 0 },
 755        { "ssd1309fb", 0 },
 756        { }
 757};
 758MODULE_DEVICE_TABLE(i2c, ssd1307fb_i2c_id);
 759
 760static 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
 770module_i2c_driver(ssd1307fb_driver);
 771
 772MODULE_DESCRIPTION("FB driver for the Solomon SSD1307 OLED controller");
 773MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
 774MODULE_LICENSE("GPL");
 775