794 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Ilitek ILI9341 TFT LCD drm_panel driver.4 *5 * This panel can be configured to support:6 * - 16-bit parallel RGB interface7 * - 18-bit parallel RGB interface8 * - 4-line serial spi interface9 *10 * Copyright (C) 2021 Dillon Min <dillon.minfei@gmail.com>11 *12 * For dbi+dpi part:13 * Derived from drivers/drm/gpu/panel/panel-ilitek-ili9322.c14 * the reuse of DBI abstraction part referred from Linus's patch15 * "drm/panel: s6e63m0: Switch to DBI abstraction for SPI"16 *17 * For only-dbi part, copy from David's code (drm/tiny/ili9341.c)18 * Copyright 2018 David Lechner <david@lechnology.com>19 */20 21#include <linux/backlight.h>22#include <linux/bitops.h>23#include <linux/delay.h>24#include <linux/gpio/consumer.h>25#include <linux/mod_devicetable.h>26#include <linux/module.h>27#include <linux/property.h>28#include <linux/regulator/consumer.h>29#include <linux/spi/spi.h>30 31#include <video/mipi_display.h>32 33#include <drm/drm_atomic_helper.h>34#include <drm/drm_drv.h>35#include <drm/drm_fbdev_dma.h>36#include <drm/drm_gem_atomic_helper.h>37#include <drm/drm_gem_dma_helper.h>38#include <drm/drm_gem_framebuffer_helper.h>39#include <drm/drm_mipi_dbi.h>40#include <drm/drm_modes.h>41#include <drm/drm_panel.h>42#include <drm/drm_print.h>43 44#define ILI9341_RGB_INTERFACE 0xb0 /* RGB Interface Signal Control */45#define ILI9341_FRC 0xb1 /* Frame Rate Control register */46#define ILI9341_DFC 0xb6 /* Display Function Control register */47#define ILI9341_POWER1 0xc0 /* Power Control 1 register */48#define ILI9341_POWER2 0xc1 /* Power Control 2 register */49#define ILI9341_VCOM1 0xc5 /* VCOM Control 1 register */50#define ILI9341_VCOM2 0xc7 /* VCOM Control 2 register */51#define ILI9341_POWERA 0xcb /* Power control A register */52#define ILI9341_POWERB 0xcf /* Power control B register */53#define ILI9341_PGAMMA 0xe0 /* Positive Gamma Correction register */54#define ILI9341_NGAMMA 0xe1 /* Negative Gamma Correction register */55#define ILI9341_DTCA 0xe8 /* Driver timing control A */56#define ILI9341_DTCB 0xea /* Driver timing control B */57#define ILI9341_POWER_SEQ 0xed /* Power on sequence register */58#define ILI9341_3GAMMA_EN 0xf2 /* 3 Gamma enable register */59#define ILI9341_INTERFACE 0xf6 /* Interface control register */60#define ILI9341_PRC 0xf7 /* Pump ratio control register */61#define ILI9341_ETMOD 0xb7 /* Entry mode set */62 63#define ILI9341_MADCTL_BGR BIT(3)64#define ILI9341_MADCTL_MV BIT(5)65#define ILI9341_MADCTL_MX BIT(6)66#define ILI9341_MADCTL_MY BIT(7)67 68#define ILI9341_POWER_B_LEN 369#define ILI9341_POWER_SEQ_LEN 470#define ILI9341_DTCA_LEN 371#define ILI9341_DTCB_LEN 272#define ILI9341_POWER_A_LEN 573#define ILI9341_DFC_1_LEN 274#define ILI9341_FRC_LEN 275#define ILI9341_VCOM_1_LEN 276#define ILI9341_DFC_2_LEN 477#define ILI9341_COLUMN_ADDR_LEN 478#define ILI9341_PAGE_ADDR_LEN 479#define ILI9341_INTERFACE_LEN 380#define ILI9341_PGAMMA_LEN 1581#define ILI9341_NGAMMA_LEN 1582#define ILI9341_CA_LEN 383 84#define ILI9341_PIXEL_DPI_16_BITS (BIT(6) | BIT(4))85#define ILI9341_PIXEL_DPI_18_BITS (BIT(6) | BIT(5))86#define ILI9341_GAMMA_CURVE_1 BIT(0)87#define ILI9341_IF_WE_MODE BIT(0)88#define ILI9341_IF_BIG_ENDIAN 0x0089#define ILI9341_IF_DM_RGB BIT(2)90#define ILI9341_IF_DM_INTERNAL 0x0091#define ILI9341_IF_DM_VSYNC BIT(3)92#define ILI9341_IF_RM_RGB BIT(1)93#define ILI9341_IF_RIM_RGB 0x0094 95#define ILI9341_COLUMN_ADDR 0x00ef96#define ILI9341_PAGE_ADDR 0x013f97 98#define ILI9341_RGB_EPL BIT(0)99#define ILI9341_RGB_DPL BIT(1)100#define ILI9341_RGB_HSPL BIT(2)101#define ILI9341_RGB_VSPL BIT(3)102#define ILI9341_RGB_DE_MODE BIT(6)103#define ILI9341_RGB_DISP_PATH_MEM BIT(7)104 105#define ILI9341_DBI_VCOMH_4P6V 0x23106#define ILI9341_DBI_PWR_2_DEFAULT 0x10107#define ILI9341_DBI_PRC_NORMAL 0x20108#define ILI9341_DBI_VCOM_1_VMH_4P25V 0x3e109#define ILI9341_DBI_VCOM_1_VML_1P5V 0x28110#define ILI9341_DBI_VCOM_2_DEC_58 0x86111#define ILI9341_DBI_FRC_DIVA 0x00112#define ILI9341_DBI_FRC_RTNA 0x1b113#define ILI9341_DBI_EMS_GAS BIT(0)114#define ILI9341_DBI_EMS_DTS BIT(1)115#define ILI9341_DBI_EMS_GON BIT(2)116 117/* struct ili9341_config - the system specific ILI9341 configuration */118struct ili9341_config {119 u32 max_spi_speed;120 /* mode: the drm display mode */121 const struct drm_display_mode mode;122 /* ca: TODO: need comments for this register */123 u8 ca[ILI9341_CA_LEN];124 /* power_b: Power control B (CFh) */125 u8 power_b[ILI9341_POWER_B_LEN];126 /* power_seq: Power on sequence control (EDh) */127 u8 power_seq[ILI9341_POWER_SEQ_LEN];128 /* dtca: Driver timing control A (E8h) */129 u8 dtca[ILI9341_DTCA_LEN];130 /* dtcb: Driver timing control B (EAh) */131 u8 dtcb[ILI9341_DTCB_LEN];132 /* power_a: Power control A (CBh) */133 u8 power_a[ILI9341_POWER_A_LEN];134 /* frc: Frame Rate Control (In Normal Mode/Full Colors) (B1h) */135 u8 frc[ILI9341_FRC_LEN];136 /* prc: Pump ratio control (F7h) */137 u8 prc;138 /* dfc_1: B6h DISCTRL (Display Function Control) */139 u8 dfc_1[ILI9341_DFC_1_LEN];140 /* power_1: Power Control 1 (C0h) */141 u8 power_1;142 /* power_2: Power Control 2 (C1h) */143 u8 power_2;144 /* vcom_1: VCOM Control 1(C5h) */145 u8 vcom_1[ILI9341_VCOM_1_LEN];146 /* vcom_2: VCOM Control 2(C7h) */147 u8 vcom_2;148 /* address_mode: Memory Access Control (36h) */149 u8 address_mode;150 /* g3amma_en: Enable 3G (F2h) */151 u8 g3amma_en;152 /* rgb_interface: RGB Interface Signal Control (B0h) */153 u8 rgb_interface;154 /* dfc_2: refer to dfc_1 */155 u8 dfc_2[ILI9341_DFC_2_LEN];156 /* column_addr: Column Address Set (2Ah) */157 u8 column_addr[ILI9341_COLUMN_ADDR_LEN];158 /* page_addr: Page Address Set (2Bh) */159 u8 page_addr[ILI9341_PAGE_ADDR_LEN];160 /* interface: Interface Control (F6h) */161 u8 interface[ILI9341_INTERFACE_LEN];162 /*163 * pixel_format: This command sets the pixel format for the RGB164 * image data used by165 */166 u8 pixel_format;167 /*168 * gamma_curve: This command is used to select the desired Gamma169 * curve for the170 */171 u8 gamma_curve;172 /* pgamma: Positive Gamma Correction (E0h) */173 u8 pgamma[ILI9341_PGAMMA_LEN];174 /* ngamma: Negative Gamma Correction (E1h) */175 u8 ngamma[ILI9341_NGAMMA_LEN];176};177 178struct ili9341 {179 struct device *dev;180 const struct ili9341_config *conf;181 struct drm_panel panel;182 struct gpio_desc *reset_gpio;183 struct gpio_desc *dc_gpio;184 struct mipi_dbi *dbi;185 u32 max_spi_speed;186 struct regulator_bulk_data supplies[3];187};188 189/*190 * The Stm32f429-disco board has a panel ili9341 connected to ltdc controller191 */192static const struct ili9341_config ili9341_stm32f429_disco_data = {193 .max_spi_speed = 10000000,194 .mode = {195 .clock = 6100,196 .hdisplay = 240,197 .hsync_start = 240 + 10,/* hfp 10 */198 .hsync_end = 240 + 10 + 10,/* hsync 10 */199 .htotal = 240 + 10 + 10 + 20,/* hbp 20 */200 .vdisplay = 320,201 .vsync_start = 320 + 4,/* vfp 4 */202 .vsync_end = 320 + 4 + 2,/* vsync 2 */203 .vtotal = 320 + 4 + 2 + 2,/* vbp 2 */204 .flags = 0,205 .width_mm = 65,206 .height_mm = 50,207 .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,208 },209 .ca = {0xc3, 0x08, 0x50},210 .power_b = {0x00, 0xc1, 0x30},211 .power_seq = {0x64, 0x03, 0x12, 0x81},212 .dtca = {0x85, 0x00, 0x78},213 .power_a = {0x39, 0x2c, 0x00, 0x34, 0x02},214 .prc = 0x20,215 .dtcb = {0x00, 0x00},216 /* 0x00 fosc, 0x1b 70hz */217 .frc = {0x00, 0x1b},218 /*219 * 0x0a Interval scan, AGND AGND AGND AGND220 * 0xa2 Normally white, G1 -> G320, S720 -> S1,221 * Scan Cycle 5 frames,85ms222 */223 .dfc_1 = {0x0a, 0xa2},224 /* 0x10 3.65v */225 .power_1 = 0x10,226 /* 0x10 AVDD=vci*2, VGH=vci*7, VGL=-vci*4 */227 .power_2 = 0x10,228 /* 0x45 VCOMH 4.425v, 0x15 VCOML -1.975*/229 .vcom_1 = {0x45, 0x15},230 /* 0x90 offset voltage, VMH-48, VML-48 */231 .vcom_2 = 0x90,232 /*233 * 0xc8 Row Address Order, Column Address Order234 * BGR 1235 */236 .address_mode = 0xc8,237 .g3amma_en = 0x00,238 /*239 * 0xc2240 * Display Data Path: Memory241 * RGB: DE mode242 * DOTCLK polarity set (data fetched at the falling time)243 */244 .rgb_interface = ILI9341_RGB_DISP_PATH_MEM |245 ILI9341_RGB_DE_MODE |246 ILI9341_RGB_DPL,247 /*248 * 0x0a249 * Gate outputs in non-display area: Interval scan250 * Determine source/VCOM output in a non-display area in the partial251 * display mode: AGND AGND AGND AGND252 *253 * 0xa7254 * Scan Cycle: 15 frames255 * fFLM = 60Hz: 255ms256 * Liquid crystal type: Normally white257 * Gate Output Scan Direction: G1 -> G320258 * Source Output Scan Direction: S720 -> S1259 *260 * 0x27261 * LCD Driver Line: 320 lines262 *263 * 0x04264 * PCDIV: 4265 */266 .dfc_2 = {0x0a, 0xa7, 0x27, 0x04},267 /* column address: 240 */268 .column_addr = {0x00, 0x00, (ILI9341_COLUMN_ADDR >> 4) & 0xff,269 ILI9341_COLUMN_ADDR & 0xff},270 /* page address: 320 */271 .page_addr = {0x00, 0x00, (ILI9341_PAGE_ADDR >> 4) & 0xff,272 ILI9341_PAGE_ADDR & 0xff},273 /*274 * Memory write control: When the transfer number of data exceeds275 * (EC-SC+1)*(EP-SP+1), the column and page number will be276 * reset, and the exceeding data will be written into the following277 * column and page.278 * Display Operation Mode: RGB Interface Mode279 * Interface for RAM Access: RGB interface280 * 16- bit RGB interface (1 transfer/pixel)281 */282 .interface = {ILI9341_IF_WE_MODE, 0x00,283 ILI9341_IF_DM_RGB | ILI9341_IF_RM_RGB},284 /* DPI: 16 bits / pixel */285 .pixel_format = ILI9341_PIXEL_DPI_16_BITS,286 /* Curve Selected: Gamma curve 1 (G2.2) */287 .gamma_curve = ILI9341_GAMMA_CURVE_1,288 .pgamma = {0x0f, 0x29, 0x24, 0x0c, 0x0e,289 0x09, 0x4e, 0x78, 0x3c, 0x09,290 0x13, 0x05, 0x17, 0x11, 0x00},291 .ngamma = {0x00, 0x16, 0x1b, 0x04, 0x11,292 0x07, 0x31, 0x33, 0x42, 0x05,293 0x0c, 0x0a, 0x28, 0x2f, 0x0f},294};295 296static inline struct ili9341 *panel_to_ili9341(struct drm_panel *panel)297{298 return container_of(panel, struct ili9341, panel);299}300 301static void ili9341_dpi_init(struct ili9341 *ili)302{303 struct device *dev = (&ili->panel)->dev;304 struct mipi_dbi *dbi = ili->dbi;305 struct ili9341_config *cfg = (struct ili9341_config *)ili->conf;306 307 /* Power Control */308 mipi_dbi_command_stackbuf(dbi, 0xca, cfg->ca, ILI9341_CA_LEN);309 mipi_dbi_command_stackbuf(dbi, ILI9341_POWERB, cfg->power_b,310 ILI9341_POWER_B_LEN);311 mipi_dbi_command_stackbuf(dbi, ILI9341_POWER_SEQ, cfg->power_seq,312 ILI9341_POWER_SEQ_LEN);313 mipi_dbi_command_stackbuf(dbi, ILI9341_DTCA, cfg->dtca,314 ILI9341_DTCA_LEN);315 mipi_dbi_command_stackbuf(dbi, ILI9341_POWERA, cfg->power_a,316 ILI9341_POWER_A_LEN);317 mipi_dbi_command(ili->dbi, ILI9341_PRC, cfg->prc);318 mipi_dbi_command_stackbuf(dbi, ILI9341_DTCB, cfg->dtcb,319 ILI9341_DTCB_LEN);320 mipi_dbi_command_stackbuf(dbi, ILI9341_FRC, cfg->frc, ILI9341_FRC_LEN);321 mipi_dbi_command_stackbuf(dbi, ILI9341_DFC, cfg->dfc_1,322 ILI9341_DFC_1_LEN);323 mipi_dbi_command(dbi, ILI9341_POWER1, cfg->power_1);324 mipi_dbi_command(dbi, ILI9341_POWER2, cfg->power_2);325 326 /* VCOM */327 mipi_dbi_command_stackbuf(dbi, ILI9341_VCOM1, cfg->vcom_1,328 ILI9341_VCOM_1_LEN);329 mipi_dbi_command(dbi, ILI9341_VCOM2, cfg->vcom_2);330 mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, cfg->address_mode);331 332 /* Gamma */333 mipi_dbi_command(dbi, ILI9341_3GAMMA_EN, cfg->g3amma_en);334 mipi_dbi_command(dbi, ILI9341_RGB_INTERFACE, cfg->rgb_interface);335 mipi_dbi_command_stackbuf(dbi, ILI9341_DFC, cfg->dfc_2,336 ILI9341_DFC_2_LEN);337 338 /* Colomn address set */339 mipi_dbi_command_stackbuf(dbi, MIPI_DCS_SET_COLUMN_ADDRESS,340 cfg->column_addr, ILI9341_COLUMN_ADDR_LEN);341 342 /* Page address set */343 mipi_dbi_command_stackbuf(dbi, MIPI_DCS_SET_PAGE_ADDRESS,344 cfg->page_addr, ILI9341_PAGE_ADDR_LEN);345 mipi_dbi_command_stackbuf(dbi, ILI9341_INTERFACE, cfg->interface,346 ILI9341_INTERFACE_LEN);347 348 /* Format */349 mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT, cfg->pixel_format);350 mipi_dbi_command(dbi, MIPI_DCS_WRITE_MEMORY_START);351 msleep(200);352 mipi_dbi_command(dbi, MIPI_DCS_SET_GAMMA_CURVE, cfg->gamma_curve);353 mipi_dbi_command_stackbuf(dbi, ILI9341_PGAMMA, cfg->pgamma,354 ILI9341_PGAMMA_LEN);355 mipi_dbi_command_stackbuf(dbi, ILI9341_NGAMMA, cfg->ngamma,356 ILI9341_NGAMMA_LEN);357 mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);358 msleep(200);359 mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);360 mipi_dbi_command(dbi, MIPI_DCS_WRITE_MEMORY_START);361 362 dev_info(dev, "Initialized display rgb interface\n");363}364 365static int ili9341_dpi_power_on(struct ili9341 *ili)366{367 struct device *dev = (&ili->panel)->dev;368 int ret = 0;369 370 /* Assert RESET */371 gpiod_set_value(ili->reset_gpio, 1);372 373 /* Enable power */374 ret = regulator_bulk_enable(ARRAY_SIZE(ili->supplies),375 ili->supplies);376 if (ret < 0) {377 dev_err(dev, "unable to enable vcc\n");378 return ret;379 }380 msleep(20);381 382 /* De-assert RESET */383 gpiod_set_value(ili->reset_gpio, 0);384 msleep(20);385 386 return 0;387}388 389static int ili9341_dpi_power_off(struct ili9341 *ili)390{391 /* Assert RESET */392 gpiod_set_value(ili->reset_gpio, 1);393 394 /* Disable power */395 return regulator_bulk_disable(ARRAY_SIZE(ili->supplies),396 ili->supplies);397}398 399static int ili9341_dpi_disable(struct drm_panel *panel)400{401 struct ili9341 *ili = panel_to_ili9341(panel);402 403 mipi_dbi_command(ili->dbi, MIPI_DCS_SET_DISPLAY_OFF);404 return 0;405}406 407static int ili9341_dpi_unprepare(struct drm_panel *panel)408{409 struct ili9341 *ili = panel_to_ili9341(panel);410 411 return ili9341_dpi_power_off(ili);412}413 414static int ili9341_dpi_prepare(struct drm_panel *panel)415{416 struct ili9341 *ili = panel_to_ili9341(panel);417 int ret;418 419 ret = ili9341_dpi_power_on(ili);420 if (ret < 0)421 return ret;422 423 ili9341_dpi_init(ili);424 425 return 0;426}427 428static int ili9341_dpi_enable(struct drm_panel *panel)429{430 struct ili9341 *ili = panel_to_ili9341(panel);431 432 mipi_dbi_command(ili->dbi, MIPI_DCS_SET_DISPLAY_ON);433 return 0;434}435 436static int ili9341_dpi_get_modes(struct drm_panel *panel,437 struct drm_connector *connector)438{439 struct ili9341 *ili = panel_to_ili9341(panel);440 struct drm_device *drm = connector->dev;441 struct drm_display_mode *mode;442 struct drm_display_info *info;443 444 info = &connector->display_info;445 info->width_mm = ili->conf->mode.width_mm;446 info->height_mm = ili->conf->mode.height_mm;447 448 if (ili->conf->rgb_interface & ILI9341_RGB_DPL)449 info->bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;450 else451 info->bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;452 453 if (ili->conf->rgb_interface & ILI9341_RGB_EPL)454 info->bus_flags |= DRM_BUS_FLAG_DE_LOW;455 else456 info->bus_flags |= DRM_BUS_FLAG_DE_HIGH;457 458 mode = drm_mode_duplicate(drm, &ili->conf->mode);459 if (!mode) {460 drm_err(drm, "bad mode or failed to add mode\n");461 return -EINVAL;462 }463 drm_mode_set_name(mode);464 465 /* Set up the polarity */466 if (ili->conf->rgb_interface & ILI9341_RGB_HSPL)467 mode->flags |= DRM_MODE_FLAG_PHSYNC;468 else469 mode->flags |= DRM_MODE_FLAG_NHSYNC;470 471 if (ili->conf->rgb_interface & ILI9341_RGB_VSPL)472 mode->flags |= DRM_MODE_FLAG_PVSYNC;473 else474 mode->flags |= DRM_MODE_FLAG_NVSYNC;475 476 drm_mode_probed_add(connector, mode);477 478 return 1; /* Number of modes */479}480 481static const struct drm_panel_funcs ili9341_dpi_funcs = {482 .disable = ili9341_dpi_disable,483 .unprepare = ili9341_dpi_unprepare,484 .prepare = ili9341_dpi_prepare,485 .enable = ili9341_dpi_enable,486 .get_modes = ili9341_dpi_get_modes,487};488 489static void ili9341_dbi_enable(struct drm_simple_display_pipe *pipe,490 struct drm_crtc_state *crtc_state,491 struct drm_plane_state *plane_state)492{493 struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev);494 struct mipi_dbi *dbi = &dbidev->dbi;495 u8 addr_mode;496 int ret, idx;497 498 if (!drm_dev_enter(pipe->crtc.dev, &idx))499 return;500 501 ret = mipi_dbi_poweron_conditional_reset(dbidev);502 if (ret < 0)503 goto out_exit;504 if (ret == 1)505 goto out_enable;506 507 mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_OFF);508 509 mipi_dbi_command(dbi, ILI9341_POWERB, 0x00, 0xc1, 0x30);510 mipi_dbi_command(dbi, ILI9341_POWER_SEQ, 0x64, 0x03, 0x12, 0x81);511 mipi_dbi_command(dbi, ILI9341_DTCA, 0x85, 0x00, 0x78);512 mipi_dbi_command(dbi, ILI9341_POWERA, 0x39, 0x2c, 0x00, 0x34, 0x02);513 mipi_dbi_command(dbi, ILI9341_PRC, ILI9341_DBI_PRC_NORMAL);514 mipi_dbi_command(dbi, ILI9341_DTCB, 0x00, 0x00);515 516 /* Power Control */517 mipi_dbi_command(dbi, ILI9341_POWER1, ILI9341_DBI_VCOMH_4P6V);518 mipi_dbi_command(dbi, ILI9341_POWER2, ILI9341_DBI_PWR_2_DEFAULT);519 /* VCOM */520 mipi_dbi_command(dbi, ILI9341_VCOM1, ILI9341_DBI_VCOM_1_VMH_4P25V,521 ILI9341_DBI_VCOM_1_VML_1P5V);522 mipi_dbi_command(dbi, ILI9341_VCOM2, ILI9341_DBI_VCOM_2_DEC_58);523 524 /* Memory Access Control */525 mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT,526 MIPI_DCS_PIXEL_FMT_16BIT);527 528 /* Frame Rate */529 mipi_dbi_command(dbi, ILI9341_FRC, ILI9341_DBI_FRC_DIVA & 0x03,530 ILI9341_DBI_FRC_RTNA & 0x1f);531 532 /* Gamma */533 mipi_dbi_command(dbi, ILI9341_3GAMMA_EN, 0x00);534 mipi_dbi_command(dbi, MIPI_DCS_SET_GAMMA_CURVE, ILI9341_GAMMA_CURVE_1);535 mipi_dbi_command(dbi, ILI9341_PGAMMA,536 0x0f, 0x31, 0x2b, 0x0c, 0x0e, 0x08, 0x4e, 0xf1,537 0x37, 0x07, 0x10, 0x03, 0x0e, 0x09, 0x00);538 mipi_dbi_command(dbi, ILI9341_NGAMMA,539 0x00, 0x0e, 0x14, 0x03, 0x11, 0x07, 0x31, 0xc1,540 0x48, 0x08, 0x0f, 0x0c, 0x31, 0x36, 0x0f);541 542 /* DDRAM */543 mipi_dbi_command(dbi, ILI9341_ETMOD, ILI9341_DBI_EMS_GAS |544 ILI9341_DBI_EMS_DTS |545 ILI9341_DBI_EMS_GON);546 547 /* Display */548 mipi_dbi_command(dbi, ILI9341_DFC, 0x08, 0x82, 0x27, 0x00);549 mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);550 msleep(100);551 552 mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);553 msleep(100);554 555out_enable:556 switch (dbidev->rotation) {557 default:558 addr_mode = ILI9341_MADCTL_MX;559 break;560 case 90:561 addr_mode = ILI9341_MADCTL_MV;562 break;563 case 180:564 addr_mode = ILI9341_MADCTL_MY;565 break;566 case 270:567 addr_mode = ILI9341_MADCTL_MV | ILI9341_MADCTL_MY |568 ILI9341_MADCTL_MX;569 break;570 }571 572 addr_mode |= ILI9341_MADCTL_BGR;573 mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);574 mipi_dbi_enable_flush(dbidev, crtc_state, plane_state);575 drm_info(&dbidev->drm, "Initialized display serial interface\n");576out_exit:577 drm_dev_exit(idx);578}579 580static const struct drm_simple_display_pipe_funcs ili9341_dbi_funcs = {581 DRM_MIPI_DBI_SIMPLE_DISPLAY_PIPE_FUNCS(ili9341_dbi_enable),582};583 584static const struct drm_display_mode ili9341_dbi_mode = {585 DRM_SIMPLE_MODE(240, 320, 37, 49),586};587 588DEFINE_DRM_GEM_DMA_FOPS(ili9341_dbi_fops);589 590static struct drm_driver ili9341_dbi_driver = {591 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,592 .fops = &ili9341_dbi_fops,593 DRM_GEM_DMA_DRIVER_OPS_VMAP,594 .debugfs_init = mipi_dbi_debugfs_init,595 .name = "ili9341",596 .desc = "Ilitek ILI9341",597 .date = "20210716",598 .major = 1,599 .minor = 0,600};601 602static int ili9341_dbi_probe(struct spi_device *spi, struct gpio_desc *dc,603 struct gpio_desc *reset)604{605 struct device *dev = &spi->dev;606 struct mipi_dbi_dev *dbidev;607 struct mipi_dbi *dbi;608 struct drm_device *drm;609 struct regulator *vcc;610 u32 rotation = 0;611 int ret;612 613 vcc = devm_regulator_get_optional(dev, "vcc");614 if (IS_ERR(vcc)) {615 dev_err(dev, "get optional vcc failed\n");616 vcc = NULL;617 }618 619 dbidev = devm_drm_dev_alloc(dev, &ili9341_dbi_driver,620 struct mipi_dbi_dev, drm);621 if (IS_ERR(dbidev))622 return PTR_ERR(dbidev);623 624 dbi = &dbidev->dbi;625 drm = &dbidev->drm;626 dbi->reset = reset;627 dbidev->regulator = vcc;628 629 drm_mode_config_init(drm);630 631 dbidev->backlight = devm_of_find_backlight(dev);632 if (IS_ERR(dbidev->backlight))633 return PTR_ERR(dbidev->backlight);634 635 device_property_read_u32(dev, "rotation", &rotation);636 637 ret = mipi_dbi_spi_init(spi, dbi, dc);638 if (ret)639 return ret;640 641 ret = mipi_dbi_dev_init(dbidev, &ili9341_dbi_funcs,642 &ili9341_dbi_mode, rotation);643 if (ret)644 return ret;645 646 drm_mode_config_reset(drm);647 648 ret = drm_dev_register(drm, 0);649 if (ret)650 return ret;651 652 spi_set_drvdata(spi, drm);653 654 drm_fbdev_dma_setup(drm, 0);655 656 return 0;657}658 659static int ili9341_dpi_probe(struct spi_device *spi, struct gpio_desc *dc,660 struct gpio_desc *reset)661{662 struct device *dev = &spi->dev;663 struct ili9341 *ili;664 int ret;665 666 ili = devm_kzalloc(dev, sizeof(struct ili9341), GFP_KERNEL);667 if (!ili)668 return -ENOMEM;669 670 ili->dbi = devm_kzalloc(dev, sizeof(struct mipi_dbi),671 GFP_KERNEL);672 if (!ili->dbi)673 return -ENOMEM;674 675 ili->supplies[0].supply = "vci";676 ili->supplies[1].supply = "vddi";677 ili->supplies[2].supply = "vddi-led";678 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ili->supplies),679 ili->supplies);680 if (ret < 0) {681 dev_err(dev, "failed to get regulators: %d\n", ret);682 return ret;683 }684 685 ret = mipi_dbi_spi_init(spi, ili->dbi, dc);686 if (ret)687 return ret;688 689 spi_set_drvdata(spi, ili);690 ili->reset_gpio = reset;691 /*692 * Every new incarnation of this display must have a unique693 * data entry for the system in this driver.694 */695 ili->conf = device_get_match_data(dev);696 if (!ili->conf) {697 dev_err(dev, "missing device configuration\n");698 return -ENODEV;699 }700 701 ili->max_spi_speed = ili->conf->max_spi_speed;702 drm_panel_init(&ili->panel, dev, &ili9341_dpi_funcs,703 DRM_MODE_CONNECTOR_DPI);704 drm_panel_add(&ili->panel);705 706 return 0;707}708 709static int ili9341_probe(struct spi_device *spi)710{711 struct device *dev = &spi->dev;712 struct gpio_desc *dc;713 struct gpio_desc *reset;714 const struct spi_device_id *id = spi_get_device_id(spi);715 716 reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);717 if (IS_ERR(reset))718 return dev_err_probe(dev, PTR_ERR(reset), "Failed to get gpio 'reset'\n");719 720 dc = devm_gpiod_get_optional(dev, "dc", GPIOD_OUT_LOW);721 if (IS_ERR(dc))722 return dev_err_probe(dev, PTR_ERR(dc), "Failed to get gpio 'dc'\n");723 724 if (!strcmp(id->name, "sf-tc240t-9370-t"))725 return ili9341_dpi_probe(spi, dc, reset);726 727 if (!strcmp(id->name, "yx240qv29"))728 return ili9341_dbi_probe(spi, dc, reset);729 730 return -ENODEV;731}732 733static void ili9341_remove(struct spi_device *spi)734{735 const struct spi_device_id *id = spi_get_device_id(spi);736 struct ili9341 *ili = spi_get_drvdata(spi);737 struct drm_device *drm = spi_get_drvdata(spi);738 739 if (!strcmp(id->name, "sf-tc240t-9370-t")) {740 ili9341_dpi_power_off(ili);741 drm_panel_remove(&ili->panel);742 } else if (!strcmp(id->name, "yx240qv29")) {743 drm_dev_unplug(drm);744 drm_atomic_helper_shutdown(drm);745 }746}747 748static void ili9341_shutdown(struct spi_device *spi)749{750 const struct spi_device_id *id = spi_get_device_id(spi);751 752 if (!strcmp(id->name, "yx240qv29"))753 drm_atomic_helper_shutdown(spi_get_drvdata(spi));754}755 756static const struct of_device_id ili9341_of_match[] = {757 {758 .compatible = "st,sf-tc240t-9370-t",759 .data = &ili9341_stm32f429_disco_data,760 },761 {762 /* porting from tiny/ili9341.c763 * for original mipi dbi compitable764 */765 .compatible = "adafruit,yx240qv29",766 .data = NULL,767 },768 { }769};770MODULE_DEVICE_TABLE(of, ili9341_of_match);771 772static const struct spi_device_id ili9341_id[] = {773 { "yx240qv29", 0 },774 { "sf-tc240t-9370-t", 0 },775 { }776};777MODULE_DEVICE_TABLE(spi, ili9341_id);778 779static struct spi_driver ili9341_driver = {780 .probe = ili9341_probe,781 .remove = ili9341_remove,782 .shutdown = ili9341_shutdown,783 .id_table = ili9341_id,784 .driver = {785 .name = "panel-ilitek-ili9341",786 .of_match_table = ili9341_of_match,787 },788};789module_spi_driver(ili9341_driver);790 791MODULE_AUTHOR("Dillon Min <dillon.minfei@gmail.com>");792MODULE_DESCRIPTION("ILI9341 LCD panel driver");793MODULE_LICENSE("GPL v2");794