diff options
author | Thierry Reding <treding@nvidia.com> | 2014-08-01 08:26:35 -0400 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2014-11-13 07:56:19 -0500 |
commit | 1976dbca047ed73888f9e7a533df899e961e1dc0 (patch) | |
tree | e6446bf77a407242d9e95a8bbe0ee0b420e8e983 | |
parent | 99035e99310a5e779b0b8f44c7d3f5814fd2ec9c (diff) |
drm/panel: Add Sharp LQ101R1SX01 support
This panel requires dual-channel mode. The device accepts command-mode
data on 8 lanes and will therefore need a dual-channel DSI controller.
The two interfaces that make up this device need to be instantiated in
the controllers that gang up to provide the dual-channel DSI host.
Reviewed-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r-- | Documentation/devicetree/bindings/panel/sharp,lq101r1sx01.txt | 49 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/Kconfig | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c | 464 |
4 files changed, 527 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/panel/sharp,lq101r1sx01.txt b/Documentation/devicetree/bindings/panel/sharp,lq101r1sx01.txt new file mode 100644 index 000000000000..f522bb8e47e1 --- /dev/null +++ b/Documentation/devicetree/bindings/panel/sharp,lq101r1sx01.txt | |||
@@ -0,0 +1,49 @@ | |||
1 | Sharp Microelectronics 10.1" WQXGA TFT LCD panel | ||
2 | |||
3 | This panel requires a dual-channel DSI host to operate. It supports two modes: | ||
4 | - left-right: each channel drives the left or right half of the screen | ||
5 | - even-odd: each channel drives the even or odd lines of the screen | ||
6 | |||
7 | Each of the DSI channels controls a separate DSI peripheral. The peripheral | ||
8 | driven by the first link (DSI-LINK1), left or even, is considered the primary | ||
9 | peripheral and controls the device. The 'link2' property contains a phandle | ||
10 | to the peripheral driven by the second link (DSI-LINK2, right or odd). | ||
11 | |||
12 | Note that in video mode the DSI-LINK1 interface always provides the left/even | ||
13 | pixels and DSI-LINK2 always provides the right/odd pixels. In command mode it | ||
14 | is possible to program either link to drive the left/even or right/odd pixels | ||
15 | but for the sake of consistency this binding assumes that the same assignment | ||
16 | is chosen as for video mode. | ||
17 | |||
18 | Required properties: | ||
19 | - compatible: should be "sharp,lq101r1sx01" | ||
20 | - reg: DSI virtual channel of the peripheral | ||
21 | |||
22 | Required properties (for DSI-LINK1 only): | ||
23 | - link2: phandle to the DSI peripheral on the secondary link. Note that the | ||
24 | presence of this property marks the containing node as DSI-LINK1. | ||
25 | - power-supply: phandle of the regulator that provides the supply voltage | ||
26 | |||
27 | Optional properties (for DSI-LINK1 only): | ||
28 | - backlight: phandle of the backlight device attached to the panel | ||
29 | |||
30 | Example: | ||
31 | |||
32 | dsi@54300000 { | ||
33 | panel: panel@0 { | ||
34 | compatible = "sharp,lq101r1sx01"; | ||
35 | reg = <0>; | ||
36 | |||
37 | link2 = <&secondary>; | ||
38 | |||
39 | power-supply = <...>; | ||
40 | backlight = <...>; | ||
41 | }; | ||
42 | }; | ||
43 | |||
44 | dsi@54400000 { | ||
45 | secondary: panel@0 { | ||
46 | compatible = "sharp,lq101r1sx01"; | ||
47 | reg = <0>; | ||
48 | }; | ||
49 | }; | ||
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index bee9f72b3a93..024e98ef8e4d 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig | |||
@@ -27,4 +27,17 @@ config DRM_PANEL_S6E8AA0 | |||
27 | select DRM_MIPI_DSI | 27 | select DRM_MIPI_DSI |
28 | select VIDEOMODE_HELPERS | 28 | select VIDEOMODE_HELPERS |
29 | 29 | ||
30 | config DRM_PANEL_SHARP_LQ101R1SX01 | ||
31 | tristate "Sharp LQ101R1SX01 panel" | ||
32 | depends on OF | ||
33 | depends on DRM_MIPI_DSI | ||
34 | help | ||
35 | Say Y here if you want to enable support for Sharp LQ101R1SX01 | ||
36 | TFT-LCD modules. The panel has a 2560x1600 resolution and uses | ||
37 | 24 bit RGB per pixel. It provides a dual MIPI DSI interface to | ||
38 | the host and has a built-in LED backlight. | ||
39 | |||
40 | To compile this driver as a module, choose M here: the module | ||
41 | will be called panel-sharp-lq101r1sx01. | ||
42 | |||
30 | endmenu | 43 | endmenu |
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 8b929212fad7..4b2a0430804b 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile | |||
@@ -1,3 +1,4 @@ | |||
1 | obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o | 1 | obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o |
2 | obj-$(CONFIG_DRM_PANEL_LD9040) += panel-ld9040.o | 2 | obj-$(CONFIG_DRM_PANEL_LD9040) += panel-ld9040.o |
3 | obj-$(CONFIG_DRM_PANEL_S6E8AA0) += panel-s6e8aa0.o | 3 | obj-$(CONFIG_DRM_PANEL_S6E8AA0) += panel-s6e8aa0.o |
4 | obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o | ||
diff --git a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c new file mode 100644 index 000000000000..9d81759d82fc --- /dev/null +++ b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c | |||
@@ -0,0 +1,464 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 NVIDIA Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/backlight.h> | ||
10 | #include <linux/gpio/consumer.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/of.h> | ||
13 | #include <linux/regulator/consumer.h> | ||
14 | |||
15 | #include <drm/drmP.h> | ||
16 | #include <drm/drm_crtc.h> | ||
17 | #include <drm/drm_mipi_dsi.h> | ||
18 | #include <drm/drm_panel.h> | ||
19 | |||
20 | #include <video/mipi_display.h> | ||
21 | |||
22 | #include <linux/host1x.h> | ||
23 | |||
24 | struct sharp_panel { | ||
25 | struct drm_panel base; | ||
26 | /* the datasheet refers to them as DSI-LINK1 and DSI-LINK2 */ | ||
27 | struct mipi_dsi_device *link1; | ||
28 | struct mipi_dsi_device *link2; | ||
29 | |||
30 | struct backlight_device *backlight; | ||
31 | struct regulator *supply; | ||
32 | |||
33 | bool prepared; | ||
34 | bool enabled; | ||
35 | |||
36 | const struct drm_display_mode *mode; | ||
37 | }; | ||
38 | |||
39 | static inline struct sharp_panel *to_sharp_panel(struct drm_panel *panel) | ||
40 | { | ||
41 | return container_of(panel, struct sharp_panel, base); | ||
42 | } | ||
43 | |||
44 | static int sharp_panel_write(struct sharp_panel *sharp, u16 offset, u8 value) | ||
45 | { | ||
46 | u8 payload[3] = { offset >> 8, offset & 0xff, value }; | ||
47 | struct mipi_dsi_device *dsi = sharp->link1; | ||
48 | ssize_t err; | ||
49 | |||
50 | err = mipi_dsi_generic_write(dsi, payload, sizeof(payload)); | ||
51 | if (err < 0) { | ||
52 | dev_err(&dsi->dev, "failed to write %02x to %04x: %zd\n", | ||
53 | value, offset, err); | ||
54 | return err; | ||
55 | } | ||
56 | |||
57 | err = mipi_dsi_dcs_nop(dsi); | ||
58 | if (err < 0) { | ||
59 | dev_err(&dsi->dev, "failed to send DCS nop: %zd\n", err); | ||
60 | return err; | ||
61 | } | ||
62 | |||
63 | usleep_range(10, 20); | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | static __maybe_unused int sharp_panel_read(struct sharp_panel *sharp, | ||
69 | u16 offset, u8 *value) | ||
70 | { | ||
71 | ssize_t err; | ||
72 | |||
73 | cpu_to_be16s(&offset); | ||
74 | |||
75 | err = mipi_dsi_generic_read(sharp->link1, &offset, sizeof(offset), | ||
76 | value, sizeof(*value)); | ||
77 | if (err < 0) | ||
78 | dev_err(&sharp->link1->dev, "failed to read from %04x: %zd\n", | ||
79 | offset, err); | ||
80 | |||
81 | return err; | ||
82 | } | ||
83 | |||
84 | static int sharp_panel_disable(struct drm_panel *panel) | ||
85 | { | ||
86 | struct sharp_panel *sharp = to_sharp_panel(panel); | ||
87 | |||
88 | if (!sharp->enabled) | ||
89 | return 0; | ||
90 | |||
91 | if (sharp->backlight) { | ||
92 | sharp->backlight->props.power = FB_BLANK_POWERDOWN; | ||
93 | backlight_update_status(sharp->backlight); | ||
94 | } | ||
95 | |||
96 | sharp->enabled = false; | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static int sharp_panel_unprepare(struct drm_panel *panel) | ||
102 | { | ||
103 | struct sharp_panel *sharp = to_sharp_panel(panel); | ||
104 | int err; | ||
105 | |||
106 | if (!sharp->prepared) | ||
107 | return 0; | ||
108 | |||
109 | err = mipi_dsi_dcs_set_display_off(sharp->link1); | ||
110 | if (err < 0) | ||
111 | dev_err(panel->dev, "failed to set display off: %d\n", err); | ||
112 | |||
113 | err = mipi_dsi_dcs_enter_sleep_mode(sharp->link1); | ||
114 | if (err < 0) | ||
115 | dev_err(panel->dev, "failed to enter sleep mode: %d\n", err); | ||
116 | |||
117 | msleep(120); | ||
118 | |||
119 | regulator_disable(sharp->supply); | ||
120 | |||
121 | sharp->prepared = false; | ||
122 | |||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static int sharp_setup_symmetrical_split(struct mipi_dsi_device *left, | ||
127 | struct mipi_dsi_device *right, | ||
128 | const struct drm_display_mode *mode) | ||
129 | { | ||
130 | int err; | ||
131 | |||
132 | err = mipi_dsi_dcs_set_column_address(left, 0, mode->hdisplay / 2 - 1); | ||
133 | if (err < 0) { | ||
134 | dev_err(&left->dev, "failed to set column address: %d\n", err); | ||
135 | return err; | ||
136 | } | ||
137 | |||
138 | err = mipi_dsi_dcs_set_page_address(left, 0, mode->vdisplay - 1); | ||
139 | if (err < 0) { | ||
140 | dev_err(&left->dev, "failed to set page address: %d\n", err); | ||
141 | return err; | ||
142 | } | ||
143 | |||
144 | err = mipi_dsi_dcs_set_column_address(right, mode->hdisplay / 2, | ||
145 | mode->hdisplay - 1); | ||
146 | if (err < 0) { | ||
147 | dev_err(&right->dev, "failed to set column address: %d\n", err); | ||
148 | return err; | ||
149 | } | ||
150 | |||
151 | err = mipi_dsi_dcs_set_page_address(right, 0, mode->vdisplay - 1); | ||
152 | if (err < 0) { | ||
153 | dev_err(&right->dev, "failed to set page address: %d\n", err); | ||
154 | return err; | ||
155 | } | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static int sharp_panel_prepare(struct drm_panel *panel) | ||
161 | { | ||
162 | struct sharp_panel *sharp = to_sharp_panel(panel); | ||
163 | u8 format = MIPI_DCS_PIXEL_FMT_24BIT; | ||
164 | int err; | ||
165 | |||
166 | if (sharp->prepared) | ||
167 | return 0; | ||
168 | |||
169 | err = regulator_enable(sharp->supply); | ||
170 | if (err < 0) | ||
171 | return err; | ||
172 | |||
173 | usleep_range(10000, 20000); | ||
174 | |||
175 | err = mipi_dsi_dcs_soft_reset(sharp->link1); | ||
176 | if (err < 0) { | ||
177 | dev_err(panel->dev, "soft reset failed: %d\n", err); | ||
178 | goto poweroff; | ||
179 | } | ||
180 | |||
181 | msleep(120); | ||
182 | |||
183 | err = mipi_dsi_dcs_exit_sleep_mode(sharp->link1); | ||
184 | if (err < 0) { | ||
185 | dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); | ||
186 | goto poweroff; | ||
187 | } | ||
188 | |||
189 | /* | ||
190 | * The MIPI DCS specification mandates this delay only between the | ||
191 | * exit_sleep_mode and enter_sleep_mode commands, so it isn't strictly | ||
192 | * necessary here. | ||
193 | */ | ||
194 | /* | ||
195 | msleep(120); | ||
196 | */ | ||
197 | |||
198 | /* set left-right mode */ | ||
199 | err = sharp_panel_write(sharp, 0x1000, 0x2a); | ||
200 | if (err < 0) { | ||
201 | dev_err(panel->dev, "failed to set left-right mode: %d\n", err); | ||
202 | goto poweroff; | ||
203 | } | ||
204 | |||
205 | /* enable command mode */ | ||
206 | err = sharp_panel_write(sharp, 0x1001, 0x01); | ||
207 | if (err < 0) { | ||
208 | dev_err(panel->dev, "failed to enable command mode: %d\n", err); | ||
209 | goto poweroff; | ||
210 | } | ||
211 | |||
212 | err = mipi_dsi_dcs_set_pixel_format(sharp->link1, format); | ||
213 | if (err < 0) { | ||
214 | dev_err(panel->dev, "failed to set pixel format: %d\n", err); | ||
215 | goto poweroff; | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * TODO: The device supports both left-right and even-odd split | ||
220 | * configurations, but this driver currently supports only the left- | ||
221 | * right split. To support a different mode a mechanism needs to be | ||
222 | * put in place to communicate the configuration back to the DSI host | ||
223 | * controller. | ||
224 | */ | ||
225 | err = sharp_setup_symmetrical_split(sharp->link1, sharp->link2, | ||
226 | sharp->mode); | ||
227 | if (err < 0) { | ||
228 | dev_err(panel->dev, "failed to set up symmetrical split: %d\n", | ||
229 | err); | ||
230 | goto poweroff; | ||
231 | } | ||
232 | |||
233 | err = mipi_dsi_dcs_set_display_on(sharp->link1); | ||
234 | if (err < 0) { | ||
235 | dev_err(panel->dev, "failed to set display on: %d\n", err); | ||
236 | goto poweroff; | ||
237 | } | ||
238 | |||
239 | sharp->prepared = true; | ||
240 | |||
241 | return 0; | ||
242 | |||
243 | poweroff: | ||
244 | regulator_disable(sharp->supply); | ||
245 | return err; | ||
246 | } | ||
247 | |||
248 | static int sharp_panel_enable(struct drm_panel *panel) | ||
249 | { | ||
250 | struct sharp_panel *sharp = to_sharp_panel(panel); | ||
251 | |||
252 | if (sharp->enabled) | ||
253 | return 0; | ||
254 | |||
255 | if (sharp->backlight) { | ||
256 | sharp->backlight->props.power = FB_BLANK_UNBLANK; | ||
257 | backlight_update_status(sharp->backlight); | ||
258 | } | ||
259 | |||
260 | sharp->enabled = true; | ||
261 | |||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | static const struct drm_display_mode default_mode = { | ||
266 | .clock = 278000, | ||
267 | .hdisplay = 2560, | ||
268 | .hsync_start = 2560 + 128, | ||
269 | .hsync_end = 2560 + 128 + 64, | ||
270 | .htotal = 2560 + 128 + 64 + 64, | ||
271 | .vdisplay = 1600, | ||
272 | .vsync_start = 1600 + 4, | ||
273 | .vsync_end = 1600 + 4 + 8, | ||
274 | .vtotal = 1600 + 4 + 8 + 32, | ||
275 | .vrefresh = 60, | ||
276 | }; | ||
277 | |||
278 | static int sharp_panel_get_modes(struct drm_panel *panel) | ||
279 | { | ||
280 | struct drm_display_mode *mode; | ||
281 | |||
282 | mode = drm_mode_duplicate(panel->drm, &default_mode); | ||
283 | if (!mode) { | ||
284 | dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n", | ||
285 | default_mode.hdisplay, default_mode.vdisplay, | ||
286 | default_mode.vrefresh); | ||
287 | return -ENOMEM; | ||
288 | } | ||
289 | |||
290 | drm_mode_set_name(mode); | ||
291 | |||
292 | drm_mode_probed_add(panel->connector, mode); | ||
293 | |||
294 | panel->connector->display_info.width_mm = 217; | ||
295 | panel->connector->display_info.height_mm = 136; | ||
296 | |||
297 | return 1; | ||
298 | } | ||
299 | |||
300 | static const struct drm_panel_funcs sharp_panel_funcs = { | ||
301 | .disable = sharp_panel_disable, | ||
302 | .unprepare = sharp_panel_unprepare, | ||
303 | .prepare = sharp_panel_prepare, | ||
304 | .enable = sharp_panel_enable, | ||
305 | .get_modes = sharp_panel_get_modes, | ||
306 | }; | ||
307 | |||
308 | static const struct of_device_id sharp_of_match[] = { | ||
309 | { .compatible = "sharp,lq101r1sx01", }, | ||
310 | { } | ||
311 | }; | ||
312 | MODULE_DEVICE_TABLE(of, sharp_of_match); | ||
313 | |||
314 | static int sharp_panel_add(struct sharp_panel *sharp) | ||
315 | { | ||
316 | struct device_node *np; | ||
317 | int err; | ||
318 | |||
319 | sharp->mode = &default_mode; | ||
320 | |||
321 | sharp->supply = devm_regulator_get(&sharp->link1->dev, "power"); | ||
322 | if (IS_ERR(sharp->supply)) | ||
323 | return PTR_ERR(sharp->supply); | ||
324 | |||
325 | np = of_parse_phandle(sharp->link1->dev.of_node, "backlight", 0); | ||
326 | if (np) { | ||
327 | sharp->backlight = of_find_backlight_by_node(np); | ||
328 | of_node_put(np); | ||
329 | |||
330 | if (!sharp->backlight) | ||
331 | return -EPROBE_DEFER; | ||
332 | } | ||
333 | |||
334 | drm_panel_init(&sharp->base); | ||
335 | sharp->base.funcs = &sharp_panel_funcs; | ||
336 | sharp->base.dev = &sharp->link1->dev; | ||
337 | |||
338 | err = drm_panel_add(&sharp->base); | ||
339 | if (err < 0) | ||
340 | goto put_backlight; | ||
341 | |||
342 | return 0; | ||
343 | |||
344 | put_backlight: | ||
345 | if (sharp->backlight) | ||
346 | put_device(&sharp->backlight->dev); | ||
347 | |||
348 | return err; | ||
349 | } | ||
350 | |||
351 | static void sharp_panel_del(struct sharp_panel *sharp) | ||
352 | { | ||
353 | if (sharp->base.dev) | ||
354 | drm_panel_remove(&sharp->base); | ||
355 | |||
356 | if (sharp->backlight) | ||
357 | put_device(&sharp->backlight->dev); | ||
358 | |||
359 | if (sharp->link2) | ||
360 | put_device(&sharp->link2->dev); | ||
361 | } | ||
362 | |||
363 | static int sharp_panel_probe(struct mipi_dsi_device *dsi) | ||
364 | { | ||
365 | struct mipi_dsi_device *secondary = NULL; | ||
366 | struct sharp_panel *sharp; | ||
367 | struct device_node *np; | ||
368 | int err; | ||
369 | |||
370 | dsi->lanes = 4; | ||
371 | dsi->format = MIPI_DSI_FMT_RGB888; | ||
372 | dsi->mode_flags = MIPI_DSI_MODE_LPM; | ||
373 | |||
374 | /* Find DSI-LINK1 */ | ||
375 | np = of_parse_phandle(dsi->dev.of_node, "link2", 0); | ||
376 | if (np) { | ||
377 | secondary = of_find_mipi_dsi_device_by_node(np); | ||
378 | of_node_put(np); | ||
379 | |||
380 | if (!secondary) | ||
381 | return -EPROBE_DEFER; | ||
382 | } | ||
383 | |||
384 | /* register a panel for only the DSI-LINK1 interface */ | ||
385 | if (secondary) { | ||
386 | sharp = devm_kzalloc(&dsi->dev, sizeof(*sharp), GFP_KERNEL); | ||
387 | if (!sharp) { | ||
388 | put_device(&secondary->dev); | ||
389 | return -ENOMEM; | ||
390 | } | ||
391 | |||
392 | mipi_dsi_set_drvdata(dsi, sharp); | ||
393 | |||
394 | sharp->link2 = secondary; | ||
395 | sharp->link1 = dsi; | ||
396 | |||
397 | err = sharp_panel_add(sharp); | ||
398 | if (err < 0) { | ||
399 | put_device(&secondary->dev); | ||
400 | return err; | ||
401 | } | ||
402 | } | ||
403 | |||
404 | err = mipi_dsi_attach(dsi); | ||
405 | if (err < 0) { | ||
406 | if (secondary) | ||
407 | sharp_panel_del(sharp); | ||
408 | |||
409 | return err; | ||
410 | } | ||
411 | |||
412 | return 0; | ||
413 | } | ||
414 | |||
415 | static int sharp_panel_remove(struct mipi_dsi_device *dsi) | ||
416 | { | ||
417 | struct sharp_panel *sharp = mipi_dsi_get_drvdata(dsi); | ||
418 | int err; | ||
419 | |||
420 | /* only detach from host for the DSI-LINK2 interface */ | ||
421 | if (!sharp) { | ||
422 | mipi_dsi_detach(dsi); | ||
423 | return 0; | ||
424 | } | ||
425 | |||
426 | err = sharp_panel_disable(&sharp->base); | ||
427 | if (err < 0) | ||
428 | dev_err(&dsi->dev, "failed to disable panel: %d\n", err); | ||
429 | |||
430 | err = mipi_dsi_detach(dsi); | ||
431 | if (err < 0) | ||
432 | dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); | ||
433 | |||
434 | drm_panel_detach(&sharp->base); | ||
435 | sharp_panel_del(sharp); | ||
436 | |||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | static void sharp_panel_shutdown(struct mipi_dsi_device *dsi) | ||
441 | { | ||
442 | struct sharp_panel *sharp = mipi_dsi_get_drvdata(dsi); | ||
443 | |||
444 | /* nothing to do for DSI-LINK2 */ | ||
445 | if (!sharp) | ||
446 | return; | ||
447 | |||
448 | sharp_panel_disable(&sharp->base); | ||
449 | } | ||
450 | |||
451 | static struct mipi_dsi_driver sharp_panel_driver = { | ||
452 | .driver = { | ||
453 | .name = "panel-sharp-lq101r1sx01", | ||
454 | .of_match_table = sharp_of_match, | ||
455 | }, | ||
456 | .probe = sharp_panel_probe, | ||
457 | .remove = sharp_panel_remove, | ||
458 | .shutdown = sharp_panel_shutdown, | ||
459 | }; | ||
460 | module_mipi_dsi_driver(sharp_panel_driver); | ||
461 | |||
462 | MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); | ||
463 | MODULE_DESCRIPTION("Sharp LQ101R1SX01 panel driver"); | ||
464 | MODULE_LICENSE("GPL v2"); | ||