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