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