1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * MIPI DSI Bus 4 * 5 * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd. 6 * Andrzej Hajda <a.hajda@samsung.com> 7 */ 8 9 #include <drm/drm_mipi_dsi.h> 10 11 #include <config.h> 12 #include <common.h> 13 #include <errno.h> 14 #include <malloc.h> 15 16 /** 17 * mipi_dsi_attach - attach a DSI device to its DSI host 18 * @dsi: DSI peripheral 19 */ 20 int mipi_dsi_attach(struct mipi_dsi_device *dsi) 21 { 22 const struct mipi_dsi_host_ops *ops = dsi->host->ops; 23 24 if (!ops || !ops->attach) 25 return -ENOSYS; 26 27 return ops->attach(dsi->host, dsi); 28 } 29 30 /** 31 * mipi_dsi_detach - detach a DSI device from its DSI host 32 * @dsi: DSI peripheral 33 */ 34 int mipi_dsi_detach(struct mipi_dsi_device *dsi) 35 { 36 const struct mipi_dsi_host_ops *ops = dsi->host->ops; 37 38 if (!ops || !ops->detach) 39 return -ENOSYS; 40 41 return ops->detach(dsi->host, dsi); 42 } 43 44 static ssize_t mipi_dsi_device_transfer(struct mipi_dsi_device *dsi, 45 struct mipi_dsi_msg *msg) 46 { 47 const struct mipi_dsi_host_ops *ops = dsi->host->ops; 48 49 if (!ops || !ops->transfer) 50 return -ENOSYS; 51 52 if (dsi->mode_flags & MIPI_DSI_MODE_LPM) 53 msg->flags |= MIPI_DSI_MSG_USE_LPM; 54 55 return ops->transfer(dsi->host, msg); 56 } 57 58 /** 59 * mipi_dsi_packet_format_is_short - check if a packet is of the short format 60 * @type: MIPI DSI data type of the packet 61 * 62 * Return: true if the packet for the given data type is a short packet, false 63 * otherwise. 64 */ 65 bool mipi_dsi_packet_format_is_short(u8 type) 66 { 67 switch (type) { 68 case MIPI_DSI_V_SYNC_START: 69 case MIPI_DSI_V_SYNC_END: 70 case MIPI_DSI_H_SYNC_START: 71 case MIPI_DSI_H_SYNC_END: 72 case MIPI_DSI_END_OF_TRANSMISSION: 73 case MIPI_DSI_COLOR_MODE_OFF: 74 case MIPI_DSI_COLOR_MODE_ON: 75 case MIPI_DSI_SHUTDOWN_PERIPHERAL: 76 case MIPI_DSI_TURN_ON_PERIPHERAL: 77 case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: 78 case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: 79 case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: 80 case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM: 81 case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM: 82 case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM: 83 case MIPI_DSI_DCS_SHORT_WRITE: 84 case MIPI_DSI_DCS_SHORT_WRITE_PARAM: 85 case MIPI_DSI_DCS_READ: 86 case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE: 87 return true; 88 } 89 90 return false; 91 } 92 93 /** 94 * mipi_dsi_packet_format_is_long - check if a packet is of the long format 95 * @type: MIPI DSI data type of the packet 96 * 97 * Return: true if the packet for the given data type is a long packet, false 98 * otherwise. 99 */ 100 bool mipi_dsi_packet_format_is_long(u8 type) 101 { 102 switch (type) { 103 case MIPI_DSI_NULL_PACKET: 104 case MIPI_DSI_BLANKING_PACKET: 105 case MIPI_DSI_GENERIC_LONG_WRITE: 106 case MIPI_DSI_DCS_LONG_WRITE: 107 case MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20: 108 case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24: 109 case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16: 110 case MIPI_DSI_PACKED_PIXEL_STREAM_30: 111 case MIPI_DSI_PACKED_PIXEL_STREAM_36: 112 case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12: 113 case MIPI_DSI_PACKED_PIXEL_STREAM_16: 114 case MIPI_DSI_PACKED_PIXEL_STREAM_18: 115 case MIPI_DSI_PIXEL_STREAM_3BYTE_18: 116 case MIPI_DSI_PACKED_PIXEL_STREAM_24: 117 return true; 118 } 119 120 return false; 121 } 122 123 /** 124 * mipi_dsi_create_packet - create a packet from a message according to the 125 * DSI protocol 126 * @packet: pointer to a DSI packet structure 127 * @msg: message to translate into a packet 128 * 129 * Return: 0 on success or a negative error code on failure. 130 */ 131 int mipi_dsi_create_packet(struct mipi_dsi_packet *packet, 132 const struct mipi_dsi_msg *msg) 133 { 134 if (!packet || !msg) 135 return -EINVAL; 136 137 /* do some minimum sanity checking */ 138 if (!mipi_dsi_packet_format_is_short(msg->type) && 139 !mipi_dsi_packet_format_is_long(msg->type)) 140 return -EINVAL; 141 142 if (msg->channel > 3) 143 return -EINVAL; 144 145 memset(packet, 0, sizeof(*packet)); 146 packet->header[0] = ((msg->channel & 0x3) << 6) | (msg->type & 0x3f); 147 if (mipi_dsi_packet_format_is_long(msg->type)) { 148 packet->header[1] = (msg->tx_len >> 0) & 0xff; 149 packet->header[2] = (msg->tx_len >> 8) & 0xff; 150 151 packet->payload_length = msg->tx_len; 152 packet->payload = msg->tx_buf; 153 } else { 154 const u8 *tx = msg->tx_buf; 155 156 packet->header[1] = (msg->tx_len > 0) ? tx[0] : 0; 157 packet->header[2] = (msg->tx_len > 1) ? tx[1] : 0; 158 } 159 160 packet->size = sizeof(packet->header) + packet->payload_length; 161 162 return 0; 163 } 164 165 /** 166 * mipi_dsi_shutdown_peripheral() - sends a Shutdown Peripheral command 167 * @dsi: DSI peripheral device 168 * 169 * Return: 0 on success or a negative error code on failure. 170 */ 171 int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi) 172 { 173 struct mipi_dsi_msg msg = { 174 .channel = dsi->channel, 175 .type = MIPI_DSI_SHUTDOWN_PERIPHERAL, 176 .tx_buf = (u8 [2]) { 0, 0 }, 177 .tx_len = 2, 178 }; 179 int ret = mipi_dsi_device_transfer(dsi, &msg); 180 181 return (ret < 0) ? ret : 0; 182 } 183 184 /** 185 * mipi_dsi_turn_on_peripheral() - sends a Turn On Peripheral command 186 * @dsi: DSI peripheral device 187 * 188 * Return: 0 on success or a negative error code on failure. 189 */ 190 int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi) 191 { 192 struct mipi_dsi_msg msg = { 193 .channel = dsi->channel, 194 .type = MIPI_DSI_TURN_ON_PERIPHERAL, 195 .tx_buf = (u8 [2]) { 0, 0 }, 196 .tx_len = 2, 197 }; 198 int ret = mipi_dsi_device_transfer(dsi, &msg); 199 200 return (ret < 0) ? ret : 0; 201 } 202 203 /* 204 * mipi_dsi_set_maximum_return_packet_size() - specify the maximum size of the 205 * the payload in a long packet transmitted from the peripheral back to the 206 * host processor 207 * @dsi: DSI peripheral device 208 * @value: the maximum size of the payload 209 * 210 * Return: 0 on success or a negative error code on failure. 211 */ 212 int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi, 213 u16 value) 214 { 215 u8 tx[2] = { value & 0xff, value >> 8 }; 216 struct mipi_dsi_msg msg = { 217 .channel = dsi->channel, 218 .type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, 219 .tx_len = sizeof(tx), 220 .tx_buf = tx, 221 }; 222 int ret = mipi_dsi_device_transfer(dsi, &msg); 223 224 return (ret < 0) ? ret : 0; 225 } 226 227 /** 228 * mipi_dsi_generic_write() - transmit data using a generic write packet 229 * @dsi: DSI peripheral device 230 * @payload: buffer containing the payload 231 * @size: size of payload buffer 232 * 233 * This function will automatically choose the right data type depending on 234 * the payload length. 235 * 236 * Return: The number of bytes transmitted on success or a negative error code 237 * on failure. 238 */ 239 ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload, 240 size_t size) 241 { 242 struct mipi_dsi_msg msg = { 243 .channel = dsi->channel, 244 .tx_buf = payload, 245 .tx_len = size 246 }; 247 248 switch (size) { 249 case 0: 250 msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM; 251 break; 252 case 1: 253 msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM; 254 break; 255 case 2: 256 msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM; 257 break; 258 default: 259 msg.type = MIPI_DSI_GENERIC_LONG_WRITE; 260 break; 261 } 262 263 return mipi_dsi_device_transfer(dsi, &msg); 264 } 265 266 /** 267 * mipi_dsi_generic_read() - receive data using a generic read packet 268 * @dsi: DSI peripheral device 269 * @params: buffer containing the request parameters 270 * @num_params: number of request parameters 271 * @data: buffer in which to return the received data 272 * @size: size of receive buffer 273 * 274 * This function will automatically choose the right data type depending on 275 * the number of parameters passed in. 276 * 277 * Return: The number of bytes successfully read or a negative error code on 278 * failure. 279 */ 280 ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params, 281 size_t num_params, void *data, size_t size) 282 { 283 struct mipi_dsi_msg msg = { 284 .channel = dsi->channel, 285 .tx_len = num_params, 286 .tx_buf = params, 287 .rx_len = size, 288 .rx_buf = data 289 }; 290 291 switch (num_params) { 292 case 0: 293 msg.type = MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM; 294 break; 295 296 case 1: 297 msg.type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM; 298 break; 299 300 case 2: 301 msg.type = MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM; 302 break; 303 304 default: 305 return -EINVAL; 306 } 307 308 return mipi_dsi_device_transfer(dsi, &msg); 309 } 310 311 /** 312 * mipi_dsi_dcs_write_buffer() - transmit a DCS command with payload 313 * @dsi: DSI peripheral device 314 * @data: buffer containing data to be transmitted 315 * @len: size of transmission buffer 316 * 317 * This function will automatically choose the right data type depending on 318 * the command payload length. 319 * 320 * Return: The number of bytes successfully transmitted or a negative error 321 * code on failure. 322 */ 323 ssize_t mipi_dsi_dcs_write_buffer(struct mipi_dsi_device *dsi, 324 const void *data, size_t len) 325 { 326 struct mipi_dsi_msg msg = { 327 .channel = dsi->channel, 328 .tx_buf = data, 329 .tx_len = len 330 }; 331 332 switch (len) { 333 case 0: 334 return -EINVAL; 335 336 case 1: 337 msg.type = MIPI_DSI_DCS_SHORT_WRITE; 338 break; 339 340 case 2: 341 msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM; 342 break; 343 344 default: 345 msg.type = MIPI_DSI_DCS_LONG_WRITE; 346 break; 347 } 348 349 return mipi_dsi_device_transfer(dsi, &msg); 350 } 351 352 /** 353 * mipi_dsi_dcs_write() - send DCS write command 354 * @dsi: DSI peripheral device 355 * @cmd: DCS command 356 * @data: buffer containing the command payload 357 * @len: command payload length 358 * 359 * This function will automatically choose the right data type depending on 360 * the command payload length. 361 * 362 * Return: The number of bytes successfully transmitted or a negative error 363 * code on failure. 364 */ 365 ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd, 366 const void *data, size_t len) 367 { 368 ssize_t err; 369 size_t size; 370 u8 *tx; 371 372 if (len > 0) { 373 size = 1 + len; 374 375 tx = malloc(size); 376 if (!tx) 377 return -ENOMEM; 378 379 /* concatenate the DCS command byte and the payload */ 380 tx[0] = cmd; 381 memcpy(&tx[1], data, len); 382 } else { 383 tx = &cmd; 384 size = 1; 385 } 386 387 err = mipi_dsi_dcs_write_buffer(dsi, tx, size); 388 389 if (len > 0) 390 free(tx); 391 392 return err; 393 } 394 395 /** 396 * mipi_dsi_dcs_read() - send DCS read request command 397 * @dsi: DSI peripheral device 398 * @cmd: DCS command 399 * @data: buffer in which to receive data 400 * @len: size of receive buffer 401 * Return: The number of bytes read or a negative error code on failure. 402 */ 403 ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data, 404 size_t len) 405 { 406 struct mipi_dsi_msg msg = { 407 .channel = dsi->channel, 408 .type = MIPI_DSI_DCS_READ, 409 .tx_buf = &cmd, 410 .tx_len = 1, 411 .rx_buf = data, 412 .rx_len = len 413 }; 414 415 return mipi_dsi_device_transfer(dsi, &msg); 416 } 417 418 /** 419 * mipi_dsi_dcs_nop() - send DCS nop packet 420 * @dsi: DSI peripheral device 421 * 422 * Return: 0 on success or a negative error code on failure. 423 */ 424 int mipi_dsi_dcs_nop(struct mipi_dsi_device *dsi) 425 { 426 ssize_t err; 427 428 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_NOP, NULL, 0); 429 if (err < 0) 430 return err; 431 432 return 0; 433 } 434 435 /** 436 * mipi_dsi_dcs_soft_reset() - perform a software reset of the display module 437 * @dsi: DSI peripheral device 438 * 439 * Return: 0 on success or a negative error code on failure. 440 */ 441 int mipi_dsi_dcs_soft_reset(struct mipi_dsi_device *dsi) 442 { 443 ssize_t err; 444 445 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SOFT_RESET, NULL, 0); 446 if (err < 0) 447 return err; 448 449 return 0; 450 } 451 452 /** 453 * mipi_dsi_dcs_get_power_mode() - query the display module's current power 454 * mode 455 * @dsi: DSI peripheral device 456 * @mode: return location for the current power mode 457 * 458 * Return: 0 on success or a negative error code on failure. 459 */ 460 int mipi_dsi_dcs_get_power_mode(struct mipi_dsi_device *dsi, u8 *mode) 461 { 462 ssize_t err; 463 464 err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_POWER_MODE, mode, 465 sizeof(*mode)); 466 if (err <= 0) { 467 if (err == 0) 468 err = -ENODATA; 469 470 return err; 471 } 472 473 return 0; 474 } 475 476 /** 477 * mipi_dsi_dcs_get_pixel_format() - gets the pixel format for the RGB image 478 * data used by the interface 479 * @dsi: DSI peripheral device 480 * @format: return location for the pixel format 481 * 482 * Return: 0 on success or a negative error code on failure. 483 */ 484 int mipi_dsi_dcs_get_pixel_format(struct mipi_dsi_device *dsi, u8 *format) 485 { 486 ssize_t err; 487 488 err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_PIXEL_FORMAT, format, 489 sizeof(*format)); 490 if (err <= 0) { 491 if (err == 0) 492 err = -ENODATA; 493 494 return err; 495 } 496 497 return 0; 498 } 499 500 /** 501 * mipi_dsi_dcs_enter_sleep_mode() - disable all unnecessary blocks inside the 502 * display module except interface communication 503 * @dsi: DSI peripheral device 504 * 505 * Return: 0 on success or a negative error code on failure. 506 */ 507 int mipi_dsi_dcs_enter_sleep_mode(struct mipi_dsi_device *dsi) 508 { 509 ssize_t err; 510 511 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_ENTER_SLEEP_MODE, NULL, 0); 512 if (err < 0) 513 return err; 514 515 return 0; 516 } 517 518 /** 519 * mipi_dsi_dcs_exit_sleep_mode() - enable all blocks inside the display 520 * module 521 * @dsi: DSI peripheral device 522 * 523 * Return: 0 on success or a negative error code on failure. 524 */ 525 int mipi_dsi_dcs_exit_sleep_mode(struct mipi_dsi_device *dsi) 526 { 527 ssize_t err; 528 529 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0); 530 if (err < 0) 531 return err; 532 533 return 0; 534 } 535 536 /** 537 * mipi_dsi_dcs_set_display_off() - stop displaying the image data on the 538 * display device 539 * @dsi: DSI peripheral device 540 * 541 * Return: 0 on success or a negative error code on failure. 542 */ 543 int mipi_dsi_dcs_set_display_off(struct mipi_dsi_device *dsi) 544 { 545 ssize_t err; 546 547 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_OFF, NULL, 0); 548 if (err < 0) 549 return err; 550 551 return 0; 552 } 553 554 /** 555 * mipi_dsi_dcs_set_display_on() - start displaying the image data on the 556 * display device 557 * @dsi: DSI peripheral device 558 * 559 * Return: 0 on success or a negative error code on failure 560 */ 561 int mipi_dsi_dcs_set_display_on(struct mipi_dsi_device *dsi) 562 { 563 ssize_t err; 564 565 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0); 566 if (err < 0) 567 return err; 568 569 return 0; 570 } 571 572 /** 573 * mipi_dsi_dcs_set_column_address() - define the column extent of the frame 574 * memory accessed by the host processor 575 * @dsi: DSI peripheral device 576 * @start: first column of frame memory 577 * @end: last column of frame memory 578 * 579 * Return: 0 on success or a negative error code on failure. 580 */ 581 int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start, 582 u16 end) 583 { 584 u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff }; 585 ssize_t err; 586 587 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_COLUMN_ADDRESS, payload, 588 sizeof(payload)); 589 if (err < 0) 590 return err; 591 592 return 0; 593 } 594 595 /** 596 * mipi_dsi_dcs_set_page_address() - define the page extent of the frame 597 * memory accessed by the host processor 598 * @dsi: DSI peripheral device 599 * @start: first page of frame memory 600 * @end: last page of frame memory 601 * 602 * Return: 0 on success or a negative error code on failure. 603 */ 604 int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start, 605 u16 end) 606 { 607 u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff }; 608 ssize_t err; 609 610 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PAGE_ADDRESS, payload, 611 sizeof(payload)); 612 if (err < 0) 613 return err; 614 615 return 0; 616 } 617 618 /** 619 * mipi_dsi_dcs_set_tear_off() - turn off the display module's Tearing Effect 620 * output signal on the TE signal line 621 * @dsi: DSI peripheral device 622 * 623 * Return: 0 on success or a negative error code on failure 624 */ 625 int mipi_dsi_dcs_set_tear_off(struct mipi_dsi_device *dsi) 626 { 627 ssize_t err; 628 629 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_OFF, NULL, 0); 630 if (err < 0) 631 return err; 632 633 return 0; 634 } 635 636 /** 637 * mipi_dsi_dcs_set_tear_on() - turn on the display module's Tearing Effect 638 * output signal on the TE signal line. 639 * @dsi: DSI peripheral device 640 * @mode: the Tearing Effect Output Line mode 641 * 642 * Return: 0 on success or a negative error code on failure 643 */ 644 int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi, 645 enum mipi_dsi_dcs_tear_mode mode) 646 { 647 u8 value = mode; 648 ssize_t err; 649 650 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_ON, &value, 651 sizeof(value)); 652 if (err < 0) 653 return err; 654 655 return 0; 656 } 657 658 /** 659 * mipi_dsi_dcs_set_pixel_format() - sets the pixel format for the RGB image 660 * data used by the interface 661 * @dsi: DSI peripheral device 662 * @format: pixel format 663 * 664 * Return: 0 on success or a negative error code on failure. 665 */ 666 int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format) 667 { 668 ssize_t err; 669 670 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PIXEL_FORMAT, &format, 671 sizeof(format)); 672 if (err < 0) 673 return err; 674 675 return 0; 676 } 677 678 /** 679 * mipi_dsi_dcs_set_tear_scanline() - set the scanline to use as trigger for 680 * the Tearing Effect output signal of the display module 681 * @dsi: DSI peripheral device 682 * @scanline: scanline to use as trigger 683 * 684 * Return: 0 on success or a negative error code on failure 685 */ 686 int mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline) 687 { 688 u8 payload[3] = { MIPI_DCS_SET_TEAR_SCANLINE, scanline >> 8, 689 scanline & 0xff }; 690 ssize_t err; 691 692 err = mipi_dsi_generic_write(dsi, payload, sizeof(payload)); 693 if (err < 0) 694 return err; 695 696 return 0; 697 } 698 699 /** 700 * mipi_dsi_dcs_set_display_brightness() - sets the brightness value of the 701 * display 702 * @dsi: DSI peripheral device 703 * @brightness: brightness value 704 * 705 * Return: 0 on success or a negative error code on failure. 706 */ 707 int mipi_dsi_dcs_set_display_brightness(struct mipi_dsi_device *dsi, 708 u16 brightness) 709 { 710 u8 payload[2] = { brightness & 0xff, brightness >> 8 }; 711 ssize_t err; 712 713 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 714 payload, sizeof(payload)); 715 if (err < 0) 716 return err; 717 718 return 0; 719 } 720 721 /** 722 * mipi_dsi_dcs_get_display_brightness() - gets the current brightness value 723 * of the display 724 * @dsi: DSI peripheral device 725 * @brightness: brightness value 726 * 727 * Return: 0 on success or a negative error code on failure. 728 */ 729 int mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi, 730 u16 *brightness) 731 { 732 ssize_t err; 733 734 err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_DISPLAY_BRIGHTNESS, 735 brightness, sizeof(*brightness)); 736 if (err <= 0) { 737 if (err == 0) 738 err = -ENODATA; 739 740 return err; 741 } 742 743 return 0; 744 } 745