4 * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd.
5 * Andrzej Hajda <a.hajda@samsung.com>
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:
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
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.
28 #include <drm/drm_mipi_dsi.h>
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>
36 #include <video/mipi_display.h>
38 static int mipi_dsi_device_match(struct device
*dev
, struct device_driver
*drv
)
40 return of_driver_match_device(dev
, drv
);
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
,
54 static struct bus_type mipi_dsi_bus_type
= {
56 .match
= mipi_dsi_device_match
,
57 .pm
= &mipi_dsi_device_pm_ops
,
60 static void mipi_dsi_dev_release(struct device
*dev
)
62 struct mipi_dsi_device
*dsi
= to_mipi_dsi_device(dev
);
64 of_node_put(dev
->of_node
);
68 static const struct device_type mipi_dsi_device_type
= {
69 .release
= mipi_dsi_dev_release
,
72 static struct mipi_dsi_device
*mipi_dsi_device_alloc(struct mipi_dsi_host
*host
)
74 struct mipi_dsi_device
*dsi
;
76 dsi
= kzalloc(sizeof(*dsi
), GFP_KERNEL
);
78 return ERR_PTR(-ENOMEM
);
81 dsi
->dev
.bus
= &mipi_dsi_bus_type
;
82 dsi
->dev
.parent
= host
->dev
;
83 dsi
->dev
.type
= &mipi_dsi_device_type
;
85 device_initialize(&dsi
->dev
);
90 static int mipi_dsi_device_add(struct mipi_dsi_device
*dsi
)
92 struct mipi_dsi_host
*host
= dsi
->host
;
94 dev_set_name(&dsi
->dev
, "%s.%d", dev_name(host
->dev
), dsi
->channel
);
96 return device_add(&dsi
->dev
);
99 static struct mipi_dsi_device
*
100 of_mipi_dsi_device_add(struct mipi_dsi_host
*host
, struct device_node
*node
)
102 struct mipi_dsi_device
*dsi
;
103 struct device
*dev
= host
->dev
;
107 ret
= of_property_read_u32(node
, "reg", ®
);
109 dev_err(dev
, "device node %s has no valid reg property: %d\n",
110 node
->full_name
, ret
);
111 return ERR_PTR(-EINVAL
);
115 dev_err(dev
, "device node %s has invalid reg property: %u\n",
116 node
->full_name
, reg
);
117 return ERR_PTR(-EINVAL
);
120 dsi
= mipi_dsi_device_alloc(host
);
122 dev_err(dev
, "failed to allocate DSI device %s: %ld\n",
123 node
->full_name
, PTR_ERR(dsi
));
127 dsi
->dev
.of_node
= of_node_get(node
);
130 ret
= mipi_dsi_device_add(dsi
);
132 dev_err(dev
, "failed to add DSI device %s: %d\n",
133 node
->full_name
, ret
);
141 int mipi_dsi_host_register(struct mipi_dsi_host
*host
)
143 struct device_node
*node
;
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
))
149 of_mipi_dsi_device_add(host
, node
);
154 EXPORT_SYMBOL(mipi_dsi_host_register
);
156 static int mipi_dsi_remove_device_fn(struct device
*dev
, void *priv
)
158 struct mipi_dsi_device
*dsi
= to_mipi_dsi_device(dev
);
160 device_unregister(&dsi
->dev
);
165 void mipi_dsi_host_unregister(struct mipi_dsi_host
*host
)
167 device_for_each_child(host
->dev
, NULL
, mipi_dsi_remove_device_fn
);
169 EXPORT_SYMBOL(mipi_dsi_host_unregister
);
172 * mipi_dsi_attach - attach a DSI device to its DSI host
173 * @dsi: DSI peripheral
175 int mipi_dsi_attach(struct mipi_dsi_device
*dsi
)
177 const struct mipi_dsi_host_ops
*ops
= dsi
->host
->ops
;
179 if (!ops
|| !ops
->attach
)
182 return ops
->attach(dsi
->host
, dsi
);
184 EXPORT_SYMBOL(mipi_dsi_attach
);
187 * mipi_dsi_detach - detach a DSI device from its DSI host
188 * @dsi: DSI peripheral
190 int mipi_dsi_detach(struct mipi_dsi_device
*dsi
)
192 const struct mipi_dsi_host_ops
*ops
= dsi
->host
->ops
;
194 if (!ops
|| !ops
->detach
)
197 return ops
->detach(dsi
->host
, dsi
);
199 EXPORT_SYMBOL(mipi_dsi_detach
);
202 * mipi_dsi_dcs_write - send DCS write command
204 * @channel: virtual channel
205 * @data: pointer to the command followed by parameters
206 * @len: length of @data
208 int mipi_dsi_dcs_write(struct mipi_dsi_device
*dsi
, unsigned int channel
,
209 const void *data
, size_t len
)
211 const struct mipi_dsi_host_ops
*ops
= dsi
->host
->ops
;
212 struct mipi_dsi_msg msg
= {
218 if (!ops
|| !ops
->transfer
)
225 msg
.type
= MIPI_DSI_DCS_SHORT_WRITE
;
228 msg
.type
= MIPI_DSI_DCS_SHORT_WRITE_PARAM
;
231 msg
.type
= MIPI_DSI_DCS_LONG_WRITE
;
235 return ops
->transfer(dsi
->host
, &msg
);
237 EXPORT_SYMBOL(mipi_dsi_dcs_write
);
240 * mipi_dsi_dcs_read - send DCS read request command
242 * @channel: virtual channel
243 * @cmd: DCS read command
244 * @data: pointer to read buffer
245 * @len: length of @data
247 * Function returns number of read bytes or error code.
249 ssize_t
mipi_dsi_dcs_read(struct mipi_dsi_device
*dsi
, unsigned int channel
,
250 u8 cmd
, void *data
, size_t len
)
252 const struct mipi_dsi_host_ops
*ops
= dsi
->host
->ops
;
253 struct mipi_dsi_msg msg
= {
255 .type
= MIPI_DSI_DCS_READ
,
262 if (!ops
|| !ops
->transfer
)
265 return ops
->transfer(dsi
->host
, &msg
);
267 EXPORT_SYMBOL(mipi_dsi_dcs_read
);
269 static int mipi_dsi_drv_probe(struct device
*dev
)
271 struct mipi_dsi_driver
*drv
= to_mipi_dsi_driver(dev
->driver
);
272 struct mipi_dsi_device
*dsi
= to_mipi_dsi_device(dev
);
274 return drv
->probe(dsi
);
277 static int mipi_dsi_drv_remove(struct device
*dev
)
279 struct mipi_dsi_driver
*drv
= to_mipi_dsi_driver(dev
->driver
);
280 struct mipi_dsi_device
*dsi
= to_mipi_dsi_device(dev
);
282 return drv
->remove(dsi
);
286 * mipi_dsi_driver_register - register a driver for DSI devices
287 * @drv: DSI driver structure
289 int mipi_dsi_driver_register(struct mipi_dsi_driver
*drv
)
291 drv
->driver
.bus
= &mipi_dsi_bus_type
;
293 drv
->driver
.probe
= mipi_dsi_drv_probe
;
295 drv
->driver
.remove
= mipi_dsi_drv_remove
;
297 return driver_register(&drv
->driver
);
299 EXPORT_SYMBOL(mipi_dsi_driver_register
);
302 * mipi_dsi_driver_unregister - unregister a driver for DSI devices
303 * @drv: DSI driver structure
305 void mipi_dsi_driver_unregister(struct mipi_dsi_driver
*drv
)
307 driver_unregister(&drv
->driver
);
309 EXPORT_SYMBOL(mipi_dsi_driver_unregister
);
311 static int __init
mipi_dsi_bus_init(void)
313 return bus_register(&mipi_dsi_bus_type
);
315 postcore_initcall(mipi_dsi_bus_init
);
317 MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");
318 MODULE_DESCRIPTION("MIPI DSI Bus");
319 MODULE_LICENSE("GPL and additional rights");