Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.8-rc4 550 lines 13 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * MIPI-DSI Sony ACX424AKP panel driver. This is a 480x864 4 * AMOLED panel with a command-only DSI interface. 5 * 6 * Copyright (C) Linaro Ltd. 2019 7 * Author: Linus Walleij 8 * Based on code and know-how from Marcus Lorentzon 9 * Copyright (C) ST-Ericsson SA 2010 10 */ 11#include <linux/backlight.h> 12#include <linux/delay.h> 13#include <linux/gpio/consumer.h> 14#include <linux/module.h> 15#include <linux/of.h> 16#include <linux/regulator/consumer.h> 17 18#include <video/mipi_display.h> 19 20#include <drm/drm_mipi_dsi.h> 21#include <drm/drm_modes.h> 22#include <drm/drm_panel.h> 23#include <drm/drm_print.h> 24 25#define ACX424_DCS_READ_ID1 0xDA 26#define ACX424_DCS_READ_ID2 0xDB 27#define ACX424_DCS_READ_ID3 0xDC 28#define ACX424_DCS_SET_MDDI 0xAE 29 30/* 31 * Sony seems to use vendor ID 0x81 32 */ 33#define DISPLAY_SONY_ACX424AKP_ID1 0x811b 34#define DISPLAY_SONY_ACX424AKP_ID2 0x811a 35/* 36 * The third ID looks like a bug, vendor IDs begin at 0x80 37 * and panel 00 ... seems like default values. 38 */ 39#define DISPLAY_SONY_ACX424AKP_ID3 0x8000 40 41struct acx424akp { 42 struct drm_panel panel; 43 struct device *dev; 44 struct backlight_device *bl; 45 struct regulator *supply; 46 struct gpio_desc *reset_gpio; 47 bool video_mode; 48}; 49 50static const struct drm_display_mode sony_acx424akp_vid_mode = { 51 .clock = 27234, 52 .hdisplay = 480, 53 .hsync_start = 480 + 15, 54 .hsync_end = 480 + 15 + 0, 55 .htotal = 480 + 15 + 0 + 15, 56 .vdisplay = 864, 57 .vsync_start = 864 + 14, 58 .vsync_end = 864 + 14 + 1, 59 .vtotal = 864 + 14 + 1 + 11, 60 .vrefresh = 60, 61 .width_mm = 48, 62 .height_mm = 84, 63 .flags = DRM_MODE_FLAG_PVSYNC, 64}; 65 66/* 67 * The timings are not very helpful as the display is used in 68 * command mode using the maximum HS frequency. 69 */ 70static const struct drm_display_mode sony_acx424akp_cmd_mode = { 71 .clock = 35478, 72 .hdisplay = 480, 73 .hsync_start = 480 + 154, 74 .hsync_end = 480 + 154 + 16, 75 .htotal = 480 + 154 + 16 + 32, 76 .vdisplay = 864, 77 .vsync_start = 864 + 1, 78 .vsync_end = 864 + 1 + 1, 79 .vtotal = 864 + 1 + 1 + 1, 80 /* 81 * Some desired refresh rate, experiments at the maximum "pixel" 82 * clock speed (HS clock 420 MHz) yields around 117Hz. 83 */ 84 .vrefresh = 60, 85 .width_mm = 48, 86 .height_mm = 84, 87}; 88 89static inline struct acx424akp *panel_to_acx424akp(struct drm_panel *panel) 90{ 91 return container_of(panel, struct acx424akp, panel); 92} 93 94#define FOSC 20 /* 20Mhz */ 95#define SCALE_FACTOR_NS_DIV_MHZ 1000 96 97static int acx424akp_set_brightness(struct backlight_device *bl) 98{ 99 struct acx424akp *acx = bl_get_data(bl); 100 struct mipi_dsi_device *dsi = to_mipi_dsi_device(acx->dev); 101 int period_ns = 1023; 102 int duty_ns = bl->props.brightness; 103 u8 pwm_ratio; 104 u8 pwm_div; 105 u8 par; 106 int ret; 107 108 /* Calculate the PWM duty cycle in n/256's */ 109 pwm_ratio = max(((duty_ns * 256) / period_ns) - 1, 1); 110 pwm_div = max(1, 111 ((FOSC * period_ns) / 256) / 112 SCALE_FACTOR_NS_DIV_MHZ); 113 114 /* Set up PWM dutycycle ONE byte (differs from the standard) */ 115 DRM_DEV_DEBUG(acx->dev, "calculated duty cycle %02x\n", pwm_ratio); 116 ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 117 &pwm_ratio, 1); 118 if (ret < 0) { 119 DRM_DEV_ERROR(acx->dev, 120 "failed to set display PWM ratio (%d)\n", 121 ret); 122 return ret; 123 } 124 125 /* 126 * Sequence to write PWMDIV: 127 * address data 128 * 0xF3 0xAA CMD2 Unlock 129 * 0x00 0x01 Enter CMD2 page 0 130 * 0X7D 0x01 No reload MTP of CMD2 P1 131 * 0x22 PWMDIV 132 * 0x7F 0xAA CMD2 page 1 lock 133 */ 134 par = 0xaa; 135 ret = mipi_dsi_dcs_write(dsi, 0xf3, &par, 1); 136 if (ret < 0) { 137 DRM_DEV_ERROR(acx->dev, 138 "failed to unlock CMD 2 (%d)\n", 139 ret); 140 return ret; 141 } 142 par = 0x01; 143 ret = mipi_dsi_dcs_write(dsi, 0x00, &par, 1); 144 if (ret < 0) { 145 DRM_DEV_ERROR(acx->dev, 146 "failed to enter page 1 (%d)\n", 147 ret); 148 return ret; 149 } 150 par = 0x01; 151 ret = mipi_dsi_dcs_write(dsi, 0x7d, &par, 1); 152 if (ret < 0) { 153 DRM_DEV_ERROR(acx->dev, 154 "failed to disable MTP reload (%d)\n", 155 ret); 156 return ret; 157 } 158 ret = mipi_dsi_dcs_write(dsi, 0x22, &pwm_div, 1); 159 if (ret < 0) { 160 DRM_DEV_ERROR(acx->dev, 161 "failed to set PWM divisor (%d)\n", 162 ret); 163 return ret; 164 } 165 par = 0xaa; 166 ret = mipi_dsi_dcs_write(dsi, 0x7f, &par, 1); 167 if (ret < 0) { 168 DRM_DEV_ERROR(acx->dev, 169 "failed to lock CMD 2 (%d)\n", 170 ret); 171 return ret; 172 } 173 174 /* Enable backlight */ 175 par = 0x24; 176 ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 177 &par, 1); 178 if (ret < 0) { 179 DRM_DEV_ERROR(acx->dev, 180 "failed to enable display backlight (%d)\n", 181 ret); 182 return ret; 183 } 184 185 return 0; 186} 187 188static const struct backlight_ops acx424akp_bl_ops = { 189 .update_status = acx424akp_set_brightness, 190}; 191 192static int acx424akp_read_id(struct acx424akp *acx) 193{ 194 struct mipi_dsi_device *dsi = to_mipi_dsi_device(acx->dev); 195 u8 vendor, version, panel; 196 u16 val; 197 int ret; 198 199 ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID1, &vendor, 1); 200 if (ret < 0) { 201 DRM_DEV_ERROR(acx->dev, "could not vendor ID byte\n"); 202 return ret; 203 } 204 ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID2, &version, 1); 205 if (ret < 0) { 206 DRM_DEV_ERROR(acx->dev, "could not read device version byte\n"); 207 return ret; 208 } 209 ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID3, &panel, 1); 210 if (ret < 0) { 211 DRM_DEV_ERROR(acx->dev, "could not read panel ID byte\n"); 212 return ret; 213 } 214 215 if (vendor == 0x00) { 216 DRM_DEV_ERROR(acx->dev, "device vendor ID is zero\n"); 217 return -ENODEV; 218 } 219 220 val = (vendor << 8) | panel; 221 switch (val) { 222 case DISPLAY_SONY_ACX424AKP_ID1: 223 case DISPLAY_SONY_ACX424AKP_ID2: 224 case DISPLAY_SONY_ACX424AKP_ID3: 225 DRM_DEV_INFO(acx->dev, 226 "MTP vendor: %02x, version: %02x, panel: %02x\n", 227 vendor, version, panel); 228 break; 229 default: 230 DRM_DEV_INFO(acx->dev, 231 "unknown vendor: %02x, version: %02x, panel: %02x\n", 232 vendor, version, panel); 233 break; 234 } 235 236 return 0; 237} 238 239static int acx424akp_power_on(struct acx424akp *acx) 240{ 241 int ret; 242 243 ret = regulator_enable(acx->supply); 244 if (ret) { 245 DRM_DEV_ERROR(acx->dev, "failed to enable supply (%d)\n", ret); 246 return ret; 247 } 248 249 /* Assert RESET */ 250 gpiod_set_value_cansleep(acx->reset_gpio, 1); 251 udelay(20); 252 /* De-assert RESET */ 253 gpiod_set_value_cansleep(acx->reset_gpio, 0); 254 usleep_range(11000, 20000); 255 256 return 0; 257} 258 259static void acx424akp_power_off(struct acx424akp *acx) 260{ 261 /* Assert RESET */ 262 gpiod_set_value_cansleep(acx->reset_gpio, 1); 263 usleep_range(11000, 20000); 264 265 regulator_disable(acx->supply); 266} 267 268static int acx424akp_prepare(struct drm_panel *panel) 269{ 270 struct acx424akp *acx = panel_to_acx424akp(panel); 271 struct mipi_dsi_device *dsi = to_mipi_dsi_device(acx->dev); 272 const u8 mddi = 3; 273 int ret; 274 275 ret = acx424akp_power_on(acx); 276 if (ret) 277 return ret; 278 279 ret = acx424akp_read_id(acx); 280 if (ret) { 281 DRM_DEV_ERROR(acx->dev, "failed to read panel ID (%d)\n", ret); 282 goto err_power_off; 283 } 284 285 /* Enabe tearing mode: send TE (tearing effect) at VBLANK */ 286 ret = mipi_dsi_dcs_set_tear_on(dsi, 287 MIPI_DSI_DCS_TEAR_MODE_VBLANK); 288 if (ret) { 289 DRM_DEV_ERROR(acx->dev, "failed to enable vblank TE (%d)\n", 290 ret); 291 goto err_power_off; 292 } 293 294 /* 295 * Set MDDI 296 * 297 * This presumably deactivates the Qualcomm MDDI interface and 298 * selects DSI, similar code is found in other drivers such as the 299 * Sharp LS043T1LE01 which makes us suspect that this panel may be 300 * using a Novatek NT35565 or similar display driver chip that shares 301 * this command. Due to the lack of documentation we cannot know for 302 * sure. 303 */ 304 ret = mipi_dsi_dcs_write(dsi, ACX424_DCS_SET_MDDI, 305 &mddi, sizeof(mddi)); 306 if (ret < 0) { 307 DRM_DEV_ERROR(acx->dev, "failed to set MDDI (%d)\n", ret); 308 goto err_power_off; 309 } 310 311 /* Exit sleep mode */ 312 ret = mipi_dsi_dcs_exit_sleep_mode(dsi); 313 if (ret) { 314 DRM_DEV_ERROR(acx->dev, "failed to exit sleep mode (%d)\n", 315 ret); 316 goto err_power_off; 317 } 318 msleep(140); 319 320 ret = mipi_dsi_dcs_set_display_on(dsi); 321 if (ret) { 322 DRM_DEV_ERROR(acx->dev, "failed to turn display on (%d)\n", 323 ret); 324 goto err_power_off; 325 } 326 if (acx->video_mode) { 327 /* In video mode turn peripheral on */ 328 ret = mipi_dsi_turn_on_peripheral(dsi); 329 if (ret) { 330 dev_err(acx->dev, "failed to turn on peripheral\n"); 331 goto err_power_off; 332 } 333 } 334 335 acx->bl->props.power = FB_BLANK_NORMAL; 336 337 return 0; 338 339err_power_off: 340 acx424akp_power_off(acx); 341 return ret; 342} 343 344static int acx424akp_unprepare(struct drm_panel *panel) 345{ 346 struct acx424akp *acx = panel_to_acx424akp(panel); 347 struct mipi_dsi_device *dsi = to_mipi_dsi_device(acx->dev); 348 u8 par; 349 int ret; 350 351 /* Disable backlight */ 352 par = 0x00; 353 ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 354 &par, 1); 355 if (ret) { 356 DRM_DEV_ERROR(acx->dev, 357 "failed to disable display backlight (%d)\n", 358 ret); 359 return ret; 360 } 361 362 ret = mipi_dsi_dcs_set_display_off(dsi); 363 if (ret) { 364 DRM_DEV_ERROR(acx->dev, "failed to turn display off (%d)\n", 365 ret); 366 return ret; 367 } 368 369 /* Enter sleep mode */ 370 ret = mipi_dsi_dcs_enter_sleep_mode(dsi); 371 if (ret) { 372 DRM_DEV_ERROR(acx->dev, "failed to enter sleep mode (%d)\n", 373 ret); 374 return ret; 375 } 376 msleep(85); 377 378 acx424akp_power_off(acx); 379 acx->bl->props.power = FB_BLANK_POWERDOWN; 380 381 return 0; 382} 383 384static int acx424akp_enable(struct drm_panel *panel) 385{ 386 struct acx424akp *acx = panel_to_acx424akp(panel); 387 388 /* 389 * The backlight is on as long as the display is on 390 * so no use to call backlight_enable() here. 391 */ 392 acx->bl->props.power = FB_BLANK_UNBLANK; 393 394 return 0; 395} 396 397static int acx424akp_disable(struct drm_panel *panel) 398{ 399 struct acx424akp *acx = panel_to_acx424akp(panel); 400 401 /* 402 * The backlight is on as long as the display is on 403 * so no use to call backlight_disable() here. 404 */ 405 acx->bl->props.power = FB_BLANK_NORMAL; 406 407 return 0; 408} 409 410static int acx424akp_get_modes(struct drm_panel *panel, 411 struct drm_connector *connector) 412{ 413 struct acx424akp *acx = panel_to_acx424akp(panel); 414 struct drm_display_mode *mode; 415 416 if (acx->video_mode) 417 mode = drm_mode_duplicate(connector->dev, 418 &sony_acx424akp_vid_mode); 419 else 420 mode = drm_mode_duplicate(connector->dev, 421 &sony_acx424akp_cmd_mode); 422 if (!mode) { 423 DRM_ERROR("bad mode or failed to add mode\n"); 424 return -EINVAL; 425 } 426 drm_mode_set_name(mode); 427 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 428 429 connector->display_info.width_mm = mode->width_mm; 430 connector->display_info.height_mm = mode->height_mm; 431 432 drm_mode_probed_add(connector, mode); 433 434 return 1; /* Number of modes */ 435} 436 437static const struct drm_panel_funcs acx424akp_drm_funcs = { 438 .disable = acx424akp_disable, 439 .unprepare = acx424akp_unprepare, 440 .prepare = acx424akp_prepare, 441 .enable = acx424akp_enable, 442 .get_modes = acx424akp_get_modes, 443}; 444 445static int acx424akp_probe(struct mipi_dsi_device *dsi) 446{ 447 struct device *dev = &dsi->dev; 448 struct acx424akp *acx; 449 int ret; 450 451 acx = devm_kzalloc(dev, sizeof(struct acx424akp), GFP_KERNEL); 452 if (!acx) 453 return -ENOMEM; 454 acx->video_mode = of_property_read_bool(dev->of_node, 455 "enforce-video-mode"); 456 457 mipi_dsi_set_drvdata(dsi, acx); 458 acx->dev = dev; 459 460 dsi->lanes = 2; 461 dsi->format = MIPI_DSI_FMT_RGB888; 462 /* 463 * FIXME: these come from the ST-Ericsson vendor driver for the 464 * HREF520 and seems to reflect limitations in the PLLs on that 465 * platform, if you have the datasheet, please cross-check the 466 * actual max rates. 467 */ 468 dsi->lp_rate = 19200000; 469 dsi->hs_rate = 420160000; 470 471 if (acx->video_mode) 472 /* Burst mode using event for sync */ 473 dsi->mode_flags = 474 MIPI_DSI_MODE_VIDEO | 475 MIPI_DSI_MODE_VIDEO_BURST; 476 else 477 dsi->mode_flags = 478 MIPI_DSI_CLOCK_NON_CONTINUOUS | 479 MIPI_DSI_MODE_EOT_PACKET; 480 481 acx->supply = devm_regulator_get(dev, "vddi"); 482 if (IS_ERR(acx->supply)) 483 return PTR_ERR(acx->supply); 484 485 /* This asserts RESET by default */ 486 acx->reset_gpio = devm_gpiod_get_optional(dev, "reset", 487 GPIOD_OUT_HIGH); 488 if (IS_ERR(acx->reset_gpio)) { 489 ret = PTR_ERR(acx->reset_gpio); 490 if (ret != -EPROBE_DEFER) 491 DRM_DEV_ERROR(dev, "failed to request GPIO (%d)\n", 492 ret); 493 return ret; 494 } 495 496 drm_panel_init(&acx->panel, dev, &acx424akp_drm_funcs, 497 DRM_MODE_CONNECTOR_DSI); 498 499 acx->bl = devm_backlight_device_register(dev, "acx424akp", dev, acx, 500 &acx424akp_bl_ops, NULL); 501 if (IS_ERR(acx->bl)) { 502 DRM_DEV_ERROR(dev, "failed to register backlight device\n"); 503 return PTR_ERR(acx->bl); 504 } 505 acx->bl->props.max_brightness = 1023; 506 acx->bl->props.brightness = 512; 507 acx->bl->props.power = FB_BLANK_POWERDOWN; 508 509 ret = drm_panel_add(&acx->panel); 510 if (ret < 0) 511 return ret; 512 513 ret = mipi_dsi_attach(dsi); 514 if (ret < 0) { 515 drm_panel_remove(&acx->panel); 516 return ret; 517 } 518 519 return 0; 520} 521 522static int acx424akp_remove(struct mipi_dsi_device *dsi) 523{ 524 struct acx424akp *acx = mipi_dsi_get_drvdata(dsi); 525 526 mipi_dsi_detach(dsi); 527 drm_panel_remove(&acx->panel); 528 529 return 0; 530} 531 532static const struct of_device_id acx424akp_of_match[] = { 533 { .compatible = "sony,acx424akp" }, 534 { /* sentinel */ } 535}; 536MODULE_DEVICE_TABLE(of, acx424akp_of_match); 537 538static struct mipi_dsi_driver acx424akp_driver = { 539 .probe = acx424akp_probe, 540 .remove = acx424akp_remove, 541 .driver = { 542 .name = "panel-sony-acx424akp", 543 .of_match_table = acx424akp_of_match, 544 }, 545}; 546module_mipi_dsi_driver(acx424akp_driver); 547 548MODULE_AUTHOR("Linus Wallei <linus.walleij@linaro.org>"); 549MODULE_DESCRIPTION("MIPI-DSI Sony acx424akp Panel Driver"); 550MODULE_LICENSE("GPL v2");