linux/drivers/staging/fbtft/fbtft_device.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 *
   4 * Copyright (C) 2013, Noralf Tronnes
   5 */
   6
   7#define pr_fmt(fmt) "fbtft_device: " fmt
   8#include <linux/module.h>
   9#include <linux/kernel.h>
  10#include <linux/init.h>
  11#include <linux/gpio.h>
  12#include <linux/spi/spi.h>
  13#include <video/mipi_display.h>
  14
  15#include "fbtft.h"
  16
  17#define MAX_GPIOS 32
  18
  19static struct spi_device *spi_device;
  20static struct platform_device *p_device;
  21
  22static char *name;
  23module_param(name, charp, 0000);
  24MODULE_PARM_DESC(name, "Devicename (required). name=list => list all supported devices.");
  25
  26static unsigned int rotate;
  27module_param(rotate, uint, 0000);
  28MODULE_PARM_DESC(rotate,
  29"Angle to rotate display counter clockwise: 0, 90, 180, 270");
  30
  31static unsigned int busnum;
  32module_param(busnum, uint, 0000);
  33MODULE_PARM_DESC(busnum, "SPI bus number (default=0)");
  34
  35static unsigned int cs;
  36module_param(cs, uint, 0000);
  37MODULE_PARM_DESC(cs, "SPI chip select (default=0)");
  38
  39static unsigned int speed;
  40module_param(speed, uint, 0000);
  41MODULE_PARM_DESC(speed, "SPI speed (override device default)");
  42
  43static int mode = -1;
  44module_param(mode, int, 0000);
  45MODULE_PARM_DESC(mode, "SPI mode (override device default)");
  46
  47static char *gpios;
  48module_param(gpios, charp, 0000);
  49MODULE_PARM_DESC(gpios,
  50"List of gpios. Comma separated with the form: reset:23,dc:24 (when overriding the default, all gpios must be specified)");
  51
  52static unsigned int fps;
  53module_param(fps, uint, 0000);
  54MODULE_PARM_DESC(fps, "Frames per second (override driver default)");
  55
  56static char *gamma;
  57module_param(gamma, charp, 0000);
  58MODULE_PARM_DESC(gamma,
  59"String representation of Gamma Curve(s). Driver specific.");
  60
  61static int txbuflen;
  62module_param(txbuflen, int, 0000);
  63MODULE_PARM_DESC(txbuflen, "txbuflen (override driver default)");
  64
  65static int bgr = -1;
  66module_param(bgr, int, 0000);
  67MODULE_PARM_DESC(bgr,
  68"BGR bit (supported by some drivers).");
  69
  70static unsigned int startbyte;
  71module_param(startbyte, uint, 0000);
  72MODULE_PARM_DESC(startbyte, "Sets the Start byte used by some SPI displays.");
  73
  74static bool custom;
  75module_param(custom, bool, 0000);
  76MODULE_PARM_DESC(custom, "Add a custom display device. Use speed= argument to make it a SPI device, else platform_device");
  77
  78static unsigned int width;
  79module_param(width, uint, 0000);
  80MODULE_PARM_DESC(width, "Display width, used with the custom argument");
  81
  82static unsigned int height;
  83module_param(height, uint, 0000);
  84MODULE_PARM_DESC(height, "Display height, used with the custom argument");
  85
  86static unsigned int buswidth = 8;
  87module_param(buswidth, uint, 0000);
  88MODULE_PARM_DESC(buswidth, "Display bus width, used with the custom argument");
  89
  90static s16 init[FBTFT_MAX_INIT_SEQUENCE];
  91static int init_num;
  92module_param_array(init, short, &init_num, 0000);
  93MODULE_PARM_DESC(init, "Init sequence, used with the custom argument");
  94
  95static unsigned long debug;
  96module_param(debug, ulong, 0000);
  97MODULE_PARM_DESC(debug,
  98"level: 0-7 (the remaining 29 bits is for advanced usage)");
  99
 100static unsigned int verbose = 3;
 101module_param(verbose, uint, 0000);
 102MODULE_PARM_DESC(verbose,
 103"0 silent, >0 show gpios, >1 show devices, >2 show devices before (default=3)");
 104
 105struct fbtft_device_display {
 106        char *name;
 107        struct spi_board_info *spi;
 108        struct platform_device *pdev;
 109};
 110
 111static void fbtft_device_pdev_release(struct device *dev);
 112
 113static int write_gpio16_wr_slow(struct fbtft_par *par, void *buf, size_t len);
 114static void adafruit18_green_tab_set_addr_win(struct fbtft_par *par,
 115        int xs, int ys, int xe, int ye);
 116
 117#define ADAFRUIT18_GAMMA \
 118                "02 1c 07 12 37 32 29 2d 29 25 2B 39 00 01 03 10\n" \
 119                "03 1d 07 06 2E 2C 29 2D 2E 2E 37 3F 00 00 02 10"
 120
 121#define CBERRY28_GAMMA \
 122                "D0 00 14 15 13 2C 42 43 4E 09 16 14 18 21\n" \
 123                "D0 00 14 15 13 0B 43 55 53 0C 17 14 23 20"
 124
 125static const s16 cberry28_init_sequence[] = {
 126        /* turn off sleep mode */
 127        -1, MIPI_DCS_EXIT_SLEEP_MODE,
 128        -2, 120,
 129
 130        /* set pixel format to RGB-565 */
 131        -1, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT,
 132
 133        -1, 0xB2, 0x0C, 0x0C, 0x00, 0x33, 0x33,
 134
 135        /*
 136         * VGH = 13.26V
 137         * VGL = -10.43V
 138         */
 139        -1, 0xB7, 0x35,
 140
 141        /*
 142         * VDV and VRH register values come from command write
 143         * (instead of NVM)
 144         */
 145        -1, 0xC2, 0x01, 0xFF,
 146
 147        /*
 148         * VAP =  4.7V + (VCOM + VCOM offset + 0.5 * VDV)
 149         * VAN = -4.7V + (VCOM + VCOM offset + 0.5 * VDV)
 150         */
 151        -1, 0xC3, 0x17,
 152
 153        /* VDV = 0V */
 154        -1, 0xC4, 0x20,
 155
 156        /* VCOM = 0.675V */
 157        -1, 0xBB, 0x17,
 158
 159        /* VCOM offset = 0V */
 160        -1, 0xC5, 0x20,
 161
 162        /*
 163         * AVDD = 6.8V
 164         * AVCL = -4.8V
 165         * VDS = 2.3V
 166         */
 167        -1, 0xD0, 0xA4, 0xA1,
 168
 169        -1, MIPI_DCS_SET_DISPLAY_ON,
 170
 171        -3,
 172};
 173
 174static const s16 hy28b_init_sequence[] = {
 175        -1, 0x00e7, 0x0010, -1, 0x0000, 0x0001,
 176        -1, 0x0001, 0x0100, -1, 0x0002, 0x0700,
 177        -1, 0x0003, 0x1030, -1, 0x0004, 0x0000,
 178        -1, 0x0008, 0x0207, -1, 0x0009, 0x0000,
 179        -1, 0x000a, 0x0000, -1, 0x000c, 0x0001,
 180        -1, 0x000d, 0x0000, -1, 0x000f, 0x0000,
 181        -1, 0x0010, 0x0000, -1, 0x0011, 0x0007,
 182        -1, 0x0012, 0x0000, -1, 0x0013, 0x0000,
 183        -2, 50, -1, 0x0010, 0x1590, -1, 0x0011,
 184        0x0227, -2, 50, -1, 0x0012, 0x009c, -2, 50,
 185        -1, 0x0013, 0x1900, -1, 0x0029, 0x0023,
 186        -1, 0x002b, 0x000e, -2, 50,
 187        -1, 0x0020, 0x0000, -1, 0x0021, 0x0000,
 188        -2, 50, -1, 0x0050, 0x0000,
 189        -1, 0x0051, 0x00ef, -1, 0x0052, 0x0000,
 190        -1, 0x0053, 0x013f, -1, 0x0060, 0xa700,
 191        -1, 0x0061, 0x0001, -1, 0x006a, 0x0000,
 192        -1, 0x0080, 0x0000, -1, 0x0081, 0x0000,
 193        -1, 0x0082, 0x0000, -1, 0x0083, 0x0000,
 194        -1, 0x0084, 0x0000, -1, 0x0085, 0x0000,
 195        -1, 0x0090, 0x0010, -1, 0x0092, 0x0000,
 196        -1, 0x0093, 0x0003, -1, 0x0095, 0x0110,
 197        -1, 0x0097, 0x0000, -1, 0x0098, 0x0000,
 198        -1, 0x0007, 0x0133, -1, 0x0020, 0x0000,
 199        -1, 0x0021, 0x0000, -2, 100, -3 };
 200
 201#define HY28B_GAMMA \
 202        "04 1F 4 7 7 0 7 7 6 0\n" \
 203        "0F 00 1 7 4 0 0 0 6 7"
 204
 205static const s16 pitft_init_sequence[] = {
 206        -1, MIPI_DCS_SOFT_RESET,
 207        -2, 5,
 208        -1, MIPI_DCS_SET_DISPLAY_OFF,
 209        -1, 0xEF, 0x03, 0x80, 0x02,
 210        -1, 0xCF, 0x00, 0xC1, 0x30,
 211        -1, 0xED, 0x64, 0x03, 0x12, 0x81,
 212        -1, 0xE8, 0x85, 0x00, 0x78,
 213        -1, 0xCB, 0x39, 0x2C, 0x00, 0x34, 0x02,
 214        -1, 0xF7, 0x20,
 215        -1, 0xEA, 0x00, 0x00,
 216        -1, 0xC0, 0x23,
 217        -1, 0xC1, 0x10,
 218        -1, 0xC5, 0x3E, 0x28,
 219        -1, 0xC7, 0x86,
 220        -1, MIPI_DCS_SET_PIXEL_FORMAT, 0x55,
 221        -1, 0xB1, 0x00, 0x18,
 222        -1, 0xB6, 0x08, 0x82, 0x27,
 223        -1, 0xF2, 0x00,
 224        -1, MIPI_DCS_SET_GAMMA_CURVE, 0x01,
 225        -1, 0xE0, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E,
 226                0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00,
 227        -1, 0xE1, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31,
 228                0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F,
 229        -1, MIPI_DCS_EXIT_SLEEP_MODE,
 230        -2, 100,
 231        -1, MIPI_DCS_SET_DISPLAY_ON,
 232        -2, 20,
 233        -3
 234};
 235
 236static const s16 waveshare32b_init_sequence[] = {
 237        -1, 0xCB, 0x39, 0x2C, 0x00, 0x34, 0x02,
 238        -1, 0xCF, 0x00, 0xC1, 0x30,
 239        -1, 0xE8, 0x85, 0x00, 0x78,
 240        -1, 0xEA, 0x00, 0x00,
 241        -1, 0xED, 0x64, 0x03, 0x12, 0x81,
 242        -1, 0xF7, 0x20,
 243        -1, 0xC0, 0x23,
 244        -1, 0xC1, 0x10,
 245        -1, 0xC5, 0x3E, 0x28,
 246        -1, 0xC7, 0x86,
 247        -1, MIPI_DCS_SET_ADDRESS_MODE, 0x28,
 248        -1, MIPI_DCS_SET_PIXEL_FORMAT, 0x55,
 249        -1, 0xB1, 0x00, 0x18,
 250        -1, 0xB6, 0x08, 0x82, 0x27,
 251        -1, 0xF2, 0x00,
 252        -1, MIPI_DCS_SET_GAMMA_CURVE, 0x01,
 253        -1, 0xE0, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E,
 254                0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00,
 255        -1, 0xE1, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31,
 256                0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F,
 257        -1, MIPI_DCS_EXIT_SLEEP_MODE,
 258        -2, 120,
 259        -1, MIPI_DCS_SET_DISPLAY_ON,
 260        -1, MIPI_DCS_WRITE_MEMORY_START,
 261        -3
 262};
 263
 264/* Supported displays in alphabetical order */
 265static struct fbtft_device_display displays[] = {
 266        {
 267                .name = "adafruit18",
 268                .spi = &(struct spi_board_info) {
 269                        .modalias = "fb_st7735r",
 270                        .max_speed_hz = 32000000,
 271                        .mode = SPI_MODE_0,
 272                        .platform_data = &(struct fbtft_platform_data) {
 273                                .display = {
 274                                        .buswidth = 8,
 275                                        .backlight = 1,
 276                                },
 277                                .gpios = (const struct fbtft_gpio []) {
 278                                        { "reset", 25 },
 279                                        { "dc", 24 },
 280                                        { "led", 18 },
 281                                        {},
 282                                },
 283                                .gamma = ADAFRUIT18_GAMMA,
 284                        }
 285                }
 286        }, {
 287                .name = "adafruit18_green",
 288                .spi = &(struct spi_board_info) {
 289                        .modalias = "fb_st7735r",
 290                        .max_speed_hz = 4000000,
 291                        .mode = SPI_MODE_0,
 292                        .platform_data = &(struct fbtft_platform_data) {
 293                                .display = {
 294                                        .buswidth = 8,
 295                                        .backlight = 1,
 296                                        .fbtftops.set_addr_win =
 297                                            adafruit18_green_tab_set_addr_win,
 298                                },
 299                                .bgr = true,
 300                                .gpios = (const struct fbtft_gpio []) {
 301                                        { "reset", 25 },
 302                                        { "dc", 24 },
 303                                        { "led", 18 },
 304                                        {},
 305                                },
 306                                .gamma = ADAFRUIT18_GAMMA,
 307                        }
 308                }
 309        }, {
 310                .name = "adafruit22",
 311                .spi = &(struct spi_board_info) {
 312                        .modalias = "fb_hx8340bn",
 313                        .max_speed_hz = 32000000,
 314                        .mode = SPI_MODE_0,
 315                        .platform_data = &(struct fbtft_platform_data) {
 316                                .display = {
 317                                        .buswidth = 9,
 318                                        .backlight = 1,
 319                                },
 320                                .bgr = true,
 321                                .gpios = (const struct fbtft_gpio []) {
 322                                        { "reset", 25 },
 323                                        { "led", 23 },
 324                                        {},
 325                                },
 326                        }
 327                }
 328        }, {
 329                .name = "adafruit22a",
 330                .spi = &(struct spi_board_info) {
 331                        .modalias = "fb_ili9340",
 332                        .max_speed_hz = 32000000,
 333                        .mode = SPI_MODE_0,
 334                        .platform_data = &(struct fbtft_platform_data) {
 335                                .display = {
 336                                        .buswidth = 8,
 337                                        .backlight = 1,
 338                                },
 339                                .bgr = true,
 340                                .gpios = (const struct fbtft_gpio []) {
 341                                        { "reset", 25 },
 342                                        { "dc", 24 },
 343                                        { "led", 18 },
 344                                        {},
 345                                },
 346                        }
 347                }
 348        }, {
 349                .name = "adafruit28",
 350                .spi = &(struct spi_board_info) {
 351                        .modalias = "fb_ili9341",
 352                        .max_speed_hz = 32000000,
 353                        .mode = SPI_MODE_0,
 354                        .platform_data = &(struct fbtft_platform_data) {
 355                                .display = {
 356                                        .buswidth = 8,
 357                                        .backlight = 1,
 358                                },
 359                                .bgr = true,
 360                                .gpios = (const struct fbtft_gpio []) {
 361                                        { "reset", 25 },
 362                                        { "dc", 24 },
 363                                        { "led", 18 },
 364                                        {},
 365                                },
 366                        }
 367                }
 368        }, {
 369                .name = "adafruit13m",
 370                .spi = &(struct spi_board_info) {
 371                        .modalias = "fb_ssd1306",
 372                        .max_speed_hz = 16000000,
 373                        .mode = SPI_MODE_0,
 374                        .platform_data = &(struct fbtft_platform_data) {
 375                                .display = {
 376                                        .buswidth = 8,
 377                                },
 378                                .gpios = (const struct fbtft_gpio []) {
 379                                        { "reset", 25 },
 380                                        { "dc", 24 },
 381                                        {},
 382                                },
 383                        }
 384                }
 385        }, {
 386                .name = "admatec_c-berry28",
 387                .spi = &(struct spi_board_info) {
 388                        .modalias = "fb_st7789v",
 389                        .max_speed_hz = 48000000,
 390                        .mode = SPI_MODE_0,
 391                        .platform_data = &(struct fbtft_platform_data) {
 392                                .display = {
 393                                        .buswidth = 8,
 394                                        .backlight = 1,
 395                                        .init_sequence = cberry28_init_sequence,
 396                                },
 397                                .gpios = (const struct fbtft_gpio []) {
 398                                        { "reset", 25 },
 399                                        { "dc", 22 },
 400                                        { "led", 18 },
 401                                        {},
 402                                },
 403                                .gamma = CBERRY28_GAMMA,
 404                        }
 405                }
 406        }, {
 407                .name = "agm1264k-fl",
 408                .pdev = &(struct platform_device) {
 409                        .name = "fb_agm1264k-fl",
 410                        .id = 0,
 411                        .dev = {
 412                        .release = fbtft_device_pdev_release,
 413                        .platform_data = &(struct fbtft_platform_data) {
 414                                .display = {
 415                                        .buswidth = 8,
 416                                        .backlight = FBTFT_ONBOARD_BACKLIGHT,
 417                                },
 418                                .gpios = (const struct fbtft_gpio []) {
 419                                        {},
 420                                },
 421                        },
 422                        }
 423                }
 424        }, {
 425                .name = "dogs102",
 426                .spi = &(struct spi_board_info) {
 427                        .modalias = "fb_uc1701",
 428                        .max_speed_hz = 8000000,
 429                        .mode = SPI_MODE_0,
 430                        .platform_data = &(struct fbtft_platform_data) {
 431                                .display = {
 432                                        .buswidth = 8,
 433                                },
 434                                .bgr = true,
 435                                .gpios = (const struct fbtft_gpio []) {
 436                                        { "reset", 13 },
 437                                        { "dc", 6 },
 438                                        {},
 439                                },
 440                        }
 441                }
 442        }, {
 443                .name = "er_tftm050_2",
 444                .spi = &(struct spi_board_info) {
 445                        .modalias = "fb_ra8875",
 446                        .max_speed_hz = 5000000,
 447                        .mode = SPI_MODE_3,
 448                        .platform_data = &(struct fbtft_platform_data) {
 449                                .display = {
 450                                        .buswidth = 8,
 451                                        .backlight = 1,
 452                                        .width = 480,
 453                                        .height = 272,
 454                                },
 455                                .bgr = true,
 456                                .gpios = (const struct fbtft_gpio []) {
 457                                        { "reset", 25 },
 458                                        { "dc", 24 },
 459                                        {},
 460                                },
 461                        }
 462                }
 463        }, {
 464                .name = "er_tftm070_5",
 465                .spi = &(struct spi_board_info) {
 466                        .modalias = "fb_ra8875",
 467                        .max_speed_hz = 5000000,
 468                        .mode = SPI_MODE_3,
 469                        .platform_data = &(struct fbtft_platform_data) {
 470                                .display = {
 471                                        .buswidth = 8,
 472                                        .backlight = 1,
 473                                        .width = 800,
 474                                        .height = 480,
 475                                },
 476                                .bgr = true,
 477                                .gpios = (const struct fbtft_gpio []) {
 478                                        { "reset", 25 },
 479                                        { "dc", 24 },
 480                                        {},
 481                                },
 482                        }
 483                }
 484        }, {
 485                .name = "ew24ha0",
 486                .spi = &(struct spi_board_info) {
 487                        .modalias = "fb_uc1611",
 488                        .max_speed_hz = 32000000,
 489                        .mode = SPI_MODE_3,
 490                        .platform_data = &(struct fbtft_platform_data) {
 491                                .display = {
 492                                        .buswidth = 8,
 493                                },
 494                                .gpios = (const struct fbtft_gpio []) {
 495                                        { "dc", 24 },
 496                                        {},
 497                                },
 498                        }
 499                }
 500        }, {
 501                .name = "ew24ha0_9bit",
 502                .spi = &(struct spi_board_info) {
 503                        .modalias = "fb_uc1611",
 504                        .max_speed_hz = 32000000,
 505                        .mode = SPI_MODE_3,
 506                        .platform_data = &(struct fbtft_platform_data) {
 507                                .display = {
 508                                        .buswidth = 9,
 509                                },
 510                                .gpios = (const struct fbtft_gpio []) {
 511                                        {},
 512                                },
 513                        }
 514                }
 515        }, {
 516                .name = "flexfb",
 517                .spi = &(struct spi_board_info) {
 518                        .modalias = "flexfb",
 519                        .max_speed_hz = 32000000,
 520                        .mode = SPI_MODE_0,
 521                        .platform_data = &(struct fbtft_platform_data) {
 522                                .gpios = (const struct fbtft_gpio []) {
 523                                        { "reset", 25 },
 524                                        { "dc", 24 },
 525                                        {},
 526                                },
 527                        }
 528                }
 529        }, {
 530                .name = "flexpfb",
 531                .pdev = &(struct platform_device) {
 532                        .name = "flexpfb",
 533                        .id = 0,
 534                        .dev = {
 535                        .release = fbtft_device_pdev_release,
 536                        .platform_data = &(struct fbtft_platform_data) {
 537                                .gpios = (const struct fbtft_gpio []) {
 538                                        { "reset", 17 },
 539                                        { "dc", 1 },
 540                                        { "wr", 0 },
 541                                        { "cs", 21 },
 542                                        { "db00", 9 },
 543                                        { "db01", 11 },
 544                                        { "db02", 18 },
 545                                        { "db03", 23 },
 546                                        { "db04", 24 },
 547                                        { "db05", 25 },
 548                                        { "db06", 8 },
 549                                        { "db07", 7 },
 550                                        { "led", 4 },
 551                                        {},
 552                                },
 553                        },
 554                        }
 555                }
 556        }, {
 557                .name = "freetronicsoled128",
 558                .spi = &(struct spi_board_info) {
 559                        .modalias = "fb_ssd1351",
 560                        .max_speed_hz = 20000000,
 561                        .mode = SPI_MODE_0,
 562                        .platform_data = &(struct fbtft_platform_data) {
 563                                .display = {
 564                                        .buswidth = 8,
 565                                        .backlight = FBTFT_ONBOARD_BACKLIGHT,
 566                                },
 567                                .bgr = true,
 568                                .gpios = (const struct fbtft_gpio []) {
 569                                        { "reset", 24 },
 570                                        { "dc", 25 },
 571                                        {},
 572                                },
 573                        }
 574                }
 575        }, {
 576                .name = "hx8353d",
 577                .spi = &(struct spi_board_info) {
 578                        .modalias = "fb_hx8353d",
 579                        .max_speed_hz = 16000000,
 580                        .mode = SPI_MODE_0,
 581                        .platform_data = &(struct fbtft_platform_data) {
 582                                .display = {
 583                                        .buswidth = 8,
 584                                        .backlight = 1,
 585                                },
 586                                .gpios = (const struct fbtft_gpio []) {
 587                                        { "reset", 25 },
 588                                        { "dc", 24 },
 589                                        { "led", 23 },
 590                                        {},
 591                                },
 592                        }
 593                }
 594        }, {
 595                .name = "hy28a",
 596                .spi = &(struct spi_board_info) {
 597                        .modalias = "fb_ili9320",
 598                        .max_speed_hz = 32000000,
 599                        .mode = SPI_MODE_3,
 600                        .platform_data = &(struct fbtft_platform_data) {
 601                                .display = {
 602                                        .buswidth = 8,
 603                                        .backlight = 1,
 604                                },
 605                                .startbyte = 0x70,
 606                                .bgr = true,
 607                                .gpios = (const struct fbtft_gpio []) {
 608                                        { "reset", 25 },
 609                                        { "led", 18 },
 610                                        {},
 611                                },
 612                        }
 613                }
 614        }, {
 615                .name = "hy28b",
 616                .spi = &(struct spi_board_info) {
 617                        .modalias = "fb_ili9325",
 618                        .max_speed_hz = 48000000,
 619                        .mode = SPI_MODE_3,
 620                        .platform_data = &(struct fbtft_platform_data) {
 621                                .display = {
 622                                        .buswidth = 8,
 623                                        .backlight = 1,
 624                                        .init_sequence = hy28b_init_sequence,
 625                                },
 626                                .startbyte = 0x70,
 627                                .bgr = true,
 628                                .fps = 50,
 629                                .gpios = (const struct fbtft_gpio []) {
 630                                        { "reset", 25 },
 631                                        { "led", 18 },
 632                                        {},
 633                                },
 634                                .gamma = HY28B_GAMMA,
 635                        }
 636                }
 637        }, {
 638                .name = "ili9481",
 639                .spi = &(struct spi_board_info) {
 640                        .modalias = "fb_ili9481",
 641                        .max_speed_hz = 32000000,
 642                        .mode = SPI_MODE_0,
 643                        .platform_data = &(struct fbtft_platform_data) {
 644                                .display = {
 645                                        .regwidth = 16,
 646                                        .buswidth = 8,
 647                                        .backlight = 1,
 648                                },
 649                                .bgr = true,
 650                                .gpios = (const struct fbtft_gpio []) {
 651                                        { "reset", 25 },
 652                                        { "dc", 24 },
 653                                        { "led", 22 },
 654                                        {},
 655                                },
 656                        }
 657                }
 658        }, {
 659                .name = "itdb24",
 660                .pdev = &(struct platform_device) {
 661                        .name = "fb_s6d1121",
 662                        .id = 0,
 663                        .dev = {
 664                        .release = fbtft_device_pdev_release,
 665                        .platform_data = &(struct fbtft_platform_data) {
 666                                .display = {
 667                                        .buswidth = 8,
 668                                        .backlight = 1,
 669                                },
 670                                .bgr = false,
 671                                .gpios = (const struct fbtft_gpio []) {
 672                                        /* Wiring for LCD adapter kit */
 673                                        { "reset", 7 },
 674                                        { "dc", 0 },    /* rev 2: 2 */
 675                                        { "wr", 1 },    /* rev 2: 3 */
 676                                        { "cs", 8 },
 677                                        { "db00", 17 },
 678                                        { "db01", 18 },
 679                                        { "db02", 21 }, /* rev 2: 27 */
 680                                        { "db03", 22 },
 681                                        { "db04", 23 },
 682                                        { "db05", 24 },
 683                                        { "db06", 25 },
 684                                        { "db07", 4 },
 685                                        {}
 686                                },
 687                        },
 688                        }
 689                }
 690        }, {
 691                .name = "itdb28",
 692                .pdev = &(struct platform_device) {
 693                        .name = "fb_ili9325",
 694                        .id = 0,
 695                        .dev = {
 696                        .release = fbtft_device_pdev_release,
 697                        .platform_data = &(struct fbtft_platform_data) {
 698                                .display = {
 699                                        .buswidth = 8,
 700                                        .backlight = 1,
 701                                },
 702                                .bgr = true,
 703                                .gpios = (const struct fbtft_gpio []) {
 704                                        {},
 705                                },
 706                        },
 707                        }
 708                }
 709        }, {
 710                .name = "itdb28_spi",
 711                .spi = &(struct spi_board_info) {
 712                        .modalias = "fb_ili9325",
 713                        .max_speed_hz = 32000000,
 714                        .mode = SPI_MODE_0,
 715                        .platform_data = &(struct fbtft_platform_data) {
 716                                .display = {
 717                                        .buswidth = 8,
 718                                        .backlight = 1,
 719                                },
 720                                .bgr = true,
 721                                .gpios = (const struct fbtft_gpio []) {
 722                                        { "reset", 25 },
 723                                        { "dc", 24 },
 724                                        {},
 725                                },
 726                        }
 727                }
 728        }, {
 729                .name = "mi0283qt-2",
 730                .spi = &(struct spi_board_info) {
 731                        .modalias = "fb_hx8347d",
 732                        .max_speed_hz = 32000000,
 733                        .mode = SPI_MODE_0,
 734                        .platform_data = &(struct fbtft_platform_data) {
 735                                .display = {
 736                                        .buswidth = 8,
 737                                        .backlight = 1,
 738                                },
 739                                .startbyte = 0x70,
 740                                .bgr = true,
 741                                .gpios = (const struct fbtft_gpio []) {
 742                                        { "reset", 25 },
 743                                        { "dc", 24 },
 744                                        { "led", 18 },
 745                                        {},
 746                                },
 747                        }
 748                }
 749        }, {
 750                .name = "mi0283qt-9a",
 751                .spi = &(struct spi_board_info) {
 752                        .modalias = "fb_ili9341",
 753                        .max_speed_hz = 32000000,
 754                        .mode = SPI_MODE_0,
 755                        .platform_data = &(struct fbtft_platform_data) {
 756                                .display = {
 757                                        .buswidth = 9,
 758                                        .backlight = 1,
 759                                },
 760                                .bgr = true,
 761                                .gpios = (const struct fbtft_gpio []) {
 762                                        { "reset", 25 },
 763                                        { "led", 18 },
 764                                        {},
 765                                },
 766                        }
 767                }
 768        }, {
 769                .name = "mi0283qt-v2",
 770                .spi = &(struct spi_board_info) {
 771                        .modalias = "fb_watterott",
 772                        .max_speed_hz = 4000000,
 773                        .mode = SPI_MODE_3,
 774                        .platform_data = &(struct fbtft_platform_data) {
 775                                .gpios = (const struct fbtft_gpio []) {
 776                                        { "reset", 25 },
 777                                        {},
 778                                },
 779                        }
 780                }
 781        }, {
 782                .name = "nokia3310",
 783                .spi = &(struct spi_board_info) {
 784                        .modalias = "fb_pcd8544",
 785                        .max_speed_hz = 400000,
 786                        .mode = SPI_MODE_0,
 787                        .platform_data = &(struct fbtft_platform_data) {
 788                                .display = {
 789                                        .buswidth = 8,
 790                                },
 791                                .gpios = (const struct fbtft_gpio []) {
 792                                        { "reset", 25 },
 793                                        { "dc", 24 },
 794                                        { "led", 23 },
 795                                        {},
 796                                },
 797                        }
 798                }
 799        }, {
 800                .name = "nokia3310a",
 801                .spi = &(struct spi_board_info) {
 802                        .modalias = "fb_tls8204",
 803                        .max_speed_hz = 1000000,
 804                        .mode = SPI_MODE_0,
 805                        .platform_data = &(struct fbtft_platform_data) {
 806                                .display = {
 807                                        .buswidth = 8,
 808                                },
 809                                .gpios = (const struct fbtft_gpio []) {
 810                                        { "reset", 25 },
 811                                        { "dc", 24 },
 812                                        { "led", 23 },
 813                                        {},
 814                                },
 815                        }
 816                }
 817        }, {
 818                .name = "nokia5110",
 819                .spi = &(struct spi_board_info) {
 820                        .modalias = "fb_ili9163",
 821                        .max_speed_hz = 12000000,
 822                        .mode = SPI_MODE_0,
 823                        .platform_data = &(struct fbtft_platform_data) {
 824                                .display = {
 825                                        .buswidth = 8,
 826                                        .backlight = 1,
 827                                },
 828                                .bgr = true,
 829                                .gpios = (const struct fbtft_gpio []) {
 830                                        {},
 831                                },
 832                        }
 833                }
 834        }, {
 835
 836                .name = "piscreen",
 837                .spi = &(struct spi_board_info) {
 838                        .modalias = "fb_ili9486",
 839                        .max_speed_hz = 32000000,
 840                        .mode = SPI_MODE_0,
 841                        .platform_data = &(struct fbtft_platform_data) {
 842                                .display = {
 843                                        .regwidth = 16,
 844                                        .buswidth = 8,
 845                                        .backlight = 1,
 846                                },
 847                                .bgr = true,
 848                                .gpios = (const struct fbtft_gpio []) {
 849                                        { "reset", 25 },
 850                                        { "dc", 24 },
 851                                        { "led", 22 },
 852                                        {},
 853                                },
 854                        }
 855                }
 856        }, {
 857                .name = "pitft",
 858                .spi = &(struct spi_board_info) {
 859                        .modalias = "fb_ili9340",
 860                        .max_speed_hz = 32000000,
 861                        .mode = SPI_MODE_0,
 862                        .chip_select = 0,
 863                        .platform_data = &(struct fbtft_platform_data) {
 864                                .display = {
 865                                        .buswidth = 8,
 866                                        .backlight = 1,
 867                                        .init_sequence = pitft_init_sequence,
 868                                },
 869                                .bgr = true,
 870                                .gpios = (const struct fbtft_gpio []) {
 871                                        { "dc", 25 },
 872                                        {},
 873                                },
 874                        }
 875                }
 876        }, {
 877                .name = "pioled",
 878                .spi = &(struct spi_board_info) {
 879                        .modalias = "fb_ssd1351",
 880                        .max_speed_hz = 20000000,
 881                        .mode = SPI_MODE_0,
 882                        .platform_data = &(struct fbtft_platform_data) {
 883                                .display = {
 884                                        .buswidth = 8,
 885                                },
 886                                .bgr = true,
 887                                .gpios = (const struct fbtft_gpio []) {
 888                                        { "reset", 24 },
 889                                        { "dc", 25 },
 890                                        {},
 891                                },
 892                                .gamma =        "0 2 2 2 2 2 2 2 "
 893                                                "2 2 2 2 2 2 2 2 "
 894                                                "2 2 2 2 2 2 2 2 "
 895                                                "2 2 2 2 2 2 2 3 "
 896                                                "3 3 3 3 3 3 3 3 "
 897                                                "3 3 3 3 3 3 3 3 "
 898                                                "3 3 3 4 4 4 4 4 "
 899                                                "4 4 4 4 4 4 4"
 900                        }
 901                }
 902        }, {
 903                .name = "rpi-display",
 904                .spi = &(struct spi_board_info) {
 905                        .modalias = "fb_ili9341",
 906                        .max_speed_hz = 32000000,
 907                        .mode = SPI_MODE_0,
 908                        .platform_data = &(struct fbtft_platform_data) {
 909                                .display = {
 910                                        .buswidth = 8,
 911                                        .backlight = 1,
 912                                },
 913                                .bgr = true,
 914                                .gpios = (const struct fbtft_gpio []) {
 915                                        { "reset", 23 },
 916                                        { "dc", 24 },
 917                                        { "led", 18 },
 918                                        {},
 919                                },
 920                        }
 921                }
 922        }, {
 923                .name = "s6d02a1",
 924                .spi = &(struct spi_board_info) {
 925                        .modalias = "fb_s6d02a1",
 926                        .max_speed_hz = 32000000,
 927                        .mode = SPI_MODE_0,
 928                        .platform_data = &(struct fbtft_platform_data) {
 929                                .display = {
 930                                        .buswidth = 8,
 931                                        .backlight = 1,
 932                                },
 933                                .bgr = true,
 934                                .gpios = (const struct fbtft_gpio []) {
 935                                        { "reset", 25 },
 936                                        { "dc", 24 },
 937                                        { "led", 23 },
 938                                        {},
 939                                },
 940                        }
 941                }
 942        }, {
 943                .name = "sainsmart18",
 944                .spi = &(struct spi_board_info) {
 945                        .modalias = "fb_st7735r",
 946                        .max_speed_hz = 32000000,
 947                        .mode = SPI_MODE_0,
 948                        .platform_data = &(struct fbtft_platform_data) {
 949                                .display = {
 950                                        .buswidth = 8,
 951                                },
 952                                .gpios = (const struct fbtft_gpio []) {
 953                                        { "reset", 25 },
 954                                        { "dc", 24 },
 955                                        {},
 956                                },
 957                        }
 958                }
 959        }, {
 960                .name = "sainsmart32",
 961                .pdev = &(struct platform_device) {
 962                        .name = "fb_ssd1289",
 963                        .id = 0,
 964                        .dev = {
 965                        .release = fbtft_device_pdev_release,
 966                        .platform_data = &(struct fbtft_platform_data) {
 967                                .display = {
 968                                        .buswidth = 16,
 969                                        .txbuflen = -2, /* disable buffer */
 970                                        .backlight = 1,
 971                                        .fbtftops.write = write_gpio16_wr_slow,
 972                                },
 973                                .bgr = true,
 974                                .gpios = (const struct fbtft_gpio []) {
 975                                        {},
 976                                },
 977                        },
 978                },
 979                }
 980        }, {
 981                .name = "sainsmart32_fast",
 982                .pdev = &(struct platform_device) {
 983                        .name = "fb_ssd1289",
 984                        .id = 0,
 985                        .dev = {
 986                        .release = fbtft_device_pdev_release,
 987                        .platform_data = &(struct fbtft_platform_data) {
 988                                .display = {
 989                                        .buswidth = 16,
 990                                        .txbuflen = -2, /* disable buffer */
 991                                        .backlight = 1,
 992                                },
 993                                .bgr = true,
 994                                .gpios = (const struct fbtft_gpio []) {
 995                                        {},
 996                                },
 997                        },
 998                },
 999                }
1000        }, {
1001                .name = "sainsmart32_latched",
1002                .pdev = &(struct platform_device) {
1003                        .name = "fb_ssd1289",
1004                        .id = 0,
1005                        .dev = {
1006                        .release = fbtft_device_pdev_release,
1007                        .platform_data = &(struct fbtft_platform_data) {
1008                                .display = {
1009                                        .buswidth = 16,
1010                                        .txbuflen = -2, /* disable buffer */
1011                                        .backlight = 1,
1012                                        .fbtftops.write =
1013                                                fbtft_write_gpio16_wr_latched,
1014                                },
1015                                .bgr = true,
1016                                .gpios = (const struct fbtft_gpio []) {
1017                                        {},
1018                                },
1019                        },
1020                },
1021                }
1022        }, {
1023                .name = "sainsmart32_spi",
1024                .spi = &(struct spi_board_info) {
1025                        .modalias = "fb_ssd1289",
1026                        .max_speed_hz = 16000000,
1027                        .mode = SPI_MODE_0,
1028                        .platform_data = &(struct fbtft_platform_data) {
1029                                .display = {
1030                                        .buswidth = 8,
1031                                        .backlight = 1,
1032                                },
1033                                .bgr = true,
1034                                .gpios = (const struct fbtft_gpio []) {
1035                                        { "reset", 25 },
1036                                        { "dc", 24 },
1037                                        {},
1038                                },
1039                        }
1040                }
1041        }, {
1042                .name = "spidev",
1043                .spi = &(struct spi_board_info) {
1044                        .modalias = "spidev",
1045                        .max_speed_hz = 500000,
1046                        .bus_num = 0,
1047                        .chip_select = 0,
1048                        .mode = SPI_MODE_0,
1049                        .platform_data = &(struct fbtft_platform_data) {
1050                                .gpios = (const struct fbtft_gpio []) {
1051                                        {},
1052                                },
1053                        }
1054                }
1055        }, {
1056                .name = "ssd1331",
1057                .spi = &(struct spi_board_info) {
1058                        .modalias = "fb_ssd1331",
1059                        .max_speed_hz = 20000000,
1060                        .mode = SPI_MODE_3,
1061                        .platform_data = &(struct fbtft_platform_data) {
1062                                .display = {
1063                                        .buswidth = 8,
1064                                },
1065                                .gpios = (const struct fbtft_gpio []) {
1066                                        { "reset", 24 },
1067                                        { "dc", 25 },
1068                                        {},
1069                                },
1070                        }
1071                }
1072        }, {
1073                .name = "tinylcd35",
1074                .spi = &(struct spi_board_info) {
1075                        .modalias = "fb_tinylcd",
1076                        .max_speed_hz = 32000000,
1077                        .mode = SPI_MODE_0,
1078                        .platform_data = &(struct fbtft_platform_data) {
1079                                .display = {
1080                                        .buswidth = 8,
1081                                        .backlight = 1,
1082                                },
1083                                .bgr = true,
1084                                .gpios = (const struct fbtft_gpio []) {
1085                                        { "reset", 25 },
1086                                        { "dc", 24 },
1087                                        { "led", 18 },
1088                                        {},
1089                                },
1090                        }
1091                }
1092        }, {
1093                .name = "tm022hdh26",
1094                .spi = &(struct spi_board_info) {
1095                        .modalias = "fb_ili9341",
1096                        .max_speed_hz = 32000000,
1097                        .mode = SPI_MODE_0,
1098                        .platform_data = &(struct fbtft_platform_data) {
1099                                .display = {
1100                                        .buswidth = 8,
1101                                        .backlight = 1,
1102                                },
1103                                .bgr = true,
1104                                .gpios = (const struct fbtft_gpio []) {
1105                                        { "reset", 25 },
1106                                        { "dc", 24 },
1107                                        { "led", 18 },
1108                                        {},
1109                                },
1110                        }
1111                }
1112        }, {
1113                .name = "tontec35_9481", /* boards before 02 July 2014 */
1114                .spi = &(struct spi_board_info) {
1115                        .modalias = "fb_ili9481",
1116                        .max_speed_hz = 128000000,
1117                        .mode = SPI_MODE_3,
1118                        .platform_data = &(struct fbtft_platform_data) {
1119                                .display = {
1120                                        .buswidth = 8,
1121                                        .backlight = 1,
1122                                },
1123                                .bgr = true,
1124                                .gpios = (const struct fbtft_gpio []) {
1125                                        { "reset", 15 },
1126                                        { "dc", 25 },
1127                                        { "led_", 18 },
1128                                        {},
1129                                },
1130                        }
1131                }
1132        }, {
1133                .name = "tontec35_9486", /* boards after 02 July 2014 */
1134                .spi = &(struct spi_board_info) {
1135                        .modalias = "fb_ili9486",
1136                        .max_speed_hz = 128000000,
1137                        .mode = SPI_MODE_3,
1138                        .platform_data = &(struct fbtft_platform_data) {
1139                                .display = {
1140                                        .buswidth = 8,
1141                                        .backlight = 1,
1142                                },
1143                                .bgr = true,
1144                                .gpios = (const struct fbtft_gpio []) {
1145                                        { "reset", 15 },
1146                                        { "dc", 25 },
1147                                        { "led_", 18 },
1148                                        {},
1149                                },
1150                        }
1151                }
1152        }, {
1153                .name = "upd161704",
1154                .spi = &(struct spi_board_info) {
1155                        .modalias = "fb_upd161704",
1156                        .max_speed_hz = 32000000,
1157                        .mode = SPI_MODE_0,
1158                        .platform_data = &(struct fbtft_platform_data) {
1159                                .display = {
1160                                        .buswidth = 8,
1161                                },
1162                                .gpios = (const struct fbtft_gpio []) {
1163                                        { "reset", 24 },
1164                                        { "dc", 25 },
1165                                        {},
1166                                },
1167                        }
1168                }
1169        }, {
1170                .name = "waveshare32b",
1171                .spi = &(struct spi_board_info) {
1172                        .modalias = "fb_ili9340",
1173                        .max_speed_hz = 48000000,
1174                        .mode = SPI_MODE_0,
1175                        .platform_data = &(struct fbtft_platform_data) {
1176                                .display = {
1177                                        .buswidth = 8,
1178                                        .backlight = 1,
1179                                        .init_sequence =
1180                                                waveshare32b_init_sequence,
1181                                },
1182                                .bgr = true,
1183                                .gpios = (const struct fbtft_gpio []) {
1184                                        { "reset", 27 },
1185                                        { "dc", 22 },
1186                                        {},
1187                                },
1188                        }
1189                }
1190        }, {
1191                .name = "waveshare22",
1192                .spi = &(struct spi_board_info) {
1193                        .modalias = "fb_bd663474",
1194                        .max_speed_hz = 32000000,
1195                        .mode = SPI_MODE_3,
1196                        .platform_data = &(struct fbtft_platform_data) {
1197                                .display = {
1198                                        .buswidth = 8,
1199                                },
1200                                .gpios = (const struct fbtft_gpio []) {
1201                                        { "reset", 24 },
1202                                        { "dc", 25 },
1203                                        {},
1204                                },
1205                        }
1206                }
1207        }, {
1208                /* This should be the last item.
1209                 * Used with the custom argument
1210                 */
1211                .name = "",
1212                .spi = &(struct spi_board_info) {
1213                        .modalias = "",
1214                        .max_speed_hz = 0,
1215                        .mode = SPI_MODE_0,
1216                        .platform_data = &(struct fbtft_platform_data) {
1217                                .gpios = (const struct fbtft_gpio []) {
1218                                        {},
1219                                },
1220                        }
1221                },
1222                .pdev = &(struct platform_device) {
1223                        .name = "",
1224                        .id = 0,
1225                        .dev = {
1226                        .release = fbtft_device_pdev_release,
1227                        .platform_data = &(struct fbtft_platform_data) {
1228                                .gpios = (const struct fbtft_gpio []) {
1229                                        {},
1230                                },
1231                        },
1232                },
1233                },
1234        }
1235};
1236
1237static int write_gpio16_wr_slow(struct fbtft_par *par, void *buf, size_t len)
1238{
1239        u16 data;
1240        int i;
1241#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
1242        static u16 prev_data;
1243#endif
1244
1245        fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
1246                "%s(len=%d): ", __func__, len);
1247
1248        while (len) {
1249                data = *(u16 *)buf;
1250
1251                /* Start writing by pulling down /WR */
1252                gpio_set_value(par->gpio.wr, 0);
1253
1254                /* Set data */
1255#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
1256                if (data == prev_data) {
1257                        gpio_set_value(par->gpio.wr, 0); /* used as delay */
1258                } else {
1259                        for (i = 0; i < 16; i++) {
1260                                if ((data & 1) != (prev_data & 1))
1261                                        gpio_set_value(par->gpio.db[i],
1262                                                                data & 1);
1263                                data >>= 1;
1264                                prev_data >>= 1;
1265                        }
1266                }
1267#else
1268                for (i = 0; i < 16; i++) {
1269                        gpio_set_value(par->gpio.db[i], data & 1);
1270                        data >>= 1;
1271                }
1272#endif
1273
1274                /* Pullup /WR */
1275                gpio_set_value(par->gpio.wr, 1);
1276
1277#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
1278                prev_data = *(u16 *)buf;
1279#endif
1280                buf += 2;
1281                len -= 2;
1282        }
1283
1284        return 0;
1285}
1286
1287static void adafruit18_green_tab_set_addr_win(struct fbtft_par *par,
1288                                                int xs, int ys, int xe, int ye)
1289{
1290        write_reg(par, 0x2A, 0, xs + 2, 0, xe + 2);
1291        write_reg(par, 0x2B, 0, ys + 1, 0, ye + 1);
1292        write_reg(par, 0x2C);
1293}
1294
1295/* used if gpios parameter is present */
1296static struct fbtft_gpio fbtft_device_param_gpios[MAX_GPIOS + 1] = { };
1297
1298static void fbtft_device_pdev_release(struct device *dev)
1299{
1300/* Needed to silence this message:
1301 * Device 'xxx' does not have a release() function,
1302 * it is broken and must be fixed
1303 */
1304}
1305
1306static int spi_device_found(struct device *dev, void *data)
1307{
1308        struct spi_device *spi = to_spi_device(dev);
1309
1310        dev_info(dev, "%s %s %dkHz %d bits mode=0x%02X\n", spi->modalias,
1311                 dev_name(dev), spi->max_speed_hz / 1000, spi->bits_per_word,
1312                 spi->mode);
1313
1314        return 0;
1315}
1316
1317static void pr_spi_devices(void)
1318{
1319        pr_debug("SPI devices registered:\n");
1320        bus_for_each_dev(&spi_bus_type, NULL, NULL, spi_device_found);
1321}
1322
1323static int p_device_found(struct device *dev, void *data)
1324{
1325        struct platform_device
1326        *pdev = to_platform_device(dev);
1327
1328        if (strstr(pdev->name, "fb"))
1329                dev_info(dev, "%s id=%d pdata? %s\n", pdev->name, pdev->id,
1330                         pdev->dev.platform_data ? "yes" : "no");
1331
1332        return 0;
1333}
1334
1335static void pr_p_devices(void)
1336{
1337        pr_debug("'fb' Platform devices registered:\n");
1338        bus_for_each_dev(&platform_bus_type, NULL, NULL, p_device_found);
1339}
1340
1341#ifdef MODULE
1342static void fbtft_device_spi_delete(struct spi_master *master, unsigned int cs)
1343{
1344        struct device *dev;
1345        char str[32];
1346
1347        snprintf(str, sizeof(str), "%s.%u", dev_name(&master->dev), cs);
1348
1349        dev = bus_find_device_by_name(&spi_bus_type, NULL, str);
1350        if (dev) {
1351                if (verbose)
1352                        dev_info(dev, "Deleting %s\n", str);
1353                device_del(dev);
1354        }
1355}
1356
1357static int fbtft_device_spi_device_register(struct spi_board_info *spi)
1358{
1359        struct spi_master *master;
1360
1361        master = spi_busnum_to_master(spi->bus_num);
1362        if (!master) {
1363                pr_err("spi_busnum_to_master(%d) returned NULL\n",
1364                       spi->bus_num);
1365                return -EINVAL;
1366        }
1367        /* make sure it's available */
1368        fbtft_device_spi_delete(master, spi->chip_select);
1369        spi_device = spi_new_device(master, spi);
1370        put_device(&master->dev);
1371        if (!spi_device) {
1372                dev_err(&master->dev, "spi_new_device() returned NULL\n");
1373                return -EPERM;
1374        }
1375        return 0;
1376}
1377#else
1378static int fbtft_device_spi_device_register(struct spi_board_info *spi)
1379{
1380        return spi_register_board_info(spi, 1);
1381}
1382#endif
1383
1384static int __init fbtft_device_init(void)
1385{
1386        struct spi_board_info *spi = NULL;
1387        struct fbtft_platform_data *pdata;
1388        const struct fbtft_gpio *gpio = NULL;
1389        char *p_gpio, *p_name, *p_num;
1390        bool found = false;
1391        int i = 0;
1392        long val;
1393        int ret = 0;
1394
1395        if (!name) {
1396#ifdef MODULE
1397                pr_err("missing module parameter: 'name'\n");
1398                return -EINVAL;
1399#else
1400                return 0;
1401#endif
1402        }
1403
1404        if (init_num > FBTFT_MAX_INIT_SEQUENCE) {
1405                pr_err("init parameter: exceeded max array size: %d\n",
1406                       FBTFT_MAX_INIT_SEQUENCE);
1407                return -EINVAL;
1408        }
1409
1410        /* parse module parameter: gpios */
1411        while ((p_gpio = strsep(&gpios, ","))) {
1412                if (!strchr(p_gpio, ':')) {
1413                        pr_err("error: missing ':' in gpios parameter: %s\n",
1414                               p_gpio);
1415                        return -EINVAL;
1416                }
1417                p_num = p_gpio;
1418                p_name = strsep(&p_num, ":");
1419                if (!p_name || !p_num) {
1420                        pr_err("something bad happened parsing gpios parameter: %s\n",
1421                               p_gpio);
1422                        return -EINVAL;
1423                }
1424                ret = kstrtol(p_num, 10, &val);
1425                if (ret) {
1426                        pr_err("could not parse number in gpios parameter: %s:%s\n",
1427                               p_name, p_num);
1428                        return -EINVAL;
1429                }
1430                strncpy(fbtft_device_param_gpios[i].name, p_name,
1431                        FBTFT_GPIO_NAME_SIZE - 1);
1432                fbtft_device_param_gpios[i++].gpio = (int)val;
1433                if (i == MAX_GPIOS) {
1434                        pr_err("gpios parameter: exceeded max array size: %d\n",
1435                               MAX_GPIOS);
1436                        return -EINVAL;
1437                }
1438        }
1439        if (fbtft_device_param_gpios[0].name[0])
1440                gpio = fbtft_device_param_gpios;
1441
1442        if (verbose > 2) {
1443                pr_spi_devices(); /* print list of registered SPI devices */
1444                pr_p_devices(); /* print list of 'fb' platform devices */
1445        }
1446
1447        pr_debug("name='%s', busnum=%d, cs=%d\n", name, busnum, cs);
1448
1449        if (rotate > 0 && rotate < 4) {
1450                rotate = (4 - rotate) * 90;
1451                pr_warn("argument 'rotate' should be an angle. Values 1-3 is deprecated. Setting it to %d.\n",
1452                        rotate);
1453        }
1454        if (rotate != 0 && rotate != 90 && rotate != 180 && rotate != 270) {
1455                pr_warn("argument 'rotate' illegal value: %d. Setting it to 0.\n",
1456                        rotate);
1457                rotate = 0;
1458        }
1459
1460        /* name=list lists all supported displays */
1461        if (strncmp(name, "list", FBTFT_GPIO_NAME_SIZE) == 0) {
1462                pr_info("Supported displays:\n");
1463
1464                for (i = 0; i < ARRAY_SIZE(displays); i++)
1465                        pr_info("%s\n", displays[i].name);
1466                return -ECANCELED;
1467        }
1468
1469        if (custom) {
1470                i = ARRAY_SIZE(displays) - 1;
1471                displays[i].name = name;
1472                if (speed == 0) {
1473                        displays[i].pdev->name = name;
1474                        displays[i].spi = NULL;
1475                } else {
1476                        size_t len;
1477
1478                        len = strlcpy(displays[i].spi->modalias, name,
1479                                SPI_NAME_SIZE);
1480                        if (len >= SPI_NAME_SIZE)
1481                                pr_warn("modalias (name) truncated to: %s\n",
1482                                        displays[i].spi->modalias);
1483                        displays[i].pdev = NULL;
1484                }
1485        }
1486
1487        for (i = 0; i < ARRAY_SIZE(displays); i++) {
1488                if (strncmp(name, displays[i].name, SPI_NAME_SIZE) == 0) {
1489                        if (displays[i].spi) {
1490                                spi = displays[i].spi;
1491                                spi->chip_select = cs;
1492                                spi->bus_num = busnum;
1493                                if (speed)
1494                                        spi->max_speed_hz = speed;
1495                                if (mode != -1)
1496                                        spi->mode = mode;
1497                                pdata = (void *)spi->platform_data;
1498                        } else if (displays[i].pdev) {
1499                                p_device = displays[i].pdev;
1500                                pdata = p_device->dev.platform_data;
1501                        } else {
1502                                pr_err("broken displays array\n");
1503                                return -EINVAL;
1504                        }
1505
1506                        pdata->rotate = rotate;
1507                        if (bgr == 0)
1508                                pdata->bgr = false;
1509                        else if (bgr == 1)
1510                                pdata->bgr = true;
1511                        if (startbyte)
1512                                pdata->startbyte = startbyte;
1513                        if (gamma)
1514                                pdata->gamma = gamma;
1515                        pdata->display.debug = debug;
1516                        if (fps)
1517                                pdata->fps = fps;
1518                        if (txbuflen)
1519                                pdata->txbuflen = txbuflen;
1520                        if (init_num)
1521                                pdata->display.init_sequence = init;
1522                        if (gpio)
1523                                pdata->gpios = gpio;
1524                        if (custom) {
1525                                pdata->display.width = width;
1526                                pdata->display.height = height;
1527                                pdata->display.buswidth = buswidth;
1528                                pdata->display.backlight = 1;
1529                        }
1530
1531                        if (displays[i].spi) {
1532                                ret = fbtft_device_spi_device_register(spi);
1533                                if (ret) {
1534                                        pr_err("failed to register SPI device\n");
1535                                        return ret;
1536                                }
1537                        } else {
1538                                ret = platform_device_register(p_device);
1539                                if (ret < 0) {
1540                                        pr_err("platform_device_register() returned %d\n",
1541                                               ret);
1542                                        return ret;
1543                                }
1544                        }
1545                        found = true;
1546                        break;
1547                }
1548        }
1549
1550        if (!found) {
1551                pr_err("display not supported: '%s'\n", name);
1552                return -EINVAL;
1553        }
1554
1555        if (verbose && pdata && pdata->gpios) {
1556                gpio = pdata->gpios;
1557                pr_info("GPIOS used by '%s':\n", name);
1558                found = false;
1559                while (verbose && gpio->name[0]) {
1560                        pr_info("'%s' = GPIO%d\n", gpio->name, gpio->gpio);
1561                        gpio++;
1562                        found = true;
1563                }
1564                if (!found)
1565                        pr_info("(none)\n");
1566        }
1567
1568        if (spi_device && (verbose > 1))
1569                pr_spi_devices();
1570        if (p_device && (verbose > 1))
1571                pr_p_devices();
1572
1573        return 0;
1574}
1575
1576static void __exit fbtft_device_exit(void)
1577{
1578        if (spi_device) {
1579                device_del(&spi_device->dev);
1580                kfree(spi_device);
1581        }
1582
1583        if (p_device)
1584                platform_device_unregister(p_device);
1585
1586}
1587
1588arch_initcall(fbtft_device_init);
1589module_exit(fbtft_device_exit);
1590
1591MODULE_DESCRIPTION("Add a FBTFT device.");
1592MODULE_AUTHOR("Noralf Tronnes");
1593MODULE_LICENSE("GPL");
1594