imx-drm: imx-drm-core: provide common connector and encoder cleanup functions
[deliverable/linux.git] / drivers / staging / imx-drm / parallel-display.c
CommitLineData
19022aaa
SH
1/*
2 * i.MX drm driver - parallel display implementation
3 *
4 * Copyright (C) 2012 Sascha Hauer, Pengutronix
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1301, USA.
19 */
20
17b5001b 21#include <linux/component.h>
19022aaa
SH
22#include <linux/module.h>
23#include <drm/drmP.h>
24#include <drm/drm_fb_helper.h>
25#include <drm/drm_crtc_helper.h>
26#include <linux/videodev2.h>
075c457b 27#include <video/of_display_timing.h>
19022aaa
SH
28
29#include "imx-drm.h"
30
31#define con_to_imxpd(x) container_of(x, struct imx_parallel_display, connector)
32#define enc_to_imxpd(x) container_of(x, struct imx_parallel_display, encoder)
33
34struct imx_parallel_display {
35 struct drm_connector connector;
36 struct imx_drm_connector *imx_drm_connector;
37 struct drm_encoder encoder;
38 struct imx_drm_encoder *imx_drm_encoder;
39 struct device *dev;
40 void *edid;
41 int edid_len;
42 u32 interface_pix_fmt;
43 int mode_valid;
44 struct drm_display_mode mode;
45};
46
47static enum drm_connector_status imx_pd_connector_detect(
48 struct drm_connector *connector, bool force)
49{
50 return connector_status_connected;
51}
52
53static void imx_pd_connector_destroy(struct drm_connector *connector)
54{
55 /* do not free here */
56}
57
58static int imx_pd_connector_get_modes(struct drm_connector *connector)
59{
60 struct imx_parallel_display *imxpd = con_to_imxpd(connector);
afb12edf 61 struct device_node *np = imxpd->dev->of_node;
19022aaa
SH
62 int num_modes = 0;
63
64 if (imxpd->edid) {
65 drm_mode_connector_update_edid_property(connector, imxpd->edid);
66 num_modes = drm_add_edid_modes(connector, imxpd->edid);
67 }
68
69 if (imxpd->mode_valid) {
70 struct drm_display_mode *mode = drm_mode_create(connector->dev);
71 drm_mode_copy(mode, &imxpd->mode);
72 mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
afb12edf
MV
73 drm_mode_probed_add(connector, mode);
74 num_modes++;
75 }
76
77 if (np) {
78 struct drm_display_mode *mode = drm_mode_create(connector->dev);
075c457b 79 of_get_drm_display_mode(np, &imxpd->mode, OF_USE_NATIVE_MODE);
afb12edf
MV
80 drm_mode_copy(mode, &imxpd->mode);
81 mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
19022aaa
SH
82 drm_mode_probed_add(connector, mode);
83 num_modes++;
84 }
85
86 return num_modes;
87}
88
19022aaa
SH
89static struct drm_encoder *imx_pd_connector_best_encoder(
90 struct drm_connector *connector)
91{
92 struct imx_parallel_display *imxpd = con_to_imxpd(connector);
93
94 return &imxpd->encoder;
95}
96
97static void imx_pd_encoder_dpms(struct drm_encoder *encoder, int mode)
98{
99}
100
101static bool imx_pd_encoder_mode_fixup(struct drm_encoder *encoder,
102 const struct drm_display_mode *mode,
103 struct drm_display_mode *adjusted_mode)
104{
105 return true;
106}
107
108static void imx_pd_encoder_prepare(struct drm_encoder *encoder)
109{
110 struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
111
f2d66aad 112 imx_drm_panel_format(encoder, imxpd->interface_pix_fmt);
19022aaa
SH
113}
114
115static void imx_pd_encoder_commit(struct drm_encoder *encoder)
116{
117}
118
119static void imx_pd_encoder_mode_set(struct drm_encoder *encoder,
120 struct drm_display_mode *mode,
121 struct drm_display_mode *adjusted_mode)
122{
123}
124
125static void imx_pd_encoder_disable(struct drm_encoder *encoder)
126{
127}
128
129static void imx_pd_encoder_destroy(struct drm_encoder *encoder)
130{
131 /* do not free here */
132}
133
134static struct drm_connector_funcs imx_pd_connector_funcs = {
135 .dpms = drm_helper_connector_dpms,
136 .fill_modes = drm_helper_probe_single_connector_modes,
137 .detect = imx_pd_connector_detect,
138 .destroy = imx_pd_connector_destroy,
139};
140
141static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
142 .get_modes = imx_pd_connector_get_modes,
143 .best_encoder = imx_pd_connector_best_encoder,
baa68c4b 144 .mode_valid = imx_drm_connector_mode_valid,
19022aaa
SH
145};
146
147static struct drm_encoder_funcs imx_pd_encoder_funcs = {
148 .destroy = imx_pd_encoder_destroy,
149};
150
151static struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = {
152 .dpms = imx_pd_encoder_dpms,
153 .mode_fixup = imx_pd_encoder_mode_fixup,
154 .prepare = imx_pd_encoder_prepare,
155 .commit = imx_pd_encoder_commit,
156 .mode_set = imx_pd_encoder_mode_set,
157 .disable = imx_pd_encoder_disable,
158};
159
160static int imx_pd_register(struct imx_parallel_display *imxpd)
161{
162 int ret;
163
164 drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder);
165
166 imxpd->connector.funcs = &imx_pd_connector_funcs;
167 imxpd->encoder.funcs = &imx_pd_encoder_funcs;
168
169 imxpd->encoder.encoder_type = DRM_MODE_ENCODER_NONE;
170 imxpd->connector.connector_type = DRM_MODE_CONNECTOR_VGA;
171
172 drm_encoder_helper_add(&imxpd->encoder, &imx_pd_encoder_helper_funcs);
173 ret = imx_drm_add_encoder(&imxpd->encoder, &imxpd->imx_drm_encoder,
174 THIS_MODULE);
175 if (ret) {
176 dev_err(imxpd->dev, "adding encoder failed with %d\n", ret);
177 return ret;
178 }
179
180 drm_connector_helper_add(&imxpd->connector,
181 &imx_pd_connector_helper_funcs);
182
183 ret = imx_drm_add_connector(&imxpd->connector,
184 &imxpd->imx_drm_connector, THIS_MODULE);
185 if (ret) {
186 imx_drm_remove_encoder(imxpd->imx_drm_encoder);
187 dev_err(imxpd->dev, "adding connector failed with %d\n", ret);
188 return ret;
189 }
190
191 imxpd->connector.encoder = &imxpd->encoder;
192
193 return 0;
194}
195
17b5001b 196static int imx_pd_bind(struct device *dev, struct device *master, void *data)
19022aaa 197{
17b5001b 198 struct device_node *np = dev->of_node;
19022aaa
SH
199 const u8 *edidp;
200 struct imx_parallel_display *imxpd;
201 int ret;
202 const char *fmt;
203
17b5001b 204 imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL);
19022aaa
SH
205 if (!imxpd)
206 return -ENOMEM;
207
208 edidp = of_get_property(np, "edid", &imxpd->edid_len);
209 if (edidp)
210 imxpd->edid = kmemdup(edidp, imxpd->edid_len, GFP_KERNEL);
211
212 ret = of_property_read_string(np, "interface-pix-fmt", &fmt);
213 if (!ret) {
214 if (!strcmp(fmt, "rgb24"))
215 imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB24;
216 else if (!strcmp(fmt, "rgb565"))
217 imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB565;
7d0a66c0
MV
218 else if (!strcmp(fmt, "bgr666"))
219 imxpd->interface_pix_fmt = V4L2_PIX_FMT_BGR666;
19022aaa
SH
220 }
221
17b5001b 222 imxpd->dev = dev;
19022aaa
SH
223
224 ret = imx_pd_register(imxpd);
225 if (ret)
226 return ret;
227
228 ret = imx_drm_encoder_add_possible_crtcs(imxpd->imx_drm_encoder, np);
229
17b5001b 230 dev_set_drvdata(dev, imxpd);
19022aaa
SH
231
232 return 0;
233}
234
17b5001b
RK
235static void imx_pd_unbind(struct device *dev, struct device *master,
236 void *data)
19022aaa 237{
17b5001b 238 struct imx_parallel_display *imxpd = dev_get_drvdata(dev);
19022aaa
SH
239 struct drm_connector *connector = &imxpd->connector;
240 struct drm_encoder *encoder = &imxpd->encoder;
241
242 drm_mode_connector_detach_encoder(connector, encoder);
243
244 imx_drm_remove_connector(imxpd->imx_drm_connector);
245 imx_drm_remove_encoder(imxpd->imx_drm_encoder);
17b5001b 246}
19022aaa 247
17b5001b
RK
248static const struct component_ops imx_pd_ops = {
249 .bind = imx_pd_bind,
250 .unbind = imx_pd_unbind,
251};
252
253static int imx_pd_probe(struct platform_device *pdev)
254{
255 return component_add(&pdev->dev, &imx_pd_ops);
256}
257
258static int imx_pd_remove(struct platform_device *pdev)
259{
260 component_del(&pdev->dev, &imx_pd_ops);
19022aaa
SH
261 return 0;
262}
263
264static const struct of_device_id imx_pd_dt_ids[] = {
265 { .compatible = "fsl,imx-parallel-display", },
266 { /* sentinel */ }
267};
fa45f2c7 268MODULE_DEVICE_TABLE(of, imx_pd_dt_ids);
19022aaa
SH
269
270static struct platform_driver imx_pd_driver = {
271 .probe = imx_pd_probe,
99c28f10 272 .remove = imx_pd_remove,
19022aaa
SH
273 .driver = {
274 .of_match_table = imx_pd_dt_ids,
275 .name = "imx-parallel-display",
276 .owner = THIS_MODULE,
277 },
278};
279
280module_platform_driver(imx_pd_driver);
281
282MODULE_DESCRIPTION("i.MX parallel display driver");
283MODULE_AUTHOR("Sascha Hauer, Pengutronix");
284MODULE_LICENSE("GPL");
b2da05ff 285MODULE_ALIAS("platform:imx-parallel-display");
This page took 0.195094 seconds and 5 git commands to generate.