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