1938 lines · c
1/*2 * MIPI DSI Bus3 *4 * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd.5 * Andrzej Hajda <a.hajda@samsung.com>6 *7 * Permission is hereby granted, free of charge, to any person obtaining a8 * copy of this software and associated documentation files (the9 * "Software"), to deal in the Software without restriction, including10 * without limitation the rights to use, copy, modify, merge, publish,11 * distribute, sub license, and/or sell copies of the Software, and to12 * permit persons to whom the Software is furnished to do so, subject to13 * the following conditions:14 *15 * The above copyright notice and this permission notice (including the16 * next paragraph) shall be included in all copies or substantial portions17 * of the Software.18 *19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,21 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL22 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,23 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR24 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE25 * USE OR OTHER DEALINGS IN THE SOFTWARE.26 */27 28#include <linux/device.h>29#include <linux/module.h>30#include <linux/of.h>31#include <linux/of_device.h>32#include <linux/pm_runtime.h>33#include <linux/slab.h>34 35#include <drm/display/drm_dsc.h>36#include <drm/drm_mipi_dsi.h>37#include <drm/drm_print.h>38 39#include <video/mipi_display.h>40 41/**42 * DOC: dsi helpers43 *44 * These functions contain some common logic and helpers to deal with MIPI DSI45 * peripherals.46 *47 * Helpers are provided for a number of standard MIPI DSI command as well as a48 * subset of the MIPI DCS command set.49 */50 51static int mipi_dsi_device_match(struct device *dev, const struct device_driver *drv)52{53 struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);54 55 /* attempt OF style match */56 if (of_driver_match_device(dev, drv))57 return 1;58 59 /* compare DSI device and driver names */60 if (!strcmp(dsi->name, drv->name))61 return 1;62 63 return 0;64}65 66static int mipi_dsi_uevent(const struct device *dev, struct kobj_uevent_env *env)67{68 const struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);69 int err;70 71 err = of_device_uevent_modalias(dev, env);72 if (err != -ENODEV)73 return err;74 75 add_uevent_var(env, "MODALIAS=%s%s", MIPI_DSI_MODULE_PREFIX,76 dsi->name);77 78 return 0;79}80 81static const struct dev_pm_ops mipi_dsi_device_pm_ops = {82 .runtime_suspend = pm_generic_runtime_suspend,83 .runtime_resume = pm_generic_runtime_resume,84 .suspend = pm_generic_suspend,85 .resume = pm_generic_resume,86 .freeze = pm_generic_freeze,87 .thaw = pm_generic_thaw,88 .poweroff = pm_generic_poweroff,89 .restore = pm_generic_restore,90};91 92static const struct bus_type mipi_dsi_bus_type = {93 .name = "mipi-dsi",94 .match = mipi_dsi_device_match,95 .uevent = mipi_dsi_uevent,96 .pm = &mipi_dsi_device_pm_ops,97};98 99/**100 * of_find_mipi_dsi_device_by_node() - find the MIPI DSI device matching a101 * device tree node102 * @np: device tree node103 *104 * Return: A pointer to the MIPI DSI device corresponding to @np or NULL if no105 * such device exists (or has not been registered yet).106 */107struct mipi_dsi_device *of_find_mipi_dsi_device_by_node(struct device_node *np)108{109 struct device *dev;110 111 dev = bus_find_device_by_of_node(&mipi_dsi_bus_type, np);112 113 return dev ? to_mipi_dsi_device(dev) : NULL;114}115EXPORT_SYMBOL(of_find_mipi_dsi_device_by_node);116 117static void mipi_dsi_dev_release(struct device *dev)118{119 struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);120 121 of_node_put(dev->of_node);122 kfree(dsi);123}124 125static const struct device_type mipi_dsi_device_type = {126 .release = mipi_dsi_dev_release,127};128 129static struct mipi_dsi_device *mipi_dsi_device_alloc(struct mipi_dsi_host *host)130{131 struct mipi_dsi_device *dsi;132 133 dsi = kzalloc(sizeof(*dsi), GFP_KERNEL);134 if (!dsi)135 return ERR_PTR(-ENOMEM);136 137 dsi->host = host;138 dsi->dev.bus = &mipi_dsi_bus_type;139 dsi->dev.parent = host->dev;140 dsi->dev.type = &mipi_dsi_device_type;141 142 device_initialize(&dsi->dev);143 144 return dsi;145}146 147static int mipi_dsi_device_add(struct mipi_dsi_device *dsi)148{149 struct mipi_dsi_host *host = dsi->host;150 151 dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), dsi->channel);152 153 return device_add(&dsi->dev);154}155 156#if IS_ENABLED(CONFIG_OF)157static struct mipi_dsi_device *158of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node)159{160 struct mipi_dsi_device_info info = { };161 int ret;162 u32 reg;163 164 if (of_alias_from_compatible(node, info.type, sizeof(info.type)) < 0) {165 drm_err(host, "modalias failure on %pOF\n", node);166 return ERR_PTR(-EINVAL);167 }168 169 ret = of_property_read_u32(node, "reg", ®);170 if (ret) {171 drm_err(host, "device node %pOF has no valid reg property: %d\n",172 node, ret);173 return ERR_PTR(-EINVAL);174 }175 176 info.channel = reg;177 info.node = of_node_get(node);178 179 return mipi_dsi_device_register_full(host, &info);180}181#else182static struct mipi_dsi_device *183of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node)184{185 return ERR_PTR(-ENODEV);186}187#endif188 189/**190 * mipi_dsi_device_register_full - create a MIPI DSI device191 * @host: DSI host to which this device is connected192 * @info: pointer to template containing DSI device information193 *194 * Create a MIPI DSI device by using the device information provided by195 * mipi_dsi_device_info template196 *197 * Returns:198 * A pointer to the newly created MIPI DSI device, or, a pointer encoded199 * with an error200 */201struct mipi_dsi_device *202mipi_dsi_device_register_full(struct mipi_dsi_host *host,203 const struct mipi_dsi_device_info *info)204{205 struct mipi_dsi_device *dsi;206 int ret;207 208 if (!info) {209 drm_err(host, "invalid mipi_dsi_device_info pointer\n");210 return ERR_PTR(-EINVAL);211 }212 213 if (info->channel > 3) {214 drm_err(host, "invalid virtual channel: %u\n", info->channel);215 return ERR_PTR(-EINVAL);216 }217 218 dsi = mipi_dsi_device_alloc(host);219 if (IS_ERR(dsi)) {220 drm_err(host, "failed to allocate DSI device %ld\n",221 PTR_ERR(dsi));222 return dsi;223 }224 225 device_set_node(&dsi->dev, of_fwnode_handle(info->node));226 dsi->channel = info->channel;227 strscpy(dsi->name, info->type, sizeof(dsi->name));228 229 ret = mipi_dsi_device_add(dsi);230 if (ret) {231 drm_err(host, "failed to add DSI device %d\n", ret);232 kfree(dsi);233 return ERR_PTR(ret);234 }235 236 return dsi;237}238EXPORT_SYMBOL(mipi_dsi_device_register_full);239 240/**241 * mipi_dsi_device_unregister - unregister MIPI DSI device242 * @dsi: DSI peripheral device243 */244void mipi_dsi_device_unregister(struct mipi_dsi_device *dsi)245{246 device_unregister(&dsi->dev);247}248EXPORT_SYMBOL(mipi_dsi_device_unregister);249 250static void devm_mipi_dsi_device_unregister(void *arg)251{252 struct mipi_dsi_device *dsi = arg;253 254 mipi_dsi_device_unregister(dsi);255}256 257/**258 * devm_mipi_dsi_device_register_full - create a managed MIPI DSI device259 * @dev: device to tie the MIPI-DSI device lifetime to260 * @host: DSI host to which this device is connected261 * @info: pointer to template containing DSI device information262 *263 * Create a MIPI DSI device by using the device information provided by264 * mipi_dsi_device_info template265 *266 * This is the managed version of mipi_dsi_device_register_full() which267 * automatically calls mipi_dsi_device_unregister() when @dev is268 * unbound.269 *270 * Returns:271 * A pointer to the newly created MIPI DSI device, or, a pointer encoded272 * with an error273 */274struct mipi_dsi_device *275devm_mipi_dsi_device_register_full(struct device *dev,276 struct mipi_dsi_host *host,277 const struct mipi_dsi_device_info *info)278{279 struct mipi_dsi_device *dsi;280 int ret;281 282 dsi = mipi_dsi_device_register_full(host, info);283 if (IS_ERR(dsi))284 return dsi;285 286 ret = devm_add_action_or_reset(dev,287 devm_mipi_dsi_device_unregister,288 dsi);289 if (ret)290 return ERR_PTR(ret);291 292 return dsi;293}294EXPORT_SYMBOL_GPL(devm_mipi_dsi_device_register_full);295 296static DEFINE_MUTEX(host_lock);297static LIST_HEAD(host_list);298 299/**300 * of_find_mipi_dsi_host_by_node() - find the MIPI DSI host matching a301 * device tree node302 * @node: device tree node303 *304 * Returns:305 * A pointer to the MIPI DSI host corresponding to @node or NULL if no306 * such device exists (or has not been registered yet).307 */308struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node)309{310 struct mipi_dsi_host *host;311 312 mutex_lock(&host_lock);313 314 list_for_each_entry(host, &host_list, list) {315 if (host->dev->of_node == node) {316 mutex_unlock(&host_lock);317 return host;318 }319 }320 321 mutex_unlock(&host_lock);322 323 return NULL;324}325EXPORT_SYMBOL(of_find_mipi_dsi_host_by_node);326 327int mipi_dsi_host_register(struct mipi_dsi_host *host)328{329 struct device_node *node;330 331 for_each_available_child_of_node(host->dev->of_node, node) {332 /* skip nodes without reg property */333 if (!of_property_present(node, "reg"))334 continue;335 of_mipi_dsi_device_add(host, node);336 }337 338 mutex_lock(&host_lock);339 list_add_tail(&host->list, &host_list);340 mutex_unlock(&host_lock);341 342 return 0;343}344EXPORT_SYMBOL(mipi_dsi_host_register);345 346static int mipi_dsi_remove_device_fn(struct device *dev, void *priv)347{348 struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);349 350 if (dsi->attached)351 mipi_dsi_detach(dsi);352 mipi_dsi_device_unregister(dsi);353 354 return 0;355}356 357void mipi_dsi_host_unregister(struct mipi_dsi_host *host)358{359 device_for_each_child(host->dev, NULL, mipi_dsi_remove_device_fn);360 361 mutex_lock(&host_lock);362 list_del_init(&host->list);363 mutex_unlock(&host_lock);364}365EXPORT_SYMBOL(mipi_dsi_host_unregister);366 367/**368 * mipi_dsi_attach - attach a DSI device to its DSI host369 * @dsi: DSI peripheral370 */371int mipi_dsi_attach(struct mipi_dsi_device *dsi)372{373 const struct mipi_dsi_host_ops *ops = dsi->host->ops;374 int ret;375 376 if (!ops || !ops->attach)377 return -ENOSYS;378 379 ret = ops->attach(dsi->host, dsi);380 if (ret)381 return ret;382 383 dsi->attached = true;384 385 return 0;386}387EXPORT_SYMBOL(mipi_dsi_attach);388 389/**390 * mipi_dsi_detach - detach a DSI device from its DSI host391 * @dsi: DSI peripheral392 */393int mipi_dsi_detach(struct mipi_dsi_device *dsi)394{395 const struct mipi_dsi_host_ops *ops = dsi->host->ops;396 397 if (WARN_ON(!dsi->attached))398 return -EINVAL;399 400 if (!ops || !ops->detach)401 return -ENOSYS;402 403 dsi->attached = false;404 405 return ops->detach(dsi->host, dsi);406}407EXPORT_SYMBOL(mipi_dsi_detach);408 409static void devm_mipi_dsi_detach(void *arg)410{411 struct mipi_dsi_device *dsi = arg;412 413 mipi_dsi_detach(dsi);414}415 416/**417 * devm_mipi_dsi_attach - Attach a MIPI-DSI device to its DSI Host418 * @dev: device to tie the MIPI-DSI device attachment lifetime to419 * @dsi: DSI peripheral420 *421 * This is the managed version of mipi_dsi_attach() which automatically422 * calls mipi_dsi_detach() when @dev is unbound.423 *424 * Returns:425 * 0 on success, a negative error code on failure.426 */427int devm_mipi_dsi_attach(struct device *dev,428 struct mipi_dsi_device *dsi)429{430 int ret;431 432 ret = mipi_dsi_attach(dsi);433 if (ret)434 return ret;435 436 ret = devm_add_action_or_reset(dev, devm_mipi_dsi_detach, dsi);437 if (ret)438 return ret;439 440 return 0;441}442EXPORT_SYMBOL_GPL(devm_mipi_dsi_attach);443 444static ssize_t mipi_dsi_device_transfer(struct mipi_dsi_device *dsi,445 struct mipi_dsi_msg *msg)446{447 const struct mipi_dsi_host_ops *ops = dsi->host->ops;448 449 if (!ops || !ops->transfer)450 return -ENOSYS;451 452 if (dsi->mode_flags & MIPI_DSI_MODE_LPM)453 msg->flags |= MIPI_DSI_MSG_USE_LPM;454 455 return ops->transfer(dsi->host, msg);456}457 458/**459 * mipi_dsi_packet_format_is_short - check if a packet is of the short format460 * @type: MIPI DSI data type of the packet461 *462 * Return: true if the packet for the given data type is a short packet, false463 * otherwise.464 */465bool mipi_dsi_packet_format_is_short(u8 type)466{467 switch (type) {468 case MIPI_DSI_V_SYNC_START:469 case MIPI_DSI_V_SYNC_END:470 case MIPI_DSI_H_SYNC_START:471 case MIPI_DSI_H_SYNC_END:472 case MIPI_DSI_COMPRESSION_MODE:473 case MIPI_DSI_END_OF_TRANSMISSION:474 case MIPI_DSI_COLOR_MODE_OFF:475 case MIPI_DSI_COLOR_MODE_ON:476 case MIPI_DSI_SHUTDOWN_PERIPHERAL:477 case MIPI_DSI_TURN_ON_PERIPHERAL:478 case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:479 case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:480 case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:481 case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:482 case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:483 case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:484 case MIPI_DSI_DCS_SHORT_WRITE:485 case MIPI_DSI_DCS_SHORT_WRITE_PARAM:486 case MIPI_DSI_DCS_READ:487 case MIPI_DSI_EXECUTE_QUEUE:488 case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:489 return true;490 }491 492 return false;493}494EXPORT_SYMBOL(mipi_dsi_packet_format_is_short);495 496/**497 * mipi_dsi_packet_format_is_long - check if a packet is of the long format498 * @type: MIPI DSI data type of the packet499 *500 * Return: true if the packet for the given data type is a long packet, false501 * otherwise.502 */503bool mipi_dsi_packet_format_is_long(u8 type)504{505 switch (type) {506 case MIPI_DSI_NULL_PACKET:507 case MIPI_DSI_BLANKING_PACKET:508 case MIPI_DSI_GENERIC_LONG_WRITE:509 case MIPI_DSI_DCS_LONG_WRITE:510 case MIPI_DSI_PICTURE_PARAMETER_SET:511 case MIPI_DSI_COMPRESSED_PIXEL_STREAM:512 case MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20:513 case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24:514 case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16:515 case MIPI_DSI_PACKED_PIXEL_STREAM_30:516 case MIPI_DSI_PACKED_PIXEL_STREAM_36:517 case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12:518 case MIPI_DSI_PACKED_PIXEL_STREAM_16:519 case MIPI_DSI_PACKED_PIXEL_STREAM_18:520 case MIPI_DSI_PIXEL_STREAM_3BYTE_18:521 case MIPI_DSI_PACKED_PIXEL_STREAM_24:522 return true;523 }524 525 return false;526}527EXPORT_SYMBOL(mipi_dsi_packet_format_is_long);528 529/**530 * mipi_dsi_create_packet - create a packet from a message according to the531 * DSI protocol532 * @packet: pointer to a DSI packet structure533 * @msg: message to translate into a packet534 *535 * Return: 0 on success or a negative error code on failure.536 */537int mipi_dsi_create_packet(struct mipi_dsi_packet *packet,538 const struct mipi_dsi_msg *msg)539{540 if (!packet || !msg)541 return -EINVAL;542 543 /* do some minimum sanity checking */544 if (!mipi_dsi_packet_format_is_short(msg->type) &&545 !mipi_dsi_packet_format_is_long(msg->type))546 return -EINVAL;547 548 if (msg->channel > 3)549 return -EINVAL;550 551 memset(packet, 0, sizeof(*packet));552 packet->header[0] = ((msg->channel & 0x3) << 6) | (msg->type & 0x3f);553 554 /* TODO: compute ECC if hardware support is not available */555 556 /*557 * Long write packets contain the word count in header bytes 1 and 2.558 * The payload follows the header and is word count bytes long.559 *560 * Short write packets encode up to two parameters in header bytes 1561 * and 2.562 */563 if (mipi_dsi_packet_format_is_long(msg->type)) {564 packet->header[1] = (msg->tx_len >> 0) & 0xff;565 packet->header[2] = (msg->tx_len >> 8) & 0xff;566 567 packet->payload_length = msg->tx_len;568 packet->payload = msg->tx_buf;569 } else {570 const u8 *tx = msg->tx_buf;571 572 packet->header[1] = (msg->tx_len > 0) ? tx[0] : 0;573 packet->header[2] = (msg->tx_len > 1) ? tx[1] : 0;574 }575 576 packet->size = sizeof(packet->header) + packet->payload_length;577 578 return 0;579}580EXPORT_SYMBOL(mipi_dsi_create_packet);581 582/**583 * mipi_dsi_shutdown_peripheral() - sends a Shutdown Peripheral command584 * @dsi: DSI peripheral device585 *586 * Return: 0 on success or a negative error code on failure.587 */588int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi)589{590 struct mipi_dsi_msg msg = {591 .channel = dsi->channel,592 .type = MIPI_DSI_SHUTDOWN_PERIPHERAL,593 .tx_buf = (u8 [2]) { 0, 0 },594 .tx_len = 2,595 };596 int ret = mipi_dsi_device_transfer(dsi, &msg);597 598 return (ret < 0) ? ret : 0;599}600EXPORT_SYMBOL(mipi_dsi_shutdown_peripheral);601 602/**603 * mipi_dsi_turn_on_peripheral() - sends a Turn On Peripheral command604 * @dsi: DSI peripheral device605 *606 * This function is deprecated. Use mipi_dsi_turn_on_peripheral_multi() instead.607 *608 * Return: 0 on success or a negative error code on failure.609 */610int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi)611{612 struct mipi_dsi_msg msg = {613 .channel = dsi->channel,614 .type = MIPI_DSI_TURN_ON_PERIPHERAL,615 .tx_buf = (u8 [2]) { 0, 0 },616 .tx_len = 2,617 };618 int ret = mipi_dsi_device_transfer(dsi, &msg);619 620 return (ret < 0) ? ret : 0;621}622EXPORT_SYMBOL(mipi_dsi_turn_on_peripheral);623 624/*625 * mipi_dsi_set_maximum_return_packet_size() - specify the maximum size of626 * the payload in a long packet transmitted from the peripheral back to the627 * host processor628 * @dsi: DSI peripheral device629 * @value: the maximum size of the payload630 *631 * Return: 0 on success or a negative error code on failure.632 */633int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi,634 u16 value)635{636 u8 tx[2] = { value & 0xff, value >> 8 };637 struct mipi_dsi_msg msg = {638 .channel = dsi->channel,639 .type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE,640 .tx_len = sizeof(tx),641 .tx_buf = tx,642 };643 int ret = mipi_dsi_device_transfer(dsi, &msg);644 645 return (ret < 0) ? ret : 0;646}647EXPORT_SYMBOL(mipi_dsi_set_maximum_return_packet_size);648 649/**650 * mipi_dsi_compression_mode_ext() - enable/disable DSC on the peripheral651 * @dsi: DSI peripheral device652 * @enable: Whether to enable or disable the DSC653 * @algo: Selected compression algorithm654 * @pps_selector: Select PPS from the table of pre-stored or uploaded PPS entries655 *656 * Enable or disable Display Stream Compression on the peripheral.657 * This function is deprecated. Use mipi_dsi_compression_mode_ext_multi() instead.658 *659 * Return: 0 on success or a negative error code on failure.660 */661int mipi_dsi_compression_mode_ext(struct mipi_dsi_device *dsi, bool enable,662 enum mipi_dsi_compression_algo algo,663 unsigned int pps_selector)664{665 u8 tx[2] = { };666 struct mipi_dsi_msg msg = {667 .channel = dsi->channel,668 .type = MIPI_DSI_COMPRESSION_MODE,669 .tx_len = sizeof(tx),670 .tx_buf = tx,671 };672 int ret;673 674 if (algo > 3 || pps_selector > 3)675 return -EINVAL;676 677 tx[0] = (enable << 0) |678 (algo << 1) |679 (pps_selector << 4);680 681 ret = mipi_dsi_device_transfer(dsi, &msg);682 683 return (ret < 0) ? ret : 0;684}685EXPORT_SYMBOL(mipi_dsi_compression_mode_ext);686 687/**688 * mipi_dsi_compression_mode() - enable/disable DSC on the peripheral689 * @dsi: DSI peripheral device690 * @enable: Whether to enable or disable the DSC691 *692 * Enable or disable Display Stream Compression on the peripheral using the693 * default Picture Parameter Set and VESA DSC 1.1 algorithm.694 *695 * Return: 0 on success or a negative error code on failure.696 */697int mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable)698{699 return mipi_dsi_compression_mode_ext(dsi, enable, MIPI_DSI_COMPRESSION_DSC, 0);700}701EXPORT_SYMBOL(mipi_dsi_compression_mode);702 703/**704 * mipi_dsi_picture_parameter_set() - transmit the DSC PPS to the peripheral705 * @dsi: DSI peripheral device706 * @pps: VESA DSC 1.1 Picture Parameter Set707 *708 * Transmit the VESA DSC 1.1 Picture Parameter Set to the peripheral.709 * This function is deprecated. Use mipi_dsi_picture_parameter_set_multi() instead.710 *711 * Return: 0 on success or a negative error code on failure.712 */713int mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi,714 const struct drm_dsc_picture_parameter_set *pps)715{716 struct mipi_dsi_msg msg = {717 .channel = dsi->channel,718 .type = MIPI_DSI_PICTURE_PARAMETER_SET,719 .tx_len = sizeof(*pps),720 .tx_buf = pps,721 };722 int ret = mipi_dsi_device_transfer(dsi, &msg);723 724 return (ret < 0) ? ret : 0;725}726EXPORT_SYMBOL(mipi_dsi_picture_parameter_set);727 728/**729 * mipi_dsi_generic_write() - transmit data using a generic write packet730 * @dsi: DSI peripheral device731 * @payload: buffer containing the payload732 * @size: size of payload buffer733 *734 * This function will automatically choose the right data type depending on735 * the payload length.736 *737 * Return: The number of bytes transmitted on success or a negative error code738 * on failure.739 */740ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload,741 size_t size)742{743 struct mipi_dsi_msg msg = {744 .channel = dsi->channel,745 .tx_buf = payload,746 .tx_len = size747 };748 749 switch (size) {750 case 0:751 msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM;752 break;753 754 case 1:755 msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM;756 break;757 758 case 2:759 msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM;760 break;761 762 default:763 msg.type = MIPI_DSI_GENERIC_LONG_WRITE;764 break;765 }766 767 return mipi_dsi_device_transfer(dsi, &msg);768}769EXPORT_SYMBOL(mipi_dsi_generic_write);770 771/**772 * mipi_dsi_generic_write_chatty() - mipi_dsi_generic_write() w/ an error log773 * @dsi: DSI peripheral device774 * @payload: buffer containing the payload775 * @size: size of payload buffer776 *777 * Like mipi_dsi_generic_write() but includes a dev_err()778 * call for you and returns 0 upon success, not the number of bytes sent.779 *780 * Return: 0 on success or a negative error code on failure.781 */782int mipi_dsi_generic_write_chatty(struct mipi_dsi_device *dsi,783 const void *payload, size_t size)784{785 struct device *dev = &dsi->dev;786 ssize_t ret;787 788 ret = mipi_dsi_generic_write(dsi, payload, size);789 if (ret < 0) {790 dev_err(dev, "sending generic data %*ph failed: %zd\n",791 (int)size, payload, ret);792 return ret;793 }794 795 return 0;796}797EXPORT_SYMBOL(mipi_dsi_generic_write_chatty);798 799/**800 * mipi_dsi_generic_write_multi() - mipi_dsi_generic_write_chatty() w/ accum_err801 * @ctx: Context for multiple DSI transactions802 * @payload: buffer containing the payload803 * @size: size of payload buffer804 *805 * Like mipi_dsi_generic_write_chatty() but deals with errors in a way that806 * makes it convenient to make several calls in a row.807 */808void mipi_dsi_generic_write_multi(struct mipi_dsi_multi_context *ctx,809 const void *payload, size_t size)810{811 struct mipi_dsi_device *dsi = ctx->dsi;812 struct device *dev = &dsi->dev;813 ssize_t ret;814 815 if (ctx->accum_err)816 return;817 818 ret = mipi_dsi_generic_write(dsi, payload, size);819 if (ret < 0) {820 ctx->accum_err = ret;821 dev_err(dev, "sending generic data %*ph failed: %d\n",822 (int)size, payload, ctx->accum_err);823 }824}825EXPORT_SYMBOL(mipi_dsi_generic_write_multi);826 827/**828 * mipi_dsi_generic_read() - receive data using a generic read packet829 * @dsi: DSI peripheral device830 * @params: buffer containing the request parameters831 * @num_params: number of request parameters832 * @data: buffer in which to return the received data833 * @size: size of receive buffer834 *835 * This function will automatically choose the right data type depending on836 * the number of parameters passed in.837 *838 * Return: The number of bytes successfully read or a negative error code on839 * failure.840 */841ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params,842 size_t num_params, void *data, size_t size)843{844 struct mipi_dsi_msg msg = {845 .channel = dsi->channel,846 .tx_len = num_params,847 .tx_buf = params,848 .rx_len = size,849 .rx_buf = data850 };851 852 switch (num_params) {853 case 0:854 msg.type = MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM;855 break;856 857 case 1:858 msg.type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM;859 break;860 861 case 2:862 msg.type = MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM;863 break;864 865 default:866 return -EINVAL;867 }868 869 return mipi_dsi_device_transfer(dsi, &msg);870}871EXPORT_SYMBOL(mipi_dsi_generic_read);872 873/**874 * mipi_dsi_dcs_write_buffer() - transmit a DCS command with payload875 * @dsi: DSI peripheral device876 * @data: buffer containing data to be transmitted877 * @len: size of transmission buffer878 *879 * This function will automatically choose the right data type depending on880 * the command payload length.881 *882 * Return: The number of bytes successfully transmitted or a negative error883 * code on failure.884 */885ssize_t mipi_dsi_dcs_write_buffer(struct mipi_dsi_device *dsi,886 const void *data, size_t len)887{888 struct mipi_dsi_msg msg = {889 .channel = dsi->channel,890 .tx_buf = data,891 .tx_len = len892 };893 894 switch (len) {895 case 0:896 return -EINVAL;897 898 case 1:899 msg.type = MIPI_DSI_DCS_SHORT_WRITE;900 break;901 902 case 2:903 msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;904 break;905 906 default:907 msg.type = MIPI_DSI_DCS_LONG_WRITE;908 break;909 }910 911 return mipi_dsi_device_transfer(dsi, &msg);912}913EXPORT_SYMBOL(mipi_dsi_dcs_write_buffer);914 915/**916 * mipi_dsi_dcs_write_buffer_chatty - mipi_dsi_dcs_write_buffer() w/ an error log917 * @dsi: DSI peripheral device918 * @data: buffer containing data to be transmitted919 * @len: size of transmission buffer920 *921 * Like mipi_dsi_dcs_write_buffer() but includes a dev_err()922 * call for you and returns 0 upon success, not the number of bytes sent.923 *924 * Return: 0 on success or a negative error code on failure.925 */926int mipi_dsi_dcs_write_buffer_chatty(struct mipi_dsi_device *dsi,927 const void *data, size_t len)928{929 struct device *dev = &dsi->dev;930 ssize_t ret;931 932 ret = mipi_dsi_dcs_write_buffer(dsi, data, len);933 if (ret < 0) {934 dev_err(dev, "sending dcs data %*ph failed: %zd\n",935 (int)len, data, ret);936 return ret;937 }938 939 return 0;940}941EXPORT_SYMBOL(mipi_dsi_dcs_write_buffer_chatty);942 943/**944 * mipi_dsi_dcs_write_buffer_multi - mipi_dsi_dcs_write_buffer_chatty() w/ accum_err945 * @ctx: Context for multiple DSI transactions946 * @data: buffer containing data to be transmitted947 * @len: size of transmission buffer948 *949 * Like mipi_dsi_dcs_write_buffer_chatty() but deals with errors in a way that950 * makes it convenient to make several calls in a row.951 */952void mipi_dsi_dcs_write_buffer_multi(struct mipi_dsi_multi_context *ctx,953 const void *data, size_t len)954{955 struct mipi_dsi_device *dsi = ctx->dsi;956 struct device *dev = &dsi->dev;957 ssize_t ret;958 959 if (ctx->accum_err)960 return;961 962 ret = mipi_dsi_dcs_write_buffer(dsi, data, len);963 if (ret < 0) {964 ctx->accum_err = ret;965 dev_err(dev, "sending dcs data %*ph failed: %d\n",966 (int)len, data, ctx->accum_err);967 }968}969EXPORT_SYMBOL(mipi_dsi_dcs_write_buffer_multi);970 971/**972 * mipi_dsi_dcs_write() - send DCS write command973 * @dsi: DSI peripheral device974 * @cmd: DCS command975 * @data: buffer containing the command payload976 * @len: command payload length977 *978 * This function will automatically choose the right data type depending on979 * the command payload length.980 *981 * Return: The number of bytes successfully transmitted or a negative error982 * code on failure.983 */984ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd,985 const void *data, size_t len)986{987 ssize_t err;988 size_t size;989 u8 stack_tx[8];990 u8 *tx;991 992 size = 1 + len;993 if (len > ARRAY_SIZE(stack_tx) - 1) {994 tx = kmalloc(size, GFP_KERNEL);995 if (!tx)996 return -ENOMEM;997 } else {998 tx = stack_tx;999 }1000 1001 /* concatenate the DCS command byte and the payload */1002 tx[0] = cmd;1003 if (data)1004 memcpy(&tx[1], data, len);1005 1006 err = mipi_dsi_dcs_write_buffer(dsi, tx, size);1007 1008 if (tx != stack_tx)1009 kfree(tx);1010 1011 return err;1012}1013EXPORT_SYMBOL(mipi_dsi_dcs_write);1014 1015/**1016 * mipi_dsi_dcs_read() - send DCS read request command1017 * @dsi: DSI peripheral device1018 * @cmd: DCS command1019 * @data: buffer in which to receive data1020 * @len: size of receive buffer1021 *1022 * Return: The number of bytes read or a negative error code on failure.1023 */1024ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data,1025 size_t len)1026{1027 struct mipi_dsi_msg msg = {1028 .channel = dsi->channel,1029 .type = MIPI_DSI_DCS_READ,1030 .tx_buf = &cmd,1031 .tx_len = 1,1032 .rx_buf = data,1033 .rx_len = len1034 };1035 1036 return mipi_dsi_device_transfer(dsi, &msg);1037}1038EXPORT_SYMBOL(mipi_dsi_dcs_read);1039 1040/**1041 * mipi_dsi_dcs_nop() - send DCS nop packet1042 * @dsi: DSI peripheral device1043 *1044 * This function is deprecated. Use mipi_dsi_dcs_nop_multi() instead.1045 *1046 * Return: 0 on success or a negative error code on failure.1047 */1048int mipi_dsi_dcs_nop(struct mipi_dsi_device *dsi)1049{1050 ssize_t err;1051 1052 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_NOP, NULL, 0);1053 if (err < 0)1054 return err;1055 1056 return 0;1057}1058EXPORT_SYMBOL(mipi_dsi_dcs_nop);1059 1060/**1061 * mipi_dsi_dcs_soft_reset() - perform a software reset of the display module1062 * @dsi: DSI peripheral device1063 *1064 * This function is deprecated. Use mipi_dsi_dcs_soft_reset_multi() instead.1065 *1066 * Return: 0 on success or a negative error code on failure.1067 */1068int mipi_dsi_dcs_soft_reset(struct mipi_dsi_device *dsi)1069{1070 ssize_t err;1071 1072 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SOFT_RESET, NULL, 0);1073 if (err < 0)1074 return err;1075 1076 return 0;1077}1078EXPORT_SYMBOL(mipi_dsi_dcs_soft_reset);1079 1080/**1081 * mipi_dsi_dcs_get_power_mode() - query the display module's current power1082 * mode1083 * @dsi: DSI peripheral device1084 * @mode: return location for the current power mode1085 *1086 * Return: 0 on success or a negative error code on failure.1087 */1088int mipi_dsi_dcs_get_power_mode(struct mipi_dsi_device *dsi, u8 *mode)1089{1090 ssize_t err;1091 1092 err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_POWER_MODE, mode,1093 sizeof(*mode));1094 if (err <= 0) {1095 if (err == 0)1096 err = -ENODATA;1097 1098 return err;1099 }1100 1101 return 0;1102}1103EXPORT_SYMBOL(mipi_dsi_dcs_get_power_mode);1104 1105/**1106 * mipi_dsi_dcs_get_pixel_format() - gets the pixel format for the RGB image1107 * data used by the interface1108 * @dsi: DSI peripheral device1109 * @format: return location for the pixel format1110 *1111 * Return: 0 on success or a negative error code on failure.1112 */1113int mipi_dsi_dcs_get_pixel_format(struct mipi_dsi_device *dsi, u8 *format)1114{1115 ssize_t err;1116 1117 err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_PIXEL_FORMAT, format,1118 sizeof(*format));1119 if (err <= 0) {1120 if (err == 0)1121 err = -ENODATA;1122 1123 return err;1124 }1125 1126 return 0;1127}1128EXPORT_SYMBOL(mipi_dsi_dcs_get_pixel_format);1129 1130/**1131 * mipi_dsi_dcs_enter_sleep_mode() - disable all unnecessary blocks inside the1132 * display module except interface communication1133 * @dsi: DSI peripheral device1134 *1135 * This function is deprecated. Use mipi_dsi_dcs_enter_sleep_mode_multi() instead.1136 *1137 * Return: 0 on success or a negative error code on failure.1138 */1139int mipi_dsi_dcs_enter_sleep_mode(struct mipi_dsi_device *dsi)1140{1141 ssize_t err;1142 1143 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_ENTER_SLEEP_MODE, NULL, 0);1144 if (err < 0)1145 return err;1146 1147 return 0;1148}1149EXPORT_SYMBOL(mipi_dsi_dcs_enter_sleep_mode);1150 1151/**1152 * mipi_dsi_dcs_exit_sleep_mode() - enable all blocks inside the display1153 * module1154 * @dsi: DSI peripheral device1155 *1156 * This function is deprecated. Use mipi_dsi_dcs_exit_sleep_mode_multi() instead.1157 *1158 * Return: 0 on success or a negative error code on failure.1159 */1160int mipi_dsi_dcs_exit_sleep_mode(struct mipi_dsi_device *dsi)1161{1162 ssize_t err;1163 1164 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0);1165 if (err < 0)1166 return err;1167 1168 return 0;1169}1170EXPORT_SYMBOL(mipi_dsi_dcs_exit_sleep_mode);1171 1172/**1173 * mipi_dsi_dcs_set_display_off() - stop displaying the image data on the1174 * display device1175 * @dsi: DSI peripheral device1176 *1177 * This function is deprecated. Use mipi_dsi_dcs_set_display_off_multi() instead.1178 *1179 * Return: 0 on success or a negative error code on failure.1180 */1181int mipi_dsi_dcs_set_display_off(struct mipi_dsi_device *dsi)1182{1183 ssize_t err;1184 1185 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_OFF, NULL, 0);1186 if (err < 0)1187 return err;1188 1189 return 0;1190}1191EXPORT_SYMBOL(mipi_dsi_dcs_set_display_off);1192 1193/**1194 * mipi_dsi_dcs_set_display_on() - start displaying the image data on the1195 * display device1196 * @dsi: DSI peripheral device1197 *1198 * This function is deprecated. Use mipi_dsi_dcs_set_display_on_multi() instead.1199 *1200 * Return: 0 on success or a negative error code on failure1201 */1202int mipi_dsi_dcs_set_display_on(struct mipi_dsi_device *dsi)1203{1204 ssize_t err;1205 1206 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0);1207 if (err < 0)1208 return err;1209 1210 return 0;1211}1212EXPORT_SYMBOL(mipi_dsi_dcs_set_display_on);1213 1214/**1215 * mipi_dsi_dcs_set_column_address() - define the column extent of the frame1216 * memory accessed by the host processor1217 * @dsi: DSI peripheral device1218 * @start: first column of frame memory1219 * @end: last column of frame memory1220 *1221 * This function is deprecated. Use mipi_dsi_dcs_set_column_address_multi()1222 * instead.1223 *1224 * Return: 0 on success or a negative error code on failure.1225 */1226int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start,1227 u16 end)1228{1229 u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff };1230 ssize_t err;1231 1232 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_COLUMN_ADDRESS, payload,1233 sizeof(payload));1234 if (err < 0)1235 return err;1236 1237 return 0;1238}1239EXPORT_SYMBOL(mipi_dsi_dcs_set_column_address);1240 1241/**1242 * mipi_dsi_dcs_set_page_address() - define the page extent of the frame1243 * memory accessed by the host processor1244 * @dsi: DSI peripheral device1245 * @start: first page of frame memory1246 * @end: last page of frame memory1247 *1248 * This function is deprecated. Use mipi_dsi_dcs_set_page_address_multi()1249 * instead.1250 *1251 * Return: 0 on success or a negative error code on failure.1252 */1253int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start,1254 u16 end)1255{1256 u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff };1257 ssize_t err;1258 1259 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PAGE_ADDRESS, payload,1260 sizeof(payload));1261 if (err < 0)1262 return err;1263 1264 return 0;1265}1266EXPORT_SYMBOL(mipi_dsi_dcs_set_page_address);1267 1268/**1269 * mipi_dsi_dcs_set_tear_off() - turn off the display module's Tearing Effect1270 * output signal on the TE signal line1271 * @dsi: DSI peripheral device1272 *1273 * Return: 0 on success or a negative error code on failure1274 */1275int mipi_dsi_dcs_set_tear_off(struct mipi_dsi_device *dsi)1276{1277 ssize_t err;1278 1279 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_OFF, NULL, 0);1280 if (err < 0)1281 return err;1282 1283 return 0;1284}1285EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_off);1286 1287/**1288 * mipi_dsi_dcs_set_tear_on() - turn on the display module's Tearing Effect1289 * output signal on the TE signal line.1290 * @dsi: DSI peripheral device1291 * @mode: the Tearing Effect Output Line mode1292 *1293 * This function is deprecated. Use mipi_dsi_dcs_set_tear_on_multi() instead.1294 *1295 * Return: 0 on success or a negative error code on failure1296 */1297int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi,1298 enum mipi_dsi_dcs_tear_mode mode)1299{1300 u8 value = mode;1301 ssize_t err;1302 1303 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_ON, &value,1304 sizeof(value));1305 if (err < 0)1306 return err;1307 1308 return 0;1309}1310EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_on);1311 1312/**1313 * mipi_dsi_dcs_set_pixel_format() - sets the pixel format for the RGB image1314 * data used by the interface1315 * @dsi: DSI peripheral device1316 * @format: pixel format1317 *1318 * This function is deprecated. Use mipi_dsi_dcs_set_pixel_format_multi()1319 * instead.1320 *1321 * Return: 0 on success or a negative error code on failure.1322 */1323int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format)1324{1325 ssize_t err;1326 1327 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PIXEL_FORMAT, &format,1328 sizeof(format));1329 if (err < 0)1330 return err;1331 1332 return 0;1333}1334EXPORT_SYMBOL(mipi_dsi_dcs_set_pixel_format);1335 1336/**1337 * mipi_dsi_dcs_set_tear_scanline() - set the scanline to use as trigger for1338 * the Tearing Effect output signal of the display module1339 * @dsi: DSI peripheral device1340 * @scanline: scanline to use as trigger1341 *1342 * This function is deprecated. Use mipi_dsi_dcs_set_tear_scanline_multi()1343 * instead.1344 *1345 * Return: 0 on success or a negative error code on failure1346 */1347int mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline)1348{1349 u8 payload[2] = { scanline >> 8, scanline & 0xff };1350 ssize_t err;1351 1352 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_SCANLINE, payload,1353 sizeof(payload));1354 if (err < 0)1355 return err;1356 1357 return 0;1358}1359EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_scanline);1360 1361/**1362 * mipi_dsi_dcs_set_display_brightness() - sets the brightness value of the1363 * display1364 * @dsi: DSI peripheral device1365 * @brightness: brightness value1366 *1367 * This function is deprecated. Use mipi_dsi_dcs_set_display_brightness_multi()1368 * instead.1369 *1370 * Return: 0 on success or a negative error code on failure.1371 */1372int mipi_dsi_dcs_set_display_brightness(struct mipi_dsi_device *dsi,1373 u16 brightness)1374{1375 u8 payload[2] = { brightness & 0xff, brightness >> 8 };1376 ssize_t err;1377 1378 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS,1379 payload, sizeof(payload));1380 if (err < 0)1381 return err;1382 1383 return 0;1384}1385EXPORT_SYMBOL(mipi_dsi_dcs_set_display_brightness);1386 1387/**1388 * mipi_dsi_dcs_get_display_brightness() - gets the current brightness value1389 * of the display1390 * @dsi: DSI peripheral device1391 * @brightness: brightness value1392 *1393 * Return: 0 on success or a negative error code on failure.1394 */1395int mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi,1396 u16 *brightness)1397{1398 ssize_t err;1399 1400 err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_DISPLAY_BRIGHTNESS,1401 brightness, sizeof(*brightness));1402 if (err <= 0) {1403 if (err == 0)1404 err = -ENODATA;1405 1406 return err;1407 }1408 1409 return 0;1410}1411EXPORT_SYMBOL(mipi_dsi_dcs_get_display_brightness);1412 1413/**1414 * mipi_dsi_dcs_set_display_brightness_large() - sets the 16-bit brightness value1415 * of the display1416 * @dsi: DSI peripheral device1417 * @brightness: brightness value1418 *1419 * Return: 0 on success or a negative error code on failure.1420 */1421int mipi_dsi_dcs_set_display_brightness_large(struct mipi_dsi_device *dsi,1422 u16 brightness)1423{1424 u8 payload[2] = { brightness >> 8, brightness & 0xff };1425 ssize_t err;1426 1427 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS,1428 payload, sizeof(payload));1429 if (err < 0)1430 return err;1431 1432 return 0;1433}1434EXPORT_SYMBOL(mipi_dsi_dcs_set_display_brightness_large);1435 1436/**1437 * mipi_dsi_dcs_get_display_brightness_large() - gets the current 16-bit1438 * brightness value of the display1439 * @dsi: DSI peripheral device1440 * @brightness: brightness value1441 *1442 * Return: 0 on success or a negative error code on failure.1443 */1444int mipi_dsi_dcs_get_display_brightness_large(struct mipi_dsi_device *dsi,1445 u16 *brightness)1446{1447 u8 brightness_be[2];1448 ssize_t err;1449 1450 err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_DISPLAY_BRIGHTNESS,1451 brightness_be, sizeof(brightness_be));1452 if (err <= 0) {1453 if (err == 0)1454 err = -ENODATA;1455 1456 return err;1457 }1458 1459 *brightness = (brightness_be[0] << 8) | brightness_be[1];1460 1461 return 0;1462}1463EXPORT_SYMBOL(mipi_dsi_dcs_get_display_brightness_large);1464 1465/**1466 * mipi_dsi_picture_parameter_set_multi() - transmit the DSC PPS to the peripheral1467 * @ctx: Context for multiple DSI transactions1468 * @pps: VESA DSC 1.1 Picture Parameter Set1469 *1470 * Like mipi_dsi_picture_parameter_set() but deals with errors in a way that1471 * makes it convenient to make several calls in a row.1472 */1473void mipi_dsi_picture_parameter_set_multi(struct mipi_dsi_multi_context *ctx,1474 const struct drm_dsc_picture_parameter_set *pps)1475{1476 struct mipi_dsi_device *dsi = ctx->dsi;1477 struct device *dev = &dsi->dev;1478 ssize_t ret;1479 1480 if (ctx->accum_err)1481 return;1482 1483 ret = mipi_dsi_picture_parameter_set(dsi, pps);1484 if (ret < 0) {1485 ctx->accum_err = ret;1486 dev_err(dev, "sending PPS failed: %d\n",1487 ctx->accum_err);1488 }1489}1490EXPORT_SYMBOL(mipi_dsi_picture_parameter_set_multi);1491 1492/**1493 * mipi_dsi_compression_mode_ext_multi() - enable/disable DSC on the peripheral1494 * @ctx: Context for multiple DSI transactions1495 * @enable: Whether to enable or disable the DSC1496 * @algo: Selected compression algorithm1497 * @pps_selector: Select PPS from the table of pre-stored or uploaded PPS entries1498 *1499 * Like mipi_dsi_compression_mode_ext() but deals with errors in a way that1500 * makes it convenient to make several calls in a row.1501 */1502void mipi_dsi_compression_mode_ext_multi(struct mipi_dsi_multi_context *ctx,1503 bool enable,1504 enum mipi_dsi_compression_algo algo,1505 unsigned int pps_selector)1506{1507 struct mipi_dsi_device *dsi = ctx->dsi;1508 struct device *dev = &dsi->dev;1509 ssize_t ret;1510 1511 if (ctx->accum_err)1512 return;1513 1514 ret = mipi_dsi_compression_mode_ext(dsi, enable, algo, pps_selector);1515 if (ret < 0) {1516 ctx->accum_err = ret;1517 dev_err(dev, "sending COMPRESSION_MODE failed: %d\n",1518 ctx->accum_err);1519 }1520}1521EXPORT_SYMBOL(mipi_dsi_compression_mode_ext_multi);1522 1523/**1524 * mipi_dsi_dcs_nop_multi() - send DCS NOP packet1525 * @ctx: Context for multiple DSI transactions1526 *1527 * Like mipi_dsi_dcs_nop() but deals with errors in a way that1528 * makes it convenient to make several calls in a row.1529 */1530void mipi_dsi_dcs_nop_multi(struct mipi_dsi_multi_context *ctx)1531{1532 struct mipi_dsi_device *dsi = ctx->dsi;1533 struct device *dev = &dsi->dev;1534 ssize_t ret;1535 1536 if (ctx->accum_err)1537 return;1538 1539 ret = mipi_dsi_dcs_nop(dsi);1540 if (ret < 0) {1541 ctx->accum_err = ret;1542 dev_err(dev, "sending DCS NOP failed: %d\n",1543 ctx->accum_err);1544 }1545}1546EXPORT_SYMBOL(mipi_dsi_dcs_nop_multi);1547 1548/**1549 * mipi_dsi_dcs_enter_sleep_mode_multi() - send DCS ENTER_SLEEP_MODE packet1550 * @ctx: Context for multiple DSI transactions1551 *1552 * Like mipi_dsi_dcs_enter_sleep_mode() but deals with errors in a way that1553 * makes it convenient to make several calls in a row.1554 */1555void mipi_dsi_dcs_enter_sleep_mode_multi(struct mipi_dsi_multi_context *ctx)1556{1557 struct mipi_dsi_device *dsi = ctx->dsi;1558 struct device *dev = &dsi->dev;1559 ssize_t ret;1560 1561 if (ctx->accum_err)1562 return;1563 1564 ret = mipi_dsi_dcs_enter_sleep_mode(dsi);1565 if (ret < 0) {1566 ctx->accum_err = ret;1567 dev_err(dev, "sending DCS ENTER_SLEEP_MODE failed: %d\n",1568 ctx->accum_err);1569 }1570}1571EXPORT_SYMBOL(mipi_dsi_dcs_enter_sleep_mode_multi);1572 1573/**1574 * mipi_dsi_dcs_exit_sleep_mode_multi() - send DCS EXIT_SLEEP_MODE packet1575 * @ctx: Context for multiple DSI transactions1576 *1577 * Like mipi_dsi_dcs_exit_sleep_mode() but deals with errors in a way that1578 * makes it convenient to make several calls in a row.1579 */1580void mipi_dsi_dcs_exit_sleep_mode_multi(struct mipi_dsi_multi_context *ctx)1581{1582 struct mipi_dsi_device *dsi = ctx->dsi;1583 struct device *dev = &dsi->dev;1584 ssize_t ret;1585 1586 if (ctx->accum_err)1587 return;1588 1589 ret = mipi_dsi_dcs_exit_sleep_mode(dsi);1590 if (ret < 0) {1591 ctx->accum_err = ret;1592 dev_err(dev, "sending DCS EXIT_SLEEP_MODE failed: %d\n",1593 ctx->accum_err);1594 }1595}1596EXPORT_SYMBOL(mipi_dsi_dcs_exit_sleep_mode_multi);1597 1598/**1599 * mipi_dsi_dcs_set_display_off_multi() - send DCS SET_DISPLAY_OFF packet1600 * @ctx: Context for multiple DSI transactions1601 *1602 * Like mipi_dsi_dcs_set_display_off() but deals with errors in a way that1603 * makes it convenient to make several calls in a row.1604 */1605void mipi_dsi_dcs_set_display_off_multi(struct mipi_dsi_multi_context *ctx)1606{1607 struct mipi_dsi_device *dsi = ctx->dsi;1608 struct device *dev = &dsi->dev;1609 ssize_t ret;1610 1611 if (ctx->accum_err)1612 return;1613 1614 ret = mipi_dsi_dcs_set_display_off(dsi);1615 if (ret < 0) {1616 ctx->accum_err = ret;1617 dev_err(dev, "sending DCS SET_DISPLAY_OFF failed: %d\n",1618 ctx->accum_err);1619 }1620}1621EXPORT_SYMBOL(mipi_dsi_dcs_set_display_off_multi);1622 1623/**1624 * mipi_dsi_dcs_set_display_on_multi() - send DCS SET_DISPLAY_ON packet1625 * @ctx: Context for multiple DSI transactions1626 *1627 * Like mipi_dsi_dcs_set_display_on() but deals with errors in a way that1628 * makes it convenient to make several calls in a row.1629 */1630void mipi_dsi_dcs_set_display_on_multi(struct mipi_dsi_multi_context *ctx)1631{1632 struct mipi_dsi_device *dsi = ctx->dsi;1633 struct device *dev = &dsi->dev;1634 ssize_t ret;1635 1636 if (ctx->accum_err)1637 return;1638 1639 ret = mipi_dsi_dcs_set_display_on(dsi);1640 if (ret < 0) {1641 ctx->accum_err = ret;1642 dev_err(dev, "sending DCS SET_DISPLAY_ON failed: %d\n",1643 ctx->accum_err);1644 }1645}1646EXPORT_SYMBOL(mipi_dsi_dcs_set_display_on_multi);1647 1648/**1649 * mipi_dsi_dcs_set_tear_on_multi() - send DCS SET_TEAR_ON packet1650 * @ctx: Context for multiple DSI transactions1651 * @mode: the Tearing Effect Output Line mode1652 *1653 * Like mipi_dsi_dcs_set_tear_on() but deals with errors in a way that1654 * makes it convenient to make several calls in a row.1655 */1656void mipi_dsi_dcs_set_tear_on_multi(struct mipi_dsi_multi_context *ctx,1657 enum mipi_dsi_dcs_tear_mode mode)1658{1659 struct mipi_dsi_device *dsi = ctx->dsi;1660 struct device *dev = &dsi->dev;1661 ssize_t ret;1662 1663 if (ctx->accum_err)1664 return;1665 1666 ret = mipi_dsi_dcs_set_tear_on(dsi, mode);1667 if (ret < 0) {1668 ctx->accum_err = ret;1669 dev_err(dev, "sending DCS SET_TEAR_ON failed: %d\n",1670 ctx->accum_err);1671 }1672}1673EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_on_multi);1674 1675/**1676 * mipi_dsi_turn_on_peripheral_multi() - sends a Turn On Peripheral command1677 * @ctx: Context for multiple DSI transactions1678 *1679 * Like mipi_dsi_turn_on_peripheral() but deals with errors in a way that1680 * makes it convenient to make several calls in a row.1681 */1682void mipi_dsi_turn_on_peripheral_multi(struct mipi_dsi_multi_context *ctx)1683{1684 struct mipi_dsi_device *dsi = ctx->dsi;1685 struct device *dev = &dsi->dev;1686 int ret;1687 1688 if (ctx->accum_err)1689 return;1690 1691 ret = mipi_dsi_turn_on_peripheral(dsi);1692 if (ret < 0) {1693 ctx->accum_err = ret;1694 dev_err(dev, "Failed to turn on peripheral: %d\n",1695 ctx->accum_err);1696 }1697}1698EXPORT_SYMBOL(mipi_dsi_turn_on_peripheral_multi);1699 1700/**1701 * mipi_dsi_dcs_soft_reset_multi() - perform a software reset of the display module1702 * @ctx: Context for multiple DSI transactions1703 *1704 * Like mipi_dsi_dcs_soft_reset() but deals with errors in a way that1705 * makes it convenient to make several calls in a row.1706 */1707void mipi_dsi_dcs_soft_reset_multi(struct mipi_dsi_multi_context *ctx)1708{1709 struct mipi_dsi_device *dsi = ctx->dsi;1710 struct device *dev = &dsi->dev;1711 int ret;1712 1713 if (ctx->accum_err)1714 return;1715 1716 ret = mipi_dsi_dcs_soft_reset(dsi);1717 if (ret < 0) {1718 ctx->accum_err = ret;1719 dev_err(dev, "Failed to mipi_dsi_dcs_soft_reset: %d\n",1720 ctx->accum_err);1721 }1722}1723EXPORT_SYMBOL(mipi_dsi_dcs_soft_reset_multi);1724 1725/**1726 * mipi_dsi_dcs_set_display_brightness_multi() - sets the brightness value of1727 * the display1728 * @ctx: Context for multiple DSI transactions1729 * @brightness: brightness value1730 *1731 * Like mipi_dsi_dcs_set_display_brightness() but deals with errors in a way that1732 * makes it convenient to make several calls in a row.1733 */1734void mipi_dsi_dcs_set_display_brightness_multi(struct mipi_dsi_multi_context *ctx,1735 u16 brightness)1736{1737 struct mipi_dsi_device *dsi = ctx->dsi;1738 struct device *dev = &dsi->dev;1739 int ret;1740 1741 if (ctx->accum_err)1742 return;1743 1744 ret = mipi_dsi_dcs_set_display_brightness(dsi, brightness);1745 if (ret < 0) {1746 ctx->accum_err = ret;1747 dev_err(dev, "Failed to write display brightness: %d\n",1748 ctx->accum_err);1749 }1750}1751EXPORT_SYMBOL(mipi_dsi_dcs_set_display_brightness_multi);1752 1753/**1754 * mipi_dsi_dcs_set_pixel_format_multi() - sets the pixel format for the RGB image1755 * data used by the interface1756 * @ctx: Context for multiple DSI transactions1757 * @format: pixel format1758 *1759 * Like mipi_dsi_dcs_set_pixel_format() but deals with errors in a way that1760 * makes it convenient to make several calls in a row.1761 */1762void mipi_dsi_dcs_set_pixel_format_multi(struct mipi_dsi_multi_context *ctx,1763 u8 format)1764{1765 struct mipi_dsi_device *dsi = ctx->dsi;1766 struct device *dev = &dsi->dev;1767 int ret;1768 1769 if (ctx->accum_err)1770 return;1771 1772 ret = mipi_dsi_dcs_set_pixel_format(dsi, format);1773 if (ret < 0) {1774 ctx->accum_err = ret;1775 dev_err(dev, "Failed to set pixel format: %d\n",1776 ctx->accum_err);1777 }1778}1779EXPORT_SYMBOL(mipi_dsi_dcs_set_pixel_format_multi);1780 1781/**1782 * mipi_dsi_dcs_set_column_address_multi() - define the column extent of the1783 * frame memory accessed by the host processor1784 * @ctx: Context for multiple DSI transactions1785 * @start: first column of frame memory1786 * @end: last column of frame memory1787 *1788 * Like mipi_dsi_dcs_set_column_address() but deals with errors in a way that1789 * makes it convenient to make several calls in a row.1790 */1791void mipi_dsi_dcs_set_column_address_multi(struct mipi_dsi_multi_context *ctx,1792 u16 start, u16 end)1793{1794 struct mipi_dsi_device *dsi = ctx->dsi;1795 struct device *dev = &dsi->dev;1796 int ret;1797 1798 if (ctx->accum_err)1799 return;1800 1801 ret = mipi_dsi_dcs_set_column_address(dsi, start, end);1802 if (ret < 0) {1803 ctx->accum_err = ret;1804 dev_err(dev, "Failed to set column address: %d\n",1805 ctx->accum_err);1806 }1807}1808EXPORT_SYMBOL(mipi_dsi_dcs_set_column_address_multi);1809 1810/**1811 * mipi_dsi_dcs_set_page_address_multi() - define the page extent of the1812 * frame memory accessed by the host processor1813 * @ctx: Context for multiple DSI transactions1814 * @start: first page of frame memory1815 * @end: last page of frame memory1816 *1817 * Like mipi_dsi_dcs_set_page_address() but deals with errors in a way that1818 * makes it convenient to make several calls in a row.1819 */1820void mipi_dsi_dcs_set_page_address_multi(struct mipi_dsi_multi_context *ctx,1821 u16 start, u16 end)1822{1823 struct mipi_dsi_device *dsi = ctx->dsi;1824 struct device *dev = &dsi->dev;1825 int ret;1826 1827 if (ctx->accum_err)1828 return;1829 1830 ret = mipi_dsi_dcs_set_page_address(dsi, start, end);1831 if (ret < 0) {1832 ctx->accum_err = ret;1833 dev_err(dev, "Failed to set page address: %d\n",1834 ctx->accum_err);1835 }1836}1837EXPORT_SYMBOL(mipi_dsi_dcs_set_page_address_multi);1838 1839/**1840 * mipi_dsi_dcs_set_tear_scanline_multi() - set the scanline to use as trigger for1841 * the Tearing Effect output signal of the display module1842 * @ctx: Context for multiple DSI transactions1843 * @scanline: scanline to use as trigger1844 *1845 * Like mipi_dsi_dcs_set_tear_scanline() but deals with errors in a way that1846 * makes it convenient to make several calls in a row.1847 */1848void mipi_dsi_dcs_set_tear_scanline_multi(struct mipi_dsi_multi_context *ctx,1849 u16 scanline)1850{1851 struct mipi_dsi_device *dsi = ctx->dsi;1852 struct device *dev = &dsi->dev;1853 int ret;1854 1855 if (ctx->accum_err)1856 return;1857 1858 ret = mipi_dsi_dcs_set_tear_scanline(dsi, scanline);1859 if (ret < 0) {1860 ctx->accum_err = ret;1861 dev_err(dev, "Failed to set tear scanline: %d\n",1862 ctx->accum_err);1863 }1864}1865EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_scanline_multi);1866 1867static int mipi_dsi_drv_probe(struct device *dev)1868{1869 struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver);1870 struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);1871 1872 return drv->probe(dsi);1873}1874 1875static int mipi_dsi_drv_remove(struct device *dev)1876{1877 struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver);1878 struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);1879 1880 drv->remove(dsi);1881 1882 return 0;1883}1884 1885static void mipi_dsi_drv_shutdown(struct device *dev)1886{1887 struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver);1888 struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);1889 1890 drv->shutdown(dsi);1891}1892 1893/**1894 * mipi_dsi_driver_register_full() - register a driver for DSI devices1895 * @drv: DSI driver structure1896 * @owner: owner module1897 *1898 * Return: 0 on success or a negative error code on failure.1899 */1900int mipi_dsi_driver_register_full(struct mipi_dsi_driver *drv,1901 struct module *owner)1902{1903 drv->driver.bus = &mipi_dsi_bus_type;1904 drv->driver.owner = owner;1905 1906 if (drv->probe)1907 drv->driver.probe = mipi_dsi_drv_probe;1908 if (drv->remove)1909 drv->driver.remove = mipi_dsi_drv_remove;1910 if (drv->shutdown)1911 drv->driver.shutdown = mipi_dsi_drv_shutdown;1912 1913 return driver_register(&drv->driver);1914}1915EXPORT_SYMBOL(mipi_dsi_driver_register_full);1916 1917/**1918 * mipi_dsi_driver_unregister() - unregister a driver for DSI devices1919 * @drv: DSI driver structure1920 *1921 * Return: 0 on success or a negative error code on failure.1922 */1923void mipi_dsi_driver_unregister(struct mipi_dsi_driver *drv)1924{1925 driver_unregister(&drv->driver);1926}1927EXPORT_SYMBOL(mipi_dsi_driver_unregister);1928 1929static int __init mipi_dsi_bus_init(void)1930{1931 return bus_register(&mipi_dsi_bus_type);1932}1933postcore_initcall(mipi_dsi_bus_init);1934 1935MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");1936MODULE_DESCRIPTION("MIPI DSI Bus");1937MODULE_LICENSE("GPL and additional rights");1938