1 /* 2 * MIPI DSI Bus 3 * 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 a 8 * copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation the rights to use, copy, modify, merge, publish, 11 * distribute, sub license, and/or sell copies of the Software, and to 12 * permit persons to whom the Software is furnished to do so, subject to 13 * the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the 16 * next paragraph) shall be included in all copies or substantial portions 17 * of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 22 * 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 OR 24 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 25 * USE OR OTHER DEALINGS IN THE SOFTWARE. 26 */ 27 28 #include <drm/drm_mipi_dsi.h> 29 30 #include <linux/device.h> 31 #include <linux/module.h> 32 #include <linux/of_device.h> 33 #include <linux/pm_runtime.h> 34 #include <linux/slab.h> 35 36 #include <video/mipi_display.h> 37 38 static int mipi_dsi_device_match(struct device *dev, struct device_driver *drv) 39 { 40 return of_driver_match_device(dev, drv); 41 } 42 43 static const struct dev_pm_ops mipi_dsi_device_pm_ops = { 44 .runtime_suspend = pm_generic_runtime_suspend, 45 .runtime_resume = pm_generic_runtime_resume, 46 .suspend = pm_generic_suspend, 47 .resume = pm_generic_resume, 48 .freeze = pm_generic_freeze, 49 .thaw = pm_generic_thaw, 50 .poweroff = pm_generic_poweroff, 51 .restore = pm_generic_restore, 52 }; 53 54 static struct bus_type mipi_dsi_bus_type = { 55 .name = "mipi-dsi", 56 .match = mipi_dsi_device_match, 57 .pm = &mipi_dsi_device_pm_ops, 58 }; 59 60 static void mipi_dsi_dev_release(struct device *dev) 61 { 62 struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); 63 64 of_node_put(dev->of_node); 65 kfree(dsi); 66 } 67 68 static const struct device_type mipi_dsi_device_type = { 69 .release = mipi_dsi_dev_release, 70 }; 71 72 static struct mipi_dsi_device *mipi_dsi_device_alloc(struct mipi_dsi_host *host) 73 { 74 struct mipi_dsi_device *dsi; 75 76 dsi = kzalloc(sizeof(*dsi), GFP_KERNEL); 77 if (!dsi) 78 return ERR_PTR(-ENOMEM); 79 80 dsi->host = host; 81 dsi->dev.bus = &mipi_dsi_bus_type; 82 dsi->dev.parent = host->dev; 83 dsi->dev.type = &mipi_dsi_device_type; 84 85 device_initialize(&dsi->dev); 86 87 return dsi; 88 } 89 90 static int mipi_dsi_device_add(struct mipi_dsi_device *dsi) 91 { 92 struct mipi_dsi_host *host = dsi->host; 93 94 dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), dsi->channel); 95 96 return device_add(&dsi->dev); 97 } 98 99 static struct mipi_dsi_device * 100 of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) 101 { 102 struct mipi_dsi_device *dsi; 103 struct device *dev = host->dev; 104 int ret; 105 u32 reg; 106 107 ret = of_property_read_u32(node, "reg", ®); 108 if (ret) { 109 dev_err(dev, "device node %s has no valid reg property: %d\n", 110 node->full_name, ret); 111 return ERR_PTR(-EINVAL); 112 } 113 114 if (reg > 3) { 115 dev_err(dev, "device node %s has invalid reg property: %u\n", 116 node->full_name, reg); 117 return ERR_PTR(-EINVAL); 118 } 119 120 dsi = mipi_dsi_device_alloc(host); 121 if (IS_ERR(dsi)) { 122 dev_err(dev, "failed to allocate DSI device %s: %ld\n", 123 node->full_name, PTR_ERR(dsi)); 124 return dsi; 125 } 126 127 dsi->dev.of_node = of_node_get(node); 128 dsi->channel = reg; 129 130 ret = mipi_dsi_device_add(dsi); 131 if (ret) { 132 dev_err(dev, "failed to add DSI device %s: %d\n", 133 node->full_name, ret); 134 kfree(dsi); 135 return ERR_PTR(ret); 136 } 137 138 return dsi; 139 } 140 141 int mipi_dsi_host_register(struct mipi_dsi_host *host) 142 { 143 struct device_node *node; 144 145 for_each_available_child_of_node(host->dev->of_node, node) { 146 /* skip nodes without reg property */ 147 if (!of_find_property(node, "reg", NULL)) 148 continue; 149 of_mipi_dsi_device_add(host, node); 150 } 151 152 return 0; 153 } 154 EXPORT_SYMBOL(mipi_dsi_host_register); 155 156 static int mipi_dsi_remove_device_fn(struct device *dev, void *priv) 157 { 158 struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); 159 160 device_unregister(&dsi->dev); 161 162 return 0; 163 } 164 165 void mipi_dsi_host_unregister(struct mipi_dsi_host *host) 166 { 167 device_for_each_child(host->dev, NULL, mipi_dsi_remove_device_fn); 168 } 169 EXPORT_SYMBOL(mipi_dsi_host_unregister); 170 171 /** 172 * mipi_dsi_attach - attach a DSI device to its DSI host 173 * @dsi: DSI peripheral 174 */ 175 int mipi_dsi_attach(struct mipi_dsi_device *dsi) 176 { 177 const struct mipi_dsi_host_ops *ops = dsi->host->ops; 178 179 if (!ops || !ops->attach) 180 return -ENOSYS; 181 182 return ops->attach(dsi->host, dsi); 183 } 184 EXPORT_SYMBOL(mipi_dsi_attach); 185 186 /** 187 * mipi_dsi_detach - detach a DSI device from its DSI host 188 * @dsi: DSI peripheral 189 */ 190 int mipi_dsi_detach(struct mipi_dsi_device *dsi) 191 { 192 const struct mipi_dsi_host_ops *ops = dsi->host->ops; 193 194 if (!ops || !ops->detach) 195 return -ENOSYS; 196 197 return ops->detach(dsi->host, dsi); 198 } 199 EXPORT_SYMBOL(mipi_dsi_detach); 200 201 /** 202 * mipi_dsi_dcs_write - send DCS write command 203 * @dsi: DSI device 204 * @data: pointer to the command followed by parameters 205 * @len: length of @data 206 */ 207 ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, const void *data, 208 size_t len) 209 { 210 const struct mipi_dsi_host_ops *ops = dsi->host->ops; 211 struct mipi_dsi_msg msg = { 212 .channel = dsi->channel, 213 .tx_buf = data, 214 .tx_len = len 215 }; 216 217 if (!ops || !ops->transfer) 218 return -ENOSYS; 219 220 switch (len) { 221 case 0: 222 return -EINVAL; 223 case 1: 224 msg.type = MIPI_DSI_DCS_SHORT_WRITE; 225 break; 226 case 2: 227 msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM; 228 break; 229 default: 230 msg.type = MIPI_DSI_DCS_LONG_WRITE; 231 break; 232 } 233 234 return ops->transfer(dsi->host, &msg); 235 } 236 EXPORT_SYMBOL(mipi_dsi_dcs_write); 237 238 /** 239 * mipi_dsi_dcs_read - send DCS read request command 240 * @dsi: DSI device 241 * @cmd: DCS read command 242 * @data: pointer to read buffer 243 * @len: length of @data 244 * 245 * Function returns number of read bytes or error code. 246 */ 247 ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data, 248 size_t len) 249 { 250 const struct mipi_dsi_host_ops *ops = dsi->host->ops; 251 struct mipi_dsi_msg msg = { 252 .channel = dsi->channel, 253 .type = MIPI_DSI_DCS_READ, 254 .tx_buf = &cmd, 255 .tx_len = 1, 256 .rx_buf = data, 257 .rx_len = len 258 }; 259 260 if (!ops || !ops->transfer) 261 return -ENOSYS; 262 263 return ops->transfer(dsi->host, &msg); 264 } 265 EXPORT_SYMBOL(mipi_dsi_dcs_read); 266 267 static int mipi_dsi_drv_probe(struct device *dev) 268 { 269 struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver); 270 struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); 271 272 return drv->probe(dsi); 273 } 274 275 static int mipi_dsi_drv_remove(struct device *dev) 276 { 277 struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver); 278 struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); 279 280 return drv->remove(dsi); 281 } 282 283 static void mipi_dsi_drv_shutdown(struct device *dev) 284 { 285 struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver); 286 struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); 287 288 drv->shutdown(dsi); 289 } 290 291 /** 292 * mipi_dsi_driver_register - register a driver for DSI devices 293 * @drv: DSI driver structure 294 */ 295 int mipi_dsi_driver_register(struct mipi_dsi_driver *drv) 296 { 297 drv->driver.bus = &mipi_dsi_bus_type; 298 if (drv->probe) 299 drv->driver.probe = mipi_dsi_drv_probe; 300 if (drv->remove) 301 drv->driver.remove = mipi_dsi_drv_remove; 302 if (drv->shutdown) 303 drv->driver.shutdown = mipi_dsi_drv_shutdown; 304 305 return driver_register(&drv->driver); 306 } 307 EXPORT_SYMBOL(mipi_dsi_driver_register); 308 309 /** 310 * mipi_dsi_driver_unregister - unregister a driver for DSI devices 311 * @drv: DSI driver structure 312 */ 313 void mipi_dsi_driver_unregister(struct mipi_dsi_driver *drv) 314 { 315 driver_unregister(&drv->driver); 316 } 317 EXPORT_SYMBOL(mipi_dsi_driver_unregister); 318 319 static int __init mipi_dsi_bus_init(void) 320 { 321 return bus_register(&mipi_dsi_bus_type); 322 } 323 postcore_initcall(mipi_dsi_bus_init); 324 325 MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>"); 326 MODULE_DESCRIPTION("MIPI DSI Bus"); 327 MODULE_LICENSE("GPL and additional rights"); 328