2 * Generic MIPI DPI Panel Driver
4 * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
5 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
12 #include <linux/gpio/consumer.h>
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/slab.h>
17 #include <linux/regulator/consumer.h>
18 #include <linux/backlight.h>
20 #include <video/of_display_timing.h>
22 #include "../dss/omapdss.h"
24 struct panel_drv_data
{
25 struct omap_dss_device dssdev
;
26 struct omap_dss_device
*in
;
30 struct backlight_device
*backlight
;
32 struct gpio_desc
*enable_gpio
;
33 struct regulator
*vcc_supply
;
36 #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
38 static int panel_dpi_connect(struct omap_dss_device
*dssdev
)
40 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
41 struct omap_dss_device
*in
= ddata
->in
;
44 if (omapdss_device_is_connected(dssdev
))
47 r
= in
->ops
.dpi
->connect(in
, dssdev
);
54 static void panel_dpi_disconnect(struct omap_dss_device
*dssdev
)
56 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
57 struct omap_dss_device
*in
= ddata
->in
;
59 if (!omapdss_device_is_connected(dssdev
))
62 in
->ops
.dpi
->disconnect(in
, dssdev
);
65 static int panel_dpi_enable(struct omap_dss_device
*dssdev
)
67 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
68 struct omap_dss_device
*in
= ddata
->in
;
71 if (!omapdss_device_is_connected(dssdev
))
74 if (omapdss_device_is_enabled(dssdev
))
77 in
->ops
.dpi
->set_timings(in
, &ddata
->vm
);
79 r
= in
->ops
.dpi
->enable(in
);
83 r
= regulator_enable(ddata
->vcc_supply
);
85 in
->ops
.dpi
->disable(in
);
89 gpiod_set_value_cansleep(ddata
->enable_gpio
, 1);
90 backlight_enable(ddata
->backlight
);
92 dssdev
->state
= OMAP_DSS_DISPLAY_ACTIVE
;
97 static void panel_dpi_disable(struct omap_dss_device
*dssdev
)
99 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
100 struct omap_dss_device
*in
= ddata
->in
;
102 if (!omapdss_device_is_enabled(dssdev
))
105 backlight_disable(ddata
->backlight
);
107 gpiod_set_value_cansleep(ddata
->enable_gpio
, 0);
108 regulator_disable(ddata
->vcc_supply
);
110 in
->ops
.dpi
->disable(in
);
112 dssdev
->state
= OMAP_DSS_DISPLAY_DISABLED
;
115 static void panel_dpi_set_timings(struct omap_dss_device
*dssdev
,
116 struct videomode
*vm
)
118 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
119 struct omap_dss_device
*in
= ddata
->in
;
122 dssdev
->panel
.vm
= *vm
;
124 in
->ops
.dpi
->set_timings(in
, vm
);
127 static void panel_dpi_get_timings(struct omap_dss_device
*dssdev
,
128 struct videomode
*vm
)
130 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
135 static int panel_dpi_check_timings(struct omap_dss_device
*dssdev
,
136 struct videomode
*vm
)
138 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
139 struct omap_dss_device
*in
= ddata
->in
;
141 return in
->ops
.dpi
->check_timings(in
, vm
);
144 static struct omap_dss_driver panel_dpi_ops
= {
145 .connect
= panel_dpi_connect
,
146 .disconnect
= panel_dpi_disconnect
,
148 .enable
= panel_dpi_enable
,
149 .disable
= panel_dpi_disable
,
151 .set_timings
= panel_dpi_set_timings
,
152 .get_timings
= panel_dpi_get_timings
,
153 .check_timings
= panel_dpi_check_timings
,
156 static int panel_dpi_probe_of(struct platform_device
*pdev
)
158 struct panel_drv_data
*ddata
= platform_get_drvdata(pdev
);
159 struct device_node
*node
= pdev
->dev
.of_node
;
160 struct omap_dss_device
*in
;
162 struct display_timing timing
;
163 struct gpio_desc
*gpio
;
165 gpio
= devm_gpiod_get_optional(&pdev
->dev
, "enable", GPIOD_OUT_LOW
);
167 return PTR_ERR(gpio
);
169 ddata
->enable_gpio
= gpio
;
172 * Many different panels are supported by this driver and there are
173 * probably very different needs for their reset pins in regards to
174 * timing and order relative to the enable gpio. So for now it's just
175 * ensured that the reset line isn't active.
177 gpio
= devm_gpiod_get_optional(&pdev
->dev
, "reset", GPIOD_OUT_LOW
);
179 return PTR_ERR(gpio
);
181 ddata
->vcc_supply
= devm_regulator_get(&pdev
->dev
, "vcc");
182 if (IS_ERR(ddata
->vcc_supply
))
183 return PTR_ERR(ddata
->vcc_supply
);
185 ddata
->backlight
= devm_of_find_backlight(&pdev
->dev
);
187 if (IS_ERR(ddata
->backlight
))
188 return PTR_ERR(ddata
->backlight
);
190 r
= of_get_display_timing(node
, "panel-timing", &timing
);
192 dev_err(&pdev
->dev
, "failed to get video timing\n");
196 videomode_from_timing(&timing
, &ddata
->vm
);
198 in
= omapdss_of_find_source_for_first_ep(node
);
200 dev_err(&pdev
->dev
, "failed to find video source\n");
209 static int panel_dpi_probe(struct platform_device
*pdev
)
211 struct panel_drv_data
*ddata
;
212 struct omap_dss_device
*dssdev
;
215 if (!pdev
->dev
.of_node
)
218 ddata
= devm_kzalloc(&pdev
->dev
, sizeof(*ddata
), GFP_KERNEL
);
222 platform_set_drvdata(pdev
, ddata
);
224 r
= panel_dpi_probe_of(pdev
);
228 dssdev
= &ddata
->dssdev
;
229 dssdev
->dev
= &pdev
->dev
;
230 dssdev
->driver
= &panel_dpi_ops
;
231 dssdev
->type
= OMAP_DISPLAY_TYPE_DPI
;
232 dssdev
->owner
= THIS_MODULE
;
233 dssdev
->panel
.vm
= ddata
->vm
;
235 r
= omapdss_register_display(dssdev
);
237 dev_err(&pdev
->dev
, "Failed to register panel\n");
244 omap_dss_put_device(ddata
->in
);
248 static int __exit
panel_dpi_remove(struct platform_device
*pdev
)
250 struct panel_drv_data
*ddata
= platform_get_drvdata(pdev
);
251 struct omap_dss_device
*dssdev
= &ddata
->dssdev
;
252 struct omap_dss_device
*in
= ddata
->in
;
254 omapdss_unregister_display(dssdev
);
256 panel_dpi_disable(dssdev
);
257 panel_dpi_disconnect(dssdev
);
259 omap_dss_put_device(in
);
264 static const struct of_device_id panel_dpi_of_match
[] = {
265 { .compatible
= "omapdss,panel-dpi", },
269 MODULE_DEVICE_TABLE(of
, panel_dpi_of_match
);
271 static struct platform_driver panel_dpi_driver
= {
272 .probe
= panel_dpi_probe
,
273 .remove
= __exit_p(panel_dpi_remove
),
276 .of_match_table
= panel_dpi_of_match
,
277 .suppress_bind_attrs
= true,
281 module_platform_driver(panel_dpi_driver
);
283 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
284 MODULE_DESCRIPTION("Generic MIPI DPI Panel Driver");
285 MODULE_LICENSE("GPL");