162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * MIPI DSI Bus 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd. 562306a36Sopenharmony_ci * Andrzej Hajda <a.hajda@samsung.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 862306a36Sopenharmony_ci * copy of this software and associated documentation files (the 962306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 1062306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 1162306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 1262306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 1362306a36Sopenharmony_ci * the following conditions: 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the 1662306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 1762306a36Sopenharmony_ci * of the Software. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2062306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2162306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 2262306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 2362306a36Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 2462306a36Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 2562306a36Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include <linux/device.h> 2962306a36Sopenharmony_ci#include <linux/module.h> 3062306a36Sopenharmony_ci#include <linux/of.h> 3162306a36Sopenharmony_ci#include <linux/of_device.h> 3262306a36Sopenharmony_ci#include <linux/pm_runtime.h> 3362306a36Sopenharmony_ci#include <linux/slab.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include <drm/display/drm_dsc.h> 3662306a36Sopenharmony_ci#include <drm/drm_mipi_dsi.h> 3762306a36Sopenharmony_ci#include <drm/drm_print.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include <video/mipi_display.h> 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/** 4262306a36Sopenharmony_ci * DOC: dsi helpers 4362306a36Sopenharmony_ci * 4462306a36Sopenharmony_ci * These functions contain some common logic and helpers to deal with MIPI DSI 4562306a36Sopenharmony_ci * peripherals. 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * Helpers are provided for a number of standard MIPI DSI command as well as a 4862306a36Sopenharmony_ci * subset of the MIPI DCS command set. 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic int mipi_dsi_device_match(struct device *dev, struct device_driver *drv) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci /* attempt OF style match */ 5662306a36Sopenharmony_ci if (of_driver_match_device(dev, drv)) 5762306a36Sopenharmony_ci return 1; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci /* compare DSI device and driver names */ 6062306a36Sopenharmony_ci if (!strcmp(dsi->name, drv->name)) 6162306a36Sopenharmony_ci return 1; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci return 0; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic int mipi_dsi_uevent(const struct device *dev, struct kobj_uevent_env *env) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci const struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); 6962306a36Sopenharmony_ci int err; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci err = of_device_uevent_modalias(dev, env); 7262306a36Sopenharmony_ci if (err != -ENODEV) 7362306a36Sopenharmony_ci return err; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci add_uevent_var(env, "MODALIAS=%s%s", MIPI_DSI_MODULE_PREFIX, 7662306a36Sopenharmony_ci dsi->name); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci return 0; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic const struct dev_pm_ops mipi_dsi_device_pm_ops = { 8262306a36Sopenharmony_ci .runtime_suspend = pm_generic_runtime_suspend, 8362306a36Sopenharmony_ci .runtime_resume = pm_generic_runtime_resume, 8462306a36Sopenharmony_ci .suspend = pm_generic_suspend, 8562306a36Sopenharmony_ci .resume = pm_generic_resume, 8662306a36Sopenharmony_ci .freeze = pm_generic_freeze, 8762306a36Sopenharmony_ci .thaw = pm_generic_thaw, 8862306a36Sopenharmony_ci .poweroff = pm_generic_poweroff, 8962306a36Sopenharmony_ci .restore = pm_generic_restore, 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic struct bus_type mipi_dsi_bus_type = { 9362306a36Sopenharmony_ci .name = "mipi-dsi", 9462306a36Sopenharmony_ci .match = mipi_dsi_device_match, 9562306a36Sopenharmony_ci .uevent = mipi_dsi_uevent, 9662306a36Sopenharmony_ci .pm = &mipi_dsi_device_pm_ops, 9762306a36Sopenharmony_ci}; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/** 10062306a36Sopenharmony_ci * of_find_mipi_dsi_device_by_node() - find the MIPI DSI device matching a 10162306a36Sopenharmony_ci * device tree node 10262306a36Sopenharmony_ci * @np: device tree node 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * Return: A pointer to the MIPI DSI device corresponding to @np or NULL if no 10562306a36Sopenharmony_ci * such device exists (or has not been registered yet). 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_cistruct mipi_dsi_device *of_find_mipi_dsi_device_by_node(struct device_node *np) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci struct device *dev; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci dev = bus_find_device_by_of_node(&mipi_dsi_bus_type, np); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return dev ? to_mipi_dsi_device(dev) : NULL; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ciEXPORT_SYMBOL(of_find_mipi_dsi_device_by_node); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic void mipi_dsi_dev_release(struct device *dev) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci of_node_put(dev->of_node); 12262306a36Sopenharmony_ci kfree(dsi); 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic const struct device_type mipi_dsi_device_type = { 12662306a36Sopenharmony_ci .release = mipi_dsi_dev_release, 12762306a36Sopenharmony_ci}; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic struct mipi_dsi_device *mipi_dsi_device_alloc(struct mipi_dsi_host *host) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct mipi_dsi_device *dsi; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci dsi = kzalloc(sizeof(*dsi), GFP_KERNEL); 13462306a36Sopenharmony_ci if (!dsi) 13562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci dsi->host = host; 13862306a36Sopenharmony_ci dsi->dev.bus = &mipi_dsi_bus_type; 13962306a36Sopenharmony_ci dsi->dev.parent = host->dev; 14062306a36Sopenharmony_ci dsi->dev.type = &mipi_dsi_device_type; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci device_initialize(&dsi->dev); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci return dsi; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic int mipi_dsi_device_add(struct mipi_dsi_device *dsi) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci struct mipi_dsi_host *host = dsi->host; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), dsi->channel); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci return device_add(&dsi->dev); 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_OF) 15762306a36Sopenharmony_cistatic struct mipi_dsi_device * 15862306a36Sopenharmony_ciof_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci struct mipi_dsi_device_info info = { }; 16162306a36Sopenharmony_ci int ret; 16262306a36Sopenharmony_ci u32 reg; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (of_alias_from_compatible(node, info.type, sizeof(info.type)) < 0) { 16562306a36Sopenharmony_ci drm_err(host, "modalias failure on %pOF\n", node); 16662306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci ret = of_property_read_u32(node, "reg", ®); 17062306a36Sopenharmony_ci if (ret) { 17162306a36Sopenharmony_ci drm_err(host, "device node %pOF has no valid reg property: %d\n", 17262306a36Sopenharmony_ci node, ret); 17362306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci info.channel = reg; 17762306a36Sopenharmony_ci info.node = of_node_get(node); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return mipi_dsi_device_register_full(host, &info); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci#else 18262306a36Sopenharmony_cistatic struct mipi_dsi_device * 18362306a36Sopenharmony_ciof_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci#endif 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci/** 19062306a36Sopenharmony_ci * mipi_dsi_device_register_full - create a MIPI DSI device 19162306a36Sopenharmony_ci * @host: DSI host to which this device is connected 19262306a36Sopenharmony_ci * @info: pointer to template containing DSI device information 19362306a36Sopenharmony_ci * 19462306a36Sopenharmony_ci * Create a MIPI DSI device by using the device information provided by 19562306a36Sopenharmony_ci * mipi_dsi_device_info template 19662306a36Sopenharmony_ci * 19762306a36Sopenharmony_ci * Returns: 19862306a36Sopenharmony_ci * A pointer to the newly created MIPI DSI device, or, a pointer encoded 19962306a36Sopenharmony_ci * with an error 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_cistruct mipi_dsi_device * 20262306a36Sopenharmony_cimipi_dsi_device_register_full(struct mipi_dsi_host *host, 20362306a36Sopenharmony_ci const struct mipi_dsi_device_info *info) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci struct mipi_dsi_device *dsi; 20662306a36Sopenharmony_ci int ret; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (!info) { 20962306a36Sopenharmony_ci drm_err(host, "invalid mipi_dsi_device_info pointer\n"); 21062306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (info->channel > 3) { 21462306a36Sopenharmony_ci drm_err(host, "invalid virtual channel: %u\n", info->channel); 21562306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci dsi = mipi_dsi_device_alloc(host); 21962306a36Sopenharmony_ci if (IS_ERR(dsi)) { 22062306a36Sopenharmony_ci drm_err(host, "failed to allocate DSI device %ld\n", 22162306a36Sopenharmony_ci PTR_ERR(dsi)); 22262306a36Sopenharmony_ci return dsi; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci device_set_node(&dsi->dev, of_fwnode_handle(info->node)); 22662306a36Sopenharmony_ci dsi->channel = info->channel; 22762306a36Sopenharmony_ci strscpy(dsi->name, info->type, sizeof(dsi->name)); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci ret = mipi_dsi_device_add(dsi); 23062306a36Sopenharmony_ci if (ret) { 23162306a36Sopenharmony_ci drm_err(host, "failed to add DSI device %d\n", ret); 23262306a36Sopenharmony_ci kfree(dsi); 23362306a36Sopenharmony_ci return ERR_PTR(ret); 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci return dsi; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_device_register_full); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci/** 24162306a36Sopenharmony_ci * mipi_dsi_device_unregister - unregister MIPI DSI device 24262306a36Sopenharmony_ci * @dsi: DSI peripheral device 24362306a36Sopenharmony_ci */ 24462306a36Sopenharmony_civoid mipi_dsi_device_unregister(struct mipi_dsi_device *dsi) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci device_unregister(&dsi->dev); 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_device_unregister); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic void devm_mipi_dsi_device_unregister(void *arg) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci struct mipi_dsi_device *dsi = arg; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci mipi_dsi_device_unregister(dsi); 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci/** 25862306a36Sopenharmony_ci * devm_mipi_dsi_device_register_full - create a managed MIPI DSI device 25962306a36Sopenharmony_ci * @dev: device to tie the MIPI-DSI device lifetime to 26062306a36Sopenharmony_ci * @host: DSI host to which this device is connected 26162306a36Sopenharmony_ci * @info: pointer to template containing DSI device information 26262306a36Sopenharmony_ci * 26362306a36Sopenharmony_ci * Create a MIPI DSI device by using the device information provided by 26462306a36Sopenharmony_ci * mipi_dsi_device_info template 26562306a36Sopenharmony_ci * 26662306a36Sopenharmony_ci * This is the managed version of mipi_dsi_device_register_full() which 26762306a36Sopenharmony_ci * automatically calls mipi_dsi_device_unregister() when @dev is 26862306a36Sopenharmony_ci * unbound. 26962306a36Sopenharmony_ci * 27062306a36Sopenharmony_ci * Returns: 27162306a36Sopenharmony_ci * A pointer to the newly created MIPI DSI device, or, a pointer encoded 27262306a36Sopenharmony_ci * with an error 27362306a36Sopenharmony_ci */ 27462306a36Sopenharmony_cistruct mipi_dsi_device * 27562306a36Sopenharmony_cidevm_mipi_dsi_device_register_full(struct device *dev, 27662306a36Sopenharmony_ci struct mipi_dsi_host *host, 27762306a36Sopenharmony_ci const struct mipi_dsi_device_info *info) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci struct mipi_dsi_device *dsi; 28062306a36Sopenharmony_ci int ret; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci dsi = mipi_dsi_device_register_full(host, info); 28362306a36Sopenharmony_ci if (IS_ERR(dsi)) 28462306a36Sopenharmony_ci return dsi; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci ret = devm_add_action_or_reset(dev, 28762306a36Sopenharmony_ci devm_mipi_dsi_device_unregister, 28862306a36Sopenharmony_ci dsi); 28962306a36Sopenharmony_ci if (ret) 29062306a36Sopenharmony_ci return ERR_PTR(ret); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return dsi; 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_mipi_dsi_device_register_full); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic DEFINE_MUTEX(host_lock); 29762306a36Sopenharmony_cistatic LIST_HEAD(host_list); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci/** 30062306a36Sopenharmony_ci * of_find_mipi_dsi_host_by_node() - find the MIPI DSI host matching a 30162306a36Sopenharmony_ci * device tree node 30262306a36Sopenharmony_ci * @node: device tree node 30362306a36Sopenharmony_ci * 30462306a36Sopenharmony_ci * Returns: 30562306a36Sopenharmony_ci * A pointer to the MIPI DSI host corresponding to @node or NULL if no 30662306a36Sopenharmony_ci * such device exists (or has not been registered yet). 30762306a36Sopenharmony_ci */ 30862306a36Sopenharmony_cistruct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci struct mipi_dsi_host *host; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci mutex_lock(&host_lock); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci list_for_each_entry(host, &host_list, list) { 31562306a36Sopenharmony_ci if (host->dev->of_node == node) { 31662306a36Sopenharmony_ci mutex_unlock(&host_lock); 31762306a36Sopenharmony_ci return host; 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci mutex_unlock(&host_lock); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci return NULL; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ciEXPORT_SYMBOL(of_find_mipi_dsi_host_by_node); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ciint mipi_dsi_host_register(struct mipi_dsi_host *host) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci struct device_node *node; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci for_each_available_child_of_node(host->dev->of_node, node) { 33262306a36Sopenharmony_ci /* skip nodes without reg property */ 33362306a36Sopenharmony_ci if (!of_property_present(node, "reg")) 33462306a36Sopenharmony_ci continue; 33562306a36Sopenharmony_ci of_mipi_dsi_device_add(host, node); 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci mutex_lock(&host_lock); 33962306a36Sopenharmony_ci list_add_tail(&host->list, &host_list); 34062306a36Sopenharmony_ci mutex_unlock(&host_lock); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci return 0; 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_host_register); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic int mipi_dsi_remove_device_fn(struct device *dev, void *priv) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (dsi->attached) 35162306a36Sopenharmony_ci mipi_dsi_detach(dsi); 35262306a36Sopenharmony_ci mipi_dsi_device_unregister(dsi); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci return 0; 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_civoid mipi_dsi_host_unregister(struct mipi_dsi_host *host) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci device_for_each_child(host->dev, NULL, mipi_dsi_remove_device_fn); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci mutex_lock(&host_lock); 36262306a36Sopenharmony_ci list_del_init(&host->list); 36362306a36Sopenharmony_ci mutex_unlock(&host_lock); 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_host_unregister); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci/** 36862306a36Sopenharmony_ci * mipi_dsi_attach - attach a DSI device to its DSI host 36962306a36Sopenharmony_ci * @dsi: DSI peripheral 37062306a36Sopenharmony_ci */ 37162306a36Sopenharmony_ciint mipi_dsi_attach(struct mipi_dsi_device *dsi) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci const struct mipi_dsi_host_ops *ops = dsi->host->ops; 37462306a36Sopenharmony_ci int ret; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (!ops || !ops->attach) 37762306a36Sopenharmony_ci return -ENOSYS; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci ret = ops->attach(dsi->host, dsi); 38062306a36Sopenharmony_ci if (ret) 38162306a36Sopenharmony_ci return ret; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci dsi->attached = true; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci return 0; 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_attach); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci/** 39062306a36Sopenharmony_ci * mipi_dsi_detach - detach a DSI device from its DSI host 39162306a36Sopenharmony_ci * @dsi: DSI peripheral 39262306a36Sopenharmony_ci */ 39362306a36Sopenharmony_ciint mipi_dsi_detach(struct mipi_dsi_device *dsi) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci const struct mipi_dsi_host_ops *ops = dsi->host->ops; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (WARN_ON(!dsi->attached)) 39862306a36Sopenharmony_ci return -EINVAL; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (!ops || !ops->detach) 40162306a36Sopenharmony_ci return -ENOSYS; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci dsi->attached = false; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci return ops->detach(dsi->host, dsi); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_detach); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic void devm_mipi_dsi_detach(void *arg) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci struct mipi_dsi_device *dsi = arg; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci mipi_dsi_detach(dsi); 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci/** 41762306a36Sopenharmony_ci * devm_mipi_dsi_attach - Attach a MIPI-DSI device to its DSI Host 41862306a36Sopenharmony_ci * @dev: device to tie the MIPI-DSI device attachment lifetime to 41962306a36Sopenharmony_ci * @dsi: DSI peripheral 42062306a36Sopenharmony_ci * 42162306a36Sopenharmony_ci * This is the managed version of mipi_dsi_attach() which automatically 42262306a36Sopenharmony_ci * calls mipi_dsi_detach() when @dev is unbound. 42362306a36Sopenharmony_ci * 42462306a36Sopenharmony_ci * Returns: 42562306a36Sopenharmony_ci * 0 on success, a negative error code on failure. 42662306a36Sopenharmony_ci */ 42762306a36Sopenharmony_ciint devm_mipi_dsi_attach(struct device *dev, 42862306a36Sopenharmony_ci struct mipi_dsi_device *dsi) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci int ret; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci ret = mipi_dsi_attach(dsi); 43362306a36Sopenharmony_ci if (ret) 43462306a36Sopenharmony_ci return ret; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci ret = devm_add_action_or_reset(dev, devm_mipi_dsi_detach, dsi); 43762306a36Sopenharmony_ci if (ret) 43862306a36Sopenharmony_ci return ret; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci return 0; 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_mipi_dsi_attach); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic ssize_t mipi_dsi_device_transfer(struct mipi_dsi_device *dsi, 44562306a36Sopenharmony_ci struct mipi_dsi_msg *msg) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci const struct mipi_dsi_host_ops *ops = dsi->host->ops; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci if (!ops || !ops->transfer) 45062306a36Sopenharmony_ci return -ENOSYS; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (dsi->mode_flags & MIPI_DSI_MODE_LPM) 45362306a36Sopenharmony_ci msg->flags |= MIPI_DSI_MSG_USE_LPM; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci return ops->transfer(dsi->host, msg); 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci/** 45962306a36Sopenharmony_ci * mipi_dsi_packet_format_is_short - check if a packet is of the short format 46062306a36Sopenharmony_ci * @type: MIPI DSI data type of the packet 46162306a36Sopenharmony_ci * 46262306a36Sopenharmony_ci * Return: true if the packet for the given data type is a short packet, false 46362306a36Sopenharmony_ci * otherwise. 46462306a36Sopenharmony_ci */ 46562306a36Sopenharmony_cibool mipi_dsi_packet_format_is_short(u8 type) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci switch (type) { 46862306a36Sopenharmony_ci case MIPI_DSI_V_SYNC_START: 46962306a36Sopenharmony_ci case MIPI_DSI_V_SYNC_END: 47062306a36Sopenharmony_ci case MIPI_DSI_H_SYNC_START: 47162306a36Sopenharmony_ci case MIPI_DSI_H_SYNC_END: 47262306a36Sopenharmony_ci case MIPI_DSI_COMPRESSION_MODE: 47362306a36Sopenharmony_ci case MIPI_DSI_END_OF_TRANSMISSION: 47462306a36Sopenharmony_ci case MIPI_DSI_COLOR_MODE_OFF: 47562306a36Sopenharmony_ci case MIPI_DSI_COLOR_MODE_ON: 47662306a36Sopenharmony_ci case MIPI_DSI_SHUTDOWN_PERIPHERAL: 47762306a36Sopenharmony_ci case MIPI_DSI_TURN_ON_PERIPHERAL: 47862306a36Sopenharmony_ci case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: 47962306a36Sopenharmony_ci case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: 48062306a36Sopenharmony_ci case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: 48162306a36Sopenharmony_ci case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM: 48262306a36Sopenharmony_ci case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM: 48362306a36Sopenharmony_ci case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM: 48462306a36Sopenharmony_ci case MIPI_DSI_DCS_SHORT_WRITE: 48562306a36Sopenharmony_ci case MIPI_DSI_DCS_SHORT_WRITE_PARAM: 48662306a36Sopenharmony_ci case MIPI_DSI_DCS_READ: 48762306a36Sopenharmony_ci case MIPI_DSI_EXECUTE_QUEUE: 48862306a36Sopenharmony_ci case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE: 48962306a36Sopenharmony_ci return true; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci return false; 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_packet_format_is_short); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci/** 49762306a36Sopenharmony_ci * mipi_dsi_packet_format_is_long - check if a packet is of the long format 49862306a36Sopenharmony_ci * @type: MIPI DSI data type of the packet 49962306a36Sopenharmony_ci * 50062306a36Sopenharmony_ci * Return: true if the packet for the given data type is a long packet, false 50162306a36Sopenharmony_ci * otherwise. 50262306a36Sopenharmony_ci */ 50362306a36Sopenharmony_cibool mipi_dsi_packet_format_is_long(u8 type) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci switch (type) { 50662306a36Sopenharmony_ci case MIPI_DSI_NULL_PACKET: 50762306a36Sopenharmony_ci case MIPI_DSI_BLANKING_PACKET: 50862306a36Sopenharmony_ci case MIPI_DSI_GENERIC_LONG_WRITE: 50962306a36Sopenharmony_ci case MIPI_DSI_DCS_LONG_WRITE: 51062306a36Sopenharmony_ci case MIPI_DSI_PICTURE_PARAMETER_SET: 51162306a36Sopenharmony_ci case MIPI_DSI_COMPRESSED_PIXEL_STREAM: 51262306a36Sopenharmony_ci case MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20: 51362306a36Sopenharmony_ci case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24: 51462306a36Sopenharmony_ci case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16: 51562306a36Sopenharmony_ci case MIPI_DSI_PACKED_PIXEL_STREAM_30: 51662306a36Sopenharmony_ci case MIPI_DSI_PACKED_PIXEL_STREAM_36: 51762306a36Sopenharmony_ci case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12: 51862306a36Sopenharmony_ci case MIPI_DSI_PACKED_PIXEL_STREAM_16: 51962306a36Sopenharmony_ci case MIPI_DSI_PACKED_PIXEL_STREAM_18: 52062306a36Sopenharmony_ci case MIPI_DSI_PIXEL_STREAM_3BYTE_18: 52162306a36Sopenharmony_ci case MIPI_DSI_PACKED_PIXEL_STREAM_24: 52262306a36Sopenharmony_ci return true; 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci return false; 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_packet_format_is_long); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci/** 53062306a36Sopenharmony_ci * mipi_dsi_create_packet - create a packet from a message according to the 53162306a36Sopenharmony_ci * DSI protocol 53262306a36Sopenharmony_ci * @packet: pointer to a DSI packet structure 53362306a36Sopenharmony_ci * @msg: message to translate into a packet 53462306a36Sopenharmony_ci * 53562306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 53662306a36Sopenharmony_ci */ 53762306a36Sopenharmony_ciint mipi_dsi_create_packet(struct mipi_dsi_packet *packet, 53862306a36Sopenharmony_ci const struct mipi_dsi_msg *msg) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci if (!packet || !msg) 54162306a36Sopenharmony_ci return -EINVAL; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci /* do some minimum sanity checking */ 54462306a36Sopenharmony_ci if (!mipi_dsi_packet_format_is_short(msg->type) && 54562306a36Sopenharmony_ci !mipi_dsi_packet_format_is_long(msg->type)) 54662306a36Sopenharmony_ci return -EINVAL; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci if (msg->channel > 3) 54962306a36Sopenharmony_ci return -EINVAL; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci memset(packet, 0, sizeof(*packet)); 55262306a36Sopenharmony_ci packet->header[0] = ((msg->channel & 0x3) << 6) | (msg->type & 0x3f); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci /* TODO: compute ECC if hardware support is not available */ 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci /* 55762306a36Sopenharmony_ci * Long write packets contain the word count in header bytes 1 and 2. 55862306a36Sopenharmony_ci * The payload follows the header and is word count bytes long. 55962306a36Sopenharmony_ci * 56062306a36Sopenharmony_ci * Short write packets encode up to two parameters in header bytes 1 56162306a36Sopenharmony_ci * and 2. 56262306a36Sopenharmony_ci */ 56362306a36Sopenharmony_ci if (mipi_dsi_packet_format_is_long(msg->type)) { 56462306a36Sopenharmony_ci packet->header[1] = (msg->tx_len >> 0) & 0xff; 56562306a36Sopenharmony_ci packet->header[2] = (msg->tx_len >> 8) & 0xff; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci packet->payload_length = msg->tx_len; 56862306a36Sopenharmony_ci packet->payload = msg->tx_buf; 56962306a36Sopenharmony_ci } else { 57062306a36Sopenharmony_ci const u8 *tx = msg->tx_buf; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci packet->header[1] = (msg->tx_len > 0) ? tx[0] : 0; 57362306a36Sopenharmony_ci packet->header[2] = (msg->tx_len > 1) ? tx[1] : 0; 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci packet->size = sizeof(packet->header) + packet->payload_length; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci return 0; 57962306a36Sopenharmony_ci} 58062306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_create_packet); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci/** 58362306a36Sopenharmony_ci * mipi_dsi_shutdown_peripheral() - sends a Shutdown Peripheral command 58462306a36Sopenharmony_ci * @dsi: DSI peripheral device 58562306a36Sopenharmony_ci * 58662306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 58762306a36Sopenharmony_ci */ 58862306a36Sopenharmony_ciint mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci struct mipi_dsi_msg msg = { 59162306a36Sopenharmony_ci .channel = dsi->channel, 59262306a36Sopenharmony_ci .type = MIPI_DSI_SHUTDOWN_PERIPHERAL, 59362306a36Sopenharmony_ci .tx_buf = (u8 [2]) { 0, 0 }, 59462306a36Sopenharmony_ci .tx_len = 2, 59562306a36Sopenharmony_ci }; 59662306a36Sopenharmony_ci int ret = mipi_dsi_device_transfer(dsi, &msg); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci return (ret < 0) ? ret : 0; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_shutdown_peripheral); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci/** 60362306a36Sopenharmony_ci * mipi_dsi_turn_on_peripheral() - sends a Turn On Peripheral command 60462306a36Sopenharmony_ci * @dsi: DSI peripheral device 60562306a36Sopenharmony_ci * 60662306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 60762306a36Sopenharmony_ci */ 60862306a36Sopenharmony_ciint mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci struct mipi_dsi_msg msg = { 61162306a36Sopenharmony_ci .channel = dsi->channel, 61262306a36Sopenharmony_ci .type = MIPI_DSI_TURN_ON_PERIPHERAL, 61362306a36Sopenharmony_ci .tx_buf = (u8 [2]) { 0, 0 }, 61462306a36Sopenharmony_ci .tx_len = 2, 61562306a36Sopenharmony_ci }; 61662306a36Sopenharmony_ci int ret = mipi_dsi_device_transfer(dsi, &msg); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci return (ret < 0) ? ret : 0; 61962306a36Sopenharmony_ci} 62062306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_turn_on_peripheral); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci/* 62362306a36Sopenharmony_ci * mipi_dsi_set_maximum_return_packet_size() - specify the maximum size of 62462306a36Sopenharmony_ci * the payload in a long packet transmitted from the peripheral back to the 62562306a36Sopenharmony_ci * host processor 62662306a36Sopenharmony_ci * @dsi: DSI peripheral device 62762306a36Sopenharmony_ci * @value: the maximum size of the payload 62862306a36Sopenharmony_ci * 62962306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 63062306a36Sopenharmony_ci */ 63162306a36Sopenharmony_ciint mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi, 63262306a36Sopenharmony_ci u16 value) 63362306a36Sopenharmony_ci{ 63462306a36Sopenharmony_ci u8 tx[2] = { value & 0xff, value >> 8 }; 63562306a36Sopenharmony_ci struct mipi_dsi_msg msg = { 63662306a36Sopenharmony_ci .channel = dsi->channel, 63762306a36Sopenharmony_ci .type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, 63862306a36Sopenharmony_ci .tx_len = sizeof(tx), 63962306a36Sopenharmony_ci .tx_buf = tx, 64062306a36Sopenharmony_ci }; 64162306a36Sopenharmony_ci int ret = mipi_dsi_device_transfer(dsi, &msg); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci return (ret < 0) ? ret : 0; 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_set_maximum_return_packet_size); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci/** 64862306a36Sopenharmony_ci * mipi_dsi_compression_mode() - enable/disable DSC on the peripheral 64962306a36Sopenharmony_ci * @dsi: DSI peripheral device 65062306a36Sopenharmony_ci * @enable: Whether to enable or disable the DSC 65162306a36Sopenharmony_ci * 65262306a36Sopenharmony_ci * Enable or disable Display Stream Compression on the peripheral using the 65362306a36Sopenharmony_ci * default Picture Parameter Set and VESA DSC 1.1 algorithm. 65462306a36Sopenharmony_ci * 65562306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 65662306a36Sopenharmony_ci */ 65762306a36Sopenharmony_cissize_t mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci /* Note: Needs updating for non-default PPS or algorithm */ 66062306a36Sopenharmony_ci u8 tx[2] = { enable << 0, 0 }; 66162306a36Sopenharmony_ci struct mipi_dsi_msg msg = { 66262306a36Sopenharmony_ci .channel = dsi->channel, 66362306a36Sopenharmony_ci .type = MIPI_DSI_COMPRESSION_MODE, 66462306a36Sopenharmony_ci .tx_len = sizeof(tx), 66562306a36Sopenharmony_ci .tx_buf = tx, 66662306a36Sopenharmony_ci }; 66762306a36Sopenharmony_ci int ret = mipi_dsi_device_transfer(dsi, &msg); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci return (ret < 0) ? ret : 0; 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_compression_mode); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci/** 67462306a36Sopenharmony_ci * mipi_dsi_picture_parameter_set() - transmit the DSC PPS to the peripheral 67562306a36Sopenharmony_ci * @dsi: DSI peripheral device 67662306a36Sopenharmony_ci * @pps: VESA DSC 1.1 Picture Parameter Set 67762306a36Sopenharmony_ci * 67862306a36Sopenharmony_ci * Transmit the VESA DSC 1.1 Picture Parameter Set to the peripheral. 67962306a36Sopenharmony_ci * 68062306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 68162306a36Sopenharmony_ci */ 68262306a36Sopenharmony_cissize_t mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi, 68362306a36Sopenharmony_ci const struct drm_dsc_picture_parameter_set *pps) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci struct mipi_dsi_msg msg = { 68662306a36Sopenharmony_ci .channel = dsi->channel, 68762306a36Sopenharmony_ci .type = MIPI_DSI_PICTURE_PARAMETER_SET, 68862306a36Sopenharmony_ci .tx_len = sizeof(*pps), 68962306a36Sopenharmony_ci .tx_buf = pps, 69062306a36Sopenharmony_ci }; 69162306a36Sopenharmony_ci int ret = mipi_dsi_device_transfer(dsi, &msg); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci return (ret < 0) ? ret : 0; 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_picture_parameter_set); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci/** 69862306a36Sopenharmony_ci * mipi_dsi_generic_write() - transmit data using a generic write packet 69962306a36Sopenharmony_ci * @dsi: DSI peripheral device 70062306a36Sopenharmony_ci * @payload: buffer containing the payload 70162306a36Sopenharmony_ci * @size: size of payload buffer 70262306a36Sopenharmony_ci * 70362306a36Sopenharmony_ci * This function will automatically choose the right data type depending on 70462306a36Sopenharmony_ci * the payload length. 70562306a36Sopenharmony_ci * 70662306a36Sopenharmony_ci * Return: The number of bytes transmitted on success or a negative error code 70762306a36Sopenharmony_ci * on failure. 70862306a36Sopenharmony_ci */ 70962306a36Sopenharmony_cissize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload, 71062306a36Sopenharmony_ci size_t size) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci struct mipi_dsi_msg msg = { 71362306a36Sopenharmony_ci .channel = dsi->channel, 71462306a36Sopenharmony_ci .tx_buf = payload, 71562306a36Sopenharmony_ci .tx_len = size 71662306a36Sopenharmony_ci }; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci switch (size) { 71962306a36Sopenharmony_ci case 0: 72062306a36Sopenharmony_ci msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM; 72162306a36Sopenharmony_ci break; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci case 1: 72462306a36Sopenharmony_ci msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM; 72562306a36Sopenharmony_ci break; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci case 2: 72862306a36Sopenharmony_ci msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM; 72962306a36Sopenharmony_ci break; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci default: 73262306a36Sopenharmony_ci msg.type = MIPI_DSI_GENERIC_LONG_WRITE; 73362306a36Sopenharmony_ci break; 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci return mipi_dsi_device_transfer(dsi, &msg); 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_generic_write); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci/** 74162306a36Sopenharmony_ci * mipi_dsi_generic_read() - receive data using a generic read packet 74262306a36Sopenharmony_ci * @dsi: DSI peripheral device 74362306a36Sopenharmony_ci * @params: buffer containing the request parameters 74462306a36Sopenharmony_ci * @num_params: number of request parameters 74562306a36Sopenharmony_ci * @data: buffer in which to return the received data 74662306a36Sopenharmony_ci * @size: size of receive buffer 74762306a36Sopenharmony_ci * 74862306a36Sopenharmony_ci * This function will automatically choose the right data type depending on 74962306a36Sopenharmony_ci * the number of parameters passed in. 75062306a36Sopenharmony_ci * 75162306a36Sopenharmony_ci * Return: The number of bytes successfully read or a negative error code on 75262306a36Sopenharmony_ci * failure. 75362306a36Sopenharmony_ci */ 75462306a36Sopenharmony_cissize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params, 75562306a36Sopenharmony_ci size_t num_params, void *data, size_t size) 75662306a36Sopenharmony_ci{ 75762306a36Sopenharmony_ci struct mipi_dsi_msg msg = { 75862306a36Sopenharmony_ci .channel = dsi->channel, 75962306a36Sopenharmony_ci .tx_len = num_params, 76062306a36Sopenharmony_ci .tx_buf = params, 76162306a36Sopenharmony_ci .rx_len = size, 76262306a36Sopenharmony_ci .rx_buf = data 76362306a36Sopenharmony_ci }; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci switch (num_params) { 76662306a36Sopenharmony_ci case 0: 76762306a36Sopenharmony_ci msg.type = MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM; 76862306a36Sopenharmony_ci break; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci case 1: 77162306a36Sopenharmony_ci msg.type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM; 77262306a36Sopenharmony_ci break; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci case 2: 77562306a36Sopenharmony_ci msg.type = MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM; 77662306a36Sopenharmony_ci break; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci default: 77962306a36Sopenharmony_ci return -EINVAL; 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci return mipi_dsi_device_transfer(dsi, &msg); 78362306a36Sopenharmony_ci} 78462306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_generic_read); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci/** 78762306a36Sopenharmony_ci * mipi_dsi_dcs_write_buffer() - transmit a DCS command with payload 78862306a36Sopenharmony_ci * @dsi: DSI peripheral device 78962306a36Sopenharmony_ci * @data: buffer containing data to be transmitted 79062306a36Sopenharmony_ci * @len: size of transmission buffer 79162306a36Sopenharmony_ci * 79262306a36Sopenharmony_ci * This function will automatically choose the right data type depending on 79362306a36Sopenharmony_ci * the command payload length. 79462306a36Sopenharmony_ci * 79562306a36Sopenharmony_ci * Return: The number of bytes successfully transmitted or a negative error 79662306a36Sopenharmony_ci * code on failure. 79762306a36Sopenharmony_ci */ 79862306a36Sopenharmony_cissize_t mipi_dsi_dcs_write_buffer(struct mipi_dsi_device *dsi, 79962306a36Sopenharmony_ci const void *data, size_t len) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci struct mipi_dsi_msg msg = { 80262306a36Sopenharmony_ci .channel = dsi->channel, 80362306a36Sopenharmony_ci .tx_buf = data, 80462306a36Sopenharmony_ci .tx_len = len 80562306a36Sopenharmony_ci }; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci switch (len) { 80862306a36Sopenharmony_ci case 0: 80962306a36Sopenharmony_ci return -EINVAL; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci case 1: 81262306a36Sopenharmony_ci msg.type = MIPI_DSI_DCS_SHORT_WRITE; 81362306a36Sopenharmony_ci break; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci case 2: 81662306a36Sopenharmony_ci msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM; 81762306a36Sopenharmony_ci break; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci default: 82062306a36Sopenharmony_ci msg.type = MIPI_DSI_DCS_LONG_WRITE; 82162306a36Sopenharmony_ci break; 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci return mipi_dsi_device_transfer(dsi, &msg); 82562306a36Sopenharmony_ci} 82662306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_dcs_write_buffer); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci/** 82962306a36Sopenharmony_ci * mipi_dsi_dcs_write() - send DCS write command 83062306a36Sopenharmony_ci * @dsi: DSI peripheral device 83162306a36Sopenharmony_ci * @cmd: DCS command 83262306a36Sopenharmony_ci * @data: buffer containing the command payload 83362306a36Sopenharmony_ci * @len: command payload length 83462306a36Sopenharmony_ci * 83562306a36Sopenharmony_ci * This function will automatically choose the right data type depending on 83662306a36Sopenharmony_ci * the command payload length. 83762306a36Sopenharmony_ci * 83862306a36Sopenharmony_ci * Return: The number of bytes successfully transmitted or a negative error 83962306a36Sopenharmony_ci * code on failure. 84062306a36Sopenharmony_ci */ 84162306a36Sopenharmony_cissize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd, 84262306a36Sopenharmony_ci const void *data, size_t len) 84362306a36Sopenharmony_ci{ 84462306a36Sopenharmony_ci ssize_t err; 84562306a36Sopenharmony_ci size_t size; 84662306a36Sopenharmony_ci u8 stack_tx[8]; 84762306a36Sopenharmony_ci u8 *tx; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci size = 1 + len; 85062306a36Sopenharmony_ci if (len > ARRAY_SIZE(stack_tx) - 1) { 85162306a36Sopenharmony_ci tx = kmalloc(size, GFP_KERNEL); 85262306a36Sopenharmony_ci if (!tx) 85362306a36Sopenharmony_ci return -ENOMEM; 85462306a36Sopenharmony_ci } else { 85562306a36Sopenharmony_ci tx = stack_tx; 85662306a36Sopenharmony_ci } 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci /* concatenate the DCS command byte and the payload */ 85962306a36Sopenharmony_ci tx[0] = cmd; 86062306a36Sopenharmony_ci if (data) 86162306a36Sopenharmony_ci memcpy(&tx[1], data, len); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci err = mipi_dsi_dcs_write_buffer(dsi, tx, size); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci if (tx != stack_tx) 86662306a36Sopenharmony_ci kfree(tx); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci return err; 86962306a36Sopenharmony_ci} 87062306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_dcs_write); 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci/** 87362306a36Sopenharmony_ci * mipi_dsi_dcs_read() - send DCS read request command 87462306a36Sopenharmony_ci * @dsi: DSI peripheral device 87562306a36Sopenharmony_ci * @cmd: DCS command 87662306a36Sopenharmony_ci * @data: buffer in which to receive data 87762306a36Sopenharmony_ci * @len: size of receive buffer 87862306a36Sopenharmony_ci * 87962306a36Sopenharmony_ci * Return: The number of bytes read or a negative error code on failure. 88062306a36Sopenharmony_ci */ 88162306a36Sopenharmony_cissize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data, 88262306a36Sopenharmony_ci size_t len) 88362306a36Sopenharmony_ci{ 88462306a36Sopenharmony_ci struct mipi_dsi_msg msg = { 88562306a36Sopenharmony_ci .channel = dsi->channel, 88662306a36Sopenharmony_ci .type = MIPI_DSI_DCS_READ, 88762306a36Sopenharmony_ci .tx_buf = &cmd, 88862306a36Sopenharmony_ci .tx_len = 1, 88962306a36Sopenharmony_ci .rx_buf = data, 89062306a36Sopenharmony_ci .rx_len = len 89162306a36Sopenharmony_ci }; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci return mipi_dsi_device_transfer(dsi, &msg); 89462306a36Sopenharmony_ci} 89562306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_dcs_read); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci/** 89862306a36Sopenharmony_ci * mipi_dsi_dcs_nop() - send DCS nop packet 89962306a36Sopenharmony_ci * @dsi: DSI peripheral device 90062306a36Sopenharmony_ci * 90162306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 90262306a36Sopenharmony_ci */ 90362306a36Sopenharmony_ciint mipi_dsi_dcs_nop(struct mipi_dsi_device *dsi) 90462306a36Sopenharmony_ci{ 90562306a36Sopenharmony_ci ssize_t err; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci err = mipi_dsi_dcs_write(dsi, MIPI_DCS_NOP, NULL, 0); 90862306a36Sopenharmony_ci if (err < 0) 90962306a36Sopenharmony_ci return err; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci return 0; 91262306a36Sopenharmony_ci} 91362306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_dcs_nop); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci/** 91662306a36Sopenharmony_ci * mipi_dsi_dcs_soft_reset() - perform a software reset of the display module 91762306a36Sopenharmony_ci * @dsi: DSI peripheral device 91862306a36Sopenharmony_ci * 91962306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 92062306a36Sopenharmony_ci */ 92162306a36Sopenharmony_ciint mipi_dsi_dcs_soft_reset(struct mipi_dsi_device *dsi) 92262306a36Sopenharmony_ci{ 92362306a36Sopenharmony_ci ssize_t err; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SOFT_RESET, NULL, 0); 92662306a36Sopenharmony_ci if (err < 0) 92762306a36Sopenharmony_ci return err; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci return 0; 93062306a36Sopenharmony_ci} 93162306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_dcs_soft_reset); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci/** 93462306a36Sopenharmony_ci * mipi_dsi_dcs_get_power_mode() - query the display module's current power 93562306a36Sopenharmony_ci * mode 93662306a36Sopenharmony_ci * @dsi: DSI peripheral device 93762306a36Sopenharmony_ci * @mode: return location for the current power mode 93862306a36Sopenharmony_ci * 93962306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 94062306a36Sopenharmony_ci */ 94162306a36Sopenharmony_ciint mipi_dsi_dcs_get_power_mode(struct mipi_dsi_device *dsi, u8 *mode) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci ssize_t err; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_POWER_MODE, mode, 94662306a36Sopenharmony_ci sizeof(*mode)); 94762306a36Sopenharmony_ci if (err <= 0) { 94862306a36Sopenharmony_ci if (err == 0) 94962306a36Sopenharmony_ci err = -ENODATA; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci return err; 95262306a36Sopenharmony_ci } 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci return 0; 95562306a36Sopenharmony_ci} 95662306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_dcs_get_power_mode); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci/** 95962306a36Sopenharmony_ci * mipi_dsi_dcs_get_pixel_format() - gets the pixel format for the RGB image 96062306a36Sopenharmony_ci * data used by the interface 96162306a36Sopenharmony_ci * @dsi: DSI peripheral device 96262306a36Sopenharmony_ci * @format: return location for the pixel format 96362306a36Sopenharmony_ci * 96462306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 96562306a36Sopenharmony_ci */ 96662306a36Sopenharmony_ciint mipi_dsi_dcs_get_pixel_format(struct mipi_dsi_device *dsi, u8 *format) 96762306a36Sopenharmony_ci{ 96862306a36Sopenharmony_ci ssize_t err; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_PIXEL_FORMAT, format, 97162306a36Sopenharmony_ci sizeof(*format)); 97262306a36Sopenharmony_ci if (err <= 0) { 97362306a36Sopenharmony_ci if (err == 0) 97462306a36Sopenharmony_ci err = -ENODATA; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci return err; 97762306a36Sopenharmony_ci } 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci return 0; 98062306a36Sopenharmony_ci} 98162306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_dcs_get_pixel_format); 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci/** 98462306a36Sopenharmony_ci * mipi_dsi_dcs_enter_sleep_mode() - disable all unnecessary blocks inside the 98562306a36Sopenharmony_ci * display module except interface communication 98662306a36Sopenharmony_ci * @dsi: DSI peripheral device 98762306a36Sopenharmony_ci * 98862306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 98962306a36Sopenharmony_ci */ 99062306a36Sopenharmony_ciint mipi_dsi_dcs_enter_sleep_mode(struct mipi_dsi_device *dsi) 99162306a36Sopenharmony_ci{ 99262306a36Sopenharmony_ci ssize_t err; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci err = mipi_dsi_dcs_write(dsi, MIPI_DCS_ENTER_SLEEP_MODE, NULL, 0); 99562306a36Sopenharmony_ci if (err < 0) 99662306a36Sopenharmony_ci return err; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci return 0; 99962306a36Sopenharmony_ci} 100062306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_dcs_enter_sleep_mode); 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci/** 100362306a36Sopenharmony_ci * mipi_dsi_dcs_exit_sleep_mode() - enable all blocks inside the display 100462306a36Sopenharmony_ci * module 100562306a36Sopenharmony_ci * @dsi: DSI peripheral device 100662306a36Sopenharmony_ci * 100762306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 100862306a36Sopenharmony_ci */ 100962306a36Sopenharmony_ciint mipi_dsi_dcs_exit_sleep_mode(struct mipi_dsi_device *dsi) 101062306a36Sopenharmony_ci{ 101162306a36Sopenharmony_ci ssize_t err; 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci err = mipi_dsi_dcs_write(dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0); 101462306a36Sopenharmony_ci if (err < 0) 101562306a36Sopenharmony_ci return err; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci return 0; 101862306a36Sopenharmony_ci} 101962306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_dcs_exit_sleep_mode); 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci/** 102262306a36Sopenharmony_ci * mipi_dsi_dcs_set_display_off() - stop displaying the image data on the 102362306a36Sopenharmony_ci * display device 102462306a36Sopenharmony_ci * @dsi: DSI peripheral device 102562306a36Sopenharmony_ci * 102662306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 102762306a36Sopenharmony_ci */ 102862306a36Sopenharmony_ciint mipi_dsi_dcs_set_display_off(struct mipi_dsi_device *dsi) 102962306a36Sopenharmony_ci{ 103062306a36Sopenharmony_ci ssize_t err; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_OFF, NULL, 0); 103362306a36Sopenharmony_ci if (err < 0) 103462306a36Sopenharmony_ci return err; 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci return 0; 103762306a36Sopenharmony_ci} 103862306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_dcs_set_display_off); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci/** 104162306a36Sopenharmony_ci * mipi_dsi_dcs_set_display_on() - start displaying the image data on the 104262306a36Sopenharmony_ci * display device 104362306a36Sopenharmony_ci * @dsi: DSI peripheral device 104462306a36Sopenharmony_ci * 104562306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure 104662306a36Sopenharmony_ci */ 104762306a36Sopenharmony_ciint mipi_dsi_dcs_set_display_on(struct mipi_dsi_device *dsi) 104862306a36Sopenharmony_ci{ 104962306a36Sopenharmony_ci ssize_t err; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0); 105262306a36Sopenharmony_ci if (err < 0) 105362306a36Sopenharmony_ci return err; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci return 0; 105662306a36Sopenharmony_ci} 105762306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_dcs_set_display_on); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci/** 106062306a36Sopenharmony_ci * mipi_dsi_dcs_set_column_address() - define the column extent of the frame 106162306a36Sopenharmony_ci * memory accessed by the host processor 106262306a36Sopenharmony_ci * @dsi: DSI peripheral device 106362306a36Sopenharmony_ci * @start: first column of frame memory 106462306a36Sopenharmony_ci * @end: last column of frame memory 106562306a36Sopenharmony_ci * 106662306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 106762306a36Sopenharmony_ci */ 106862306a36Sopenharmony_ciint mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start, 106962306a36Sopenharmony_ci u16 end) 107062306a36Sopenharmony_ci{ 107162306a36Sopenharmony_ci u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff }; 107262306a36Sopenharmony_ci ssize_t err; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_COLUMN_ADDRESS, payload, 107562306a36Sopenharmony_ci sizeof(payload)); 107662306a36Sopenharmony_ci if (err < 0) 107762306a36Sopenharmony_ci return err; 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci return 0; 108062306a36Sopenharmony_ci} 108162306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_dcs_set_column_address); 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci/** 108462306a36Sopenharmony_ci * mipi_dsi_dcs_set_page_address() - define the page extent of the frame 108562306a36Sopenharmony_ci * memory accessed by the host processor 108662306a36Sopenharmony_ci * @dsi: DSI peripheral device 108762306a36Sopenharmony_ci * @start: first page of frame memory 108862306a36Sopenharmony_ci * @end: last page of frame memory 108962306a36Sopenharmony_ci * 109062306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 109162306a36Sopenharmony_ci */ 109262306a36Sopenharmony_ciint mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start, 109362306a36Sopenharmony_ci u16 end) 109462306a36Sopenharmony_ci{ 109562306a36Sopenharmony_ci u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff }; 109662306a36Sopenharmony_ci ssize_t err; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PAGE_ADDRESS, payload, 109962306a36Sopenharmony_ci sizeof(payload)); 110062306a36Sopenharmony_ci if (err < 0) 110162306a36Sopenharmony_ci return err; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci return 0; 110462306a36Sopenharmony_ci} 110562306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_dcs_set_page_address); 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci/** 110862306a36Sopenharmony_ci * mipi_dsi_dcs_set_tear_off() - turn off the display module's Tearing Effect 110962306a36Sopenharmony_ci * output signal on the TE signal line 111062306a36Sopenharmony_ci * @dsi: DSI peripheral device 111162306a36Sopenharmony_ci * 111262306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure 111362306a36Sopenharmony_ci */ 111462306a36Sopenharmony_ciint mipi_dsi_dcs_set_tear_off(struct mipi_dsi_device *dsi) 111562306a36Sopenharmony_ci{ 111662306a36Sopenharmony_ci ssize_t err; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_OFF, NULL, 0); 111962306a36Sopenharmony_ci if (err < 0) 112062306a36Sopenharmony_ci return err; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci return 0; 112362306a36Sopenharmony_ci} 112462306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_dcs_set_tear_off); 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci/** 112762306a36Sopenharmony_ci * mipi_dsi_dcs_set_tear_on() - turn on the display module's Tearing Effect 112862306a36Sopenharmony_ci * output signal on the TE signal line. 112962306a36Sopenharmony_ci * @dsi: DSI peripheral device 113062306a36Sopenharmony_ci * @mode: the Tearing Effect Output Line mode 113162306a36Sopenharmony_ci * 113262306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure 113362306a36Sopenharmony_ci */ 113462306a36Sopenharmony_ciint mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi, 113562306a36Sopenharmony_ci enum mipi_dsi_dcs_tear_mode mode) 113662306a36Sopenharmony_ci{ 113762306a36Sopenharmony_ci u8 value = mode; 113862306a36Sopenharmony_ci ssize_t err; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_ON, &value, 114162306a36Sopenharmony_ci sizeof(value)); 114262306a36Sopenharmony_ci if (err < 0) 114362306a36Sopenharmony_ci return err; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci return 0; 114662306a36Sopenharmony_ci} 114762306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_dcs_set_tear_on); 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci/** 115062306a36Sopenharmony_ci * mipi_dsi_dcs_set_pixel_format() - sets the pixel format for the RGB image 115162306a36Sopenharmony_ci * data used by the interface 115262306a36Sopenharmony_ci * @dsi: DSI peripheral device 115362306a36Sopenharmony_ci * @format: pixel format 115462306a36Sopenharmony_ci * 115562306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 115662306a36Sopenharmony_ci */ 115762306a36Sopenharmony_ciint mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format) 115862306a36Sopenharmony_ci{ 115962306a36Sopenharmony_ci ssize_t err; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PIXEL_FORMAT, &format, 116262306a36Sopenharmony_ci sizeof(format)); 116362306a36Sopenharmony_ci if (err < 0) 116462306a36Sopenharmony_ci return err; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci return 0; 116762306a36Sopenharmony_ci} 116862306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_dcs_set_pixel_format); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci/** 117162306a36Sopenharmony_ci * mipi_dsi_dcs_set_tear_scanline() - set the scanline to use as trigger for 117262306a36Sopenharmony_ci * the Tearing Effect output signal of the display module 117362306a36Sopenharmony_ci * @dsi: DSI peripheral device 117462306a36Sopenharmony_ci * @scanline: scanline to use as trigger 117562306a36Sopenharmony_ci * 117662306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure 117762306a36Sopenharmony_ci */ 117862306a36Sopenharmony_ciint mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline) 117962306a36Sopenharmony_ci{ 118062306a36Sopenharmony_ci u8 payload[2] = { scanline >> 8, scanline & 0xff }; 118162306a36Sopenharmony_ci ssize_t err; 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_SCANLINE, payload, 118462306a36Sopenharmony_ci sizeof(payload)); 118562306a36Sopenharmony_ci if (err < 0) 118662306a36Sopenharmony_ci return err; 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci return 0; 118962306a36Sopenharmony_ci} 119062306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_dcs_set_tear_scanline); 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci/** 119362306a36Sopenharmony_ci * mipi_dsi_dcs_set_display_brightness() - sets the brightness value of the 119462306a36Sopenharmony_ci * display 119562306a36Sopenharmony_ci * @dsi: DSI peripheral device 119662306a36Sopenharmony_ci * @brightness: brightness value 119762306a36Sopenharmony_ci * 119862306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 119962306a36Sopenharmony_ci */ 120062306a36Sopenharmony_ciint mipi_dsi_dcs_set_display_brightness(struct mipi_dsi_device *dsi, 120162306a36Sopenharmony_ci u16 brightness) 120262306a36Sopenharmony_ci{ 120362306a36Sopenharmony_ci u8 payload[2] = { brightness & 0xff, brightness >> 8 }; 120462306a36Sopenharmony_ci ssize_t err; 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 120762306a36Sopenharmony_ci payload, sizeof(payload)); 120862306a36Sopenharmony_ci if (err < 0) 120962306a36Sopenharmony_ci return err; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci return 0; 121262306a36Sopenharmony_ci} 121362306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_dcs_set_display_brightness); 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci/** 121662306a36Sopenharmony_ci * mipi_dsi_dcs_get_display_brightness() - gets the current brightness value 121762306a36Sopenharmony_ci * of the display 121862306a36Sopenharmony_ci * @dsi: DSI peripheral device 121962306a36Sopenharmony_ci * @brightness: brightness value 122062306a36Sopenharmony_ci * 122162306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 122262306a36Sopenharmony_ci */ 122362306a36Sopenharmony_ciint mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi, 122462306a36Sopenharmony_ci u16 *brightness) 122562306a36Sopenharmony_ci{ 122662306a36Sopenharmony_ci ssize_t err; 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_DISPLAY_BRIGHTNESS, 122962306a36Sopenharmony_ci brightness, sizeof(*brightness)); 123062306a36Sopenharmony_ci if (err <= 0) { 123162306a36Sopenharmony_ci if (err == 0) 123262306a36Sopenharmony_ci err = -ENODATA; 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci return err; 123562306a36Sopenharmony_ci } 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci return 0; 123862306a36Sopenharmony_ci} 123962306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_dcs_get_display_brightness); 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci/** 124262306a36Sopenharmony_ci * mipi_dsi_dcs_set_display_brightness_large() - sets the 16-bit brightness value 124362306a36Sopenharmony_ci * of the display 124462306a36Sopenharmony_ci * @dsi: DSI peripheral device 124562306a36Sopenharmony_ci * @brightness: brightness value 124662306a36Sopenharmony_ci * 124762306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 124862306a36Sopenharmony_ci */ 124962306a36Sopenharmony_ciint mipi_dsi_dcs_set_display_brightness_large(struct mipi_dsi_device *dsi, 125062306a36Sopenharmony_ci u16 brightness) 125162306a36Sopenharmony_ci{ 125262306a36Sopenharmony_ci u8 payload[2] = { brightness >> 8, brightness & 0xff }; 125362306a36Sopenharmony_ci ssize_t err; 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 125662306a36Sopenharmony_ci payload, sizeof(payload)); 125762306a36Sopenharmony_ci if (err < 0) 125862306a36Sopenharmony_ci return err; 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci return 0; 126162306a36Sopenharmony_ci} 126262306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_dcs_set_display_brightness_large); 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci/** 126562306a36Sopenharmony_ci * mipi_dsi_dcs_get_display_brightness_large() - gets the current 16-bit 126662306a36Sopenharmony_ci * brightness value of the display 126762306a36Sopenharmony_ci * @dsi: DSI peripheral device 126862306a36Sopenharmony_ci * @brightness: brightness value 126962306a36Sopenharmony_ci * 127062306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 127162306a36Sopenharmony_ci */ 127262306a36Sopenharmony_ciint mipi_dsi_dcs_get_display_brightness_large(struct mipi_dsi_device *dsi, 127362306a36Sopenharmony_ci u16 *brightness) 127462306a36Sopenharmony_ci{ 127562306a36Sopenharmony_ci u8 brightness_be[2]; 127662306a36Sopenharmony_ci ssize_t err; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_DISPLAY_BRIGHTNESS, 127962306a36Sopenharmony_ci brightness_be, sizeof(brightness_be)); 128062306a36Sopenharmony_ci if (err <= 0) { 128162306a36Sopenharmony_ci if (err == 0) 128262306a36Sopenharmony_ci err = -ENODATA; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci return err; 128562306a36Sopenharmony_ci } 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci *brightness = (brightness_be[0] << 8) | brightness_be[1]; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci return 0; 129062306a36Sopenharmony_ci} 129162306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_dcs_get_display_brightness_large); 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_cistatic int mipi_dsi_drv_probe(struct device *dev) 129462306a36Sopenharmony_ci{ 129562306a36Sopenharmony_ci struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver); 129662306a36Sopenharmony_ci struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci return drv->probe(dsi); 129962306a36Sopenharmony_ci} 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_cistatic int mipi_dsi_drv_remove(struct device *dev) 130262306a36Sopenharmony_ci{ 130362306a36Sopenharmony_ci struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver); 130462306a36Sopenharmony_ci struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci drv->remove(dsi); 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci return 0; 130962306a36Sopenharmony_ci} 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_cistatic void mipi_dsi_drv_shutdown(struct device *dev) 131262306a36Sopenharmony_ci{ 131362306a36Sopenharmony_ci struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver); 131462306a36Sopenharmony_ci struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci drv->shutdown(dsi); 131762306a36Sopenharmony_ci} 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci/** 132062306a36Sopenharmony_ci * mipi_dsi_driver_register_full() - register a driver for DSI devices 132162306a36Sopenharmony_ci * @drv: DSI driver structure 132262306a36Sopenharmony_ci * @owner: owner module 132362306a36Sopenharmony_ci * 132462306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 132562306a36Sopenharmony_ci */ 132662306a36Sopenharmony_ciint mipi_dsi_driver_register_full(struct mipi_dsi_driver *drv, 132762306a36Sopenharmony_ci struct module *owner) 132862306a36Sopenharmony_ci{ 132962306a36Sopenharmony_ci drv->driver.bus = &mipi_dsi_bus_type; 133062306a36Sopenharmony_ci drv->driver.owner = owner; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci if (drv->probe) 133362306a36Sopenharmony_ci drv->driver.probe = mipi_dsi_drv_probe; 133462306a36Sopenharmony_ci if (drv->remove) 133562306a36Sopenharmony_ci drv->driver.remove = mipi_dsi_drv_remove; 133662306a36Sopenharmony_ci if (drv->shutdown) 133762306a36Sopenharmony_ci drv->driver.shutdown = mipi_dsi_drv_shutdown; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci return driver_register(&drv->driver); 134062306a36Sopenharmony_ci} 134162306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_driver_register_full); 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci/** 134462306a36Sopenharmony_ci * mipi_dsi_driver_unregister() - unregister a driver for DSI devices 134562306a36Sopenharmony_ci * @drv: DSI driver structure 134662306a36Sopenharmony_ci * 134762306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 134862306a36Sopenharmony_ci */ 134962306a36Sopenharmony_civoid mipi_dsi_driver_unregister(struct mipi_dsi_driver *drv) 135062306a36Sopenharmony_ci{ 135162306a36Sopenharmony_ci driver_unregister(&drv->driver); 135262306a36Sopenharmony_ci} 135362306a36Sopenharmony_ciEXPORT_SYMBOL(mipi_dsi_driver_unregister); 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_cistatic int __init mipi_dsi_bus_init(void) 135662306a36Sopenharmony_ci{ 135762306a36Sopenharmony_ci return bus_register(&mipi_dsi_bus_type); 135862306a36Sopenharmony_ci} 135962306a36Sopenharmony_cipostcore_initcall(mipi_dsi_bus_init); 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ciMODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>"); 136262306a36Sopenharmony_ciMODULE_DESCRIPTION("MIPI DSI Bus"); 136362306a36Sopenharmony_ciMODULE_LICENSE("GPL and additional rights"); 1364