linux/drivers/staging/fbtft/flexfb.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Generic FB driver for TFT LCD displays
   4 *
   5 * Copyright (C) 2013 Noralf Tronnes
   6 */
   7
   8#include <linux/module.h>
   9#include <linux/kernel.h>
  10#include <linux/init.h>
  11#include <linux/vmalloc.h>
  12#include <linux/gpio/consumer.h>
  13#include <linux/spi/spi.h>
  14#include <linux/delay.h>
  15
  16#include "fbtft.h"
  17
  18#define DRVNAME     "flexfb"
  19
  20static char *chip;
  21module_param(chip, charp, 0000);
  22MODULE_PARM_DESC(chip, "LCD controller");
  23
  24static unsigned int width;
  25module_param(width, uint, 0000);
  26MODULE_PARM_DESC(width, "Display width");
  27
  28static unsigned int height;
  29module_param(height, uint, 0000);
  30MODULE_PARM_DESC(height, "Display height");
  31
  32static s16 init[512];
  33static int init_num;
  34module_param_array(init, short, &init_num, 0000);
  35MODULE_PARM_DESC(init, "Init sequence");
  36
  37static unsigned int setaddrwin;
  38module_param(setaddrwin, uint, 0000);
  39MODULE_PARM_DESC(setaddrwin, "Which set_addr_win() implementation to use");
  40
  41static unsigned int buswidth = 8;
  42module_param(buswidth, uint, 0000);
  43MODULE_PARM_DESC(buswidth, "Width of databus (default: 8)");
  44
  45static unsigned int regwidth = 8;
  46module_param(regwidth, uint, 0000);
  47MODULE_PARM_DESC(regwidth, "Width of controller register (default: 8)");
  48
  49static bool nobacklight;
  50module_param(nobacklight, bool, 0000);
  51MODULE_PARM_DESC(nobacklight, "Turn off backlight functionality.");
  52
  53static bool latched;
  54module_param(latched, bool, 0000);
  55MODULE_PARM_DESC(latched, "Use with latched 16-bit databus");
  56
  57static const s16 *initp;
  58static int initp_num;
  59
  60/* default init sequences */
  61static const s16 st7735r_init[] = {
  62        -1, 0x01,
  63        -2, 150,
  64        -1, 0x11,
  65        -2, 500,
  66        -1, 0xB1, 0x01, 0x2C, 0x2D,
  67        -1, 0xB2, 0x01, 0x2C, 0x2D,
  68        -1, 0xB3, 0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D,
  69        -1, 0xB4, 0x07,
  70        -1, 0xC0, 0xA2, 0x02, 0x84,
  71        -1, 0xC1, 0xC5,
  72        -1, 0xC2, 0x0A, 0x00,
  73        -1, 0xC3, 0x8A, 0x2A,
  74        -1, 0xC4, 0x8A, 0xEE,
  75        -1, 0xC5, 0x0E,
  76        -1, 0x20,
  77        -1, 0x36, 0xC0,
  78        -1, 0x3A, 0x05,
  79        -1, 0xE0, 0x0f, 0x1a, 0x0f, 0x18, 0x2f, 0x28, 0x20, 0x22,
  80            0x1f, 0x1b, 0x23, 0x37, 0x00, 0x07, 0x02, 0x10,
  81        -1, 0xE1, 0x0f, 0x1b, 0x0f, 0x17, 0x33, 0x2c, 0x29, 0x2e,
  82            0x30, 0x30, 0x39, 0x3f, 0x00, 0x07, 0x03, 0x10,
  83        -1, 0x29,
  84        -2, 100,
  85        -1, 0x13,
  86        -2, 10,
  87        -3
  88};
  89
  90static const s16 ssd1289_init[] = {
  91        -1, 0x00, 0x0001,
  92        -1, 0x03, 0xA8A4,
  93        -1, 0x0C, 0x0000,
  94        -1, 0x0D, 0x080C,
  95        -1, 0x0E, 0x2B00,
  96        -1, 0x1E, 0x00B7,
  97        -1, 0x01, 0x2B3F,
  98        -1, 0x02, 0x0600,
  99        -1, 0x10, 0x0000,
 100        -1, 0x11, 0x6070,
 101        -1, 0x05, 0x0000,
 102        -1, 0x06, 0x0000,
 103        -1, 0x16, 0xEF1C,
 104        -1, 0x17, 0x0003,
 105        -1, 0x07, 0x0233,
 106        -1, 0x0B, 0x0000,
 107        -1, 0x0F, 0x0000,
 108        -1, 0x41, 0x0000,
 109        -1, 0x42, 0x0000,
 110        -1, 0x48, 0x0000,
 111        -1, 0x49, 0x013F,
 112        -1, 0x4A, 0x0000,
 113        -1, 0x4B, 0x0000,
 114        -1, 0x44, 0xEF00,
 115        -1, 0x45, 0x0000,
 116        -1, 0x46, 0x013F,
 117        -1, 0x30, 0x0707,
 118        -1, 0x31, 0x0204,
 119        -1, 0x32, 0x0204,
 120        -1, 0x33, 0x0502,
 121        -1, 0x34, 0x0507,
 122        -1, 0x35, 0x0204,
 123        -1, 0x36, 0x0204,
 124        -1, 0x37, 0x0502,
 125        -1, 0x3A, 0x0302,
 126        -1, 0x3B, 0x0302,
 127        -1, 0x23, 0x0000,
 128        -1, 0x24, 0x0000,
 129        -1, 0x25, 0x8000,
 130        -1, 0x4f, 0x0000,
 131        -1, 0x4e, 0x0000,
 132        -1, 0x22,
 133        -3
 134};
 135
 136static const s16 hx8340bn_init[] = {
 137        -1, 0xC1, 0xFF, 0x83, 0x40,
 138        -1, 0x11,
 139        -2, 150,
 140        -1, 0xCA, 0x70, 0x00, 0xD9,
 141        -1, 0xB0, 0x01, 0x11,
 142        -1, 0xC9, 0x90, 0x49, 0x10, 0x28, 0x28, 0x10, 0x00, 0x06,
 143        -2, 20,
 144        -1, 0xC2, 0x60, 0x71, 0x01, 0x0E, 0x05, 0x02, 0x09, 0x31, 0x0A,
 145        -1, 0xC3, 0x67, 0x30, 0x61, 0x17, 0x48, 0x07, 0x05, 0x33,
 146        -2, 10,
 147        -1, 0xB5, 0x35, 0x20, 0x45,
 148        -1, 0xB4, 0x33, 0x25, 0x4C,
 149        -2, 10,
 150        -1, 0x3A, 0x05,
 151        -1, 0x29,
 152        -2, 10,
 153        -3
 154};
 155
 156static const s16 ili9225_init[] = {
 157        -1, 0x0001, 0x011C,
 158        -1, 0x0002, 0x0100,
 159        -1, 0x0003, 0x1030,
 160        -1, 0x0008, 0x0808,
 161        -1, 0x000C, 0x0000,
 162        -1, 0x000F, 0x0A01,
 163        -1, 0x0020, 0x0000,
 164        -1, 0x0021, 0x0000,
 165        -2, 50,
 166        -1, 0x0010, 0x0A00,
 167        -1, 0x0011, 0x1038,
 168        -2, 50,
 169        -1, 0x0012, 0x1121,
 170        -1, 0x0013, 0x004E,
 171        -1, 0x0014, 0x676F,
 172        -1, 0x0030, 0x0000,
 173        -1, 0x0031, 0x00DB,
 174        -1, 0x0032, 0x0000,
 175        -1, 0x0033, 0x0000,
 176        -1, 0x0034, 0x00DB,
 177        -1, 0x0035, 0x0000,
 178        -1, 0x0036, 0x00AF,
 179        -1, 0x0037, 0x0000,
 180        -1, 0x0038, 0x00DB,
 181        -1, 0x0039, 0x0000,
 182        -1, 0x0050, 0x0000,
 183        -1, 0x0051, 0x060A,
 184        -1, 0x0052, 0x0D0A,
 185        -1, 0x0053, 0x0303,
 186        -1, 0x0054, 0x0A0D,
 187        -1, 0x0055, 0x0A06,
 188        -1, 0x0056, 0x0000,
 189        -1, 0x0057, 0x0303,
 190        -1, 0x0058, 0x0000,
 191        -1, 0x0059, 0x0000,
 192        -2, 50,
 193        -1, 0x0007, 0x1017,
 194        -2, 50,
 195        -3
 196};
 197
 198static const s16 ili9320_init[] = {
 199        -1, 0x00E5, 0x8000,
 200        -1, 0x0000, 0x0001,
 201        -1, 0x0001, 0x0100,
 202        -1, 0x0002, 0x0700,
 203        -1, 0x0003, 0x1030,
 204        -1, 0x0004, 0x0000,
 205        -1, 0x0008, 0x0202,
 206        -1, 0x0009, 0x0000,
 207        -1, 0x000A, 0x0000,
 208        -1, 0x000C, 0x0000,
 209        -1, 0x000D, 0x0000,
 210        -1, 0x000F, 0x0000,
 211        -1, 0x0010, 0x0000,
 212        -1, 0x0011, 0x0007,
 213        -1, 0x0012, 0x0000,
 214        -1, 0x0013, 0x0000,
 215        -2, 200,
 216        -1, 0x0010, 0x17B0,
 217        -1, 0x0011, 0x0031,
 218        -2, 50,
 219        -1, 0x0012, 0x0138,
 220        -2, 50,
 221        -1, 0x0013, 0x1800,
 222        -1, 0x0029, 0x0008,
 223        -2, 50,
 224        -1, 0x0020, 0x0000,
 225        -1, 0x0021, 0x0000,
 226        -1, 0x0030, 0x0000,
 227        -1, 0x0031, 0x0505,
 228        -1, 0x0032, 0x0004,
 229        -1, 0x0035, 0x0006,
 230        -1, 0x0036, 0x0707,
 231        -1, 0x0037, 0x0105,
 232        -1, 0x0038, 0x0002,
 233        -1, 0x0039, 0x0707,
 234        -1, 0x003C, 0x0704,
 235        -1, 0x003D, 0x0807,
 236        -1, 0x0050, 0x0000,
 237        -1, 0x0051, 0x00EF,
 238        -1, 0x0052, 0x0000,
 239        -1, 0x0053, 0x013F,
 240        -1, 0x0060, 0x2700,
 241        -1, 0x0061, 0x0001,
 242        -1, 0x006A, 0x0000,
 243        -1, 0x0080, 0x0000,
 244        -1, 0x0081, 0x0000,
 245        -1, 0x0082, 0x0000,
 246        -1, 0x0083, 0x0000,
 247        -1, 0x0084, 0x0000,
 248        -1, 0x0085, 0x0000,
 249        -1, 0x0090, 0x0010,
 250        -1, 0x0092, 0x0000,
 251        -1, 0x0093, 0x0003,
 252        -1, 0x0095, 0x0110,
 253        -1, 0x0097, 0x0000,
 254        -1, 0x0098, 0x0000,
 255        -1, 0x0007, 0x0173,
 256        -3
 257};
 258
 259static const s16 ili9325_init[] = {
 260        -1, 0x00E3, 0x3008,
 261        -1, 0x00E7, 0x0012,
 262        -1, 0x00EF, 0x1231,
 263        -1, 0x0001, 0x0100,
 264        -1, 0x0002, 0x0700,
 265        -1, 0x0003, 0x1030,
 266        -1, 0x0004, 0x0000,
 267        -1, 0x0008, 0x0207,
 268        -1, 0x0009, 0x0000,
 269        -1, 0x000A, 0x0000,
 270        -1, 0x000C, 0x0000,
 271        -1, 0x000D, 0x0000,
 272        -1, 0x000F, 0x0000,
 273        -1, 0x0010, 0x0000,
 274        -1, 0x0011, 0x0007,
 275        -1, 0x0012, 0x0000,
 276        -1, 0x0013, 0x0000,
 277        -2, 200,
 278        -1, 0x0010, 0x1690,
 279        -1, 0x0011, 0x0223,
 280        -2, 50,
 281        -1, 0x0012, 0x000D,
 282        -2, 50,
 283        -1, 0x0013, 0x1200,
 284        -1, 0x0029, 0x000A,
 285        -1, 0x002B, 0x000C,
 286        -2, 50,
 287        -1, 0x0020, 0x0000,
 288        -1, 0x0021, 0x0000,
 289        -1, 0x0030, 0x0000,
 290        -1, 0x0031, 0x0506,
 291        -1, 0x0032, 0x0104,
 292        -1, 0x0035, 0x0207,
 293        -1, 0x0036, 0x000F,
 294        -1, 0x0037, 0x0306,
 295        -1, 0x0038, 0x0102,
 296        -1, 0x0039, 0x0707,
 297        -1, 0x003C, 0x0702,
 298        -1, 0x003D, 0x1604,
 299        -1, 0x0050, 0x0000,
 300        -1, 0x0051, 0x00EF,
 301        -1, 0x0052, 0x0000,
 302        -1, 0x0053, 0x013F,
 303        -1, 0x0060, 0xA700,
 304        -1, 0x0061, 0x0001,
 305        -1, 0x006A, 0x0000,
 306        -1, 0x0080, 0x0000,
 307        -1, 0x0081, 0x0000,
 308        -1, 0x0082, 0x0000,
 309        -1, 0x0083, 0x0000,
 310        -1, 0x0084, 0x0000,
 311        -1, 0x0085, 0x0000,
 312        -1, 0x0090, 0x0010,
 313        -1, 0x0092, 0x0600,
 314        -1, 0x0007, 0x0133,
 315        -3
 316};
 317
 318static const s16 ili9341_init[] = {
 319        -1, 0x28,
 320        -2, 20,
 321        -1, 0xCF, 0x00, 0x83, 0x30,
 322        -1, 0xED, 0x64, 0x03, 0x12, 0x81,
 323        -1, 0xE8, 0x85, 0x01, 0x79,
 324        -1, 0xCB, 0x39, 0x2c, 0x00, 0x34, 0x02,
 325        -1, 0xF7, 0x20,
 326        -1, 0xEA, 0x00, 0x00,
 327        -1, 0xC0, 0x26,
 328        -1, 0xC1, 0x11,
 329        -1, 0xC5, 0x35, 0x3E,
 330        -1, 0xC7, 0xBE,
 331        -1, 0xB1, 0x00, 0x1B,
 332        -1, 0xB6, 0x0a, 0x82, 0x27, 0x00,
 333        -1, 0xB7, 0x07,
 334        -1, 0x3A, 0x55,
 335        -1, 0x36, 0x48,
 336        -1, 0x11,
 337        -2, 120,
 338        -1, 0x29,
 339        -2, 20,
 340        -3
 341};
 342
 343static const s16 ssd1351_init[] = {
 344        -1, 0xfd, 0x12,
 345        -1, 0xfd, 0xb1,
 346        -1, 0xae,
 347        -1, 0xb3, 0xf1,
 348        -1, 0xca, 0x7f,
 349        -1, 0xa0, 0x74,
 350        -1, 0x15, 0x00, 0x7f,
 351        -1, 0x75, 0x00, 0x7f,
 352        -1, 0xa1, 0x00,
 353        -1, 0xa2, 0x00,
 354        -1, 0xb5, 0x00,
 355        -1, 0xab, 0x01,
 356        -1, 0xb1, 0x32,
 357        -1, 0xb4, 0xa0, 0xb5, 0x55,
 358        -1, 0xbb, 0x17,
 359        -1, 0xbe, 0x05,
 360        -1, 0xc1, 0xc8, 0x80, 0xc8,
 361        -1, 0xc7, 0x0f,
 362        -1, 0xb6, 0x01,
 363        -1, 0xa6,
 364        -1, 0xaf,
 365        -3
 366};
 367
 368/**
 369 * struct flexfb_lcd_controller - Describes the LCD controller properties
 370 * @name: Model name of the chip
 371 * @width: Width of display in pixels
 372 * @height: Height of display in pixels
 373 * @setaddrwin: Which set_addr_win() implementation to use
 374 * @regwidth: LCD Controller Register width in bits
 375 * @init_seq: LCD initialization sequence
 376 * @init_seq_sz: Size of LCD initialization sequence
 377 */
 378struct flexfb_lcd_controller {
 379        const char *name;
 380        unsigned int width;
 381        unsigned int height;
 382        unsigned int setaddrwin;
 383        unsigned int regwidth;
 384        const s16 *init_seq;
 385        int init_seq_sz;
 386};
 387
 388static const struct flexfb_lcd_controller flexfb_chip_table[] = {
 389        {
 390                .name = "st7735r",
 391                .width = 120,
 392                .height = 160,
 393                .init_seq = st7735r_init,
 394                .init_seq_sz = ARRAY_SIZE(st7735r_init),
 395        },
 396        {
 397                .name = "hx8340bn",
 398                .width = 176,
 399                .height = 220,
 400                .init_seq = hx8340bn_init,
 401                .init_seq_sz = ARRAY_SIZE(hx8340bn_init),
 402        },
 403        {
 404                .name = "ili9225",
 405                .width = 176,
 406                .height = 220,
 407                .regwidth = 16,
 408                .init_seq = ili9225_init,
 409                .init_seq_sz = ARRAY_SIZE(ili9225_init),
 410        },
 411        {
 412                .name = "ili9320",
 413                .width = 240,
 414                .height = 320,
 415                .setaddrwin = 1,
 416                .regwidth = 16,
 417                .init_seq = ili9320_init,
 418                .init_seq_sz = ARRAY_SIZE(ili9320_init),
 419        },
 420        {
 421                .name = "ili9325",
 422                .width = 240,
 423                .height = 320,
 424                .setaddrwin = 1,
 425                .regwidth = 16,
 426                .init_seq = ili9325_init,
 427                .init_seq_sz = ARRAY_SIZE(ili9325_init),
 428        },
 429        {
 430                .name = "ili9341",
 431                .width = 240,
 432                .height = 320,
 433                .init_seq = ili9341_init,
 434                .init_seq_sz = ARRAY_SIZE(ili9341_init),
 435        },
 436        {
 437                .name = "ssd1289",
 438                .width = 240,
 439                .height = 320,
 440                .setaddrwin = 2,
 441                .regwidth = 16,
 442                .init_seq = ssd1289_init,
 443                .init_seq_sz = ARRAY_SIZE(ssd1289_init),
 444        },
 445        {
 446                .name = "ssd1351",
 447                .width = 128,
 448                .height = 128,
 449                .setaddrwin = 3,
 450                .init_seq = ssd1351_init,
 451                .init_seq_sz = ARRAY_SIZE(ssd1351_init),
 452        },
 453};
 454
 455/* ili9320, ili9325 */
 456static void flexfb_set_addr_win_1(struct fbtft_par *par,
 457                                  int xs, int ys, int xe, int ye)
 458{
 459        switch (par->info->var.rotate) {
 460        /* R20h = Horizontal GRAM Start Address */
 461        /* R21h = Vertical GRAM Start Address */
 462        case 0:
 463                write_reg(par, 0x0020, xs);
 464                write_reg(par, 0x0021, ys);
 465                break;
 466        case 180:
 467                write_reg(par, 0x0020, width - 1 - xs);
 468                write_reg(par, 0x0021, height - 1 - ys);
 469                break;
 470        case 270:
 471                write_reg(par, 0x0020, width - 1 - ys);
 472                write_reg(par, 0x0021, xs);
 473                break;
 474        case 90:
 475                write_reg(par, 0x0020, ys);
 476                write_reg(par, 0x0021, height - 1 - xs);
 477                break;
 478        }
 479        write_reg(par, 0x0022); /* Write Data to GRAM */
 480}
 481
 482/* ssd1289 */
 483static void flexfb_set_addr_win_2(struct fbtft_par *par,
 484                                  int xs, int ys, int xe, int ye)
 485{
 486        switch (par->info->var.rotate) {
 487        /* R4Eh - Set GDDRAM X address counter */
 488        /* R4Fh - Set GDDRAM Y address counter */
 489        case 0:
 490                write_reg(par, 0x4e, xs);
 491                write_reg(par, 0x4f, ys);
 492                break;
 493        case 180:
 494                write_reg(par, 0x4e, par->info->var.xres - 1 - xs);
 495                write_reg(par, 0x4f, par->info->var.yres - 1 - ys);
 496                break;
 497        case 270:
 498                write_reg(par, 0x4e, par->info->var.yres - 1 - ys);
 499                write_reg(par, 0x4f, xs);
 500                break;
 501        case 90:
 502                write_reg(par, 0x4e, ys);
 503                write_reg(par, 0x4f, par->info->var.xres - 1 - xs);
 504                break;
 505        }
 506
 507        /* R22h - RAM data write */
 508        write_reg(par, 0x22, 0);
 509}
 510
 511/* ssd1351 */
 512static void set_addr_win_3(struct fbtft_par *par,
 513                           int xs, int ys, int xe, int ye)
 514{
 515        write_reg(par, 0x15, xs, xe);
 516        write_reg(par, 0x75, ys, ye);
 517        write_reg(par, 0x5C);
 518}
 519
 520static int flexfb_verify_gpios_dc(struct fbtft_par *par)
 521{
 522        fbtft_par_dbg(DEBUG_VERIFY_GPIOS, par, "%s()\n", __func__);
 523
 524        if (!par->gpio.dc) {
 525                dev_err(par->info->device,
 526                        "Missing info about 'dc' gpio. Aborting.\n");
 527                return -EINVAL;
 528        }
 529
 530        return 0;
 531}
 532
 533static int flexfb_verify_gpios_db(struct fbtft_par *par)
 534{
 535        int i;
 536        int num_db = buswidth;
 537
 538        fbtft_par_dbg(DEBUG_VERIFY_GPIOS, par, "%s()\n", __func__);
 539
 540        if (!par->gpio.dc) {
 541                dev_err(par->info->device, "Missing info about 'dc' gpio. Aborting.\n");
 542                return -EINVAL;
 543        }
 544        if (!par->gpio.wr) {
 545                dev_err(par->info->device, "Missing info about 'wr' gpio. Aborting.\n");
 546                return -EINVAL;
 547        }
 548        if (latched && !par->gpio.latch) {
 549                dev_err(par->info->device, "Missing info about 'latch' gpio. Aborting.\n");
 550                return -EINVAL;
 551        }
 552        if (latched)
 553                num_db = buswidth / 2;
 554        for (i = 0; i < num_db; i++) {
 555                if (!par->gpio.db[i]) {
 556                        dev_err(par->info->device,
 557                                "Missing info about 'db%02d' gpio. Aborting.\n",
 558                                i);
 559                        return -EINVAL;
 560                }
 561        }
 562
 563        return 0;
 564}
 565
 566static void flexfb_chip_load_param(const struct flexfb_lcd_controller *chip)
 567{
 568        if (!width)
 569                width = chip->width;
 570        if (!height)
 571                height = chip->height;
 572        setaddrwin = chip->setaddrwin;
 573        if (chip->regwidth)
 574                regwidth = chip->regwidth;
 575        if (!init_num) {
 576                initp = chip->init_seq;
 577                initp_num = chip->init_seq_sz;
 578        }
 579}
 580
 581static struct fbtft_display flex_display = { };
 582
 583static int flexfb_chip_init(const struct device *dev)
 584{
 585        int i;
 586
 587        for (i = 0; i < ARRAY_SIZE(flexfb_chip_table); i++)
 588                if (!strcmp(chip, flexfb_chip_table[i].name)) {
 589                        flexfb_chip_load_param(&flexfb_chip_table[i]);
 590                        return 0;
 591                }
 592
 593        dev_err(dev, "chip=%s is not supported\n", chip);
 594
 595        return -EINVAL;
 596}
 597
 598static int flexfb_probe_common(struct spi_device *sdev,
 599                               struct platform_device *pdev)
 600{
 601        struct device *dev;
 602        struct fb_info *info;
 603        struct fbtft_par *par;
 604        int ret;
 605
 606        initp = init;
 607        initp_num = init_num;
 608
 609        if (sdev)
 610                dev = &sdev->dev;
 611        else
 612                dev = &pdev->dev;
 613
 614        fbtft_init_dbg(dev, "%s(%s)\n", __func__,
 615                       sdev ? "'SPI device'" : "'Platform device'");
 616
 617        if (chip) {
 618                ret = flexfb_chip_init(dev);
 619                if (ret)
 620                        return ret;
 621        }
 622
 623        if (width == 0 || height == 0) {
 624                dev_err(dev, "argument(s) missing: width and height has to be set.\n");
 625                return -EINVAL;
 626        }
 627        flex_display.width = width;
 628        flex_display.height = height;
 629        fbtft_init_dbg(dev, "Display resolution: %dx%d\n", width, height);
 630        fbtft_init_dbg(dev, "chip = %s\n", chip ? chip : "not set");
 631        fbtft_init_dbg(dev, "setaddrwin = %d\n", setaddrwin);
 632        fbtft_init_dbg(dev, "regwidth = %d\n", regwidth);
 633        fbtft_init_dbg(dev, "buswidth = %d\n", buswidth);
 634
 635        info = fbtft_framebuffer_alloc(&flex_display, dev, dev->platform_data);
 636        if (!info)
 637                return -ENOMEM;
 638
 639        par = info->par;
 640        if (sdev)
 641                par->spi = sdev;
 642        else
 643                par->pdev = pdev;
 644        if (!par->init_sequence)
 645                par->init_sequence = initp;
 646        par->fbtftops.init_display = fbtft_init_display;
 647
 648        /* registerwrite functions */
 649        switch (regwidth) {
 650        case 8:
 651                par->fbtftops.write_register = fbtft_write_reg8_bus8;
 652                break;
 653        case 16:
 654                par->fbtftops.write_register = fbtft_write_reg16_bus8;
 655                break;
 656        default:
 657                dev_err(dev,
 658                        "argument 'regwidth': %d is not supported.\n",
 659                        regwidth);
 660                return -EINVAL;
 661        }
 662
 663        /* bus functions */
 664        if (sdev) {
 665                par->fbtftops.write = fbtft_write_spi;
 666                switch (buswidth) {
 667                case 8:
 668                        par->fbtftops.write_vmem = fbtft_write_vmem16_bus8;
 669                        if (!par->startbyte)
 670                                par->fbtftops.verify_gpios = flexfb_verify_gpios_dc;
 671                        break;
 672                case 9:
 673                        if (regwidth == 16) {
 674                                dev_err(dev, "argument 'regwidth': %d is not supported with buswidth=%d and SPI.\n",
 675                                        regwidth, buswidth);
 676                                return -EINVAL;
 677                        }
 678                        par->fbtftops.write_register = fbtft_write_reg8_bus9;
 679                        par->fbtftops.write_vmem = fbtft_write_vmem16_bus9;
 680                        if (par->spi->master->bits_per_word_mask
 681                            & SPI_BPW_MASK(9)) {
 682                                par->spi->bits_per_word = 9;
 683                                break;
 684                        }
 685
 686                        dev_warn(dev,
 687                                 "9-bit SPI not available, emulating using 8-bit.\n");
 688                        /* allocate buffer with room for dc bits */
 689                        par->extra = devm_kzalloc(par->info->device,
 690                                                  par->txbuf.len
 691                                                  + (par->txbuf.len / 8) + 8,
 692                                                  GFP_KERNEL);
 693                        if (!par->extra) {
 694                                ret = -ENOMEM;
 695                                goto out_release;
 696                        }
 697                        par->fbtftops.write = fbtft_write_spi_emulate_9;
 698
 699                        break;
 700                default:
 701                        dev_err(dev,
 702                                "argument 'buswidth': %d is not supported with SPI.\n",
 703                                buswidth);
 704                        return -EINVAL;
 705                }
 706        } else {
 707                par->fbtftops.verify_gpios = flexfb_verify_gpios_db;
 708                switch (buswidth) {
 709                case 8:
 710                        par->fbtftops.write = fbtft_write_gpio8_wr;
 711                        par->fbtftops.write_vmem = fbtft_write_vmem16_bus8;
 712                        break;
 713                case 16:
 714                        par->fbtftops.write_register = fbtft_write_reg16_bus16;
 715                        if (latched)
 716                                par->fbtftops.write = fbtft_write_gpio16_wr_latched;
 717                        else
 718                                par->fbtftops.write = fbtft_write_gpio16_wr;
 719                        par->fbtftops.write_vmem = fbtft_write_vmem16_bus16;
 720                        break;
 721                default:
 722                        dev_err(dev,
 723                                "argument 'buswidth': %d is not supported with parallel.\n",
 724                                buswidth);
 725                        return -EINVAL;
 726                }
 727        }
 728
 729        /* set_addr_win function */
 730        switch (setaddrwin) {
 731        case 0:
 732                /* use default */
 733                break;
 734        case 1:
 735                par->fbtftops.set_addr_win = flexfb_set_addr_win_1;
 736                break;
 737        case 2:
 738                par->fbtftops.set_addr_win = flexfb_set_addr_win_2;
 739                break;
 740        case 3:
 741                par->fbtftops.set_addr_win = set_addr_win_3;
 742                break;
 743        default:
 744                dev_err(dev, "argument 'setaddrwin': unknown value %d.\n",
 745                        setaddrwin);
 746                return -EINVAL;
 747        }
 748
 749        if (!nobacklight)
 750                par->fbtftops.register_backlight = fbtft_register_backlight;
 751
 752        ret = fbtft_register_framebuffer(info);
 753        if (ret < 0)
 754                goto out_release;
 755
 756        return 0;
 757
 758out_release:
 759        fbtft_framebuffer_release(info);
 760
 761        return ret;
 762}
 763
 764static int flexfb_remove_common(struct device *dev, struct fb_info *info)
 765{
 766        struct fbtft_par *par;
 767
 768        if (!info)
 769                return -EINVAL;
 770        par = info->par;
 771        if (par)
 772                fbtft_par_dbg(DEBUG_DRIVER_INIT_FUNCTIONS, par, "%s()\n",
 773                              __func__);
 774        fbtft_unregister_framebuffer(info);
 775        fbtft_framebuffer_release(info);
 776
 777        return 0;
 778}
 779
 780static int flexfb_probe_spi(struct spi_device *spi)
 781{
 782        return flexfb_probe_common(spi, NULL);
 783}
 784
 785static int flexfb_remove_spi(struct spi_device *spi)
 786{
 787        struct fb_info *info = spi_get_drvdata(spi);
 788
 789        return flexfb_remove_common(&spi->dev, info);
 790}
 791
 792static int flexfb_probe_pdev(struct platform_device *pdev)
 793{
 794        return flexfb_probe_common(NULL, pdev);
 795}
 796
 797static int flexfb_remove_pdev(struct platform_device *pdev)
 798{
 799        struct fb_info *info = platform_get_drvdata(pdev);
 800
 801        return flexfb_remove_common(&pdev->dev, info);
 802}
 803
 804static struct spi_driver flexfb_spi_driver = {
 805        .driver = {
 806                .name   = DRVNAME,
 807        },
 808        .probe  = flexfb_probe_spi,
 809        .remove = flexfb_remove_spi,
 810};
 811
 812static const struct platform_device_id flexfb_platform_ids[] = {
 813        { "flexpfb", 0 },
 814        { },
 815};
 816MODULE_DEVICE_TABLE(platform, flexfb_platform_ids);
 817
 818static struct platform_driver flexfb_platform_driver = {
 819        .driver = {
 820                .name   = DRVNAME,
 821        },
 822        .id_table = flexfb_platform_ids,
 823        .probe  = flexfb_probe_pdev,
 824        .remove = flexfb_remove_pdev,
 825};
 826
 827static int __init flexfb_init(void)
 828{
 829        int ret, ret2;
 830
 831        ret = spi_register_driver(&flexfb_spi_driver);
 832        ret2 = platform_driver_register(&flexfb_platform_driver);
 833        if (ret < 0)
 834                return ret;
 835        return ret2;
 836}
 837
 838static void __exit flexfb_exit(void)
 839{
 840        spi_unregister_driver(&flexfb_spi_driver);
 841        platform_driver_unregister(&flexfb_platform_driver);
 842}
 843
 844/* ------------------------------------------------------------------------- */
 845
 846module_init(flexfb_init);
 847module_exit(flexfb_exit);
 848
 849MODULE_DESCRIPTION("Generic FB driver for TFT LCD displays");
 850MODULE_AUTHOR("Noralf Tronnes");
 851MODULE_LICENSE("GPL");
 852