brintos

brintos / linux-shallow public Read only

0
0
Text · 49.4 KiB · 2bc3973 Raw
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", &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