1 // SPDX-License-Identifier: GPL-2.0-only
2 // SPDX-FileCopyrightText: 2020 Marian Cichy <M.Cichy@pengutronix.de>
4 #include <drm/drm_bridge.h>
5 #include <drm/drm_bridge_connector.h>
6 #include <drm/drm_client_setup.h>
7 #include <drm/drm_damage_helper.h>
8 #include <drm/drm_drv.h>
9 #include <drm/drm_fbdev_dma.h>
10 #include <drm/drm_fb_dma_helper.h>
11 #include <drm/drm_fourcc.h>
12 #include <drm/drm_framebuffer.h>
13 #include <drm/drm_gem_atomic_helper.h>
14 #include <drm/drm_gem_dma_helper.h>
15 #include <drm/drm_gem_framebuffer_helper.h>
16 #include <drm/drm_of.h>
17 #include <drm/drm_probe_helper.h>
18 #include <drm/drm_simple_kms_helper.h>
19 #include <drm/drm_vblank.h>
20 #include <linux/bitfield.h>
21 #include <linux/clk.h>
22 #include <linux/dma-mapping.h>
23 #include <linux/mod_devicetable.h>
24 #include <linux/module.h>
25 #include <linux/platform_device.h>
27 #define IMX21LCDC_LSSAR 0x0000 /* LCDC Screen Start Address Register */
28 #define IMX21LCDC_LSR 0x0004 /* LCDC Size Register */
29 #define IMX21LCDC_LVPWR 0x0008 /* LCDC Virtual Page Width Register */
30 #define IMX21LCDC_LCPR 0x000C /* LCDC Cursor Position Register */
31 #define IMX21LCDC_LCWHB 0x0010 /* LCDC Cursor Width Height and Blink Register*/
32 #define IMX21LCDC_LCCMR 0x0014 /* LCDC Color Cursor Mapping Register */
33 #define IMX21LCDC_LPCR 0x0018 /* LCDC Panel Configuration Register */
34 #define IMX21LCDC_LHCR 0x001C /* LCDC Horizontal Configuration Register */
35 #define IMX21LCDC_LVCR 0x0020 /* LCDC Vertical Configuration Register */
36 #define IMX21LCDC_LPOR 0x0024 /* LCDC Panning Offset Register */
37 #define IMX21LCDC_LSCR 0x0028 /* LCDC Sharp Configuration Register */
38 #define IMX21LCDC_LPCCR 0x002C /* LCDC PWM Contrast Control Register */
39 #define IMX21LCDC_LDCR 0x0030 /* LCDC DMA Control Register */
40 #define IMX21LCDC_LRMCR 0x0034 /* LCDC Refresh Mode Control Register */
41 #define IMX21LCDC_LICR 0x0038 /* LCDC Interrupt Configuration Register */
42 #define IMX21LCDC_LIER 0x003C /* LCDC Interrupt Enable Register */
43 #define IMX21LCDC_LISR 0x0040 /* LCDC Interrupt Status Register */
44 #define IMX21LCDC_LGWSAR 0x0050 /* LCDC Graphic Window Start Address Register */
45 #define IMX21LCDC_LGWSR 0x0054 /* LCDC Graph Window Size Register */
46 #define IMX21LCDC_LGWVPWR 0x0058 /* LCDC Graphic Window Virtual Page Width Register */
47 #define IMX21LCDC_LGWPOR 0x005C /* LCDC Graphic Window Panning Offset Register */
48 #define IMX21LCDC_LGWPR 0x0060 /* LCDC Graphic Window Position Register */
49 #define IMX21LCDC_LGWCR 0x0064 /* LCDC Graphic Window Control Register */
50 #define IMX21LCDC_LGWDCR 0x0068 /* LCDC Graphic Window DMA Control Register */
51 #define IMX21LCDC_LAUSCR 0x0080 /* LCDC AUS Mode Control Register */
52 #define IMX21LCDC_LAUSCCR 0x0084 /* LCDC AUS Mode Cursor Control Register */
53 #define IMX21LCDC_BGLUT 0x0800 /* Background Lookup Table */
54 #define IMX21LCDC_GWLUT 0x0C00 /* Graphic Window Lookup Table */
56 #define IMX21LCDC_LCPR_CC0 BIT(30) /* Cursor Control Bit 0 */
57 #define IMX21LCDC_LCPR_CC1 BIT(31) /* Cursor Control Bit 1 */
59 /* Values HSYNC, VSYNC and Framesize Register */
60 #define IMX21LCDC_LHCR_HWIDTH GENMASK(31, 26)
61 #define IMX21LCDC_LHCR_HFPORCH GENMASK(15, 8) /* H_WAIT_1 in the i.MX25 Reference manual */
62 #define IMX21LCDC_LHCR_HBPORCH GENMASK(7, 0) /* H_WAIT_2 in the i.MX25 Reference manual */
64 #define IMX21LCDC_LVCR_VWIDTH GENMASK(31, 26)
65 #define IMX21LCDC_LVCR_VFPORCH GENMASK(15, 8) /* V_WAIT_1 in the i.MX25 Reference manual */
66 #define IMX21LCDC_LVCR_VBPORCH GENMASK(7, 0) /* V_WAIT_2 in the i.MX25 Reference manual */
68 #define IMX21LCDC_LSR_XMAX GENMASK(25, 20)
69 #define IMX21LCDC_LSR_YMAX GENMASK(9, 0)
71 /* Values for LPCR Register */
72 #define IMX21LCDC_LPCR_PCD GENMASK(5, 0)
73 #define IMX21LCDC_LPCR_SHARP BIT(6)
74 #define IMX21LCDC_LPCR_SCLKSEL BIT(7)
75 #define IMX21LCDC_LPCR_ACD GENMASK(14, 8)
76 #define IMX21LCDC_LPCR_ACDSEL BIT(15)
77 #define IMX21LCDC_LPCR_REV_VS BIT(16)
78 #define IMX21LCDC_LPCR_SWAP_SEL BIT(17)
79 #define IMX21LCDC_LPCR_END_SEL BIT(18)
80 #define IMX21LCDC_LPCR_SCLKIDLE BIT(19)
81 #define IMX21LCDC_LPCR_OEPOL BIT(20)
82 #define IMX21LCDC_LPCR_CLKPOL BIT(21)
83 #define IMX21LCDC_LPCR_LPPOL BIT(22)
84 #define IMX21LCDC_LPCR_FLMPOL BIT(23)
85 #define IMX21LCDC_LPCR_PIXPOL BIT(24)
86 #define IMX21LCDC_LPCR_BPIX GENMASK(27, 25)
87 #define IMX21LCDC_LPCR_PBSIZ GENMASK(29, 28)
88 #define IMX21LCDC_LPCR_COLOR BIT(30)
89 #define IMX21LCDC_LPCR_TFT BIT(31)
91 #define INTR_EOF BIT(1) /* VBLANK Interrupt Bit */
93 #define BPP_RGB565 0x05
94 #define BPP_XRGB8888 0x07
96 #define LCDC_MIN_XRES 64
97 #define LCDC_MIN_YRES 64
99 #define LCDC_MAX_XRES 1024
100 #define LCDC_MAX_YRES 1024
103 struct drm_device drm
;
104 struct drm_simple_display_pipe pipe
;
105 struct drm_connector
*connector
;
113 static const u32 imx_lcdc_formats
[] = {
114 DRM_FORMAT_RGB565
, DRM_FORMAT_XRGB8888
,
117 static inline struct imx_lcdc
*imx_lcdc_from_drmdev(struct drm_device
*drm
)
119 return container_of(drm
, struct imx_lcdc
, drm
);
122 static unsigned int imx_lcdc_get_format(unsigned int drm_format
)
124 switch (drm_format
) {
126 DRM_WARN("Format not supported - fallback to XRGB8888\n");
129 case DRM_FORMAT_XRGB8888
:
132 case DRM_FORMAT_RGB565
:
137 static void imx_lcdc_update_hw_registers(struct drm_simple_display_pipe
*pipe
,
138 struct drm_plane_state
*old_state
,
141 struct drm_crtc
*crtc
= &pipe
->crtc
;
142 struct drm_plane_state
*new_state
= pipe
->plane
.state
;
143 struct drm_framebuffer
*fb
= new_state
->fb
;
144 struct imx_lcdc
*lcdc
= imx_lcdc_from_drmdev(pipe
->crtc
.dev
);
145 u32 lpcr
, lvcr
, lhcr
;
149 addr
= drm_fb_dma_get_gem_addr(fb
, new_state
, 0);
150 /* The LSSAR register specifies the LCD screen start address (SSA). */
151 writel(addr
, lcdc
->base
+ IMX21LCDC_LSSAR
);
156 /* Disable PER clock to make register write possible */
157 if (old_state
&& old_state
->crtc
&& old_state
->crtc
->enabled
)
158 clk_disable_unprepare(lcdc
->clk_per
);
161 framesize
= FIELD_PREP(IMX21LCDC_LSR_XMAX
, crtc
->mode
.hdisplay
>> 4) |
162 FIELD_PREP(IMX21LCDC_LSR_YMAX
, crtc
->mode
.vdisplay
);
163 writel(framesize
, lcdc
->base
+ IMX21LCDC_LSR
);
166 lhcr
= FIELD_PREP(IMX21LCDC_LHCR_HFPORCH
, crtc
->mode
.hsync_start
- crtc
->mode
.hdisplay
- 1) |
167 FIELD_PREP(IMX21LCDC_LHCR_HWIDTH
, crtc
->mode
.hsync_end
- crtc
->mode
.hsync_start
- 1) |
168 FIELD_PREP(IMX21LCDC_LHCR_HBPORCH
, crtc
->mode
.htotal
- crtc
->mode
.hsync_end
- 3);
169 writel(lhcr
, lcdc
->base
+ IMX21LCDC_LHCR
);
172 lvcr
= FIELD_PREP(IMX21LCDC_LVCR_VFPORCH
, crtc
->mode
.vsync_start
- crtc
->mode
.vdisplay
) |
173 FIELD_PREP(IMX21LCDC_LVCR_VWIDTH
, crtc
->mode
.vsync_end
- crtc
->mode
.vsync_start
) |
174 FIELD_PREP(IMX21LCDC_LVCR_VBPORCH
, crtc
->mode
.vtotal
- crtc
->mode
.vsync_end
);
175 writel(lvcr
, lcdc
->base
+ IMX21LCDC_LVCR
);
177 lpcr
= readl(lcdc
->base
+ IMX21LCDC_LPCR
);
178 lpcr
&= ~IMX21LCDC_LPCR_BPIX
;
179 lpcr
|= FIELD_PREP(IMX21LCDC_LPCR_BPIX
, imx_lcdc_get_format(fb
->format
->format
));
180 writel(lpcr
, lcdc
->base
+ IMX21LCDC_LPCR
);
182 /* Virtual Page Width */
183 writel(new_state
->fb
->pitches
[0] / 4, lcdc
->base
+ IMX21LCDC_LVPWR
);
185 /* Enable PER clock */
186 if (new_state
->crtc
->enabled
)
187 clk_prepare_enable(lcdc
->clk_per
);
190 static void imx_lcdc_pipe_enable(struct drm_simple_display_pipe
*pipe
,
191 struct drm_crtc_state
*crtc_state
,
192 struct drm_plane_state
*plane_state
)
197 struct imx_lcdc
*lcdc
= imx_lcdc_from_drmdev(pipe
->crtc
.dev
);
198 struct drm_display_mode
*mode
= &pipe
->crtc
.mode
;
199 struct drm_display_info
*disp_info
= &lcdc
->connector
->display_info
;
200 const int hsync_pol
= (mode
->flags
& DRM_MODE_FLAG_PHSYNC
) ? 0 : 1;
201 const int vsync_pol
= (mode
->flags
& DRM_MODE_FLAG_PVSYNC
) ? 0 : 1;
202 const int data_enable_pol
=
203 (disp_info
->bus_flags
& DRM_BUS_FLAG_DE_HIGH
) ? 0 : 1;
205 (disp_info
->bus_flags
& DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE
) ? 0 : 1;
207 clk_div
= DIV_ROUND_CLOSEST_ULL(clk_get_rate(lcdc
->clk_per
),
209 bpp
= imx_lcdc_get_format(plane_state
->fb
->format
->format
);
211 writel(FIELD_PREP(IMX21LCDC_LPCR_PCD
, clk_div
- 1) |
212 FIELD_PREP(IMX21LCDC_LPCR_LPPOL
, hsync_pol
) |
213 FIELD_PREP(IMX21LCDC_LPCR_FLMPOL
, vsync_pol
) |
214 FIELD_PREP(IMX21LCDC_LPCR_OEPOL
, data_enable_pol
) |
215 FIELD_PREP(IMX21LCDC_LPCR_TFT
, 1) |
216 FIELD_PREP(IMX21LCDC_LPCR_COLOR
, 1) |
217 FIELD_PREP(IMX21LCDC_LPCR_PBSIZ
, 3) |
218 FIELD_PREP(IMX21LCDC_LPCR_BPIX
, bpp
) |
219 FIELD_PREP(IMX21LCDC_LPCR_SCLKSEL
, 1) |
220 FIELD_PREP(IMX21LCDC_LPCR_PIXPOL
, 0) |
221 FIELD_PREP(IMX21LCDC_LPCR_CLKPOL
, clk_pol
),
222 lcdc
->base
+ IMX21LCDC_LPCR
);
224 /* 0px panning offset */
225 writel(0x00000000, lcdc
->base
+ IMX21LCDC_LPOR
);
227 /* disable hardware cursor */
228 writel(readl(lcdc
->base
+ IMX21LCDC_LCPR
) & ~(IMX21LCDC_LCPR_CC0
| IMX21LCDC_LCPR_CC1
),
229 lcdc
->base
+ IMX21LCDC_LCPR
);
231 ret
= clk_prepare_enable(lcdc
->clk_ipg
);
233 dev_err(pipe
->crtc
.dev
->dev
, "Cannot enable ipg clock: %pe\n", ERR_PTR(ret
));
236 ret
= clk_prepare_enable(lcdc
->clk_ahb
);
238 dev_err(pipe
->crtc
.dev
->dev
, "Cannot enable ahb clock: %pe\n", ERR_PTR(ret
));
240 clk_disable_unprepare(lcdc
->clk_ipg
);
245 imx_lcdc_update_hw_registers(pipe
, NULL
, true);
247 /* Enable VBLANK Interrupt */
248 writel(INTR_EOF
, lcdc
->base
+ IMX21LCDC_LIER
);
251 static void imx_lcdc_pipe_disable(struct drm_simple_display_pipe
*pipe
)
253 struct imx_lcdc
*lcdc
= imx_lcdc_from_drmdev(pipe
->crtc
.dev
);
254 struct drm_crtc
*crtc
= &lcdc
->pipe
.crtc
;
255 struct drm_pending_vblank_event
*event
;
257 clk_disable_unprepare(lcdc
->clk_ahb
);
258 clk_disable_unprepare(lcdc
->clk_ipg
);
260 if (pipe
->crtc
.enabled
)
261 clk_disable_unprepare(lcdc
->clk_per
);
263 spin_lock_irq(&lcdc
->drm
.event_lock
);
264 event
= crtc
->state
->event
;
266 crtc
->state
->event
= NULL
;
267 drm_crtc_send_vblank_event(crtc
, event
);
269 spin_unlock_irq(&lcdc
->drm
.event_lock
);
271 /* Disable VBLANK Interrupt */
272 writel(0, lcdc
->base
+ IMX21LCDC_LIER
);
275 static int imx_lcdc_pipe_check(struct drm_simple_display_pipe
*pipe
,
276 struct drm_plane_state
*plane_state
,
277 struct drm_crtc_state
*crtc_state
)
279 const struct drm_display_mode
*mode
= &crtc_state
->mode
;
280 const struct drm_display_mode
*old_mode
= &pipe
->crtc
.state
->mode
;
282 if (mode
->hdisplay
< LCDC_MIN_XRES
|| mode
->hdisplay
> LCDC_MAX_XRES
||
283 mode
->vdisplay
< LCDC_MIN_YRES
|| mode
->vdisplay
> LCDC_MAX_YRES
||
284 mode
->hdisplay
% 0x10) { /* must be multiple of 16 */
285 drm_err(pipe
->crtc
.dev
, "unsupported display mode (%u x %u)\n",
286 mode
->hdisplay
, mode
->vdisplay
);
290 crtc_state
->mode_changed
=
291 old_mode
->hdisplay
!= mode
->hdisplay
||
292 old_mode
->vdisplay
!= mode
->vdisplay
;
297 static void imx_lcdc_pipe_update(struct drm_simple_display_pipe
*pipe
,
298 struct drm_plane_state
*old_state
)
300 struct drm_crtc
*crtc
= &pipe
->crtc
;
301 struct drm_pending_vblank_event
*event
= crtc
->state
->event
;
302 struct drm_plane_state
*new_state
= pipe
->plane
.state
;
303 struct drm_framebuffer
*fb
= new_state
->fb
;
304 struct drm_framebuffer
*old_fb
= old_state
->fb
;
305 struct drm_crtc
*old_crtc
= old_state
->crtc
;
306 bool mode_changed
= false;
308 if (old_fb
&& old_fb
->format
!= fb
->format
)
310 else if (old_crtc
!= crtc
)
313 imx_lcdc_update_hw_registers(pipe
, old_state
, mode_changed
);
316 crtc
->state
->event
= NULL
;
318 spin_lock_irq(&crtc
->dev
->event_lock
);
320 if (crtc
->state
->active
&& drm_crtc_vblank_get(crtc
) == 0)
321 drm_crtc_arm_vblank_event(crtc
, event
);
323 drm_crtc_send_vblank_event(crtc
, event
);
325 spin_unlock_irq(&crtc
->dev
->event_lock
);
329 static const struct drm_simple_display_pipe_funcs imx_lcdc_pipe_funcs
= {
330 .enable
= imx_lcdc_pipe_enable
,
331 .disable
= imx_lcdc_pipe_disable
,
332 .check
= imx_lcdc_pipe_check
,
333 .update
= imx_lcdc_pipe_update
,
336 static const struct drm_mode_config_funcs imx_lcdc_mode_config_funcs
= {
337 .fb_create
= drm_gem_fb_create_with_dirty
,
338 .atomic_check
= drm_atomic_helper_check
,
339 .atomic_commit
= drm_atomic_helper_commit
,
342 static const struct drm_mode_config_helper_funcs imx_lcdc_mode_config_helpers
= {
343 .atomic_commit_tail
= drm_atomic_helper_commit_tail_rpm
,
346 DEFINE_DRM_GEM_DMA_FOPS(imx_lcdc_drm_fops
);
348 static struct drm_driver imx_lcdc_drm_driver
= {
349 .driver_features
= DRIVER_GEM
| DRIVER_MODESET
| DRIVER_ATOMIC
,
350 .fops
= &imx_lcdc_drm_fops
,
351 DRM_GEM_DMA_DRIVER_OPS_VMAP
,
352 DRM_FBDEV_DMA_DRIVER_OPS
,
354 .desc
= "i.MX LCDC driver",
358 static const struct of_device_id imx_lcdc_of_dev_id
[] = {
360 .compatible
= "fsl,imx21-lcdc",
363 .compatible
= "fsl,imx25-lcdc",
367 MODULE_DEVICE_TABLE(of
, imx_lcdc_of_dev_id
);
369 static irqreturn_t
imx_lcdc_irq_handler(int irq
, void *arg
)
371 struct imx_lcdc
*lcdc
= arg
;
372 struct drm_crtc
*crtc
= &lcdc
->pipe
.crtc
;
375 status
= readl(lcdc
->base
+ IMX21LCDC_LISR
);
377 if (status
& INTR_EOF
) {
378 drm_crtc_handle_vblank(crtc
);
385 static int imx_lcdc_probe(struct platform_device
*pdev
)
387 struct imx_lcdc
*lcdc
;
388 struct drm_device
*drm
;
389 struct drm_bridge
*bridge
;
392 struct device
*dev
= &pdev
->dev
;
394 lcdc
= devm_drm_dev_alloc(dev
, &imx_lcdc_drm_driver
,
395 struct imx_lcdc
, drm
);
397 return PTR_ERR(lcdc
);
401 lcdc
->base
= devm_platform_ioremap_resource(pdev
, 0);
402 if (IS_ERR(lcdc
->base
))
403 return dev_err_probe(dev
, PTR_ERR(lcdc
->base
), "Cannot get IO memory\n");
405 bridge
= devm_drm_of_get_bridge(dev
, dev
->of_node
, 0, 0);
407 return dev_err_probe(dev
, PTR_ERR(bridge
), "Failed to find bridge\n");
410 lcdc
->clk_ipg
= devm_clk_get(dev
, "ipg");
411 if (IS_ERR(lcdc
->clk_ipg
))
412 return dev_err_probe(dev
, PTR_ERR(lcdc
->clk_ipg
), "Failed to get %s clk\n", "ipg");
414 lcdc
->clk_ahb
= devm_clk_get(dev
, "ahb");
415 if (IS_ERR(lcdc
->clk_ahb
))
416 return dev_err_probe(dev
, PTR_ERR(lcdc
->clk_ahb
), "Failed to get %s clk\n", "ahb");
418 lcdc
->clk_per
= devm_clk_get(dev
, "per");
419 if (IS_ERR(lcdc
->clk_per
))
420 return dev_err_probe(dev
, PTR_ERR(lcdc
->clk_per
), "Failed to get %s clk\n", "per");
422 ret
= dma_set_mask_and_coherent(drm
->dev
, DMA_BIT_MASK(32));
424 return dev_err_probe(dev
, ret
, "Cannot set DMA Mask\n");
427 ret
= drmm_mode_config_init(drm
);
429 return dev_err_probe(dev
, ret
, "Cannot initialize mode configuration structure\n");
431 /* CRTC, Plane, Encoder */
432 ret
= drm_simple_display_pipe_init(drm
, &lcdc
->pipe
,
433 &imx_lcdc_pipe_funcs
,
435 ARRAY_SIZE(imx_lcdc_formats
), NULL
, NULL
);
437 return dev_err_probe(drm
->dev
, ret
, "Cannot setup simple display pipe\n");
439 ret
= drm_vblank_init(drm
, drm
->mode_config
.num_crtc
);
441 return dev_err_probe(drm
->dev
, ret
, "Failed to initialize vblank\n");
443 ret
= drm_bridge_attach(&lcdc
->pipe
.encoder
, bridge
, NULL
, DRM_BRIDGE_ATTACH_NO_CONNECTOR
);
445 return dev_err_probe(drm
->dev
, ret
, "Cannot attach bridge\n");
447 lcdc
->connector
= drm_bridge_connector_init(drm
, &lcdc
->pipe
.encoder
);
448 if (IS_ERR(lcdc
->connector
))
449 return dev_err_probe(drm
->dev
, PTR_ERR(lcdc
->connector
), "Cannot init bridge connector\n");
451 drm_connector_attach_encoder(lcdc
->connector
, &lcdc
->pipe
.encoder
);
454 * The LCDC controller does not have an enable bit. The
455 * controller starts directly when the clocks are enabled.
456 * If the clocks are enabled when the controller is not yet
457 * programmed with proper register values (enabled at the
458 * bootloader, for example) then it just goes into some undefined
460 * To avoid this issue, let's enable and disable LCDC IPG,
461 * PER and AHB clock so that we force some kind of 'reset'
465 ret
= clk_prepare_enable(lcdc
->clk_ipg
);
467 return dev_err_probe(dev
, ret
, "Cannot enable ipg clock\n");
468 clk_disable_unprepare(lcdc
->clk_ipg
);
470 ret
= clk_prepare_enable(lcdc
->clk_per
);
472 return dev_err_probe(dev
, ret
, "Cannot enable per clock\n");
473 clk_disable_unprepare(lcdc
->clk_per
);
475 ret
= clk_prepare_enable(lcdc
->clk_ahb
);
477 return dev_err_probe(dev
, ret
, "Cannot enable ahb clock\n");
478 clk_disable_unprepare(lcdc
->clk_ahb
);
480 drm
->mode_config
.min_width
= LCDC_MIN_XRES
;
481 drm
->mode_config
.max_width
= LCDC_MAX_XRES
;
482 drm
->mode_config
.min_height
= LCDC_MIN_YRES
;
483 drm
->mode_config
.max_height
= LCDC_MAX_YRES
;
484 drm
->mode_config
.preferred_depth
= 16;
485 drm
->mode_config
.funcs
= &imx_lcdc_mode_config_funcs
;
486 drm
->mode_config
.helper_private
= &imx_lcdc_mode_config_helpers
;
488 drm_mode_config_reset(drm
);
490 irq
= platform_get_irq(pdev
, 0);
496 ret
= devm_request_irq(dev
, irq
, imx_lcdc_irq_handler
, 0, "imx-lcdc", lcdc
);
498 return dev_err_probe(drm
->dev
, ret
, "Failed to install IRQ handler\n");
500 platform_set_drvdata(pdev
, drm
);
502 ret
= drm_dev_register(&lcdc
->drm
, 0);
504 return dev_err_probe(dev
, ret
, "Cannot register device\n");
506 drm_client_setup(drm
, NULL
);
511 static void imx_lcdc_remove(struct platform_device
*pdev
)
513 struct drm_device
*drm
= platform_get_drvdata(pdev
);
515 drm_dev_unregister(drm
);
516 drm_atomic_helper_shutdown(drm
);
519 static void imx_lcdc_shutdown(struct platform_device
*pdev
)
521 drm_atomic_helper_shutdown(platform_get_drvdata(pdev
));
524 static struct platform_driver imx_lcdc_driver
= {
527 .of_match_table
= imx_lcdc_of_dev_id
,
529 .probe
= imx_lcdc_probe
,
530 .remove
= imx_lcdc_remove
,
531 .shutdown
= imx_lcdc_shutdown
,
533 module_platform_driver(imx_lcdc_driver
);
535 MODULE_AUTHOR("Marian Cichy <M.Cichy@pengutronix.de>");
536 MODULE_DESCRIPTION("Freescale i.MX LCDC driver");
537 MODULE_LICENSE("GPL");