diff options
95 files changed, 8700 insertions, 1214 deletions
diff --git a/Documentation/devicetree/bindings/video/fsl,imx-fb.txt b/Documentation/devicetree/bindings/video/fsl,imx-fb.txt new file mode 100644 index 000000000000..46da08db186a --- /dev/null +++ b/Documentation/devicetree/bindings/video/fsl,imx-fb.txt | |||
@@ -0,0 +1,51 @@ | |||
1 | Freescale imx21 Framebuffer | ||
2 | |||
3 | This framebuffer driver supports devices imx1, imx21, imx25, and imx27. | ||
4 | |||
5 | Required properties: | ||
6 | - compatible : "fsl,<chip>-fb", chip should be imx1 or imx21 | ||
7 | - reg : Should contain 1 register ranges(address and length) | ||
8 | - interrupts : One interrupt of the fb dev | ||
9 | |||
10 | Required nodes: | ||
11 | - display: Phandle to a display node as described in | ||
12 | Documentation/devicetree/bindings/video/display-timing.txt | ||
13 | Additional, the display node has to define properties: | ||
14 | - bits-per-pixel: Bits per pixel | ||
15 | - fsl,pcr: LCDC PCR value | ||
16 | |||
17 | Optional properties: | ||
18 | - fsl,dmacr: DMA Control Register value. This is optional. By default, the | ||
19 | register is not modified as recommended by the datasheet. | ||
20 | - fsl,lscr1: LCDC Sharp Configuration Register value. | ||
21 | |||
22 | Example: | ||
23 | |||
24 | imxfb: fb@10021000 { | ||
25 | compatible = "fsl,imx21-fb"; | ||
26 | interrupts = <61>; | ||
27 | reg = <0x10021000 0x1000>; | ||
28 | display = <&display0>; | ||
29 | }; | ||
30 | |||
31 | ... | ||
32 | |||
33 | display0: display0 { | ||
34 | model = "Primeview-PD050VL1"; | ||
35 | native-mode = <&timing_disp0>; | ||
36 | bits-per-pixel = <16>; | ||
37 | fsl,pcr = <0xf0c88080>; /* non-standard but required */ | ||
38 | display-timings { | ||
39 | timing_disp0: 640x480 { | ||
40 | hactive = <640>; | ||
41 | vactive = <480>; | ||
42 | hback-porch = <112>; | ||
43 | hfront-porch = <36>; | ||
44 | hsync-len = <32>; | ||
45 | vback-porch = <33>; | ||
46 | vfront-porch = <33>; | ||
47 | vsync-len = <2>; | ||
48 | clock-frequency = <25000000>; | ||
49 | }; | ||
50 | }; | ||
51 | }; | ||
diff --git a/Documentation/devicetree/bindings/video/ssd1307fb.txt b/Documentation/devicetree/bindings/video/ssd1307fb.txt index 3d0060cff062..7a125427ff4b 100644 --- a/Documentation/devicetree/bindings/video/ssd1307fb.txt +++ b/Documentation/devicetree/bindings/video/ssd1307fb.txt | |||
@@ -1,13 +1,17 @@ | |||
1 | * Solomon SSD1307 Framebuffer Driver | 1 | * Solomon SSD1307 Framebuffer Driver |
2 | 2 | ||
3 | Required properties: | 3 | Required properties: |
4 | - compatible: Should be "solomon,ssd1307fb-<bus>". The only supported bus for | 4 | - compatible: Should be "solomon,<chip>fb-<bus>". The only supported bus for |
5 | now is i2c. | 5 | now is i2c, and the supported chips are ssd1306 and ssd1307. |
6 | - reg: Should contain address of the controller on the I2C bus. Most likely | 6 | - reg: Should contain address of the controller on the I2C bus. Most likely |
7 | 0x3c or 0x3d | 7 | 0x3c or 0x3d |
8 | - pwm: Should contain the pwm to use according to the OF device tree PWM | 8 | - pwm: Should contain the pwm to use according to the OF device tree PWM |
9 | specification [0] | 9 | specification [0]. Only required for the ssd1307. |
10 | - reset-gpios: Should contain the GPIO used to reset the OLED display | 10 | - reset-gpios: Should contain the GPIO used to reset the OLED display |
11 | - solomon,height: Height in pixel of the screen driven by the controller | ||
12 | - solomon,width: Width in pixel of the screen driven by the controller | ||
13 | - solomon,page-offset: Offset of pages (band of 8 pixels) that the screen is | ||
14 | mapped to. | ||
11 | 15 | ||
12 | Optional properties: | 16 | Optional properties: |
13 | - reset-active-low: Is the reset gpio is active on physical low? | 17 | - reset-active-low: Is the reset gpio is active on physical low? |
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 79b200aee18a..4cec678dba94 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c | |||
@@ -40,7 +40,7 @@ struct omap_crtc { | |||
40 | * mgr->id.) Eventually this will be replaced w/ something | 40 | * mgr->id.) Eventually this will be replaced w/ something |
41 | * more common-panel-framework-y | 41 | * more common-panel-framework-y |
42 | */ | 42 | */ |
43 | struct omap_overlay_manager mgr; | 43 | struct omap_overlay_manager *mgr; |
44 | 44 | ||
45 | struct omap_video_timings timings; | 45 | struct omap_video_timings timings; |
46 | bool enabled; | 46 | bool enabled; |
@@ -90,7 +90,32 @@ uint32_t pipe2vbl(struct drm_crtc *crtc) | |||
90 | * job of sequencing the setup of the video pipe in the proper order | 90 | * job of sequencing the setup of the video pipe in the proper order |
91 | */ | 91 | */ |
92 | 92 | ||
93 | /* ovl-mgr-id -> crtc */ | ||
94 | static struct omap_crtc *omap_crtcs[8]; | ||
95 | |||
93 | /* we can probably ignore these until we support command-mode panels: */ | 96 | /* we can probably ignore these until we support command-mode panels: */ |
97 | static int omap_crtc_connect(struct omap_overlay_manager *mgr, | ||
98 | struct omap_dss_device *dst) | ||
99 | { | ||
100 | if (mgr->output) | ||
101 | return -EINVAL; | ||
102 | |||
103 | if ((mgr->supported_outputs & dst->id) == 0) | ||
104 | return -EINVAL; | ||
105 | |||
106 | dst->manager = mgr; | ||
107 | mgr->output = dst; | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | static void omap_crtc_disconnect(struct omap_overlay_manager *mgr, | ||
113 | struct omap_dss_device *dst) | ||
114 | { | ||
115 | mgr->output->manager = NULL; | ||
116 | mgr->output = NULL; | ||
117 | } | ||
118 | |||
94 | static void omap_crtc_start_update(struct omap_overlay_manager *mgr) | 119 | static void omap_crtc_start_update(struct omap_overlay_manager *mgr) |
95 | { | 120 | { |
96 | } | 121 | } |
@@ -107,7 +132,7 @@ static void omap_crtc_disable(struct omap_overlay_manager *mgr) | |||
107 | static void omap_crtc_set_timings(struct omap_overlay_manager *mgr, | 132 | static void omap_crtc_set_timings(struct omap_overlay_manager *mgr, |
108 | const struct omap_video_timings *timings) | 133 | const struct omap_video_timings *timings) |
109 | { | 134 | { |
110 | struct omap_crtc *omap_crtc = container_of(mgr, struct omap_crtc, mgr); | 135 | struct omap_crtc *omap_crtc = omap_crtcs[mgr->id]; |
111 | DBG("%s", omap_crtc->name); | 136 | DBG("%s", omap_crtc->name); |
112 | omap_crtc->timings = *timings; | 137 | omap_crtc->timings = *timings; |
113 | omap_crtc->full_update = true; | 138 | omap_crtc->full_update = true; |
@@ -116,7 +141,7 @@ static void omap_crtc_set_timings(struct omap_overlay_manager *mgr, | |||
116 | static void omap_crtc_set_lcd_config(struct omap_overlay_manager *mgr, | 141 | static void omap_crtc_set_lcd_config(struct omap_overlay_manager *mgr, |
117 | const struct dss_lcd_mgr_config *config) | 142 | const struct dss_lcd_mgr_config *config) |
118 | { | 143 | { |
119 | struct omap_crtc *omap_crtc = container_of(mgr, struct omap_crtc, mgr); | 144 | struct omap_crtc *omap_crtc = omap_crtcs[mgr->id]; |
120 | DBG("%s", omap_crtc->name); | 145 | DBG("%s", omap_crtc->name); |
121 | dispc_mgr_set_lcd_config(omap_crtc->channel, config); | 146 | dispc_mgr_set_lcd_config(omap_crtc->channel, config); |
122 | } | 147 | } |
@@ -135,6 +160,8 @@ static void omap_crtc_unregister_framedone_handler( | |||
135 | } | 160 | } |
136 | 161 | ||
137 | static const struct dss_mgr_ops mgr_ops = { | 162 | static const struct dss_mgr_ops mgr_ops = { |
163 | .connect = omap_crtc_connect, | ||
164 | .disconnect = omap_crtc_disconnect, | ||
138 | .start_update = omap_crtc_start_update, | 165 | .start_update = omap_crtc_start_update, |
139 | .enable = omap_crtc_enable, | 166 | .enable = omap_crtc_enable, |
140 | .disable = omap_crtc_disable, | 167 | .disable = omap_crtc_disable, |
@@ -569,7 +596,7 @@ static void omap_crtc_pre_apply(struct omap_drm_apply *apply) | |||
569 | } else { | 596 | } else { |
570 | if (encoder) { | 597 | if (encoder) { |
571 | omap_encoder_set_enabled(encoder, false); | 598 | omap_encoder_set_enabled(encoder, false); |
572 | omap_encoder_update(encoder, &omap_crtc->mgr, | 599 | omap_encoder_update(encoder, omap_crtc->mgr, |
573 | &omap_crtc->timings); | 600 | &omap_crtc->timings); |
574 | omap_encoder_set_enabled(encoder, true); | 601 | omap_encoder_set_enabled(encoder, true); |
575 | omap_crtc->full_update = false; | 602 | omap_crtc->full_update = false; |
@@ -595,6 +622,11 @@ static const char *channel_names[] = { | |||
595 | [OMAP_DSS_CHANNEL_LCD2] = "lcd2", | 622 | [OMAP_DSS_CHANNEL_LCD2] = "lcd2", |
596 | }; | 623 | }; |
597 | 624 | ||
625 | void omap_crtc_pre_init(void) | ||
626 | { | ||
627 | dss_install_mgr_ops(&mgr_ops); | ||
628 | } | ||
629 | |||
598 | /* initialize crtc */ | 630 | /* initialize crtc */ |
599 | struct drm_crtc *omap_crtc_init(struct drm_device *dev, | 631 | struct drm_crtc *omap_crtc_init(struct drm_device *dev, |
600 | struct drm_plane *plane, enum omap_channel channel, int id) | 632 | struct drm_plane *plane, enum omap_channel channel, int id) |
@@ -635,9 +667,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, | |||
635 | omap_irq_register(dev, &omap_crtc->error_irq); | 667 | omap_irq_register(dev, &omap_crtc->error_irq); |
636 | 668 | ||
637 | /* temporary: */ | 669 | /* temporary: */ |
638 | omap_crtc->mgr.id = channel; | 670 | omap_crtc->mgr = omap_dss_get_overlay_manager(channel); |
639 | |||
640 | dss_install_mgr_ops(&mgr_ops); | ||
641 | 671 | ||
642 | /* TODO: fix hard-coded setup.. add properties! */ | 672 | /* TODO: fix hard-coded setup.. add properties! */ |
643 | info = &omap_crtc->info; | 673 | info = &omap_crtc->info; |
@@ -651,6 +681,8 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, | |||
651 | 681 | ||
652 | omap_plane_install_properties(omap_crtc->plane, &crtc->base); | 682 | omap_plane_install_properties(omap_crtc->plane, &crtc->base); |
653 | 683 | ||
684 | omap_crtcs[channel] = omap_crtc; | ||
685 | |||
654 | return crtc; | 686 | return crtc; |
655 | 687 | ||
656 | fail: | 688 | fail: |
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 826586ffbe83..a3004f12b9a3 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c | |||
@@ -65,10 +65,8 @@ static int get_connector_type(struct omap_dss_device *dssdev) | |||
65 | switch (dssdev->type) { | 65 | switch (dssdev->type) { |
66 | case OMAP_DISPLAY_TYPE_HDMI: | 66 | case OMAP_DISPLAY_TYPE_HDMI: |
67 | return DRM_MODE_CONNECTOR_HDMIA; | 67 | return DRM_MODE_CONNECTOR_HDMIA; |
68 | case OMAP_DISPLAY_TYPE_DPI: | 68 | case OMAP_DISPLAY_TYPE_DVI: |
69 | if (!strcmp(dssdev->name, "dvi")) | 69 | return DRM_MODE_CONNECTOR_DVID; |
70 | return DRM_MODE_CONNECTOR_DVID; | ||
71 | /* fallthrough */ | ||
72 | default: | 70 | default: |
73 | return DRM_MODE_CONNECTOR_Unknown; | 71 | return DRM_MODE_CONNECTOR_Unknown; |
74 | } | 72 | } |
@@ -97,6 +95,9 @@ static int omap_modeset_init(struct drm_device *dev) | |||
97 | int num_mgrs = dss_feat_get_num_mgrs(); | 95 | int num_mgrs = dss_feat_get_num_mgrs(); |
98 | int num_crtcs; | 96 | int num_crtcs; |
99 | int i, id = 0; | 97 | int i, id = 0; |
98 | int r; | ||
99 | |||
100 | omap_crtc_pre_init(); | ||
100 | 101 | ||
101 | drm_mode_config_init(dev); | 102 | drm_mode_config_init(dev); |
102 | 103 | ||
@@ -116,6 +117,7 @@ static int omap_modeset_init(struct drm_device *dev) | |||
116 | struct drm_connector *connector; | 117 | struct drm_connector *connector; |
117 | struct drm_encoder *encoder; | 118 | struct drm_encoder *encoder; |
118 | enum omap_channel channel; | 119 | enum omap_channel channel; |
120 | struct omap_overlay_manager *mgr; | ||
119 | 121 | ||
120 | if (!dssdev->driver) { | 122 | if (!dssdev->driver) { |
121 | dev_warn(dev->dev, "%s has no driver.. skipping it\n", | 123 | dev_warn(dev->dev, "%s has no driver.. skipping it\n", |
@@ -131,6 +133,13 @@ static int omap_modeset_init(struct drm_device *dev) | |||
131 | continue; | 133 | continue; |
132 | } | 134 | } |
133 | 135 | ||
136 | r = dssdev->driver->connect(dssdev); | ||
137 | if (r) { | ||
138 | dev_err(dev->dev, "could not connect display: %s\n", | ||
139 | dssdev->name); | ||
140 | continue; | ||
141 | } | ||
142 | |||
134 | encoder = omap_encoder_init(dev, dssdev); | 143 | encoder = omap_encoder_init(dev, dssdev); |
135 | 144 | ||
136 | if (!encoder) { | 145 | if (!encoder) { |
@@ -172,8 +181,9 @@ static int omap_modeset_init(struct drm_device *dev) | |||
172 | * other possible channels to which the encoder can connect are | 181 | * other possible channels to which the encoder can connect are |
173 | * not considered. | 182 | * not considered. |
174 | */ | 183 | */ |
175 | channel = dssdev->output->dispc_channel; | ||
176 | 184 | ||
185 | mgr = omapdss_find_mgr_from_display(dssdev); | ||
186 | channel = mgr->id; | ||
177 | /* | 187 | /* |
178 | * if this channel hasn't already been taken by a previously | 188 | * if this channel hasn't already been taken by a previously |
179 | * allocated crtc, we create a new crtc for it | 189 | * allocated crtc, we create a new crtc for it |
@@ -247,6 +257,9 @@ static int omap_modeset_init(struct drm_device *dev) | |||
247 | struct drm_encoder *encoder = priv->encoders[i]; | 257 | struct drm_encoder *encoder = priv->encoders[i]; |
248 | struct omap_dss_device *dssdev = | 258 | struct omap_dss_device *dssdev = |
249 | omap_encoder_get_dssdev(encoder); | 259 | omap_encoder_get_dssdev(encoder); |
260 | struct omap_dss_device *output; | ||
261 | |||
262 | output = omapdss_find_output_from_display(dssdev); | ||
250 | 263 | ||
251 | /* figure out which crtc's we can connect the encoder to: */ | 264 | /* figure out which crtc's we can connect the encoder to: */ |
252 | encoder->possible_crtcs = 0; | 265 | encoder->possible_crtcs = 0; |
@@ -259,9 +272,11 @@ static int omap_modeset_init(struct drm_device *dev) | |||
259 | supported_outputs = | 272 | supported_outputs = |
260 | dss_feat_get_supported_outputs(crtc_channel); | 273 | dss_feat_get_supported_outputs(crtc_channel); |
261 | 274 | ||
262 | if (supported_outputs & dssdev->output->id) | 275 | if (supported_outputs & output->id) |
263 | encoder->possible_crtcs |= (1 << id); | 276 | encoder->possible_crtcs |= (1 << id); |
264 | } | 277 | } |
278 | |||
279 | omap_dss_put_device(output); | ||
265 | } | 280 | } |
266 | 281 | ||
267 | DBG("registered %d planes, %d crtcs, %d encoders and %d connectors\n", | 282 | DBG("registered %d planes, %d crtcs, %d encoders and %d connectors\n", |
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 215a20dd340c..14f17da2ce25 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h | |||
@@ -157,6 +157,7 @@ const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc); | |||
157 | enum omap_channel omap_crtc_channel(struct drm_crtc *crtc); | 157 | enum omap_channel omap_crtc_channel(struct drm_crtc *crtc); |
158 | int omap_crtc_apply(struct drm_crtc *crtc, | 158 | int omap_crtc_apply(struct drm_crtc *crtc, |
159 | struct omap_drm_apply *apply); | 159 | struct omap_drm_apply *apply); |
160 | void omap_crtc_pre_init(void); | ||
160 | struct drm_crtc *omap_crtc_init(struct drm_device *dev, | 161 | struct drm_crtc *omap_crtc_init(struct drm_device *dev, |
161 | struct drm_plane *plane, enum omap_channel channel, int id); | 162 | struct drm_plane *plane, enum omap_channel channel, int id); |
162 | 163 | ||
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 2e937bdace6f..4cf1e1dd5621 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -367,6 +367,8 @@ config FB_IMX | |||
367 | select FB_CFB_FILLRECT | 367 | select FB_CFB_FILLRECT |
368 | select FB_CFB_COPYAREA | 368 | select FB_CFB_COPYAREA |
369 | select FB_CFB_IMAGEBLIT | 369 | select FB_CFB_IMAGEBLIT |
370 | select FB_MODE_HELPERS | ||
371 | select VIDEOMODE_HELPERS | ||
370 | 372 | ||
371 | config FB_CYBER2000 | 373 | config FB_CYBER2000 |
372 | tristate "CyberPro 2000/2010/5000 support" | 374 | tristate "CyberPro 2000/2010/5000 support" |
@@ -2188,7 +2190,7 @@ config FB_PS3_DEFAULT_SIZE_M | |||
2188 | 2190 | ||
2189 | config FB_XILINX | 2191 | config FB_XILINX |
2190 | tristate "Xilinx frame buffer support" | 2192 | tristate "Xilinx frame buffer support" |
2191 | depends on FB && (XILINX_VIRTEX || MICROBLAZE) | 2193 | depends on FB && (XILINX_VIRTEX || MICROBLAZE || ARCH_ZYNQ) |
2192 | select FB_CFB_FILLRECT | 2194 | select FB_CFB_FILLRECT |
2193 | select FB_CFB_COPYAREA | 2195 | select FB_CFB_COPYAREA |
2194 | select FB_CFB_IMAGEBLIT | 2196 | select FB_CFB_IMAGEBLIT |
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index 8c55011313dc..a4dfe8cb0a0a 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c | |||
@@ -2016,7 +2016,7 @@ static int aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
2016 | 2016 | ||
2017 | aty128_init_engine(par); | 2017 | aty128_init_engine(par); |
2018 | 2018 | ||
2019 | par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM); | 2019 | par->pm_reg = pdev->pm_cap; |
2020 | par->pdev = pdev; | 2020 | par->pdev = pdev; |
2021 | par->asleep = 0; | 2021 | par->asleep = 0; |
2022 | par->lock_blank = 0; | 2022 | par->lock_blank = 0; |
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 4f27fdc58d84..a89c15de9f45 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c | |||
@@ -58,6 +58,7 @@ | |||
58 | #include <linux/slab.h> | 58 | #include <linux/slab.h> |
59 | #include <linux/vmalloc.h> | 59 | #include <linux/vmalloc.h> |
60 | #include <linux/delay.h> | 60 | #include <linux/delay.h> |
61 | #include <linux/compiler.h> | ||
61 | #include <linux/console.h> | 62 | #include <linux/console.h> |
62 | #include <linux/fb.h> | 63 | #include <linux/fb.h> |
63 | #include <linux/init.h> | 64 | #include <linux/init.h> |
@@ -434,8 +435,8 @@ static int correct_chipset(struct atyfb_par *par) | |||
434 | const char *name; | 435 | const char *name; |
435 | int i; | 436 | int i; |
436 | 437 | ||
437 | for (i = ARRAY_SIZE(aty_chips) - 1; i >= 0; i--) | 438 | for (i = ARRAY_SIZE(aty_chips); i > 0; i--) |
438 | if (par->pci_id == aty_chips[i].pci_id) | 439 | if (par->pci_id == aty_chips[i - 1].pci_id) |
439 | break; | 440 | break; |
440 | 441 | ||
441 | if (i < 0) | 442 | if (i < 0) |
@@ -531,8 +532,8 @@ static int correct_chipset(struct atyfb_par *par) | |||
531 | return 0; | 532 | return 0; |
532 | } | 533 | } |
533 | 534 | ||
534 | static char ram_dram[] = "DRAM"; | 535 | static char ram_dram[] __maybe_unused = "DRAM"; |
535 | static char ram_resv[] = "RESV"; | 536 | static char ram_resv[] __maybe_unused = "RESV"; |
536 | #ifdef CONFIG_FB_ATY_GX | 537 | #ifdef CONFIG_FB_ATY_GX |
537 | static char ram_vram[] = "VRAM"; | 538 | static char ram_vram[] = "VRAM"; |
538 | #endif /* CONFIG_FB_ATY_GX */ | 539 | #endif /* CONFIG_FB_ATY_GX */ |
diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c index 92bda5848516..f7091ece580d 100644 --- a/drivers/video/aty/radeon_pm.c +++ b/drivers/video/aty/radeon_pm.c | |||
@@ -2805,7 +2805,7 @@ static void radeonfb_early_resume(void *data) | |||
2805 | void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk, int ignore_devlist, int force_sleep) | 2805 | void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk, int ignore_devlist, int force_sleep) |
2806 | { | 2806 | { |
2807 | /* Find PM registers in config space if any*/ | 2807 | /* Find PM registers in config space if any*/ |
2808 | rinfo->pm_reg = pci_find_capability(rinfo->pdev, PCI_CAP_ID_PM); | 2808 | rinfo->pm_reg = rinfo->pdev->pm_cap; |
2809 | 2809 | ||
2810 | /* Enable/Disable dynamic clocks: TODO add sysfs access */ | 2810 | /* Enable/Disable dynamic clocks: TODO add sysfs access */ |
2811 | if (rinfo->family == CHIP_FAMILY_RS480) | 2811 | if (rinfo->family == CHIP_FAMILY_RS480) |
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c index ebeb9715f061..a54ccdc4d661 100644 --- a/drivers/video/au1100fb.c +++ b/drivers/video/au1100fb.c | |||
@@ -577,7 +577,6 @@ failed: | |||
577 | if (fbdev->info.cmap.len != 0) { | 577 | if (fbdev->info.cmap.len != 0) { |
578 | fb_dealloc_cmap(&fbdev->info.cmap); | 578 | fb_dealloc_cmap(&fbdev->info.cmap); |
579 | } | 579 | } |
580 | platform_set_drvdata(dev, NULL); | ||
581 | 580 | ||
582 | return -ENODEV; | 581 | return -ENODEV; |
583 | } | 582 | } |
diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c index 2726a5b66741..87f288bfc58c 100644 --- a/drivers/video/bf54x-lq043fb.c +++ b/drivers/video/bf54x-lq043fb.c | |||
@@ -681,7 +681,6 @@ out3: | |||
681 | out2: | 681 | out2: |
682 | free_dma(CH_EPPI0); | 682 | free_dma(CH_EPPI0); |
683 | out1: | 683 | out1: |
684 | platform_set_drvdata(pdev, NULL); | ||
685 | 684 | ||
686 | return ret; | 685 | return ret; |
687 | } | 686 | } |
diff --git a/drivers/video/bfin-lq035q1-fb.c b/drivers/video/bfin-lq035q1-fb.c index 29d8c0443a1f..b594a58ff21d 100644 --- a/drivers/video/bfin-lq035q1-fb.c +++ b/drivers/video/bfin-lq035q1-fb.c | |||
@@ -170,16 +170,19 @@ static int lq035q1_spidev_remove(struct spi_device *spi) | |||
170 | return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT); | 170 | return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT); |
171 | } | 171 | } |
172 | 172 | ||
173 | #ifdef CONFIG_PM | 173 | #ifdef CONFIG_PM_SLEEP |
174 | static int lq035q1_spidev_suspend(struct spi_device *spi, pm_message_t state) | 174 | static int lq035q1_spidev_suspend(struct device *dev) |
175 | { | 175 | { |
176 | struct spi_device *spi = to_spi_device(dev); | ||
177 | |||
176 | return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT); | 178 | return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT); |
177 | } | 179 | } |
178 | 180 | ||
179 | static int lq035q1_spidev_resume(struct spi_device *spi) | 181 | static int lq035q1_spidev_resume(struct device *dev) |
180 | { | 182 | { |
181 | int ret; | 183 | struct spi_device *spi = to_spi_device(dev); |
182 | struct spi_control *ctl = spi_get_drvdata(spi); | 184 | struct spi_control *ctl = spi_get_drvdata(spi); |
185 | int ret; | ||
183 | 186 | ||
184 | ret = lq035q1_control(spi, LQ035_DRIVER_OUTPUT_CTL, ctl->mode); | 187 | ret = lq035q1_control(spi, LQ035_DRIVER_OUTPUT_CTL, ctl->mode); |
185 | if (ret) | 188 | if (ret) |
@@ -187,9 +190,13 @@ static int lq035q1_spidev_resume(struct spi_device *spi) | |||
187 | 190 | ||
188 | return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_ON); | 191 | return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_ON); |
189 | } | 192 | } |
193 | |||
194 | static SIMPLE_DEV_PM_OPS(lq035q1_spidev_pm_ops, lq035q1_spidev_suspend, | ||
195 | lq035q1_spidev_resume); | ||
196 | #define LQ035Q1_SPIDEV_PM_OPS (&lq035q1_spidev_pm_ops) | ||
197 | |||
190 | #else | 198 | #else |
191 | # define lq035q1_spidev_suspend NULL | 199 | #define LQ035Q1_SPIDEV_PM_OPS NULL |
192 | # define lq035q1_spidev_resume NULL | ||
193 | #endif | 200 | #endif |
194 | 201 | ||
195 | /* Power down all displays on reboot, poweroff or halt */ | 202 | /* Power down all displays on reboot, poweroff or halt */ |
@@ -708,8 +715,7 @@ static int bfin_lq035q1_probe(struct platform_device *pdev) | |||
708 | info->spidrv.probe = lq035q1_spidev_probe; | 715 | info->spidrv.probe = lq035q1_spidev_probe; |
709 | info->spidrv.remove = lq035q1_spidev_remove; | 716 | info->spidrv.remove = lq035q1_spidev_remove; |
710 | info->spidrv.shutdown = lq035q1_spidev_shutdown; | 717 | info->spidrv.shutdown = lq035q1_spidev_shutdown; |
711 | info->spidrv.suspend = lq035q1_spidev_suspend; | 718 | info->spidrv.driver.pm = LQ035Q1_SPIDEV_PM_OPS; |
712 | info->spidrv.resume = lq035q1_spidev_resume; | ||
713 | 719 | ||
714 | ret = spi_register_driver(&info->spidrv); | 720 | ret = spi_register_driver(&info->spidrv); |
715 | if (ret < 0) { | 721 | if (ret < 0) { |
@@ -759,7 +765,6 @@ static int bfin_lq035q1_probe(struct platform_device *pdev) | |||
759 | out2: | 765 | out2: |
760 | free_dma(CH_PPI); | 766 | free_dma(CH_PPI); |
761 | out1: | 767 | out1: |
762 | platform_set_drvdata(pdev, NULL); | ||
763 | 768 | ||
764 | return ret; | 769 | return ret; |
765 | } | 770 | } |
@@ -788,7 +793,6 @@ static int bfin_lq035q1_remove(struct platform_device *pdev) | |||
788 | bfin_lq035q1_free_ports(info->disp_info->ppi_mode == | 793 | bfin_lq035q1_free_ports(info->disp_info->ppi_mode == |
789 | USE_RGB565_16_BIT_PPI); | 794 | USE_RGB565_16_BIT_PPI); |
790 | 795 | ||
791 | platform_set_drvdata(pdev, NULL); | ||
792 | framebuffer_release(fbinfo); | 796 | framebuffer_release(fbinfo); |
793 | 797 | ||
794 | dev_info(&pdev->dev, "unregistered LCD driver\n"); | 798 | dev_info(&pdev->dev, "unregistered LCD driver\n"); |
diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c index d46da01c31ae..48c0c4e38a62 100644 --- a/drivers/video/bfin-t350mcqb-fb.c +++ b/drivers/video/bfin-t350mcqb-fb.c | |||
@@ -578,7 +578,6 @@ out3: | |||
578 | out2: | 578 | out2: |
579 | free_dma(CH_PPI); | 579 | free_dma(CH_PPI); |
580 | out1: | 580 | out1: |
581 | platform_set_drvdata(pdev, NULL); | ||
582 | 581 | ||
583 | return ret; | 582 | return ret; |
584 | } | 583 | } |
@@ -608,7 +607,6 @@ static int bfin_t350mcqb_remove(struct platform_device *pdev) | |||
608 | 607 | ||
609 | bfin_t350mcqb_request_ports(0); | 608 | bfin_t350mcqb_request_ports(0); |
610 | 609 | ||
611 | platform_set_drvdata(pdev, NULL); | ||
612 | framebuffer_release(fbinfo); | 610 | framebuffer_release(fbinfo); |
613 | 611 | ||
614 | printk(KERN_INFO DRIVER_NAME ": Unregister LCD driver.\n"); | 612 | printk(KERN_INFO DRIVER_NAME ": Unregister LCD driver.\n"); |
diff --git a/drivers/video/ep93xx-fb.c b/drivers/video/ep93xx-fb.c index ee1ee5401544..28a837dfddd1 100644 --- a/drivers/video/ep93xx-fb.c +++ b/drivers/video/ep93xx-fb.c | |||
@@ -595,7 +595,6 @@ failed_videomem: | |||
595 | fb_dealloc_cmap(&info->cmap); | 595 | fb_dealloc_cmap(&info->cmap); |
596 | failed_cmap: | 596 | failed_cmap: |
597 | kfree(info); | 597 | kfree(info); |
598 | platform_set_drvdata(pdev, NULL); | ||
599 | 598 | ||
600 | return err; | 599 | return err; |
601 | } | 600 | } |
@@ -614,7 +613,6 @@ static int ep93xxfb_remove(struct platform_device *pdev) | |||
614 | fbi->mach_info->teardown(pdev); | 613 | fbi->mach_info->teardown(pdev); |
615 | 614 | ||
616 | kfree(info); | 615 | kfree(info); |
617 | platform_set_drvdata(pdev, NULL); | ||
618 | 616 | ||
619 | return 0; | 617 | return 0; |
620 | } | 618 | } |
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 098bfc64cfb9..36e1fe21b9b5 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c | |||
@@ -1305,7 +1305,9 @@ static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix, | |||
1305 | err |= copy_to_user(fix32->reserved, fix->reserved, | 1305 | err |= copy_to_user(fix32->reserved, fix->reserved, |
1306 | sizeof(fix->reserved)); | 1306 | sizeof(fix->reserved)); |
1307 | 1307 | ||
1308 | return err; | 1308 | if (err) |
1309 | return -EFAULT; | ||
1310 | return 0; | ||
1309 | } | 1311 | } |
1310 | 1312 | ||
1311 | static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd, | 1313 | static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd, |
@@ -1881,7 +1883,7 @@ static int ofonly __read_mostly; | |||
1881 | * | 1883 | * |
1882 | * NOTE: Needed to maintain backwards compatibility | 1884 | * NOTE: Needed to maintain backwards compatibility |
1883 | */ | 1885 | */ |
1884 | int fb_get_options(char *name, char **option) | 1886 | int fb_get_options(const char *name, char **option) |
1885 | { | 1887 | { |
1886 | char *opt, *options = NULL; | 1888 | char *opt, *options = NULL; |
1887 | int retval = 0; | 1889 | int retval = 0; |
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index 6c278056fc60..6dd72250111e 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c | |||
@@ -469,7 +469,7 @@ static enum fsl_diu_monitor_port fsl_diu_name_to_port(const char *s) | |||
469 | unsigned long val; | 469 | unsigned long val; |
470 | 470 | ||
471 | if (s) { | 471 | if (s) { |
472 | if (!strict_strtoul(s, 10, &val) && (val <= 2)) | 472 | if (!kstrtoul(s, 10, &val) && (val <= 2)) |
473 | port = (enum fsl_diu_monitor_port) val; | 473 | port = (enum fsl_diu_monitor_port) val; |
474 | else if (strncmp(s, "lvds", 4) == 0) | 474 | else if (strncmp(s, "lvds", 4) == 0) |
475 | port = FSL_DIU_PORT_LVDS; | 475 | port = FSL_DIU_PORT_LVDS; |
@@ -1853,7 +1853,7 @@ static int __init fsl_diu_setup(char *options) | |||
1853 | if (!strncmp(opt, "monitor=", 8)) { | 1853 | if (!strncmp(opt, "monitor=", 8)) { |
1854 | monitor_port = fsl_diu_name_to_port(opt + 8); | 1854 | monitor_port = fsl_diu_name_to_port(opt + 8); |
1855 | } else if (!strncmp(opt, "bpp=", 4)) { | 1855 | } else if (!strncmp(opt, "bpp=", 4)) { |
1856 | if (!strict_strtoul(opt + 4, 10, &val)) | 1856 | if (!kstrtoul(opt + 4, 10, &val)) |
1857 | default_bpp = val; | 1857 | default_bpp = val; |
1858 | } else | 1858 | } else |
1859 | fb_mode = opt; | 1859 | fb_mode = opt; |
diff --git a/drivers/video/i740fb.c b/drivers/video/i740fb.c index cfd0c52e8f73..6c4838818950 100644 --- a/drivers/video/i740fb.c +++ b/drivers/video/i740fb.c | |||
@@ -1302,7 +1302,7 @@ static int __init i740fb_setup(char *options) | |||
1302 | } | 1302 | } |
1303 | #endif | 1303 | #endif |
1304 | 1304 | ||
1305 | int __init i740fb_init(void) | 1305 | static int __init i740fb_init(void) |
1306 | { | 1306 | { |
1307 | #ifndef MODULE | 1307 | #ifndef MODULE |
1308 | char *option = NULL; | 1308 | char *option = NULL; |
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 0abf2bf20836..38733ac2b698 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c | |||
@@ -31,6 +31,12 @@ | |||
31 | #include <linux/dma-mapping.h> | 31 | #include <linux/dma-mapping.h> |
32 | #include <linux/io.h> | 32 | #include <linux/io.h> |
33 | #include <linux/math64.h> | 33 | #include <linux/math64.h> |
34 | #include <linux/of.h> | ||
35 | #include <linux/of_device.h> | ||
36 | |||
37 | #include <video/of_display_timing.h> | ||
38 | #include <video/of_videomode.h> | ||
39 | #include <video/videomode.h> | ||
34 | 40 | ||
35 | #include <linux/platform_data/video-imxfb.h> | 41 | #include <linux/platform_data/video-imxfb.h> |
36 | 42 | ||
@@ -112,10 +118,11 @@ | |||
112 | #define LCDISR_EOF (1<<1) | 118 | #define LCDISR_EOF (1<<1) |
113 | #define LCDISR_BOF (1<<0) | 119 | #define LCDISR_BOF (1<<0) |
114 | 120 | ||
121 | #define IMXFB_LSCR1_DEFAULT 0x00120300 | ||
122 | |||
115 | /* Used fb-mode. Can be set on kernel command line, therefore file-static. */ | 123 | /* Used fb-mode. Can be set on kernel command line, therefore file-static. */ |
116 | static const char *fb_mode; | 124 | static const char *fb_mode; |
117 | 125 | ||
118 | |||
119 | /* | 126 | /* |
120 | * These are the bitfields for each | 127 | * These are the bitfields for each |
121 | * display depth that we support. | 128 | * display depth that we support. |
@@ -187,6 +194,19 @@ static struct platform_device_id imxfb_devtype[] = { | |||
187 | }; | 194 | }; |
188 | MODULE_DEVICE_TABLE(platform, imxfb_devtype); | 195 | MODULE_DEVICE_TABLE(platform, imxfb_devtype); |
189 | 196 | ||
197 | static struct of_device_id imxfb_of_dev_id[] = { | ||
198 | { | ||
199 | .compatible = "fsl,imx1-fb", | ||
200 | .data = &imxfb_devtype[IMX1_FB], | ||
201 | }, { | ||
202 | .compatible = "fsl,imx21-fb", | ||
203 | .data = &imxfb_devtype[IMX21_FB], | ||
204 | }, { | ||
205 | /* sentinel */ | ||
206 | } | ||
207 | }; | ||
208 | MODULE_DEVICE_TABLE(of, imxfb_of_dev_id); | ||
209 | |||
190 | static inline int is_imx1_fb(struct imxfb_info *fbi) | 210 | static inline int is_imx1_fb(struct imxfb_info *fbi) |
191 | { | 211 | { |
192 | return fbi->devtype == IMX1_FB; | 212 | return fbi->devtype == IMX1_FB; |
@@ -319,6 +339,9 @@ static const struct imx_fb_videomode *imxfb_find_mode(struct imxfb_info *fbi) | |||
319 | struct imx_fb_videomode *m; | 339 | struct imx_fb_videomode *m; |
320 | int i; | 340 | int i; |
321 | 341 | ||
342 | if (!fb_mode) | ||
343 | return &fbi->mode[0]; | ||
344 | |||
322 | for (i = 0, m = &fbi->mode[0]; i < fbi->num_modes; i++, m++) { | 345 | for (i = 0, m = &fbi->mode[0]; i < fbi->num_modes; i++, m++) { |
323 | if (!strcmp(m->mode.name, fb_mode)) | 346 | if (!strcmp(m->mode.name, fb_mode)) |
324 | return m; | 347 | return m; |
@@ -474,6 +497,9 @@ static int imxfb_bl_update_status(struct backlight_device *bl) | |||
474 | struct imxfb_info *fbi = bl_get_data(bl); | 497 | struct imxfb_info *fbi = bl_get_data(bl); |
475 | int brightness = bl->props.brightness; | 498 | int brightness = bl->props.brightness; |
476 | 499 | ||
500 | if (!fbi->pwmr) | ||
501 | return 0; | ||
502 | |||
477 | if (bl->props.power != FB_BLANK_UNBLANK) | 503 | if (bl->props.power != FB_BLANK_UNBLANK) |
478 | brightness = 0; | 504 | brightness = 0; |
479 | if (bl->props.fb_blank != FB_BLANK_UNBLANK) | 505 | if (bl->props.fb_blank != FB_BLANK_UNBLANK) |
@@ -684,10 +710,14 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf | |||
684 | 710 | ||
685 | writel(fbi->pcr, fbi->regs + LCDC_PCR); | 711 | writel(fbi->pcr, fbi->regs + LCDC_PCR); |
686 | #ifndef PWMR_BACKLIGHT_AVAILABLE | 712 | #ifndef PWMR_BACKLIGHT_AVAILABLE |
687 | writel(fbi->pwmr, fbi->regs + LCDC_PWMR); | 713 | if (fbi->pwmr) |
714 | writel(fbi->pwmr, fbi->regs + LCDC_PWMR); | ||
688 | #endif | 715 | #endif |
689 | writel(fbi->lscr1, fbi->regs + LCDC_LSCR1); | 716 | writel(fbi->lscr1, fbi->regs + LCDC_LSCR1); |
690 | writel(fbi->dmacr, fbi->regs + LCDC_DMACR); | 717 | |
718 | /* dmacr = 0 is no valid value, as we need DMA control marks. */ | ||
719 | if (fbi->dmacr) | ||
720 | writel(fbi->dmacr, fbi->regs + LCDC_DMACR); | ||
691 | 721 | ||
692 | return 0; | 722 | return 0; |
693 | } | 723 | } |
@@ -723,13 +753,12 @@ static int imxfb_resume(struct platform_device *dev) | |||
723 | #define imxfb_resume NULL | 753 | #define imxfb_resume NULL |
724 | #endif | 754 | #endif |
725 | 755 | ||
726 | static int __init imxfb_init_fbinfo(struct platform_device *pdev) | 756 | static int imxfb_init_fbinfo(struct platform_device *pdev) |
727 | { | 757 | { |
728 | struct imx_fb_platform_data *pdata = pdev->dev.platform_data; | 758 | struct imx_fb_platform_data *pdata = pdev->dev.platform_data; |
729 | struct fb_info *info = dev_get_drvdata(&pdev->dev); | 759 | struct fb_info *info = dev_get_drvdata(&pdev->dev); |
730 | struct imxfb_info *fbi = info->par; | 760 | struct imxfb_info *fbi = info->par; |
731 | struct imx_fb_videomode *m; | 761 | struct device_node *np; |
732 | int i; | ||
733 | 762 | ||
734 | pr_debug("%s\n",__func__); | 763 | pr_debug("%s\n",__func__); |
735 | 764 | ||
@@ -760,41 +789,95 @@ static int __init imxfb_init_fbinfo(struct platform_device *pdev) | |||
760 | info->fbops = &imxfb_ops; | 789 | info->fbops = &imxfb_ops; |
761 | info->flags = FBINFO_FLAG_DEFAULT | | 790 | info->flags = FBINFO_FLAG_DEFAULT | |
762 | FBINFO_READS_FAST; | 791 | FBINFO_READS_FAST; |
763 | info->var.grayscale = pdata->cmap_greyscale; | 792 | if (pdata) { |
764 | fbi->cmap_inverse = pdata->cmap_inverse; | 793 | info->var.grayscale = pdata->cmap_greyscale; |
765 | fbi->cmap_static = pdata->cmap_static; | 794 | fbi->cmap_inverse = pdata->cmap_inverse; |
766 | fbi->lscr1 = pdata->lscr1; | 795 | fbi->cmap_static = pdata->cmap_static; |
767 | fbi->dmacr = pdata->dmacr; | 796 | fbi->lscr1 = pdata->lscr1; |
768 | fbi->pwmr = pdata->pwmr; | 797 | fbi->dmacr = pdata->dmacr; |
769 | fbi->lcd_power = pdata->lcd_power; | 798 | fbi->pwmr = pdata->pwmr; |
770 | fbi->backlight_power = pdata->backlight_power; | 799 | fbi->lcd_power = pdata->lcd_power; |
771 | 800 | fbi->backlight_power = pdata->backlight_power; | |
772 | for (i = 0, m = &pdata->mode[0]; i < pdata->num_modes; i++, m++) | 801 | } else { |
773 | info->fix.smem_len = max_t(size_t, info->fix.smem_len, | 802 | np = pdev->dev.of_node; |
774 | m->mode.xres * m->mode.yres * m->bpp / 8); | 803 | info->var.grayscale = of_property_read_bool(np, |
804 | "cmap-greyscale"); | ||
805 | fbi->cmap_inverse = of_property_read_bool(np, "cmap-inverse"); | ||
806 | fbi->cmap_static = of_property_read_bool(np, "cmap-static"); | ||
807 | |||
808 | fbi->lscr1 = IMXFB_LSCR1_DEFAULT; | ||
809 | of_property_read_u32(np, "fsl,lscr1", &fbi->lscr1); | ||
810 | |||
811 | of_property_read_u32(np, "fsl,dmacr", &fbi->dmacr); | ||
812 | |||
813 | /* These two function pointers could be used by some specific | ||
814 | * platforms. */ | ||
815 | fbi->lcd_power = NULL; | ||
816 | fbi->backlight_power = NULL; | ||
817 | } | ||
775 | 818 | ||
776 | return 0; | 819 | return 0; |
777 | } | 820 | } |
778 | 821 | ||
779 | static int __init imxfb_probe(struct platform_device *pdev) | 822 | static int imxfb_of_read_mode(struct device *dev, struct device_node *np, |
823 | struct imx_fb_videomode *imxfb_mode) | ||
824 | { | ||
825 | int ret; | ||
826 | struct fb_videomode *of_mode = &imxfb_mode->mode; | ||
827 | u32 bpp; | ||
828 | u32 pcr; | ||
829 | |||
830 | ret = of_property_read_string(np, "model", &of_mode->name); | ||
831 | if (ret) | ||
832 | of_mode->name = NULL; | ||
833 | |||
834 | ret = of_get_fb_videomode(np, of_mode, OF_USE_NATIVE_MODE); | ||
835 | if (ret) { | ||
836 | dev_err(dev, "Failed to get videomode from DT\n"); | ||
837 | return ret; | ||
838 | } | ||
839 | |||
840 | ret = of_property_read_u32(np, "bits-per-pixel", &bpp); | ||
841 | ret |= of_property_read_u32(np, "fsl,pcr", &pcr); | ||
842 | |||
843 | if (ret) { | ||
844 | dev_err(dev, "Failed to read bpp and pcr from DT\n"); | ||
845 | return -EINVAL; | ||
846 | } | ||
847 | |||
848 | if (bpp < 1 || bpp > 255) { | ||
849 | dev_err(dev, "Bits per pixel have to be between 1 and 255\n"); | ||
850 | return -EINVAL; | ||
851 | } | ||
852 | |||
853 | imxfb_mode->bpp = bpp; | ||
854 | imxfb_mode->pcr = pcr; | ||
855 | |||
856 | return 0; | ||
857 | } | ||
858 | |||
859 | static int imxfb_probe(struct platform_device *pdev) | ||
780 | { | 860 | { |
781 | struct imxfb_info *fbi; | 861 | struct imxfb_info *fbi; |
782 | struct fb_info *info; | 862 | struct fb_info *info; |
783 | struct imx_fb_platform_data *pdata; | 863 | struct imx_fb_platform_data *pdata; |
784 | struct resource *res; | 864 | struct resource *res; |
865 | struct imx_fb_videomode *m; | ||
866 | const struct of_device_id *of_id; | ||
785 | int ret, i; | 867 | int ret, i; |
868 | int bytes_per_pixel; | ||
786 | 869 | ||
787 | dev_info(&pdev->dev, "i.MX Framebuffer driver\n"); | 870 | dev_info(&pdev->dev, "i.MX Framebuffer driver\n"); |
788 | 871 | ||
872 | of_id = of_match_device(imxfb_of_dev_id, &pdev->dev); | ||
873 | if (of_id) | ||
874 | pdev->id_entry = of_id->data; | ||
875 | |||
789 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 876 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
790 | if (!res) | 877 | if (!res) |
791 | return -ENODEV; | 878 | return -ENODEV; |
792 | 879 | ||
793 | pdata = pdev->dev.platform_data; | 880 | pdata = pdev->dev.platform_data; |
794 | if (!pdata) { | ||
795 | dev_err(&pdev->dev,"No platform_data available\n"); | ||
796 | return -ENOMEM; | ||
797 | } | ||
798 | 881 | ||
799 | info = framebuffer_alloc(sizeof(struct imxfb_info), &pdev->dev); | 882 | info = framebuffer_alloc(sizeof(struct imxfb_info), &pdev->dev); |
800 | if (!info) | 883 | if (!info) |
@@ -802,15 +885,55 @@ static int __init imxfb_probe(struct platform_device *pdev) | |||
802 | 885 | ||
803 | fbi = info->par; | 886 | fbi = info->par; |
804 | 887 | ||
805 | if (!fb_mode) | ||
806 | fb_mode = pdata->mode[0].mode.name; | ||
807 | |||
808 | platform_set_drvdata(pdev, info); | 888 | platform_set_drvdata(pdev, info); |
809 | 889 | ||
810 | ret = imxfb_init_fbinfo(pdev); | 890 | ret = imxfb_init_fbinfo(pdev); |
811 | if (ret < 0) | 891 | if (ret < 0) |
812 | goto failed_init; | 892 | goto failed_init; |
813 | 893 | ||
894 | if (pdata) { | ||
895 | if (!fb_mode) | ||
896 | fb_mode = pdata->mode[0].mode.name; | ||
897 | |||
898 | fbi->mode = pdata->mode; | ||
899 | fbi->num_modes = pdata->num_modes; | ||
900 | } else { | ||
901 | struct device_node *display_np; | ||
902 | fb_mode = NULL; | ||
903 | |||
904 | display_np = of_parse_phandle(pdev->dev.of_node, "display", 0); | ||
905 | if (!display_np) { | ||
906 | dev_err(&pdev->dev, "No display defined in devicetree\n"); | ||
907 | ret = -EINVAL; | ||
908 | goto failed_of_parse; | ||
909 | } | ||
910 | |||
911 | /* | ||
912 | * imxfb does not support more modes, we choose only the native | ||
913 | * mode. | ||
914 | */ | ||
915 | fbi->num_modes = 1; | ||
916 | |||
917 | fbi->mode = devm_kzalloc(&pdev->dev, | ||
918 | sizeof(struct imx_fb_videomode), GFP_KERNEL); | ||
919 | if (!fbi->mode) { | ||
920 | ret = -ENOMEM; | ||
921 | goto failed_of_parse; | ||
922 | } | ||
923 | |||
924 | ret = imxfb_of_read_mode(&pdev->dev, display_np, fbi->mode); | ||
925 | if (ret) | ||
926 | goto failed_of_parse; | ||
927 | } | ||
928 | |||
929 | /* Calculate maximum bytes used per pixel. In most cases this should | ||
930 | * be the same as m->bpp/8 */ | ||
931 | m = &fbi->mode[0]; | ||
932 | bytes_per_pixel = (m->bpp + 7) / 8; | ||
933 | for (i = 0; i < fbi->num_modes; i++, m++) | ||
934 | info->fix.smem_len = max_t(size_t, info->fix.smem_len, | ||
935 | m->mode.xres * m->mode.yres * bytes_per_pixel); | ||
936 | |||
814 | res = request_mem_region(res->start, resource_size(res), | 937 | res = request_mem_region(res->start, resource_size(res), |
815 | DRIVER_NAME); | 938 | DRIVER_NAME); |
816 | if (!res) { | 939 | if (!res) { |
@@ -843,7 +966,8 @@ static int __init imxfb_probe(struct platform_device *pdev) | |||
843 | goto failed_ioremap; | 966 | goto failed_ioremap; |
844 | } | 967 | } |
845 | 968 | ||
846 | if (!pdata->fixed_screen_cpu) { | 969 | /* Seems not being used by anyone, so no support for oftree */ |
970 | if (!pdata || !pdata->fixed_screen_cpu) { | ||
847 | fbi->map_size = PAGE_ALIGN(info->fix.smem_len); | 971 | fbi->map_size = PAGE_ALIGN(info->fix.smem_len); |
848 | fbi->map_cpu = dma_alloc_writecombine(&pdev->dev, | 972 | fbi->map_cpu = dma_alloc_writecombine(&pdev->dev, |
849 | fbi->map_size, &fbi->map_dma, GFP_KERNEL); | 973 | fbi->map_size, &fbi->map_dma, GFP_KERNEL); |
@@ -868,18 +992,16 @@ static int __init imxfb_probe(struct platform_device *pdev) | |||
868 | info->fix.smem_start = fbi->screen_dma; | 992 | info->fix.smem_start = fbi->screen_dma; |
869 | } | 993 | } |
870 | 994 | ||
871 | if (pdata->init) { | 995 | if (pdata && pdata->init) { |
872 | ret = pdata->init(fbi->pdev); | 996 | ret = pdata->init(fbi->pdev); |
873 | if (ret) | 997 | if (ret) |
874 | goto failed_platform_init; | 998 | goto failed_platform_init; |
875 | } | 999 | } |
876 | 1000 | ||
877 | fbi->mode = pdata->mode; | ||
878 | fbi->num_modes = pdata->num_modes; | ||
879 | 1001 | ||
880 | INIT_LIST_HEAD(&info->modelist); | 1002 | INIT_LIST_HEAD(&info->modelist); |
881 | for (i = 0; i < pdata->num_modes; i++) | 1003 | for (i = 0; i < fbi->num_modes; i++) |
882 | fb_add_videomode(&pdata->mode[i].mode, &info->modelist); | 1004 | fb_add_videomode(&fbi->mode[i].mode, &info->modelist); |
883 | 1005 | ||
884 | /* | 1006 | /* |
885 | * This makes sure that our colour bitfield | 1007 | * This makes sure that our colour bitfield |
@@ -909,10 +1031,10 @@ static int __init imxfb_probe(struct platform_device *pdev) | |||
909 | failed_register: | 1031 | failed_register: |
910 | fb_dealloc_cmap(&info->cmap); | 1032 | fb_dealloc_cmap(&info->cmap); |
911 | failed_cmap: | 1033 | failed_cmap: |
912 | if (pdata->exit) | 1034 | if (pdata && pdata->exit) |
913 | pdata->exit(fbi->pdev); | 1035 | pdata->exit(fbi->pdev); |
914 | failed_platform_init: | 1036 | failed_platform_init: |
915 | if (!pdata->fixed_screen_cpu) | 1037 | if (pdata && !pdata->fixed_screen_cpu) |
916 | dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu, | 1038 | dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu, |
917 | fbi->map_dma); | 1039 | fbi->map_dma); |
918 | failed_map: | 1040 | failed_map: |
@@ -921,9 +1043,9 @@ failed_ioremap: | |||
921 | failed_getclock: | 1043 | failed_getclock: |
922 | release_mem_region(res->start, resource_size(res)); | 1044 | release_mem_region(res->start, resource_size(res)); |
923 | failed_req: | 1045 | failed_req: |
1046 | failed_of_parse: | ||
924 | kfree(info->pseudo_palette); | 1047 | kfree(info->pseudo_palette); |
925 | failed_init: | 1048 | failed_init: |
926 | platform_set_drvdata(pdev, NULL); | ||
927 | framebuffer_release(info); | 1049 | framebuffer_release(info); |
928 | return ret; | 1050 | return ret; |
929 | } | 1051 | } |
@@ -945,7 +1067,7 @@ static int imxfb_remove(struct platform_device *pdev) | |||
945 | unregister_framebuffer(info); | 1067 | unregister_framebuffer(info); |
946 | 1068 | ||
947 | pdata = pdev->dev.platform_data; | 1069 | pdata = pdev->dev.platform_data; |
948 | if (pdata->exit) | 1070 | if (pdata && pdata->exit) |
949 | pdata->exit(fbi->pdev); | 1071 | pdata->exit(fbi->pdev); |
950 | 1072 | ||
951 | fb_dealloc_cmap(&info->cmap); | 1073 | fb_dealloc_cmap(&info->cmap); |
@@ -955,12 +1077,10 @@ static int imxfb_remove(struct platform_device *pdev) | |||
955 | iounmap(fbi->regs); | 1077 | iounmap(fbi->regs); |
956 | release_mem_region(res->start, resource_size(res)); | 1078 | release_mem_region(res->start, resource_size(res)); |
957 | 1079 | ||
958 | platform_set_drvdata(pdev, NULL); | ||
959 | |||
960 | return 0; | 1080 | return 0; |
961 | } | 1081 | } |
962 | 1082 | ||
963 | void imxfb_shutdown(struct platform_device * dev) | 1083 | static void imxfb_shutdown(struct platform_device *dev) |
964 | { | 1084 | { |
965 | struct fb_info *info = platform_get_drvdata(dev); | 1085 | struct fb_info *info = platform_get_drvdata(dev); |
966 | struct imxfb_info *fbi = info->par; | 1086 | struct imxfb_info *fbi = info->par; |
@@ -974,6 +1094,7 @@ static struct platform_driver imxfb_driver = { | |||
974 | .shutdown = imxfb_shutdown, | 1094 | .shutdown = imxfb_shutdown, |
975 | .driver = { | 1095 | .driver = { |
976 | .name = DRIVER_NAME, | 1096 | .name = DRIVER_NAME, |
1097 | .of_match_table = imxfb_of_dev_id, | ||
977 | }, | 1098 | }, |
978 | .id_table = imxfb_devtype, | 1099 | .id_table = imxfb_devtype, |
979 | }; | 1100 | }; |
@@ -999,7 +1120,7 @@ static int imxfb_setup(void) | |||
999 | return 0; | 1120 | return 0; |
1000 | } | 1121 | } |
1001 | 1122 | ||
1002 | int __init imxfb_init(void) | 1123 | static int __init imxfb_init(void) |
1003 | { | 1124 | { |
1004 | int ret = imxfb_setup(); | 1125 | int ret = imxfb_setup(); |
1005 | 1126 | ||
diff --git a/drivers/video/jz4740_fb.c b/drivers/video/jz4740_fb.c index 36979b4131ab..2c49112fdd6c 100644 --- a/drivers/video/jz4740_fb.c +++ b/drivers/video/jz4740_fb.c | |||
@@ -737,8 +737,6 @@ static int jzfb_remove(struct platform_device *pdev) | |||
737 | fb_dealloc_cmap(&jzfb->fb->cmap); | 737 | fb_dealloc_cmap(&jzfb->fb->cmap); |
738 | jzfb_free_devmem(jzfb); | 738 | jzfb_free_devmem(jzfb); |
739 | 739 | ||
740 | platform_set_drvdata(pdev, NULL); | ||
741 | |||
742 | framebuffer_release(jzfb->fb); | 740 | framebuffer_release(jzfb->fb); |
743 | 741 | ||
744 | return 0; | 742 | return 0; |
diff --git a/drivers/video/mmp/fb/mmpfb.c b/drivers/video/mmp/fb/mmpfb.c index 6d1fa96c5cc3..4ab95b8daed3 100644 --- a/drivers/video/mmp/fb/mmpfb.c +++ b/drivers/video/mmp/fb/mmpfb.c | |||
@@ -659,7 +659,6 @@ failed_destroy_mutex: | |||
659 | mutex_destroy(&fbi->access_ok); | 659 | mutex_destroy(&fbi->access_ok); |
660 | failed: | 660 | failed: |
661 | dev_err(fbi->dev, "mmp-fb: frame buffer device init failed\n"); | 661 | dev_err(fbi->dev, "mmp-fb: frame buffer device init failed\n"); |
662 | platform_set_drvdata(pdev, NULL); | ||
663 | 662 | ||
664 | framebuffer_release(info); | 663 | framebuffer_release(info); |
665 | 664 | ||
diff --git a/drivers/video/mmp/hw/mmp_ctrl.c b/drivers/video/mmp/hw/mmp_ctrl.c index 4bd31b2af398..75dca19bf214 100644 --- a/drivers/video/mmp/hw/mmp_ctrl.c +++ b/drivers/video/mmp/hw/mmp_ctrl.c | |||
@@ -165,9 +165,9 @@ static void overlay_set_win(struct mmp_overlay *overlay, struct mmp_win *win) | |||
165 | 165 | ||
166 | static void dmafetch_onoff(struct mmp_overlay *overlay, int on) | 166 | static void dmafetch_onoff(struct mmp_overlay *overlay, int on) |
167 | { | 167 | { |
168 | u32 mask = overlay_is_vid(overlay) ? CFG_GRA_ENA_MASK : | 168 | u32 mask = overlay_is_vid(overlay) ? CFG_DMA_ENA_MASK : |
169 | CFG_DMA_ENA_MASK; | 169 | CFG_GRA_ENA_MASK; |
170 | u32 enable = overlay_is_vid(overlay) ? CFG_GRA_ENA(1) : CFG_DMA_ENA(1); | 170 | u32 enable = overlay_is_vid(overlay) ? CFG_DMA_ENA(1) : CFG_GRA_ENA(1); |
171 | u32 tmp; | 171 | u32 tmp; |
172 | struct mmp_path *path = overlay->path; | 172 | struct mmp_path *path = overlay->path; |
173 | 173 | ||
@@ -238,7 +238,7 @@ static int overlay_set_addr(struct mmp_overlay *overlay, struct mmp_addr *addr) | |||
238 | struct lcd_regs *regs = path_regs(overlay->path); | 238 | struct lcd_regs *regs = path_regs(overlay->path); |
239 | 239 | ||
240 | /* FIXME: assert addr supported */ | 240 | /* FIXME: assert addr supported */ |
241 | memcpy(&overlay->addr, addr, sizeof(struct mmp_win)); | 241 | memcpy(&overlay->addr, addr, sizeof(struct mmp_addr)); |
242 | writel(addr->phys[0], ®s->g_0); | 242 | writel(addr->phys[0], ®s->g_0); |
243 | 243 | ||
244 | return overlay->addr.phys[0]; | 244 | return overlay->addr.phys[0]; |
@@ -566,7 +566,6 @@ failed: | |||
566 | devm_kfree(ctrl->dev, ctrl); | 566 | devm_kfree(ctrl->dev, ctrl); |
567 | } | 567 | } |
568 | 568 | ||
569 | platform_set_drvdata(pdev, NULL); | ||
570 | dev_err(&pdev->dev, "device init failed\n"); | 569 | dev_err(&pdev->dev, "device init failed\n"); |
571 | 570 | ||
572 | return ret; | 571 | return ret; |
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c index 21223d475b39..3ba37713b1f9 100644 --- a/drivers/video/mxsfb.c +++ b/drivers/video/mxsfb.c | |||
@@ -899,7 +899,6 @@ static int mxsfb_probe(struct platform_device *pdev) | |||
899 | 899 | ||
900 | host->base = devm_ioremap_resource(&pdev->dev, res); | 900 | host->base = devm_ioremap_resource(&pdev->dev, res); |
901 | if (IS_ERR(host->base)) { | 901 | if (IS_ERR(host->base)) { |
902 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
903 | ret = PTR_ERR(host->base); | 902 | ret = PTR_ERR(host->base); |
904 | goto fb_release; | 903 | goto fb_release; |
905 | } | 904 | } |
@@ -986,8 +985,6 @@ static int mxsfb_remove(struct platform_device *pdev) | |||
986 | 985 | ||
987 | framebuffer_release(fb_info); | 986 | framebuffer_release(fb_info); |
988 | 987 | ||
989 | platform_set_drvdata(pdev, NULL); | ||
990 | |||
991 | return 0; | 988 | return 0; |
992 | } | 989 | } |
993 | 990 | ||
diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c index 32581c72ad09..8c527e5b293c 100644 --- a/drivers/video/nuc900fb.c +++ b/drivers/video/nuc900fb.c | |||
@@ -707,7 +707,6 @@ static int nuc900fb_remove(struct platform_device *pdev) | |||
707 | release_resource(fbi->mem); | 707 | release_resource(fbi->mem); |
708 | kfree(fbi->mem); | 708 | kfree(fbi->mem); |
709 | 709 | ||
710 | platform_set_drvdata(pdev, NULL); | ||
711 | framebuffer_release(fbinfo); | 710 | framebuffer_release(fbinfo); |
712 | 711 | ||
713 | return 0; | 712 | return 0; |
diff --git a/drivers/video/of_display_timing.c b/drivers/video/of_display_timing.c index 56009bc02b02..9c0f17b2e6fb 100644 --- a/drivers/video/of_display_timing.c +++ b/drivers/video/of_display_timing.c | |||
@@ -53,21 +53,16 @@ static int parse_timing_property(struct device_node *np, const char *name, | |||
53 | } | 53 | } |
54 | 54 | ||
55 | /** | 55 | /** |
56 | * of_get_display_timing - parse display_timing entry from device_node | 56 | * of_parse_display_timing - parse display_timing entry from device_node |
57 | * @np: device_node with the properties | 57 | * @np: device_node with the properties |
58 | **/ | 58 | **/ |
59 | static struct display_timing *of_get_display_timing(struct device_node *np) | 59 | static int of_parse_display_timing(struct device_node *np, |
60 | struct display_timing *dt) | ||
60 | { | 61 | { |
61 | struct display_timing *dt; | ||
62 | u32 val = 0; | 62 | u32 val = 0; |
63 | int ret = 0; | 63 | int ret = 0; |
64 | 64 | ||
65 | dt = kzalloc(sizeof(*dt), GFP_KERNEL); | 65 | memset(dt, 0, sizeof(*dt)); |
66 | if (!dt) { | ||
67 | pr_err("%s: could not allocate display_timing struct\n", | ||
68 | of_node_full_name(np)); | ||
69 | return NULL; | ||
70 | } | ||
71 | 66 | ||
72 | ret |= parse_timing_property(np, "hback-porch", &dt->hback_porch); | 67 | ret |= parse_timing_property(np, "hback-porch", &dt->hback_porch); |
73 | ret |= parse_timing_property(np, "hfront-porch", &dt->hfront_porch); | 68 | ret |= parse_timing_property(np, "hfront-porch", &dt->hfront_porch); |
@@ -101,12 +96,38 @@ static struct display_timing *of_get_display_timing(struct device_node *np) | |||
101 | if (ret) { | 96 | if (ret) { |
102 | pr_err("%s: error reading timing properties\n", | 97 | pr_err("%s: error reading timing properties\n", |
103 | of_node_full_name(np)); | 98 | of_node_full_name(np)); |
104 | kfree(dt); | 99 | return -EINVAL; |
105 | return NULL; | 100 | } |
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | /** | ||
106 | * of_get_display_timing - parse a display_timing entry | ||
107 | * @np: device_node with the timing subnode | ||
108 | * @name: name of the timing node | ||
109 | * @dt: display_timing struct to fill | ||
110 | **/ | ||
111 | int of_get_display_timing(struct device_node *np, const char *name, | ||
112 | struct display_timing *dt) | ||
113 | { | ||
114 | struct device_node *timing_np; | ||
115 | |||
116 | if (!np) { | ||
117 | pr_err("%s: no devicenode given\n", of_node_full_name(np)); | ||
118 | return -EINVAL; | ||
106 | } | 119 | } |
107 | 120 | ||
108 | return dt; | 121 | timing_np = of_find_node_by_name(np, name); |
122 | if (!timing_np) { | ||
123 | pr_err("%s: could not find node '%s'\n", | ||
124 | of_node_full_name(np), name); | ||
125 | return -ENOENT; | ||
126 | } | ||
127 | |||
128 | return of_parse_display_timing(timing_np, dt); | ||
109 | } | 129 | } |
130 | EXPORT_SYMBOL_GPL(of_get_display_timing); | ||
110 | 131 | ||
111 | /** | 132 | /** |
112 | * of_get_display_timings - parse all display_timing entries from a device_node | 133 | * of_get_display_timings - parse all display_timing entries from a device_node |
@@ -174,9 +195,17 @@ struct display_timings *of_get_display_timings(struct device_node *np) | |||
174 | 195 | ||
175 | for_each_child_of_node(timings_np, entry) { | 196 | for_each_child_of_node(timings_np, entry) { |
176 | struct display_timing *dt; | 197 | struct display_timing *dt; |
198 | int r; | ||
177 | 199 | ||
178 | dt = of_get_display_timing(entry); | 200 | dt = kzalloc(sizeof(*dt), GFP_KERNEL); |
179 | if (!dt) { | 201 | if (!dt) { |
202 | pr_err("%s: could not allocate display_timing struct\n", | ||
203 | of_node_full_name(np)); | ||
204 | goto timingfail; | ||
205 | } | ||
206 | |||
207 | r = of_parse_display_timing(entry, dt); | ||
208 | if (r) { | ||
180 | /* | 209 | /* |
181 | * to not encourage wrong devicetrees, fail in case of | 210 | * to not encourage wrong devicetrees, fail in case of |
182 | * an error | 211 | * an error |
diff --git a/drivers/video/omap2/Kconfig b/drivers/video/omap2/Kconfig index b07b2b042e7e..56cad0f5386c 100644 --- a/drivers/video/omap2/Kconfig +++ b/drivers/video/omap2/Kconfig | |||
@@ -6,5 +6,6 @@ if ARCH_OMAP2PLUS | |||
6 | source "drivers/video/omap2/dss/Kconfig" | 6 | source "drivers/video/omap2/dss/Kconfig" |
7 | source "drivers/video/omap2/omapfb/Kconfig" | 7 | source "drivers/video/omap2/omapfb/Kconfig" |
8 | source "drivers/video/omap2/displays/Kconfig" | 8 | source "drivers/video/omap2/displays/Kconfig" |
9 | source "drivers/video/omap2/displays-new/Kconfig" | ||
9 | 10 | ||
10 | endif | 11 | endif |
diff --git a/drivers/video/omap2/Makefile b/drivers/video/omap2/Makefile index 296e5c5281c5..86873c2fbb27 100644 --- a/drivers/video/omap2/Makefile +++ b/drivers/video/omap2/Makefile | |||
@@ -2,4 +2,5 @@ obj-$(CONFIG_OMAP2_VRFB) += vrfb.o | |||
2 | 2 | ||
3 | obj-$(CONFIG_OMAP2_DSS) += dss/ | 3 | obj-$(CONFIG_OMAP2_DSS) += dss/ |
4 | obj-y += displays/ | 4 | obj-y += displays/ |
5 | obj-y += displays-new/ | ||
5 | obj-$(CONFIG_FB_OMAP2) += omapfb/ | 6 | obj-$(CONFIG_FB_OMAP2) += omapfb/ |
diff --git a/drivers/video/omap2/displays-new/Kconfig b/drivers/video/omap2/displays-new/Kconfig new file mode 100644 index 000000000000..6c90885b0940 --- /dev/null +++ b/drivers/video/omap2/displays-new/Kconfig | |||
@@ -0,0 +1,73 @@ | |||
1 | menu "OMAP Display Device Drivers (new device model)" | ||
2 | depends on OMAP2_DSS | ||
3 | |||
4 | config DISPLAY_ENCODER_TFP410 | ||
5 | tristate "TFP410 DPI to DVI Encoder" | ||
6 | help | ||
7 | Driver for TFP410 DPI to DVI encoder. | ||
8 | |||
9 | config DISPLAY_ENCODER_TPD12S015 | ||
10 | tristate "TPD12S015 HDMI ESD protection and level shifter" | ||
11 | help | ||
12 | Driver for TPD12S015, which offers HDMI ESD protection and level | ||
13 | shifting. | ||
14 | |||
15 | config DISPLAY_CONNECTOR_DVI | ||
16 | tristate "DVI Connector" | ||
17 | depends on I2C | ||
18 | help | ||
19 | Driver for a generic DVI connector. | ||
20 | |||
21 | config DISPLAY_CONNECTOR_HDMI | ||
22 | tristate "HDMI Connector" | ||
23 | help | ||
24 | Driver for a generic HDMI connector. | ||
25 | |||
26 | config DISPLAY_CONNECTOR_ANALOG_TV | ||
27 | tristate "Analog TV Connector" | ||
28 | help | ||
29 | Driver for a generic analog TV connector. | ||
30 | |||
31 | config DISPLAY_PANEL_DPI | ||
32 | tristate "Generic DPI panel" | ||
33 | help | ||
34 | Driver for generic DPI panels. | ||
35 | |||
36 | config DISPLAY_PANEL_DSI_CM | ||
37 | tristate "Generic DSI Command Mode Panel" | ||
38 | help | ||
39 | Driver for generic DSI command mode panels. | ||
40 | |||
41 | config DISPLAY_PANEL_SONY_ACX565AKM | ||
42 | tristate "ACX565AKM Panel" | ||
43 | depends on SPI && BACKLIGHT_CLASS_DEVICE | ||
44 | help | ||
45 | This is the LCD panel used on Nokia N900 | ||
46 | |||
47 | config DISPLAY_PANEL_LGPHILIPS_LB035Q02 | ||
48 | tristate "LG.Philips LB035Q02 LCD Panel" | ||
49 | depends on SPI | ||
50 | help | ||
51 | LCD Panel used on the Gumstix Overo Palo35 | ||
52 | |||
53 | config DISPLAY_PANEL_SHARP_LS037V7DW01 | ||
54 | tristate "Sharp LS037V7DW01 LCD Panel" | ||
55 | depends on BACKLIGHT_CLASS_DEVICE | ||
56 | help | ||
57 | LCD Panel used in TI's SDP3430 and EVM boards | ||
58 | |||
59 | config DISPLAY_PANEL_TPO_TD043MTEA1 | ||
60 | tristate "TPO TD043MTEA1 LCD Panel" | ||
61 | depends on SPI | ||
62 | help | ||
63 | LCD Panel used in OMAP3 Pandora | ||
64 | |||
65 | config DISPLAY_PANEL_NEC_NL8048HL11 | ||
66 | tristate "NEC NL8048HL11 Panel" | ||
67 | depends on SPI | ||
68 | depends on BACKLIGHT_CLASS_DEVICE | ||
69 | help | ||
70 | This NEC NL8048HL11 panel is TFT LCD used in the | ||
71 | Zoom2/3/3630 sdp boards. | ||
72 | |||
73 | endmenu | ||
diff --git a/drivers/video/omap2/displays-new/Makefile b/drivers/video/omap2/displays-new/Makefile new file mode 100644 index 000000000000..5aeb11b8fcd5 --- /dev/null +++ b/drivers/video/omap2/displays-new/Makefile | |||
@@ -0,0 +1,12 @@ | |||
1 | obj-$(CONFIG_DISPLAY_ENCODER_TFP410) += encoder-tfp410.o | ||
2 | obj-$(CONFIG_DISPLAY_ENCODER_TPD12S015) += encoder-tpd12s015.o | ||
3 | obj-$(CONFIG_DISPLAY_CONNECTOR_DVI) += connector-dvi.o | ||
4 | obj-$(CONFIG_DISPLAY_CONNECTOR_HDMI) += connector-hdmi.o | ||
5 | obj-$(CONFIG_DISPLAY_CONNECTOR_ANALOG_TV) += connector-analog-tv.o | ||
6 | obj-$(CONFIG_DISPLAY_PANEL_DPI) += panel-dpi.o | ||
7 | obj-$(CONFIG_DISPLAY_PANEL_DSI_CM) += panel-dsi-cm.o | ||
8 | obj-$(CONFIG_DISPLAY_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o | ||
9 | obj-$(CONFIG_DISPLAY_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o | ||
10 | obj-$(CONFIG_DISPLAY_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o | ||
11 | obj-$(CONFIG_DISPLAY_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o | ||
12 | obj-$(CONFIG_DISPLAY_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o | ||
diff --git a/drivers/video/omap2/displays-new/connector-analog-tv.c b/drivers/video/omap2/displays-new/connector-analog-tv.c new file mode 100644 index 000000000000..5338f362293b --- /dev/null +++ b/drivers/video/omap2/displays-new/connector-analog-tv.c | |||
@@ -0,0 +1,265 @@ | |||
1 | /* | ||
2 | * Analog TV Connector driver | ||
3 | * | ||
4 | * Copyright (C) 2013 Texas Instruments | ||
5 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> | ||
6 | * | ||
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. | ||
10 | */ | ||
11 | |||
12 | #include <linux/slab.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | |||
16 | #include <video/omapdss.h> | ||
17 | #include <video/omap-panel-data.h> | ||
18 | |||
19 | struct panel_drv_data { | ||
20 | struct omap_dss_device dssdev; | ||
21 | struct omap_dss_device *in; | ||
22 | |||
23 | struct device *dev; | ||
24 | |||
25 | struct omap_video_timings timings; | ||
26 | |||
27 | enum omap_dss_venc_type connector_type; | ||
28 | bool invert_polarity; | ||
29 | }; | ||
30 | |||
31 | #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) | ||
32 | |||
33 | static int tvc_connect(struct omap_dss_device *dssdev) | ||
34 | { | ||
35 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
36 | struct omap_dss_device *in = ddata->in; | ||
37 | int r; | ||
38 | |||
39 | dev_dbg(ddata->dev, "connect\n"); | ||
40 | |||
41 | if (omapdss_device_is_connected(dssdev)) | ||
42 | return 0; | ||
43 | |||
44 | r = in->ops.atv->connect(in, dssdev); | ||
45 | if (r) | ||
46 | return r; | ||
47 | |||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | static void tvc_disconnect(struct omap_dss_device *dssdev) | ||
52 | { | ||
53 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
54 | struct omap_dss_device *in = ddata->in; | ||
55 | |||
56 | dev_dbg(ddata->dev, "disconnect\n"); | ||
57 | |||
58 | if (!omapdss_device_is_connected(dssdev)) | ||
59 | return; | ||
60 | |||
61 | in->ops.atv->disconnect(in, dssdev); | ||
62 | } | ||
63 | |||
64 | static int tvc_enable(struct omap_dss_device *dssdev) | ||
65 | { | ||
66 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
67 | struct omap_dss_device *in = ddata->in; | ||
68 | int r; | ||
69 | |||
70 | dev_dbg(ddata->dev, "enable\n"); | ||
71 | |||
72 | if (!omapdss_device_is_connected(dssdev)) | ||
73 | return -ENODEV; | ||
74 | |||
75 | if (omapdss_device_is_enabled(dssdev)) | ||
76 | return 0; | ||
77 | |||
78 | in->ops.atv->set_timings(in, &ddata->timings); | ||
79 | |||
80 | in->ops.atv->set_type(in, ddata->connector_type); | ||
81 | in->ops.atv->invert_vid_out_polarity(in, ddata->invert_polarity); | ||
82 | |||
83 | r = in->ops.atv->enable(in); | ||
84 | if (r) | ||
85 | return r; | ||
86 | |||
87 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
88 | |||
89 | return r; | ||
90 | } | ||
91 | |||
92 | static void tvc_disable(struct omap_dss_device *dssdev) | ||
93 | { | ||
94 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
95 | struct omap_dss_device *in = ddata->in; | ||
96 | |||
97 | dev_dbg(ddata->dev, "disable\n"); | ||
98 | |||
99 | if (!omapdss_device_is_enabled(dssdev)) | ||
100 | return; | ||
101 | |||
102 | in->ops.atv->disable(in); | ||
103 | |||
104 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
105 | } | ||
106 | |||
107 | static void tvc_set_timings(struct omap_dss_device *dssdev, | ||
108 | struct omap_video_timings *timings) | ||
109 | { | ||
110 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
111 | struct omap_dss_device *in = ddata->in; | ||
112 | |||
113 | ddata->timings = *timings; | ||
114 | dssdev->panel.timings = *timings; | ||
115 | |||
116 | in->ops.atv->set_timings(in, timings); | ||
117 | } | ||
118 | |||
119 | static void tvc_get_timings(struct omap_dss_device *dssdev, | ||
120 | struct omap_video_timings *timings) | ||
121 | { | ||
122 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
123 | |||
124 | *timings = ddata->timings; | ||
125 | } | ||
126 | |||
127 | static int tvc_check_timings(struct omap_dss_device *dssdev, | ||
128 | struct omap_video_timings *timings) | ||
129 | { | ||
130 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
131 | struct omap_dss_device *in = ddata->in; | ||
132 | |||
133 | return in->ops.atv->check_timings(in, timings); | ||
134 | } | ||
135 | |||
136 | static u32 tvc_get_wss(struct omap_dss_device *dssdev) | ||
137 | { | ||
138 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
139 | struct omap_dss_device *in = ddata->in; | ||
140 | |||
141 | return in->ops.atv->get_wss(in); | ||
142 | } | ||
143 | |||
144 | static int tvc_set_wss(struct omap_dss_device *dssdev, u32 wss) | ||
145 | { | ||
146 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
147 | struct omap_dss_device *in = ddata->in; | ||
148 | |||
149 | return in->ops.atv->set_wss(in, wss); | ||
150 | } | ||
151 | |||
152 | static struct omap_dss_driver tvc_driver = { | ||
153 | .connect = tvc_connect, | ||
154 | .disconnect = tvc_disconnect, | ||
155 | |||
156 | .enable = tvc_enable, | ||
157 | .disable = tvc_disable, | ||
158 | |||
159 | .set_timings = tvc_set_timings, | ||
160 | .get_timings = tvc_get_timings, | ||
161 | .check_timings = tvc_check_timings, | ||
162 | |||
163 | .get_resolution = omapdss_default_get_resolution, | ||
164 | |||
165 | .get_wss = tvc_get_wss, | ||
166 | .set_wss = tvc_set_wss, | ||
167 | }; | ||
168 | |||
169 | static int tvc_probe_pdata(struct platform_device *pdev) | ||
170 | { | ||
171 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
172 | struct connector_atv_platform_data *pdata; | ||
173 | struct omap_dss_device *in, *dssdev; | ||
174 | |||
175 | pdata = dev_get_platdata(&pdev->dev); | ||
176 | |||
177 | in = omap_dss_find_output(pdata->source); | ||
178 | if (in == NULL) { | ||
179 | dev_err(&pdev->dev, "Failed to find video source\n"); | ||
180 | return -ENODEV; | ||
181 | } | ||
182 | |||
183 | ddata->in = in; | ||
184 | |||
185 | ddata->connector_type = pdata->connector_type; | ||
186 | ddata->invert_polarity = ddata->invert_polarity; | ||
187 | |||
188 | dssdev = &ddata->dssdev; | ||
189 | dssdev->name = pdata->name; | ||
190 | |||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static int tvc_probe(struct platform_device *pdev) | ||
195 | { | ||
196 | struct panel_drv_data *ddata; | ||
197 | struct omap_dss_device *dssdev; | ||
198 | int r; | ||
199 | |||
200 | ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); | ||
201 | if (!ddata) | ||
202 | return -ENOMEM; | ||
203 | |||
204 | platform_set_drvdata(pdev, ddata); | ||
205 | ddata->dev = &pdev->dev; | ||
206 | |||
207 | if (dev_get_platdata(&pdev->dev)) { | ||
208 | r = tvc_probe_pdata(pdev); | ||
209 | if (r) | ||
210 | return r; | ||
211 | } else { | ||
212 | return -ENODEV; | ||
213 | } | ||
214 | |||
215 | ddata->timings = omap_dss_pal_timings; | ||
216 | |||
217 | dssdev = &ddata->dssdev; | ||
218 | dssdev->driver = &tvc_driver; | ||
219 | dssdev->dev = &pdev->dev; | ||
220 | dssdev->type = OMAP_DISPLAY_TYPE_VENC; | ||
221 | dssdev->owner = THIS_MODULE; | ||
222 | dssdev->panel.timings = omap_dss_pal_timings; | ||
223 | |||
224 | r = omapdss_register_display(dssdev); | ||
225 | if (r) { | ||
226 | dev_err(&pdev->dev, "Failed to register panel\n"); | ||
227 | goto err_reg; | ||
228 | } | ||
229 | |||
230 | return 0; | ||
231 | err_reg: | ||
232 | omap_dss_put_device(ddata->in); | ||
233 | return r; | ||
234 | } | ||
235 | |||
236 | static int __exit tvc_remove(struct platform_device *pdev) | ||
237 | { | ||
238 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
239 | struct omap_dss_device *dssdev = &ddata->dssdev; | ||
240 | struct omap_dss_device *in = ddata->in; | ||
241 | |||
242 | omapdss_unregister_display(&ddata->dssdev); | ||
243 | |||
244 | tvc_disable(dssdev); | ||
245 | tvc_disconnect(dssdev); | ||
246 | |||
247 | omap_dss_put_device(in); | ||
248 | |||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | static struct platform_driver tvc_connector_driver = { | ||
253 | .probe = tvc_probe, | ||
254 | .remove = __exit_p(tvc_remove), | ||
255 | .driver = { | ||
256 | .name = "connector-analog-tv", | ||
257 | .owner = THIS_MODULE, | ||
258 | }, | ||
259 | }; | ||
260 | |||
261 | module_platform_driver(tvc_connector_driver); | ||
262 | |||
263 | MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); | ||
264 | MODULE_DESCRIPTION("Analog TV Connector driver"); | ||
265 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays-new/connector-dvi.c b/drivers/video/omap2/displays-new/connector-dvi.c new file mode 100644 index 000000000000..bc5f8ceda371 --- /dev/null +++ b/drivers/video/omap2/displays-new/connector-dvi.c | |||
@@ -0,0 +1,351 @@ | |||
1 | /* | ||
2 | * Generic DVI Connector driver | ||
3 | * | ||
4 | * Copyright (C) 2013 Texas Instruments | ||
5 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> | ||
6 | * | ||
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. | ||
10 | */ | ||
11 | |||
12 | #include <linux/i2c.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/slab.h> | ||
16 | |||
17 | #include <drm/drm_edid.h> | ||
18 | |||
19 | #include <video/omapdss.h> | ||
20 | #include <video/omap-panel-data.h> | ||
21 | |||
22 | static const struct omap_video_timings dvic_default_timings = { | ||
23 | .x_res = 640, | ||
24 | .y_res = 480, | ||
25 | |||
26 | .pixel_clock = 23500, | ||
27 | |||
28 | .hfp = 48, | ||
29 | .hsw = 32, | ||
30 | .hbp = 80, | ||
31 | |||
32 | .vfp = 3, | ||
33 | .vsw = 4, | ||
34 | .vbp = 7, | ||
35 | |||
36 | .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
37 | .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
38 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
39 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
40 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
41 | }; | ||
42 | |||
43 | struct panel_drv_data { | ||
44 | struct omap_dss_device dssdev; | ||
45 | struct omap_dss_device *in; | ||
46 | |||
47 | struct omap_video_timings timings; | ||
48 | |||
49 | struct i2c_adapter *i2c_adapter; | ||
50 | }; | ||
51 | |||
52 | #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) | ||
53 | |||
54 | static int dvic_connect(struct omap_dss_device *dssdev) | ||
55 | { | ||
56 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
57 | struct omap_dss_device *in = ddata->in; | ||
58 | int r; | ||
59 | |||
60 | if (omapdss_device_is_connected(dssdev)) | ||
61 | return 0; | ||
62 | |||
63 | r = in->ops.dvi->connect(in, dssdev); | ||
64 | if (r) | ||
65 | return r; | ||
66 | |||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | static void dvic_disconnect(struct omap_dss_device *dssdev) | ||
71 | { | ||
72 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
73 | struct omap_dss_device *in = ddata->in; | ||
74 | |||
75 | if (!omapdss_device_is_connected(dssdev)) | ||
76 | return; | ||
77 | |||
78 | in->ops.dvi->disconnect(in, dssdev); | ||
79 | } | ||
80 | |||
81 | static int dvic_enable(struct omap_dss_device *dssdev) | ||
82 | { | ||
83 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
84 | struct omap_dss_device *in = ddata->in; | ||
85 | int r; | ||
86 | |||
87 | if (!omapdss_device_is_connected(dssdev)) | ||
88 | return -ENODEV; | ||
89 | |||
90 | if (omapdss_device_is_enabled(dssdev)) | ||
91 | return 0; | ||
92 | |||
93 | in->ops.dvi->set_timings(in, &ddata->timings); | ||
94 | |||
95 | r = in->ops.dvi->enable(in); | ||
96 | if (r) | ||
97 | return r; | ||
98 | |||
99 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static void dvic_disable(struct omap_dss_device *dssdev) | ||
105 | { | ||
106 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
107 | struct omap_dss_device *in = ddata->in; | ||
108 | |||
109 | if (!omapdss_device_is_enabled(dssdev)) | ||
110 | return; | ||
111 | |||
112 | in->ops.dvi->disable(in); | ||
113 | |||
114 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
115 | } | ||
116 | |||
117 | static void dvic_set_timings(struct omap_dss_device *dssdev, | ||
118 | struct omap_video_timings *timings) | ||
119 | { | ||
120 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
121 | struct omap_dss_device *in = ddata->in; | ||
122 | |||
123 | ddata->timings = *timings; | ||
124 | dssdev->panel.timings = *timings; | ||
125 | |||
126 | in->ops.dvi->set_timings(in, timings); | ||
127 | } | ||
128 | |||
129 | static void dvic_get_timings(struct omap_dss_device *dssdev, | ||
130 | struct omap_video_timings *timings) | ||
131 | { | ||
132 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
133 | |||
134 | *timings = ddata->timings; | ||
135 | } | ||
136 | |||
137 | static int dvic_check_timings(struct omap_dss_device *dssdev, | ||
138 | struct omap_video_timings *timings) | ||
139 | { | ||
140 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
141 | struct omap_dss_device *in = ddata->in; | ||
142 | |||
143 | return in->ops.dvi->check_timings(in, timings); | ||
144 | } | ||
145 | |||
146 | static int dvic_ddc_read(struct i2c_adapter *adapter, | ||
147 | unsigned char *buf, u16 count, u8 offset) | ||
148 | { | ||
149 | int r, retries; | ||
150 | |||
151 | for (retries = 3; retries > 0; retries--) { | ||
152 | struct i2c_msg msgs[] = { | ||
153 | { | ||
154 | .addr = DDC_ADDR, | ||
155 | .flags = 0, | ||
156 | .len = 1, | ||
157 | .buf = &offset, | ||
158 | }, { | ||
159 | .addr = DDC_ADDR, | ||
160 | .flags = I2C_M_RD, | ||
161 | .len = count, | ||
162 | .buf = buf, | ||
163 | } | ||
164 | }; | ||
165 | |||
166 | r = i2c_transfer(adapter, msgs, 2); | ||
167 | if (r == 2) | ||
168 | return 0; | ||
169 | |||
170 | if (r != -EAGAIN) | ||
171 | break; | ||
172 | } | ||
173 | |||
174 | return r < 0 ? r : -EIO; | ||
175 | } | ||
176 | |||
177 | static int dvic_read_edid(struct omap_dss_device *dssdev, | ||
178 | u8 *edid, int len) | ||
179 | { | ||
180 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
181 | int r, l, bytes_read; | ||
182 | |||
183 | if (!ddata->i2c_adapter) | ||
184 | return -ENODEV; | ||
185 | |||
186 | l = min(EDID_LENGTH, len); | ||
187 | r = dvic_ddc_read(ddata->i2c_adapter, edid, l, 0); | ||
188 | if (r) | ||
189 | return r; | ||
190 | |||
191 | bytes_read = l; | ||
192 | |||
193 | /* if there are extensions, read second block */ | ||
194 | if (len > EDID_LENGTH && edid[0x7e] > 0) { | ||
195 | l = min(EDID_LENGTH, len - EDID_LENGTH); | ||
196 | |||
197 | r = dvic_ddc_read(ddata->i2c_adapter, edid + EDID_LENGTH, | ||
198 | l, EDID_LENGTH); | ||
199 | if (r) | ||
200 | return r; | ||
201 | |||
202 | bytes_read += l; | ||
203 | } | ||
204 | |||
205 | return bytes_read; | ||
206 | } | ||
207 | |||
208 | static bool dvic_detect(struct omap_dss_device *dssdev) | ||
209 | { | ||
210 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
211 | unsigned char out; | ||
212 | int r; | ||
213 | |||
214 | if (!ddata->i2c_adapter) | ||
215 | return true; | ||
216 | |||
217 | r = dvic_ddc_read(ddata->i2c_adapter, &out, 1, 0); | ||
218 | |||
219 | return r == 0; | ||
220 | } | ||
221 | |||
222 | static struct omap_dss_driver dvic_driver = { | ||
223 | .connect = dvic_connect, | ||
224 | .disconnect = dvic_disconnect, | ||
225 | |||
226 | .enable = dvic_enable, | ||
227 | .disable = dvic_disable, | ||
228 | |||
229 | .set_timings = dvic_set_timings, | ||
230 | .get_timings = dvic_get_timings, | ||
231 | .check_timings = dvic_check_timings, | ||
232 | |||
233 | .get_resolution = omapdss_default_get_resolution, | ||
234 | |||
235 | .read_edid = dvic_read_edid, | ||
236 | .detect = dvic_detect, | ||
237 | }; | ||
238 | |||
239 | static int dvic_probe_pdata(struct platform_device *pdev) | ||
240 | { | ||
241 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
242 | struct connector_dvi_platform_data *pdata; | ||
243 | struct omap_dss_device *in, *dssdev; | ||
244 | int i2c_bus_num; | ||
245 | |||
246 | pdata = dev_get_platdata(&pdev->dev); | ||
247 | i2c_bus_num = pdata->i2c_bus_num; | ||
248 | |||
249 | if (i2c_bus_num != -1) { | ||
250 | struct i2c_adapter *adapter; | ||
251 | |||
252 | adapter = i2c_get_adapter(i2c_bus_num); | ||
253 | if (!adapter) { | ||
254 | dev_err(&pdev->dev, | ||
255 | "Failed to get I2C adapter, bus %d\n", | ||
256 | i2c_bus_num); | ||
257 | return -EPROBE_DEFER; | ||
258 | } | ||
259 | |||
260 | ddata->i2c_adapter = adapter; | ||
261 | } | ||
262 | |||
263 | in = omap_dss_find_output(pdata->source); | ||
264 | if (in == NULL) { | ||
265 | dev_err(&pdev->dev, "Failed to find video source\n"); | ||
266 | return -ENODEV; | ||
267 | } | ||
268 | |||
269 | ddata->in = in; | ||
270 | |||
271 | dssdev = &ddata->dssdev; | ||
272 | dssdev->name = pdata->name; | ||
273 | |||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | static int dvic_probe(struct platform_device *pdev) | ||
278 | { | ||
279 | struct panel_drv_data *ddata; | ||
280 | struct omap_dss_device *dssdev; | ||
281 | int r; | ||
282 | |||
283 | ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); | ||
284 | if (!ddata) | ||
285 | return -ENOMEM; | ||
286 | |||
287 | platform_set_drvdata(pdev, ddata); | ||
288 | |||
289 | if (dev_get_platdata(&pdev->dev)) { | ||
290 | r = dvic_probe_pdata(pdev); | ||
291 | if (r) | ||
292 | return r; | ||
293 | } else { | ||
294 | return -ENODEV; | ||
295 | } | ||
296 | |||
297 | ddata->timings = dvic_default_timings; | ||
298 | |||
299 | dssdev = &ddata->dssdev; | ||
300 | dssdev->driver = &dvic_driver; | ||
301 | dssdev->dev = &pdev->dev; | ||
302 | dssdev->type = OMAP_DISPLAY_TYPE_DVI; | ||
303 | dssdev->owner = THIS_MODULE; | ||
304 | dssdev->panel.timings = dvic_default_timings; | ||
305 | |||
306 | r = omapdss_register_display(dssdev); | ||
307 | if (r) { | ||
308 | dev_err(&pdev->dev, "Failed to register panel\n"); | ||
309 | goto err_reg; | ||
310 | } | ||
311 | |||
312 | return 0; | ||
313 | |||
314 | err_reg: | ||
315 | omap_dss_put_device(ddata->in); | ||
316 | return r; | ||
317 | } | ||
318 | |||
319 | static int __exit dvic_remove(struct platform_device *pdev) | ||
320 | { | ||
321 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
322 | struct omap_dss_device *dssdev = &ddata->dssdev; | ||
323 | struct omap_dss_device *in = ddata->in; | ||
324 | |||
325 | omapdss_unregister_display(&ddata->dssdev); | ||
326 | |||
327 | dvic_disable(dssdev); | ||
328 | dvic_disconnect(dssdev); | ||
329 | |||
330 | omap_dss_put_device(in); | ||
331 | |||
332 | if (ddata->i2c_adapter) | ||
333 | i2c_put_adapter(ddata->i2c_adapter); | ||
334 | |||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | static struct platform_driver dvi_connector_driver = { | ||
339 | .probe = dvic_probe, | ||
340 | .remove = __exit_p(dvic_remove), | ||
341 | .driver = { | ||
342 | .name = "connector-dvi", | ||
343 | .owner = THIS_MODULE, | ||
344 | }, | ||
345 | }; | ||
346 | |||
347 | module_platform_driver(dvi_connector_driver); | ||
348 | |||
349 | MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); | ||
350 | MODULE_DESCRIPTION("Generic DVI Connector driver"); | ||
351 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays-new/connector-hdmi.c b/drivers/video/omap2/displays-new/connector-hdmi.c new file mode 100644 index 000000000000..c5826716d6ab --- /dev/null +++ b/drivers/video/omap2/displays-new/connector-hdmi.c | |||
@@ -0,0 +1,375 @@ | |||
1 | /* | ||
2 | * HDMI Connector driver | ||
3 | * | ||
4 | * Copyright (C) 2013 Texas Instruments | ||
5 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> | ||
6 | * | ||
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. | ||
10 | */ | ||
11 | |||
12 | #include <linux/slab.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | |||
16 | #include <drm/drm_edid.h> | ||
17 | |||
18 | #include <video/omapdss.h> | ||
19 | #include <video/omap-panel-data.h> | ||
20 | |||
21 | static const struct omap_video_timings hdmic_default_timings = { | ||
22 | .x_res = 640, | ||
23 | .y_res = 480, | ||
24 | .pixel_clock = 25175, | ||
25 | .hsw = 96, | ||
26 | .hfp = 16, | ||
27 | .hbp = 48, | ||
28 | .vsw = 2, | ||
29 | .vfp = 11, | ||
30 | .vbp = 31, | ||
31 | |||
32 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
33 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
34 | |||
35 | .interlace = false, | ||
36 | }; | ||
37 | |||
38 | struct panel_drv_data { | ||
39 | struct omap_dss_device dssdev; | ||
40 | struct omap_dss_device *in; | ||
41 | |||
42 | struct device *dev; | ||
43 | |||
44 | struct omap_video_timings timings; | ||
45 | }; | ||
46 | |||
47 | #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) | ||
48 | |||
49 | static int hdmic_connect(struct omap_dss_device *dssdev) | ||
50 | { | ||
51 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
52 | struct omap_dss_device *in = ddata->in; | ||
53 | int r; | ||
54 | |||
55 | dev_dbg(ddata->dev, "connect\n"); | ||
56 | |||
57 | if (omapdss_device_is_connected(dssdev)) | ||
58 | return 0; | ||
59 | |||
60 | r = in->ops.hdmi->connect(in, dssdev); | ||
61 | if (r) | ||
62 | return r; | ||
63 | |||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static void hdmic_disconnect(struct omap_dss_device *dssdev) | ||
68 | { | ||
69 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
70 | struct omap_dss_device *in = ddata->in; | ||
71 | |||
72 | dev_dbg(ddata->dev, "disconnect\n"); | ||
73 | |||
74 | if (!omapdss_device_is_connected(dssdev)) | ||
75 | return; | ||
76 | |||
77 | in->ops.hdmi->disconnect(in, dssdev); | ||
78 | } | ||
79 | |||
80 | static int hdmic_enable(struct omap_dss_device *dssdev) | ||
81 | { | ||
82 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
83 | struct omap_dss_device *in = ddata->in; | ||
84 | int r; | ||
85 | |||
86 | dev_dbg(ddata->dev, "enable\n"); | ||
87 | |||
88 | if (!omapdss_device_is_connected(dssdev)) | ||
89 | return -ENODEV; | ||
90 | |||
91 | if (omapdss_device_is_enabled(dssdev)) | ||
92 | return 0; | ||
93 | |||
94 | in->ops.hdmi->set_timings(in, &ddata->timings); | ||
95 | |||
96 | r = in->ops.hdmi->enable(in); | ||
97 | if (r) | ||
98 | return r; | ||
99 | |||
100 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
101 | |||
102 | return r; | ||
103 | } | ||
104 | |||
105 | static void hdmic_disable(struct omap_dss_device *dssdev) | ||
106 | { | ||
107 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
108 | struct omap_dss_device *in = ddata->in; | ||
109 | |||
110 | dev_dbg(ddata->dev, "disable\n"); | ||
111 | |||
112 | if (!omapdss_device_is_enabled(dssdev)) | ||
113 | return; | ||
114 | |||
115 | in->ops.hdmi->disable(in); | ||
116 | |||
117 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
118 | } | ||
119 | |||
120 | static void hdmic_set_timings(struct omap_dss_device *dssdev, | ||
121 | struct omap_video_timings *timings) | ||
122 | { | ||
123 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
124 | struct omap_dss_device *in = ddata->in; | ||
125 | |||
126 | ddata->timings = *timings; | ||
127 | dssdev->panel.timings = *timings; | ||
128 | |||
129 | in->ops.hdmi->set_timings(in, timings); | ||
130 | } | ||
131 | |||
132 | static void hdmic_get_timings(struct omap_dss_device *dssdev, | ||
133 | struct omap_video_timings *timings) | ||
134 | { | ||
135 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
136 | |||
137 | *timings = ddata->timings; | ||
138 | } | ||
139 | |||
140 | static int hdmic_check_timings(struct omap_dss_device *dssdev, | ||
141 | struct omap_video_timings *timings) | ||
142 | { | ||
143 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
144 | struct omap_dss_device *in = ddata->in; | ||
145 | |||
146 | return in->ops.hdmi->check_timings(in, timings); | ||
147 | } | ||
148 | |||
149 | static int hdmic_read_edid(struct omap_dss_device *dssdev, | ||
150 | u8 *edid, int len) | ||
151 | { | ||
152 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
153 | struct omap_dss_device *in = ddata->in; | ||
154 | |||
155 | return in->ops.hdmi->read_edid(in, edid, len); | ||
156 | } | ||
157 | |||
158 | static bool hdmic_detect(struct omap_dss_device *dssdev) | ||
159 | { | ||
160 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
161 | struct omap_dss_device *in = ddata->in; | ||
162 | |||
163 | return in->ops.hdmi->detect(in); | ||
164 | } | ||
165 | |||
166 | static int hdmic_audio_enable(struct omap_dss_device *dssdev) | ||
167 | { | ||
168 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
169 | struct omap_dss_device *in = ddata->in; | ||
170 | int r; | ||
171 | |||
172 | /* enable audio only if the display is active */ | ||
173 | if (!omapdss_device_is_enabled(dssdev)) | ||
174 | return -EPERM; | ||
175 | |||
176 | r = in->ops.hdmi->audio_enable(in); | ||
177 | if (r) | ||
178 | return r; | ||
179 | |||
180 | dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED; | ||
181 | |||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | static void hdmic_audio_disable(struct omap_dss_device *dssdev) | ||
186 | { | ||
187 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
188 | struct omap_dss_device *in = ddata->in; | ||
189 | |||
190 | in->ops.hdmi->audio_disable(in); | ||
191 | |||
192 | dssdev->audio_state = OMAP_DSS_AUDIO_DISABLED; | ||
193 | } | ||
194 | |||
195 | static int hdmic_audio_start(struct omap_dss_device *dssdev) | ||
196 | { | ||
197 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
198 | struct omap_dss_device *in = ddata->in; | ||
199 | int r; | ||
200 | |||
201 | /* | ||
202 | * No need to check the panel state. It was checked when trasitioning | ||
203 | * to AUDIO_ENABLED. | ||
204 | */ | ||
205 | if (dssdev->audio_state != OMAP_DSS_AUDIO_ENABLED) | ||
206 | return -EPERM; | ||
207 | |||
208 | r = in->ops.hdmi->audio_start(in); | ||
209 | if (r) | ||
210 | return r; | ||
211 | |||
212 | dssdev->audio_state = OMAP_DSS_AUDIO_PLAYING; | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | static void hdmic_audio_stop(struct omap_dss_device *dssdev) | ||
218 | { | ||
219 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
220 | struct omap_dss_device *in = ddata->in; | ||
221 | |||
222 | in->ops.hdmi->audio_stop(in); | ||
223 | |||
224 | dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED; | ||
225 | } | ||
226 | |||
227 | static bool hdmic_audio_supported(struct omap_dss_device *dssdev) | ||
228 | { | ||
229 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
230 | struct omap_dss_device *in = ddata->in; | ||
231 | |||
232 | if (!omapdss_device_is_enabled(dssdev)) | ||
233 | return false; | ||
234 | |||
235 | return in->ops.hdmi->audio_supported(in); | ||
236 | } | ||
237 | |||
238 | static int hdmic_audio_config(struct omap_dss_device *dssdev, | ||
239 | struct omap_dss_audio *audio) | ||
240 | { | ||
241 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
242 | struct omap_dss_device *in = ddata->in; | ||
243 | int r; | ||
244 | |||
245 | /* config audio only if the display is active */ | ||
246 | if (!omapdss_device_is_enabled(dssdev)) | ||
247 | return -EPERM; | ||
248 | |||
249 | r = in->ops.hdmi->audio_config(in, audio); | ||
250 | if (r) | ||
251 | return r; | ||
252 | |||
253 | dssdev->audio_state = OMAP_DSS_AUDIO_CONFIGURED; | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | static struct omap_dss_driver hdmic_driver = { | ||
259 | .connect = hdmic_connect, | ||
260 | .disconnect = hdmic_disconnect, | ||
261 | |||
262 | .enable = hdmic_enable, | ||
263 | .disable = hdmic_disable, | ||
264 | |||
265 | .set_timings = hdmic_set_timings, | ||
266 | .get_timings = hdmic_get_timings, | ||
267 | .check_timings = hdmic_check_timings, | ||
268 | |||
269 | .get_resolution = omapdss_default_get_resolution, | ||
270 | |||
271 | .read_edid = hdmic_read_edid, | ||
272 | .detect = hdmic_detect, | ||
273 | |||
274 | .audio_enable = hdmic_audio_enable, | ||
275 | .audio_disable = hdmic_audio_disable, | ||
276 | .audio_start = hdmic_audio_start, | ||
277 | .audio_stop = hdmic_audio_stop, | ||
278 | .audio_supported = hdmic_audio_supported, | ||
279 | .audio_config = hdmic_audio_config, | ||
280 | }; | ||
281 | |||
282 | static int hdmic_probe_pdata(struct platform_device *pdev) | ||
283 | { | ||
284 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
285 | struct connector_hdmi_platform_data *pdata; | ||
286 | struct omap_dss_device *in, *dssdev; | ||
287 | |||
288 | pdata = dev_get_platdata(&pdev->dev); | ||
289 | |||
290 | in = omap_dss_find_output(pdata->source); | ||
291 | if (in == NULL) { | ||
292 | dev_err(&pdev->dev, "Failed to find video source\n"); | ||
293 | return -ENODEV; | ||
294 | } | ||
295 | |||
296 | ddata->in = in; | ||
297 | |||
298 | dssdev = &ddata->dssdev; | ||
299 | dssdev->name = pdata->name; | ||
300 | |||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | static int hdmic_probe(struct platform_device *pdev) | ||
305 | { | ||
306 | struct panel_drv_data *ddata; | ||
307 | struct omap_dss_device *dssdev; | ||
308 | int r; | ||
309 | |||
310 | ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); | ||
311 | if (!ddata) | ||
312 | return -ENOMEM; | ||
313 | |||
314 | platform_set_drvdata(pdev, ddata); | ||
315 | ddata->dev = &pdev->dev; | ||
316 | |||
317 | if (dev_get_platdata(&pdev->dev)) { | ||
318 | r = hdmic_probe_pdata(pdev); | ||
319 | if (r) | ||
320 | return r; | ||
321 | } else { | ||
322 | return -ENODEV; | ||
323 | } | ||
324 | |||
325 | ddata->timings = hdmic_default_timings; | ||
326 | |||
327 | dssdev = &ddata->dssdev; | ||
328 | dssdev->driver = &hdmic_driver; | ||
329 | dssdev->dev = &pdev->dev; | ||
330 | dssdev->type = OMAP_DISPLAY_TYPE_HDMI; | ||
331 | dssdev->owner = THIS_MODULE; | ||
332 | dssdev->panel.timings = hdmic_default_timings; | ||
333 | |||
334 | r = omapdss_register_display(dssdev); | ||
335 | if (r) { | ||
336 | dev_err(&pdev->dev, "Failed to register panel\n"); | ||
337 | goto err_reg; | ||
338 | } | ||
339 | |||
340 | return 0; | ||
341 | err_reg: | ||
342 | omap_dss_put_device(ddata->in); | ||
343 | return r; | ||
344 | } | ||
345 | |||
346 | static int __exit hdmic_remove(struct platform_device *pdev) | ||
347 | { | ||
348 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
349 | struct omap_dss_device *dssdev = &ddata->dssdev; | ||
350 | struct omap_dss_device *in = ddata->in; | ||
351 | |||
352 | omapdss_unregister_display(&ddata->dssdev); | ||
353 | |||
354 | hdmic_disable(dssdev); | ||
355 | hdmic_disconnect(dssdev); | ||
356 | |||
357 | omap_dss_put_device(in); | ||
358 | |||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | static struct platform_driver hdmi_connector_driver = { | ||
363 | .probe = hdmic_probe, | ||
364 | .remove = __exit_p(hdmic_remove), | ||
365 | .driver = { | ||
366 | .name = "connector-hdmi", | ||
367 | .owner = THIS_MODULE, | ||
368 | }, | ||
369 | }; | ||
370 | |||
371 | module_platform_driver(hdmi_connector_driver); | ||
372 | |||
373 | MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); | ||
374 | MODULE_DESCRIPTION("HDMI Connector driver"); | ||
375 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays-new/encoder-tfp410.c b/drivers/video/omap2/displays-new/encoder-tfp410.c new file mode 100644 index 000000000000..a04f65856d6b --- /dev/null +++ b/drivers/video/omap2/displays-new/encoder-tfp410.c | |||
@@ -0,0 +1,267 @@ | |||
1 | /* | ||
2 | * TFP410 DPI-to-DVI encoder driver | ||
3 | * | ||
4 | * Copyright (C) 2013 Texas Instruments | ||
5 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> | ||
6 | * | ||
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. | ||
10 | */ | ||
11 | |||
12 | #include <linux/gpio.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/slab.h> | ||
16 | |||
17 | #include <video/omapdss.h> | ||
18 | #include <video/omap-panel-data.h> | ||
19 | |||
20 | struct panel_drv_data { | ||
21 | struct omap_dss_device dssdev; | ||
22 | struct omap_dss_device *in; | ||
23 | |||
24 | int pd_gpio; | ||
25 | int data_lines; | ||
26 | |||
27 | struct omap_video_timings timings; | ||
28 | }; | ||
29 | |||
30 | #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) | ||
31 | |||
32 | static int tfp410_connect(struct omap_dss_device *dssdev, | ||
33 | struct omap_dss_device *dst) | ||
34 | { | ||
35 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
36 | struct omap_dss_device *in = ddata->in; | ||
37 | int r; | ||
38 | |||
39 | if (omapdss_device_is_connected(dssdev)) | ||
40 | return -EBUSY; | ||
41 | |||
42 | r = in->ops.dpi->connect(in, dssdev); | ||
43 | if (r) | ||
44 | return r; | ||
45 | |||
46 | dst->output = dssdev; | ||
47 | dssdev->device = dst; | ||
48 | |||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | static void tfp410_disconnect(struct omap_dss_device *dssdev, | ||
53 | struct omap_dss_device *dst) | ||
54 | { | ||
55 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
56 | struct omap_dss_device *in = ddata->in; | ||
57 | |||
58 | WARN_ON(!omapdss_device_is_connected(dssdev)); | ||
59 | if (!omapdss_device_is_connected(dssdev)) | ||
60 | return; | ||
61 | |||
62 | WARN_ON(dst != dssdev->device); | ||
63 | if (dst != dssdev->device) | ||
64 | return; | ||
65 | |||
66 | dst->output = NULL; | ||
67 | dssdev->device = NULL; | ||
68 | |||
69 | in->ops.dpi->disconnect(in, &ddata->dssdev); | ||
70 | } | ||
71 | |||
72 | static int tfp410_enable(struct omap_dss_device *dssdev) | ||
73 | { | ||
74 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
75 | struct omap_dss_device *in = ddata->in; | ||
76 | int r; | ||
77 | |||
78 | if (!omapdss_device_is_connected(dssdev)) | ||
79 | return -ENODEV; | ||
80 | |||
81 | if (omapdss_device_is_enabled(dssdev)) | ||
82 | return 0; | ||
83 | |||
84 | in->ops.dpi->set_timings(in, &ddata->timings); | ||
85 | in->ops.dpi->set_data_lines(in, ddata->data_lines); | ||
86 | |||
87 | r = in->ops.dpi->enable(in); | ||
88 | if (r) | ||
89 | return r; | ||
90 | |||
91 | if (gpio_is_valid(ddata->pd_gpio)) | ||
92 | gpio_set_value_cansleep(ddata->pd_gpio, 1); | ||
93 | |||
94 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
95 | |||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static void tfp410_disable(struct omap_dss_device *dssdev) | ||
100 | { | ||
101 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
102 | struct omap_dss_device *in = ddata->in; | ||
103 | |||
104 | if (!omapdss_device_is_enabled(dssdev)) | ||
105 | return; | ||
106 | |||
107 | if (gpio_is_valid(ddata->pd_gpio)) | ||
108 | gpio_set_value_cansleep(ddata->pd_gpio, 0); | ||
109 | |||
110 | in->ops.dpi->disable(in); | ||
111 | |||
112 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
113 | } | ||
114 | |||
115 | static void tfp410_set_timings(struct omap_dss_device *dssdev, | ||
116 | struct omap_video_timings *timings) | ||
117 | { | ||
118 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
119 | struct omap_dss_device *in = ddata->in; | ||
120 | |||
121 | ddata->timings = *timings; | ||
122 | dssdev->panel.timings = *timings; | ||
123 | |||
124 | in->ops.dpi->set_timings(in, timings); | ||
125 | } | ||
126 | |||
127 | static void tfp410_get_timings(struct omap_dss_device *dssdev, | ||
128 | struct omap_video_timings *timings) | ||
129 | { | ||
130 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
131 | |||
132 | *timings = ddata->timings; | ||
133 | } | ||
134 | |||
135 | static int tfp410_check_timings(struct omap_dss_device *dssdev, | ||
136 | struct omap_video_timings *timings) | ||
137 | { | ||
138 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
139 | struct omap_dss_device *in = ddata->in; | ||
140 | |||
141 | return in->ops.dpi->check_timings(in, timings); | ||
142 | } | ||
143 | |||
144 | static const struct omapdss_dvi_ops tfp410_dvi_ops = { | ||
145 | .connect = tfp410_connect, | ||
146 | .disconnect = tfp410_disconnect, | ||
147 | |||
148 | .enable = tfp410_enable, | ||
149 | .disable = tfp410_disable, | ||
150 | |||
151 | .check_timings = tfp410_check_timings, | ||
152 | .set_timings = tfp410_set_timings, | ||
153 | .get_timings = tfp410_get_timings, | ||
154 | }; | ||
155 | |||
156 | static int tfp410_probe_pdata(struct platform_device *pdev) | ||
157 | { | ||
158 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
159 | struct encoder_tfp410_platform_data *pdata; | ||
160 | struct omap_dss_device *dssdev, *in; | ||
161 | |||
162 | pdata = dev_get_platdata(&pdev->dev); | ||
163 | |||
164 | ddata->pd_gpio = pdata->power_down_gpio; | ||
165 | |||
166 | ddata->data_lines = pdata->data_lines; | ||
167 | |||
168 | in = omap_dss_find_output(pdata->source); | ||
169 | if (in == NULL) { | ||
170 | dev_err(&pdev->dev, "Failed to find video source\n"); | ||
171 | return -ENODEV; | ||
172 | } | ||
173 | |||
174 | ddata->in = in; | ||
175 | |||
176 | dssdev = &ddata->dssdev; | ||
177 | dssdev->name = pdata->name; | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | static int tfp410_probe(struct platform_device *pdev) | ||
183 | { | ||
184 | struct panel_drv_data *ddata; | ||
185 | struct omap_dss_device *dssdev; | ||
186 | int r; | ||
187 | |||
188 | ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); | ||
189 | if (!ddata) | ||
190 | return -ENOMEM; | ||
191 | |||
192 | platform_set_drvdata(pdev, ddata); | ||
193 | |||
194 | if (dev_get_platdata(&pdev->dev)) { | ||
195 | r = tfp410_probe_pdata(pdev); | ||
196 | if (r) | ||
197 | return r; | ||
198 | } else { | ||
199 | return -ENODEV; | ||
200 | } | ||
201 | |||
202 | if (gpio_is_valid(ddata->pd_gpio)) { | ||
203 | r = devm_gpio_request_one(&pdev->dev, ddata->pd_gpio, | ||
204 | GPIOF_OUT_INIT_LOW, "tfp410 PD"); | ||
205 | if (r) { | ||
206 | dev_err(&pdev->dev, "Failed to request PD GPIO %d\n", | ||
207 | ddata->pd_gpio); | ||
208 | goto err_gpio; | ||
209 | } | ||
210 | } | ||
211 | |||
212 | dssdev = &ddata->dssdev; | ||
213 | dssdev->ops.dvi = &tfp410_dvi_ops; | ||
214 | dssdev->dev = &pdev->dev; | ||
215 | dssdev->type = OMAP_DISPLAY_TYPE_DPI; | ||
216 | dssdev->output_type = OMAP_DISPLAY_TYPE_DVI; | ||
217 | dssdev->owner = THIS_MODULE; | ||
218 | dssdev->phy.dpi.data_lines = ddata->data_lines; | ||
219 | |||
220 | r = omapdss_register_output(dssdev); | ||
221 | if (r) { | ||
222 | dev_err(&pdev->dev, "Failed to register output\n"); | ||
223 | goto err_reg; | ||
224 | } | ||
225 | |||
226 | return 0; | ||
227 | err_reg: | ||
228 | err_gpio: | ||
229 | omap_dss_put_device(ddata->in); | ||
230 | return r; | ||
231 | } | ||
232 | |||
233 | static int __exit tfp410_remove(struct platform_device *pdev) | ||
234 | { | ||
235 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
236 | struct omap_dss_device *dssdev = &ddata->dssdev; | ||
237 | struct omap_dss_device *in = ddata->in; | ||
238 | |||
239 | omapdss_unregister_output(&ddata->dssdev); | ||
240 | |||
241 | WARN_ON(omapdss_device_is_enabled(dssdev)); | ||
242 | if (omapdss_device_is_enabled(dssdev)) | ||
243 | tfp410_disable(dssdev); | ||
244 | |||
245 | WARN_ON(omapdss_device_is_connected(dssdev)); | ||
246 | if (omapdss_device_is_connected(dssdev)) | ||
247 | tfp410_disconnect(dssdev, dssdev->device); | ||
248 | |||
249 | omap_dss_put_device(in); | ||
250 | |||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | static struct platform_driver tfp410_driver = { | ||
255 | .probe = tfp410_probe, | ||
256 | .remove = __exit_p(tfp410_remove), | ||
257 | .driver = { | ||
258 | .name = "tfp410", | ||
259 | .owner = THIS_MODULE, | ||
260 | }, | ||
261 | }; | ||
262 | |||
263 | module_platform_driver(tfp410_driver); | ||
264 | |||
265 | MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); | ||
266 | MODULE_DESCRIPTION("TFP410 DPI to DVI encoder driver"); | ||
267 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays-new/encoder-tpd12s015.c b/drivers/video/omap2/displays-new/encoder-tpd12s015.c new file mode 100644 index 000000000000..ce0e010026cb --- /dev/null +++ b/drivers/video/omap2/displays-new/encoder-tpd12s015.c | |||
@@ -0,0 +1,395 @@ | |||
1 | /* | ||
2 | * TPD12S015 HDMI ESD protection & level shifter chip driver | ||
3 | * | ||
4 | * Copyright (C) 2013 Texas Instruments | ||
5 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> | ||
6 | * | ||
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. | ||
10 | */ | ||
11 | |||
12 | #include <linux/completion.h> | ||
13 | #include <linux/delay.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/gpio.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | |||
19 | #include <video/omapdss.h> | ||
20 | #include <video/omap-panel-data.h> | ||
21 | |||
22 | struct panel_drv_data { | ||
23 | struct omap_dss_device dssdev; | ||
24 | struct omap_dss_device *in; | ||
25 | |||
26 | int ct_cp_hpd_gpio; | ||
27 | int ls_oe_gpio; | ||
28 | int hpd_gpio; | ||
29 | |||
30 | struct omap_video_timings timings; | ||
31 | |||
32 | struct completion hpd_completion; | ||
33 | }; | ||
34 | |||
35 | #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) | ||
36 | |||
37 | static irqreturn_t tpd_hpd_irq_handler(int irq, void *data) | ||
38 | { | ||
39 | struct panel_drv_data *ddata = data; | ||
40 | bool hpd; | ||
41 | |||
42 | hpd = gpio_get_value_cansleep(ddata->hpd_gpio); | ||
43 | |||
44 | dev_dbg(ddata->dssdev.dev, "hpd %d\n", hpd); | ||
45 | |||
46 | if (gpio_is_valid(ddata->ls_oe_gpio)) { | ||
47 | if (hpd) | ||
48 | gpio_set_value_cansleep(ddata->ls_oe_gpio, 1); | ||
49 | else | ||
50 | gpio_set_value_cansleep(ddata->ls_oe_gpio, 0); | ||
51 | } | ||
52 | |||
53 | complete_all(&ddata->hpd_completion); | ||
54 | |||
55 | return IRQ_HANDLED; | ||
56 | } | ||
57 | |||
58 | static int tpd_connect(struct omap_dss_device *dssdev, | ||
59 | struct omap_dss_device *dst) | ||
60 | { | ||
61 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
62 | struct omap_dss_device *in = ddata->in; | ||
63 | int r; | ||
64 | |||
65 | r = in->ops.hdmi->connect(in, dssdev); | ||
66 | if (r) | ||
67 | return r; | ||
68 | |||
69 | dst->output = dssdev; | ||
70 | dssdev->device = dst; | ||
71 | |||
72 | INIT_COMPLETION(ddata->hpd_completion); | ||
73 | |||
74 | gpio_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1); | ||
75 | /* DC-DC converter needs at max 300us to get to 90% of 5V */ | ||
76 | udelay(300); | ||
77 | |||
78 | /* | ||
79 | * If there's a cable connected, wait for the hpd irq to trigger, | ||
80 | * which turns on the level shifters. | ||
81 | */ | ||
82 | if (gpio_get_value_cansleep(ddata->hpd_gpio)) { | ||
83 | unsigned long to; | ||
84 | to = wait_for_completion_timeout(&ddata->hpd_completion, | ||
85 | msecs_to_jiffies(250)); | ||
86 | WARN_ON_ONCE(to == 0); | ||
87 | } | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static void tpd_disconnect(struct omap_dss_device *dssdev, | ||
93 | struct omap_dss_device *dst) | ||
94 | { | ||
95 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
96 | struct omap_dss_device *in = ddata->in; | ||
97 | |||
98 | WARN_ON(dst != dssdev->device); | ||
99 | |||
100 | if (dst != dssdev->device) | ||
101 | return; | ||
102 | |||
103 | gpio_set_value_cansleep(ddata->ct_cp_hpd_gpio, 0); | ||
104 | |||
105 | dst->output = NULL; | ||
106 | dssdev->device = NULL; | ||
107 | |||
108 | in->ops.hdmi->disconnect(in, &ddata->dssdev); | ||
109 | } | ||
110 | |||
111 | static int tpd_enable(struct omap_dss_device *dssdev) | ||
112 | { | ||
113 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
114 | struct omap_dss_device *in = ddata->in; | ||
115 | int r; | ||
116 | |||
117 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | ||
118 | return 0; | ||
119 | |||
120 | in->ops.hdmi->set_timings(in, &ddata->timings); | ||
121 | |||
122 | r = in->ops.hdmi->enable(in); | ||
123 | if (r) | ||
124 | return r; | ||
125 | |||
126 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
127 | |||
128 | return r; | ||
129 | } | ||
130 | |||
131 | static void tpd_disable(struct omap_dss_device *dssdev) | ||
132 | { | ||
133 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
134 | struct omap_dss_device *in = ddata->in; | ||
135 | |||
136 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
137 | return; | ||
138 | |||
139 | in->ops.hdmi->disable(in); | ||
140 | |||
141 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
142 | } | ||
143 | |||
144 | static void tpd_set_timings(struct omap_dss_device *dssdev, | ||
145 | struct omap_video_timings *timings) | ||
146 | { | ||
147 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
148 | struct omap_dss_device *in = ddata->in; | ||
149 | |||
150 | ddata->timings = *timings; | ||
151 | dssdev->panel.timings = *timings; | ||
152 | |||
153 | in->ops.hdmi->set_timings(in, timings); | ||
154 | } | ||
155 | |||
156 | static void tpd_get_timings(struct omap_dss_device *dssdev, | ||
157 | struct omap_video_timings *timings) | ||
158 | { | ||
159 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
160 | |||
161 | *timings = ddata->timings; | ||
162 | } | ||
163 | |||
164 | static int tpd_check_timings(struct omap_dss_device *dssdev, | ||
165 | struct omap_video_timings *timings) | ||
166 | { | ||
167 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
168 | struct omap_dss_device *in = ddata->in; | ||
169 | int r; | ||
170 | |||
171 | r = in->ops.hdmi->check_timings(in, timings); | ||
172 | |||
173 | return r; | ||
174 | } | ||
175 | |||
176 | static int tpd_read_edid(struct omap_dss_device *dssdev, | ||
177 | u8 *edid, int len) | ||
178 | { | ||
179 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
180 | struct omap_dss_device *in = ddata->in; | ||
181 | |||
182 | if (!gpio_get_value_cansleep(ddata->hpd_gpio)) | ||
183 | return -ENODEV; | ||
184 | |||
185 | return in->ops.hdmi->read_edid(in, edid, len); | ||
186 | } | ||
187 | |||
188 | static bool tpd_detect(struct omap_dss_device *dssdev) | ||
189 | { | ||
190 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
191 | |||
192 | return gpio_get_value_cansleep(ddata->hpd_gpio); | ||
193 | } | ||
194 | |||
195 | static int tpd_audio_enable(struct omap_dss_device *dssdev) | ||
196 | { | ||
197 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
198 | struct omap_dss_device *in = ddata->in; | ||
199 | |||
200 | return in->ops.hdmi->audio_enable(in); | ||
201 | } | ||
202 | |||
203 | static void tpd_audio_disable(struct omap_dss_device *dssdev) | ||
204 | { | ||
205 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
206 | struct omap_dss_device *in = ddata->in; | ||
207 | |||
208 | in->ops.hdmi->audio_disable(in); | ||
209 | } | ||
210 | |||
211 | static int tpd_audio_start(struct omap_dss_device *dssdev) | ||
212 | { | ||
213 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
214 | struct omap_dss_device *in = ddata->in; | ||
215 | |||
216 | return in->ops.hdmi->audio_start(in); | ||
217 | } | ||
218 | |||
219 | static void tpd_audio_stop(struct omap_dss_device *dssdev) | ||
220 | { | ||
221 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
222 | struct omap_dss_device *in = ddata->in; | ||
223 | |||
224 | in->ops.hdmi->audio_stop(in); | ||
225 | } | ||
226 | |||
227 | static bool tpd_audio_supported(struct omap_dss_device *dssdev) | ||
228 | { | ||
229 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
230 | struct omap_dss_device *in = ddata->in; | ||
231 | |||
232 | return in->ops.hdmi->audio_supported(in); | ||
233 | } | ||
234 | |||
235 | static int tpd_audio_config(struct omap_dss_device *dssdev, | ||
236 | struct omap_dss_audio *audio) | ||
237 | { | ||
238 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
239 | struct omap_dss_device *in = ddata->in; | ||
240 | |||
241 | return in->ops.hdmi->audio_config(in, audio); | ||
242 | } | ||
243 | |||
244 | static const struct omapdss_hdmi_ops tpd_hdmi_ops = { | ||
245 | .connect = tpd_connect, | ||
246 | .disconnect = tpd_disconnect, | ||
247 | |||
248 | .enable = tpd_enable, | ||
249 | .disable = tpd_disable, | ||
250 | |||
251 | .check_timings = tpd_check_timings, | ||
252 | .set_timings = tpd_set_timings, | ||
253 | .get_timings = tpd_get_timings, | ||
254 | |||
255 | .read_edid = tpd_read_edid, | ||
256 | .detect = tpd_detect, | ||
257 | |||
258 | .audio_enable = tpd_audio_enable, | ||
259 | .audio_disable = tpd_audio_disable, | ||
260 | .audio_start = tpd_audio_start, | ||
261 | .audio_stop = tpd_audio_stop, | ||
262 | .audio_supported = tpd_audio_supported, | ||
263 | .audio_config = tpd_audio_config, | ||
264 | }; | ||
265 | |||
266 | static int tpd_probe_pdata(struct platform_device *pdev) | ||
267 | { | ||
268 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
269 | struct encoder_tpd12s015_platform_data *pdata; | ||
270 | struct omap_dss_device *dssdev, *in; | ||
271 | |||
272 | pdata = dev_get_platdata(&pdev->dev); | ||
273 | |||
274 | ddata->ct_cp_hpd_gpio = pdata->ct_cp_hpd_gpio; | ||
275 | ddata->ls_oe_gpio = pdata->ls_oe_gpio; | ||
276 | ddata->hpd_gpio = pdata->hpd_gpio; | ||
277 | |||
278 | in = omap_dss_find_output(pdata->source); | ||
279 | if (in == NULL) { | ||
280 | dev_err(&pdev->dev, "Failed to find video source\n"); | ||
281 | return -ENODEV; | ||
282 | } | ||
283 | |||
284 | ddata->in = in; | ||
285 | |||
286 | dssdev = &ddata->dssdev; | ||
287 | dssdev->name = pdata->name; | ||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static int tpd_probe(struct platform_device *pdev) | ||
293 | { | ||
294 | struct omap_dss_device *in, *dssdev; | ||
295 | struct panel_drv_data *ddata; | ||
296 | int r; | ||
297 | |||
298 | ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); | ||
299 | if (!ddata) | ||
300 | return -ENOMEM; | ||
301 | |||
302 | platform_set_drvdata(pdev, ddata); | ||
303 | |||
304 | init_completion(&ddata->hpd_completion); | ||
305 | |||
306 | if (dev_get_platdata(&pdev->dev)) { | ||
307 | r = tpd_probe_pdata(pdev); | ||
308 | if (r) | ||
309 | return r; | ||
310 | } else { | ||
311 | return -ENODEV; | ||
312 | } | ||
313 | |||
314 | r = devm_gpio_request_one(&pdev->dev, ddata->ct_cp_hpd_gpio, | ||
315 | GPIOF_OUT_INIT_LOW, "hdmi_ct_cp_hpd"); | ||
316 | if (r) | ||
317 | goto err_gpio; | ||
318 | |||
319 | if (gpio_is_valid(ddata->ls_oe_gpio)) { | ||
320 | r = devm_gpio_request_one(&pdev->dev, ddata->ls_oe_gpio, | ||
321 | GPIOF_OUT_INIT_LOW, "hdmi_ls_oe"); | ||
322 | if (r) | ||
323 | goto err_gpio; | ||
324 | } | ||
325 | |||
326 | r = devm_gpio_request_one(&pdev->dev, ddata->hpd_gpio, | ||
327 | GPIOF_DIR_IN, "hdmi_hpd"); | ||
328 | if (r) | ||
329 | goto err_gpio; | ||
330 | |||
331 | r = devm_request_threaded_irq(&pdev->dev, gpio_to_irq(ddata->hpd_gpio), | ||
332 | NULL, tpd_hpd_irq_handler, | ||
333 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | | ||
334 | IRQF_ONESHOT, "hpd", ddata); | ||
335 | if (r) | ||
336 | goto err_irq; | ||
337 | |||
338 | dssdev = &ddata->dssdev; | ||
339 | dssdev->ops.hdmi = &tpd_hdmi_ops; | ||
340 | dssdev->dev = &pdev->dev; | ||
341 | dssdev->type = OMAP_DISPLAY_TYPE_HDMI; | ||
342 | dssdev->output_type = OMAP_DISPLAY_TYPE_HDMI; | ||
343 | dssdev->owner = THIS_MODULE; | ||
344 | |||
345 | in = ddata->in; | ||
346 | |||
347 | r = omapdss_register_output(dssdev); | ||
348 | if (r) { | ||
349 | dev_err(&pdev->dev, "Failed to register output\n"); | ||
350 | goto err_reg; | ||
351 | } | ||
352 | |||
353 | return 0; | ||
354 | err_reg: | ||
355 | err_irq: | ||
356 | err_gpio: | ||
357 | omap_dss_put_device(ddata->in); | ||
358 | return r; | ||
359 | } | ||
360 | |||
361 | static int __exit tpd_remove(struct platform_device *pdev) | ||
362 | { | ||
363 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
364 | struct omap_dss_device *dssdev = &ddata->dssdev; | ||
365 | struct omap_dss_device *in = ddata->in; | ||
366 | |||
367 | omapdss_unregister_output(&ddata->dssdev); | ||
368 | |||
369 | WARN_ON(omapdss_device_is_enabled(dssdev)); | ||
370 | if (omapdss_device_is_enabled(dssdev)) | ||
371 | tpd_disable(dssdev); | ||
372 | |||
373 | WARN_ON(omapdss_device_is_connected(dssdev)); | ||
374 | if (omapdss_device_is_connected(dssdev)) | ||
375 | tpd_disconnect(dssdev, dssdev->device); | ||
376 | |||
377 | omap_dss_put_device(in); | ||
378 | |||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static struct platform_driver tpd_driver = { | ||
383 | .probe = tpd_probe, | ||
384 | .remove = __exit_p(tpd_remove), | ||
385 | .driver = { | ||
386 | .name = "tpd12s015", | ||
387 | .owner = THIS_MODULE, | ||
388 | }, | ||
389 | }; | ||
390 | |||
391 | module_platform_driver(tpd_driver); | ||
392 | |||
393 | MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); | ||
394 | MODULE_DESCRIPTION("TPD12S015 driver"); | ||
395 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays-new/panel-dpi.c b/drivers/video/omap2/displays-new/panel-dpi.c new file mode 100644 index 000000000000..5f8f7e7c81ef --- /dev/null +++ b/drivers/video/omap2/displays-new/panel-dpi.c | |||
@@ -0,0 +1,270 @@ | |||
1 | /* | ||
2 | * Generic MIPI DPI Panel Driver | ||
3 | * | ||
4 | * Copyright (C) 2013 Texas Instruments | ||
5 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> | ||
6 | * | ||
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. | ||
10 | */ | ||
11 | |||
12 | #include <linux/gpio.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/slab.h> | ||
16 | |||
17 | #include <video/omapdss.h> | ||
18 | #include <video/omap-panel-data.h> | ||
19 | |||
20 | struct panel_drv_data { | ||
21 | struct omap_dss_device dssdev; | ||
22 | struct omap_dss_device *in; | ||
23 | |||
24 | int data_lines; | ||
25 | |||
26 | struct omap_video_timings videomode; | ||
27 | |||
28 | int backlight_gpio; | ||
29 | int enable_gpio; | ||
30 | }; | ||
31 | |||
32 | #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) | ||
33 | |||
34 | static int panel_dpi_connect(struct omap_dss_device *dssdev) | ||
35 | { | ||
36 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
37 | struct omap_dss_device *in = ddata->in; | ||
38 | int r; | ||
39 | |||
40 | if (omapdss_device_is_connected(dssdev)) | ||
41 | return 0; | ||
42 | |||
43 | r = in->ops.dpi->connect(in, dssdev); | ||
44 | if (r) | ||
45 | return r; | ||
46 | |||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | static void panel_dpi_disconnect(struct omap_dss_device *dssdev) | ||
51 | { | ||
52 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
53 | struct omap_dss_device *in = ddata->in; | ||
54 | |||
55 | if (!omapdss_device_is_connected(dssdev)) | ||
56 | return; | ||
57 | |||
58 | in->ops.dpi->disconnect(in, dssdev); | ||
59 | } | ||
60 | |||
61 | static int panel_dpi_enable(struct omap_dss_device *dssdev) | ||
62 | { | ||
63 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
64 | struct omap_dss_device *in = ddata->in; | ||
65 | int r; | ||
66 | |||
67 | if (!omapdss_device_is_connected(dssdev)) | ||
68 | return -ENODEV; | ||
69 | |||
70 | if (omapdss_device_is_enabled(dssdev)) | ||
71 | return 0; | ||
72 | |||
73 | in->ops.dpi->set_data_lines(in, ddata->data_lines); | ||
74 | in->ops.dpi->set_timings(in, &ddata->videomode); | ||
75 | |||
76 | r = in->ops.dpi->enable(in); | ||
77 | if (r) | ||
78 | return r; | ||
79 | |||
80 | if (gpio_is_valid(ddata->enable_gpio)) | ||
81 | gpio_set_value_cansleep(ddata->enable_gpio, 1); | ||
82 | |||
83 | if (gpio_is_valid(ddata->backlight_gpio)) | ||
84 | gpio_set_value_cansleep(ddata->backlight_gpio, 1); | ||
85 | |||
86 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static void panel_dpi_disable(struct omap_dss_device *dssdev) | ||
92 | { | ||
93 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
94 | struct omap_dss_device *in = ddata->in; | ||
95 | |||
96 | if (!omapdss_device_is_enabled(dssdev)) | ||
97 | return; | ||
98 | |||
99 | if (gpio_is_valid(ddata->enable_gpio)) | ||
100 | gpio_set_value_cansleep(ddata->enable_gpio, 0); | ||
101 | |||
102 | if (gpio_is_valid(ddata->backlight_gpio)) | ||
103 | gpio_set_value_cansleep(ddata->backlight_gpio, 0); | ||
104 | |||
105 | in->ops.dpi->disable(in); | ||
106 | |||
107 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
108 | } | ||
109 | |||
110 | static void panel_dpi_set_timings(struct omap_dss_device *dssdev, | ||
111 | struct omap_video_timings *timings) | ||
112 | { | ||
113 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
114 | struct omap_dss_device *in = ddata->in; | ||
115 | |||
116 | ddata->videomode = *timings; | ||
117 | dssdev->panel.timings = *timings; | ||
118 | |||
119 | in->ops.dpi->set_timings(in, timings); | ||
120 | } | ||
121 | |||
122 | static void panel_dpi_get_timings(struct omap_dss_device *dssdev, | ||
123 | struct omap_video_timings *timings) | ||
124 | { | ||
125 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
126 | |||
127 | *timings = ddata->videomode; | ||
128 | } | ||
129 | |||
130 | static int panel_dpi_check_timings(struct omap_dss_device *dssdev, | ||
131 | struct omap_video_timings *timings) | ||
132 | { | ||
133 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
134 | struct omap_dss_device *in = ddata->in; | ||
135 | |||
136 | return in->ops.dpi->check_timings(in, timings); | ||
137 | } | ||
138 | |||
139 | static struct omap_dss_driver panel_dpi_ops = { | ||
140 | .connect = panel_dpi_connect, | ||
141 | .disconnect = panel_dpi_disconnect, | ||
142 | |||
143 | .enable = panel_dpi_enable, | ||
144 | .disable = panel_dpi_disable, | ||
145 | |||
146 | .set_timings = panel_dpi_set_timings, | ||
147 | .get_timings = panel_dpi_get_timings, | ||
148 | .check_timings = panel_dpi_check_timings, | ||
149 | |||
150 | .get_resolution = omapdss_default_get_resolution, | ||
151 | }; | ||
152 | |||
153 | static int panel_dpi_probe_pdata(struct platform_device *pdev) | ||
154 | { | ||
155 | const struct panel_dpi_platform_data *pdata; | ||
156 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
157 | struct omap_dss_device *dssdev, *in; | ||
158 | struct videomode vm; | ||
159 | |||
160 | pdata = dev_get_platdata(&pdev->dev); | ||
161 | |||
162 | in = omap_dss_find_output(pdata->source); | ||
163 | if (in == NULL) { | ||
164 | dev_err(&pdev->dev, "failed to find video source '%s'\n", | ||
165 | pdata->source); | ||
166 | return -EPROBE_DEFER; | ||
167 | } | ||
168 | |||
169 | ddata->in = in; | ||
170 | |||
171 | ddata->data_lines = pdata->data_lines; | ||
172 | |||
173 | videomode_from_timing(pdata->display_timing, &vm); | ||
174 | videomode_to_omap_video_timings(&vm, &ddata->videomode); | ||
175 | |||
176 | dssdev = &ddata->dssdev; | ||
177 | dssdev->name = pdata->name; | ||
178 | |||
179 | ddata->enable_gpio = pdata->enable_gpio; | ||
180 | ddata->backlight_gpio = pdata->backlight_gpio; | ||
181 | |||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | static int panel_dpi_probe(struct platform_device *pdev) | ||
186 | { | ||
187 | struct panel_drv_data *ddata; | ||
188 | struct omap_dss_device *dssdev; | ||
189 | int r; | ||
190 | |||
191 | ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); | ||
192 | if (ddata == NULL) | ||
193 | return -ENOMEM; | ||
194 | |||
195 | platform_set_drvdata(pdev, ddata); | ||
196 | |||
197 | if (dev_get_platdata(&pdev->dev)) { | ||
198 | r = panel_dpi_probe_pdata(pdev); | ||
199 | if (r) | ||
200 | return r; | ||
201 | } else { | ||
202 | return -ENODEV; | ||
203 | } | ||
204 | |||
205 | if (gpio_is_valid(ddata->enable_gpio)) { | ||
206 | r = devm_gpio_request_one(&pdev->dev, ddata->enable_gpio, | ||
207 | GPIOF_OUT_INIT_LOW, "panel enable"); | ||
208 | if (r) | ||
209 | goto err_gpio; | ||
210 | } | ||
211 | |||
212 | if (gpio_is_valid(ddata->backlight_gpio)) { | ||
213 | r = devm_gpio_request_one(&pdev->dev, ddata->backlight_gpio, | ||
214 | GPIOF_OUT_INIT_LOW, "panel backlight"); | ||
215 | if (r) | ||
216 | goto err_gpio; | ||
217 | } | ||
218 | |||
219 | dssdev = &ddata->dssdev; | ||
220 | dssdev->dev = &pdev->dev; | ||
221 | dssdev->driver = &panel_dpi_ops; | ||
222 | dssdev->type = OMAP_DISPLAY_TYPE_DPI; | ||
223 | dssdev->owner = THIS_MODULE; | ||
224 | dssdev->panel.timings = ddata->videomode; | ||
225 | dssdev->phy.dpi.data_lines = ddata->data_lines; | ||
226 | |||
227 | r = omapdss_register_display(dssdev); | ||
228 | if (r) { | ||
229 | dev_err(&pdev->dev, "Failed to register panel\n"); | ||
230 | goto err_reg; | ||
231 | } | ||
232 | |||
233 | return 0; | ||
234 | |||
235 | err_reg: | ||
236 | err_gpio: | ||
237 | omap_dss_put_device(ddata->in); | ||
238 | return r; | ||
239 | } | ||
240 | |||
241 | static int __exit panel_dpi_remove(struct platform_device *pdev) | ||
242 | { | ||
243 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
244 | struct omap_dss_device *dssdev = &ddata->dssdev; | ||
245 | struct omap_dss_device *in = ddata->in; | ||
246 | |||
247 | omapdss_unregister_display(dssdev); | ||
248 | |||
249 | panel_dpi_disable(dssdev); | ||
250 | panel_dpi_disconnect(dssdev); | ||
251 | |||
252 | omap_dss_put_device(in); | ||
253 | |||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | static struct platform_driver panel_dpi_driver = { | ||
258 | .probe = panel_dpi_probe, | ||
259 | .remove = __exit_p(panel_dpi_remove), | ||
260 | .driver = { | ||
261 | .name = "panel-dpi", | ||
262 | .owner = THIS_MODULE, | ||
263 | }, | ||
264 | }; | ||
265 | |||
266 | module_platform_driver(panel_dpi_driver); | ||
267 | |||
268 | MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); | ||
269 | MODULE_DESCRIPTION("Generic MIPI DPI Panel Driver"); | ||
270 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays-new/panel-dsi-cm.c b/drivers/video/omap2/displays-new/panel-dsi-cm.c new file mode 100644 index 000000000000..aaaea6469cd9 --- /dev/null +++ b/drivers/video/omap2/displays-new/panel-dsi-cm.c | |||
@@ -0,0 +1,1336 @@ | |||
1 | /* | ||
2 | * Generic DSI Command Mode panel driver | ||
3 | * | ||
4 | * Copyright (C) 2013 Texas Instruments | ||
5 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> | ||
6 | * | ||
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. | ||
10 | */ | ||
11 | |||
12 | /* #define DEBUG */ | ||
13 | |||
14 | #include <linux/backlight.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/fb.h> | ||
17 | #include <linux/gpio.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/jiffies.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/workqueue.h> | ||
25 | |||
26 | #include <video/omapdss.h> | ||
27 | #include <video/omap-panel-data.h> | ||
28 | #include <video/mipi_display.h> | ||
29 | |||
30 | /* DSI Virtual channel. Hardcoded for now. */ | ||
31 | #define TCH 0 | ||
32 | |||
33 | #define DCS_READ_NUM_ERRORS 0x05 | ||
34 | #define DCS_BRIGHTNESS 0x51 | ||
35 | #define DCS_CTRL_DISPLAY 0x53 | ||
36 | #define DCS_GET_ID1 0xda | ||
37 | #define DCS_GET_ID2 0xdb | ||
38 | #define DCS_GET_ID3 0xdc | ||
39 | |||
40 | struct panel_drv_data { | ||
41 | struct omap_dss_device dssdev; | ||
42 | struct omap_dss_device *in; | ||
43 | |||
44 | struct omap_video_timings timings; | ||
45 | |||
46 | struct platform_device *pdev; | ||
47 | |||
48 | struct mutex lock; | ||
49 | |||
50 | struct backlight_device *bldev; | ||
51 | |||
52 | unsigned long hw_guard_end; /* next value of jiffies when we can | ||
53 | * issue the next sleep in/out command | ||
54 | */ | ||
55 | unsigned long hw_guard_wait; /* max guard time in jiffies */ | ||
56 | |||
57 | /* panel HW configuration from DT or platform data */ | ||
58 | int reset_gpio; | ||
59 | int ext_te_gpio; | ||
60 | |||
61 | bool use_dsi_backlight; | ||
62 | |||
63 | struct omap_dsi_pin_config pin_config; | ||
64 | |||
65 | /* runtime variables */ | ||
66 | bool enabled; | ||
67 | |||
68 | bool te_enabled; | ||
69 | |||
70 | atomic_t do_update; | ||
71 | int channel; | ||
72 | |||
73 | struct delayed_work te_timeout_work; | ||
74 | |||
75 | bool intro_printed; | ||
76 | |||
77 | struct workqueue_struct *workqueue; | ||
78 | |||
79 | bool ulps_enabled; | ||
80 | unsigned ulps_timeout; | ||
81 | struct delayed_work ulps_work; | ||
82 | }; | ||
83 | |||
84 | #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) | ||
85 | |||
86 | static irqreturn_t dsicm_te_isr(int irq, void *data); | ||
87 | static void dsicm_te_timeout_work_callback(struct work_struct *work); | ||
88 | static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable); | ||
89 | |||
90 | static int dsicm_panel_reset(struct panel_drv_data *ddata); | ||
91 | |||
92 | static void dsicm_ulps_work(struct work_struct *work); | ||
93 | |||
94 | static void hw_guard_start(struct panel_drv_data *ddata, int guard_msec) | ||
95 | { | ||
96 | ddata->hw_guard_wait = msecs_to_jiffies(guard_msec); | ||
97 | ddata->hw_guard_end = jiffies + ddata->hw_guard_wait; | ||
98 | } | ||
99 | |||
100 | static void hw_guard_wait(struct panel_drv_data *ddata) | ||
101 | { | ||
102 | unsigned long wait = ddata->hw_guard_end - jiffies; | ||
103 | |||
104 | if ((long)wait > 0 && wait <= ddata->hw_guard_wait) { | ||
105 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
106 | schedule_timeout(wait); | ||
107 | } | ||
108 | } | ||
109 | |||
110 | static int dsicm_dcs_read_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 *data) | ||
111 | { | ||
112 | struct omap_dss_device *in = ddata->in; | ||
113 | int r; | ||
114 | u8 buf[1]; | ||
115 | |||
116 | r = in->ops.dsi->dcs_read(in, ddata->channel, dcs_cmd, buf, 1); | ||
117 | |||
118 | if (r < 0) | ||
119 | return r; | ||
120 | |||
121 | *data = buf[0]; | ||
122 | |||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static int dsicm_dcs_write_0(struct panel_drv_data *ddata, u8 dcs_cmd) | ||
127 | { | ||
128 | struct omap_dss_device *in = ddata->in; | ||
129 | return in->ops.dsi->dcs_write(in, ddata->channel, &dcs_cmd, 1); | ||
130 | } | ||
131 | |||
132 | static int dsicm_dcs_write_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 param) | ||
133 | { | ||
134 | struct omap_dss_device *in = ddata->in; | ||
135 | u8 buf[2] = { dcs_cmd, param }; | ||
136 | |||
137 | return in->ops.dsi->dcs_write(in, ddata->channel, buf, 2); | ||
138 | } | ||
139 | |||
140 | static int dsicm_sleep_in(struct panel_drv_data *ddata) | ||
141 | |||
142 | { | ||
143 | struct omap_dss_device *in = ddata->in; | ||
144 | u8 cmd; | ||
145 | int r; | ||
146 | |||
147 | hw_guard_wait(ddata); | ||
148 | |||
149 | cmd = MIPI_DCS_ENTER_SLEEP_MODE; | ||
150 | r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, &cmd, 1); | ||
151 | if (r) | ||
152 | return r; | ||
153 | |||
154 | hw_guard_start(ddata, 120); | ||
155 | |||
156 | usleep_range(5000, 10000); | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static int dsicm_sleep_out(struct panel_drv_data *ddata) | ||
162 | { | ||
163 | int r; | ||
164 | |||
165 | hw_guard_wait(ddata); | ||
166 | |||
167 | r = dsicm_dcs_write_0(ddata, MIPI_DCS_EXIT_SLEEP_MODE); | ||
168 | if (r) | ||
169 | return r; | ||
170 | |||
171 | hw_guard_start(ddata, 120); | ||
172 | |||
173 | usleep_range(5000, 10000); | ||
174 | |||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static int dsicm_get_id(struct panel_drv_data *ddata, u8 *id1, u8 *id2, u8 *id3) | ||
179 | { | ||
180 | int r; | ||
181 | |||
182 | r = dsicm_dcs_read_1(ddata, DCS_GET_ID1, id1); | ||
183 | if (r) | ||
184 | return r; | ||
185 | r = dsicm_dcs_read_1(ddata, DCS_GET_ID2, id2); | ||
186 | if (r) | ||
187 | return r; | ||
188 | r = dsicm_dcs_read_1(ddata, DCS_GET_ID3, id3); | ||
189 | if (r) | ||
190 | return r; | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static int dsicm_set_update_window(struct panel_drv_data *ddata, | ||
196 | u16 x, u16 y, u16 w, u16 h) | ||
197 | { | ||
198 | struct omap_dss_device *in = ddata->in; | ||
199 | int r; | ||
200 | u16 x1 = x; | ||
201 | u16 x2 = x + w - 1; | ||
202 | u16 y1 = y; | ||
203 | u16 y2 = y + h - 1; | ||
204 | |||
205 | u8 buf[5]; | ||
206 | buf[0] = MIPI_DCS_SET_COLUMN_ADDRESS; | ||
207 | buf[1] = (x1 >> 8) & 0xff; | ||
208 | buf[2] = (x1 >> 0) & 0xff; | ||
209 | buf[3] = (x2 >> 8) & 0xff; | ||
210 | buf[4] = (x2 >> 0) & 0xff; | ||
211 | |||
212 | r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, buf, sizeof(buf)); | ||
213 | if (r) | ||
214 | return r; | ||
215 | |||
216 | buf[0] = MIPI_DCS_SET_PAGE_ADDRESS; | ||
217 | buf[1] = (y1 >> 8) & 0xff; | ||
218 | buf[2] = (y1 >> 0) & 0xff; | ||
219 | buf[3] = (y2 >> 8) & 0xff; | ||
220 | buf[4] = (y2 >> 0) & 0xff; | ||
221 | |||
222 | r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, buf, sizeof(buf)); | ||
223 | if (r) | ||
224 | return r; | ||
225 | |||
226 | in->ops.dsi->bta_sync(in, ddata->channel); | ||
227 | |||
228 | return r; | ||
229 | } | ||
230 | |||
231 | static void dsicm_queue_ulps_work(struct panel_drv_data *ddata) | ||
232 | { | ||
233 | if (ddata->ulps_timeout > 0) | ||
234 | queue_delayed_work(ddata->workqueue, &ddata->ulps_work, | ||
235 | msecs_to_jiffies(ddata->ulps_timeout)); | ||
236 | } | ||
237 | |||
238 | static void dsicm_cancel_ulps_work(struct panel_drv_data *ddata) | ||
239 | { | ||
240 | cancel_delayed_work(&ddata->ulps_work); | ||
241 | } | ||
242 | |||
243 | static int dsicm_enter_ulps(struct panel_drv_data *ddata) | ||
244 | { | ||
245 | struct omap_dss_device *in = ddata->in; | ||
246 | int r; | ||
247 | |||
248 | if (ddata->ulps_enabled) | ||
249 | return 0; | ||
250 | |||
251 | dsicm_cancel_ulps_work(ddata); | ||
252 | |||
253 | r = _dsicm_enable_te(ddata, false); | ||
254 | if (r) | ||
255 | goto err; | ||
256 | |||
257 | if (gpio_is_valid(ddata->ext_te_gpio)) | ||
258 | disable_irq(gpio_to_irq(ddata->ext_te_gpio)); | ||
259 | |||
260 | in->ops.dsi->disable(in, false, true); | ||
261 | |||
262 | ddata->ulps_enabled = true; | ||
263 | |||
264 | return 0; | ||
265 | |||
266 | err: | ||
267 | dev_err(&ddata->pdev->dev, "enter ULPS failed"); | ||
268 | dsicm_panel_reset(ddata); | ||
269 | |||
270 | ddata->ulps_enabled = false; | ||
271 | |||
272 | dsicm_queue_ulps_work(ddata); | ||
273 | |||
274 | return r; | ||
275 | } | ||
276 | |||
277 | static int dsicm_exit_ulps(struct panel_drv_data *ddata) | ||
278 | { | ||
279 | struct omap_dss_device *in = ddata->in; | ||
280 | int r; | ||
281 | |||
282 | if (!ddata->ulps_enabled) | ||
283 | return 0; | ||
284 | |||
285 | r = in->ops.dsi->enable(in); | ||
286 | if (r) { | ||
287 | dev_err(&ddata->pdev->dev, "failed to enable DSI\n"); | ||
288 | goto err1; | ||
289 | } | ||
290 | |||
291 | in->ops.dsi->enable_hs(in, ddata->channel, true); | ||
292 | |||
293 | r = _dsicm_enable_te(ddata, true); | ||
294 | if (r) { | ||
295 | dev_err(&ddata->pdev->dev, "failed to re-enable TE"); | ||
296 | goto err2; | ||
297 | } | ||
298 | |||
299 | if (gpio_is_valid(ddata->ext_te_gpio)) | ||
300 | enable_irq(gpio_to_irq(ddata->ext_te_gpio)); | ||
301 | |||
302 | dsicm_queue_ulps_work(ddata); | ||
303 | |||
304 | ddata->ulps_enabled = false; | ||
305 | |||
306 | return 0; | ||
307 | |||
308 | err2: | ||
309 | dev_err(&ddata->pdev->dev, "failed to exit ULPS"); | ||
310 | |||
311 | r = dsicm_panel_reset(ddata); | ||
312 | if (!r) { | ||
313 | if (gpio_is_valid(ddata->ext_te_gpio)) | ||
314 | enable_irq(gpio_to_irq(ddata->ext_te_gpio)); | ||
315 | ddata->ulps_enabled = false; | ||
316 | } | ||
317 | err1: | ||
318 | dsicm_queue_ulps_work(ddata); | ||
319 | |||
320 | return r; | ||
321 | } | ||
322 | |||
323 | static int dsicm_wake_up(struct panel_drv_data *ddata) | ||
324 | { | ||
325 | if (ddata->ulps_enabled) | ||
326 | return dsicm_exit_ulps(ddata); | ||
327 | |||
328 | dsicm_cancel_ulps_work(ddata); | ||
329 | dsicm_queue_ulps_work(ddata); | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | static int dsicm_bl_update_status(struct backlight_device *dev) | ||
334 | { | ||
335 | struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev); | ||
336 | struct omap_dss_device *in = ddata->in; | ||
337 | int r; | ||
338 | int level; | ||
339 | |||
340 | if (dev->props.fb_blank == FB_BLANK_UNBLANK && | ||
341 | dev->props.power == FB_BLANK_UNBLANK) | ||
342 | level = dev->props.brightness; | ||
343 | else | ||
344 | level = 0; | ||
345 | |||
346 | dev_dbg(&ddata->pdev->dev, "update brightness to %d\n", level); | ||
347 | |||
348 | mutex_lock(&ddata->lock); | ||
349 | |||
350 | if (ddata->enabled) { | ||
351 | in->ops.dsi->bus_lock(in); | ||
352 | |||
353 | r = dsicm_wake_up(ddata); | ||
354 | if (!r) | ||
355 | r = dsicm_dcs_write_1(ddata, DCS_BRIGHTNESS, level); | ||
356 | |||
357 | in->ops.dsi->bus_unlock(in); | ||
358 | } else { | ||
359 | r = 0; | ||
360 | } | ||
361 | |||
362 | mutex_unlock(&ddata->lock); | ||
363 | |||
364 | return r; | ||
365 | } | ||
366 | |||
367 | static int dsicm_bl_get_intensity(struct backlight_device *dev) | ||
368 | { | ||
369 | if (dev->props.fb_blank == FB_BLANK_UNBLANK && | ||
370 | dev->props.power == FB_BLANK_UNBLANK) | ||
371 | return dev->props.brightness; | ||
372 | |||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static const struct backlight_ops dsicm_bl_ops = { | ||
377 | .get_brightness = dsicm_bl_get_intensity, | ||
378 | .update_status = dsicm_bl_update_status, | ||
379 | }; | ||
380 | |||
381 | static void dsicm_get_resolution(struct omap_dss_device *dssdev, | ||
382 | u16 *xres, u16 *yres) | ||
383 | { | ||
384 | *xres = dssdev->panel.timings.x_res; | ||
385 | *yres = dssdev->panel.timings.y_res; | ||
386 | } | ||
387 | |||
388 | static ssize_t dsicm_num_errors_show(struct device *dev, | ||
389 | struct device_attribute *attr, char *buf) | ||
390 | { | ||
391 | struct platform_device *pdev = to_platform_device(dev); | ||
392 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
393 | struct omap_dss_device *in = ddata->in; | ||
394 | u8 errors = 0; | ||
395 | int r; | ||
396 | |||
397 | mutex_lock(&ddata->lock); | ||
398 | |||
399 | if (ddata->enabled) { | ||
400 | in->ops.dsi->bus_lock(in); | ||
401 | |||
402 | r = dsicm_wake_up(ddata); | ||
403 | if (!r) | ||
404 | r = dsicm_dcs_read_1(ddata, DCS_READ_NUM_ERRORS, | ||
405 | &errors); | ||
406 | |||
407 | in->ops.dsi->bus_unlock(in); | ||
408 | } else { | ||
409 | r = -ENODEV; | ||
410 | } | ||
411 | |||
412 | mutex_unlock(&ddata->lock); | ||
413 | |||
414 | if (r) | ||
415 | return r; | ||
416 | |||
417 | return snprintf(buf, PAGE_SIZE, "%d\n", errors); | ||
418 | } | ||
419 | |||
420 | static ssize_t dsicm_hw_revision_show(struct device *dev, | ||
421 | struct device_attribute *attr, char *buf) | ||
422 | { | ||
423 | struct platform_device *pdev = to_platform_device(dev); | ||
424 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
425 | struct omap_dss_device *in = ddata->in; | ||
426 | u8 id1, id2, id3; | ||
427 | int r; | ||
428 | |||
429 | mutex_lock(&ddata->lock); | ||
430 | |||
431 | if (ddata->enabled) { | ||
432 | in->ops.dsi->bus_lock(in); | ||
433 | |||
434 | r = dsicm_wake_up(ddata); | ||
435 | if (!r) | ||
436 | r = dsicm_get_id(ddata, &id1, &id2, &id3); | ||
437 | |||
438 | in->ops.dsi->bus_unlock(in); | ||
439 | } else { | ||
440 | r = -ENODEV; | ||
441 | } | ||
442 | |||
443 | mutex_unlock(&ddata->lock); | ||
444 | |||
445 | if (r) | ||
446 | return r; | ||
447 | |||
448 | return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x\n", id1, id2, id3); | ||
449 | } | ||
450 | |||
451 | static ssize_t dsicm_store_ulps(struct device *dev, | ||
452 | struct device_attribute *attr, | ||
453 | const char *buf, size_t count) | ||
454 | { | ||
455 | struct platform_device *pdev = to_platform_device(dev); | ||
456 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
457 | struct omap_dss_device *in = ddata->in; | ||
458 | unsigned long t; | ||
459 | int r; | ||
460 | |||
461 | r = kstrtoul(buf, 0, &t); | ||
462 | if (r) | ||
463 | return r; | ||
464 | |||
465 | mutex_lock(&ddata->lock); | ||
466 | |||
467 | if (ddata->enabled) { | ||
468 | in->ops.dsi->bus_lock(in); | ||
469 | |||
470 | if (t) | ||
471 | r = dsicm_enter_ulps(ddata); | ||
472 | else | ||
473 | r = dsicm_wake_up(ddata); | ||
474 | |||
475 | in->ops.dsi->bus_unlock(in); | ||
476 | } | ||
477 | |||
478 | mutex_unlock(&ddata->lock); | ||
479 | |||
480 | if (r) | ||
481 | return r; | ||
482 | |||
483 | return count; | ||
484 | } | ||
485 | |||
486 | static ssize_t dsicm_show_ulps(struct device *dev, | ||
487 | struct device_attribute *attr, | ||
488 | char *buf) | ||
489 | { | ||
490 | struct platform_device *pdev = to_platform_device(dev); | ||
491 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
492 | unsigned t; | ||
493 | |||
494 | mutex_lock(&ddata->lock); | ||
495 | t = ddata->ulps_enabled; | ||
496 | mutex_unlock(&ddata->lock); | ||
497 | |||
498 | return snprintf(buf, PAGE_SIZE, "%u\n", t); | ||
499 | } | ||
500 | |||
501 | static ssize_t dsicm_store_ulps_timeout(struct device *dev, | ||
502 | struct device_attribute *attr, | ||
503 | const char *buf, size_t count) | ||
504 | { | ||
505 | struct platform_device *pdev = to_platform_device(dev); | ||
506 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
507 | struct omap_dss_device *in = ddata->in; | ||
508 | unsigned long t; | ||
509 | int r; | ||
510 | |||
511 | r = kstrtoul(buf, 0, &t); | ||
512 | if (r) | ||
513 | return r; | ||
514 | |||
515 | mutex_lock(&ddata->lock); | ||
516 | ddata->ulps_timeout = t; | ||
517 | |||
518 | if (ddata->enabled) { | ||
519 | /* dsicm_wake_up will restart the timer */ | ||
520 | in->ops.dsi->bus_lock(in); | ||
521 | r = dsicm_wake_up(ddata); | ||
522 | in->ops.dsi->bus_unlock(in); | ||
523 | } | ||
524 | |||
525 | mutex_unlock(&ddata->lock); | ||
526 | |||
527 | if (r) | ||
528 | return r; | ||
529 | |||
530 | return count; | ||
531 | } | ||
532 | |||
533 | static ssize_t dsicm_show_ulps_timeout(struct device *dev, | ||
534 | struct device_attribute *attr, | ||
535 | char *buf) | ||
536 | { | ||
537 | struct platform_device *pdev = to_platform_device(dev); | ||
538 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
539 | unsigned t; | ||
540 | |||
541 | mutex_lock(&ddata->lock); | ||
542 | t = ddata->ulps_timeout; | ||
543 | mutex_unlock(&ddata->lock); | ||
544 | |||
545 | return snprintf(buf, PAGE_SIZE, "%u\n", t); | ||
546 | } | ||
547 | |||
548 | static DEVICE_ATTR(num_dsi_errors, S_IRUGO, dsicm_num_errors_show, NULL); | ||
549 | static DEVICE_ATTR(hw_revision, S_IRUGO, dsicm_hw_revision_show, NULL); | ||
550 | static DEVICE_ATTR(ulps, S_IRUGO | S_IWUSR, | ||
551 | dsicm_show_ulps, dsicm_store_ulps); | ||
552 | static DEVICE_ATTR(ulps_timeout, S_IRUGO | S_IWUSR, | ||
553 | dsicm_show_ulps_timeout, dsicm_store_ulps_timeout); | ||
554 | |||
555 | static struct attribute *dsicm_attrs[] = { | ||
556 | &dev_attr_num_dsi_errors.attr, | ||
557 | &dev_attr_hw_revision.attr, | ||
558 | &dev_attr_ulps.attr, | ||
559 | &dev_attr_ulps_timeout.attr, | ||
560 | NULL, | ||
561 | }; | ||
562 | |||
563 | static struct attribute_group dsicm_attr_group = { | ||
564 | .attrs = dsicm_attrs, | ||
565 | }; | ||
566 | |||
567 | static void dsicm_hw_reset(struct panel_drv_data *ddata) | ||
568 | { | ||
569 | if (!gpio_is_valid(ddata->reset_gpio)) | ||
570 | return; | ||
571 | |||
572 | gpio_set_value(ddata->reset_gpio, 1); | ||
573 | udelay(10); | ||
574 | /* reset the panel */ | ||
575 | gpio_set_value(ddata->reset_gpio, 0); | ||
576 | /* assert reset */ | ||
577 | udelay(10); | ||
578 | gpio_set_value(ddata->reset_gpio, 1); | ||
579 | /* wait after releasing reset */ | ||
580 | usleep_range(5000, 10000); | ||
581 | } | ||
582 | |||
583 | static int dsicm_power_on(struct panel_drv_data *ddata) | ||
584 | { | ||
585 | struct omap_dss_device *in = ddata->in; | ||
586 | u8 id1, id2, id3; | ||
587 | int r; | ||
588 | struct omap_dss_dsi_config dsi_config = { | ||
589 | .mode = OMAP_DSS_DSI_CMD_MODE, | ||
590 | .pixel_format = OMAP_DSS_DSI_FMT_RGB888, | ||
591 | .timings = &ddata->timings, | ||
592 | .hs_clk_min = 150000000, | ||
593 | .hs_clk_max = 300000000, | ||
594 | .lp_clk_min = 7000000, | ||
595 | .lp_clk_max = 10000000, | ||
596 | }; | ||
597 | |||
598 | r = in->ops.dsi->configure_pins(in, &ddata->pin_config); | ||
599 | if (r) { | ||
600 | dev_err(&ddata->pdev->dev, "failed to configure DSI pins\n"); | ||
601 | goto err0; | ||
602 | }; | ||
603 | |||
604 | r = in->ops.dsi->set_config(in, &dsi_config); | ||
605 | if (r) { | ||
606 | dev_err(&ddata->pdev->dev, "failed to configure DSI\n"); | ||
607 | goto err0; | ||
608 | } | ||
609 | |||
610 | r = in->ops.dsi->enable(in); | ||
611 | if (r) { | ||
612 | dev_err(&ddata->pdev->dev, "failed to enable DSI\n"); | ||
613 | goto err0; | ||
614 | } | ||
615 | |||
616 | dsicm_hw_reset(ddata); | ||
617 | |||
618 | in->ops.dsi->enable_hs(in, ddata->channel, false); | ||
619 | |||
620 | r = dsicm_sleep_out(ddata); | ||
621 | if (r) | ||
622 | goto err; | ||
623 | |||
624 | r = dsicm_get_id(ddata, &id1, &id2, &id3); | ||
625 | if (r) | ||
626 | goto err; | ||
627 | |||
628 | r = dsicm_dcs_write_1(ddata, DCS_BRIGHTNESS, 0xff); | ||
629 | if (r) | ||
630 | goto err; | ||
631 | |||
632 | r = dsicm_dcs_write_1(ddata, DCS_CTRL_DISPLAY, | ||
633 | (1<<2) | (1<<5)); /* BL | BCTRL */ | ||
634 | if (r) | ||
635 | goto err; | ||
636 | |||
637 | r = dsicm_dcs_write_1(ddata, MIPI_DCS_SET_PIXEL_FORMAT, | ||
638 | MIPI_DCS_PIXEL_FMT_24BIT); | ||
639 | if (r) | ||
640 | goto err; | ||
641 | |||
642 | r = dsicm_dcs_write_0(ddata, MIPI_DCS_SET_DISPLAY_ON); | ||
643 | if (r) | ||
644 | goto err; | ||
645 | |||
646 | r = _dsicm_enable_te(ddata, ddata->te_enabled); | ||
647 | if (r) | ||
648 | goto err; | ||
649 | |||
650 | r = in->ops.dsi->enable_video_output(in, ddata->channel); | ||
651 | if (r) | ||
652 | goto err; | ||
653 | |||
654 | ddata->enabled = 1; | ||
655 | |||
656 | if (!ddata->intro_printed) { | ||
657 | dev_info(&ddata->pdev->dev, "panel revision %02x.%02x.%02x\n", | ||
658 | id1, id2, id3); | ||
659 | ddata->intro_printed = true; | ||
660 | } | ||
661 | |||
662 | in->ops.dsi->enable_hs(in, ddata->channel, true); | ||
663 | |||
664 | return 0; | ||
665 | err: | ||
666 | dev_err(&ddata->pdev->dev, "error while enabling panel, issuing HW reset\n"); | ||
667 | |||
668 | dsicm_hw_reset(ddata); | ||
669 | |||
670 | in->ops.dsi->disable(in, true, false); | ||
671 | err0: | ||
672 | return r; | ||
673 | } | ||
674 | |||
675 | static void dsicm_power_off(struct panel_drv_data *ddata) | ||
676 | { | ||
677 | struct omap_dss_device *in = ddata->in; | ||
678 | int r; | ||
679 | |||
680 | in->ops.dsi->disable_video_output(in, ddata->channel); | ||
681 | |||
682 | r = dsicm_dcs_write_0(ddata, MIPI_DCS_SET_DISPLAY_OFF); | ||
683 | if (!r) | ||
684 | r = dsicm_sleep_in(ddata); | ||
685 | |||
686 | if (r) { | ||
687 | dev_err(&ddata->pdev->dev, | ||
688 | "error disabling panel, issuing HW reset\n"); | ||
689 | dsicm_hw_reset(ddata); | ||
690 | } | ||
691 | |||
692 | in->ops.dsi->disable(in, true, false); | ||
693 | |||
694 | ddata->enabled = 0; | ||
695 | } | ||
696 | |||
697 | static int dsicm_panel_reset(struct panel_drv_data *ddata) | ||
698 | { | ||
699 | dev_err(&ddata->pdev->dev, "performing LCD reset\n"); | ||
700 | |||
701 | dsicm_power_off(ddata); | ||
702 | dsicm_hw_reset(ddata); | ||
703 | return dsicm_power_on(ddata); | ||
704 | } | ||
705 | |||
706 | static int dsicm_connect(struct omap_dss_device *dssdev) | ||
707 | { | ||
708 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
709 | struct omap_dss_device *in = ddata->in; | ||
710 | struct device *dev = &ddata->pdev->dev; | ||
711 | int r; | ||
712 | |||
713 | if (omapdss_device_is_connected(dssdev)) | ||
714 | return 0; | ||
715 | |||
716 | r = in->ops.dsi->connect(in, dssdev); | ||
717 | if (r) { | ||
718 | dev_err(dev, "Failed to connect to video source\n"); | ||
719 | return r; | ||
720 | } | ||
721 | |||
722 | r = in->ops.dsi->request_vc(ddata->in, &ddata->channel); | ||
723 | if (r) { | ||
724 | dev_err(dev, "failed to get virtual channel\n"); | ||
725 | goto err_req_vc; | ||
726 | } | ||
727 | |||
728 | r = in->ops.dsi->set_vc_id(ddata->in, ddata->channel, TCH); | ||
729 | if (r) { | ||
730 | dev_err(dev, "failed to set VC_ID\n"); | ||
731 | goto err_vc_id; | ||
732 | } | ||
733 | |||
734 | return 0; | ||
735 | |||
736 | err_vc_id: | ||
737 | in->ops.dsi->release_vc(ddata->in, ddata->channel); | ||
738 | err_req_vc: | ||
739 | in->ops.dsi->disconnect(in, dssdev); | ||
740 | return r; | ||
741 | } | ||
742 | |||
743 | static void dsicm_disconnect(struct omap_dss_device *dssdev) | ||
744 | { | ||
745 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
746 | struct omap_dss_device *in = ddata->in; | ||
747 | |||
748 | if (!omapdss_device_is_connected(dssdev)) | ||
749 | return; | ||
750 | |||
751 | in->ops.dsi->release_vc(in, ddata->channel); | ||
752 | in->ops.dsi->disconnect(in, dssdev); | ||
753 | } | ||
754 | |||
755 | static int dsicm_enable(struct omap_dss_device *dssdev) | ||
756 | { | ||
757 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
758 | struct omap_dss_device *in = ddata->in; | ||
759 | int r; | ||
760 | |||
761 | dev_dbg(&ddata->pdev->dev, "enable\n"); | ||
762 | |||
763 | mutex_lock(&ddata->lock); | ||
764 | |||
765 | if (!omapdss_device_is_connected(dssdev)) { | ||
766 | r = -ENODEV; | ||
767 | goto err; | ||
768 | } | ||
769 | |||
770 | if (omapdss_device_is_enabled(dssdev)) { | ||
771 | r = 0; | ||
772 | goto err; | ||
773 | } | ||
774 | |||
775 | in->ops.dsi->bus_lock(in); | ||
776 | |||
777 | r = dsicm_power_on(ddata); | ||
778 | |||
779 | in->ops.dsi->bus_unlock(in); | ||
780 | |||
781 | if (r) | ||
782 | goto err; | ||
783 | |||
784 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
785 | |||
786 | mutex_unlock(&ddata->lock); | ||
787 | |||
788 | return 0; | ||
789 | err: | ||
790 | dev_dbg(&ddata->pdev->dev, "enable failed\n"); | ||
791 | mutex_unlock(&ddata->lock); | ||
792 | return r; | ||
793 | } | ||
794 | |||
795 | static void dsicm_disable(struct omap_dss_device *dssdev) | ||
796 | { | ||
797 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
798 | struct omap_dss_device *in = ddata->in; | ||
799 | int r; | ||
800 | |||
801 | dev_dbg(&ddata->pdev->dev, "disable\n"); | ||
802 | |||
803 | mutex_lock(&ddata->lock); | ||
804 | |||
805 | dsicm_cancel_ulps_work(ddata); | ||
806 | |||
807 | in->ops.dsi->bus_lock(in); | ||
808 | |||
809 | if (omapdss_device_is_enabled(dssdev)) { | ||
810 | r = dsicm_wake_up(ddata); | ||
811 | if (!r) | ||
812 | dsicm_power_off(ddata); | ||
813 | } | ||
814 | |||
815 | in->ops.dsi->bus_unlock(in); | ||
816 | |||
817 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
818 | |||
819 | mutex_unlock(&ddata->lock); | ||
820 | } | ||
821 | |||
822 | static void dsicm_framedone_cb(int err, void *data) | ||
823 | { | ||
824 | struct panel_drv_data *ddata = data; | ||
825 | struct omap_dss_device *in = ddata->in; | ||
826 | |||
827 | dev_dbg(&ddata->pdev->dev, "framedone, err %d\n", err); | ||
828 | in->ops.dsi->bus_unlock(ddata->in); | ||
829 | } | ||
830 | |||
831 | static irqreturn_t dsicm_te_isr(int irq, void *data) | ||
832 | { | ||
833 | struct panel_drv_data *ddata = data; | ||
834 | struct omap_dss_device *in = ddata->in; | ||
835 | int old; | ||
836 | int r; | ||
837 | |||
838 | old = atomic_cmpxchg(&ddata->do_update, 1, 0); | ||
839 | |||
840 | if (old) { | ||
841 | cancel_delayed_work(&ddata->te_timeout_work); | ||
842 | |||
843 | r = in->ops.dsi->update(in, ddata->channel, dsicm_framedone_cb, | ||
844 | ddata); | ||
845 | if (r) | ||
846 | goto err; | ||
847 | } | ||
848 | |||
849 | return IRQ_HANDLED; | ||
850 | err: | ||
851 | dev_err(&ddata->pdev->dev, "start update failed\n"); | ||
852 | in->ops.dsi->bus_unlock(in); | ||
853 | return IRQ_HANDLED; | ||
854 | } | ||
855 | |||
856 | static void dsicm_te_timeout_work_callback(struct work_struct *work) | ||
857 | { | ||
858 | struct panel_drv_data *ddata = container_of(work, struct panel_drv_data, | ||
859 | te_timeout_work.work); | ||
860 | struct omap_dss_device *in = ddata->in; | ||
861 | |||
862 | dev_err(&ddata->pdev->dev, "TE not received for 250ms!\n"); | ||
863 | |||
864 | atomic_set(&ddata->do_update, 0); | ||
865 | in->ops.dsi->bus_unlock(in); | ||
866 | } | ||
867 | |||
868 | static int dsicm_update(struct omap_dss_device *dssdev, | ||
869 | u16 x, u16 y, u16 w, u16 h) | ||
870 | { | ||
871 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
872 | struct omap_dss_device *in = ddata->in; | ||
873 | int r; | ||
874 | |||
875 | dev_dbg(&ddata->pdev->dev, "update %d, %d, %d x %d\n", x, y, w, h); | ||
876 | |||
877 | mutex_lock(&ddata->lock); | ||
878 | in->ops.dsi->bus_lock(in); | ||
879 | |||
880 | r = dsicm_wake_up(ddata); | ||
881 | if (r) | ||
882 | goto err; | ||
883 | |||
884 | if (!ddata->enabled) { | ||
885 | r = 0; | ||
886 | goto err; | ||
887 | } | ||
888 | |||
889 | /* XXX no need to send this every frame, but dsi break if not done */ | ||
890 | r = dsicm_set_update_window(ddata, 0, 0, | ||
891 | dssdev->panel.timings.x_res, | ||
892 | dssdev->panel.timings.y_res); | ||
893 | if (r) | ||
894 | goto err; | ||
895 | |||
896 | if (ddata->te_enabled && gpio_is_valid(ddata->ext_te_gpio)) { | ||
897 | schedule_delayed_work(&ddata->te_timeout_work, | ||
898 | msecs_to_jiffies(250)); | ||
899 | atomic_set(&ddata->do_update, 1); | ||
900 | } else { | ||
901 | r = in->ops.dsi->update(in, ddata->channel, dsicm_framedone_cb, | ||
902 | ddata); | ||
903 | if (r) | ||
904 | goto err; | ||
905 | } | ||
906 | |||
907 | /* note: no bus_unlock here. unlock is in framedone_cb */ | ||
908 | mutex_unlock(&ddata->lock); | ||
909 | return 0; | ||
910 | err: | ||
911 | in->ops.dsi->bus_unlock(in); | ||
912 | mutex_unlock(&ddata->lock); | ||
913 | return r; | ||
914 | } | ||
915 | |||
916 | static int dsicm_sync(struct omap_dss_device *dssdev) | ||
917 | { | ||
918 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
919 | struct omap_dss_device *in = ddata->in; | ||
920 | |||
921 | dev_dbg(&ddata->pdev->dev, "sync\n"); | ||
922 | |||
923 | mutex_lock(&ddata->lock); | ||
924 | in->ops.dsi->bus_lock(in); | ||
925 | in->ops.dsi->bus_unlock(in); | ||
926 | mutex_unlock(&ddata->lock); | ||
927 | |||
928 | dev_dbg(&ddata->pdev->dev, "sync done\n"); | ||
929 | |||
930 | return 0; | ||
931 | } | ||
932 | |||
933 | static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable) | ||
934 | { | ||
935 | struct omap_dss_device *in = ddata->in; | ||
936 | int r; | ||
937 | |||
938 | if (enable) | ||
939 | r = dsicm_dcs_write_1(ddata, MIPI_DCS_SET_TEAR_ON, 0); | ||
940 | else | ||
941 | r = dsicm_dcs_write_0(ddata, MIPI_DCS_SET_TEAR_OFF); | ||
942 | |||
943 | if (!gpio_is_valid(ddata->ext_te_gpio)) | ||
944 | in->ops.dsi->enable_te(in, enable); | ||
945 | |||
946 | /* possible panel bug */ | ||
947 | msleep(100); | ||
948 | |||
949 | return r; | ||
950 | } | ||
951 | |||
952 | static int dsicm_enable_te(struct omap_dss_device *dssdev, bool enable) | ||
953 | { | ||
954 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
955 | struct omap_dss_device *in = ddata->in; | ||
956 | int r; | ||
957 | |||
958 | mutex_lock(&ddata->lock); | ||
959 | |||
960 | if (ddata->te_enabled == enable) | ||
961 | goto end; | ||
962 | |||
963 | in->ops.dsi->bus_lock(in); | ||
964 | |||
965 | if (ddata->enabled) { | ||
966 | r = dsicm_wake_up(ddata); | ||
967 | if (r) | ||
968 | goto err; | ||
969 | |||
970 | r = _dsicm_enable_te(ddata, enable); | ||
971 | if (r) | ||
972 | goto err; | ||
973 | } | ||
974 | |||
975 | ddata->te_enabled = enable; | ||
976 | |||
977 | in->ops.dsi->bus_unlock(in); | ||
978 | end: | ||
979 | mutex_unlock(&ddata->lock); | ||
980 | |||
981 | return 0; | ||
982 | err: | ||
983 | in->ops.dsi->bus_unlock(in); | ||
984 | mutex_unlock(&ddata->lock); | ||
985 | |||
986 | return r; | ||
987 | } | ||
988 | |||
989 | static int dsicm_get_te(struct omap_dss_device *dssdev) | ||
990 | { | ||
991 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
992 | int r; | ||
993 | |||
994 | mutex_lock(&ddata->lock); | ||
995 | r = ddata->te_enabled; | ||
996 | mutex_unlock(&ddata->lock); | ||
997 | |||
998 | return r; | ||
999 | } | ||
1000 | |||
1001 | static int dsicm_memory_read(struct omap_dss_device *dssdev, | ||
1002 | void *buf, size_t size, | ||
1003 | u16 x, u16 y, u16 w, u16 h) | ||
1004 | { | ||
1005 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
1006 | struct omap_dss_device *in = ddata->in; | ||
1007 | int r; | ||
1008 | int first = 1; | ||
1009 | int plen; | ||
1010 | unsigned buf_used = 0; | ||
1011 | |||
1012 | if (size < w * h * 3) | ||
1013 | return -ENOMEM; | ||
1014 | |||
1015 | mutex_lock(&ddata->lock); | ||
1016 | |||
1017 | if (!ddata->enabled) { | ||
1018 | r = -ENODEV; | ||
1019 | goto err1; | ||
1020 | } | ||
1021 | |||
1022 | size = min(w * h * 3, | ||
1023 | dssdev->panel.timings.x_res * | ||
1024 | dssdev->panel.timings.y_res * 3); | ||
1025 | |||
1026 | in->ops.dsi->bus_lock(in); | ||
1027 | |||
1028 | r = dsicm_wake_up(ddata); | ||
1029 | if (r) | ||
1030 | goto err2; | ||
1031 | |||
1032 | /* plen 1 or 2 goes into short packet. until checksum error is fixed, | ||
1033 | * use short packets. plen 32 works, but bigger packets seem to cause | ||
1034 | * an error. */ | ||
1035 | if (size % 2) | ||
1036 | plen = 1; | ||
1037 | else | ||
1038 | plen = 2; | ||
1039 | |||
1040 | dsicm_set_update_window(ddata, x, y, w, h); | ||
1041 | |||
1042 | r = in->ops.dsi->set_max_rx_packet_size(in, ddata->channel, plen); | ||
1043 | if (r) | ||
1044 | goto err2; | ||
1045 | |||
1046 | while (buf_used < size) { | ||
1047 | u8 dcs_cmd = first ? 0x2e : 0x3e; | ||
1048 | first = 0; | ||
1049 | |||
1050 | r = in->ops.dsi->dcs_read(in, ddata->channel, dcs_cmd, | ||
1051 | buf + buf_used, size - buf_used); | ||
1052 | |||
1053 | if (r < 0) { | ||
1054 | dev_err(dssdev->dev, "read error\n"); | ||
1055 | goto err3; | ||
1056 | } | ||
1057 | |||
1058 | buf_used += r; | ||
1059 | |||
1060 | if (r < plen) { | ||
1061 | dev_err(&ddata->pdev->dev, "short read\n"); | ||
1062 | break; | ||
1063 | } | ||
1064 | |||
1065 | if (signal_pending(current)) { | ||
1066 | dev_err(&ddata->pdev->dev, "signal pending, " | ||
1067 | "aborting memory read\n"); | ||
1068 | r = -ERESTARTSYS; | ||
1069 | goto err3; | ||
1070 | } | ||
1071 | } | ||
1072 | |||
1073 | r = buf_used; | ||
1074 | |||
1075 | err3: | ||
1076 | in->ops.dsi->set_max_rx_packet_size(in, ddata->channel, 1); | ||
1077 | err2: | ||
1078 | in->ops.dsi->bus_unlock(in); | ||
1079 | err1: | ||
1080 | mutex_unlock(&ddata->lock); | ||
1081 | return r; | ||
1082 | } | ||
1083 | |||
1084 | static void dsicm_ulps_work(struct work_struct *work) | ||
1085 | { | ||
1086 | struct panel_drv_data *ddata = container_of(work, struct panel_drv_data, | ||
1087 | ulps_work.work); | ||
1088 | struct omap_dss_device *dssdev = &ddata->dssdev; | ||
1089 | struct omap_dss_device *in = ddata->in; | ||
1090 | |||
1091 | mutex_lock(&ddata->lock); | ||
1092 | |||
1093 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE || !ddata->enabled) { | ||
1094 | mutex_unlock(&ddata->lock); | ||
1095 | return; | ||
1096 | } | ||
1097 | |||
1098 | in->ops.dsi->bus_lock(in); | ||
1099 | |||
1100 | dsicm_enter_ulps(ddata); | ||
1101 | |||
1102 | in->ops.dsi->bus_unlock(in); | ||
1103 | mutex_unlock(&ddata->lock); | ||
1104 | } | ||
1105 | |||
1106 | static struct omap_dss_driver dsicm_ops = { | ||
1107 | .connect = dsicm_connect, | ||
1108 | .disconnect = dsicm_disconnect, | ||
1109 | |||
1110 | .enable = dsicm_enable, | ||
1111 | .disable = dsicm_disable, | ||
1112 | |||
1113 | .update = dsicm_update, | ||
1114 | .sync = dsicm_sync, | ||
1115 | |||
1116 | .get_resolution = dsicm_get_resolution, | ||
1117 | .get_recommended_bpp = omapdss_default_get_recommended_bpp, | ||
1118 | |||
1119 | .enable_te = dsicm_enable_te, | ||
1120 | .get_te = dsicm_get_te, | ||
1121 | |||
1122 | .memory_read = dsicm_memory_read, | ||
1123 | }; | ||
1124 | |||
1125 | static int dsicm_probe_pdata(struct platform_device *pdev) | ||
1126 | { | ||
1127 | const struct panel_dsicm_platform_data *pdata; | ||
1128 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
1129 | struct omap_dss_device *dssdev, *in; | ||
1130 | |||
1131 | pdata = dev_get_platdata(&pdev->dev); | ||
1132 | |||
1133 | in = omap_dss_find_output(pdata->source); | ||
1134 | if (in == NULL) { | ||
1135 | dev_err(&pdev->dev, "failed to find video source\n"); | ||
1136 | return -EPROBE_DEFER; | ||
1137 | } | ||
1138 | ddata->in = in; | ||
1139 | |||
1140 | ddata->reset_gpio = pdata->reset_gpio; | ||
1141 | |||
1142 | if (pdata->use_ext_te) | ||
1143 | ddata->ext_te_gpio = pdata->ext_te_gpio; | ||
1144 | else | ||
1145 | ddata->ext_te_gpio = -1; | ||
1146 | |||
1147 | ddata->ulps_timeout = pdata->ulps_timeout; | ||
1148 | |||
1149 | ddata->use_dsi_backlight = pdata->use_dsi_backlight; | ||
1150 | |||
1151 | ddata->pin_config = pdata->pin_config; | ||
1152 | |||
1153 | dssdev = &ddata->dssdev; | ||
1154 | dssdev->name = pdata->name; | ||
1155 | |||
1156 | return 0; | ||
1157 | } | ||
1158 | |||
1159 | static int dsicm_probe(struct platform_device *pdev) | ||
1160 | { | ||
1161 | struct backlight_properties props; | ||
1162 | struct panel_drv_data *ddata; | ||
1163 | struct backlight_device *bldev = NULL; | ||
1164 | struct device *dev = &pdev->dev; | ||
1165 | struct omap_dss_device *dssdev; | ||
1166 | int r; | ||
1167 | |||
1168 | dev_dbg(dev, "probe\n"); | ||
1169 | |||
1170 | ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); | ||
1171 | if (!ddata) | ||
1172 | return -ENOMEM; | ||
1173 | |||
1174 | platform_set_drvdata(pdev, ddata); | ||
1175 | ddata->pdev = pdev; | ||
1176 | |||
1177 | if (dev_get_platdata(dev)) { | ||
1178 | r = dsicm_probe_pdata(pdev); | ||
1179 | if (r) | ||
1180 | return r; | ||
1181 | } else { | ||
1182 | return -ENODEV; | ||
1183 | } | ||
1184 | |||
1185 | ddata->timings.x_res = 864; | ||
1186 | ddata->timings.y_res = 480; | ||
1187 | ddata->timings.pixel_clock = DIV_ROUND_UP(864 * 480 * 60, 1000); | ||
1188 | |||
1189 | dssdev = &ddata->dssdev; | ||
1190 | dssdev->dev = dev; | ||
1191 | dssdev->driver = &dsicm_ops; | ||
1192 | dssdev->panel.timings = ddata->timings; | ||
1193 | dssdev->type = OMAP_DISPLAY_TYPE_DSI; | ||
1194 | dssdev->owner = THIS_MODULE; | ||
1195 | |||
1196 | dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888; | ||
1197 | dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | | ||
1198 | OMAP_DSS_DISPLAY_CAP_TEAR_ELIM; | ||
1199 | |||
1200 | r = omapdss_register_display(dssdev); | ||
1201 | if (r) { | ||
1202 | dev_err(dev, "Failed to register panel\n"); | ||
1203 | goto err_reg; | ||
1204 | } | ||
1205 | |||
1206 | mutex_init(&ddata->lock); | ||
1207 | |||
1208 | atomic_set(&ddata->do_update, 0); | ||
1209 | |||
1210 | if (gpio_is_valid(ddata->reset_gpio)) { | ||
1211 | r = devm_gpio_request_one(dev, ddata->reset_gpio, | ||
1212 | GPIOF_OUT_INIT_LOW, "taal rst"); | ||
1213 | if (r) { | ||
1214 | dev_err(dev, "failed to request reset gpio\n"); | ||
1215 | return r; | ||
1216 | } | ||
1217 | } | ||
1218 | |||
1219 | if (gpio_is_valid(ddata->ext_te_gpio)) { | ||
1220 | r = devm_gpio_request_one(dev, ddata->ext_te_gpio, | ||
1221 | GPIOF_IN, "taal irq"); | ||
1222 | if (r) { | ||
1223 | dev_err(dev, "GPIO request failed\n"); | ||
1224 | return r; | ||
1225 | } | ||
1226 | |||
1227 | r = devm_request_irq(dev, gpio_to_irq(ddata->ext_te_gpio), | ||
1228 | dsicm_te_isr, | ||
1229 | IRQF_TRIGGER_RISING, | ||
1230 | "taal vsync", ddata); | ||
1231 | |||
1232 | if (r) { | ||
1233 | dev_err(dev, "IRQ request failed\n"); | ||
1234 | return r; | ||
1235 | } | ||
1236 | |||
1237 | INIT_DEFERRABLE_WORK(&ddata->te_timeout_work, | ||
1238 | dsicm_te_timeout_work_callback); | ||
1239 | |||
1240 | dev_dbg(dev, "Using GPIO TE\n"); | ||
1241 | } | ||
1242 | |||
1243 | ddata->workqueue = create_singlethread_workqueue("dsicm_wq"); | ||
1244 | if (ddata->workqueue == NULL) { | ||
1245 | dev_err(dev, "can't create workqueue\n"); | ||
1246 | return -ENOMEM; | ||
1247 | } | ||
1248 | INIT_DELAYED_WORK(&ddata->ulps_work, dsicm_ulps_work); | ||
1249 | |||
1250 | dsicm_hw_reset(ddata); | ||
1251 | |||
1252 | if (ddata->use_dsi_backlight) { | ||
1253 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
1254 | props.max_brightness = 255; | ||
1255 | |||
1256 | props.type = BACKLIGHT_RAW; | ||
1257 | bldev = backlight_device_register(dev_name(dev), | ||
1258 | dev, ddata, &dsicm_bl_ops, &props); | ||
1259 | if (IS_ERR(bldev)) { | ||
1260 | r = PTR_ERR(bldev); | ||
1261 | goto err_bl; | ||
1262 | } | ||
1263 | |||
1264 | ddata->bldev = bldev; | ||
1265 | |||
1266 | bldev->props.fb_blank = FB_BLANK_UNBLANK; | ||
1267 | bldev->props.power = FB_BLANK_UNBLANK; | ||
1268 | bldev->props.brightness = 255; | ||
1269 | |||
1270 | dsicm_bl_update_status(bldev); | ||
1271 | } | ||
1272 | |||
1273 | r = sysfs_create_group(&dev->kobj, &dsicm_attr_group); | ||
1274 | if (r) { | ||
1275 | dev_err(dev, "failed to create sysfs files\n"); | ||
1276 | goto err_sysfs_create; | ||
1277 | } | ||
1278 | |||
1279 | return 0; | ||
1280 | |||
1281 | err_sysfs_create: | ||
1282 | if (bldev != NULL) | ||
1283 | backlight_device_unregister(bldev); | ||
1284 | err_bl: | ||
1285 | destroy_workqueue(ddata->workqueue); | ||
1286 | err_reg: | ||
1287 | return r; | ||
1288 | } | ||
1289 | |||
1290 | static int __exit dsicm_remove(struct platform_device *pdev) | ||
1291 | { | ||
1292 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
1293 | struct omap_dss_device *dssdev = &ddata->dssdev; | ||
1294 | struct backlight_device *bldev; | ||
1295 | |||
1296 | dev_dbg(&pdev->dev, "remove\n"); | ||
1297 | |||
1298 | omapdss_unregister_display(dssdev); | ||
1299 | |||
1300 | dsicm_disable(dssdev); | ||
1301 | dsicm_disconnect(dssdev); | ||
1302 | |||
1303 | sysfs_remove_group(&pdev->dev.kobj, &dsicm_attr_group); | ||
1304 | |||
1305 | bldev = ddata->bldev; | ||
1306 | if (bldev != NULL) { | ||
1307 | bldev->props.power = FB_BLANK_POWERDOWN; | ||
1308 | dsicm_bl_update_status(bldev); | ||
1309 | backlight_device_unregister(bldev); | ||
1310 | } | ||
1311 | |||
1312 | omap_dss_put_device(ddata->in); | ||
1313 | |||
1314 | dsicm_cancel_ulps_work(ddata); | ||
1315 | destroy_workqueue(ddata->workqueue); | ||
1316 | |||
1317 | /* reset, to be sure that the panel is in a valid state */ | ||
1318 | dsicm_hw_reset(ddata); | ||
1319 | |||
1320 | return 0; | ||
1321 | } | ||
1322 | |||
1323 | static struct platform_driver dsicm_driver = { | ||
1324 | .probe = dsicm_probe, | ||
1325 | .remove = __exit_p(dsicm_remove), | ||
1326 | .driver = { | ||
1327 | .name = "panel-dsi-cm", | ||
1328 | .owner = THIS_MODULE, | ||
1329 | }, | ||
1330 | }; | ||
1331 | |||
1332 | module_platform_driver(dsicm_driver); | ||
1333 | |||
1334 | MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); | ||
1335 | MODULE_DESCRIPTION("Generic DSI Command Mode Panel Driver"); | ||
1336 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays-new/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays-new/panel-lgphilips-lb035q02.c new file mode 100644 index 000000000000..6e8977b18950 --- /dev/null +++ b/drivers/video/omap2/displays-new/panel-lgphilips-lb035q02.c | |||
@@ -0,0 +1,358 @@ | |||
1 | /* | ||
2 | * LG.Philips LB035Q02 LCD Panel driver | ||
3 | * | ||
4 | * Copyright (C) 2013 Texas Instruments | ||
5 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> | ||
6 | * Based on a driver by: Steve Sakoman <steve@sakoman.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License version 2 as published by | ||
10 | * the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/spi/spi.h> | ||
16 | #include <linux/mutex.h> | ||
17 | #include <linux/gpio.h> | ||
18 | |||
19 | #include <video/omapdss.h> | ||
20 | #include <video/omap-panel-data.h> | ||
21 | |||
22 | static struct omap_video_timings lb035q02_timings = { | ||
23 | .x_res = 320, | ||
24 | .y_res = 240, | ||
25 | |||
26 | .pixel_clock = 6500, | ||
27 | |||
28 | .hsw = 2, | ||
29 | .hfp = 20, | ||
30 | .hbp = 68, | ||
31 | |||
32 | .vsw = 2, | ||
33 | .vfp = 4, | ||
34 | .vbp = 18, | ||
35 | |||
36 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
37 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
38 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
39 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
40 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
41 | }; | ||
42 | |||
43 | struct panel_drv_data { | ||
44 | struct omap_dss_device dssdev; | ||
45 | struct omap_dss_device *in; | ||
46 | |||
47 | struct spi_device *spi; | ||
48 | |||
49 | int data_lines; | ||
50 | |||
51 | struct omap_video_timings videomode; | ||
52 | |||
53 | int reset_gpio; | ||
54 | int backlight_gpio; | ||
55 | int enable_gpio; | ||
56 | }; | ||
57 | |||
58 | #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) | ||
59 | |||
60 | static int lb035q02_write_reg(struct spi_device *spi, u8 reg, u16 val) | ||
61 | { | ||
62 | struct spi_message msg; | ||
63 | struct spi_transfer index_xfer = { | ||
64 | .len = 3, | ||
65 | .cs_change = 1, | ||
66 | }; | ||
67 | struct spi_transfer value_xfer = { | ||
68 | .len = 3, | ||
69 | }; | ||
70 | u8 buffer[16]; | ||
71 | |||
72 | spi_message_init(&msg); | ||
73 | |||
74 | /* register index */ | ||
75 | buffer[0] = 0x70; | ||
76 | buffer[1] = 0x00; | ||
77 | buffer[2] = reg & 0x7f; | ||
78 | index_xfer.tx_buf = buffer; | ||
79 | spi_message_add_tail(&index_xfer, &msg); | ||
80 | |||
81 | /* register value */ | ||
82 | buffer[4] = 0x72; | ||
83 | buffer[5] = val >> 8; | ||
84 | buffer[6] = val; | ||
85 | value_xfer.tx_buf = buffer + 4; | ||
86 | spi_message_add_tail(&value_xfer, &msg); | ||
87 | |||
88 | return spi_sync(spi, &msg); | ||
89 | } | ||
90 | |||
91 | static void init_lb035q02_panel(struct spi_device *spi) | ||
92 | { | ||
93 | /* Init sequence from page 28 of the lb035q02 spec */ | ||
94 | lb035q02_write_reg(spi, 0x01, 0x6300); | ||
95 | lb035q02_write_reg(spi, 0x02, 0x0200); | ||
96 | lb035q02_write_reg(spi, 0x03, 0x0177); | ||
97 | lb035q02_write_reg(spi, 0x04, 0x04c7); | ||
98 | lb035q02_write_reg(spi, 0x05, 0xffc0); | ||
99 | lb035q02_write_reg(spi, 0x06, 0xe806); | ||
100 | lb035q02_write_reg(spi, 0x0a, 0x4008); | ||
101 | lb035q02_write_reg(spi, 0x0b, 0x0000); | ||
102 | lb035q02_write_reg(spi, 0x0d, 0x0030); | ||
103 | lb035q02_write_reg(spi, 0x0e, 0x2800); | ||
104 | lb035q02_write_reg(spi, 0x0f, 0x0000); | ||
105 | lb035q02_write_reg(spi, 0x16, 0x9f80); | ||
106 | lb035q02_write_reg(spi, 0x17, 0x0a0f); | ||
107 | lb035q02_write_reg(spi, 0x1e, 0x00c1); | ||
108 | lb035q02_write_reg(spi, 0x30, 0x0300); | ||
109 | lb035q02_write_reg(spi, 0x31, 0x0007); | ||
110 | lb035q02_write_reg(spi, 0x32, 0x0000); | ||
111 | lb035q02_write_reg(spi, 0x33, 0x0000); | ||
112 | lb035q02_write_reg(spi, 0x34, 0x0707); | ||
113 | lb035q02_write_reg(spi, 0x35, 0x0004); | ||
114 | lb035q02_write_reg(spi, 0x36, 0x0302); | ||
115 | lb035q02_write_reg(spi, 0x37, 0x0202); | ||
116 | lb035q02_write_reg(spi, 0x3a, 0x0a0d); | ||
117 | lb035q02_write_reg(spi, 0x3b, 0x0806); | ||
118 | } | ||
119 | |||
120 | static int lb035q02_connect(struct omap_dss_device *dssdev) | ||
121 | { | ||
122 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
123 | struct omap_dss_device *in = ddata->in; | ||
124 | int r; | ||
125 | |||
126 | if (omapdss_device_is_connected(dssdev)) | ||
127 | return 0; | ||
128 | |||
129 | r = in->ops.dpi->connect(in, dssdev); | ||
130 | if (r) | ||
131 | return r; | ||
132 | |||
133 | init_lb035q02_panel(ddata->spi); | ||
134 | |||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static void lb035q02_disconnect(struct omap_dss_device *dssdev) | ||
139 | { | ||
140 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
141 | struct omap_dss_device *in = ddata->in; | ||
142 | |||
143 | if (!omapdss_device_is_connected(dssdev)) | ||
144 | return; | ||
145 | |||
146 | in->ops.dpi->disconnect(in, dssdev); | ||
147 | } | ||
148 | |||
149 | static int lb035q02_enable(struct omap_dss_device *dssdev) | ||
150 | { | ||
151 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
152 | struct omap_dss_device *in = ddata->in; | ||
153 | int r; | ||
154 | |||
155 | if (!omapdss_device_is_connected(dssdev)) | ||
156 | return -ENODEV; | ||
157 | |||
158 | if (omapdss_device_is_enabled(dssdev)) | ||
159 | return 0; | ||
160 | |||
161 | in->ops.dpi->set_data_lines(in, ddata->data_lines); | ||
162 | in->ops.dpi->set_timings(in, &ddata->videomode); | ||
163 | |||
164 | r = in->ops.dpi->enable(in); | ||
165 | if (r) | ||
166 | return r; | ||
167 | |||
168 | if (gpio_is_valid(ddata->enable_gpio)) | ||
169 | gpio_set_value_cansleep(ddata->enable_gpio, 1); | ||
170 | |||
171 | if (gpio_is_valid(ddata->backlight_gpio)) | ||
172 | gpio_set_value_cansleep(ddata->backlight_gpio, 1); | ||
173 | |||
174 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static void lb035q02_disable(struct omap_dss_device *dssdev) | ||
180 | { | ||
181 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
182 | struct omap_dss_device *in = ddata->in; | ||
183 | |||
184 | if (!omapdss_device_is_enabled(dssdev)) | ||
185 | return; | ||
186 | |||
187 | if (gpio_is_valid(ddata->enable_gpio)) | ||
188 | gpio_set_value_cansleep(ddata->enable_gpio, 0); | ||
189 | |||
190 | if (gpio_is_valid(ddata->backlight_gpio)) | ||
191 | gpio_set_value_cansleep(ddata->backlight_gpio, 0); | ||
192 | |||
193 | in->ops.dpi->disable(in); | ||
194 | |||
195 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
196 | } | ||
197 | |||
198 | static void lb035q02_set_timings(struct omap_dss_device *dssdev, | ||
199 | struct omap_video_timings *timings) | ||
200 | { | ||
201 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
202 | struct omap_dss_device *in = ddata->in; | ||
203 | |||
204 | ddata->videomode = *timings; | ||
205 | dssdev->panel.timings = *timings; | ||
206 | |||
207 | in->ops.dpi->set_timings(in, timings); | ||
208 | } | ||
209 | |||
210 | static void lb035q02_get_timings(struct omap_dss_device *dssdev, | ||
211 | struct omap_video_timings *timings) | ||
212 | { | ||
213 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
214 | |||
215 | *timings = ddata->videomode; | ||
216 | } | ||
217 | |||
218 | static int lb035q02_check_timings(struct omap_dss_device *dssdev, | ||
219 | struct omap_video_timings *timings) | ||
220 | { | ||
221 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
222 | struct omap_dss_device *in = ddata->in; | ||
223 | |||
224 | return in->ops.dpi->check_timings(in, timings); | ||
225 | } | ||
226 | |||
227 | static struct omap_dss_driver lb035q02_ops = { | ||
228 | .connect = lb035q02_connect, | ||
229 | .disconnect = lb035q02_disconnect, | ||
230 | |||
231 | .enable = lb035q02_enable, | ||
232 | .disable = lb035q02_disable, | ||
233 | |||
234 | .set_timings = lb035q02_set_timings, | ||
235 | .get_timings = lb035q02_get_timings, | ||
236 | .check_timings = lb035q02_check_timings, | ||
237 | |||
238 | .get_resolution = omapdss_default_get_resolution, | ||
239 | }; | ||
240 | |||
241 | static int lb035q02_probe_pdata(struct spi_device *spi) | ||
242 | { | ||
243 | const struct panel_lb035q02_platform_data *pdata; | ||
244 | struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); | ||
245 | struct omap_dss_device *dssdev, *in; | ||
246 | |||
247 | pdata = dev_get_platdata(&spi->dev); | ||
248 | |||
249 | in = omap_dss_find_output(pdata->source); | ||
250 | if (in == NULL) { | ||
251 | dev_err(&spi->dev, "failed to find video source '%s'\n", | ||
252 | pdata->source); | ||
253 | return -EPROBE_DEFER; | ||
254 | } | ||
255 | |||
256 | ddata->in = in; | ||
257 | |||
258 | ddata->data_lines = pdata->data_lines; | ||
259 | |||
260 | dssdev = &ddata->dssdev; | ||
261 | dssdev->name = pdata->name; | ||
262 | |||
263 | ddata->enable_gpio = pdata->enable_gpio; | ||
264 | ddata->backlight_gpio = pdata->backlight_gpio; | ||
265 | |||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static int lb035q02_panel_spi_probe(struct spi_device *spi) | ||
270 | { | ||
271 | struct panel_drv_data *ddata; | ||
272 | struct omap_dss_device *dssdev; | ||
273 | int r; | ||
274 | |||
275 | ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL); | ||
276 | if (ddata == NULL) | ||
277 | return -ENOMEM; | ||
278 | |||
279 | dev_set_drvdata(&spi->dev, ddata); | ||
280 | |||
281 | ddata->spi = spi; | ||
282 | |||
283 | if (dev_get_platdata(&spi->dev)) { | ||
284 | r = lb035q02_probe_pdata(spi); | ||
285 | if (r) | ||
286 | return r; | ||
287 | } else { | ||
288 | return -ENODEV; | ||
289 | } | ||
290 | |||
291 | if (gpio_is_valid(ddata->enable_gpio)) { | ||
292 | r = devm_gpio_request_one(&spi->dev, ddata->enable_gpio, | ||
293 | GPIOF_OUT_INIT_LOW, "panel enable"); | ||
294 | if (r) | ||
295 | goto err_gpio; | ||
296 | } | ||
297 | |||
298 | if (gpio_is_valid(ddata->backlight_gpio)) { | ||
299 | r = devm_gpio_request_one(&spi->dev, ddata->backlight_gpio, | ||
300 | GPIOF_OUT_INIT_LOW, "panel backlight"); | ||
301 | if (r) | ||
302 | goto err_gpio; | ||
303 | } | ||
304 | |||
305 | ddata->videomode = lb035q02_timings; | ||
306 | |||
307 | dssdev = &ddata->dssdev; | ||
308 | dssdev->dev = &spi->dev; | ||
309 | dssdev->driver = &lb035q02_ops; | ||
310 | dssdev->type = OMAP_DISPLAY_TYPE_DPI; | ||
311 | dssdev->owner = THIS_MODULE; | ||
312 | dssdev->panel.timings = ddata->videomode; | ||
313 | dssdev->phy.dpi.data_lines = ddata->data_lines; | ||
314 | |||
315 | r = omapdss_register_display(dssdev); | ||
316 | if (r) { | ||
317 | dev_err(&spi->dev, "Failed to register panel\n"); | ||
318 | goto err_reg; | ||
319 | } | ||
320 | |||
321 | return 0; | ||
322 | |||
323 | err_reg: | ||
324 | err_gpio: | ||
325 | omap_dss_put_device(ddata->in); | ||
326 | return r; | ||
327 | } | ||
328 | |||
329 | static int lb035q02_panel_spi_remove(struct spi_device *spi) | ||
330 | { | ||
331 | struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); | ||
332 | struct omap_dss_device *dssdev = &ddata->dssdev; | ||
333 | struct omap_dss_device *in = ddata->in; | ||
334 | |||
335 | omapdss_unregister_display(dssdev); | ||
336 | |||
337 | lb035q02_disable(dssdev); | ||
338 | lb035q02_disconnect(dssdev); | ||
339 | |||
340 | omap_dss_put_device(in); | ||
341 | |||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | static struct spi_driver lb035q02_spi_driver = { | ||
346 | .probe = lb035q02_panel_spi_probe, | ||
347 | .remove = lb035q02_panel_spi_remove, | ||
348 | .driver = { | ||
349 | .name = "panel_lgphilips_lb035q02", | ||
350 | .owner = THIS_MODULE, | ||
351 | }, | ||
352 | }; | ||
353 | |||
354 | module_spi_driver(lb035q02_spi_driver); | ||
355 | |||
356 | MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); | ||
357 | MODULE_DESCRIPTION("LG.Philips LB035Q02 LCD Panel driver"); | ||
358 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays-new/panel-nec-nl8048hl11.c b/drivers/video/omap2/displays-new/panel-nec-nl8048hl11.c new file mode 100644 index 000000000000..bb217da65c5f --- /dev/null +++ b/drivers/video/omap2/displays-new/panel-nec-nl8048hl11.c | |||
@@ -0,0 +1,394 @@ | |||
1 | /* | ||
2 | * NEC NL8048HL11 Panel driver | ||
3 | * | ||
4 | * Copyright (C) 2010 Texas Instruments Inc. | ||
5 | * Author: Erik Gilling <konkers@android.com> | ||
6 | * Converted to new DSS device model: Tomi Valkeinen <tomi.valkeinen@ti.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/spi/spi.h> | ||
17 | #include <linux/fb.h> | ||
18 | #include <linux/gpio.h> | ||
19 | |||
20 | #include <video/omapdss.h> | ||
21 | #include <video/omap-panel-data.h> | ||
22 | |||
23 | struct panel_drv_data { | ||
24 | struct omap_dss_device dssdev; | ||
25 | struct omap_dss_device *in; | ||
26 | |||
27 | struct omap_video_timings videomode; | ||
28 | |||
29 | int data_lines; | ||
30 | |||
31 | int res_gpio; | ||
32 | int qvga_gpio; | ||
33 | |||
34 | struct spi_device *spi; | ||
35 | }; | ||
36 | |||
37 | #define LCD_XRES 800 | ||
38 | #define LCD_YRES 480 | ||
39 | /* | ||
40 | * NEC PIX Clock Ratings | ||
41 | * MIN:21.8MHz TYP:23.8MHz MAX:25.7MHz | ||
42 | */ | ||
43 | #define LCD_PIXEL_CLOCK 23800 | ||
44 | |||
45 | static const struct { | ||
46 | unsigned char addr; | ||
47 | unsigned char dat; | ||
48 | } nec_8048_init_seq[] = { | ||
49 | { 3, 0x01 }, { 0, 0x00 }, { 1, 0x01 }, { 4, 0x00 }, { 5, 0x14 }, | ||
50 | { 6, 0x24 }, { 16, 0xD7 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x55 }, | ||
51 | { 20, 0x01 }, { 21, 0x70 }, { 22, 0x1E }, { 23, 0x25 }, { 24, 0x25 }, | ||
52 | { 25, 0x02 }, { 26, 0x02 }, { 27, 0xA0 }, { 32, 0x2F }, { 33, 0x0F }, | ||
53 | { 34, 0x0F }, { 35, 0x0F }, { 36, 0x0F }, { 37, 0x0F }, { 38, 0x0F }, | ||
54 | { 39, 0x00 }, { 40, 0x02 }, { 41, 0x02 }, { 42, 0x02 }, { 43, 0x0F }, | ||
55 | { 44, 0x0F }, { 45, 0x0F }, { 46, 0x0F }, { 47, 0x0F }, { 48, 0x0F }, | ||
56 | { 49, 0x0F }, { 50, 0x00 }, { 51, 0x02 }, { 52, 0x02 }, { 53, 0x02 }, | ||
57 | { 80, 0x0C }, { 83, 0x42 }, { 84, 0x42 }, { 85, 0x41 }, { 86, 0x14 }, | ||
58 | { 89, 0x88 }, { 90, 0x01 }, { 91, 0x00 }, { 92, 0x02 }, { 93, 0x0C }, | ||
59 | { 94, 0x1C }, { 95, 0x27 }, { 98, 0x49 }, { 99, 0x27 }, { 102, 0x76 }, | ||
60 | { 103, 0x27 }, { 112, 0x01 }, { 113, 0x0E }, { 114, 0x02 }, | ||
61 | { 115, 0x0C }, { 118, 0x0C }, { 121, 0x30 }, { 130, 0x00 }, | ||
62 | { 131, 0x00 }, { 132, 0xFC }, { 134, 0x00 }, { 136, 0x00 }, | ||
63 | { 138, 0x00 }, { 139, 0x00 }, { 140, 0x00 }, { 141, 0xFC }, | ||
64 | { 143, 0x00 }, { 145, 0x00 }, { 147, 0x00 }, { 148, 0x00 }, | ||
65 | { 149, 0x00 }, { 150, 0xFC }, { 152, 0x00 }, { 154, 0x00 }, | ||
66 | { 156, 0x00 }, { 157, 0x00 }, { 2, 0x00 }, | ||
67 | }; | ||
68 | |||
69 | static const struct omap_video_timings nec_8048_panel_timings = { | ||
70 | .x_res = LCD_XRES, | ||
71 | .y_res = LCD_YRES, | ||
72 | .pixel_clock = LCD_PIXEL_CLOCK, | ||
73 | .hfp = 6, | ||
74 | .hsw = 1, | ||
75 | .hbp = 4, | ||
76 | .vfp = 3, | ||
77 | .vsw = 1, | ||
78 | .vbp = 4, | ||
79 | |||
80 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
81 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
82 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
83 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
84 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
85 | }; | ||
86 | |||
87 | #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) | ||
88 | |||
89 | static int nec_8048_spi_send(struct spi_device *spi, unsigned char reg_addr, | ||
90 | unsigned char reg_data) | ||
91 | { | ||
92 | int ret = 0; | ||
93 | unsigned int cmd = 0, data = 0; | ||
94 | |||
95 | cmd = 0x0000 | reg_addr; /* register address write */ | ||
96 | data = 0x0100 | reg_data; /* register data write */ | ||
97 | data = (cmd << 16) | data; | ||
98 | |||
99 | ret = spi_write(spi, (unsigned char *)&data, 4); | ||
100 | if (ret) | ||
101 | pr_err("error in spi_write %x\n", data); | ||
102 | |||
103 | return ret; | ||
104 | } | ||
105 | |||
106 | static int init_nec_8048_wvga_lcd(struct spi_device *spi) | ||
107 | { | ||
108 | unsigned int i; | ||
109 | /* Initialization Sequence */ | ||
110 | /* nec_8048_spi_send(spi, REG, VAL) */ | ||
111 | for (i = 0; i < (ARRAY_SIZE(nec_8048_init_seq) - 1); i++) | ||
112 | nec_8048_spi_send(spi, nec_8048_init_seq[i].addr, | ||
113 | nec_8048_init_seq[i].dat); | ||
114 | udelay(20); | ||
115 | nec_8048_spi_send(spi, nec_8048_init_seq[i].addr, | ||
116 | nec_8048_init_seq[i].dat); | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | static int nec_8048_connect(struct omap_dss_device *dssdev) | ||
121 | { | ||
122 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
123 | struct omap_dss_device *in = ddata->in; | ||
124 | int r; | ||
125 | |||
126 | if (omapdss_device_is_connected(dssdev)) | ||
127 | return 0; | ||
128 | |||
129 | r = in->ops.dpi->connect(in, dssdev); | ||
130 | if (r) | ||
131 | return r; | ||
132 | |||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static void nec_8048_disconnect(struct omap_dss_device *dssdev) | ||
137 | { | ||
138 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
139 | struct omap_dss_device *in = ddata->in; | ||
140 | |||
141 | if (!omapdss_device_is_connected(dssdev)) | ||
142 | return; | ||
143 | |||
144 | in->ops.dpi->disconnect(in, dssdev); | ||
145 | } | ||
146 | |||
147 | static int nec_8048_enable(struct omap_dss_device *dssdev) | ||
148 | { | ||
149 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
150 | struct omap_dss_device *in = ddata->in; | ||
151 | int r; | ||
152 | |||
153 | if (!omapdss_device_is_connected(dssdev)) | ||
154 | return -ENODEV; | ||
155 | |||
156 | if (omapdss_device_is_enabled(dssdev)) | ||
157 | return 0; | ||
158 | |||
159 | in->ops.dpi->set_data_lines(in, ddata->data_lines); | ||
160 | in->ops.dpi->set_timings(in, &ddata->videomode); | ||
161 | |||
162 | r = in->ops.dpi->enable(in); | ||
163 | if (r) | ||
164 | return r; | ||
165 | |||
166 | if (gpio_is_valid(ddata->res_gpio)) | ||
167 | gpio_set_value_cansleep(ddata->res_gpio, 1); | ||
168 | |||
169 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static void nec_8048_disable(struct omap_dss_device *dssdev) | ||
175 | { | ||
176 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
177 | struct omap_dss_device *in = ddata->in; | ||
178 | |||
179 | if (!omapdss_device_is_enabled(dssdev)) | ||
180 | return; | ||
181 | |||
182 | if (gpio_is_valid(ddata->res_gpio)) | ||
183 | gpio_set_value_cansleep(ddata->res_gpio, 0); | ||
184 | |||
185 | in->ops.dpi->disable(in); | ||
186 | |||
187 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
188 | } | ||
189 | |||
190 | static void nec_8048_set_timings(struct omap_dss_device *dssdev, | ||
191 | struct omap_video_timings *timings) | ||
192 | { | ||
193 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
194 | struct omap_dss_device *in = ddata->in; | ||
195 | |||
196 | ddata->videomode = *timings; | ||
197 | dssdev->panel.timings = *timings; | ||
198 | |||
199 | in->ops.dpi->set_timings(in, timings); | ||
200 | } | ||
201 | |||
202 | static void nec_8048_get_timings(struct omap_dss_device *dssdev, | ||
203 | struct omap_video_timings *timings) | ||
204 | { | ||
205 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
206 | |||
207 | *timings = ddata->videomode; | ||
208 | } | ||
209 | |||
210 | static int nec_8048_check_timings(struct omap_dss_device *dssdev, | ||
211 | struct omap_video_timings *timings) | ||
212 | { | ||
213 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
214 | struct omap_dss_device *in = ddata->in; | ||
215 | |||
216 | return in->ops.dpi->check_timings(in, timings); | ||
217 | } | ||
218 | |||
219 | static struct omap_dss_driver nec_8048_ops = { | ||
220 | .connect = nec_8048_connect, | ||
221 | .disconnect = nec_8048_disconnect, | ||
222 | |||
223 | .enable = nec_8048_enable, | ||
224 | .disable = nec_8048_disable, | ||
225 | |||
226 | .set_timings = nec_8048_set_timings, | ||
227 | .get_timings = nec_8048_get_timings, | ||
228 | .check_timings = nec_8048_check_timings, | ||
229 | |||
230 | .get_resolution = omapdss_default_get_resolution, | ||
231 | }; | ||
232 | |||
233 | |||
234 | static int nec_8048_probe_pdata(struct spi_device *spi) | ||
235 | { | ||
236 | const struct panel_nec_nl8048hl11_platform_data *pdata; | ||
237 | struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); | ||
238 | struct omap_dss_device *dssdev, *in; | ||
239 | |||
240 | pdata = dev_get_platdata(&spi->dev); | ||
241 | |||
242 | ddata->qvga_gpio = pdata->qvga_gpio; | ||
243 | ddata->res_gpio = pdata->res_gpio; | ||
244 | |||
245 | in = omap_dss_find_output(pdata->source); | ||
246 | if (in == NULL) { | ||
247 | dev_err(&spi->dev, "failed to find video source '%s'\n", | ||
248 | pdata->source); | ||
249 | return -EPROBE_DEFER; | ||
250 | } | ||
251 | ddata->in = in; | ||
252 | |||
253 | ddata->data_lines = pdata->data_lines; | ||
254 | |||
255 | dssdev = &ddata->dssdev; | ||
256 | dssdev->name = pdata->name; | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | static int nec_8048_probe(struct spi_device *spi) | ||
262 | { | ||
263 | struct panel_drv_data *ddata; | ||
264 | struct omap_dss_device *dssdev; | ||
265 | int r; | ||
266 | |||
267 | dev_dbg(&spi->dev, "%s\n", __func__); | ||
268 | |||
269 | spi->mode = SPI_MODE_0; | ||
270 | spi->bits_per_word = 32; | ||
271 | |||
272 | r = spi_setup(spi); | ||
273 | if (r < 0) { | ||
274 | dev_err(&spi->dev, "spi_setup failed: %d\n", r); | ||
275 | return r; | ||
276 | } | ||
277 | |||
278 | init_nec_8048_wvga_lcd(spi); | ||
279 | |||
280 | ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL); | ||
281 | if (ddata == NULL) | ||
282 | return -ENOMEM; | ||
283 | |||
284 | dev_set_drvdata(&spi->dev, ddata); | ||
285 | |||
286 | ddata->spi = spi; | ||
287 | |||
288 | if (dev_get_platdata(&spi->dev)) { | ||
289 | r = nec_8048_probe_pdata(spi); | ||
290 | if (r) | ||
291 | return r; | ||
292 | } else { | ||
293 | return -ENODEV; | ||
294 | } | ||
295 | |||
296 | if (gpio_is_valid(ddata->qvga_gpio)) { | ||
297 | r = devm_gpio_request_one(&spi->dev, ddata->qvga_gpio, | ||
298 | GPIOF_OUT_INIT_HIGH, "lcd QVGA"); | ||
299 | if (r) | ||
300 | goto err_gpio; | ||
301 | } | ||
302 | |||
303 | if (gpio_is_valid(ddata->res_gpio)) { | ||
304 | r = devm_gpio_request_one(&spi->dev, ddata->res_gpio, | ||
305 | GPIOF_OUT_INIT_LOW, "lcd RES"); | ||
306 | if (r) | ||
307 | goto err_gpio; | ||
308 | } | ||
309 | |||
310 | ddata->videomode = nec_8048_panel_timings; | ||
311 | |||
312 | dssdev = &ddata->dssdev; | ||
313 | dssdev->dev = &spi->dev; | ||
314 | dssdev->driver = &nec_8048_ops; | ||
315 | dssdev->type = OMAP_DISPLAY_TYPE_DPI; | ||
316 | dssdev->owner = THIS_MODULE; | ||
317 | dssdev->panel.timings = ddata->videomode; | ||
318 | |||
319 | r = omapdss_register_display(dssdev); | ||
320 | if (r) { | ||
321 | dev_err(&spi->dev, "Failed to register panel\n"); | ||
322 | goto err_reg; | ||
323 | } | ||
324 | |||
325 | return 0; | ||
326 | |||
327 | err_reg: | ||
328 | err_gpio: | ||
329 | omap_dss_put_device(ddata->in); | ||
330 | return r; | ||
331 | } | ||
332 | |||
333 | static int nec_8048_remove(struct spi_device *spi) | ||
334 | { | ||
335 | struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); | ||
336 | struct omap_dss_device *dssdev = &ddata->dssdev; | ||
337 | struct omap_dss_device *in = ddata->in; | ||
338 | |||
339 | dev_dbg(&ddata->spi->dev, "%s\n", __func__); | ||
340 | |||
341 | omapdss_unregister_display(dssdev); | ||
342 | |||
343 | nec_8048_disable(dssdev); | ||
344 | nec_8048_disconnect(dssdev); | ||
345 | |||
346 | omap_dss_put_device(in); | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | #ifdef CONFIG_PM_SLEEP | ||
352 | static int nec_8048_suspend(struct device *dev) | ||
353 | { | ||
354 | struct spi_device *spi = to_spi_device(dev); | ||
355 | |||
356 | nec_8048_spi_send(spi, 2, 0x01); | ||
357 | mdelay(40); | ||
358 | |||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | static int nec_8048_resume(struct device *dev) | ||
363 | { | ||
364 | struct spi_device *spi = to_spi_device(dev); | ||
365 | |||
366 | /* reinitialize the panel */ | ||
367 | spi_setup(spi); | ||
368 | nec_8048_spi_send(spi, 2, 0x00); | ||
369 | init_nec_8048_wvga_lcd(spi); | ||
370 | |||
371 | return 0; | ||
372 | } | ||
373 | static SIMPLE_DEV_PM_OPS(nec_8048_pm_ops, nec_8048_suspend, | ||
374 | nec_8048_resume); | ||
375 | #define NEC_8048_PM_OPS (&nec_8048_pm_ops) | ||
376 | #else | ||
377 | #define NEC_8048_PM_OPS NULL | ||
378 | #endif | ||
379 | |||
380 | static struct spi_driver nec_8048_driver = { | ||
381 | .driver = { | ||
382 | .name = "panel-nec-nl8048hl11", | ||
383 | .owner = THIS_MODULE, | ||
384 | .pm = NEC_8048_PM_OPS, | ||
385 | }, | ||
386 | .probe = nec_8048_probe, | ||
387 | .remove = nec_8048_remove, | ||
388 | }; | ||
389 | |||
390 | module_spi_driver(nec_8048_driver); | ||
391 | |||
392 | MODULE_AUTHOR("Erik Gilling <konkers@android.com>"); | ||
393 | MODULE_DESCRIPTION("NEC-NL8048HL11 Driver"); | ||
394 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays-new/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays-new/panel-sharp-ls037v7dw01.c new file mode 100644 index 000000000000..72a4fb5aa6b1 --- /dev/null +++ b/drivers/video/omap2/displays-new/panel-sharp-ls037v7dw01.c | |||
@@ -0,0 +1,324 @@ | |||
1 | /* | ||
2 | * LCD panel driver for Sharp LS037V7DW01 | ||
3 | * | ||
4 | * Copyright (C) 2013 Texas Instruments | ||
5 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> | ||
6 | * | ||
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. | ||
10 | */ | ||
11 | |||
12 | #include <linux/delay.h> | ||
13 | #include <linux/gpio.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/slab.h> | ||
17 | |||
18 | #include <video/omapdss.h> | ||
19 | #include <video/omap-panel-data.h> | ||
20 | |||
21 | struct panel_drv_data { | ||
22 | struct omap_dss_device dssdev; | ||
23 | struct omap_dss_device *in; | ||
24 | |||
25 | int data_lines; | ||
26 | |||
27 | struct omap_video_timings videomode; | ||
28 | |||
29 | int resb_gpio; | ||
30 | int ini_gpio; | ||
31 | int mo_gpio; | ||
32 | int lr_gpio; | ||
33 | int ud_gpio; | ||
34 | }; | ||
35 | |||
36 | static const struct omap_video_timings sharp_ls_timings = { | ||
37 | .x_res = 480, | ||
38 | .y_res = 640, | ||
39 | |||
40 | .pixel_clock = 19200, | ||
41 | |||
42 | .hsw = 2, | ||
43 | .hfp = 1, | ||
44 | .hbp = 28, | ||
45 | |||
46 | .vsw = 1, | ||
47 | .vfp = 1, | ||
48 | .vbp = 1, | ||
49 | |||
50 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
51 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
52 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
53 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
54 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
55 | }; | ||
56 | |||
57 | #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) | ||
58 | |||
59 | static int sharp_ls_connect(struct omap_dss_device *dssdev) | ||
60 | { | ||
61 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
62 | struct omap_dss_device *in = ddata->in; | ||
63 | int r; | ||
64 | |||
65 | if (omapdss_device_is_connected(dssdev)) | ||
66 | return 0; | ||
67 | |||
68 | r = in->ops.dpi->connect(in, dssdev); | ||
69 | if (r) | ||
70 | return r; | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static void sharp_ls_disconnect(struct omap_dss_device *dssdev) | ||
76 | { | ||
77 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
78 | struct omap_dss_device *in = ddata->in; | ||
79 | |||
80 | if (!omapdss_device_is_connected(dssdev)) | ||
81 | return; | ||
82 | |||
83 | in->ops.dpi->disconnect(in, dssdev); | ||
84 | } | ||
85 | |||
86 | static int sharp_ls_enable(struct omap_dss_device *dssdev) | ||
87 | { | ||
88 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
89 | struct omap_dss_device *in = ddata->in; | ||
90 | int r; | ||
91 | |||
92 | if (!omapdss_device_is_connected(dssdev)) | ||
93 | return -ENODEV; | ||
94 | |||
95 | if (omapdss_device_is_enabled(dssdev)) | ||
96 | return 0; | ||
97 | |||
98 | in->ops.dpi->set_data_lines(in, ddata->data_lines); | ||
99 | in->ops.dpi->set_timings(in, &ddata->videomode); | ||
100 | |||
101 | r = in->ops.dpi->enable(in); | ||
102 | if (r) | ||
103 | return r; | ||
104 | |||
105 | /* wait couple of vsyncs until enabling the LCD */ | ||
106 | msleep(50); | ||
107 | |||
108 | if (gpio_is_valid(ddata->resb_gpio)) | ||
109 | gpio_set_value_cansleep(ddata->resb_gpio, 1); | ||
110 | |||
111 | if (gpio_is_valid(ddata->ini_gpio)) | ||
112 | gpio_set_value_cansleep(ddata->ini_gpio, 1); | ||
113 | |||
114 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static void sharp_ls_disable(struct omap_dss_device *dssdev) | ||
120 | { | ||
121 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
122 | struct omap_dss_device *in = ddata->in; | ||
123 | |||
124 | if (!omapdss_device_is_enabled(dssdev)) | ||
125 | return; | ||
126 | |||
127 | if (gpio_is_valid(ddata->ini_gpio)) | ||
128 | gpio_set_value_cansleep(ddata->ini_gpio, 0); | ||
129 | |||
130 | if (gpio_is_valid(ddata->resb_gpio)) | ||
131 | gpio_set_value_cansleep(ddata->resb_gpio, 0); | ||
132 | |||
133 | /* wait at least 5 vsyncs after disabling the LCD */ | ||
134 | |||
135 | msleep(100); | ||
136 | |||
137 | in->ops.dpi->disable(in); | ||
138 | |||
139 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
140 | } | ||
141 | |||
142 | static void sharp_ls_set_timings(struct omap_dss_device *dssdev, | ||
143 | struct omap_video_timings *timings) | ||
144 | { | ||
145 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
146 | struct omap_dss_device *in = ddata->in; | ||
147 | |||
148 | ddata->videomode = *timings; | ||
149 | dssdev->panel.timings = *timings; | ||
150 | |||
151 | in->ops.dpi->set_timings(in, timings); | ||
152 | } | ||
153 | |||
154 | static void sharp_ls_get_timings(struct omap_dss_device *dssdev, | ||
155 | struct omap_video_timings *timings) | ||
156 | { | ||
157 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
158 | |||
159 | *timings = ddata->videomode; | ||
160 | } | ||
161 | |||
162 | static int sharp_ls_check_timings(struct omap_dss_device *dssdev, | ||
163 | struct omap_video_timings *timings) | ||
164 | { | ||
165 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
166 | struct omap_dss_device *in = ddata->in; | ||
167 | |||
168 | return in->ops.dpi->check_timings(in, timings); | ||
169 | } | ||
170 | |||
171 | static struct omap_dss_driver sharp_ls_ops = { | ||
172 | .connect = sharp_ls_connect, | ||
173 | .disconnect = sharp_ls_disconnect, | ||
174 | |||
175 | .enable = sharp_ls_enable, | ||
176 | .disable = sharp_ls_disable, | ||
177 | |||
178 | .set_timings = sharp_ls_set_timings, | ||
179 | .get_timings = sharp_ls_get_timings, | ||
180 | .check_timings = sharp_ls_check_timings, | ||
181 | |||
182 | .get_resolution = omapdss_default_get_resolution, | ||
183 | }; | ||
184 | |||
185 | static int sharp_ls_probe_pdata(struct platform_device *pdev) | ||
186 | { | ||
187 | const struct panel_sharp_ls037v7dw01_platform_data *pdata; | ||
188 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
189 | struct omap_dss_device *dssdev, *in; | ||
190 | |||
191 | pdata = dev_get_platdata(&pdev->dev); | ||
192 | |||
193 | in = omap_dss_find_output(pdata->source); | ||
194 | if (in == NULL) { | ||
195 | dev_err(&pdev->dev, "failed to find video source '%s'\n", | ||
196 | pdata->source); | ||
197 | return -EPROBE_DEFER; | ||
198 | } | ||
199 | |||
200 | ddata->in = in; | ||
201 | |||
202 | ddata->data_lines = pdata->data_lines; | ||
203 | |||
204 | dssdev = &ddata->dssdev; | ||
205 | dssdev->name = pdata->name; | ||
206 | |||
207 | ddata->resb_gpio = pdata->resb_gpio; | ||
208 | ddata->ini_gpio = pdata->ini_gpio; | ||
209 | ddata->mo_gpio = pdata->mo_gpio; | ||
210 | ddata->lr_gpio = pdata->lr_gpio; | ||
211 | ddata->ud_gpio = pdata->ud_gpio; | ||
212 | |||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static int sharp_ls_probe(struct platform_device *pdev) | ||
217 | { | ||
218 | struct panel_drv_data *ddata; | ||
219 | struct omap_dss_device *dssdev; | ||
220 | int r; | ||
221 | |||
222 | ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); | ||
223 | if (ddata == NULL) | ||
224 | return -ENOMEM; | ||
225 | |||
226 | platform_set_drvdata(pdev, ddata); | ||
227 | |||
228 | if (dev_get_platdata(&pdev->dev)) { | ||
229 | r = sharp_ls_probe_pdata(pdev); | ||
230 | if (r) | ||
231 | return r; | ||
232 | } else { | ||
233 | return -ENODEV; | ||
234 | } | ||
235 | |||
236 | if (gpio_is_valid(ddata->mo_gpio)) { | ||
237 | r = devm_gpio_request_one(&pdev->dev, ddata->mo_gpio, | ||
238 | GPIOF_OUT_INIT_LOW, "lcd MO"); | ||
239 | if (r) | ||
240 | goto err_gpio; | ||
241 | } | ||
242 | |||
243 | if (gpio_is_valid(ddata->lr_gpio)) { | ||
244 | r = devm_gpio_request_one(&pdev->dev, ddata->lr_gpio, | ||
245 | GPIOF_OUT_INIT_HIGH, "lcd LR"); | ||
246 | if (r) | ||
247 | goto err_gpio; | ||
248 | } | ||
249 | |||
250 | if (gpio_is_valid(ddata->ud_gpio)) { | ||
251 | r = devm_gpio_request_one(&pdev->dev, ddata->ud_gpio, | ||
252 | GPIOF_OUT_INIT_HIGH, "lcd UD"); | ||
253 | if (r) | ||
254 | goto err_gpio; | ||
255 | } | ||
256 | |||
257 | if (gpio_is_valid(ddata->resb_gpio)) { | ||
258 | r = devm_gpio_request_one(&pdev->dev, ddata->resb_gpio, | ||
259 | GPIOF_OUT_INIT_LOW, "lcd RESB"); | ||
260 | if (r) | ||
261 | goto err_gpio; | ||
262 | } | ||
263 | |||
264 | if (gpio_is_valid(ddata->ini_gpio)) { | ||
265 | r = devm_gpio_request_one(&pdev->dev, ddata->ini_gpio, | ||
266 | GPIOF_OUT_INIT_LOW, "lcd INI"); | ||
267 | if (r) | ||
268 | goto err_gpio; | ||
269 | } | ||
270 | |||
271 | ddata->videomode = sharp_ls_timings; | ||
272 | |||
273 | dssdev = &ddata->dssdev; | ||
274 | dssdev->dev = &pdev->dev; | ||
275 | dssdev->driver = &sharp_ls_ops; | ||
276 | dssdev->type = OMAP_DISPLAY_TYPE_DPI; | ||
277 | dssdev->owner = THIS_MODULE; | ||
278 | dssdev->panel.timings = ddata->videomode; | ||
279 | dssdev->phy.dpi.data_lines = ddata->data_lines; | ||
280 | |||
281 | r = omapdss_register_display(dssdev); | ||
282 | if (r) { | ||
283 | dev_err(&pdev->dev, "Failed to register panel\n"); | ||
284 | goto err_reg; | ||
285 | } | ||
286 | |||
287 | return 0; | ||
288 | |||
289 | err_reg: | ||
290 | err_gpio: | ||
291 | omap_dss_put_device(ddata->in); | ||
292 | return r; | ||
293 | } | ||
294 | |||
295 | static int __exit sharp_ls_remove(struct platform_device *pdev) | ||
296 | { | ||
297 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
298 | struct omap_dss_device *dssdev = &ddata->dssdev; | ||
299 | struct omap_dss_device *in = ddata->in; | ||
300 | |||
301 | omapdss_unregister_display(dssdev); | ||
302 | |||
303 | sharp_ls_disable(dssdev); | ||
304 | sharp_ls_disconnect(dssdev); | ||
305 | |||
306 | omap_dss_put_device(in); | ||
307 | |||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | static struct platform_driver sharp_ls_driver = { | ||
312 | .probe = sharp_ls_probe, | ||
313 | .remove = __exit_p(sharp_ls_remove), | ||
314 | .driver = { | ||
315 | .name = "panel-sharp-ls037v7dw01", | ||
316 | .owner = THIS_MODULE, | ||
317 | }, | ||
318 | }; | ||
319 | |||
320 | module_platform_driver(sharp_ls_driver); | ||
321 | |||
322 | MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); | ||
323 | MODULE_DESCRIPTION("Sharp LS037V7DW01 Panel Driver"); | ||
324 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays-new/panel-sony-acx565akm.c b/drivers/video/omap2/displays-new/panel-sony-acx565akm.c new file mode 100644 index 000000000000..e6d56f714ae4 --- /dev/null +++ b/drivers/video/omap2/displays-new/panel-sony-acx565akm.c | |||
@@ -0,0 +1,865 @@ | |||
1 | /* | ||
2 | * Sony ACX565AKM LCD Panel driver | ||
3 | * | ||
4 | * Copyright (C) 2010 Nokia Corporation | ||
5 | * | ||
6 | * Original Driver Author: Imre Deak <imre.deak@nokia.com> | ||
7 | * Based on panel-generic.c by Tomi Valkeinen <tomi.valkeinen@nokia.com> | ||
8 | * Adapted to new DSS2 framework: Roger Quadros <roger.quadros@nokia.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License version 2 as published by | ||
12 | * the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
17 | * more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along with | ||
20 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
21 | */ | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/spi/spi.h> | ||
28 | #include <linux/jiffies.h> | ||
29 | #include <linux/sched.h> | ||
30 | #include <linux/backlight.h> | ||
31 | #include <linux/fb.h> | ||
32 | #include <linux/gpio.h> | ||
33 | |||
34 | #include <video/omapdss.h> | ||
35 | #include <video/omap-panel-data.h> | ||
36 | |||
37 | #define MIPID_CMD_READ_DISP_ID 0x04 | ||
38 | #define MIPID_CMD_READ_RED 0x06 | ||
39 | #define MIPID_CMD_READ_GREEN 0x07 | ||
40 | #define MIPID_CMD_READ_BLUE 0x08 | ||
41 | #define MIPID_CMD_READ_DISP_STATUS 0x09 | ||
42 | #define MIPID_CMD_RDDSDR 0x0F | ||
43 | #define MIPID_CMD_SLEEP_IN 0x10 | ||
44 | #define MIPID_CMD_SLEEP_OUT 0x11 | ||
45 | #define MIPID_CMD_DISP_OFF 0x28 | ||
46 | #define MIPID_CMD_DISP_ON 0x29 | ||
47 | #define MIPID_CMD_WRITE_DISP_BRIGHTNESS 0x51 | ||
48 | #define MIPID_CMD_READ_DISP_BRIGHTNESS 0x52 | ||
49 | #define MIPID_CMD_WRITE_CTRL_DISP 0x53 | ||
50 | |||
51 | #define CTRL_DISP_BRIGHTNESS_CTRL_ON (1 << 5) | ||
52 | #define CTRL_DISP_AMBIENT_LIGHT_CTRL_ON (1 << 4) | ||
53 | #define CTRL_DISP_BACKLIGHT_ON (1 << 2) | ||
54 | #define CTRL_DISP_AUTO_BRIGHTNESS_ON (1 << 1) | ||
55 | |||
56 | #define MIPID_CMD_READ_CTRL_DISP 0x54 | ||
57 | #define MIPID_CMD_WRITE_CABC 0x55 | ||
58 | #define MIPID_CMD_READ_CABC 0x56 | ||
59 | |||
60 | #define MIPID_VER_LPH8923 3 | ||
61 | #define MIPID_VER_LS041Y3 4 | ||
62 | #define MIPID_VER_L4F00311 8 | ||
63 | #define MIPID_VER_ACX565AKM 9 | ||
64 | |||
65 | struct panel_drv_data { | ||
66 | struct omap_dss_device dssdev; | ||
67 | struct omap_dss_device *in; | ||
68 | |||
69 | int reset_gpio; | ||
70 | int datapairs; | ||
71 | |||
72 | struct omap_video_timings videomode; | ||
73 | |||
74 | char *name; | ||
75 | int enabled; | ||
76 | int model; | ||
77 | int revision; | ||
78 | u8 display_id[3]; | ||
79 | unsigned has_bc:1; | ||
80 | unsigned has_cabc:1; | ||
81 | unsigned cabc_mode; | ||
82 | unsigned long hw_guard_end; /* next value of jiffies | ||
83 | when we can issue the | ||
84 | next sleep in/out command */ | ||
85 | unsigned long hw_guard_wait; /* max guard time in jiffies */ | ||
86 | |||
87 | struct spi_device *spi; | ||
88 | struct mutex mutex; | ||
89 | |||
90 | struct backlight_device *bl_dev; | ||
91 | }; | ||
92 | |||
93 | static const struct omap_video_timings acx565akm_panel_timings = { | ||
94 | .x_res = 800, | ||
95 | .y_res = 480, | ||
96 | .pixel_clock = 24000, | ||
97 | .hfp = 28, | ||
98 | .hsw = 4, | ||
99 | .hbp = 24, | ||
100 | .vfp = 3, | ||
101 | .vsw = 3, | ||
102 | .vbp = 4, | ||
103 | |||
104 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
105 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
106 | |||
107 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
108 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
109 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
110 | }; | ||
111 | |||
112 | #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) | ||
113 | |||
114 | static void acx565akm_transfer(struct panel_drv_data *ddata, int cmd, | ||
115 | const u8 *wbuf, int wlen, u8 *rbuf, int rlen) | ||
116 | { | ||
117 | struct spi_message m; | ||
118 | struct spi_transfer *x, xfer[5]; | ||
119 | int r; | ||
120 | |||
121 | BUG_ON(ddata->spi == NULL); | ||
122 | |||
123 | spi_message_init(&m); | ||
124 | |||
125 | memset(xfer, 0, sizeof(xfer)); | ||
126 | x = &xfer[0]; | ||
127 | |||
128 | cmd &= 0xff; | ||
129 | x->tx_buf = &cmd; | ||
130 | x->bits_per_word = 9; | ||
131 | x->len = 2; | ||
132 | |||
133 | if (rlen > 1 && wlen == 0) { | ||
134 | /* | ||
135 | * Between the command and the response data there is a | ||
136 | * dummy clock cycle. Add an extra bit after the command | ||
137 | * word to account for this. | ||
138 | */ | ||
139 | x->bits_per_word = 10; | ||
140 | cmd <<= 1; | ||
141 | } | ||
142 | spi_message_add_tail(x, &m); | ||
143 | |||
144 | if (wlen) { | ||
145 | x++; | ||
146 | x->tx_buf = wbuf; | ||
147 | x->len = wlen; | ||
148 | x->bits_per_word = 9; | ||
149 | spi_message_add_tail(x, &m); | ||
150 | } | ||
151 | |||
152 | if (rlen) { | ||
153 | x++; | ||
154 | x->rx_buf = rbuf; | ||
155 | x->len = rlen; | ||
156 | spi_message_add_tail(x, &m); | ||
157 | } | ||
158 | |||
159 | r = spi_sync(ddata->spi, &m); | ||
160 | if (r < 0) | ||
161 | dev_dbg(&ddata->spi->dev, "spi_sync %d\n", r); | ||
162 | } | ||
163 | |||
164 | static inline void acx565akm_cmd(struct panel_drv_data *ddata, int cmd) | ||
165 | { | ||
166 | acx565akm_transfer(ddata, cmd, NULL, 0, NULL, 0); | ||
167 | } | ||
168 | |||
169 | static inline void acx565akm_write(struct panel_drv_data *ddata, | ||
170 | int reg, const u8 *buf, int len) | ||
171 | { | ||
172 | acx565akm_transfer(ddata, reg, buf, len, NULL, 0); | ||
173 | } | ||
174 | |||
175 | static inline void acx565akm_read(struct panel_drv_data *ddata, | ||
176 | int reg, u8 *buf, int len) | ||
177 | { | ||
178 | acx565akm_transfer(ddata, reg, NULL, 0, buf, len); | ||
179 | } | ||
180 | |||
181 | static void hw_guard_start(struct panel_drv_data *ddata, int guard_msec) | ||
182 | { | ||
183 | ddata->hw_guard_wait = msecs_to_jiffies(guard_msec); | ||
184 | ddata->hw_guard_end = jiffies + ddata->hw_guard_wait; | ||
185 | } | ||
186 | |||
187 | static void hw_guard_wait(struct panel_drv_data *ddata) | ||
188 | { | ||
189 | unsigned long wait = ddata->hw_guard_end - jiffies; | ||
190 | |||
191 | if ((long)wait > 0 && wait <= ddata->hw_guard_wait) { | ||
192 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
193 | schedule_timeout(wait); | ||
194 | } | ||
195 | } | ||
196 | |||
197 | static void set_sleep_mode(struct panel_drv_data *ddata, int on) | ||
198 | { | ||
199 | int cmd; | ||
200 | |||
201 | if (on) | ||
202 | cmd = MIPID_CMD_SLEEP_IN; | ||
203 | else | ||
204 | cmd = MIPID_CMD_SLEEP_OUT; | ||
205 | /* | ||
206 | * We have to keep 120msec between sleep in/out commands. | ||
207 | * (8.2.15, 8.2.16). | ||
208 | */ | ||
209 | hw_guard_wait(ddata); | ||
210 | acx565akm_cmd(ddata, cmd); | ||
211 | hw_guard_start(ddata, 120); | ||
212 | } | ||
213 | |||
214 | static void set_display_state(struct panel_drv_data *ddata, int enabled) | ||
215 | { | ||
216 | int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF; | ||
217 | |||
218 | acx565akm_cmd(ddata, cmd); | ||
219 | } | ||
220 | |||
221 | static int panel_enabled(struct panel_drv_data *ddata) | ||
222 | { | ||
223 | u32 disp_status; | ||
224 | int enabled; | ||
225 | |||
226 | acx565akm_read(ddata, MIPID_CMD_READ_DISP_STATUS, | ||
227 | (u8 *)&disp_status, 4); | ||
228 | disp_status = __be32_to_cpu(disp_status); | ||
229 | enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10)); | ||
230 | dev_dbg(&ddata->spi->dev, | ||
231 | "LCD panel %senabled by bootloader (status 0x%04x)\n", | ||
232 | enabled ? "" : "not ", disp_status); | ||
233 | return enabled; | ||
234 | } | ||
235 | |||
236 | static int panel_detect(struct panel_drv_data *ddata) | ||
237 | { | ||
238 | acx565akm_read(ddata, MIPID_CMD_READ_DISP_ID, ddata->display_id, 3); | ||
239 | dev_dbg(&ddata->spi->dev, "MIPI display ID: %02x%02x%02x\n", | ||
240 | ddata->display_id[0], | ||
241 | ddata->display_id[1], | ||
242 | ddata->display_id[2]); | ||
243 | |||
244 | switch (ddata->display_id[0]) { | ||
245 | case 0x10: | ||
246 | ddata->model = MIPID_VER_ACX565AKM; | ||
247 | ddata->name = "acx565akm"; | ||
248 | ddata->has_bc = 1; | ||
249 | ddata->has_cabc = 1; | ||
250 | break; | ||
251 | case 0x29: | ||
252 | ddata->model = MIPID_VER_L4F00311; | ||
253 | ddata->name = "l4f00311"; | ||
254 | break; | ||
255 | case 0x45: | ||
256 | ddata->model = MIPID_VER_LPH8923; | ||
257 | ddata->name = "lph8923"; | ||
258 | break; | ||
259 | case 0x83: | ||
260 | ddata->model = MIPID_VER_LS041Y3; | ||
261 | ddata->name = "ls041y3"; | ||
262 | break; | ||
263 | default: | ||
264 | ddata->name = "unknown"; | ||
265 | dev_err(&ddata->spi->dev, "invalid display ID\n"); | ||
266 | return -ENODEV; | ||
267 | } | ||
268 | |||
269 | ddata->revision = ddata->display_id[1]; | ||
270 | |||
271 | dev_info(&ddata->spi->dev, "omapfb: %s rev %02x LCD detected\n", | ||
272 | ddata->name, ddata->revision); | ||
273 | |||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | /*----------------------Backlight Control-------------------------*/ | ||
278 | |||
279 | static void enable_backlight_ctrl(struct panel_drv_data *ddata, int enable) | ||
280 | { | ||
281 | u16 ctrl; | ||
282 | |||
283 | acx565akm_read(ddata, MIPID_CMD_READ_CTRL_DISP, (u8 *)&ctrl, 1); | ||
284 | if (enable) { | ||
285 | ctrl |= CTRL_DISP_BRIGHTNESS_CTRL_ON | | ||
286 | CTRL_DISP_BACKLIGHT_ON; | ||
287 | } else { | ||
288 | ctrl &= ~(CTRL_DISP_BRIGHTNESS_CTRL_ON | | ||
289 | CTRL_DISP_BACKLIGHT_ON); | ||
290 | } | ||
291 | |||
292 | ctrl |= 1 << 8; | ||
293 | acx565akm_write(ddata, MIPID_CMD_WRITE_CTRL_DISP, (u8 *)&ctrl, 2); | ||
294 | } | ||
295 | |||
296 | static void set_cabc_mode(struct panel_drv_data *ddata, unsigned mode) | ||
297 | { | ||
298 | u16 cabc_ctrl; | ||
299 | |||
300 | ddata->cabc_mode = mode; | ||
301 | if (!ddata->enabled) | ||
302 | return; | ||
303 | cabc_ctrl = 0; | ||
304 | acx565akm_read(ddata, MIPID_CMD_READ_CABC, (u8 *)&cabc_ctrl, 1); | ||
305 | cabc_ctrl &= ~3; | ||
306 | cabc_ctrl |= (1 << 8) | (mode & 3); | ||
307 | acx565akm_write(ddata, MIPID_CMD_WRITE_CABC, (u8 *)&cabc_ctrl, 2); | ||
308 | } | ||
309 | |||
310 | static unsigned get_cabc_mode(struct panel_drv_data *ddata) | ||
311 | { | ||
312 | return ddata->cabc_mode; | ||
313 | } | ||
314 | |||
315 | static unsigned get_hw_cabc_mode(struct panel_drv_data *ddata) | ||
316 | { | ||
317 | u8 cabc_ctrl; | ||
318 | |||
319 | acx565akm_read(ddata, MIPID_CMD_READ_CABC, &cabc_ctrl, 1); | ||
320 | return cabc_ctrl & 3; | ||
321 | } | ||
322 | |||
323 | static void acx565akm_set_brightness(struct panel_drv_data *ddata, int level) | ||
324 | { | ||
325 | int bv; | ||
326 | |||
327 | bv = level | (1 << 8); | ||
328 | acx565akm_write(ddata, MIPID_CMD_WRITE_DISP_BRIGHTNESS, (u8 *)&bv, 2); | ||
329 | |||
330 | if (level) | ||
331 | enable_backlight_ctrl(ddata, 1); | ||
332 | else | ||
333 | enable_backlight_ctrl(ddata, 0); | ||
334 | } | ||
335 | |||
336 | static int acx565akm_get_actual_brightness(struct panel_drv_data *ddata) | ||
337 | { | ||
338 | u8 bv; | ||
339 | |||
340 | acx565akm_read(ddata, MIPID_CMD_READ_DISP_BRIGHTNESS, &bv, 1); | ||
341 | |||
342 | return bv; | ||
343 | } | ||
344 | |||
345 | |||
346 | static int acx565akm_bl_update_status(struct backlight_device *dev) | ||
347 | { | ||
348 | struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev); | ||
349 | int r; | ||
350 | int level; | ||
351 | |||
352 | dev_dbg(&ddata->spi->dev, "%s\n", __func__); | ||
353 | |||
354 | mutex_lock(&ddata->mutex); | ||
355 | |||
356 | if (dev->props.fb_blank == FB_BLANK_UNBLANK && | ||
357 | dev->props.power == FB_BLANK_UNBLANK) | ||
358 | level = dev->props.brightness; | ||
359 | else | ||
360 | level = 0; | ||
361 | |||
362 | r = 0; | ||
363 | if (ddata->has_bc) | ||
364 | acx565akm_set_brightness(ddata, level); | ||
365 | else | ||
366 | r = -ENODEV; | ||
367 | |||
368 | mutex_unlock(&ddata->mutex); | ||
369 | |||
370 | return r; | ||
371 | } | ||
372 | |||
373 | static int acx565akm_bl_get_intensity(struct backlight_device *dev) | ||
374 | { | ||
375 | struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev); | ||
376 | |||
377 | dev_dbg(&dev->dev, "%s\n", __func__); | ||
378 | |||
379 | if (!ddata->has_bc) | ||
380 | return -ENODEV; | ||
381 | |||
382 | if (dev->props.fb_blank == FB_BLANK_UNBLANK && | ||
383 | dev->props.power == FB_BLANK_UNBLANK) { | ||
384 | if (ddata->has_bc) | ||
385 | return acx565akm_get_actual_brightness(ddata); | ||
386 | else | ||
387 | return dev->props.brightness; | ||
388 | } | ||
389 | |||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | static const struct backlight_ops acx565akm_bl_ops = { | ||
394 | .get_brightness = acx565akm_bl_get_intensity, | ||
395 | .update_status = acx565akm_bl_update_status, | ||
396 | }; | ||
397 | |||
398 | /*--------------------Auto Brightness control via Sysfs---------------------*/ | ||
399 | |||
400 | static const char * const cabc_modes[] = { | ||
401 | "off", /* always used when CABC is not supported */ | ||
402 | "ui", | ||
403 | "still-image", | ||
404 | "moving-image", | ||
405 | }; | ||
406 | |||
407 | static ssize_t show_cabc_mode(struct device *dev, | ||
408 | struct device_attribute *attr, | ||
409 | char *buf) | ||
410 | { | ||
411 | struct panel_drv_data *ddata = dev_get_drvdata(dev); | ||
412 | const char *mode_str; | ||
413 | int mode; | ||
414 | int len; | ||
415 | |||
416 | if (!ddata->has_cabc) | ||
417 | mode = 0; | ||
418 | else | ||
419 | mode = get_cabc_mode(ddata); | ||
420 | mode_str = "unknown"; | ||
421 | if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes)) | ||
422 | mode_str = cabc_modes[mode]; | ||
423 | len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str); | ||
424 | |||
425 | return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1; | ||
426 | } | ||
427 | |||
428 | static ssize_t store_cabc_mode(struct device *dev, | ||
429 | struct device_attribute *attr, | ||
430 | const char *buf, size_t count) | ||
431 | { | ||
432 | struct panel_drv_data *ddata = dev_get_drvdata(dev); | ||
433 | int i; | ||
434 | |||
435 | for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) { | ||
436 | const char *mode_str = cabc_modes[i]; | ||
437 | int cmp_len = strlen(mode_str); | ||
438 | |||
439 | if (count > 0 && buf[count - 1] == '\n') | ||
440 | count--; | ||
441 | if (count != cmp_len) | ||
442 | continue; | ||
443 | |||
444 | if (strncmp(buf, mode_str, cmp_len) == 0) | ||
445 | break; | ||
446 | } | ||
447 | |||
448 | if (i == ARRAY_SIZE(cabc_modes)) | ||
449 | return -EINVAL; | ||
450 | |||
451 | if (!ddata->has_cabc && i != 0) | ||
452 | return -EINVAL; | ||
453 | |||
454 | mutex_lock(&ddata->mutex); | ||
455 | set_cabc_mode(ddata, i); | ||
456 | mutex_unlock(&ddata->mutex); | ||
457 | |||
458 | return count; | ||
459 | } | ||
460 | |||
461 | static ssize_t show_cabc_available_modes(struct device *dev, | ||
462 | struct device_attribute *attr, | ||
463 | char *buf) | ||
464 | { | ||
465 | struct panel_drv_data *ddata = dev_get_drvdata(dev); | ||
466 | int len; | ||
467 | int i; | ||
468 | |||
469 | if (!ddata->has_cabc) | ||
470 | return snprintf(buf, PAGE_SIZE, "%s\n", cabc_modes[0]); | ||
471 | |||
472 | for (i = 0, len = 0; | ||
473 | len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++) | ||
474 | len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s", | ||
475 | i ? " " : "", cabc_modes[i], | ||
476 | i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : ""); | ||
477 | |||
478 | return len < PAGE_SIZE ? len : PAGE_SIZE - 1; | ||
479 | } | ||
480 | |||
481 | static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR, | ||
482 | show_cabc_mode, store_cabc_mode); | ||
483 | static DEVICE_ATTR(cabc_available_modes, S_IRUGO, | ||
484 | show_cabc_available_modes, NULL); | ||
485 | |||
486 | static struct attribute *bldev_attrs[] = { | ||
487 | &dev_attr_cabc_mode.attr, | ||
488 | &dev_attr_cabc_available_modes.attr, | ||
489 | NULL, | ||
490 | }; | ||
491 | |||
492 | static struct attribute_group bldev_attr_group = { | ||
493 | .attrs = bldev_attrs, | ||
494 | }; | ||
495 | |||
496 | static int acx565akm_connect(struct omap_dss_device *dssdev) | ||
497 | { | ||
498 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
499 | struct omap_dss_device *in = ddata->in; | ||
500 | int r; | ||
501 | |||
502 | if (omapdss_device_is_connected(dssdev)) | ||
503 | return 0; | ||
504 | |||
505 | r = in->ops.sdi->connect(in, dssdev); | ||
506 | if (r) | ||
507 | return r; | ||
508 | |||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | static void acx565akm_disconnect(struct omap_dss_device *dssdev) | ||
513 | { | ||
514 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
515 | struct omap_dss_device *in = ddata->in; | ||
516 | |||
517 | if (!omapdss_device_is_connected(dssdev)) | ||
518 | return; | ||
519 | |||
520 | in->ops.sdi->disconnect(in, dssdev); | ||
521 | } | ||
522 | |||
523 | static int acx565akm_panel_power_on(struct omap_dss_device *dssdev) | ||
524 | { | ||
525 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
526 | struct omap_dss_device *in = ddata->in; | ||
527 | int r; | ||
528 | |||
529 | dev_dbg(&ddata->spi->dev, "%s\n", __func__); | ||
530 | |||
531 | in->ops.sdi->set_timings(in, &ddata->videomode); | ||
532 | in->ops.sdi->set_datapairs(in, ddata->datapairs); | ||
533 | |||
534 | r = in->ops.sdi->enable(in); | ||
535 | if (r) { | ||
536 | pr_err("%s sdi enable failed\n", __func__); | ||
537 | return r; | ||
538 | } | ||
539 | |||
540 | /*FIXME tweak me */ | ||
541 | msleep(50); | ||
542 | |||
543 | if (gpio_is_valid(ddata->reset_gpio)) | ||
544 | gpio_set_value(ddata->reset_gpio, 1); | ||
545 | |||
546 | if (ddata->enabled) { | ||
547 | dev_dbg(&ddata->spi->dev, "panel already enabled\n"); | ||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | /* | ||
552 | * We have to meet all the following delay requirements: | ||
553 | * 1. tRW: reset pulse width 10usec (7.12.1) | ||
554 | * 2. tRT: reset cancel time 5msec (7.12.1) | ||
555 | * 3. Providing PCLK,HS,VS signals for 2 frames = ~50msec worst | ||
556 | * case (7.6.2) | ||
557 | * 4. 120msec before the sleep out command (7.12.1) | ||
558 | */ | ||
559 | msleep(120); | ||
560 | |||
561 | set_sleep_mode(ddata, 0); | ||
562 | ddata->enabled = 1; | ||
563 | |||
564 | /* 5msec between sleep out and the next command. (8.2.16) */ | ||
565 | usleep_range(5000, 10000); | ||
566 | set_display_state(ddata, 1); | ||
567 | set_cabc_mode(ddata, ddata->cabc_mode); | ||
568 | |||
569 | mutex_unlock(&ddata->mutex); | ||
570 | |||
571 | return acx565akm_bl_update_status(ddata->bl_dev); | ||
572 | } | ||
573 | |||
574 | static void acx565akm_panel_power_off(struct omap_dss_device *dssdev) | ||
575 | { | ||
576 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
577 | struct omap_dss_device *in = ddata->in; | ||
578 | |||
579 | dev_dbg(dssdev->dev, "%s\n", __func__); | ||
580 | |||
581 | if (!ddata->enabled) | ||
582 | return; | ||
583 | |||
584 | set_display_state(ddata, 0); | ||
585 | set_sleep_mode(ddata, 1); | ||
586 | ddata->enabled = 0; | ||
587 | /* | ||
588 | * We have to provide PCLK,HS,VS signals for 2 frames (worst case | ||
589 | * ~50msec) after sending the sleep in command and asserting the | ||
590 | * reset signal. We probably could assert the reset w/o the delay | ||
591 | * but we still delay to avoid possible artifacts. (7.6.1) | ||
592 | */ | ||
593 | msleep(50); | ||
594 | |||
595 | if (gpio_is_valid(ddata->reset_gpio)) | ||
596 | gpio_set_value(ddata->reset_gpio, 0); | ||
597 | |||
598 | /* FIXME need to tweak this delay */ | ||
599 | msleep(100); | ||
600 | |||
601 | in->ops.sdi->disable(in); | ||
602 | } | ||
603 | |||
604 | static int acx565akm_enable(struct omap_dss_device *dssdev) | ||
605 | { | ||
606 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
607 | int r; | ||
608 | |||
609 | dev_dbg(dssdev->dev, "%s\n", __func__); | ||
610 | |||
611 | if (!omapdss_device_is_connected(dssdev)) | ||
612 | return -ENODEV; | ||
613 | |||
614 | if (omapdss_device_is_enabled(dssdev)) | ||
615 | return 0; | ||
616 | |||
617 | mutex_lock(&ddata->mutex); | ||
618 | r = acx565akm_panel_power_on(dssdev); | ||
619 | mutex_unlock(&ddata->mutex); | ||
620 | |||
621 | if (r) | ||
622 | return r; | ||
623 | |||
624 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
625 | |||
626 | return 0; | ||
627 | } | ||
628 | |||
629 | static void acx565akm_disable(struct omap_dss_device *dssdev) | ||
630 | { | ||
631 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
632 | |||
633 | dev_dbg(dssdev->dev, "%s\n", __func__); | ||
634 | |||
635 | if (!omapdss_device_is_enabled(dssdev)) | ||
636 | return; | ||
637 | |||
638 | mutex_lock(&ddata->mutex); | ||
639 | acx565akm_panel_power_off(dssdev); | ||
640 | mutex_unlock(&ddata->mutex); | ||
641 | |||
642 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
643 | } | ||
644 | |||
645 | static void acx565akm_set_timings(struct omap_dss_device *dssdev, | ||
646 | struct omap_video_timings *timings) | ||
647 | { | ||
648 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
649 | struct omap_dss_device *in = ddata->in; | ||
650 | |||
651 | ddata->videomode = *timings; | ||
652 | dssdev->panel.timings = *timings; | ||
653 | |||
654 | in->ops.sdi->set_timings(in, timings); | ||
655 | } | ||
656 | |||
657 | static void acx565akm_get_timings(struct omap_dss_device *dssdev, | ||
658 | struct omap_video_timings *timings) | ||
659 | { | ||
660 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
661 | |||
662 | *timings = ddata->videomode; | ||
663 | } | ||
664 | |||
665 | static int acx565akm_check_timings(struct omap_dss_device *dssdev, | ||
666 | struct omap_video_timings *timings) | ||
667 | { | ||
668 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
669 | struct omap_dss_device *in = ddata->in; | ||
670 | |||
671 | return in->ops.sdi->check_timings(in, timings); | ||
672 | } | ||
673 | |||
674 | static struct omap_dss_driver acx565akm_ops = { | ||
675 | .connect = acx565akm_connect, | ||
676 | .disconnect = acx565akm_disconnect, | ||
677 | |||
678 | .enable = acx565akm_enable, | ||
679 | .disable = acx565akm_disable, | ||
680 | |||
681 | .set_timings = acx565akm_set_timings, | ||
682 | .get_timings = acx565akm_get_timings, | ||
683 | .check_timings = acx565akm_check_timings, | ||
684 | |||
685 | .get_resolution = omapdss_default_get_resolution, | ||
686 | }; | ||
687 | |||
688 | static int acx565akm_probe_pdata(struct spi_device *spi) | ||
689 | { | ||
690 | const struct panel_acx565akm_platform_data *pdata; | ||
691 | struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); | ||
692 | struct omap_dss_device *dssdev, *in; | ||
693 | |||
694 | pdata = dev_get_platdata(&spi->dev); | ||
695 | |||
696 | ddata->reset_gpio = pdata->reset_gpio; | ||
697 | |||
698 | in = omap_dss_find_output(pdata->source); | ||
699 | if (in == NULL) { | ||
700 | dev_err(&spi->dev, "failed to find video source '%s'\n", | ||
701 | pdata->source); | ||
702 | return -EPROBE_DEFER; | ||
703 | } | ||
704 | ddata->in = in; | ||
705 | |||
706 | ddata->datapairs = pdata->datapairs; | ||
707 | |||
708 | dssdev = &ddata->dssdev; | ||
709 | dssdev->name = pdata->name; | ||
710 | |||
711 | return 0; | ||
712 | } | ||
713 | |||
714 | static int acx565akm_probe(struct spi_device *spi) | ||
715 | { | ||
716 | struct panel_drv_data *ddata; | ||
717 | struct omap_dss_device *dssdev; | ||
718 | struct backlight_device *bldev; | ||
719 | int max_brightness, brightness; | ||
720 | struct backlight_properties props; | ||
721 | int r; | ||
722 | |||
723 | dev_dbg(&spi->dev, "%s\n", __func__); | ||
724 | |||
725 | spi->mode = SPI_MODE_3; | ||
726 | |||
727 | ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL); | ||
728 | if (ddata == NULL) | ||
729 | return -ENOMEM; | ||
730 | |||
731 | dev_set_drvdata(&spi->dev, ddata); | ||
732 | |||
733 | ddata->spi = spi; | ||
734 | |||
735 | mutex_init(&ddata->mutex); | ||
736 | |||
737 | if (dev_get_platdata(&spi->dev)) { | ||
738 | r = acx565akm_probe_pdata(spi); | ||
739 | if (r) | ||
740 | return r; | ||
741 | } else { | ||
742 | return -ENODEV; | ||
743 | } | ||
744 | |||
745 | if (gpio_is_valid(ddata->reset_gpio)) { | ||
746 | r = devm_gpio_request_one(&spi->dev, ddata->reset_gpio, | ||
747 | GPIOF_OUT_INIT_LOW, "lcd reset"); | ||
748 | if (r) | ||
749 | goto err_gpio; | ||
750 | } | ||
751 | |||
752 | if (gpio_is_valid(ddata->reset_gpio)) | ||
753 | gpio_set_value(ddata->reset_gpio, 1); | ||
754 | |||
755 | /* | ||
756 | * After reset we have to wait 5 msec before the first | ||
757 | * command can be sent. | ||
758 | */ | ||
759 | usleep_range(5000, 10000); | ||
760 | |||
761 | ddata->enabled = panel_enabled(ddata); | ||
762 | |||
763 | r = panel_detect(ddata); | ||
764 | |||
765 | if (!ddata->enabled && gpio_is_valid(ddata->reset_gpio)) | ||
766 | gpio_set_value(ddata->reset_gpio, 0); | ||
767 | |||
768 | if (r) { | ||
769 | dev_err(&spi->dev, "%s panel detect error\n", __func__); | ||
770 | goto err_detect; | ||
771 | } | ||
772 | |||
773 | memset(&props, 0, sizeof(props)); | ||
774 | props.fb_blank = FB_BLANK_UNBLANK; | ||
775 | props.power = FB_BLANK_UNBLANK; | ||
776 | props.type = BACKLIGHT_RAW; | ||
777 | |||
778 | bldev = backlight_device_register("acx565akm", &ddata->spi->dev, | ||
779 | ddata, &acx565akm_bl_ops, &props); | ||
780 | ddata->bl_dev = bldev; | ||
781 | if (ddata->has_cabc) { | ||
782 | r = sysfs_create_group(&bldev->dev.kobj, &bldev_attr_group); | ||
783 | if (r) { | ||
784 | dev_err(&bldev->dev, | ||
785 | "%s failed to create sysfs files\n", __func__); | ||
786 | goto err_sysfs; | ||
787 | } | ||
788 | ddata->cabc_mode = get_hw_cabc_mode(ddata); | ||
789 | } | ||
790 | |||
791 | max_brightness = 255; | ||
792 | |||
793 | if (ddata->has_bc) | ||
794 | brightness = acx565akm_get_actual_brightness(ddata); | ||
795 | else | ||
796 | brightness = 0; | ||
797 | |||
798 | bldev->props.max_brightness = max_brightness; | ||
799 | bldev->props.brightness = brightness; | ||
800 | |||
801 | acx565akm_bl_update_status(bldev); | ||
802 | |||
803 | |||
804 | ddata->videomode = acx565akm_panel_timings; | ||
805 | |||
806 | dssdev = &ddata->dssdev; | ||
807 | dssdev->dev = &spi->dev; | ||
808 | dssdev->driver = &acx565akm_ops; | ||
809 | dssdev->type = OMAP_DISPLAY_TYPE_SDI; | ||
810 | dssdev->owner = THIS_MODULE; | ||
811 | dssdev->panel.timings = ddata->videomode; | ||
812 | |||
813 | r = omapdss_register_display(dssdev); | ||
814 | if (r) { | ||
815 | dev_err(&spi->dev, "Failed to register panel\n"); | ||
816 | goto err_reg; | ||
817 | } | ||
818 | |||
819 | return 0; | ||
820 | |||
821 | err_reg: | ||
822 | sysfs_remove_group(&bldev->dev.kobj, &bldev_attr_group); | ||
823 | err_sysfs: | ||
824 | backlight_device_unregister(bldev); | ||
825 | err_detect: | ||
826 | err_gpio: | ||
827 | omap_dss_put_device(ddata->in); | ||
828 | return r; | ||
829 | } | ||
830 | |||
831 | static int acx565akm_remove(struct spi_device *spi) | ||
832 | { | ||
833 | struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); | ||
834 | struct omap_dss_device *dssdev = &ddata->dssdev; | ||
835 | struct omap_dss_device *in = ddata->in; | ||
836 | |||
837 | dev_dbg(&ddata->spi->dev, "%s\n", __func__); | ||
838 | |||
839 | sysfs_remove_group(&ddata->bl_dev->dev.kobj, &bldev_attr_group); | ||
840 | backlight_device_unregister(ddata->bl_dev); | ||
841 | |||
842 | omapdss_unregister_display(dssdev); | ||
843 | |||
844 | acx565akm_disable(dssdev); | ||
845 | acx565akm_disconnect(dssdev); | ||
846 | |||
847 | omap_dss_put_device(in); | ||
848 | |||
849 | return 0; | ||
850 | } | ||
851 | |||
852 | static struct spi_driver acx565akm_driver = { | ||
853 | .driver = { | ||
854 | .name = "acx565akm", | ||
855 | .owner = THIS_MODULE, | ||
856 | }, | ||
857 | .probe = acx565akm_probe, | ||
858 | .remove = acx565akm_remove, | ||
859 | }; | ||
860 | |||
861 | module_spi_driver(acx565akm_driver); | ||
862 | |||
863 | MODULE_AUTHOR("Nokia Corporation"); | ||
864 | MODULE_DESCRIPTION("acx565akm LCD Driver"); | ||
865 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays-new/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays-new/panel-tpo-td043mtea1.c new file mode 100644 index 000000000000..eadc6529fa3d --- /dev/null +++ b/drivers/video/omap2/displays-new/panel-tpo-td043mtea1.c | |||
@@ -0,0 +1,646 @@ | |||
1 | /* | ||
2 | * TPO TD043MTEA1 Panel driver | ||
3 | * | ||
4 | * Author: Gražvydas Ignotas <notasas@gmail.com> | ||
5 | * Converted to new DSS device model: Tomi Valkeinen <tomi.valkeinen@ti.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/spi/spi.h> | ||
16 | #include <linux/regulator/consumer.h> | ||
17 | #include <linux/gpio.h> | ||
18 | #include <linux/err.h> | ||
19 | #include <linux/slab.h> | ||
20 | |||
21 | #include <video/omapdss.h> | ||
22 | #include <video/omap-panel-data.h> | ||
23 | |||
24 | #define TPO_R02_MODE(x) ((x) & 7) | ||
25 | #define TPO_R02_MODE_800x480 7 | ||
26 | #define TPO_R02_NCLK_RISING BIT(3) | ||
27 | #define TPO_R02_HSYNC_HIGH BIT(4) | ||
28 | #define TPO_R02_VSYNC_HIGH BIT(5) | ||
29 | |||
30 | #define TPO_R03_NSTANDBY BIT(0) | ||
31 | #define TPO_R03_EN_CP_CLK BIT(1) | ||
32 | #define TPO_R03_EN_VGL_PUMP BIT(2) | ||
33 | #define TPO_R03_EN_PWM BIT(3) | ||
34 | #define TPO_R03_DRIVING_CAP_100 BIT(4) | ||
35 | #define TPO_R03_EN_PRE_CHARGE BIT(6) | ||
36 | #define TPO_R03_SOFTWARE_CTL BIT(7) | ||
37 | |||
38 | #define TPO_R04_NFLIP_H BIT(0) | ||
39 | #define TPO_R04_NFLIP_V BIT(1) | ||
40 | #define TPO_R04_CP_CLK_FREQ_1H BIT(2) | ||
41 | #define TPO_R04_VGL_FREQ_1H BIT(4) | ||
42 | |||
43 | #define TPO_R03_VAL_NORMAL (TPO_R03_NSTANDBY | TPO_R03_EN_CP_CLK | \ | ||
44 | TPO_R03_EN_VGL_PUMP | TPO_R03_EN_PWM | \ | ||
45 | TPO_R03_DRIVING_CAP_100 | TPO_R03_EN_PRE_CHARGE | \ | ||
46 | TPO_R03_SOFTWARE_CTL) | ||
47 | |||
48 | #define TPO_R03_VAL_STANDBY (TPO_R03_DRIVING_CAP_100 | \ | ||
49 | TPO_R03_EN_PRE_CHARGE | TPO_R03_SOFTWARE_CTL) | ||
50 | |||
51 | static const u16 tpo_td043_def_gamma[12] = { | ||
52 | 105, 315, 381, 431, 490, 537, 579, 686, 780, 837, 880, 1023 | ||
53 | }; | ||
54 | |||
55 | struct panel_drv_data { | ||
56 | struct omap_dss_device dssdev; | ||
57 | struct omap_dss_device *in; | ||
58 | |||
59 | struct omap_video_timings videomode; | ||
60 | |||
61 | int data_lines; | ||
62 | |||
63 | struct spi_device *spi; | ||
64 | struct regulator *vcc_reg; | ||
65 | int nreset_gpio; | ||
66 | u16 gamma[12]; | ||
67 | u32 mode; | ||
68 | u32 hmirror:1; | ||
69 | u32 vmirror:1; | ||
70 | u32 powered_on:1; | ||
71 | u32 spi_suspended:1; | ||
72 | u32 power_on_resume:1; | ||
73 | }; | ||
74 | |||
75 | static const struct omap_video_timings tpo_td043_timings = { | ||
76 | .x_res = 800, | ||
77 | .y_res = 480, | ||
78 | |||
79 | .pixel_clock = 36000, | ||
80 | |||
81 | .hsw = 1, | ||
82 | .hfp = 68, | ||
83 | .hbp = 214, | ||
84 | |||
85 | .vsw = 1, | ||
86 | .vfp = 39, | ||
87 | .vbp = 34, | ||
88 | |||
89 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
90 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
91 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, | ||
92 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
93 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
94 | }; | ||
95 | |||
96 | #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) | ||
97 | |||
98 | static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data) | ||
99 | { | ||
100 | struct spi_message m; | ||
101 | struct spi_transfer xfer; | ||
102 | u16 w; | ||
103 | int r; | ||
104 | |||
105 | spi_message_init(&m); | ||
106 | |||
107 | memset(&xfer, 0, sizeof(xfer)); | ||
108 | |||
109 | w = ((u16)addr << 10) | (1 << 8) | data; | ||
110 | xfer.tx_buf = &w; | ||
111 | xfer.bits_per_word = 16; | ||
112 | xfer.len = 2; | ||
113 | spi_message_add_tail(&xfer, &m); | ||
114 | |||
115 | r = spi_sync(spi, &m); | ||
116 | if (r < 0) | ||
117 | dev_warn(&spi->dev, "failed to write to LCD reg (%d)\n", r); | ||
118 | return r; | ||
119 | } | ||
120 | |||
121 | static void tpo_td043_write_gamma(struct spi_device *spi, u16 gamma[12]) | ||
122 | { | ||
123 | u8 i, val; | ||
124 | |||
125 | /* gamma bits [9:8] */ | ||
126 | for (val = i = 0; i < 4; i++) | ||
127 | val |= (gamma[i] & 0x300) >> ((i + 1) * 2); | ||
128 | tpo_td043_write(spi, 0x11, val); | ||
129 | |||
130 | for (val = i = 0; i < 4; i++) | ||
131 | val |= (gamma[i+4] & 0x300) >> ((i + 1) * 2); | ||
132 | tpo_td043_write(spi, 0x12, val); | ||
133 | |||
134 | for (val = i = 0; i < 4; i++) | ||
135 | val |= (gamma[i+8] & 0x300) >> ((i + 1) * 2); | ||
136 | tpo_td043_write(spi, 0x13, val); | ||
137 | |||
138 | /* gamma bits [7:0] */ | ||
139 | for (val = i = 0; i < 12; i++) | ||
140 | tpo_td043_write(spi, 0x14 + i, gamma[i] & 0xff); | ||
141 | } | ||
142 | |||
143 | static int tpo_td043_write_mirror(struct spi_device *spi, bool h, bool v) | ||
144 | { | ||
145 | u8 reg4 = TPO_R04_NFLIP_H | TPO_R04_NFLIP_V | | ||
146 | TPO_R04_CP_CLK_FREQ_1H | TPO_R04_VGL_FREQ_1H; | ||
147 | if (h) | ||
148 | reg4 &= ~TPO_R04_NFLIP_H; | ||
149 | if (v) | ||
150 | reg4 &= ~TPO_R04_NFLIP_V; | ||
151 | |||
152 | return tpo_td043_write(spi, 4, reg4); | ||
153 | } | ||
154 | |||
155 | static int tpo_td043_set_hmirror(struct omap_dss_device *dssdev, bool enable) | ||
156 | { | ||
157 | struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev); | ||
158 | |||
159 | ddata->hmirror = enable; | ||
160 | return tpo_td043_write_mirror(ddata->spi, ddata->hmirror, | ||
161 | ddata->vmirror); | ||
162 | } | ||
163 | |||
164 | static bool tpo_td043_get_hmirror(struct omap_dss_device *dssdev) | ||
165 | { | ||
166 | struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev); | ||
167 | |||
168 | return ddata->hmirror; | ||
169 | } | ||
170 | |||
171 | static ssize_t tpo_td043_vmirror_show(struct device *dev, | ||
172 | struct device_attribute *attr, char *buf) | ||
173 | { | ||
174 | struct panel_drv_data *ddata = dev_get_drvdata(dev); | ||
175 | |||
176 | return snprintf(buf, PAGE_SIZE, "%d\n", ddata->vmirror); | ||
177 | } | ||
178 | |||
179 | static ssize_t tpo_td043_vmirror_store(struct device *dev, | ||
180 | struct device_attribute *attr, const char *buf, size_t count) | ||
181 | { | ||
182 | struct panel_drv_data *ddata = dev_get_drvdata(dev); | ||
183 | int val; | ||
184 | int ret; | ||
185 | |||
186 | ret = kstrtoint(buf, 0, &val); | ||
187 | if (ret < 0) | ||
188 | return ret; | ||
189 | |||
190 | val = !!val; | ||
191 | |||
192 | ret = tpo_td043_write_mirror(ddata->spi, ddata->hmirror, val); | ||
193 | if (ret < 0) | ||
194 | return ret; | ||
195 | |||
196 | ddata->vmirror = val; | ||
197 | |||
198 | return count; | ||
199 | } | ||
200 | |||
201 | static ssize_t tpo_td043_mode_show(struct device *dev, | ||
202 | struct device_attribute *attr, char *buf) | ||
203 | { | ||
204 | struct panel_drv_data *ddata = dev_get_drvdata(dev); | ||
205 | |||
206 | return snprintf(buf, PAGE_SIZE, "%d\n", ddata->mode); | ||
207 | } | ||
208 | |||
209 | static ssize_t tpo_td043_mode_store(struct device *dev, | ||
210 | struct device_attribute *attr, const char *buf, size_t count) | ||
211 | { | ||
212 | struct panel_drv_data *ddata = dev_get_drvdata(dev); | ||
213 | long val; | ||
214 | int ret; | ||
215 | |||
216 | ret = kstrtol(buf, 0, &val); | ||
217 | if (ret != 0 || val & ~7) | ||
218 | return -EINVAL; | ||
219 | |||
220 | ddata->mode = val; | ||
221 | |||
222 | val |= TPO_R02_NCLK_RISING; | ||
223 | tpo_td043_write(ddata->spi, 2, val); | ||
224 | |||
225 | return count; | ||
226 | } | ||
227 | |||
228 | static ssize_t tpo_td043_gamma_show(struct device *dev, | ||
229 | struct device_attribute *attr, char *buf) | ||
230 | { | ||
231 | struct panel_drv_data *ddata = dev_get_drvdata(dev); | ||
232 | ssize_t len = 0; | ||
233 | int ret; | ||
234 | int i; | ||
235 | |||
236 | for (i = 0; i < ARRAY_SIZE(ddata->gamma); i++) { | ||
237 | ret = snprintf(buf + len, PAGE_SIZE - len, "%u ", | ||
238 | ddata->gamma[i]); | ||
239 | if (ret < 0) | ||
240 | return ret; | ||
241 | len += ret; | ||
242 | } | ||
243 | buf[len - 1] = '\n'; | ||
244 | |||
245 | return len; | ||
246 | } | ||
247 | |||
248 | static ssize_t tpo_td043_gamma_store(struct device *dev, | ||
249 | struct device_attribute *attr, const char *buf, size_t count) | ||
250 | { | ||
251 | struct panel_drv_data *ddata = dev_get_drvdata(dev); | ||
252 | unsigned int g[12]; | ||
253 | int ret; | ||
254 | int i; | ||
255 | |||
256 | ret = sscanf(buf, "%u %u %u %u %u %u %u %u %u %u %u %u", | ||
257 | &g[0], &g[1], &g[2], &g[3], &g[4], &g[5], | ||
258 | &g[6], &g[7], &g[8], &g[9], &g[10], &g[11]); | ||
259 | |||
260 | if (ret != 12) | ||
261 | return -EINVAL; | ||
262 | |||
263 | for (i = 0; i < 12; i++) | ||
264 | ddata->gamma[i] = g[i]; | ||
265 | |||
266 | tpo_td043_write_gamma(ddata->spi, ddata->gamma); | ||
267 | |||
268 | return count; | ||
269 | } | ||
270 | |||
271 | static DEVICE_ATTR(vmirror, S_IRUGO | S_IWUSR, | ||
272 | tpo_td043_vmirror_show, tpo_td043_vmirror_store); | ||
273 | static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, | ||
274 | tpo_td043_mode_show, tpo_td043_mode_store); | ||
275 | static DEVICE_ATTR(gamma, S_IRUGO | S_IWUSR, | ||
276 | tpo_td043_gamma_show, tpo_td043_gamma_store); | ||
277 | |||
278 | static struct attribute *tpo_td043_attrs[] = { | ||
279 | &dev_attr_vmirror.attr, | ||
280 | &dev_attr_mode.attr, | ||
281 | &dev_attr_gamma.attr, | ||
282 | NULL, | ||
283 | }; | ||
284 | |||
285 | static struct attribute_group tpo_td043_attr_group = { | ||
286 | .attrs = tpo_td043_attrs, | ||
287 | }; | ||
288 | |||
289 | static int tpo_td043_power_on(struct panel_drv_data *ddata) | ||
290 | { | ||
291 | int r; | ||
292 | |||
293 | if (ddata->powered_on) | ||
294 | return 0; | ||
295 | |||
296 | r = regulator_enable(ddata->vcc_reg); | ||
297 | if (r != 0) | ||
298 | return r; | ||
299 | |||
300 | /* wait for panel to stabilize */ | ||
301 | msleep(160); | ||
302 | |||
303 | if (gpio_is_valid(ddata->nreset_gpio)) | ||
304 | gpio_set_value(ddata->nreset_gpio, 1); | ||
305 | |||
306 | tpo_td043_write(ddata->spi, 2, | ||
307 | TPO_R02_MODE(ddata->mode) | TPO_R02_NCLK_RISING); | ||
308 | tpo_td043_write(ddata->spi, 3, TPO_R03_VAL_NORMAL); | ||
309 | tpo_td043_write(ddata->spi, 0x20, 0xf0); | ||
310 | tpo_td043_write(ddata->spi, 0x21, 0xf0); | ||
311 | tpo_td043_write_mirror(ddata->spi, ddata->hmirror, | ||
312 | ddata->vmirror); | ||
313 | tpo_td043_write_gamma(ddata->spi, ddata->gamma); | ||
314 | |||
315 | ddata->powered_on = 1; | ||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | static void tpo_td043_power_off(struct panel_drv_data *ddata) | ||
320 | { | ||
321 | if (!ddata->powered_on) | ||
322 | return; | ||
323 | |||
324 | tpo_td043_write(ddata->spi, 3, | ||
325 | TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM); | ||
326 | |||
327 | if (gpio_is_valid(ddata->nreset_gpio)) | ||
328 | gpio_set_value(ddata->nreset_gpio, 0); | ||
329 | |||
330 | /* wait for at least 2 vsyncs before cutting off power */ | ||
331 | msleep(50); | ||
332 | |||
333 | tpo_td043_write(ddata->spi, 3, TPO_R03_VAL_STANDBY); | ||
334 | |||
335 | regulator_disable(ddata->vcc_reg); | ||
336 | |||
337 | ddata->powered_on = 0; | ||
338 | } | ||
339 | |||
340 | static int tpo_td043_connect(struct omap_dss_device *dssdev) | ||
341 | { | ||
342 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
343 | struct omap_dss_device *in = ddata->in; | ||
344 | int r; | ||
345 | |||
346 | if (omapdss_device_is_connected(dssdev)) | ||
347 | return 0; | ||
348 | |||
349 | r = in->ops.dpi->connect(in, dssdev); | ||
350 | if (r) | ||
351 | return r; | ||
352 | |||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | static void tpo_td043_disconnect(struct omap_dss_device *dssdev) | ||
357 | { | ||
358 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
359 | struct omap_dss_device *in = ddata->in; | ||
360 | |||
361 | if (!omapdss_device_is_connected(dssdev)) | ||
362 | return; | ||
363 | |||
364 | in->ops.dpi->disconnect(in, dssdev); | ||
365 | } | ||
366 | |||
367 | static int tpo_td043_enable(struct omap_dss_device *dssdev) | ||
368 | { | ||
369 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
370 | struct omap_dss_device *in = ddata->in; | ||
371 | int r; | ||
372 | |||
373 | if (!omapdss_device_is_connected(dssdev)) | ||
374 | return -ENODEV; | ||
375 | |||
376 | if (omapdss_device_is_enabled(dssdev)) | ||
377 | return 0; | ||
378 | |||
379 | in->ops.dpi->set_data_lines(in, ddata->data_lines); | ||
380 | in->ops.dpi->set_timings(in, &ddata->videomode); | ||
381 | |||
382 | r = in->ops.dpi->enable(in); | ||
383 | if (r) | ||
384 | return r; | ||
385 | |||
386 | /* | ||
387 | * If we are resuming from system suspend, SPI clocks might not be | ||
388 | * enabled yet, so we'll program the LCD from SPI PM resume callback. | ||
389 | */ | ||
390 | if (!ddata->spi_suspended) { | ||
391 | r = tpo_td043_power_on(ddata); | ||
392 | if (r) { | ||
393 | in->ops.dpi->disable(in); | ||
394 | return r; | ||
395 | } | ||
396 | } | ||
397 | |||
398 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | static void tpo_td043_disable(struct omap_dss_device *dssdev) | ||
404 | { | ||
405 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
406 | struct omap_dss_device *in = ddata->in; | ||
407 | |||
408 | if (!omapdss_device_is_enabled(dssdev)) | ||
409 | return; | ||
410 | |||
411 | in->ops.dpi->disable(in); | ||
412 | |||
413 | if (!ddata->spi_suspended) | ||
414 | tpo_td043_power_off(ddata); | ||
415 | |||
416 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
417 | } | ||
418 | |||
419 | static void tpo_td043_set_timings(struct omap_dss_device *dssdev, | ||
420 | struct omap_video_timings *timings) | ||
421 | { | ||
422 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
423 | struct omap_dss_device *in = ddata->in; | ||
424 | |||
425 | ddata->videomode = *timings; | ||
426 | dssdev->panel.timings = *timings; | ||
427 | |||
428 | in->ops.dpi->set_timings(in, timings); | ||
429 | } | ||
430 | |||
431 | static void tpo_td043_get_timings(struct omap_dss_device *dssdev, | ||
432 | struct omap_video_timings *timings) | ||
433 | { | ||
434 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
435 | |||
436 | *timings = ddata->videomode; | ||
437 | } | ||
438 | |||
439 | static int tpo_td043_check_timings(struct omap_dss_device *dssdev, | ||
440 | struct omap_video_timings *timings) | ||
441 | { | ||
442 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
443 | struct omap_dss_device *in = ddata->in; | ||
444 | |||
445 | return in->ops.dpi->check_timings(in, timings); | ||
446 | } | ||
447 | |||
448 | static struct omap_dss_driver tpo_td043_ops = { | ||
449 | .connect = tpo_td043_connect, | ||
450 | .disconnect = tpo_td043_disconnect, | ||
451 | |||
452 | .enable = tpo_td043_enable, | ||
453 | .disable = tpo_td043_disable, | ||
454 | |||
455 | .set_timings = tpo_td043_set_timings, | ||
456 | .get_timings = tpo_td043_get_timings, | ||
457 | .check_timings = tpo_td043_check_timings, | ||
458 | |||
459 | .set_mirror = tpo_td043_set_hmirror, | ||
460 | .get_mirror = tpo_td043_get_hmirror, | ||
461 | |||
462 | .get_resolution = omapdss_default_get_resolution, | ||
463 | }; | ||
464 | |||
465 | |||
466 | static int tpo_td043_probe_pdata(struct spi_device *spi) | ||
467 | { | ||
468 | const struct panel_tpo_td043mtea1_platform_data *pdata; | ||
469 | struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); | ||
470 | struct omap_dss_device *dssdev, *in; | ||
471 | |||
472 | pdata = dev_get_platdata(&spi->dev); | ||
473 | |||
474 | ddata->nreset_gpio = pdata->nreset_gpio; | ||
475 | |||
476 | in = omap_dss_find_output(pdata->source); | ||
477 | if (in == NULL) { | ||
478 | dev_err(&spi->dev, "failed to find video source '%s'\n", | ||
479 | pdata->source); | ||
480 | return -EPROBE_DEFER; | ||
481 | } | ||
482 | ddata->in = in; | ||
483 | |||
484 | ddata->data_lines = pdata->data_lines; | ||
485 | |||
486 | dssdev = &ddata->dssdev; | ||
487 | dssdev->name = pdata->name; | ||
488 | |||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | static int tpo_td043_probe(struct spi_device *spi) | ||
493 | { | ||
494 | struct panel_drv_data *ddata; | ||
495 | struct omap_dss_device *dssdev; | ||
496 | int r; | ||
497 | |||
498 | dev_dbg(&spi->dev, "%s\n", __func__); | ||
499 | |||
500 | spi->bits_per_word = 16; | ||
501 | spi->mode = SPI_MODE_0; | ||
502 | |||
503 | r = spi_setup(spi); | ||
504 | if (r < 0) { | ||
505 | dev_err(&spi->dev, "spi_setup failed: %d\n", r); | ||
506 | return r; | ||
507 | } | ||
508 | |||
509 | ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL); | ||
510 | if (ddata == NULL) | ||
511 | return -ENOMEM; | ||
512 | |||
513 | dev_set_drvdata(&spi->dev, ddata); | ||
514 | |||
515 | ddata->spi = spi; | ||
516 | |||
517 | if (dev_get_platdata(&spi->dev)) { | ||
518 | r = tpo_td043_probe_pdata(spi); | ||
519 | if (r) | ||
520 | return r; | ||
521 | } else { | ||
522 | return -ENODEV; | ||
523 | } | ||
524 | |||
525 | ddata->mode = TPO_R02_MODE_800x480; | ||
526 | memcpy(ddata->gamma, tpo_td043_def_gamma, sizeof(ddata->gamma)); | ||
527 | |||
528 | ddata->vcc_reg = devm_regulator_get(&spi->dev, "vcc"); | ||
529 | if (IS_ERR(ddata->vcc_reg)) { | ||
530 | dev_err(&spi->dev, "failed to get LCD VCC regulator\n"); | ||
531 | r = PTR_ERR(ddata->vcc_reg); | ||
532 | goto err_regulator; | ||
533 | } | ||
534 | |||
535 | if (gpio_is_valid(ddata->nreset_gpio)) { | ||
536 | r = devm_gpio_request_one(&spi->dev, | ||
537 | ddata->nreset_gpio, GPIOF_OUT_INIT_LOW, | ||
538 | "lcd reset"); | ||
539 | if (r < 0) { | ||
540 | dev_err(&spi->dev, "couldn't request reset GPIO\n"); | ||
541 | goto err_gpio_req; | ||
542 | } | ||
543 | } | ||
544 | |||
545 | r = sysfs_create_group(&spi->dev.kobj, &tpo_td043_attr_group); | ||
546 | if (r) { | ||
547 | dev_err(&spi->dev, "failed to create sysfs files\n"); | ||
548 | goto err_sysfs; | ||
549 | } | ||
550 | |||
551 | ddata->videomode = tpo_td043_timings; | ||
552 | |||
553 | dssdev = &ddata->dssdev; | ||
554 | dssdev->dev = &spi->dev; | ||
555 | dssdev->driver = &tpo_td043_ops; | ||
556 | dssdev->type = OMAP_DISPLAY_TYPE_DPI; | ||
557 | dssdev->owner = THIS_MODULE; | ||
558 | dssdev->panel.timings = ddata->videomode; | ||
559 | |||
560 | r = omapdss_register_display(dssdev); | ||
561 | if (r) { | ||
562 | dev_err(&spi->dev, "Failed to register panel\n"); | ||
563 | goto err_reg; | ||
564 | } | ||
565 | |||
566 | return 0; | ||
567 | |||
568 | err_reg: | ||
569 | sysfs_remove_group(&spi->dev.kobj, &tpo_td043_attr_group); | ||
570 | err_sysfs: | ||
571 | err_gpio_req: | ||
572 | err_regulator: | ||
573 | omap_dss_put_device(ddata->in); | ||
574 | return r; | ||
575 | } | ||
576 | |||
577 | static int tpo_td043_remove(struct spi_device *spi) | ||
578 | { | ||
579 | struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); | ||
580 | struct omap_dss_device *dssdev = &ddata->dssdev; | ||
581 | struct omap_dss_device *in = ddata->in; | ||
582 | |||
583 | dev_dbg(&ddata->spi->dev, "%s\n", __func__); | ||
584 | |||
585 | omapdss_unregister_display(dssdev); | ||
586 | |||
587 | tpo_td043_disable(dssdev); | ||
588 | tpo_td043_disconnect(dssdev); | ||
589 | |||
590 | omap_dss_put_device(in); | ||
591 | |||
592 | sysfs_remove_group(&spi->dev.kobj, &tpo_td043_attr_group); | ||
593 | |||
594 | return 0; | ||
595 | } | ||
596 | |||
597 | #ifdef CONFIG_PM_SLEEP | ||
598 | static int tpo_td043_spi_suspend(struct device *dev) | ||
599 | { | ||
600 | struct panel_drv_data *ddata = dev_get_drvdata(dev); | ||
601 | |||
602 | dev_dbg(dev, "tpo_td043_spi_suspend, tpo %p\n", ddata); | ||
603 | |||
604 | ddata->power_on_resume = ddata->powered_on; | ||
605 | tpo_td043_power_off(ddata); | ||
606 | ddata->spi_suspended = 1; | ||
607 | |||
608 | return 0; | ||
609 | } | ||
610 | |||
611 | static int tpo_td043_spi_resume(struct device *dev) | ||
612 | { | ||
613 | struct panel_drv_data *ddata = dev_get_drvdata(dev); | ||
614 | int ret; | ||
615 | |||
616 | dev_dbg(dev, "tpo_td043_spi_resume\n"); | ||
617 | |||
618 | if (ddata->power_on_resume) { | ||
619 | ret = tpo_td043_power_on(ddata); | ||
620 | if (ret) | ||
621 | return ret; | ||
622 | } | ||
623 | ddata->spi_suspended = 0; | ||
624 | |||
625 | return 0; | ||
626 | } | ||
627 | #endif | ||
628 | |||
629 | static SIMPLE_DEV_PM_OPS(tpo_td043_spi_pm, | ||
630 | tpo_td043_spi_suspend, tpo_td043_spi_resume); | ||
631 | |||
632 | static struct spi_driver tpo_td043_spi_driver = { | ||
633 | .driver = { | ||
634 | .name = "panel-tpo-td043mtea1", | ||
635 | .owner = THIS_MODULE, | ||
636 | .pm = &tpo_td043_spi_pm, | ||
637 | }, | ||
638 | .probe = tpo_td043_probe, | ||
639 | .remove = tpo_td043_remove, | ||
640 | }; | ||
641 | |||
642 | module_spi_driver(tpo_td043_spi_driver); | ||
643 | |||
644 | MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>"); | ||
645 | MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver"); | ||
646 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig index c3853c92279b..e80ac1c79561 100644 --- a/drivers/video/omap2/displays/Kconfig +++ b/drivers/video/omap2/displays/Kconfig | |||
@@ -1,4 +1,4 @@ | |||
1 | menu "OMAP2/3 Display Device Drivers" | 1 | menu "OMAP2/3 Display Device Drivers (old device model)" |
2 | depends on OMAP2_DSS | 2 | depends on OMAP2_DSS |
3 | 3 | ||
4 | config PANEL_GENERIC_DPI | 4 | config PANEL_GENERIC_DPI |
diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c index d7f69c09ecf1..3fd100fc853e 100644 --- a/drivers/video/omap2/displays/panel-acx565akm.c +++ b/drivers/video/omap2/displays/panel-acx565akm.c | |||
@@ -510,7 +510,7 @@ static int acx_panel_probe(struct omap_dss_device *dssdev) | |||
510 | int max_brightness, brightness; | 510 | int max_brightness, brightness; |
511 | struct backlight_properties props; | 511 | struct backlight_properties props; |
512 | 512 | ||
513 | dev_dbg(&dssdev->dev, "%s\n", __func__); | 513 | dev_dbg(dssdev->dev, "%s\n", __func__); |
514 | 514 | ||
515 | if (!panel_data) | 515 | if (!panel_data) |
516 | return -EINVAL; | 516 | return -EINVAL; |
@@ -519,7 +519,7 @@ static int acx_panel_probe(struct omap_dss_device *dssdev) | |||
519 | dssdev->panel.timings = acx_panel_timings; | 519 | dssdev->panel.timings = acx_panel_timings; |
520 | 520 | ||
521 | if (gpio_is_valid(panel_data->reset_gpio)) { | 521 | if (gpio_is_valid(panel_data->reset_gpio)) { |
522 | r = devm_gpio_request_one(&dssdev->dev, panel_data->reset_gpio, | 522 | r = devm_gpio_request_one(dssdev->dev, panel_data->reset_gpio, |
523 | GPIOF_OUT_INIT_LOW, "lcd reset"); | 523 | GPIOF_OUT_INIT_LOW, "lcd reset"); |
524 | if (r) | 524 | if (r) |
525 | return r; | 525 | return r; |
@@ -538,7 +538,7 @@ static int acx_panel_probe(struct omap_dss_device *dssdev) | |||
538 | 538 | ||
539 | r = panel_detect(md); | 539 | r = panel_detect(md); |
540 | if (r) { | 540 | if (r) { |
541 | dev_err(&dssdev->dev, "%s panel detect error\n", __func__); | 541 | dev_err(dssdev->dev, "%s panel detect error\n", __func__); |
542 | if (!md->enabled && gpio_is_valid(panel_data->reset_gpio)) | 542 | if (!md->enabled && gpio_is_valid(panel_data->reset_gpio)) |
543 | gpio_set_value(panel_data->reset_gpio, 0); | 543 | gpio_set_value(panel_data->reset_gpio, 0); |
544 | 544 | ||
@@ -593,7 +593,7 @@ static void acx_panel_remove(struct omap_dss_device *dssdev) | |||
593 | { | 593 | { |
594 | struct acx565akm_device *md = &acx_dev; | 594 | struct acx565akm_device *md = &acx_dev; |
595 | 595 | ||
596 | dev_dbg(&dssdev->dev, "%s\n", __func__); | 596 | dev_dbg(dssdev->dev, "%s\n", __func__); |
597 | sysfs_remove_group(&md->bl_dev->dev.kobj, &bldev_attr_group); | 597 | sysfs_remove_group(&md->bl_dev->dev.kobj, &bldev_attr_group); |
598 | backlight_device_unregister(md->bl_dev); | 598 | backlight_device_unregister(md->bl_dev); |
599 | mutex_lock(&acx_dev.mutex); | 599 | mutex_lock(&acx_dev.mutex); |
@@ -607,7 +607,7 @@ static int acx_panel_power_on(struct omap_dss_device *dssdev) | |||
607 | struct panel_acx565akm_data *panel_data = get_panel_data(dssdev); | 607 | struct panel_acx565akm_data *panel_data = get_panel_data(dssdev); |
608 | int r; | 608 | int r; |
609 | 609 | ||
610 | dev_dbg(&dssdev->dev, "%s\n", __func__); | 610 | dev_dbg(dssdev->dev, "%s\n", __func__); |
611 | 611 | ||
612 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | 612 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) |
613 | return 0; | 613 | return 0; |
@@ -667,7 +667,7 @@ static void acx_panel_power_off(struct omap_dss_device *dssdev) | |||
667 | struct acx565akm_device *md = &acx_dev; | 667 | struct acx565akm_device *md = &acx_dev; |
668 | struct panel_acx565akm_data *panel_data = get_panel_data(dssdev); | 668 | struct panel_acx565akm_data *panel_data = get_panel_data(dssdev); |
669 | 669 | ||
670 | dev_dbg(&dssdev->dev, "%s\n", __func__); | 670 | dev_dbg(dssdev->dev, "%s\n", __func__); |
671 | 671 | ||
672 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | 672 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) |
673 | return; | 673 | return; |
@@ -704,7 +704,7 @@ static int acx_panel_enable(struct omap_dss_device *dssdev) | |||
704 | { | 704 | { |
705 | int r; | 705 | int r; |
706 | 706 | ||
707 | dev_dbg(&dssdev->dev, "%s\n", __func__); | 707 | dev_dbg(dssdev->dev, "%s\n", __func__); |
708 | r = acx_panel_power_on(dssdev); | 708 | r = acx_panel_power_on(dssdev); |
709 | 709 | ||
710 | if (r) | 710 | if (r) |
@@ -716,7 +716,7 @@ static int acx_panel_enable(struct omap_dss_device *dssdev) | |||
716 | 716 | ||
717 | static void acx_panel_disable(struct omap_dss_device *dssdev) | 717 | static void acx_panel_disable(struct omap_dss_device *dssdev) |
718 | { | 718 | { |
719 | dev_dbg(&dssdev->dev, "%s\n", __func__); | 719 | dev_dbg(dssdev->dev, "%s\n", __func__); |
720 | acx_panel_power_off(dssdev); | 720 | acx_panel_power_off(dssdev); |
721 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | 721 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; |
722 | } | 722 | } |
diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c index 97363f733683..bebebd45847f 100644 --- a/drivers/video/omap2/displays/panel-generic-dpi.c +++ b/drivers/video/omap2/displays/panel-generic-dpi.c | |||
@@ -536,7 +536,7 @@ static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev) | |||
536 | { | 536 | { |
537 | int r, i; | 537 | int r, i; |
538 | struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); | 538 | struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); |
539 | struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); | 539 | struct panel_drv_data *drv_data = dev_get_drvdata(dssdev->dev); |
540 | struct panel_config *panel_config = drv_data->panel_config; | 540 | struct panel_config *panel_config = drv_data->panel_config; |
541 | 541 | ||
542 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | 542 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) |
@@ -567,7 +567,7 @@ err0: | |||
567 | static void generic_dpi_panel_power_off(struct omap_dss_device *dssdev) | 567 | static void generic_dpi_panel_power_off(struct omap_dss_device *dssdev) |
568 | { | 568 | { |
569 | struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); | 569 | struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); |
570 | struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); | 570 | struct panel_drv_data *drv_data = dev_get_drvdata(dssdev->dev); |
571 | struct panel_config *panel_config = drv_data->panel_config; | 571 | struct panel_config *panel_config = drv_data->panel_config; |
572 | int i; | 572 | int i; |
573 | 573 | ||
@@ -593,7 +593,7 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev) | |||
593 | struct panel_drv_data *drv_data = NULL; | 593 | struct panel_drv_data *drv_data = NULL; |
594 | int i, r; | 594 | int i, r; |
595 | 595 | ||
596 | dev_dbg(&dssdev->dev, "probe\n"); | 596 | dev_dbg(dssdev->dev, "probe\n"); |
597 | 597 | ||
598 | if (!panel_data || !panel_data->name) | 598 | if (!panel_data || !panel_data->name) |
599 | return -EINVAL; | 599 | return -EINVAL; |
@@ -609,7 +609,7 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev) | |||
609 | return -EINVAL; | 609 | return -EINVAL; |
610 | 610 | ||
611 | for (i = 0; i < panel_data->num_gpios; ++i) { | 611 | for (i = 0; i < panel_data->num_gpios; ++i) { |
612 | r = devm_gpio_request_one(&dssdev->dev, panel_data->gpios[i], | 612 | r = devm_gpio_request_one(dssdev->dev, panel_data->gpios[i], |
613 | panel_data->gpio_invert[i] ? | 613 | panel_data->gpio_invert[i] ? |
614 | GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, | 614 | GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, |
615 | "panel gpio"); | 615 | "panel gpio"); |
@@ -619,7 +619,7 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev) | |||
619 | 619 | ||
620 | dssdev->panel.timings = panel_config->timings; | 620 | dssdev->panel.timings = panel_config->timings; |
621 | 621 | ||
622 | drv_data = devm_kzalloc(&dssdev->dev, sizeof(*drv_data), GFP_KERNEL); | 622 | drv_data = devm_kzalloc(dssdev->dev, sizeof(*drv_data), GFP_KERNEL); |
623 | if (!drv_data) | 623 | if (!drv_data) |
624 | return -ENOMEM; | 624 | return -ENOMEM; |
625 | 625 | ||
@@ -628,21 +628,21 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev) | |||
628 | 628 | ||
629 | mutex_init(&drv_data->lock); | 629 | mutex_init(&drv_data->lock); |
630 | 630 | ||
631 | dev_set_drvdata(&dssdev->dev, drv_data); | 631 | dev_set_drvdata(dssdev->dev, drv_data); |
632 | 632 | ||
633 | return 0; | 633 | return 0; |
634 | } | 634 | } |
635 | 635 | ||
636 | static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev) | 636 | static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev) |
637 | { | 637 | { |
638 | dev_dbg(&dssdev->dev, "remove\n"); | 638 | dev_dbg(dssdev->dev, "remove\n"); |
639 | 639 | ||
640 | dev_set_drvdata(&dssdev->dev, NULL); | 640 | dev_set_drvdata(dssdev->dev, NULL); |
641 | } | 641 | } |
642 | 642 | ||
643 | static int generic_dpi_panel_enable(struct omap_dss_device *dssdev) | 643 | static int generic_dpi_panel_enable(struct omap_dss_device *dssdev) |
644 | { | 644 | { |
645 | struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); | 645 | struct panel_drv_data *drv_data = dev_get_drvdata(dssdev->dev); |
646 | int r; | 646 | int r; |
647 | 647 | ||
648 | mutex_lock(&drv_data->lock); | 648 | mutex_lock(&drv_data->lock); |
@@ -660,7 +660,7 @@ err: | |||
660 | 660 | ||
661 | static void generic_dpi_panel_disable(struct omap_dss_device *dssdev) | 661 | static void generic_dpi_panel_disable(struct omap_dss_device *dssdev) |
662 | { | 662 | { |
663 | struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); | 663 | struct panel_drv_data *drv_data = dev_get_drvdata(dssdev->dev); |
664 | 664 | ||
665 | mutex_lock(&drv_data->lock); | 665 | mutex_lock(&drv_data->lock); |
666 | 666 | ||
@@ -674,7 +674,7 @@ static void generic_dpi_panel_disable(struct omap_dss_device *dssdev) | |||
674 | static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev, | 674 | static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev, |
675 | struct omap_video_timings *timings) | 675 | struct omap_video_timings *timings) |
676 | { | 676 | { |
677 | struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); | 677 | struct panel_drv_data *drv_data = dev_get_drvdata(dssdev->dev); |
678 | 678 | ||
679 | mutex_lock(&drv_data->lock); | 679 | mutex_lock(&drv_data->lock); |
680 | 680 | ||
@@ -688,7 +688,7 @@ static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev, | |||
688 | static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev, | 688 | static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev, |
689 | struct omap_video_timings *timings) | 689 | struct omap_video_timings *timings) |
690 | { | 690 | { |
691 | struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); | 691 | struct panel_drv_data *drv_data = dev_get_drvdata(dssdev->dev); |
692 | 692 | ||
693 | mutex_lock(&drv_data->lock); | 693 | mutex_lock(&drv_data->lock); |
694 | 694 | ||
@@ -700,7 +700,7 @@ static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev, | |||
700 | static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev, | 700 | static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev, |
701 | struct omap_video_timings *timings) | 701 | struct omap_video_timings *timings) |
702 | { | 702 | { |
703 | struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); | 703 | struct panel_drv_data *drv_data = dev_get_drvdata(dssdev->dev); |
704 | int r; | 704 | int r; |
705 | 705 | ||
706 | mutex_lock(&drv_data->lock); | 706 | mutex_lock(&drv_data->lock); |
diff --git a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c index 4ea6548c0ae9..6c51430ddb37 100644 --- a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c +++ b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c | |||
@@ -109,12 +109,12 @@ static int lb035q02_panel_probe(struct omap_dss_device *dssdev) | |||
109 | 109 | ||
110 | dssdev->panel.timings = lb035q02_timings; | 110 | dssdev->panel.timings = lb035q02_timings; |
111 | 111 | ||
112 | ld = devm_kzalloc(&dssdev->dev, sizeof(*ld), GFP_KERNEL); | 112 | ld = devm_kzalloc(dssdev->dev, sizeof(*ld), GFP_KERNEL); |
113 | if (!ld) | 113 | if (!ld) |
114 | return -ENOMEM; | 114 | return -ENOMEM; |
115 | 115 | ||
116 | for (i = 0; i < panel_data->num_gpios; ++i) { | 116 | for (i = 0; i < panel_data->num_gpios; ++i) { |
117 | r = devm_gpio_request_one(&dssdev->dev, panel_data->gpios[i], | 117 | r = devm_gpio_request_one(dssdev->dev, panel_data->gpios[i], |
118 | panel_data->gpio_invert[i] ? | 118 | panel_data->gpio_invert[i] ? |
119 | GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, | 119 | GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, |
120 | "panel gpio"); | 120 | "panel gpio"); |
@@ -123,7 +123,7 @@ static int lb035q02_panel_probe(struct omap_dss_device *dssdev) | |||
123 | } | 123 | } |
124 | 124 | ||
125 | mutex_init(&ld->lock); | 125 | mutex_init(&ld->lock); |
126 | dev_set_drvdata(&dssdev->dev, ld); | 126 | dev_set_drvdata(dssdev->dev, ld); |
127 | 127 | ||
128 | return 0; | 128 | return 0; |
129 | } | 129 | } |
@@ -134,7 +134,7 @@ static void lb035q02_panel_remove(struct omap_dss_device *dssdev) | |||
134 | 134 | ||
135 | static int lb035q02_panel_enable(struct omap_dss_device *dssdev) | 135 | static int lb035q02_panel_enable(struct omap_dss_device *dssdev) |
136 | { | 136 | { |
137 | struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev); | 137 | struct lb035q02_data *ld = dev_get_drvdata(dssdev->dev); |
138 | int r; | 138 | int r; |
139 | 139 | ||
140 | mutex_lock(&ld->lock); | 140 | mutex_lock(&ld->lock); |
@@ -153,7 +153,7 @@ err: | |||
153 | 153 | ||
154 | static void lb035q02_panel_disable(struct omap_dss_device *dssdev) | 154 | static void lb035q02_panel_disable(struct omap_dss_device *dssdev) |
155 | { | 155 | { |
156 | struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev); | 156 | struct lb035q02_data *ld = dev_get_drvdata(dssdev->dev); |
157 | 157 | ||
158 | mutex_lock(&ld->lock); | 158 | mutex_lock(&ld->lock); |
159 | 159 | ||
diff --git a/drivers/video/omap2/displays/panel-n8x0.c b/drivers/video/omap2/displays/panel-n8x0.c index 860b18014ad7..1d525fc84db9 100644 --- a/drivers/video/omap2/displays/panel-n8x0.c +++ b/drivers/video/omap2/displays/panel-n8x0.c | |||
@@ -311,16 +311,16 @@ static int n8x0_panel_power_on(struct omap_dss_device *dssdev) | |||
311 | switch (rev & 0xfc) { | 311 | switch (rev & 0xfc) { |
312 | case 0x9c: | 312 | case 0x9c: |
313 | ddata->blizzard_ver = BLIZZARD_VERSION_S1D13744; | 313 | ddata->blizzard_ver = BLIZZARD_VERSION_S1D13744; |
314 | dev_info(&dssdev->dev, "s1d13744 LCD controller rev %d " | 314 | dev_info(dssdev->dev, "s1d13744 LCD controller rev %d " |
315 | "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07); | 315 | "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07); |
316 | break; | 316 | break; |
317 | case 0xa4: | 317 | case 0xa4: |
318 | ddata->blizzard_ver = BLIZZARD_VERSION_S1D13745; | 318 | ddata->blizzard_ver = BLIZZARD_VERSION_S1D13745; |
319 | dev_info(&dssdev->dev, "s1d13745 LCD controller rev %d " | 319 | dev_info(dssdev->dev, "s1d13745 LCD controller rev %d " |
320 | "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07); | 320 | "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07); |
321 | break; | 321 | break; |
322 | default: | 322 | default: |
323 | dev_err(&dssdev->dev, "invalid s1d1374x revision %02x\n", rev); | 323 | dev_err(dssdev->dev, "invalid s1d1374x revision %02x\n", rev); |
324 | r = -ENODEV; | 324 | r = -ENODEV; |
325 | goto err_inv_chip; | 325 | goto err_inv_chip; |
326 | } | 326 | } |
@@ -341,13 +341,13 @@ static int n8x0_panel_power_on(struct omap_dss_device *dssdev) | |||
341 | panel_name = "ls041y3"; | 341 | panel_name = "ls041y3"; |
342 | break; | 342 | break; |
343 | default: | 343 | default: |
344 | dev_err(&dssdev->dev, "invalid display ID 0x%x\n", | 344 | dev_err(dssdev->dev, "invalid display ID 0x%x\n", |
345 | display_id[0]); | 345 | display_id[0]); |
346 | r = -ENODEV; | 346 | r = -ENODEV; |
347 | goto err_inv_panel; | 347 | goto err_inv_panel; |
348 | } | 348 | } |
349 | 349 | ||
350 | dev_info(&dssdev->dev, "%s rev %02x LCD detected\n", | 350 | dev_info(dssdev->dev, "%s rev %02x LCD detected\n", |
351 | panel_name, display_id[1]); | 351 | panel_name, display_id[1]); |
352 | 352 | ||
353 | send_sleep_out(spi); | 353 | send_sleep_out(spi); |
@@ -416,7 +416,7 @@ static int n8x0_panel_probe(struct omap_dss_device *dssdev) | |||
416 | struct panel_drv_data *ddata; | 416 | struct panel_drv_data *ddata; |
417 | int r; | 417 | int r; |
418 | 418 | ||
419 | dev_dbg(&dssdev->dev, "probe\n"); | 419 | dev_dbg(dssdev->dev, "probe\n"); |
420 | 420 | ||
421 | if (!bdata) | 421 | if (!bdata) |
422 | return -EINVAL; | 422 | return -EINVAL; |
@@ -434,14 +434,14 @@ static int n8x0_panel_probe(struct omap_dss_device *dssdev) | |||
434 | dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; | 434 | dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; |
435 | 435 | ||
436 | if (gpio_is_valid(bdata->panel_reset)) { | 436 | if (gpio_is_valid(bdata->panel_reset)) { |
437 | r = devm_gpio_request_one(&dssdev->dev, bdata->panel_reset, | 437 | r = devm_gpio_request_one(dssdev->dev, bdata->panel_reset, |
438 | GPIOF_OUT_INIT_LOW, "PANEL RESET"); | 438 | GPIOF_OUT_INIT_LOW, "PANEL RESET"); |
439 | if (r) | 439 | if (r) |
440 | return r; | 440 | return r; |
441 | } | 441 | } |
442 | 442 | ||
443 | if (gpio_is_valid(bdata->ctrl_pwrdown)) { | 443 | if (gpio_is_valid(bdata->ctrl_pwrdown)) { |
444 | r = devm_gpio_request_one(&dssdev->dev, bdata->ctrl_pwrdown, | 444 | r = devm_gpio_request_one(dssdev->dev, bdata->ctrl_pwrdown, |
445 | GPIOF_OUT_INIT_LOW, "PANEL PWRDOWN"); | 445 | GPIOF_OUT_INIT_LOW, "PANEL PWRDOWN"); |
446 | if (r) | 446 | if (r) |
447 | return r; | 447 | return r; |
@@ -452,9 +452,9 @@ static int n8x0_panel_probe(struct omap_dss_device *dssdev) | |||
452 | 452 | ||
453 | static void n8x0_panel_remove(struct omap_dss_device *dssdev) | 453 | static void n8x0_panel_remove(struct omap_dss_device *dssdev) |
454 | { | 454 | { |
455 | dev_dbg(&dssdev->dev, "remove\n"); | 455 | dev_dbg(dssdev->dev, "remove\n"); |
456 | 456 | ||
457 | dev_set_drvdata(&dssdev->dev, NULL); | 457 | dev_set_drvdata(dssdev->dev, NULL); |
458 | } | 458 | } |
459 | 459 | ||
460 | static int n8x0_panel_enable(struct omap_dss_device *dssdev) | 460 | static int n8x0_panel_enable(struct omap_dss_device *dssdev) |
@@ -462,7 +462,7 @@ static int n8x0_panel_enable(struct omap_dss_device *dssdev) | |||
462 | struct panel_drv_data *ddata = get_drv_data(dssdev); | 462 | struct panel_drv_data *ddata = get_drv_data(dssdev); |
463 | int r; | 463 | int r; |
464 | 464 | ||
465 | dev_dbg(&dssdev->dev, "enable\n"); | 465 | dev_dbg(dssdev->dev, "enable\n"); |
466 | 466 | ||
467 | mutex_lock(&ddata->lock); | 467 | mutex_lock(&ddata->lock); |
468 | 468 | ||
@@ -488,7 +488,7 @@ static void n8x0_panel_disable(struct omap_dss_device *dssdev) | |||
488 | { | 488 | { |
489 | struct panel_drv_data *ddata = get_drv_data(dssdev); | 489 | struct panel_drv_data *ddata = get_drv_data(dssdev); |
490 | 490 | ||
491 | dev_dbg(&dssdev->dev, "disable\n"); | 491 | dev_dbg(dssdev->dev, "disable\n"); |
492 | 492 | ||
493 | mutex_lock(&ddata->lock); | 493 | mutex_lock(&ddata->lock); |
494 | 494 | ||
@@ -521,13 +521,13 @@ static int n8x0_panel_update(struct omap_dss_device *dssdev, | |||
521 | struct panel_drv_data *ddata = get_drv_data(dssdev); | 521 | struct panel_drv_data *ddata = get_drv_data(dssdev); |
522 | u16 dw, dh; | 522 | u16 dw, dh; |
523 | 523 | ||
524 | dev_dbg(&dssdev->dev, "update\n"); | 524 | dev_dbg(dssdev->dev, "update\n"); |
525 | 525 | ||
526 | dw = dssdev->panel.timings.x_res; | 526 | dw = dssdev->panel.timings.x_res; |
527 | dh = dssdev->panel.timings.y_res; | 527 | dh = dssdev->panel.timings.y_res; |
528 | 528 | ||
529 | if (x != 0 || y != 0 || w != dw || h != dh) { | 529 | if (x != 0 || y != 0 || w != dw || h != dh) { |
530 | dev_err(&dssdev->dev, "invalid update region %d, %d, %d, %d\n", | 530 | dev_err(dssdev->dev, "invalid update region %d, %d, %d, %d\n", |
531 | x, y, w, h); | 531 | x, y, w, h); |
532 | return -EINVAL; | 532 | return -EINVAL; |
533 | } | 533 | } |
@@ -548,7 +548,7 @@ static int n8x0_panel_sync(struct omap_dss_device *dssdev) | |||
548 | { | 548 | { |
549 | struct panel_drv_data *ddata = get_drv_data(dssdev); | 549 | struct panel_drv_data *ddata = get_drv_data(dssdev); |
550 | 550 | ||
551 | dev_dbg(&dssdev->dev, "sync\n"); | 551 | dev_dbg(dssdev->dev, "sync\n"); |
552 | 552 | ||
553 | mutex_lock(&ddata->lock); | 553 | mutex_lock(&ddata->lock); |
554 | rfbi_bus_lock(); | 554 | rfbi_bus_lock(); |
diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c index 20c3cd91ff9b..6b9f7925e918 100644 --- a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c +++ b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c | |||
@@ -98,14 +98,14 @@ static int nec_8048_panel_probe(struct omap_dss_device *dssdev) | |||
98 | dssdev->panel.timings = nec_8048_panel_timings; | 98 | dssdev->panel.timings = nec_8048_panel_timings; |
99 | 99 | ||
100 | if (gpio_is_valid(pd->qvga_gpio)) { | 100 | if (gpio_is_valid(pd->qvga_gpio)) { |
101 | r = devm_gpio_request_one(&dssdev->dev, pd->qvga_gpio, | 101 | r = devm_gpio_request_one(dssdev->dev, pd->qvga_gpio, |
102 | GPIOF_OUT_INIT_HIGH, "lcd QVGA"); | 102 | GPIOF_OUT_INIT_HIGH, "lcd QVGA"); |
103 | if (r) | 103 | if (r) |
104 | return r; | 104 | return r; |
105 | } | 105 | } |
106 | 106 | ||
107 | if (gpio_is_valid(pd->res_gpio)) { | 107 | if (gpio_is_valid(pd->res_gpio)) { |
108 | r = devm_gpio_request_one(&dssdev->dev, pd->res_gpio, | 108 | r = devm_gpio_request_one(dssdev->dev, pd->res_gpio, |
109 | GPIOF_OUT_INIT_LOW, "lcd RES"); | 109 | GPIOF_OUT_INIT_LOW, "lcd RES"); |
110 | if (r) | 110 | if (r) |
111 | return r; | 111 | return r; |
diff --git a/drivers/video/omap2/displays/panel-picodlp.c b/drivers/video/omap2/displays/panel-picodlp.c index 62f2db04fbc8..153e9bea0f6e 100644 --- a/drivers/video/omap2/displays/panel-picodlp.c +++ b/drivers/video/omap2/displays/panel-picodlp.c | |||
@@ -351,7 +351,7 @@ static struct i2c_driver picodlp_i2c_driver = { | |||
351 | static int picodlp_panel_power_on(struct omap_dss_device *dssdev) | 351 | static int picodlp_panel_power_on(struct omap_dss_device *dssdev) |
352 | { | 352 | { |
353 | int r, trial = 100; | 353 | int r, trial = 100; |
354 | struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); | 354 | struct picodlp_data *picod = dev_get_drvdata(dssdev->dev); |
355 | struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev); | 355 | struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev); |
356 | 356 | ||
357 | gpio_set_value(picodlp_pdata->pwrgood_gpio, 0); | 357 | gpio_set_value(picodlp_pdata->pwrgood_gpio, 0); |
@@ -360,7 +360,7 @@ static int picodlp_panel_power_on(struct omap_dss_device *dssdev) | |||
360 | 360 | ||
361 | while (!gpio_get_value(picodlp_pdata->emu_done_gpio)) { | 361 | while (!gpio_get_value(picodlp_pdata->emu_done_gpio)) { |
362 | if (!trial--) { | 362 | if (!trial--) { |
363 | dev_err(&dssdev->dev, "emu_done signal not" | 363 | dev_err(dssdev->dev, "emu_done signal not" |
364 | " going high\n"); | 364 | " going high\n"); |
365 | return -ETIMEDOUT; | 365 | return -ETIMEDOUT; |
366 | } | 366 | } |
@@ -378,7 +378,7 @@ static int picodlp_panel_power_on(struct omap_dss_device *dssdev) | |||
378 | 378 | ||
379 | r = omapdss_dpi_display_enable(dssdev); | 379 | r = omapdss_dpi_display_enable(dssdev); |
380 | if (r) { | 380 | if (r) { |
381 | dev_err(&dssdev->dev, "failed to enable DPI\n"); | 381 | dev_err(dssdev->dev, "failed to enable DPI\n"); |
382 | goto err1; | 382 | goto err1; |
383 | } | 383 | } |
384 | 384 | ||
@@ -418,7 +418,7 @@ static int picodlp_panel_probe(struct omap_dss_device *dssdev) | |||
418 | if (!picodlp_pdata) | 418 | if (!picodlp_pdata) |
419 | return -EINVAL; | 419 | return -EINVAL; |
420 | 420 | ||
421 | picod = devm_kzalloc(&dssdev->dev, sizeof(*picod), GFP_KERNEL); | 421 | picod = devm_kzalloc(dssdev->dev, sizeof(*picod), GFP_KERNEL); |
422 | if (!picod) | 422 | if (!picod) |
423 | return -ENOMEM; | 423 | return -ENOMEM; |
424 | 424 | ||
@@ -428,23 +428,23 @@ static int picodlp_panel_probe(struct omap_dss_device *dssdev) | |||
428 | 428 | ||
429 | adapter = i2c_get_adapter(picodlp_adapter_id); | 429 | adapter = i2c_get_adapter(picodlp_adapter_id); |
430 | if (!adapter) { | 430 | if (!adapter) { |
431 | dev_err(&dssdev->dev, "can't get i2c adapter\n"); | 431 | dev_err(dssdev->dev, "can't get i2c adapter\n"); |
432 | return -ENODEV; | 432 | return -ENODEV; |
433 | } | 433 | } |
434 | 434 | ||
435 | picodlp_i2c_client = i2c_new_device(adapter, &picodlp_i2c_board_info); | 435 | picodlp_i2c_client = i2c_new_device(adapter, &picodlp_i2c_board_info); |
436 | if (!picodlp_i2c_client) { | 436 | if (!picodlp_i2c_client) { |
437 | dev_err(&dssdev->dev, "can't add i2c device::" | 437 | dev_err(dssdev->dev, "can't add i2c device::" |
438 | " picodlp_i2c_client is NULL\n"); | 438 | " picodlp_i2c_client is NULL\n"); |
439 | return -ENODEV; | 439 | return -ENODEV; |
440 | } | 440 | } |
441 | 441 | ||
442 | picod->picodlp_i2c_client = picodlp_i2c_client; | 442 | picod->picodlp_i2c_client = picodlp_i2c_client; |
443 | 443 | ||
444 | dev_set_drvdata(&dssdev->dev, picod); | 444 | dev_set_drvdata(dssdev->dev, picod); |
445 | 445 | ||
446 | if (gpio_is_valid(picodlp_pdata->emu_done_gpio)) { | 446 | if (gpio_is_valid(picodlp_pdata->emu_done_gpio)) { |
447 | r = devm_gpio_request_one(&dssdev->dev, | 447 | r = devm_gpio_request_one(dssdev->dev, |
448 | picodlp_pdata->emu_done_gpio, | 448 | picodlp_pdata->emu_done_gpio, |
449 | GPIOF_IN, "DLP EMU DONE"); | 449 | GPIOF_IN, "DLP EMU DONE"); |
450 | if (r) | 450 | if (r) |
@@ -452,7 +452,7 @@ static int picodlp_panel_probe(struct omap_dss_device *dssdev) | |||
452 | } | 452 | } |
453 | 453 | ||
454 | if (gpio_is_valid(picodlp_pdata->pwrgood_gpio)) { | 454 | if (gpio_is_valid(picodlp_pdata->pwrgood_gpio)) { |
455 | r = devm_gpio_request_one(&dssdev->dev, | 455 | r = devm_gpio_request_one(dssdev->dev, |
456 | picodlp_pdata->pwrgood_gpio, | 456 | picodlp_pdata->pwrgood_gpio, |
457 | GPIOF_OUT_INIT_LOW, "DLP PWRGOOD"); | 457 | GPIOF_OUT_INIT_LOW, "DLP PWRGOOD"); |
458 | if (r) | 458 | if (r) |
@@ -464,21 +464,19 @@ static int picodlp_panel_probe(struct omap_dss_device *dssdev) | |||
464 | 464 | ||
465 | static void picodlp_panel_remove(struct omap_dss_device *dssdev) | 465 | static void picodlp_panel_remove(struct omap_dss_device *dssdev) |
466 | { | 466 | { |
467 | struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); | 467 | struct picodlp_data *picod = dev_get_drvdata(dssdev->dev); |
468 | 468 | ||
469 | i2c_unregister_device(picod->picodlp_i2c_client); | 469 | i2c_unregister_device(picod->picodlp_i2c_client); |
470 | dev_set_drvdata(&dssdev->dev, NULL); | 470 | dev_set_drvdata(dssdev->dev, NULL); |
471 | dev_dbg(&dssdev->dev, "removing picodlp panel\n"); | 471 | dev_dbg(dssdev->dev, "removing picodlp panel\n"); |
472 | |||
473 | kfree(picod); | ||
474 | } | 472 | } |
475 | 473 | ||
476 | static int picodlp_panel_enable(struct omap_dss_device *dssdev) | 474 | static int picodlp_panel_enable(struct omap_dss_device *dssdev) |
477 | { | 475 | { |
478 | struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); | 476 | struct picodlp_data *picod = dev_get_drvdata(dssdev->dev); |
479 | int r; | 477 | int r; |
480 | 478 | ||
481 | dev_dbg(&dssdev->dev, "enabling picodlp panel\n"); | 479 | dev_dbg(dssdev->dev, "enabling picodlp panel\n"); |
482 | 480 | ||
483 | mutex_lock(&picod->lock); | 481 | mutex_lock(&picod->lock); |
484 | if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { | 482 | if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { |
@@ -494,7 +492,7 @@ static int picodlp_panel_enable(struct omap_dss_device *dssdev) | |||
494 | 492 | ||
495 | static void picodlp_panel_disable(struct omap_dss_device *dssdev) | 493 | static void picodlp_panel_disable(struct omap_dss_device *dssdev) |
496 | { | 494 | { |
497 | struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); | 495 | struct picodlp_data *picod = dev_get_drvdata(dssdev->dev); |
498 | 496 | ||
499 | mutex_lock(&picod->lock); | 497 | mutex_lock(&picod->lock); |
500 | /* Turn off DLP Power */ | 498 | /* Turn off DLP Power */ |
@@ -504,7 +502,7 @@ static void picodlp_panel_disable(struct omap_dss_device *dssdev) | |||
504 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | 502 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; |
505 | mutex_unlock(&picod->lock); | 503 | mutex_unlock(&picod->lock); |
506 | 504 | ||
507 | dev_dbg(&dssdev->dev, "disabling picodlp panel\n"); | 505 | dev_dbg(dssdev->dev, "disabling picodlp panel\n"); |
508 | } | 506 | } |
509 | 507 | ||
510 | static void picodlp_get_resolution(struct omap_dss_device *dssdev, | 508 | static void picodlp_get_resolution(struct omap_dss_device *dssdev, |
diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c index 74cb0eb45311..78f0a6779756 100644 --- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c +++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c | |||
@@ -66,35 +66,35 @@ static int sharp_ls_panel_probe(struct omap_dss_device *dssdev) | |||
66 | dssdev->panel.timings = sharp_ls_timings; | 66 | dssdev->panel.timings = sharp_ls_timings; |
67 | 67 | ||
68 | if (gpio_is_valid(pd->mo_gpio)) { | 68 | if (gpio_is_valid(pd->mo_gpio)) { |
69 | r = devm_gpio_request_one(&dssdev->dev, pd->mo_gpio, | 69 | r = devm_gpio_request_one(dssdev->dev, pd->mo_gpio, |
70 | GPIOF_OUT_INIT_LOW, "lcd MO"); | 70 | GPIOF_OUT_INIT_LOW, "lcd MO"); |
71 | if (r) | 71 | if (r) |
72 | return r; | 72 | return r; |
73 | } | 73 | } |
74 | 74 | ||
75 | if (gpio_is_valid(pd->lr_gpio)) { | 75 | if (gpio_is_valid(pd->lr_gpio)) { |
76 | r = devm_gpio_request_one(&dssdev->dev, pd->lr_gpio, | 76 | r = devm_gpio_request_one(dssdev->dev, pd->lr_gpio, |
77 | GPIOF_OUT_INIT_HIGH, "lcd LR"); | 77 | GPIOF_OUT_INIT_HIGH, "lcd LR"); |
78 | if (r) | 78 | if (r) |
79 | return r; | 79 | return r; |
80 | } | 80 | } |
81 | 81 | ||
82 | if (gpio_is_valid(pd->ud_gpio)) { | 82 | if (gpio_is_valid(pd->ud_gpio)) { |
83 | r = devm_gpio_request_one(&dssdev->dev, pd->ud_gpio, | 83 | r = devm_gpio_request_one(dssdev->dev, pd->ud_gpio, |
84 | GPIOF_OUT_INIT_HIGH, "lcd UD"); | 84 | GPIOF_OUT_INIT_HIGH, "lcd UD"); |
85 | if (r) | 85 | if (r) |
86 | return r; | 86 | return r; |
87 | } | 87 | } |
88 | 88 | ||
89 | if (gpio_is_valid(pd->resb_gpio)) { | 89 | if (gpio_is_valid(pd->resb_gpio)) { |
90 | r = devm_gpio_request_one(&dssdev->dev, pd->resb_gpio, | 90 | r = devm_gpio_request_one(dssdev->dev, pd->resb_gpio, |
91 | GPIOF_OUT_INIT_LOW, "lcd RESB"); | 91 | GPIOF_OUT_INIT_LOW, "lcd RESB"); |
92 | if (r) | 92 | if (r) |
93 | return r; | 93 | return r; |
94 | } | 94 | } |
95 | 95 | ||
96 | if (gpio_is_valid(pd->ini_gpio)) { | 96 | if (gpio_is_valid(pd->ini_gpio)) { |
97 | r = devm_gpio_request_one(&dssdev->dev, pd->ini_gpio, | 97 | r = devm_gpio_request_one(dssdev->dev, pd->ini_gpio, |
98 | GPIOF_OUT_INIT_LOW, "lcd INI"); | 98 | GPIOF_OUT_INIT_LOW, "lcd INI"); |
99 | if (r) | 99 | if (r) |
100 | return r; | 100 | return r; |
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index c4f78bda115a..54a07da8587a 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c | |||
@@ -237,7 +237,7 @@ static int taal_set_update_window(struct taal_data *td, | |||
237 | 237 | ||
238 | static void taal_queue_esd_work(struct omap_dss_device *dssdev) | 238 | static void taal_queue_esd_work(struct omap_dss_device *dssdev) |
239 | { | 239 | { |
240 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 240 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
241 | 241 | ||
242 | if (td->esd_interval > 0) | 242 | if (td->esd_interval > 0) |
243 | queue_delayed_work(td->workqueue, &td->esd_work, | 243 | queue_delayed_work(td->workqueue, &td->esd_work, |
@@ -246,14 +246,14 @@ static void taal_queue_esd_work(struct omap_dss_device *dssdev) | |||
246 | 246 | ||
247 | static void taal_cancel_esd_work(struct omap_dss_device *dssdev) | 247 | static void taal_cancel_esd_work(struct omap_dss_device *dssdev) |
248 | { | 248 | { |
249 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 249 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
250 | 250 | ||
251 | cancel_delayed_work(&td->esd_work); | 251 | cancel_delayed_work(&td->esd_work); |
252 | } | 252 | } |
253 | 253 | ||
254 | static void taal_queue_ulps_work(struct omap_dss_device *dssdev) | 254 | static void taal_queue_ulps_work(struct omap_dss_device *dssdev) |
255 | { | 255 | { |
256 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 256 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
257 | 257 | ||
258 | if (td->ulps_timeout > 0) | 258 | if (td->ulps_timeout > 0) |
259 | queue_delayed_work(td->workqueue, &td->ulps_work, | 259 | queue_delayed_work(td->workqueue, &td->ulps_work, |
@@ -262,14 +262,14 @@ static void taal_queue_ulps_work(struct omap_dss_device *dssdev) | |||
262 | 262 | ||
263 | static void taal_cancel_ulps_work(struct omap_dss_device *dssdev) | 263 | static void taal_cancel_ulps_work(struct omap_dss_device *dssdev) |
264 | { | 264 | { |
265 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 265 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
266 | 266 | ||
267 | cancel_delayed_work(&td->ulps_work); | 267 | cancel_delayed_work(&td->ulps_work); |
268 | } | 268 | } |
269 | 269 | ||
270 | static int taal_enter_ulps(struct omap_dss_device *dssdev) | 270 | static int taal_enter_ulps(struct omap_dss_device *dssdev) |
271 | { | 271 | { |
272 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 272 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
273 | int r; | 273 | int r; |
274 | 274 | ||
275 | if (td->ulps_enabled) | 275 | if (td->ulps_enabled) |
@@ -291,7 +291,7 @@ static int taal_enter_ulps(struct omap_dss_device *dssdev) | |||
291 | return 0; | 291 | return 0; |
292 | 292 | ||
293 | err: | 293 | err: |
294 | dev_err(&dssdev->dev, "enter ULPS failed"); | 294 | dev_err(dssdev->dev, "enter ULPS failed"); |
295 | taal_panel_reset(dssdev); | 295 | taal_panel_reset(dssdev); |
296 | 296 | ||
297 | td->ulps_enabled = false; | 297 | td->ulps_enabled = false; |
@@ -303,7 +303,7 @@ err: | |||
303 | 303 | ||
304 | static int taal_exit_ulps(struct omap_dss_device *dssdev) | 304 | static int taal_exit_ulps(struct omap_dss_device *dssdev) |
305 | { | 305 | { |
306 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 306 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
307 | int r; | 307 | int r; |
308 | 308 | ||
309 | if (!td->ulps_enabled) | 309 | if (!td->ulps_enabled) |
@@ -311,7 +311,7 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev) | |||
311 | 311 | ||
312 | r = omapdss_dsi_display_enable(dssdev); | 312 | r = omapdss_dsi_display_enable(dssdev); |
313 | if (r) { | 313 | if (r) { |
314 | dev_err(&dssdev->dev, "failed to enable DSI\n"); | 314 | dev_err(dssdev->dev, "failed to enable DSI\n"); |
315 | goto err1; | 315 | goto err1; |
316 | } | 316 | } |
317 | 317 | ||
@@ -319,7 +319,7 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev) | |||
319 | 319 | ||
320 | r = _taal_enable_te(dssdev, true); | 320 | r = _taal_enable_te(dssdev, true); |
321 | if (r) { | 321 | if (r) { |
322 | dev_err(&dssdev->dev, "failed to re-enable TE"); | 322 | dev_err(dssdev->dev, "failed to re-enable TE"); |
323 | goto err2; | 323 | goto err2; |
324 | } | 324 | } |
325 | 325 | ||
@@ -333,7 +333,7 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev) | |||
333 | return 0; | 333 | return 0; |
334 | 334 | ||
335 | err2: | 335 | err2: |
336 | dev_err(&dssdev->dev, "failed to exit ULPS"); | 336 | dev_err(dssdev->dev, "failed to exit ULPS"); |
337 | 337 | ||
338 | r = taal_panel_reset(dssdev); | 338 | r = taal_panel_reset(dssdev); |
339 | if (!r) { | 339 | if (!r) { |
@@ -349,7 +349,7 @@ err1: | |||
349 | 349 | ||
350 | static int taal_wake_up(struct omap_dss_device *dssdev) | 350 | static int taal_wake_up(struct omap_dss_device *dssdev) |
351 | { | 351 | { |
352 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 352 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
353 | 353 | ||
354 | if (td->ulps_enabled) | 354 | if (td->ulps_enabled) |
355 | return taal_exit_ulps(dssdev); | 355 | return taal_exit_ulps(dssdev); |
@@ -362,7 +362,7 @@ static int taal_wake_up(struct omap_dss_device *dssdev) | |||
362 | static int taal_bl_update_status(struct backlight_device *dev) | 362 | static int taal_bl_update_status(struct backlight_device *dev) |
363 | { | 363 | { |
364 | struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev); | 364 | struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev); |
365 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 365 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
366 | int r; | 366 | int r; |
367 | int level; | 367 | int level; |
368 | 368 | ||
@@ -372,7 +372,7 @@ static int taal_bl_update_status(struct backlight_device *dev) | |||
372 | else | 372 | else |
373 | level = 0; | 373 | level = 0; |
374 | 374 | ||
375 | dev_dbg(&dssdev->dev, "update brightness to %d\n", level); | 375 | dev_dbg(dssdev->dev, "update brightness to %d\n", level); |
376 | 376 | ||
377 | mutex_lock(&td->lock); | 377 | mutex_lock(&td->lock); |
378 | 378 | ||
@@ -418,7 +418,7 @@ static ssize_t taal_num_errors_show(struct device *dev, | |||
418 | struct device_attribute *attr, char *buf) | 418 | struct device_attribute *attr, char *buf) |
419 | { | 419 | { |
420 | struct omap_dss_device *dssdev = to_dss_device(dev); | 420 | struct omap_dss_device *dssdev = to_dss_device(dev); |
421 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 421 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
422 | u8 errors = 0; | 422 | u8 errors = 0; |
423 | int r; | 423 | int r; |
424 | 424 | ||
@@ -448,7 +448,7 @@ static ssize_t taal_hw_revision_show(struct device *dev, | |||
448 | struct device_attribute *attr, char *buf) | 448 | struct device_attribute *attr, char *buf) |
449 | { | 449 | { |
450 | struct omap_dss_device *dssdev = to_dss_device(dev); | 450 | struct omap_dss_device *dssdev = to_dss_device(dev); |
451 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 451 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
452 | u8 id1, id2, id3; | 452 | u8 id1, id2, id3; |
453 | int r; | 453 | int r; |
454 | 454 | ||
@@ -486,7 +486,7 @@ static ssize_t show_cabc_mode(struct device *dev, | |||
486 | char *buf) | 486 | char *buf) |
487 | { | 487 | { |
488 | struct omap_dss_device *dssdev = to_dss_device(dev); | 488 | struct omap_dss_device *dssdev = to_dss_device(dev); |
489 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 489 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
490 | const char *mode_str; | 490 | const char *mode_str; |
491 | int mode; | 491 | int mode; |
492 | int len; | 492 | int len; |
@@ -506,7 +506,7 @@ static ssize_t store_cabc_mode(struct device *dev, | |||
506 | const char *buf, size_t count) | 506 | const char *buf, size_t count) |
507 | { | 507 | { |
508 | struct omap_dss_device *dssdev = to_dss_device(dev); | 508 | struct omap_dss_device *dssdev = to_dss_device(dev); |
509 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 509 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
510 | int i; | 510 | int i; |
511 | int r; | 511 | int r; |
512 | 512 | ||
@@ -568,12 +568,12 @@ static ssize_t taal_store_esd_interval(struct device *dev, | |||
568 | const char *buf, size_t count) | 568 | const char *buf, size_t count) |
569 | { | 569 | { |
570 | struct omap_dss_device *dssdev = to_dss_device(dev); | 570 | struct omap_dss_device *dssdev = to_dss_device(dev); |
571 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 571 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
572 | 572 | ||
573 | unsigned long t; | 573 | unsigned long t; |
574 | int r; | 574 | int r; |
575 | 575 | ||
576 | r = strict_strtoul(buf, 10, &t); | 576 | r = kstrtoul(buf, 10, &t); |
577 | if (r) | 577 | if (r) |
578 | return r; | 578 | return r; |
579 | 579 | ||
@@ -592,7 +592,7 @@ static ssize_t taal_show_esd_interval(struct device *dev, | |||
592 | char *buf) | 592 | char *buf) |
593 | { | 593 | { |
594 | struct omap_dss_device *dssdev = to_dss_device(dev); | 594 | struct omap_dss_device *dssdev = to_dss_device(dev); |
595 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 595 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
596 | unsigned t; | 596 | unsigned t; |
597 | 597 | ||
598 | mutex_lock(&td->lock); | 598 | mutex_lock(&td->lock); |
@@ -607,11 +607,11 @@ static ssize_t taal_store_ulps(struct device *dev, | |||
607 | const char *buf, size_t count) | 607 | const char *buf, size_t count) |
608 | { | 608 | { |
609 | struct omap_dss_device *dssdev = to_dss_device(dev); | 609 | struct omap_dss_device *dssdev = to_dss_device(dev); |
610 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 610 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
611 | unsigned long t; | 611 | unsigned long t; |
612 | int r; | 612 | int r; |
613 | 613 | ||
614 | r = strict_strtoul(buf, 10, &t); | 614 | r = kstrtoul(buf, 10, &t); |
615 | if (r) | 615 | if (r) |
616 | return r; | 616 | return r; |
617 | 617 | ||
@@ -641,7 +641,7 @@ static ssize_t taal_show_ulps(struct device *dev, | |||
641 | char *buf) | 641 | char *buf) |
642 | { | 642 | { |
643 | struct omap_dss_device *dssdev = to_dss_device(dev); | 643 | struct omap_dss_device *dssdev = to_dss_device(dev); |
644 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 644 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
645 | unsigned t; | 645 | unsigned t; |
646 | 646 | ||
647 | mutex_lock(&td->lock); | 647 | mutex_lock(&td->lock); |
@@ -656,11 +656,11 @@ static ssize_t taal_store_ulps_timeout(struct device *dev, | |||
656 | const char *buf, size_t count) | 656 | const char *buf, size_t count) |
657 | { | 657 | { |
658 | struct omap_dss_device *dssdev = to_dss_device(dev); | 658 | struct omap_dss_device *dssdev = to_dss_device(dev); |
659 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 659 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
660 | unsigned long t; | 660 | unsigned long t; |
661 | int r; | 661 | int r; |
662 | 662 | ||
663 | r = strict_strtoul(buf, 10, &t); | 663 | r = kstrtoul(buf, 10, &t); |
664 | if (r) | 664 | if (r) |
665 | return r; | 665 | return r; |
666 | 666 | ||
@@ -687,7 +687,7 @@ static ssize_t taal_show_ulps_timeout(struct device *dev, | |||
687 | char *buf) | 687 | char *buf) |
688 | { | 688 | { |
689 | struct omap_dss_device *dssdev = to_dss_device(dev); | 689 | struct omap_dss_device *dssdev = to_dss_device(dev); |
690 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 690 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
691 | unsigned t; | 691 | unsigned t; |
692 | 692 | ||
693 | mutex_lock(&td->lock); | 693 | mutex_lock(&td->lock); |
@@ -727,7 +727,7 @@ static struct attribute_group taal_attr_group = { | |||
727 | 727 | ||
728 | static void taal_hw_reset(struct omap_dss_device *dssdev) | 728 | static void taal_hw_reset(struct omap_dss_device *dssdev) |
729 | { | 729 | { |
730 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 730 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
731 | 731 | ||
732 | if (!gpio_is_valid(td->reset_gpio)) | 732 | if (!gpio_is_valid(td->reset_gpio)) |
733 | return; | 733 | return; |
@@ -768,13 +768,13 @@ static int taal_probe(struct omap_dss_device *dssdev) | |||
768 | struct backlight_device *bldev = NULL; | 768 | struct backlight_device *bldev = NULL; |
769 | int r; | 769 | int r; |
770 | 770 | ||
771 | dev_dbg(&dssdev->dev, "probe\n"); | 771 | dev_dbg(dssdev->dev, "probe\n"); |
772 | 772 | ||
773 | td = devm_kzalloc(&dssdev->dev, sizeof(*td), GFP_KERNEL); | 773 | td = devm_kzalloc(dssdev->dev, sizeof(*td), GFP_KERNEL); |
774 | if (!td) | 774 | if (!td) |
775 | return -ENOMEM; | 775 | return -ENOMEM; |
776 | 776 | ||
777 | dev_set_drvdata(&dssdev->dev, td); | 777 | dev_set_drvdata(dssdev->dev, td); |
778 | td->dssdev = dssdev; | 778 | td->dssdev = dssdev; |
779 | 779 | ||
780 | if (dssdev->data) { | 780 | if (dssdev->data) { |
@@ -797,41 +797,41 @@ static int taal_probe(struct omap_dss_device *dssdev) | |||
797 | atomic_set(&td->do_update, 0); | 797 | atomic_set(&td->do_update, 0); |
798 | 798 | ||
799 | if (gpio_is_valid(td->reset_gpio)) { | 799 | if (gpio_is_valid(td->reset_gpio)) { |
800 | r = devm_gpio_request_one(&dssdev->dev, td->reset_gpio, | 800 | r = devm_gpio_request_one(dssdev->dev, td->reset_gpio, |
801 | GPIOF_OUT_INIT_LOW, "taal rst"); | 801 | GPIOF_OUT_INIT_LOW, "taal rst"); |
802 | if (r) { | 802 | if (r) { |
803 | dev_err(&dssdev->dev, "failed to request reset gpio\n"); | 803 | dev_err(dssdev->dev, "failed to request reset gpio\n"); |
804 | return r; | 804 | return r; |
805 | } | 805 | } |
806 | } | 806 | } |
807 | 807 | ||
808 | if (gpio_is_valid(td->ext_te_gpio)) { | 808 | if (gpio_is_valid(td->ext_te_gpio)) { |
809 | r = devm_gpio_request_one(&dssdev->dev, td->ext_te_gpio, | 809 | r = devm_gpio_request_one(dssdev->dev, td->ext_te_gpio, |
810 | GPIOF_IN, "taal irq"); | 810 | GPIOF_IN, "taal irq"); |
811 | if (r) { | 811 | if (r) { |
812 | dev_err(&dssdev->dev, "GPIO request failed\n"); | 812 | dev_err(dssdev->dev, "GPIO request failed\n"); |
813 | return r; | 813 | return r; |
814 | } | 814 | } |
815 | 815 | ||
816 | r = devm_request_irq(&dssdev->dev, gpio_to_irq(td->ext_te_gpio), | 816 | r = devm_request_irq(dssdev->dev, gpio_to_irq(td->ext_te_gpio), |
817 | taal_te_isr, | 817 | taal_te_isr, |
818 | IRQF_TRIGGER_RISING, | 818 | IRQF_TRIGGER_RISING, |
819 | "taal vsync", dssdev); | 819 | "taal vsync", dssdev); |
820 | 820 | ||
821 | if (r) { | 821 | if (r) { |
822 | dev_err(&dssdev->dev, "IRQ request failed\n"); | 822 | dev_err(dssdev->dev, "IRQ request failed\n"); |
823 | return r; | 823 | return r; |
824 | } | 824 | } |
825 | 825 | ||
826 | INIT_DEFERRABLE_WORK(&td->te_timeout_work, | 826 | INIT_DEFERRABLE_WORK(&td->te_timeout_work, |
827 | taal_te_timeout_work_callback); | 827 | taal_te_timeout_work_callback); |
828 | 828 | ||
829 | dev_dbg(&dssdev->dev, "Using GPIO TE\n"); | 829 | dev_dbg(dssdev->dev, "Using GPIO TE\n"); |
830 | } | 830 | } |
831 | 831 | ||
832 | td->workqueue = create_singlethread_workqueue("taal_esd"); | 832 | td->workqueue = create_singlethread_workqueue("taal_esd"); |
833 | if (td->workqueue == NULL) { | 833 | if (td->workqueue == NULL) { |
834 | dev_err(&dssdev->dev, "can't create ESD workqueue\n"); | 834 | dev_err(dssdev->dev, "can't create ESD workqueue\n"); |
835 | return -ENOMEM; | 835 | return -ENOMEM; |
836 | } | 836 | } |
837 | INIT_DEFERRABLE_WORK(&td->esd_work, taal_esd_work); | 837 | INIT_DEFERRABLE_WORK(&td->esd_work, taal_esd_work); |
@@ -844,8 +844,8 @@ static int taal_probe(struct omap_dss_device *dssdev) | |||
844 | props.max_brightness = 255; | 844 | props.max_brightness = 255; |
845 | 845 | ||
846 | props.type = BACKLIGHT_RAW; | 846 | props.type = BACKLIGHT_RAW; |
847 | bldev = backlight_device_register(dev_name(&dssdev->dev), | 847 | bldev = backlight_device_register(dev_name(dssdev->dev), |
848 | &dssdev->dev, dssdev, &taal_bl_ops, &props); | 848 | dssdev->dev, dssdev, &taal_bl_ops, &props); |
849 | if (IS_ERR(bldev)) { | 849 | if (IS_ERR(bldev)) { |
850 | r = PTR_ERR(bldev); | 850 | r = PTR_ERR(bldev); |
851 | goto err_bl; | 851 | goto err_bl; |
@@ -862,19 +862,19 @@ static int taal_probe(struct omap_dss_device *dssdev) | |||
862 | 862 | ||
863 | r = omap_dsi_request_vc(dssdev, &td->channel); | 863 | r = omap_dsi_request_vc(dssdev, &td->channel); |
864 | if (r) { | 864 | if (r) { |
865 | dev_err(&dssdev->dev, "failed to get virtual channel\n"); | 865 | dev_err(dssdev->dev, "failed to get virtual channel\n"); |
866 | goto err_req_vc; | 866 | goto err_req_vc; |
867 | } | 867 | } |
868 | 868 | ||
869 | r = omap_dsi_set_vc_id(dssdev, td->channel, TCH); | 869 | r = omap_dsi_set_vc_id(dssdev, td->channel, TCH); |
870 | if (r) { | 870 | if (r) { |
871 | dev_err(&dssdev->dev, "failed to set VC_ID\n"); | 871 | dev_err(dssdev->dev, "failed to set VC_ID\n"); |
872 | goto err_vc_id; | 872 | goto err_vc_id; |
873 | } | 873 | } |
874 | 874 | ||
875 | r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group); | 875 | r = sysfs_create_group(&dssdev->dev->kobj, &taal_attr_group); |
876 | if (r) { | 876 | if (r) { |
877 | dev_err(&dssdev->dev, "failed to create sysfs files\n"); | 877 | dev_err(dssdev->dev, "failed to create sysfs files\n"); |
878 | goto err_vc_id; | 878 | goto err_vc_id; |
879 | } | 879 | } |
880 | 880 | ||
@@ -892,12 +892,12 @@ err_bl: | |||
892 | 892 | ||
893 | static void __exit taal_remove(struct omap_dss_device *dssdev) | 893 | static void __exit taal_remove(struct omap_dss_device *dssdev) |
894 | { | 894 | { |
895 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 895 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
896 | struct backlight_device *bldev; | 896 | struct backlight_device *bldev; |
897 | 897 | ||
898 | dev_dbg(&dssdev->dev, "remove\n"); | 898 | dev_dbg(dssdev->dev, "remove\n"); |
899 | 899 | ||
900 | sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group); | 900 | sysfs_remove_group(&dssdev->dev->kobj, &taal_attr_group); |
901 | omap_dsi_release_vc(dssdev, td->channel); | 901 | omap_dsi_release_vc(dssdev, td->channel); |
902 | 902 | ||
903 | bldev = td->bldev; | 903 | bldev = td->bldev; |
@@ -917,7 +917,7 @@ static void __exit taal_remove(struct omap_dss_device *dssdev) | |||
917 | 917 | ||
918 | static int taal_power_on(struct omap_dss_device *dssdev) | 918 | static int taal_power_on(struct omap_dss_device *dssdev) |
919 | { | 919 | { |
920 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 920 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
921 | u8 id1, id2, id3; | 921 | u8 id1, id2, id3; |
922 | int r; | 922 | int r; |
923 | struct omap_dss_dsi_config dsi_config = { | 923 | struct omap_dss_dsi_config dsi_config = { |
@@ -932,19 +932,19 @@ static int taal_power_on(struct omap_dss_device *dssdev) | |||
932 | 932 | ||
933 | r = omapdss_dsi_configure_pins(dssdev, &td->pin_config); | 933 | r = omapdss_dsi_configure_pins(dssdev, &td->pin_config); |
934 | if (r) { | 934 | if (r) { |
935 | dev_err(&dssdev->dev, "failed to configure DSI pins\n"); | 935 | dev_err(dssdev->dev, "failed to configure DSI pins\n"); |
936 | goto err0; | 936 | goto err0; |
937 | }; | 937 | }; |
938 | 938 | ||
939 | r = omapdss_dsi_set_config(dssdev, &dsi_config); | 939 | r = omapdss_dsi_set_config(dssdev, &dsi_config); |
940 | if (r) { | 940 | if (r) { |
941 | dev_err(&dssdev->dev, "failed to configure DSI\n"); | 941 | dev_err(dssdev->dev, "failed to configure DSI\n"); |
942 | goto err0; | 942 | goto err0; |
943 | } | 943 | } |
944 | 944 | ||
945 | r = omapdss_dsi_display_enable(dssdev); | 945 | r = omapdss_dsi_display_enable(dssdev); |
946 | if (r) { | 946 | if (r) { |
947 | dev_err(&dssdev->dev, "failed to enable DSI\n"); | 947 | dev_err(dssdev->dev, "failed to enable DSI\n"); |
948 | goto err0; | 948 | goto err0; |
949 | } | 949 | } |
950 | 950 | ||
@@ -999,10 +999,10 @@ static int taal_power_on(struct omap_dss_device *dssdev) | |||
999 | td->enabled = 1; | 999 | td->enabled = 1; |
1000 | 1000 | ||
1001 | if (!td->intro_printed) { | 1001 | if (!td->intro_printed) { |
1002 | dev_info(&dssdev->dev, "panel revision %02x.%02x.%02x\n", | 1002 | dev_info(dssdev->dev, "panel revision %02x.%02x.%02x\n", |
1003 | id1, id2, id3); | 1003 | id1, id2, id3); |
1004 | if (td->cabc_broken) | 1004 | if (td->cabc_broken) |
1005 | dev_info(&dssdev->dev, | 1005 | dev_info(dssdev->dev, |
1006 | "old Taal version, CABC disabled\n"); | 1006 | "old Taal version, CABC disabled\n"); |
1007 | td->intro_printed = true; | 1007 | td->intro_printed = true; |
1008 | } | 1008 | } |
@@ -1011,7 +1011,7 @@ static int taal_power_on(struct omap_dss_device *dssdev) | |||
1011 | 1011 | ||
1012 | return 0; | 1012 | return 0; |
1013 | err: | 1013 | err: |
1014 | dev_err(&dssdev->dev, "error while enabling panel, issuing HW reset\n"); | 1014 | dev_err(dssdev->dev, "error while enabling panel, issuing HW reset\n"); |
1015 | 1015 | ||
1016 | taal_hw_reset(dssdev); | 1016 | taal_hw_reset(dssdev); |
1017 | 1017 | ||
@@ -1022,7 +1022,7 @@ err0: | |||
1022 | 1022 | ||
1023 | static void taal_power_off(struct omap_dss_device *dssdev) | 1023 | static void taal_power_off(struct omap_dss_device *dssdev) |
1024 | { | 1024 | { |
1025 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1025 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
1026 | int r; | 1026 | int r; |
1027 | 1027 | ||
1028 | dsi_disable_video_output(dssdev, td->channel); | 1028 | dsi_disable_video_output(dssdev, td->channel); |
@@ -1032,7 +1032,7 @@ static void taal_power_off(struct omap_dss_device *dssdev) | |||
1032 | r = taal_sleep_in(td); | 1032 | r = taal_sleep_in(td); |
1033 | 1033 | ||
1034 | if (r) { | 1034 | if (r) { |
1035 | dev_err(&dssdev->dev, | 1035 | dev_err(dssdev->dev, |
1036 | "error disabling panel, issuing HW reset\n"); | 1036 | "error disabling panel, issuing HW reset\n"); |
1037 | taal_hw_reset(dssdev); | 1037 | taal_hw_reset(dssdev); |
1038 | } | 1038 | } |
@@ -1044,7 +1044,7 @@ static void taal_power_off(struct omap_dss_device *dssdev) | |||
1044 | 1044 | ||
1045 | static int taal_panel_reset(struct omap_dss_device *dssdev) | 1045 | static int taal_panel_reset(struct omap_dss_device *dssdev) |
1046 | { | 1046 | { |
1047 | dev_err(&dssdev->dev, "performing LCD reset\n"); | 1047 | dev_err(dssdev->dev, "performing LCD reset\n"); |
1048 | 1048 | ||
1049 | taal_power_off(dssdev); | 1049 | taal_power_off(dssdev); |
1050 | taal_hw_reset(dssdev); | 1050 | taal_hw_reset(dssdev); |
@@ -1053,10 +1053,10 @@ static int taal_panel_reset(struct omap_dss_device *dssdev) | |||
1053 | 1053 | ||
1054 | static int taal_enable(struct omap_dss_device *dssdev) | 1054 | static int taal_enable(struct omap_dss_device *dssdev) |
1055 | { | 1055 | { |
1056 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1056 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
1057 | int r; | 1057 | int r; |
1058 | 1058 | ||
1059 | dev_dbg(&dssdev->dev, "enable\n"); | 1059 | dev_dbg(dssdev->dev, "enable\n"); |
1060 | 1060 | ||
1061 | mutex_lock(&td->lock); | 1061 | mutex_lock(&td->lock); |
1062 | 1062 | ||
@@ -1082,16 +1082,16 @@ static int taal_enable(struct omap_dss_device *dssdev) | |||
1082 | 1082 | ||
1083 | return 0; | 1083 | return 0; |
1084 | err: | 1084 | err: |
1085 | dev_dbg(&dssdev->dev, "enable failed\n"); | 1085 | dev_dbg(dssdev->dev, "enable failed\n"); |
1086 | mutex_unlock(&td->lock); | 1086 | mutex_unlock(&td->lock); |
1087 | return r; | 1087 | return r; |
1088 | } | 1088 | } |
1089 | 1089 | ||
1090 | static void taal_disable(struct omap_dss_device *dssdev) | 1090 | static void taal_disable(struct omap_dss_device *dssdev) |
1091 | { | 1091 | { |
1092 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1092 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
1093 | 1093 | ||
1094 | dev_dbg(&dssdev->dev, "disable\n"); | 1094 | dev_dbg(dssdev->dev, "disable\n"); |
1095 | 1095 | ||
1096 | mutex_lock(&td->lock); | 1096 | mutex_lock(&td->lock); |
1097 | 1097 | ||
@@ -1118,14 +1118,14 @@ static void taal_disable(struct omap_dss_device *dssdev) | |||
1118 | static void taal_framedone_cb(int err, void *data) | 1118 | static void taal_framedone_cb(int err, void *data) |
1119 | { | 1119 | { |
1120 | struct omap_dss_device *dssdev = data; | 1120 | struct omap_dss_device *dssdev = data; |
1121 | dev_dbg(&dssdev->dev, "framedone, err %d\n", err); | 1121 | dev_dbg(dssdev->dev, "framedone, err %d\n", err); |
1122 | dsi_bus_unlock(dssdev); | 1122 | dsi_bus_unlock(dssdev); |
1123 | } | 1123 | } |
1124 | 1124 | ||
1125 | static irqreturn_t taal_te_isr(int irq, void *data) | 1125 | static irqreturn_t taal_te_isr(int irq, void *data) |
1126 | { | 1126 | { |
1127 | struct omap_dss_device *dssdev = data; | 1127 | struct omap_dss_device *dssdev = data; |
1128 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1128 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
1129 | int old; | 1129 | int old; |
1130 | int r; | 1130 | int r; |
1131 | 1131 | ||
@@ -1142,7 +1142,7 @@ static irqreturn_t taal_te_isr(int irq, void *data) | |||
1142 | 1142 | ||
1143 | return IRQ_HANDLED; | 1143 | return IRQ_HANDLED; |
1144 | err: | 1144 | err: |
1145 | dev_err(&dssdev->dev, "start update failed\n"); | 1145 | dev_err(dssdev->dev, "start update failed\n"); |
1146 | dsi_bus_unlock(dssdev); | 1146 | dsi_bus_unlock(dssdev); |
1147 | return IRQ_HANDLED; | 1147 | return IRQ_HANDLED; |
1148 | } | 1148 | } |
@@ -1153,7 +1153,7 @@ static void taal_te_timeout_work_callback(struct work_struct *work) | |||
1153 | te_timeout_work.work); | 1153 | te_timeout_work.work); |
1154 | struct omap_dss_device *dssdev = td->dssdev; | 1154 | struct omap_dss_device *dssdev = td->dssdev; |
1155 | 1155 | ||
1156 | dev_err(&dssdev->dev, "TE not received for 250ms!\n"); | 1156 | dev_err(dssdev->dev, "TE not received for 250ms!\n"); |
1157 | 1157 | ||
1158 | atomic_set(&td->do_update, 0); | 1158 | atomic_set(&td->do_update, 0); |
1159 | dsi_bus_unlock(dssdev); | 1159 | dsi_bus_unlock(dssdev); |
@@ -1162,10 +1162,10 @@ static void taal_te_timeout_work_callback(struct work_struct *work) | |||
1162 | static int taal_update(struct omap_dss_device *dssdev, | 1162 | static int taal_update(struct omap_dss_device *dssdev, |
1163 | u16 x, u16 y, u16 w, u16 h) | 1163 | u16 x, u16 y, u16 w, u16 h) |
1164 | { | 1164 | { |
1165 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1165 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
1166 | int r; | 1166 | int r; |
1167 | 1167 | ||
1168 | dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h); | 1168 | dev_dbg(dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h); |
1169 | 1169 | ||
1170 | mutex_lock(&td->lock); | 1170 | mutex_lock(&td->lock); |
1171 | dsi_bus_lock(dssdev); | 1171 | dsi_bus_lock(dssdev); |
@@ -1208,23 +1208,23 @@ err: | |||
1208 | 1208 | ||
1209 | static int taal_sync(struct omap_dss_device *dssdev) | 1209 | static int taal_sync(struct omap_dss_device *dssdev) |
1210 | { | 1210 | { |
1211 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1211 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
1212 | 1212 | ||
1213 | dev_dbg(&dssdev->dev, "sync\n"); | 1213 | dev_dbg(dssdev->dev, "sync\n"); |
1214 | 1214 | ||
1215 | mutex_lock(&td->lock); | 1215 | mutex_lock(&td->lock); |
1216 | dsi_bus_lock(dssdev); | 1216 | dsi_bus_lock(dssdev); |
1217 | dsi_bus_unlock(dssdev); | 1217 | dsi_bus_unlock(dssdev); |
1218 | mutex_unlock(&td->lock); | 1218 | mutex_unlock(&td->lock); |
1219 | 1219 | ||
1220 | dev_dbg(&dssdev->dev, "sync done\n"); | 1220 | dev_dbg(dssdev->dev, "sync done\n"); |
1221 | 1221 | ||
1222 | return 0; | 1222 | return 0; |
1223 | } | 1223 | } |
1224 | 1224 | ||
1225 | static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) | 1225 | static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) |
1226 | { | 1226 | { |
1227 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1227 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
1228 | int r; | 1228 | int r; |
1229 | 1229 | ||
1230 | if (enable) | 1230 | if (enable) |
@@ -1243,7 +1243,7 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) | |||
1243 | 1243 | ||
1244 | static int taal_enable_te(struct omap_dss_device *dssdev, bool enable) | 1244 | static int taal_enable_te(struct omap_dss_device *dssdev, bool enable) |
1245 | { | 1245 | { |
1246 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1246 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
1247 | int r; | 1247 | int r; |
1248 | 1248 | ||
1249 | mutex_lock(&td->lock); | 1249 | mutex_lock(&td->lock); |
@@ -1279,7 +1279,7 @@ err: | |||
1279 | 1279 | ||
1280 | static int taal_get_te(struct omap_dss_device *dssdev) | 1280 | static int taal_get_te(struct omap_dss_device *dssdev) |
1281 | { | 1281 | { |
1282 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1282 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
1283 | int r; | 1283 | int r; |
1284 | 1284 | ||
1285 | mutex_lock(&td->lock); | 1285 | mutex_lock(&td->lock); |
@@ -1291,7 +1291,7 @@ static int taal_get_te(struct omap_dss_device *dssdev) | |||
1291 | 1291 | ||
1292 | static int taal_run_test(struct omap_dss_device *dssdev, int test_num) | 1292 | static int taal_run_test(struct omap_dss_device *dssdev, int test_num) |
1293 | { | 1293 | { |
1294 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1294 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
1295 | u8 id1, id2, id3; | 1295 | u8 id1, id2, id3; |
1296 | int r; | 1296 | int r; |
1297 | 1297 | ||
@@ -1336,7 +1336,7 @@ static int taal_memory_read(struct omap_dss_device *dssdev, | |||
1336 | int first = 1; | 1336 | int first = 1; |
1337 | int plen; | 1337 | int plen; |
1338 | unsigned buf_used = 0; | 1338 | unsigned buf_used = 0; |
1339 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1339 | struct taal_data *td = dev_get_drvdata(dssdev->dev); |
1340 | 1340 | ||
1341 | if (size < w * h * 3) | 1341 | if (size < w * h * 3) |
1342 | return -ENOMEM; | 1342 | return -ENOMEM; |
@@ -1380,19 +1380,19 @@ static int taal_memory_read(struct omap_dss_device *dssdev, | |||
1380 | buf + buf_used, size - buf_used); | 1380 | buf + buf_used, size - buf_used); |
1381 | 1381 | ||
1382 | if (r < 0) { | 1382 | if (r < 0) { |
1383 | dev_err(&dssdev->dev, "read error\n"); | 1383 | dev_err(dssdev->dev, "read error\n"); |
1384 | goto err3; | 1384 | goto err3; |
1385 | } | 1385 | } |
1386 | 1386 | ||
1387 | buf_used += r; | 1387 | buf_used += r; |
1388 | 1388 | ||
1389 | if (r < plen) { | 1389 | if (r < plen) { |
1390 | dev_err(&dssdev->dev, "short read\n"); | 1390 | dev_err(dssdev->dev, "short read\n"); |
1391 | break; | 1391 | break; |
1392 | } | 1392 | } |
1393 | 1393 | ||
1394 | if (signal_pending(current)) { | 1394 | if (signal_pending(current)) { |
1395 | dev_err(&dssdev->dev, "signal pending, " | 1395 | dev_err(dssdev->dev, "signal pending, " |
1396 | "aborting memory read\n"); | 1396 | "aborting memory read\n"); |
1397 | r = -ERESTARTSYS; | 1397 | r = -ERESTARTSYS; |
1398 | goto err3; | 1398 | goto err3; |
@@ -1450,26 +1450,26 @@ static void taal_esd_work(struct work_struct *work) | |||
1450 | 1450 | ||
1451 | r = taal_wake_up(dssdev); | 1451 | r = taal_wake_up(dssdev); |
1452 | if (r) { | 1452 | if (r) { |
1453 | dev_err(&dssdev->dev, "failed to exit ULPS\n"); | 1453 | dev_err(dssdev->dev, "failed to exit ULPS\n"); |
1454 | goto err; | 1454 | goto err; |
1455 | } | 1455 | } |
1456 | 1456 | ||
1457 | r = taal_dcs_read_1(td, MIPI_DCS_GET_DIAGNOSTIC_RESULT, &state1); | 1457 | r = taal_dcs_read_1(td, MIPI_DCS_GET_DIAGNOSTIC_RESULT, &state1); |
1458 | if (r) { | 1458 | if (r) { |
1459 | dev_err(&dssdev->dev, "failed to read Taal status\n"); | 1459 | dev_err(dssdev->dev, "failed to read Taal status\n"); |
1460 | goto err; | 1460 | goto err; |
1461 | } | 1461 | } |
1462 | 1462 | ||
1463 | /* Run self diagnostics */ | 1463 | /* Run self diagnostics */ |
1464 | r = taal_sleep_out(td); | 1464 | r = taal_sleep_out(td); |
1465 | if (r) { | 1465 | if (r) { |
1466 | dev_err(&dssdev->dev, "failed to run Taal self-diagnostics\n"); | 1466 | dev_err(dssdev->dev, "failed to run Taal self-diagnostics\n"); |
1467 | goto err; | 1467 | goto err; |
1468 | } | 1468 | } |
1469 | 1469 | ||
1470 | r = taal_dcs_read_1(td, MIPI_DCS_GET_DIAGNOSTIC_RESULT, &state2); | 1470 | r = taal_dcs_read_1(td, MIPI_DCS_GET_DIAGNOSTIC_RESULT, &state2); |
1471 | if (r) { | 1471 | if (r) { |
1472 | dev_err(&dssdev->dev, "failed to read Taal status\n"); | 1472 | dev_err(dssdev->dev, "failed to read Taal status\n"); |
1473 | goto err; | 1473 | goto err; |
1474 | } | 1474 | } |
1475 | 1475 | ||
@@ -1477,7 +1477,7 @@ static void taal_esd_work(struct work_struct *work) | |||
1477 | * Bit6 if the test passes. | 1477 | * Bit6 if the test passes. |
1478 | */ | 1478 | */ |
1479 | if (!((state1 ^ state2) & (1 << 6))) { | 1479 | if (!((state1 ^ state2) & (1 << 6))) { |
1480 | dev_err(&dssdev->dev, "LCD self diagnostics failed\n"); | 1480 | dev_err(dssdev->dev, "LCD self diagnostics failed\n"); |
1481 | goto err; | 1481 | goto err; |
1482 | } | 1482 | } |
1483 | /* Self-diagnostics result is also shown on TE GPIO line. We need | 1483 | /* Self-diagnostics result is also shown on TE GPIO line. We need |
@@ -1495,7 +1495,7 @@ static void taal_esd_work(struct work_struct *work) | |||
1495 | mutex_unlock(&td->lock); | 1495 | mutex_unlock(&td->lock); |
1496 | return; | 1496 | return; |
1497 | err: | 1497 | err: |
1498 | dev_err(&dssdev->dev, "performing LCD reset\n"); | 1498 | dev_err(dssdev->dev, "performing LCD reset\n"); |
1499 | 1499 | ||
1500 | taal_panel_reset(dssdev); | 1500 | taal_panel_reset(dssdev); |
1501 | 1501 | ||
diff --git a/drivers/video/omap2/displays/panel-tfp410.c b/drivers/video/omap2/displays/panel-tfp410.c index 46039c4bf1ed..1fdfb158a2a9 100644 --- a/drivers/video/omap2/displays/panel-tfp410.c +++ b/drivers/video/omap2/displays/panel-tfp410.c | |||
@@ -59,7 +59,7 @@ struct panel_drv_data { | |||
59 | 59 | ||
60 | static int tfp410_power_on(struct omap_dss_device *dssdev) | 60 | static int tfp410_power_on(struct omap_dss_device *dssdev) |
61 | { | 61 | { |
62 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | 62 | struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev); |
63 | int r; | 63 | int r; |
64 | 64 | ||
65 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | 65 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) |
@@ -82,7 +82,7 @@ err0: | |||
82 | 82 | ||
83 | static void tfp410_power_off(struct omap_dss_device *dssdev) | 83 | static void tfp410_power_off(struct omap_dss_device *dssdev) |
84 | { | 84 | { |
85 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | 85 | struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev); |
86 | 86 | ||
87 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | 87 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) |
88 | return; | 88 | return; |
@@ -99,7 +99,7 @@ static int tfp410_probe(struct omap_dss_device *dssdev) | |||
99 | int r; | 99 | int r; |
100 | int i2c_bus_num; | 100 | int i2c_bus_num; |
101 | 101 | ||
102 | ddata = devm_kzalloc(&dssdev->dev, sizeof(*ddata), GFP_KERNEL); | 102 | ddata = devm_kzalloc(dssdev->dev, sizeof(*ddata), GFP_KERNEL); |
103 | if (!ddata) | 103 | if (!ddata) |
104 | return -ENOMEM; | 104 | return -ENOMEM; |
105 | 105 | ||
@@ -119,10 +119,10 @@ static int tfp410_probe(struct omap_dss_device *dssdev) | |||
119 | } | 119 | } |
120 | 120 | ||
121 | if (gpio_is_valid(ddata->pd_gpio)) { | 121 | if (gpio_is_valid(ddata->pd_gpio)) { |
122 | r = devm_gpio_request_one(&dssdev->dev, ddata->pd_gpio, | 122 | r = devm_gpio_request_one(dssdev->dev, ddata->pd_gpio, |
123 | GPIOF_OUT_INIT_LOW, "tfp410 pd"); | 123 | GPIOF_OUT_INIT_LOW, "tfp410 pd"); |
124 | if (r) { | 124 | if (r) { |
125 | dev_err(&dssdev->dev, "Failed to request PD GPIO %d\n", | 125 | dev_err(dssdev->dev, "Failed to request PD GPIO %d\n", |
126 | ddata->pd_gpio); | 126 | ddata->pd_gpio); |
127 | return r; | 127 | return r; |
128 | } | 128 | } |
@@ -133,7 +133,7 @@ static int tfp410_probe(struct omap_dss_device *dssdev) | |||
133 | 133 | ||
134 | adapter = i2c_get_adapter(i2c_bus_num); | 134 | adapter = i2c_get_adapter(i2c_bus_num); |
135 | if (!adapter) { | 135 | if (!adapter) { |
136 | dev_err(&dssdev->dev, "Failed to get I2C adapter, bus %d\n", | 136 | dev_err(dssdev->dev, "Failed to get I2C adapter, bus %d\n", |
137 | i2c_bus_num); | 137 | i2c_bus_num); |
138 | return -EPROBE_DEFER; | 138 | return -EPROBE_DEFER; |
139 | } | 139 | } |
@@ -141,28 +141,28 @@ static int tfp410_probe(struct omap_dss_device *dssdev) | |||
141 | ddata->i2c_adapter = adapter; | 141 | ddata->i2c_adapter = adapter; |
142 | } | 142 | } |
143 | 143 | ||
144 | dev_set_drvdata(&dssdev->dev, ddata); | 144 | dev_set_drvdata(dssdev->dev, ddata); |
145 | 145 | ||
146 | return 0; | 146 | return 0; |
147 | } | 147 | } |
148 | 148 | ||
149 | static void __exit tfp410_remove(struct omap_dss_device *dssdev) | 149 | static void __exit tfp410_remove(struct omap_dss_device *dssdev) |
150 | { | 150 | { |
151 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | 151 | struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev); |
152 | 152 | ||
153 | mutex_lock(&ddata->lock); | 153 | mutex_lock(&ddata->lock); |
154 | 154 | ||
155 | if (ddata->i2c_adapter) | 155 | if (ddata->i2c_adapter) |
156 | i2c_put_adapter(ddata->i2c_adapter); | 156 | i2c_put_adapter(ddata->i2c_adapter); |
157 | 157 | ||
158 | dev_set_drvdata(&dssdev->dev, NULL); | 158 | dev_set_drvdata(dssdev->dev, NULL); |
159 | 159 | ||
160 | mutex_unlock(&ddata->lock); | 160 | mutex_unlock(&ddata->lock); |
161 | } | 161 | } |
162 | 162 | ||
163 | static int tfp410_enable(struct omap_dss_device *dssdev) | 163 | static int tfp410_enable(struct omap_dss_device *dssdev) |
164 | { | 164 | { |
165 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | 165 | struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev); |
166 | int r; | 166 | int r; |
167 | 167 | ||
168 | mutex_lock(&ddata->lock); | 168 | mutex_lock(&ddata->lock); |
@@ -178,7 +178,7 @@ static int tfp410_enable(struct omap_dss_device *dssdev) | |||
178 | 178 | ||
179 | static void tfp410_disable(struct omap_dss_device *dssdev) | 179 | static void tfp410_disable(struct omap_dss_device *dssdev) |
180 | { | 180 | { |
181 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | 181 | struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev); |
182 | 182 | ||
183 | mutex_lock(&ddata->lock); | 183 | mutex_lock(&ddata->lock); |
184 | 184 | ||
@@ -192,7 +192,7 @@ static void tfp410_disable(struct omap_dss_device *dssdev) | |||
192 | static void tfp410_set_timings(struct omap_dss_device *dssdev, | 192 | static void tfp410_set_timings(struct omap_dss_device *dssdev, |
193 | struct omap_video_timings *timings) | 193 | struct omap_video_timings *timings) |
194 | { | 194 | { |
195 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | 195 | struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev); |
196 | 196 | ||
197 | mutex_lock(&ddata->lock); | 197 | mutex_lock(&ddata->lock); |
198 | omapdss_dpi_set_timings(dssdev, timings); | 198 | omapdss_dpi_set_timings(dssdev, timings); |
@@ -203,7 +203,7 @@ static void tfp410_set_timings(struct omap_dss_device *dssdev, | |||
203 | static void tfp410_get_timings(struct omap_dss_device *dssdev, | 203 | static void tfp410_get_timings(struct omap_dss_device *dssdev, |
204 | struct omap_video_timings *timings) | 204 | struct omap_video_timings *timings) |
205 | { | 205 | { |
206 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | 206 | struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev); |
207 | 207 | ||
208 | mutex_lock(&ddata->lock); | 208 | mutex_lock(&ddata->lock); |
209 | *timings = dssdev->panel.timings; | 209 | *timings = dssdev->panel.timings; |
@@ -213,7 +213,7 @@ static void tfp410_get_timings(struct omap_dss_device *dssdev, | |||
213 | static int tfp410_check_timings(struct omap_dss_device *dssdev, | 213 | static int tfp410_check_timings(struct omap_dss_device *dssdev, |
214 | struct omap_video_timings *timings) | 214 | struct omap_video_timings *timings) |
215 | { | 215 | { |
216 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | 216 | struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev); |
217 | int r; | 217 | int r; |
218 | 218 | ||
219 | mutex_lock(&ddata->lock); | 219 | mutex_lock(&ddata->lock); |
@@ -258,7 +258,7 @@ static int tfp410_ddc_read(struct i2c_adapter *adapter, | |||
258 | static int tfp410_read_edid(struct omap_dss_device *dssdev, | 258 | static int tfp410_read_edid(struct omap_dss_device *dssdev, |
259 | u8 *edid, int len) | 259 | u8 *edid, int len) |
260 | { | 260 | { |
261 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | 261 | struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev); |
262 | int r, l, bytes_read; | 262 | int r, l, bytes_read; |
263 | 263 | ||
264 | mutex_lock(&ddata->lock); | 264 | mutex_lock(&ddata->lock); |
@@ -298,7 +298,7 @@ err: | |||
298 | 298 | ||
299 | static bool tfp410_detect(struct omap_dss_device *dssdev) | 299 | static bool tfp410_detect(struct omap_dss_device *dssdev) |
300 | { | 300 | { |
301 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | 301 | struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev); |
302 | unsigned char out; | 302 | unsigned char out; |
303 | int r; | 303 | int r; |
304 | 304 | ||
diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c index abf2bc4a18ab..7729b6fa6f97 100644 --- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c +++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c | |||
@@ -126,7 +126,7 @@ static int tpo_td043_write_mirror(struct spi_device *spi, bool h, bool v) | |||
126 | 126 | ||
127 | static int tpo_td043_set_hmirror(struct omap_dss_device *dssdev, bool enable) | 127 | static int tpo_td043_set_hmirror(struct omap_dss_device *dssdev, bool enable) |
128 | { | 128 | { |
129 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); | 129 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dssdev->dev); |
130 | 130 | ||
131 | tpo_td043->hmirror = enable; | 131 | tpo_td043->hmirror = enable; |
132 | return tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror, | 132 | return tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror, |
@@ -135,7 +135,7 @@ static int tpo_td043_set_hmirror(struct omap_dss_device *dssdev, bool enable) | |||
135 | 135 | ||
136 | static bool tpo_td043_get_hmirror(struct omap_dss_device *dssdev) | 136 | static bool tpo_td043_get_hmirror(struct omap_dss_device *dssdev) |
137 | { | 137 | { |
138 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); | 138 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dssdev->dev); |
139 | 139 | ||
140 | return tpo_td043->hmirror; | 140 | return tpo_td043->hmirror; |
141 | } | 141 | } |
@@ -338,7 +338,7 @@ static void tpo_td043_power_off(struct tpo_td043_device *tpo_td043) | |||
338 | 338 | ||
339 | static int tpo_td043_enable_dss(struct omap_dss_device *dssdev) | 339 | static int tpo_td043_enable_dss(struct omap_dss_device *dssdev) |
340 | { | 340 | { |
341 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); | 341 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dssdev->dev); |
342 | int r; | 342 | int r; |
343 | 343 | ||
344 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | 344 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) |
@@ -372,7 +372,7 @@ err0: | |||
372 | 372 | ||
373 | static void tpo_td043_disable_dss(struct omap_dss_device *dssdev) | 373 | static void tpo_td043_disable_dss(struct omap_dss_device *dssdev) |
374 | { | 374 | { |
375 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); | 375 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dssdev->dev); |
376 | 376 | ||
377 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | 377 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) |
378 | return; | 378 | return; |
@@ -385,14 +385,14 @@ static void tpo_td043_disable_dss(struct omap_dss_device *dssdev) | |||
385 | 385 | ||
386 | static int tpo_td043_enable(struct omap_dss_device *dssdev) | 386 | static int tpo_td043_enable(struct omap_dss_device *dssdev) |
387 | { | 387 | { |
388 | dev_dbg(&dssdev->dev, "enable\n"); | 388 | dev_dbg(dssdev->dev, "enable\n"); |
389 | 389 | ||
390 | return tpo_td043_enable_dss(dssdev); | 390 | return tpo_td043_enable_dss(dssdev); |
391 | } | 391 | } |
392 | 392 | ||
393 | static void tpo_td043_disable(struct omap_dss_device *dssdev) | 393 | static void tpo_td043_disable(struct omap_dss_device *dssdev) |
394 | { | 394 | { |
395 | dev_dbg(&dssdev->dev, "disable\n"); | 395 | dev_dbg(dssdev->dev, "disable\n"); |
396 | 396 | ||
397 | tpo_td043_disable_dss(dssdev); | 397 | tpo_td043_disable_dss(dssdev); |
398 | 398 | ||
@@ -405,10 +405,10 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev) | |||
405 | struct panel_tpo_td043_data *pdata = get_panel_data(dssdev); | 405 | struct panel_tpo_td043_data *pdata = get_panel_data(dssdev); |
406 | int ret = 0; | 406 | int ret = 0; |
407 | 407 | ||
408 | dev_dbg(&dssdev->dev, "probe\n"); | 408 | dev_dbg(dssdev->dev, "probe\n"); |
409 | 409 | ||
410 | if (tpo_td043 == NULL) { | 410 | if (tpo_td043 == NULL) { |
411 | dev_err(&dssdev->dev, "missing tpo_td043_device\n"); | 411 | dev_err(dssdev->dev, "missing tpo_td043_device\n"); |
412 | return -ENODEV; | 412 | return -ENODEV; |
413 | } | 413 | } |
414 | 414 | ||
@@ -423,28 +423,28 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev) | |||
423 | tpo_td043->mode = TPO_R02_MODE_800x480; | 423 | tpo_td043->mode = TPO_R02_MODE_800x480; |
424 | memcpy(tpo_td043->gamma, tpo_td043_def_gamma, sizeof(tpo_td043->gamma)); | 424 | memcpy(tpo_td043->gamma, tpo_td043_def_gamma, sizeof(tpo_td043->gamma)); |
425 | 425 | ||
426 | tpo_td043->vcc_reg = regulator_get(&dssdev->dev, "vcc"); | 426 | tpo_td043->vcc_reg = regulator_get(dssdev->dev, "vcc"); |
427 | if (IS_ERR(tpo_td043->vcc_reg)) { | 427 | if (IS_ERR(tpo_td043->vcc_reg)) { |
428 | dev_err(&dssdev->dev, "failed to get LCD VCC regulator\n"); | 428 | dev_err(dssdev->dev, "failed to get LCD VCC regulator\n"); |
429 | ret = PTR_ERR(tpo_td043->vcc_reg); | 429 | ret = PTR_ERR(tpo_td043->vcc_reg); |
430 | goto fail_regulator; | 430 | goto fail_regulator; |
431 | } | 431 | } |
432 | 432 | ||
433 | if (gpio_is_valid(tpo_td043->nreset_gpio)) { | 433 | if (gpio_is_valid(tpo_td043->nreset_gpio)) { |
434 | ret = devm_gpio_request_one(&dssdev->dev, | 434 | ret = devm_gpio_request_one(dssdev->dev, |
435 | tpo_td043->nreset_gpio, GPIOF_OUT_INIT_LOW, | 435 | tpo_td043->nreset_gpio, GPIOF_OUT_INIT_LOW, |
436 | "lcd reset"); | 436 | "lcd reset"); |
437 | if (ret < 0) { | 437 | if (ret < 0) { |
438 | dev_err(&dssdev->dev, "couldn't request reset GPIO\n"); | 438 | dev_err(dssdev->dev, "couldn't request reset GPIO\n"); |
439 | goto fail_gpio_req; | 439 | goto fail_gpio_req; |
440 | } | 440 | } |
441 | } | 441 | } |
442 | 442 | ||
443 | ret = sysfs_create_group(&dssdev->dev.kobj, &tpo_td043_attr_group); | 443 | ret = sysfs_create_group(&dssdev->dev->kobj, &tpo_td043_attr_group); |
444 | if (ret) | 444 | if (ret) |
445 | dev_warn(&dssdev->dev, "failed to create sysfs files\n"); | 445 | dev_warn(dssdev->dev, "failed to create sysfs files\n"); |
446 | 446 | ||
447 | dev_set_drvdata(&dssdev->dev, tpo_td043); | 447 | dev_set_drvdata(dssdev->dev, tpo_td043); |
448 | 448 | ||
449 | return 0; | 449 | return 0; |
450 | 450 | ||
@@ -457,11 +457,11 @@ fail_regulator: | |||
457 | 457 | ||
458 | static void tpo_td043_remove(struct omap_dss_device *dssdev) | 458 | static void tpo_td043_remove(struct omap_dss_device *dssdev) |
459 | { | 459 | { |
460 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); | 460 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dssdev->dev); |
461 | 461 | ||
462 | dev_dbg(&dssdev->dev, "remove\n"); | 462 | dev_dbg(dssdev->dev, "remove\n"); |
463 | 463 | ||
464 | sysfs_remove_group(&dssdev->dev.kobj, &tpo_td043_attr_group); | 464 | sysfs_remove_group(&dssdev->dev->kobj, &tpo_td043_attr_group); |
465 | regulator_put(tpo_td043->vcc_reg); | 465 | regulator_put(tpo_td043->vcc_reg); |
466 | } | 466 | } |
467 | 467 | ||
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index cb0f145c7077..8f70a8300b84 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig | |||
@@ -1,5 +1,6 @@ | |||
1 | menuconfig OMAP2_DSS | 1 | menuconfig OMAP2_DSS |
2 | tristate "OMAP2+ Display Subsystem support" | 2 | tristate "OMAP2+ Display Subsystem support" |
3 | select VIDEOMODE_HELPERS | ||
3 | help | 4 | help |
4 | OMAP2+ Display Subsystem support. | 5 | OMAP2+ Display Subsystem support. |
5 | 6 | ||
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c index a4b356a9780d..d6212d63cfb2 100644 --- a/drivers/video/omap2/dss/apply.c +++ b/drivers/video/omap2/dss/apply.c | |||
@@ -420,16 +420,26 @@ static void wait_pending_extra_info_updates(void) | |||
420 | DSSWARN("timeout in wait_pending_extra_info_updates\n"); | 420 | DSSWARN("timeout in wait_pending_extra_info_updates\n"); |
421 | } | 421 | } |
422 | 422 | ||
423 | static inline struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl) | 423 | static struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr) |
424 | { | 424 | { |
425 | return ovl->manager ? | 425 | struct omap_dss_device *dssdev; |
426 | (ovl->manager->output ? ovl->manager->output->device : NULL) : | 426 | |
427 | NULL; | 427 | dssdev = mgr->output; |
428 | if (dssdev == NULL) | ||
429 | return NULL; | ||
430 | |||
431 | while (dssdev->device) | ||
432 | dssdev = dssdev->device; | ||
433 | |||
434 | if (dssdev->driver) | ||
435 | return dssdev; | ||
436 | else | ||
437 | return NULL; | ||
428 | } | 438 | } |
429 | 439 | ||
430 | static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr) | 440 | static struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl) |
431 | { | 441 | { |
432 | return mgr->output ? mgr->output->device : NULL; | 442 | return ovl->manager ? dss_mgr_get_device(ovl->manager) : NULL; |
433 | } | 443 | } |
434 | 444 | ||
435 | static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) | 445 | static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) |
@@ -792,6 +802,18 @@ static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr) | |||
792 | } | 802 | } |
793 | } | 803 | } |
794 | 804 | ||
805 | static int dss_mgr_connect_compat(struct omap_overlay_manager *mgr, | ||
806 | struct omap_dss_device *dst) | ||
807 | { | ||
808 | return mgr->set_output(mgr, dst); | ||
809 | } | ||
810 | |||
811 | static void dss_mgr_disconnect_compat(struct omap_overlay_manager *mgr, | ||
812 | struct omap_dss_device *dst) | ||
813 | { | ||
814 | mgr->unset_output(mgr); | ||
815 | } | ||
816 | |||
795 | static void dss_mgr_start_update_compat(struct omap_overlay_manager *mgr) | 817 | static void dss_mgr_start_update_compat(struct omap_overlay_manager *mgr) |
796 | { | 818 | { |
797 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | 819 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
@@ -1156,7 +1178,7 @@ static void dss_mgr_get_info(struct omap_overlay_manager *mgr, | |||
1156 | } | 1178 | } |
1157 | 1179 | ||
1158 | static int dss_mgr_set_output(struct omap_overlay_manager *mgr, | 1180 | static int dss_mgr_set_output(struct omap_overlay_manager *mgr, |
1159 | struct omap_dss_output *output) | 1181 | struct omap_dss_device *output) |
1160 | { | 1182 | { |
1161 | int r; | 1183 | int r; |
1162 | 1184 | ||
@@ -1554,6 +1576,8 @@ static void dss_mgr_unregister_framedone_handler_compat(struct omap_overlay_mana | |||
1554 | } | 1576 | } |
1555 | 1577 | ||
1556 | static const struct dss_mgr_ops apply_mgr_ops = { | 1578 | static const struct dss_mgr_ops apply_mgr_ops = { |
1579 | .connect = dss_mgr_connect_compat, | ||
1580 | .disconnect = dss_mgr_disconnect_compat, | ||
1557 | .start_update = dss_mgr_start_update_compat, | 1581 | .start_update = dss_mgr_start_update_compat, |
1558 | .enable = dss_mgr_enable_compat, | 1582 | .enable = dss_mgr_enable_compat, |
1559 | .disable = dss_mgr_disable_compat, | 1583 | .disable = dss_mgr_disable_compat, |
@@ -1569,7 +1593,6 @@ static DEFINE_MUTEX(compat_init_lock); | |||
1569 | int omapdss_compat_init(void) | 1593 | int omapdss_compat_init(void) |
1570 | { | 1594 | { |
1571 | struct platform_device *pdev = dss_get_core_pdev(); | 1595 | struct platform_device *pdev = dss_get_core_pdev(); |
1572 | struct omap_dss_device *dssdev = NULL; | ||
1573 | int i, r; | 1596 | int i, r; |
1574 | 1597 | ||
1575 | mutex_lock(&compat_init_lock); | 1598 | mutex_lock(&compat_init_lock); |
@@ -1579,7 +1602,7 @@ int omapdss_compat_init(void) | |||
1579 | 1602 | ||
1580 | apply_init_priv(); | 1603 | apply_init_priv(); |
1581 | 1604 | ||
1582 | dss_init_overlay_managers(pdev); | 1605 | dss_init_overlay_managers_sysfs(pdev); |
1583 | dss_init_overlays(pdev); | 1606 | dss_init_overlays(pdev); |
1584 | 1607 | ||
1585 | for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) { | 1608 | for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) { |
@@ -1615,12 +1638,9 @@ int omapdss_compat_init(void) | |||
1615 | if (r) | 1638 | if (r) |
1616 | goto err_mgr_ops; | 1639 | goto err_mgr_ops; |
1617 | 1640 | ||
1618 | for_each_dss_dev(dssdev) { | 1641 | r = display_init_sysfs(pdev); |
1619 | r = display_init_sysfs(pdev, dssdev); | 1642 | if (r) |
1620 | /* XXX uninit sysfs files on error */ | 1643 | goto err_disp_sysfs; |
1621 | if (r) | ||
1622 | goto err_disp_sysfs; | ||
1623 | } | ||
1624 | 1644 | ||
1625 | dispc_runtime_get(); | 1645 | dispc_runtime_get(); |
1626 | 1646 | ||
@@ -1637,12 +1657,13 @@ out: | |||
1637 | 1657 | ||
1638 | err_init_irq: | 1658 | err_init_irq: |
1639 | dispc_runtime_put(); | 1659 | dispc_runtime_put(); |
1660 | display_uninit_sysfs(pdev); | ||
1640 | 1661 | ||
1641 | err_disp_sysfs: | 1662 | err_disp_sysfs: |
1642 | dss_uninstall_mgr_ops(); | 1663 | dss_uninstall_mgr_ops(); |
1643 | 1664 | ||
1644 | err_mgr_ops: | 1665 | err_mgr_ops: |
1645 | dss_uninit_overlay_managers(pdev); | 1666 | dss_uninit_overlay_managers_sysfs(pdev); |
1646 | dss_uninit_overlays(pdev); | 1667 | dss_uninit_overlays(pdev); |
1647 | 1668 | ||
1648 | compat_refcnt--; | 1669 | compat_refcnt--; |
@@ -1656,7 +1677,6 @@ EXPORT_SYMBOL(omapdss_compat_init); | |||
1656 | void omapdss_compat_uninit(void) | 1677 | void omapdss_compat_uninit(void) |
1657 | { | 1678 | { |
1658 | struct platform_device *pdev = dss_get_core_pdev(); | 1679 | struct platform_device *pdev = dss_get_core_pdev(); |
1659 | struct omap_dss_device *dssdev = NULL; | ||
1660 | 1680 | ||
1661 | mutex_lock(&compat_init_lock); | 1681 | mutex_lock(&compat_init_lock); |
1662 | 1682 | ||
@@ -1665,12 +1685,11 @@ void omapdss_compat_uninit(void) | |||
1665 | 1685 | ||
1666 | dss_dispc_uninitialize_irq(); | 1686 | dss_dispc_uninitialize_irq(); |
1667 | 1687 | ||
1668 | for_each_dss_dev(dssdev) | 1688 | display_uninit_sysfs(pdev); |
1669 | display_uninit_sysfs(pdev, dssdev); | ||
1670 | 1689 | ||
1671 | dss_uninstall_mgr_ops(); | 1690 | dss_uninstall_mgr_ops(); |
1672 | 1691 | ||
1673 | dss_uninit_overlay_managers(pdev); | 1692 | dss_uninit_overlay_managers_sysfs(pdev); |
1674 | dss_uninit_overlays(pdev); | 1693 | dss_uninit_overlays(pdev); |
1675 | out: | 1694 | out: |
1676 | mutex_unlock(&compat_init_lock); | 1695 | mutex_unlock(&compat_init_lock); |
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index c9c2252e3719..1aeb274e30fc 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c | |||
@@ -88,7 +88,7 @@ struct regulator *dss_get_vdds_dsi(void) | |||
88 | if (core.vdds_dsi_reg != NULL) | 88 | if (core.vdds_dsi_reg != NULL) |
89 | return core.vdds_dsi_reg; | 89 | return core.vdds_dsi_reg; |
90 | 90 | ||
91 | reg = regulator_get(&core.pdev->dev, "vdds_dsi"); | 91 | reg = devm_regulator_get(&core.pdev->dev, "vdds_dsi"); |
92 | if (!IS_ERR(reg)) | 92 | if (!IS_ERR(reg)) |
93 | core.vdds_dsi_reg = reg; | 93 | core.vdds_dsi_reg = reg; |
94 | 94 | ||
@@ -102,7 +102,7 @@ struct regulator *dss_get_vdds_sdi(void) | |||
102 | if (core.vdds_sdi_reg != NULL) | 102 | if (core.vdds_sdi_reg != NULL) |
103 | return core.vdds_sdi_reg; | 103 | return core.vdds_sdi_reg; |
104 | 104 | ||
105 | reg = regulator_get(&core.pdev->dev, "vdds_sdi"); | 105 | reg = devm_regulator_get(&core.pdev->dev, "vdds_sdi"); |
106 | if (!IS_ERR(reg)) | 106 | if (!IS_ERR(reg)) |
107 | core.vdds_sdi_reg = reg; | 107 | core.vdds_sdi_reg = reg; |
108 | 108 | ||
@@ -243,6 +243,8 @@ static int __init omap_dss_probe(struct platform_device *pdev) | |||
243 | 243 | ||
244 | if (def_disp_name) | 244 | if (def_disp_name) |
245 | core.default_display_name = def_disp_name; | 245 | core.default_display_name = def_disp_name; |
246 | else if (pdata->default_display_name) | ||
247 | core.default_display_name = pdata->default_display_name; | ||
246 | else if (pdata->default_device) | 248 | else if (pdata->default_device) |
247 | core.default_display_name = pdata->default_device->name; | 249 | core.default_display_name = pdata->default_device->name; |
248 | 250 | ||
@@ -290,37 +292,9 @@ static int dss_bus_match(struct device *dev, struct device_driver *driver) | |||
290 | return strcmp(dssdev->driver_name, driver->name) == 0; | 292 | return strcmp(dssdev->driver_name, driver->name) == 0; |
291 | } | 293 | } |
292 | 294 | ||
293 | static ssize_t device_name_show(struct device *dev, | ||
294 | struct device_attribute *attr, char *buf) | ||
295 | { | ||
296 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
297 | return snprintf(buf, PAGE_SIZE, "%s\n", | ||
298 | dssdev->name ? | ||
299 | dssdev->name : ""); | ||
300 | } | ||
301 | |||
302 | static struct device_attribute default_dev_attrs[] = { | ||
303 | __ATTR(name, S_IRUGO, device_name_show, NULL), | ||
304 | __ATTR_NULL, | ||
305 | }; | ||
306 | |||
307 | static ssize_t driver_name_show(struct device_driver *drv, char *buf) | ||
308 | { | ||
309 | struct omap_dss_driver *dssdrv = to_dss_driver(drv); | ||
310 | return snprintf(buf, PAGE_SIZE, "%s\n", | ||
311 | dssdrv->driver.name ? | ||
312 | dssdrv->driver.name : ""); | ||
313 | } | ||
314 | static struct driver_attribute default_drv_attrs[] = { | ||
315 | __ATTR(name, S_IRUGO, driver_name_show, NULL), | ||
316 | __ATTR_NULL, | ||
317 | }; | ||
318 | |||
319 | static struct bus_type dss_bus_type = { | 295 | static struct bus_type dss_bus_type = { |
320 | .name = "omapdss", | 296 | .name = "omapdss", |
321 | .match = dss_bus_match, | 297 | .match = dss_bus_match, |
322 | .dev_attrs = default_dev_attrs, | ||
323 | .drv_attrs = default_drv_attrs, | ||
324 | }; | 298 | }; |
325 | 299 | ||
326 | static void dss_bus_release(struct device *dev) | 300 | static void dss_bus_release(struct device *dev) |
@@ -377,6 +351,46 @@ static int dss_driver_remove(struct device *dev) | |||
377 | return 0; | 351 | return 0; |
378 | } | 352 | } |
379 | 353 | ||
354 | static int omapdss_default_connect(struct omap_dss_device *dssdev) | ||
355 | { | ||
356 | struct omap_dss_device *out; | ||
357 | struct omap_overlay_manager *mgr; | ||
358 | int r; | ||
359 | |||
360 | out = dssdev->output; | ||
361 | |||
362 | if (out == NULL) | ||
363 | return -ENODEV; | ||
364 | |||
365 | mgr = omap_dss_get_overlay_manager(out->dispc_channel); | ||
366 | if (!mgr) | ||
367 | return -ENODEV; | ||
368 | |||
369 | r = dss_mgr_connect(mgr, out); | ||
370 | if (r) | ||
371 | return r; | ||
372 | |||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static void omapdss_default_disconnect(struct omap_dss_device *dssdev) | ||
377 | { | ||
378 | struct omap_dss_device *out; | ||
379 | struct omap_overlay_manager *mgr; | ||
380 | |||
381 | out = dssdev->output; | ||
382 | |||
383 | if (out == NULL) | ||
384 | return; | ||
385 | |||
386 | mgr = out->manager; | ||
387 | |||
388 | if (mgr == NULL) | ||
389 | return; | ||
390 | |||
391 | dss_mgr_disconnect(mgr, out); | ||
392 | } | ||
393 | |||
380 | int omap_dss_register_driver(struct omap_dss_driver *dssdriver) | 394 | int omap_dss_register_driver(struct omap_dss_driver *dssdriver) |
381 | { | 395 | { |
382 | dssdriver->driver.bus = &dss_bus_type; | 396 | dssdriver->driver.bus = &dss_bus_type; |
@@ -390,6 +404,10 @@ int omap_dss_register_driver(struct omap_dss_driver *dssdriver) | |||
390 | omapdss_default_get_recommended_bpp; | 404 | omapdss_default_get_recommended_bpp; |
391 | if (dssdriver->get_timings == NULL) | 405 | if (dssdriver->get_timings == NULL) |
392 | dssdriver->get_timings = omapdss_default_get_timings; | 406 | dssdriver->get_timings = omapdss_default_get_timings; |
407 | if (dssdriver->connect == NULL) | ||
408 | dssdriver->connect = omapdss_default_connect; | ||
409 | if (dssdriver->disconnect == NULL) | ||
410 | dssdriver->disconnect = omapdss_default_disconnect; | ||
393 | 411 | ||
394 | return driver_register(&dssdriver->driver); | 412 | return driver_register(&dssdriver->driver); |
395 | } | 413 | } |
@@ -419,29 +437,33 @@ struct omap_dss_device *dss_alloc_and_init_device(struct device *parent) | |||
419 | if (!dssdev) | 437 | if (!dssdev) |
420 | return NULL; | 438 | return NULL; |
421 | 439 | ||
422 | dssdev->dev.bus = &dss_bus_type; | 440 | dssdev->old_dev.bus = &dss_bus_type; |
423 | dssdev->dev.parent = parent; | 441 | dssdev->old_dev.parent = parent; |
424 | dssdev->dev.release = omap_dss_dev_release; | 442 | dssdev->old_dev.release = omap_dss_dev_release; |
425 | dev_set_name(&dssdev->dev, "display%d", disp_num_counter++); | 443 | dev_set_name(&dssdev->old_dev, "display%d", disp_num_counter++); |
426 | 444 | ||
427 | device_initialize(&dssdev->dev); | 445 | device_initialize(&dssdev->old_dev); |
428 | 446 | ||
429 | return dssdev; | 447 | return dssdev; |
430 | } | 448 | } |
431 | 449 | ||
432 | int dss_add_device(struct omap_dss_device *dssdev) | 450 | int dss_add_device(struct omap_dss_device *dssdev) |
433 | { | 451 | { |
434 | return device_add(&dssdev->dev); | 452 | dssdev->dev = &dssdev->old_dev; |
453 | |||
454 | omapdss_register_display(dssdev); | ||
455 | return device_add(&dssdev->old_dev); | ||
435 | } | 456 | } |
436 | 457 | ||
437 | void dss_put_device(struct omap_dss_device *dssdev) | 458 | void dss_put_device(struct omap_dss_device *dssdev) |
438 | { | 459 | { |
439 | put_device(&dssdev->dev); | 460 | put_device(&dssdev->old_dev); |
440 | } | 461 | } |
441 | 462 | ||
442 | void dss_unregister_device(struct omap_dss_device *dssdev) | 463 | void dss_unregister_device(struct omap_dss_device *dssdev) |
443 | { | 464 | { |
444 | device_unregister(&dssdev->dev); | 465 | device_unregister(&dssdev->old_dev); |
466 | omapdss_unregister_display(dssdev); | ||
445 | } | 467 | } |
446 | 468 | ||
447 | static int dss_unregister_dss_dev(struct device *dev, void *data) | 469 | static int dss_unregister_dss_dev(struct device *dev, void *data) |
@@ -618,16 +640,6 @@ static int __init omap_dss_init(void) | |||
618 | 640 | ||
619 | static void __exit omap_dss_exit(void) | 641 | static void __exit omap_dss_exit(void) |
620 | { | 642 | { |
621 | if (core.vdds_dsi_reg != NULL) { | ||
622 | regulator_put(core.vdds_dsi_reg); | ||
623 | core.vdds_dsi_reg = NULL; | ||
624 | } | ||
625 | |||
626 | if (core.vdds_sdi_reg != NULL) { | ||
627 | regulator_put(core.vdds_sdi_reg); | ||
628 | core.vdds_sdi_reg = NULL; | ||
629 | } | ||
630 | |||
631 | omap_dss_unregister_drivers(); | 643 | omap_dss_unregister_drivers(); |
632 | 644 | ||
633 | omap_dss_bus_unregister(); | 645 | omap_dss_bus_unregister(); |
diff --git a/drivers/video/omap2/dss/dispc-compat.c b/drivers/video/omap2/dss/dispc-compat.c index 928884c9a0a9..83779c2b292a 100644 --- a/drivers/video/omap2/dss/dispc-compat.c +++ b/drivers/video/omap2/dss/dispc-compat.c | |||
@@ -360,8 +360,7 @@ static void dispc_error_worker(struct work_struct *work) | |||
360 | if (bit & errors) { | 360 | if (bit & errors) { |
361 | DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n", | 361 | DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n", |
362 | ovl->name); | 362 | ovl->name); |
363 | dispc_ovl_enable(ovl->id, false); | 363 | ovl->disable(ovl); |
364 | dispc_mgr_go(ovl->manager->id); | ||
365 | msleep(50); | 364 | msleep(50); |
366 | } | 365 | } |
367 | } | 366 | } |
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index b33b0169bb3b..02a7340111df 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c | |||
@@ -103,6 +103,7 @@ static struct { | |||
103 | int irq; | 103 | int irq; |
104 | 104 | ||
105 | unsigned long core_clk_rate; | 105 | unsigned long core_clk_rate; |
106 | unsigned long tv_pclk_rate; | ||
106 | 107 | ||
107 | u32 fifo_size[DISPC_MAX_NR_FIFOS]; | 108 | u32 fifo_size[DISPC_MAX_NR_FIFOS]; |
108 | /* maps which plane is using a fifo. fifo-id -> plane-id */ | 109 | /* maps which plane is using a fifo. fifo-id -> plane-id */ |
@@ -3071,22 +3072,15 @@ unsigned long dispc_mgr_pclk_rate(enum omap_channel channel) | |||
3071 | 3072 | ||
3072 | return r / pcd; | 3073 | return r / pcd; |
3073 | } else { | 3074 | } else { |
3074 | enum dss_hdmi_venc_clk_source_select source; | 3075 | return dispc.tv_pclk_rate; |
3075 | |||
3076 | source = dss_get_hdmi_venc_clk_source(); | ||
3077 | |||
3078 | switch (source) { | ||
3079 | case DSS_VENC_TV_CLK: | ||
3080 | return venc_get_pixel_clock(); | ||
3081 | case DSS_HDMI_M_PCLK: | ||
3082 | return hdmi_get_pixel_clock(); | ||
3083 | default: | ||
3084 | BUG(); | ||
3085 | return 0; | ||
3086 | } | ||
3087 | } | 3076 | } |
3088 | } | 3077 | } |
3089 | 3078 | ||
3079 | void dispc_set_tv_pclk(unsigned long pclk) | ||
3080 | { | ||
3081 | dispc.tv_pclk_rate = pclk; | ||
3082 | } | ||
3083 | |||
3090 | unsigned long dispc_core_clk_rate(void) | 3084 | unsigned long dispc_core_clk_rate(void) |
3091 | { | 3085 | { |
3092 | return dispc.core_clk_rate; | 3086 | return dispc.core_clk_rate; |
@@ -3710,6 +3704,8 @@ static int __init omap_dispchw_probe(struct platform_device *pdev) | |||
3710 | 3704 | ||
3711 | dispc_runtime_put(); | 3705 | dispc_runtime_put(); |
3712 | 3706 | ||
3707 | dss_init_overlay_managers(); | ||
3708 | |||
3713 | dss_debugfs_create_file("dispc", dispc_dump_regs); | 3709 | dss_debugfs_create_file("dispc", dispc_dump_regs); |
3714 | 3710 | ||
3715 | return 0; | 3711 | return 0; |
@@ -3723,6 +3719,8 @@ static int __exit omap_dispchw_remove(struct platform_device *pdev) | |||
3723 | { | 3719 | { |
3724 | pm_runtime_disable(&pdev->dev); | 3720 | pm_runtime_disable(&pdev->dev); |
3725 | 3721 | ||
3722 | dss_uninit_overlay_managers(); | ||
3723 | |||
3726 | return 0; | 3724 | return 0; |
3727 | } | 3725 | } |
3728 | 3726 | ||
diff --git a/drivers/video/omap2/dss/display-sysfs.c b/drivers/video/omap2/dss/display-sysfs.c index 18211a9ab354..21d7f77df702 100644 --- a/drivers/video/omap2/dss/display-sysfs.c +++ b/drivers/video/omap2/dss/display-sysfs.c | |||
@@ -22,42 +22,69 @@ | |||
22 | 22 | ||
23 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/jiffies.h> | ||
26 | #include <linux/platform_device.h> | 25 | #include <linux/platform_device.h> |
26 | #include <linux/sysfs.h> | ||
27 | 27 | ||
28 | #include <video/omapdss.h> | 28 | #include <video/omapdss.h> |
29 | #include "dss.h" | 29 | #include "dss.h" |
30 | #include "dss_features.h" | 30 | |
31 | static struct omap_dss_device *to_dss_device_sysfs(struct device *dev) | ||
32 | { | ||
33 | struct omap_dss_device *dssdev = NULL; | ||
34 | |||
35 | for_each_dss_dev(dssdev) { | ||
36 | if (dssdev->dev == dev) { | ||
37 | omap_dss_put_device(dssdev); | ||
38 | return dssdev; | ||
39 | } | ||
40 | } | ||
41 | |||
42 | return NULL; | ||
43 | } | ||
44 | |||
45 | static ssize_t display_name_show(struct device *dev, | ||
46 | struct device_attribute *attr, char *buf) | ||
47 | { | ||
48 | struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); | ||
49 | |||
50 | return snprintf(buf, PAGE_SIZE, "%s\n", | ||
51 | dssdev->name ? | ||
52 | dssdev->name : ""); | ||
53 | } | ||
31 | 54 | ||
32 | static ssize_t display_enabled_show(struct device *dev, | 55 | static ssize_t display_enabled_show(struct device *dev, |
33 | struct device_attribute *attr, char *buf) | 56 | struct device_attribute *attr, char *buf) |
34 | { | 57 | { |
35 | struct omap_dss_device *dssdev = to_dss_device(dev); | 58 | struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); |
36 | bool enabled = dssdev->state != OMAP_DSS_DISPLAY_DISABLED; | ||
37 | 59 | ||
38 | return snprintf(buf, PAGE_SIZE, "%d\n", enabled); | 60 | return snprintf(buf, PAGE_SIZE, "%d\n", |
61 | omapdss_device_is_enabled(dssdev)); | ||
39 | } | 62 | } |
40 | 63 | ||
41 | static ssize_t display_enabled_store(struct device *dev, | 64 | static ssize_t display_enabled_store(struct device *dev, |
42 | struct device_attribute *attr, | 65 | struct device_attribute *attr, |
43 | const char *buf, size_t size) | 66 | const char *buf, size_t size) |
44 | { | 67 | { |
45 | struct omap_dss_device *dssdev = to_dss_device(dev); | 68 | struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); |
46 | int r; | 69 | int r; |
47 | bool enabled; | 70 | bool enable; |
48 | 71 | ||
49 | r = strtobool(buf, &enabled); | 72 | r = strtobool(buf, &enable); |
50 | if (r) | 73 | if (r) |
51 | return r; | 74 | return r; |
52 | 75 | ||
53 | if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) { | 76 | if (enable == omapdss_device_is_enabled(dssdev)) |
54 | if (enabled) { | 77 | return size; |
55 | r = dssdev->driver->enable(dssdev); | 78 | |
56 | if (r) | 79 | if (omapdss_device_is_connected(dssdev) == false) |
57 | return r; | 80 | return -ENODEV; |
58 | } else { | 81 | |
59 | dssdev->driver->disable(dssdev); | 82 | if (enable) { |
60 | } | 83 | r = dssdev->driver->enable(dssdev); |
84 | if (r) | ||
85 | return r; | ||
86 | } else { | ||
87 | dssdev->driver->disable(dssdev); | ||
61 | } | 88 | } |
62 | 89 | ||
63 | return size; | 90 | return size; |
@@ -66,7 +93,7 @@ static ssize_t display_enabled_store(struct device *dev, | |||
66 | static ssize_t display_tear_show(struct device *dev, | 93 | static ssize_t display_tear_show(struct device *dev, |
67 | struct device_attribute *attr, char *buf) | 94 | struct device_attribute *attr, char *buf) |
68 | { | 95 | { |
69 | struct omap_dss_device *dssdev = to_dss_device(dev); | 96 | struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); |
70 | return snprintf(buf, PAGE_SIZE, "%d\n", | 97 | return snprintf(buf, PAGE_SIZE, "%d\n", |
71 | dssdev->driver->get_te ? | 98 | dssdev->driver->get_te ? |
72 | dssdev->driver->get_te(dssdev) : 0); | 99 | dssdev->driver->get_te(dssdev) : 0); |
@@ -75,7 +102,7 @@ static ssize_t display_tear_show(struct device *dev, | |||
75 | static ssize_t display_tear_store(struct device *dev, | 102 | static ssize_t display_tear_store(struct device *dev, |
76 | struct device_attribute *attr, const char *buf, size_t size) | 103 | struct device_attribute *attr, const char *buf, size_t size) |
77 | { | 104 | { |
78 | struct omap_dss_device *dssdev = to_dss_device(dev); | 105 | struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); |
79 | int r; | 106 | int r; |
80 | bool te; | 107 | bool te; |
81 | 108 | ||
@@ -96,7 +123,7 @@ static ssize_t display_tear_store(struct device *dev, | |||
96 | static ssize_t display_timings_show(struct device *dev, | 123 | static ssize_t display_timings_show(struct device *dev, |
97 | struct device_attribute *attr, char *buf) | 124 | struct device_attribute *attr, char *buf) |
98 | { | 125 | { |
99 | struct omap_dss_device *dssdev = to_dss_device(dev); | 126 | struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); |
100 | struct omap_video_timings t; | 127 | struct omap_video_timings t; |
101 | 128 | ||
102 | if (!dssdev->driver->get_timings) | 129 | if (!dssdev->driver->get_timings) |
@@ -113,7 +140,7 @@ static ssize_t display_timings_show(struct device *dev, | |||
113 | static ssize_t display_timings_store(struct device *dev, | 140 | static ssize_t display_timings_store(struct device *dev, |
114 | struct device_attribute *attr, const char *buf, size_t size) | 141 | struct device_attribute *attr, const char *buf, size_t size) |
115 | { | 142 | { |
116 | struct omap_dss_device *dssdev = to_dss_device(dev); | 143 | struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); |
117 | struct omap_video_timings t = dssdev->panel.timings; | 144 | struct omap_video_timings t = dssdev->panel.timings; |
118 | int r, found; | 145 | int r, found; |
119 | 146 | ||
@@ -152,7 +179,7 @@ static ssize_t display_timings_store(struct device *dev, | |||
152 | static ssize_t display_rotate_show(struct device *dev, | 179 | static ssize_t display_rotate_show(struct device *dev, |
153 | struct device_attribute *attr, char *buf) | 180 | struct device_attribute *attr, char *buf) |
154 | { | 181 | { |
155 | struct omap_dss_device *dssdev = to_dss_device(dev); | 182 | struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); |
156 | int rotate; | 183 | int rotate; |
157 | if (!dssdev->driver->get_rotate) | 184 | if (!dssdev->driver->get_rotate) |
158 | return -ENOENT; | 185 | return -ENOENT; |
@@ -163,7 +190,7 @@ static ssize_t display_rotate_show(struct device *dev, | |||
163 | static ssize_t display_rotate_store(struct device *dev, | 190 | static ssize_t display_rotate_store(struct device *dev, |
164 | struct device_attribute *attr, const char *buf, size_t size) | 191 | struct device_attribute *attr, const char *buf, size_t size) |
165 | { | 192 | { |
166 | struct omap_dss_device *dssdev = to_dss_device(dev); | 193 | struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); |
167 | int rot, r; | 194 | int rot, r; |
168 | 195 | ||
169 | if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate) | 196 | if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate) |
@@ -183,7 +210,7 @@ static ssize_t display_rotate_store(struct device *dev, | |||
183 | static ssize_t display_mirror_show(struct device *dev, | 210 | static ssize_t display_mirror_show(struct device *dev, |
184 | struct device_attribute *attr, char *buf) | 211 | struct device_attribute *attr, char *buf) |
185 | { | 212 | { |
186 | struct omap_dss_device *dssdev = to_dss_device(dev); | 213 | struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); |
187 | int mirror; | 214 | int mirror; |
188 | if (!dssdev->driver->get_mirror) | 215 | if (!dssdev->driver->get_mirror) |
189 | return -ENOENT; | 216 | return -ENOENT; |
@@ -194,7 +221,7 @@ static ssize_t display_mirror_show(struct device *dev, | |||
194 | static ssize_t display_mirror_store(struct device *dev, | 221 | static ssize_t display_mirror_store(struct device *dev, |
195 | struct device_attribute *attr, const char *buf, size_t size) | 222 | struct device_attribute *attr, const char *buf, size_t size) |
196 | { | 223 | { |
197 | struct omap_dss_device *dssdev = to_dss_device(dev); | 224 | struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); |
198 | int r; | 225 | int r; |
199 | bool mirror; | 226 | bool mirror; |
200 | 227 | ||
@@ -215,7 +242,7 @@ static ssize_t display_mirror_store(struct device *dev, | |||
215 | static ssize_t display_wss_show(struct device *dev, | 242 | static ssize_t display_wss_show(struct device *dev, |
216 | struct device_attribute *attr, char *buf) | 243 | struct device_attribute *attr, char *buf) |
217 | { | 244 | { |
218 | struct omap_dss_device *dssdev = to_dss_device(dev); | 245 | struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); |
219 | unsigned int wss; | 246 | unsigned int wss; |
220 | 247 | ||
221 | if (!dssdev->driver->get_wss) | 248 | if (!dssdev->driver->get_wss) |
@@ -229,7 +256,7 @@ static ssize_t display_wss_show(struct device *dev, | |||
229 | static ssize_t display_wss_store(struct device *dev, | 256 | static ssize_t display_wss_store(struct device *dev, |
230 | struct device_attribute *attr, const char *buf, size_t size) | 257 | struct device_attribute *attr, const char *buf, size_t size) |
231 | { | 258 | { |
232 | struct omap_dss_device *dssdev = to_dss_device(dev); | 259 | struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); |
233 | u32 wss; | 260 | u32 wss; |
234 | int r; | 261 | int r; |
235 | 262 | ||
@@ -250,6 +277,7 @@ static ssize_t display_wss_store(struct device *dev, | |||
250 | return size; | 277 | return size; |
251 | } | 278 | } |
252 | 279 | ||
280 | static DEVICE_ATTR(name, S_IRUGO, display_name_show, NULL); | ||
253 | static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR, | 281 | static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR, |
254 | display_enabled_show, display_enabled_store); | 282 | display_enabled_show, display_enabled_store); |
255 | static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR, | 283 | static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR, |
@@ -263,59 +291,55 @@ static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR, | |||
263 | static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR, | 291 | static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR, |
264 | display_wss_show, display_wss_store); | 292 | display_wss_show, display_wss_store); |
265 | 293 | ||
266 | static struct device_attribute *display_sysfs_attrs[] = { | 294 | static const struct attribute *display_sysfs_attrs[] = { |
267 | &dev_attr_enabled, | 295 | &dev_attr_name.attr, |
268 | &dev_attr_tear_elim, | 296 | &dev_attr_enabled.attr, |
269 | &dev_attr_timings, | 297 | &dev_attr_tear_elim.attr, |
270 | &dev_attr_rotate, | 298 | &dev_attr_timings.attr, |
271 | &dev_attr_mirror, | 299 | &dev_attr_rotate.attr, |
272 | &dev_attr_wss, | 300 | &dev_attr_mirror.attr, |
301 | &dev_attr_wss.attr, | ||
273 | NULL | 302 | NULL |
274 | }; | 303 | }; |
275 | 304 | ||
276 | int display_init_sysfs(struct platform_device *pdev, | 305 | int display_init_sysfs(struct platform_device *pdev) |
277 | struct omap_dss_device *dssdev) | ||
278 | { | 306 | { |
279 | struct device_attribute *attr; | 307 | struct omap_dss_device *dssdev = NULL; |
280 | int i, r; | 308 | int r; |
281 | 309 | ||
282 | /* create device sysfs files */ | 310 | for_each_dss_dev(dssdev) { |
283 | i = 0; | 311 | struct kobject *kobj = &dssdev->dev->kobj; |
284 | while ((attr = display_sysfs_attrs[i++]) != NULL) { | ||
285 | r = device_create_file(&dssdev->dev, attr); | ||
286 | if (r) { | ||
287 | for (i = i - 2; i >= 0; i--) { | ||
288 | attr = display_sysfs_attrs[i]; | ||
289 | device_remove_file(&dssdev->dev, attr); | ||
290 | } | ||
291 | 312 | ||
292 | DSSERR("failed to create sysfs file\n"); | 313 | r = sysfs_create_files(kobj, display_sysfs_attrs); |
293 | return r; | 314 | if (r) { |
315 | DSSERR("failed to create sysfs files\n"); | ||
316 | goto err; | ||
294 | } | 317 | } |
295 | } | ||
296 | 318 | ||
297 | /* create display? sysfs links */ | 319 | r = sysfs_create_link(&pdev->dev.kobj, kobj, dssdev->alias); |
298 | r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj, | 320 | if (r) { |
299 | dev_name(&dssdev->dev)); | 321 | sysfs_remove_files(kobj, display_sysfs_attrs); |
300 | if (r) { | ||
301 | while ((attr = display_sysfs_attrs[i++]) != NULL) | ||
302 | device_remove_file(&dssdev->dev, attr); | ||
303 | 322 | ||
304 | DSSERR("failed to create sysfs display link\n"); | 323 | DSSERR("failed to create sysfs display link\n"); |
305 | return r; | 324 | goto err; |
325 | } | ||
306 | } | 326 | } |
307 | 327 | ||
308 | return 0; | 328 | return 0; |
329 | |||
330 | err: | ||
331 | display_uninit_sysfs(pdev); | ||
332 | |||
333 | return r; | ||
309 | } | 334 | } |
310 | 335 | ||
311 | void display_uninit_sysfs(struct platform_device *pdev, | 336 | void display_uninit_sysfs(struct platform_device *pdev) |
312 | struct omap_dss_device *dssdev) | ||
313 | { | 337 | { |
314 | struct device_attribute *attr; | 338 | struct omap_dss_device *dssdev = NULL; |
315 | int i = 0; | ||
316 | |||
317 | sysfs_remove_link(&pdev->dev.kobj, dev_name(&dssdev->dev)); | ||
318 | 339 | ||
319 | while ((attr = display_sysfs_attrs[i++]) != NULL) | 340 | for_each_dss_dev(dssdev) { |
320 | device_remove_file(&dssdev->dev, attr); | 341 | sysfs_remove_link(&pdev->dev.kobj, dssdev->alias); |
342 | sysfs_remove_files(&dssdev->dev->kobj, | ||
343 | display_sysfs_attrs); | ||
344 | } | ||
321 | } | 345 | } |
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index 0aa8ad8f9667..fafe7c941a60 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c | |||
@@ -61,6 +61,7 @@ int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev) | |||
61 | case OMAP_DISPLAY_TYPE_VENC: | 61 | case OMAP_DISPLAY_TYPE_VENC: |
62 | case OMAP_DISPLAY_TYPE_SDI: | 62 | case OMAP_DISPLAY_TYPE_SDI: |
63 | case OMAP_DISPLAY_TYPE_HDMI: | 63 | case OMAP_DISPLAY_TYPE_HDMI: |
64 | case OMAP_DISPLAY_TYPE_DVI: | ||
64 | return 24; | 65 | return 24; |
65 | default: | 66 | default: |
66 | BUG(); | 67 | BUG(); |
@@ -76,110 +77,154 @@ void omapdss_default_get_timings(struct omap_dss_device *dssdev, | |||
76 | } | 77 | } |
77 | EXPORT_SYMBOL(omapdss_default_get_timings); | 78 | EXPORT_SYMBOL(omapdss_default_get_timings); |
78 | 79 | ||
79 | static int dss_suspend_device(struct device *dev, void *data) | 80 | int dss_suspend_all_devices(void) |
80 | { | 81 | { |
81 | struct omap_dss_device *dssdev = to_dss_device(dev); | 82 | struct omap_dss_device *dssdev = NULL; |
82 | |||
83 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { | ||
84 | dssdev->activate_after_resume = false; | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | dssdev->driver->disable(dssdev); | ||
89 | |||
90 | dssdev->activate_after_resume = true; | ||
91 | 83 | ||
92 | return 0; | 84 | for_each_dss_dev(dssdev) { |
93 | } | 85 | if (!dssdev->driver) |
86 | continue; | ||
94 | 87 | ||
95 | int dss_suspend_all_devices(void) | 88 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { |
96 | { | 89 | dssdev->driver->disable(dssdev); |
97 | int r; | 90 | dssdev->activate_after_resume = true; |
98 | struct bus_type *bus = dss_get_bus(); | 91 | } else { |
99 | 92 | dssdev->activate_after_resume = false; | |
100 | r = bus_for_each_dev(bus, NULL, NULL, dss_suspend_device); | 93 | } |
101 | if (r) { | ||
102 | /* resume all displays that were suspended */ | ||
103 | dss_resume_all_devices(); | ||
104 | return r; | ||
105 | } | 94 | } |
106 | 95 | ||
107 | return 0; | 96 | return 0; |
108 | } | 97 | } |
109 | 98 | ||
110 | static int dss_resume_device(struct device *dev, void *data) | 99 | int dss_resume_all_devices(void) |
111 | { | 100 | { |
112 | int r; | 101 | struct omap_dss_device *dssdev = NULL; |
113 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
114 | 102 | ||
115 | if (dssdev->activate_after_resume) { | 103 | for_each_dss_dev(dssdev) { |
116 | r = dssdev->driver->enable(dssdev); | 104 | if (!dssdev->driver) |
117 | if (r) | 105 | continue; |
118 | return r; | ||
119 | } | ||
120 | 106 | ||
121 | dssdev->activate_after_resume = false; | 107 | if (dssdev->activate_after_resume) { |
108 | dssdev->driver->enable(dssdev); | ||
109 | dssdev->activate_after_resume = false; | ||
110 | } | ||
111 | } | ||
122 | 112 | ||
123 | return 0; | 113 | return 0; |
124 | } | 114 | } |
125 | 115 | ||
126 | int dss_resume_all_devices(void) | 116 | void dss_disable_all_devices(void) |
127 | { | 117 | { |
128 | struct bus_type *bus = dss_get_bus(); | 118 | struct omap_dss_device *dssdev = NULL; |
119 | |||
120 | for_each_dss_dev(dssdev) { | ||
121 | if (!dssdev->driver) | ||
122 | continue; | ||
129 | 123 | ||
130 | return bus_for_each_dev(bus, NULL, NULL, dss_resume_device); | 124 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) |
125 | dssdev->driver->disable(dssdev); | ||
126 | } | ||
131 | } | 127 | } |
132 | 128 | ||
133 | static int dss_disable_device(struct device *dev, void *data) | 129 | static LIST_HEAD(panel_list); |
130 | static DEFINE_MUTEX(panel_list_mutex); | ||
131 | static int disp_num_counter; | ||
132 | |||
133 | int omapdss_register_display(struct omap_dss_device *dssdev) | ||
134 | { | 134 | { |
135 | struct omap_dss_device *dssdev = to_dss_device(dev); | 135 | struct omap_dss_driver *drv = dssdev->driver; |
136 | 136 | ||
137 | if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) | 137 | snprintf(dssdev->alias, sizeof(dssdev->alias), |
138 | dssdev->driver->disable(dssdev); | 138 | "display%d", disp_num_counter++); |
139 | 139 | ||
140 | if (drv && drv->get_resolution == NULL) | ||
141 | drv->get_resolution = omapdss_default_get_resolution; | ||
142 | if (drv && drv->get_recommended_bpp == NULL) | ||
143 | drv->get_recommended_bpp = omapdss_default_get_recommended_bpp; | ||
144 | if (drv && drv->get_timings == NULL) | ||
145 | drv->get_timings = omapdss_default_get_timings; | ||
146 | |||
147 | mutex_lock(&panel_list_mutex); | ||
148 | list_add_tail(&dssdev->panel_list, &panel_list); | ||
149 | mutex_unlock(&panel_list_mutex); | ||
140 | return 0; | 150 | return 0; |
141 | } | 151 | } |
152 | EXPORT_SYMBOL(omapdss_register_display); | ||
142 | 153 | ||
143 | void dss_disable_all_devices(void) | 154 | void omapdss_unregister_display(struct omap_dss_device *dssdev) |
144 | { | 155 | { |
145 | struct bus_type *bus = dss_get_bus(); | 156 | mutex_lock(&panel_list_mutex); |
146 | bus_for_each_dev(bus, NULL, NULL, dss_disable_device); | 157 | list_del(&dssdev->panel_list); |
158 | mutex_unlock(&panel_list_mutex); | ||
147 | } | 159 | } |
160 | EXPORT_SYMBOL(omapdss_unregister_display); | ||
148 | 161 | ||
149 | 162 | struct omap_dss_device *omap_dss_get_device(struct omap_dss_device *dssdev) | |
150 | void omap_dss_get_device(struct omap_dss_device *dssdev) | ||
151 | { | 163 | { |
152 | get_device(&dssdev->dev); | 164 | if (!try_module_get(dssdev->owner)) |
165 | return NULL; | ||
166 | |||
167 | if (get_device(dssdev->dev) == NULL) { | ||
168 | module_put(dssdev->owner); | ||
169 | return NULL; | ||
170 | } | ||
171 | |||
172 | return dssdev; | ||
153 | } | 173 | } |
154 | EXPORT_SYMBOL(omap_dss_get_device); | 174 | EXPORT_SYMBOL(omap_dss_get_device); |
155 | 175 | ||
156 | void omap_dss_put_device(struct omap_dss_device *dssdev) | 176 | void omap_dss_put_device(struct omap_dss_device *dssdev) |
157 | { | 177 | { |
158 | put_device(&dssdev->dev); | 178 | put_device(dssdev->dev); |
179 | module_put(dssdev->owner); | ||
159 | } | 180 | } |
160 | EXPORT_SYMBOL(omap_dss_put_device); | 181 | EXPORT_SYMBOL(omap_dss_put_device); |
161 | 182 | ||
162 | /* ref count of the found device is incremented. ref count | 183 | /* |
163 | * of from-device is decremented. */ | 184 | * ref count of the found device is incremented. |
185 | * ref count of from-device is decremented. | ||
186 | */ | ||
164 | struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from) | 187 | struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from) |
165 | { | 188 | { |
166 | struct device *dev; | 189 | struct list_head *l; |
167 | struct device *dev_start = NULL; | 190 | struct omap_dss_device *dssdev; |
168 | struct omap_dss_device *dssdev = NULL; | 191 | |
192 | mutex_lock(&panel_list_mutex); | ||
169 | 193 | ||
170 | int match(struct device *dev, void *data) | 194 | if (list_empty(&panel_list)) { |
171 | { | 195 | dssdev = NULL; |
172 | return 1; | 196 | goto out; |
173 | } | 197 | } |
174 | 198 | ||
175 | if (from) | 199 | if (from == NULL) { |
176 | dev_start = &from->dev; | 200 | dssdev = list_first_entry(&panel_list, struct omap_dss_device, |
177 | dev = bus_find_device(dss_get_bus(), dev_start, NULL, match); | 201 | panel_list); |
178 | if (dev) | 202 | omap_dss_get_device(dssdev); |
179 | dssdev = to_dss_device(dev); | 203 | goto out; |
180 | if (from) | 204 | } |
181 | put_device(&from->dev); | 205 | |
206 | omap_dss_put_device(from); | ||
207 | |||
208 | list_for_each(l, &panel_list) { | ||
209 | dssdev = list_entry(l, struct omap_dss_device, panel_list); | ||
210 | if (dssdev == from) { | ||
211 | if (list_is_last(l, &panel_list)) { | ||
212 | dssdev = NULL; | ||
213 | goto out; | ||
214 | } | ||
215 | |||
216 | dssdev = list_entry(l->next, struct omap_dss_device, | ||
217 | panel_list); | ||
218 | omap_dss_get_device(dssdev); | ||
219 | goto out; | ||
220 | } | ||
221 | } | ||
182 | 222 | ||
223 | WARN(1, "'from' dssdev not found\n"); | ||
224 | |||
225 | dssdev = NULL; | ||
226 | out: | ||
227 | mutex_unlock(&panel_list_mutex); | ||
183 | return dssdev; | 228 | return dssdev; |
184 | } | 229 | } |
185 | EXPORT_SYMBOL(omap_dss_get_next_device); | 230 | EXPORT_SYMBOL(omap_dss_get_next_device); |
@@ -198,24 +243,72 @@ struct omap_dss_device *omap_dss_find_device(void *data, | |||
198 | } | 243 | } |
199 | EXPORT_SYMBOL(omap_dss_find_device); | 244 | EXPORT_SYMBOL(omap_dss_find_device); |
200 | 245 | ||
201 | int omap_dss_start_device(struct omap_dss_device *dssdev) | 246 | void videomode_to_omap_video_timings(const struct videomode *vm, |
247 | struct omap_video_timings *ovt) | ||
202 | { | 248 | { |
203 | if (!dssdev->driver) { | 249 | memset(ovt, 0, sizeof(*ovt)); |
204 | DSSDBG("no driver\n"); | 250 | |
205 | return -ENODEV; | 251 | ovt->pixel_clock = vm->pixelclock / 1000; |
206 | } | 252 | ovt->x_res = vm->hactive; |
207 | 253 | ovt->hbp = vm->hback_porch; | |
208 | if (!try_module_get(dssdev->dev.driver->owner)) { | 254 | ovt->hfp = vm->hfront_porch; |
209 | return -ENODEV; | 255 | ovt->hsw = vm->hsync_len; |
210 | } | 256 | ovt->y_res = vm->vactive; |
211 | 257 | ovt->vbp = vm->vback_porch; | |
212 | return 0; | 258 | ovt->vfp = vm->vfront_porch; |
259 | ovt->vsw = vm->vsync_len; | ||
260 | |||
261 | ovt->vsync_level = vm->flags & DISPLAY_FLAGS_VSYNC_HIGH ? | ||
262 | OMAPDSS_SIG_ACTIVE_HIGH : | ||
263 | OMAPDSS_SIG_ACTIVE_LOW; | ||
264 | ovt->hsync_level = vm->flags & DISPLAY_FLAGS_HSYNC_HIGH ? | ||
265 | OMAPDSS_SIG_ACTIVE_HIGH : | ||
266 | OMAPDSS_SIG_ACTIVE_LOW; | ||
267 | ovt->de_level = vm->flags & DISPLAY_FLAGS_DE_HIGH ? | ||
268 | OMAPDSS_SIG_ACTIVE_HIGH : | ||
269 | OMAPDSS_SIG_ACTIVE_HIGH; | ||
270 | ovt->data_pclk_edge = vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE ? | ||
271 | OMAPDSS_DRIVE_SIG_RISING_EDGE : | ||
272 | OMAPDSS_DRIVE_SIG_FALLING_EDGE; | ||
273 | |||
274 | ovt->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; | ||
213 | } | 275 | } |
214 | EXPORT_SYMBOL(omap_dss_start_device); | 276 | EXPORT_SYMBOL(videomode_to_omap_video_timings); |
215 | 277 | ||
216 | void omap_dss_stop_device(struct omap_dss_device *dssdev) | 278 | void omap_video_timings_to_videomode(const struct omap_video_timings *ovt, |
279 | struct videomode *vm) | ||
217 | { | 280 | { |
218 | module_put(dssdev->dev.driver->owner); | 281 | memset(vm, 0, sizeof(*vm)); |
282 | |||
283 | vm->pixelclock = ovt->pixel_clock * 1000; | ||
284 | |||
285 | vm->hactive = ovt->x_res; | ||
286 | vm->hback_porch = ovt->hbp; | ||
287 | vm->hfront_porch = ovt->hfp; | ||
288 | vm->hsync_len = ovt->hsw; | ||
289 | vm->vactive = ovt->y_res; | ||
290 | vm->vback_porch = ovt->vbp; | ||
291 | vm->vfront_porch = ovt->vfp; | ||
292 | vm->vsync_len = ovt->vsw; | ||
293 | |||
294 | if (ovt->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH) | ||
295 | vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH; | ||
296 | else | ||
297 | vm->flags |= DISPLAY_FLAGS_HSYNC_LOW; | ||
298 | |||
299 | if (ovt->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH) | ||
300 | vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH; | ||
301 | else | ||
302 | vm->flags |= DISPLAY_FLAGS_VSYNC_LOW; | ||
303 | |||
304 | if (ovt->de_level == OMAPDSS_SIG_ACTIVE_HIGH) | ||
305 | vm->flags |= DISPLAY_FLAGS_DE_HIGH; | ||
306 | else | ||
307 | vm->flags |= DISPLAY_FLAGS_DE_LOW; | ||
308 | |||
309 | if (ovt->data_pclk_edge == OMAPDSS_DRIVE_SIG_RISING_EDGE) | ||
310 | vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE; | ||
311 | else | ||
312 | vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE; | ||
219 | } | 313 | } |
220 | EXPORT_SYMBOL(omap_dss_stop_device); | 314 | EXPORT_SYMBOL(omap_video_timings_to_videomode); |
221 | |||
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 757b57f7275a..a6b331ef7763 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c | |||
@@ -37,6 +37,8 @@ | |||
37 | #include "dss_features.h" | 37 | #include "dss_features.h" |
38 | 38 | ||
39 | static struct { | 39 | static struct { |
40 | struct platform_device *pdev; | ||
41 | |||
40 | struct regulator *vdds_dsi_reg; | 42 | struct regulator *vdds_dsi_reg; |
41 | struct platform_device *dsidev; | 43 | struct platform_device *dsidev; |
42 | 44 | ||
@@ -46,7 +48,7 @@ static struct { | |||
46 | struct dss_lcd_mgr_config mgr_config; | 48 | struct dss_lcd_mgr_config mgr_config; |
47 | int data_lines; | 49 | int data_lines; |
48 | 50 | ||
49 | struct omap_dss_output output; | 51 | struct omap_dss_device output; |
50 | } dpi; | 52 | } dpi; |
51 | 53 | ||
52 | static struct platform_device *dpi_get_dsidev(enum omap_channel channel) | 54 | static struct platform_device *dpi_get_dsidev(enum omap_channel channel) |
@@ -129,7 +131,7 @@ static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck, | |||
129 | * shifted. So skip all odd dividers when the pixel clock is on the | 131 | * shifted. So skip all odd dividers when the pixel clock is on the |
130 | * higher side. | 132 | * higher side. |
131 | */ | 133 | */ |
132 | if (ctx->pck_min >= 1000000) { | 134 | if (ctx->pck_min >= 100000000) { |
133 | if (lckd > 1 && lckd % 2 != 0) | 135 | if (lckd > 1 && lckd % 2 != 0) |
134 | return false; | 136 | return false; |
135 | 137 | ||
@@ -156,7 +158,7 @@ static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc, | |||
156 | * shifted. So skip all odd dividers when the pixel clock is on the | 158 | * shifted. So skip all odd dividers when the pixel clock is on the |
157 | * higher side. | 159 | * higher side. |
158 | */ | 160 | */ |
159 | if (regm_dispc > 1 && regm_dispc % 2 != 0 && ctx->pck_min >= 1000000) | 161 | if (regm_dispc > 1 && regm_dispc % 2 != 0 && ctx->pck_min >= 100000000) |
160 | return false; | 162 | return false; |
161 | 163 | ||
162 | ctx->dsi_cinfo.regm_dispc = regm_dispc; | 164 | ctx->dsi_cinfo.regm_dispc = regm_dispc; |
@@ -345,7 +347,7 @@ static void dpi_config_lcd_manager(struct omap_overlay_manager *mgr) | |||
345 | 347 | ||
346 | int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) | 348 | int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) |
347 | { | 349 | { |
348 | struct omap_dss_output *out = &dpi.output; | 350 | struct omap_dss_device *out = &dpi.output; |
349 | int r; | 351 | int r; |
350 | 352 | ||
351 | mutex_lock(&dpi.lock); | 353 | mutex_lock(&dpi.lock); |
@@ -362,12 +364,6 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) | |||
362 | goto err_no_out_mgr; | 364 | goto err_no_out_mgr; |
363 | } | 365 | } |
364 | 366 | ||
365 | r = omap_dss_start_device(dssdev); | ||
366 | if (r) { | ||
367 | DSSERR("failed to start device\n"); | ||
368 | goto err_start_dev; | ||
369 | } | ||
370 | |||
371 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) { | 367 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) { |
372 | r = regulator_enable(dpi.vdds_dsi_reg); | 368 | r = regulator_enable(dpi.vdds_dsi_reg); |
373 | if (r) | 369 | if (r) |
@@ -422,8 +418,6 @@ err_get_dispc: | |||
422 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) | 418 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) |
423 | regulator_disable(dpi.vdds_dsi_reg); | 419 | regulator_disable(dpi.vdds_dsi_reg); |
424 | err_reg_enable: | 420 | err_reg_enable: |
425 | omap_dss_stop_device(dssdev); | ||
426 | err_start_dev: | ||
427 | err_no_out_mgr: | 421 | err_no_out_mgr: |
428 | err_no_reg: | 422 | err_no_reg: |
429 | mutex_unlock(&dpi.lock); | 423 | mutex_unlock(&dpi.lock); |
@@ -450,8 +444,6 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) | |||
450 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) | 444 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) |
451 | regulator_disable(dpi.vdds_dsi_reg); | 445 | regulator_disable(dpi.vdds_dsi_reg); |
452 | 446 | ||
453 | omap_dss_stop_device(dssdev); | ||
454 | |||
455 | mutex_unlock(&dpi.lock); | 447 | mutex_unlock(&dpi.lock); |
456 | } | 448 | } |
457 | EXPORT_SYMBOL(omapdss_dpi_display_disable); | 449 | EXPORT_SYMBOL(omapdss_dpi_display_disable); |
@@ -469,6 +461,16 @@ void omapdss_dpi_set_timings(struct omap_dss_device *dssdev, | |||
469 | } | 461 | } |
470 | EXPORT_SYMBOL(omapdss_dpi_set_timings); | 462 | EXPORT_SYMBOL(omapdss_dpi_set_timings); |
471 | 463 | ||
464 | static void dpi_get_timings(struct omap_dss_device *dssdev, | ||
465 | struct omap_video_timings *timings) | ||
466 | { | ||
467 | mutex_lock(&dpi.lock); | ||
468 | |||
469 | *timings = dpi.timings; | ||
470 | |||
471 | mutex_unlock(&dpi.lock); | ||
472 | } | ||
473 | |||
472 | int dpi_check_timings(struct omap_dss_device *dssdev, | 474 | int dpi_check_timings(struct omap_dss_device *dssdev, |
473 | struct omap_video_timings *timings) | 475 | struct omap_video_timings *timings) |
474 | { | 476 | { |
@@ -542,6 +544,50 @@ static int dpi_verify_dsi_pll(struct platform_device *dsidev) | |||
542 | return 0; | 544 | return 0; |
543 | } | 545 | } |
544 | 546 | ||
547 | static int dpi_init_regulator(void) | ||
548 | { | ||
549 | struct regulator *vdds_dsi; | ||
550 | |||
551 | if (!dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) | ||
552 | return 0; | ||
553 | |||
554 | if (dpi.vdds_dsi_reg) | ||
555 | return 0; | ||
556 | |||
557 | vdds_dsi = dss_get_vdds_dsi(); | ||
558 | |||
559 | if (IS_ERR(vdds_dsi)) { | ||
560 | vdds_dsi = devm_regulator_get(&dpi.pdev->dev, "vdds_dsi"); | ||
561 | if (IS_ERR(vdds_dsi)) { | ||
562 | DSSERR("can't get VDDS_DSI regulator\n"); | ||
563 | return PTR_ERR(vdds_dsi); | ||
564 | } | ||
565 | } | ||
566 | |||
567 | dpi.vdds_dsi_reg = vdds_dsi; | ||
568 | |||
569 | return 0; | ||
570 | } | ||
571 | |||
572 | static void dpi_init_pll(void) | ||
573 | { | ||
574 | struct platform_device *dsidev; | ||
575 | |||
576 | if (dpi.dsidev) | ||
577 | return; | ||
578 | |||
579 | dsidev = dpi_get_dsidev(dpi.output.dispc_channel); | ||
580 | if (!dsidev) | ||
581 | return; | ||
582 | |||
583 | if (dpi_verify_dsi_pll(dsidev)) { | ||
584 | DSSWARN("DSI PLL not operational\n"); | ||
585 | return; | ||
586 | } | ||
587 | |||
588 | dpi.dsidev = dsidev; | ||
589 | } | ||
590 | |||
545 | /* | 591 | /* |
546 | * Return a hardcoded channel for the DPI output. This should work for | 592 | * Return a hardcoded channel for the DPI output. This should work for |
547 | * current use cases, but this can be later expanded to either resolve | 593 | * current use cases, but this can be later expanded to either resolve |
@@ -572,41 +618,6 @@ static enum omap_channel dpi_get_channel(void) | |||
572 | } | 618 | } |
573 | } | 619 | } |
574 | 620 | ||
575 | static int dpi_init_display(struct omap_dss_device *dssdev) | ||
576 | { | ||
577 | struct platform_device *dsidev; | ||
578 | |||
579 | DSSDBG("init_display\n"); | ||
580 | |||
581 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && | ||
582 | dpi.vdds_dsi_reg == NULL) { | ||
583 | struct regulator *vdds_dsi; | ||
584 | |||
585 | vdds_dsi = dss_get_vdds_dsi(); | ||
586 | |||
587 | if (IS_ERR(vdds_dsi)) { | ||
588 | DSSERR("can't get VDDS_DSI regulator\n"); | ||
589 | return PTR_ERR(vdds_dsi); | ||
590 | } | ||
591 | |||
592 | dpi.vdds_dsi_reg = vdds_dsi; | ||
593 | } | ||
594 | |||
595 | dsidev = dpi_get_dsidev(dpi.output.dispc_channel); | ||
596 | |||
597 | if (dsidev && dpi_verify_dsi_pll(dsidev)) { | ||
598 | dsidev = NULL; | ||
599 | DSSWARN("DSI PLL not operational\n"); | ||
600 | } | ||
601 | |||
602 | if (dsidev) | ||
603 | DSSDBG("using DSI PLL for DPI clock\n"); | ||
604 | |||
605 | dpi.dsidev = dsidev; | ||
606 | |||
607 | return 0; | ||
608 | } | ||
609 | |||
610 | static struct omap_dss_device *dpi_find_dssdev(struct platform_device *pdev) | 621 | static struct omap_dss_device *dpi_find_dssdev(struct platform_device *pdev) |
611 | { | 622 | { |
612 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | 623 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; |
@@ -646,19 +657,18 @@ static int dpi_probe_pdata(struct platform_device *dpidev) | |||
646 | if (!plat_dssdev) | 657 | if (!plat_dssdev) |
647 | return 0; | 658 | return 0; |
648 | 659 | ||
660 | r = dpi_init_regulator(); | ||
661 | if (r) | ||
662 | return r; | ||
663 | |||
664 | dpi_init_pll(); | ||
665 | |||
649 | dssdev = dss_alloc_and_init_device(&dpidev->dev); | 666 | dssdev = dss_alloc_and_init_device(&dpidev->dev); |
650 | if (!dssdev) | 667 | if (!dssdev) |
651 | return -ENOMEM; | 668 | return -ENOMEM; |
652 | 669 | ||
653 | dss_copy_device_pdata(dssdev, plat_dssdev); | 670 | dss_copy_device_pdata(dssdev, plat_dssdev); |
654 | 671 | ||
655 | r = dpi_init_display(dssdev); | ||
656 | if (r) { | ||
657 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | ||
658 | dss_put_device(dssdev); | ||
659 | return r; | ||
660 | } | ||
661 | |||
662 | r = omapdss_output_set_device(&dpi.output, dssdev); | 672 | r = omapdss_output_set_device(&dpi.output, dssdev); |
663 | if (r) { | 673 | if (r) { |
664 | DSSERR("failed to connect output to new device: %s\n", | 674 | DSSERR("failed to connect output to new device: %s\n", |
@@ -678,41 +688,108 @@ static int dpi_probe_pdata(struct platform_device *dpidev) | |||
678 | return 0; | 688 | return 0; |
679 | } | 689 | } |
680 | 690 | ||
691 | static int dpi_connect(struct omap_dss_device *dssdev, | ||
692 | struct omap_dss_device *dst) | ||
693 | { | ||
694 | struct omap_overlay_manager *mgr; | ||
695 | int r; | ||
696 | |||
697 | r = dpi_init_regulator(); | ||
698 | if (r) | ||
699 | return r; | ||
700 | |||
701 | dpi_init_pll(); | ||
702 | |||
703 | mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel); | ||
704 | if (!mgr) | ||
705 | return -ENODEV; | ||
706 | |||
707 | r = dss_mgr_connect(mgr, dssdev); | ||
708 | if (r) | ||
709 | return r; | ||
710 | |||
711 | r = omapdss_output_set_device(dssdev, dst); | ||
712 | if (r) { | ||
713 | DSSERR("failed to connect output to new device: %s\n", | ||
714 | dst->name); | ||
715 | dss_mgr_disconnect(mgr, dssdev); | ||
716 | return r; | ||
717 | } | ||
718 | |||
719 | return 0; | ||
720 | } | ||
721 | |||
722 | static void dpi_disconnect(struct omap_dss_device *dssdev, | ||
723 | struct omap_dss_device *dst) | ||
724 | { | ||
725 | WARN_ON(dst != dssdev->device); | ||
726 | |||
727 | if (dst != dssdev->device) | ||
728 | return; | ||
729 | |||
730 | omapdss_output_unset_device(dssdev); | ||
731 | |||
732 | if (dssdev->manager) | ||
733 | dss_mgr_disconnect(dssdev->manager, dssdev); | ||
734 | } | ||
735 | |||
736 | static const struct omapdss_dpi_ops dpi_ops = { | ||
737 | .connect = dpi_connect, | ||
738 | .disconnect = dpi_disconnect, | ||
739 | |||
740 | .enable = omapdss_dpi_display_enable, | ||
741 | .disable = omapdss_dpi_display_disable, | ||
742 | |||
743 | .check_timings = dpi_check_timings, | ||
744 | .set_timings = omapdss_dpi_set_timings, | ||
745 | .get_timings = dpi_get_timings, | ||
746 | |||
747 | .set_data_lines = omapdss_dpi_set_data_lines, | ||
748 | }; | ||
749 | |||
681 | static void dpi_init_output(struct platform_device *pdev) | 750 | static void dpi_init_output(struct platform_device *pdev) |
682 | { | 751 | { |
683 | struct omap_dss_output *out = &dpi.output; | 752 | struct omap_dss_device *out = &dpi.output; |
684 | 753 | ||
685 | out->pdev = pdev; | 754 | out->dev = &pdev->dev; |
686 | out->id = OMAP_DSS_OUTPUT_DPI; | 755 | out->id = OMAP_DSS_OUTPUT_DPI; |
687 | out->type = OMAP_DISPLAY_TYPE_DPI; | 756 | out->output_type = OMAP_DISPLAY_TYPE_DPI; |
688 | out->name = "dpi.0"; | 757 | out->name = "dpi.0"; |
689 | out->dispc_channel = dpi_get_channel(); | 758 | out->dispc_channel = dpi_get_channel(); |
759 | out->ops.dpi = &dpi_ops; | ||
760 | out->owner = THIS_MODULE; | ||
690 | 761 | ||
691 | dss_register_output(out); | 762 | omapdss_register_output(out); |
692 | } | 763 | } |
693 | 764 | ||
694 | static void __exit dpi_uninit_output(struct platform_device *pdev) | 765 | static void __exit dpi_uninit_output(struct platform_device *pdev) |
695 | { | 766 | { |
696 | struct omap_dss_output *out = &dpi.output; | 767 | struct omap_dss_device *out = &dpi.output; |
697 | 768 | ||
698 | dss_unregister_output(out); | 769 | omapdss_unregister_output(out); |
699 | } | 770 | } |
700 | 771 | ||
701 | static int omap_dpi_probe(struct platform_device *pdev) | 772 | static int omap_dpi_probe(struct platform_device *pdev) |
702 | { | 773 | { |
703 | int r; | 774 | int r; |
704 | 775 | ||
776 | dpi.pdev = pdev; | ||
777 | |||
705 | mutex_init(&dpi.lock); | 778 | mutex_init(&dpi.lock); |
706 | 779 | ||
707 | dpi_init_output(pdev); | 780 | dpi_init_output(pdev); |
708 | 781 | ||
709 | r = dpi_probe_pdata(pdev); | 782 | if (pdev->dev.platform_data) { |
710 | if (r) { | 783 | r = dpi_probe_pdata(pdev); |
711 | dpi_uninit_output(pdev); | 784 | if (r) |
712 | return r; | 785 | goto err_probe; |
713 | } | 786 | } |
714 | 787 | ||
715 | return 0; | 788 | return 0; |
789 | |||
790 | err_probe: | ||
791 | dpi_uninit_output(pdev); | ||
792 | return r; | ||
716 | } | 793 | } |
717 | 794 | ||
718 | static int __exit omap_dpi_remove(struct platform_device *pdev) | 795 | static int __exit omap_dpi_remove(struct platform_device *pdev) |
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index a73dedc33101..99a043b08f0d 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c | |||
@@ -363,7 +363,7 @@ struct dsi_data { | |||
363 | enum omap_dss_dsi_mode mode; | 363 | enum omap_dss_dsi_mode mode; |
364 | struct omap_dss_dsi_videomode_timings vm_timings; | 364 | struct omap_dss_dsi_videomode_timings vm_timings; |
365 | 365 | ||
366 | struct omap_dss_output output; | 366 | struct omap_dss_device output; |
367 | }; | 367 | }; |
368 | 368 | ||
369 | struct dsi_packet_sent_handler_data { | 369 | struct dsi_packet_sent_handler_data { |
@@ -383,12 +383,21 @@ static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dside | |||
383 | 383 | ||
384 | static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev) | 384 | static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev) |
385 | { | 385 | { |
386 | return dssdev->output->pdev; | 386 | /* HACK: dssdev can be either the panel device, when using old API, or |
387 | * the dsi device itself, when using the new API. So we solve this for | ||
388 | * now by checking the dssdev->id. This will be removed when the old API | ||
389 | * is removed. | ||
390 | */ | ||
391 | if (dssdev->id == OMAP_DSS_OUTPUT_DSI1 || | ||
392 | dssdev->id == OMAP_DSS_OUTPUT_DSI2) | ||
393 | return to_platform_device(dssdev->dev); | ||
394 | |||
395 | return to_platform_device(dssdev->output->dev); | ||
387 | } | 396 | } |
388 | 397 | ||
389 | struct platform_device *dsi_get_dsidev_from_id(int module) | 398 | struct platform_device *dsi_get_dsidev_from_id(int module) |
390 | { | 399 | { |
391 | struct omap_dss_output *out; | 400 | struct omap_dss_device *out; |
392 | enum omap_dss_output_id id; | 401 | enum omap_dss_output_id id; |
393 | 402 | ||
394 | switch (module) { | 403 | switch (module) { |
@@ -404,7 +413,7 @@ struct platform_device *dsi_get_dsidev_from_id(int module) | |||
404 | 413 | ||
405 | out = omap_dss_get_output(id); | 414 | out = omap_dss_get_output(id); |
406 | 415 | ||
407 | return out ? out->pdev : NULL; | 416 | return out ? to_platform_device(out->dev) : NULL; |
408 | } | 417 | } |
409 | 418 | ||
410 | static inline void dsi_write_reg(struct platform_device *dsidev, | 419 | static inline void dsi_write_reg(struct platform_device *dsidev, |
@@ -1114,6 +1123,30 @@ void dsi_runtime_put(struct platform_device *dsidev) | |||
1114 | WARN_ON(r < 0 && r != -ENOSYS); | 1123 | WARN_ON(r < 0 && r != -ENOSYS); |
1115 | } | 1124 | } |
1116 | 1125 | ||
1126 | static int dsi_regulator_init(struct platform_device *dsidev) | ||
1127 | { | ||
1128 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
1129 | struct regulator *vdds_dsi; | ||
1130 | |||
1131 | if (dsi->vdds_dsi_reg != NULL) | ||
1132 | return 0; | ||
1133 | |||
1134 | vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "vdds_dsi"); | ||
1135 | |||
1136 | /* DT HACK: try VCXIO to make omapdss work for o4 sdp/panda */ | ||
1137 | if (IS_ERR(vdds_dsi)) | ||
1138 | vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "VCXIO"); | ||
1139 | |||
1140 | if (IS_ERR(vdds_dsi)) { | ||
1141 | DSSERR("can't get VDDS_DSI regulator\n"); | ||
1142 | return PTR_ERR(vdds_dsi); | ||
1143 | } | ||
1144 | |||
1145 | dsi->vdds_dsi_reg = vdds_dsi; | ||
1146 | |||
1147 | return 0; | ||
1148 | } | ||
1149 | |||
1117 | /* source clock for DSI PLL. this could also be PCLKFREE */ | 1150 | /* source clock for DSI PLL. this could also be PCLKFREE */ |
1118 | static inline void dsi_enable_pll_clock(struct platform_device *dsidev, | 1151 | static inline void dsi_enable_pll_clock(struct platform_device *dsidev, |
1119 | bool enable) | 1152 | bool enable) |
@@ -1592,22 +1625,9 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, | |||
1592 | */ | 1625 | */ |
1593 | enable_hsclk = enable_hsdiv = true; | 1626 | enable_hsclk = enable_hsdiv = true; |
1594 | 1627 | ||
1595 | if (dsi->vdds_dsi_reg == NULL) { | 1628 | r = dsi_regulator_init(dsidev); |
1596 | struct regulator *vdds_dsi; | 1629 | if (r) |
1597 | 1630 | return r; | |
1598 | vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi"); | ||
1599 | |||
1600 | /* DT HACK: try VCXIO to make omapdss work for o4 sdp/panda */ | ||
1601 | if (IS_ERR(vdds_dsi)) | ||
1602 | vdds_dsi = regulator_get(&dsi->pdev->dev, "VCXIO"); | ||
1603 | |||
1604 | if (IS_ERR(vdds_dsi)) { | ||
1605 | DSSERR("can't get VDDS_DSI regulator\n"); | ||
1606 | return PTR_ERR(vdds_dsi); | ||
1607 | } | ||
1608 | |||
1609 | dsi->vdds_dsi_reg = vdds_dsi; | ||
1610 | } | ||
1611 | 1631 | ||
1612 | dsi_enable_pll_clock(dsidev, 1); | 1632 | dsi_enable_pll_clock(dsidev, 1); |
1613 | /* | 1633 | /* |
@@ -4122,7 +4142,7 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) | |||
4122 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4142 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4123 | struct omap_overlay_manager *mgr = dsi->output.manager; | 4143 | struct omap_overlay_manager *mgr = dsi->output.manager; |
4124 | int bpp = dsi_get_pixel_size(dsi->pix_fmt); | 4144 | int bpp = dsi_get_pixel_size(dsi->pix_fmt); |
4125 | struct omap_dss_output *out = &dsi->output; | 4145 | struct omap_dss_device *out = &dsi->output; |
4126 | u8 data_type; | 4146 | u8 data_type; |
4127 | u16 word_count; | 4147 | u16 word_count; |
4128 | int r; | 4148 | int r; |
@@ -4581,12 +4601,6 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) | |||
4581 | 4601 | ||
4582 | mutex_lock(&dsi->lock); | 4602 | mutex_lock(&dsi->lock); |
4583 | 4603 | ||
4584 | r = omap_dss_start_device(dssdev); | ||
4585 | if (r) { | ||
4586 | DSSERR("failed to start device\n"); | ||
4587 | goto err_start_dev; | ||
4588 | } | ||
4589 | |||
4590 | r = dsi_runtime_get(dsidev); | 4604 | r = dsi_runtime_get(dsidev); |
4591 | if (r) | 4605 | if (r) |
4592 | goto err_get_dsi; | 4606 | goto err_get_dsi; |
@@ -4607,8 +4621,6 @@ err_init_dsi: | |||
4607 | dsi_enable_pll_clock(dsidev, 0); | 4621 | dsi_enable_pll_clock(dsidev, 0); |
4608 | dsi_runtime_put(dsidev); | 4622 | dsi_runtime_put(dsidev); |
4609 | err_get_dsi: | 4623 | err_get_dsi: |
4610 | omap_dss_stop_device(dssdev); | ||
4611 | err_start_dev: | ||
4612 | mutex_unlock(&dsi->lock); | 4624 | mutex_unlock(&dsi->lock); |
4613 | DSSDBG("dsi_display_enable FAILED\n"); | 4625 | DSSDBG("dsi_display_enable FAILED\n"); |
4614 | return r; | 4626 | return r; |
@@ -4637,8 +4649,6 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev, | |||
4637 | dsi_runtime_put(dsidev); | 4649 | dsi_runtime_put(dsidev); |
4638 | dsi_enable_pll_clock(dsidev, 0); | 4650 | dsi_enable_pll_clock(dsidev, 0); |
4639 | 4651 | ||
4640 | omap_dss_stop_device(dssdev); | ||
4641 | |||
4642 | mutex_unlock(&dsi->lock); | 4652 | mutex_unlock(&dsi->lock); |
4643 | } | 4653 | } |
4644 | EXPORT_SYMBOL(omapdss_dsi_display_disable); | 4654 | EXPORT_SYMBOL(omapdss_dsi_display_disable); |
@@ -5225,34 +5235,6 @@ static enum omap_channel dsi_get_channel(int module_id) | |||
5225 | } | 5235 | } |
5226 | } | 5236 | } |
5227 | 5237 | ||
5228 | static int dsi_init_display(struct omap_dss_device *dssdev) | ||
5229 | { | ||
5230 | struct platform_device *dsidev = | ||
5231 | dsi_get_dsidev_from_id(dssdev->phy.dsi.module); | ||
5232 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
5233 | |||
5234 | DSSDBG("DSI init\n"); | ||
5235 | |||
5236 | if (dsi->vdds_dsi_reg == NULL) { | ||
5237 | struct regulator *vdds_dsi; | ||
5238 | |||
5239 | vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi"); | ||
5240 | |||
5241 | /* DT HACK: try VCXIO to make omapdss work for o4 sdp/panda */ | ||
5242 | if (IS_ERR(vdds_dsi)) | ||
5243 | vdds_dsi = regulator_get(&dsi->pdev->dev, "VCXIO"); | ||
5244 | |||
5245 | if (IS_ERR(vdds_dsi)) { | ||
5246 | DSSERR("can't get VDDS_DSI regulator\n"); | ||
5247 | return PTR_ERR(vdds_dsi); | ||
5248 | } | ||
5249 | |||
5250 | dsi->vdds_dsi_reg = vdds_dsi; | ||
5251 | } | ||
5252 | |||
5253 | return 0; | ||
5254 | } | ||
5255 | |||
5256 | int omap_dsi_request_vc(struct omap_dss_device *dssdev, int *channel) | 5238 | int omap_dsi_request_vc(struct omap_dss_device *dssdev, int *channel) |
5257 | { | 5239 | { |
5258 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 5240 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
@@ -5410,19 +5392,16 @@ static int dsi_probe_pdata(struct platform_device *dsidev) | |||
5410 | if (!plat_dssdev) | 5392 | if (!plat_dssdev) |
5411 | return 0; | 5393 | return 0; |
5412 | 5394 | ||
5395 | r = dsi_regulator_init(dsidev); | ||
5396 | if (r) | ||
5397 | return r; | ||
5398 | |||
5413 | dssdev = dss_alloc_and_init_device(&dsidev->dev); | 5399 | dssdev = dss_alloc_and_init_device(&dsidev->dev); |
5414 | if (!dssdev) | 5400 | if (!dssdev) |
5415 | return -ENOMEM; | 5401 | return -ENOMEM; |
5416 | 5402 | ||
5417 | dss_copy_device_pdata(dssdev, plat_dssdev); | 5403 | dss_copy_device_pdata(dssdev, plat_dssdev); |
5418 | 5404 | ||
5419 | r = dsi_init_display(dssdev); | ||
5420 | if (r) { | ||
5421 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | ||
5422 | dss_put_device(dssdev); | ||
5423 | return r; | ||
5424 | } | ||
5425 | |||
5426 | r = omapdss_output_set_device(&dsi->output, dssdev); | 5405 | r = omapdss_output_set_device(&dsi->output, dssdev); |
5427 | if (r) { | 5406 | if (r) { |
5428 | DSSERR("failed to connect output to new device: %s\n", | 5407 | DSSERR("failed to connect output to new device: %s\n", |
@@ -5442,28 +5421,113 @@ static int dsi_probe_pdata(struct platform_device *dsidev) | |||
5442 | return 0; | 5421 | return 0; |
5443 | } | 5422 | } |
5444 | 5423 | ||
5424 | static int dsi_connect(struct omap_dss_device *dssdev, | ||
5425 | struct omap_dss_device *dst) | ||
5426 | { | ||
5427 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
5428 | struct omap_overlay_manager *mgr; | ||
5429 | int r; | ||
5430 | |||
5431 | r = dsi_regulator_init(dsidev); | ||
5432 | if (r) | ||
5433 | return r; | ||
5434 | |||
5435 | mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel); | ||
5436 | if (!mgr) | ||
5437 | return -ENODEV; | ||
5438 | |||
5439 | r = dss_mgr_connect(mgr, dssdev); | ||
5440 | if (r) | ||
5441 | return r; | ||
5442 | |||
5443 | r = omapdss_output_set_device(dssdev, dst); | ||
5444 | if (r) { | ||
5445 | DSSERR("failed to connect output to new device: %s\n", | ||
5446 | dssdev->name); | ||
5447 | dss_mgr_disconnect(mgr, dssdev); | ||
5448 | return r; | ||
5449 | } | ||
5450 | |||
5451 | return 0; | ||
5452 | } | ||
5453 | |||
5454 | static void dsi_disconnect(struct omap_dss_device *dssdev, | ||
5455 | struct omap_dss_device *dst) | ||
5456 | { | ||
5457 | WARN_ON(dst != dssdev->device); | ||
5458 | |||
5459 | if (dst != dssdev->device) | ||
5460 | return; | ||
5461 | |||
5462 | omapdss_output_unset_device(dssdev); | ||
5463 | |||
5464 | if (dssdev->manager) | ||
5465 | dss_mgr_disconnect(dssdev->manager, dssdev); | ||
5466 | } | ||
5467 | |||
5468 | static const struct omapdss_dsi_ops dsi_ops = { | ||
5469 | .connect = dsi_connect, | ||
5470 | .disconnect = dsi_disconnect, | ||
5471 | |||
5472 | .bus_lock = dsi_bus_lock, | ||
5473 | .bus_unlock = dsi_bus_unlock, | ||
5474 | |||
5475 | .enable = omapdss_dsi_display_enable, | ||
5476 | .disable = omapdss_dsi_display_disable, | ||
5477 | |||
5478 | .enable_hs = omapdss_dsi_vc_enable_hs, | ||
5479 | |||
5480 | .configure_pins = omapdss_dsi_configure_pins, | ||
5481 | .set_config = omapdss_dsi_set_config, | ||
5482 | |||
5483 | .enable_video_output = dsi_enable_video_output, | ||
5484 | .disable_video_output = dsi_disable_video_output, | ||
5485 | |||
5486 | .update = omap_dsi_update, | ||
5487 | |||
5488 | .enable_te = omapdss_dsi_enable_te, | ||
5489 | |||
5490 | .request_vc = omap_dsi_request_vc, | ||
5491 | .set_vc_id = omap_dsi_set_vc_id, | ||
5492 | .release_vc = omap_dsi_release_vc, | ||
5493 | |||
5494 | .dcs_write = dsi_vc_dcs_write, | ||
5495 | .dcs_write_nosync = dsi_vc_dcs_write_nosync, | ||
5496 | .dcs_read = dsi_vc_dcs_read, | ||
5497 | |||
5498 | .gen_write = dsi_vc_generic_write, | ||
5499 | .gen_write_nosync = dsi_vc_generic_write_nosync, | ||
5500 | .gen_read = dsi_vc_generic_read, | ||
5501 | |||
5502 | .bta_sync = dsi_vc_send_bta_sync, | ||
5503 | |||
5504 | .set_max_rx_packet_size = dsi_vc_set_max_rx_packet_size, | ||
5505 | }; | ||
5506 | |||
5445 | static void dsi_init_output(struct platform_device *dsidev) | 5507 | static void dsi_init_output(struct platform_device *dsidev) |
5446 | { | 5508 | { |
5447 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 5509 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
5448 | struct omap_dss_output *out = &dsi->output; | 5510 | struct omap_dss_device *out = &dsi->output; |
5449 | 5511 | ||
5450 | out->pdev = dsidev; | 5512 | out->dev = &dsidev->dev; |
5451 | out->id = dsi->module_id == 0 ? | 5513 | out->id = dsi->module_id == 0 ? |
5452 | OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2; | 5514 | OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2; |
5453 | 5515 | ||
5454 | out->type = OMAP_DISPLAY_TYPE_DSI; | 5516 | out->output_type = OMAP_DISPLAY_TYPE_DSI; |
5455 | out->name = dsi->module_id == 0 ? "dsi.0" : "dsi.1"; | 5517 | out->name = dsi->module_id == 0 ? "dsi.0" : "dsi.1"; |
5456 | out->dispc_channel = dsi_get_channel(dsi->module_id); | 5518 | out->dispc_channel = dsi_get_channel(dsi->module_id); |
5519 | out->ops.dsi = &dsi_ops; | ||
5520 | out->owner = THIS_MODULE; | ||
5457 | 5521 | ||
5458 | dss_register_output(out); | 5522 | omapdss_register_output(out); |
5459 | } | 5523 | } |
5460 | 5524 | ||
5461 | static void dsi_uninit_output(struct platform_device *dsidev) | 5525 | static void dsi_uninit_output(struct platform_device *dsidev) |
5462 | { | 5526 | { |
5463 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 5527 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
5464 | struct omap_dss_output *out = &dsi->output; | 5528 | struct omap_dss_device *out = &dsi->output; |
5465 | 5529 | ||
5466 | dss_unregister_output(out); | 5530 | omapdss_unregister_output(out); |
5467 | } | 5531 | } |
5468 | 5532 | ||
5469 | /* DSI1 HW IP initialisation */ | 5533 | /* DSI1 HW IP initialisation */ |
@@ -5563,12 +5627,10 @@ static int omap_dsihw_probe(struct platform_device *dsidev) | |||
5563 | 5627 | ||
5564 | dsi_init_output(dsidev); | 5628 | dsi_init_output(dsidev); |
5565 | 5629 | ||
5566 | r = dsi_probe_pdata(dsidev); | 5630 | if (dsidev->dev.platform_data) { |
5567 | if (r) { | 5631 | r = dsi_probe_pdata(dsidev); |
5568 | dsi_runtime_put(dsidev); | 5632 | if (r) |
5569 | dsi_uninit_output(dsidev); | 5633 | goto err_probe; |
5570 | pm_runtime_disable(&dsidev->dev); | ||
5571 | return r; | ||
5572 | } | 5634 | } |
5573 | 5635 | ||
5574 | dsi_runtime_put(dsidev); | 5636 | dsi_runtime_put(dsidev); |
@@ -5586,6 +5648,9 @@ static int omap_dsihw_probe(struct platform_device *dsidev) | |||
5586 | #endif | 5648 | #endif |
5587 | return 0; | 5649 | return 0; |
5588 | 5650 | ||
5651 | err_probe: | ||
5652 | dsi_runtime_put(dsidev); | ||
5653 | dsi_uninit_output(dsidev); | ||
5589 | err_runtime_get: | 5654 | err_runtime_get: |
5590 | pm_runtime_disable(&dsidev->dev); | 5655 | pm_runtime_disable(&dsidev->dev); |
5591 | return r; | 5656 | return r; |
@@ -5603,14 +5668,9 @@ static int __exit omap_dsihw_remove(struct platform_device *dsidev) | |||
5603 | 5668 | ||
5604 | pm_runtime_disable(&dsidev->dev); | 5669 | pm_runtime_disable(&dsidev->dev); |
5605 | 5670 | ||
5606 | if (dsi->vdds_dsi_reg != NULL) { | 5671 | if (dsi->vdds_dsi_reg != NULL && dsi->vdds_dsi_enabled) { |
5607 | if (dsi->vdds_dsi_enabled) { | 5672 | regulator_disable(dsi->vdds_dsi_reg); |
5608 | regulator_disable(dsi->vdds_dsi_reg); | 5673 | dsi->vdds_dsi_enabled = false; |
5609 | dsi->vdds_dsi_enabled = false; | ||
5610 | } | ||
5611 | |||
5612 | regulator_put(dsi->vdds_dsi_reg); | ||
5613 | dsi->vdds_dsi_reg = NULL; | ||
5614 | } | 5674 | } |
5615 | 5675 | ||
5616 | return 0; | 5676 | return 0; |
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 94f66f9f10a3..bd01608e67e2 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c | |||
@@ -157,7 +157,8 @@ static void dss_restore_context(void) | |||
157 | 157 | ||
158 | int dss_get_ctx_loss_count(void) | 158 | int dss_get_ctx_loss_count(void) |
159 | { | 159 | { |
160 | struct omap_dss_board_info *board_data = dss.pdev->dev.platform_data; | 160 | struct platform_device *core_pdev = dss_get_core_pdev(); |
161 | struct omap_dss_board_info *board_data = core_pdev->dev.platform_data; | ||
161 | int cnt; | 162 | int cnt; |
162 | 163 | ||
163 | if (!board_data->get_context_loss_count) | 164 | if (!board_data->get_context_loss_count) |
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 84758936429d..50a2362ef8f8 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h | |||
@@ -179,23 +179,19 @@ void dss_put_device(struct omap_dss_device *dssdev); | |||
179 | void dss_copy_device_pdata(struct omap_dss_device *dst, | 179 | void dss_copy_device_pdata(struct omap_dss_device *dst, |
180 | const struct omap_dss_device *src); | 180 | const struct omap_dss_device *src); |
181 | 181 | ||
182 | /* output */ | ||
183 | void dss_register_output(struct omap_dss_output *out); | ||
184 | void dss_unregister_output(struct omap_dss_output *out); | ||
185 | |||
186 | /* display */ | 182 | /* display */ |
187 | int dss_suspend_all_devices(void); | 183 | int dss_suspend_all_devices(void); |
188 | int dss_resume_all_devices(void); | 184 | int dss_resume_all_devices(void); |
189 | void dss_disable_all_devices(void); | 185 | void dss_disable_all_devices(void); |
190 | 186 | ||
191 | int display_init_sysfs(struct platform_device *pdev, | 187 | int display_init_sysfs(struct platform_device *pdev); |
192 | struct omap_dss_device *dssdev); | 188 | void display_uninit_sysfs(struct platform_device *pdev); |
193 | void display_uninit_sysfs(struct platform_device *pdev, | ||
194 | struct omap_dss_device *dssdev); | ||
195 | 189 | ||
196 | /* manager */ | 190 | /* manager */ |
197 | int dss_init_overlay_managers(struct platform_device *pdev); | 191 | int dss_init_overlay_managers(void); |
198 | void dss_uninit_overlay_managers(struct platform_device *pdev); | 192 | void dss_uninit_overlay_managers(void); |
193 | int dss_init_overlay_managers_sysfs(struct platform_device *pdev); | ||
194 | void dss_uninit_overlay_managers_sysfs(struct platform_device *pdev); | ||
199 | int dss_mgr_simple_check(struct omap_overlay_manager *mgr, | 195 | int dss_mgr_simple_check(struct omap_overlay_manager *mgr, |
200 | const struct omap_overlay_manager_info *info); | 196 | const struct omap_overlay_manager_info *info); |
201 | int dss_mgr_check_timings(struct omap_overlay_manager *mgr, | 197 | int dss_mgr_check_timings(struct omap_overlay_manager *mgr, |
@@ -426,6 +422,7 @@ void dispc_mgr_set_clock_div(enum omap_channel channel, | |||
426 | const struct dispc_clock_info *cinfo); | 422 | const struct dispc_clock_info *cinfo); |
427 | int dispc_mgr_get_clock_div(enum omap_channel channel, | 423 | int dispc_mgr_get_clock_div(enum omap_channel channel, |
428 | struct dispc_clock_info *cinfo); | 424 | struct dispc_clock_info *cinfo); |
425 | void dispc_set_tv_pclk(unsigned long pclk); | ||
429 | 426 | ||
430 | u32 dispc_wb_get_framedone_irq(void); | 427 | u32 dispc_wb_get_framedone_irq(void); |
431 | bool dispc_wb_go_busy(void); | 428 | bool dispc_wb_go_busy(void); |
@@ -437,17 +434,8 @@ int dispc_wb_setup(const struct omap_dss_writeback_info *wi, | |||
437 | bool mem_to_mem, const struct omap_video_timings *timings); | 434 | bool mem_to_mem, const struct omap_video_timings *timings); |
438 | 435 | ||
439 | /* VENC */ | 436 | /* VENC */ |
440 | #ifdef CONFIG_OMAP2_DSS_VENC | ||
441 | int venc_init_platform_driver(void) __init; | 437 | int venc_init_platform_driver(void) __init; |
442 | void venc_uninit_platform_driver(void) __exit; | 438 | void venc_uninit_platform_driver(void) __exit; |
443 | unsigned long venc_get_pixel_clock(void); | ||
444 | #else | ||
445 | static inline unsigned long venc_get_pixel_clock(void) | ||
446 | { | ||
447 | WARN("%s: VENC not compiled in, returning pclk as 0\n", __func__); | ||
448 | return 0; | ||
449 | } | ||
450 | #endif | ||
451 | int omapdss_venc_display_enable(struct omap_dss_device *dssdev); | 439 | int omapdss_venc_display_enable(struct omap_dss_device *dssdev); |
452 | void omapdss_venc_display_disable(struct omap_dss_device *dssdev); | 440 | void omapdss_venc_display_disable(struct omap_dss_device *dssdev); |
453 | void omapdss_venc_set_timings(struct omap_dss_device *dssdev, | 441 | void omapdss_venc_set_timings(struct omap_dss_device *dssdev, |
@@ -464,17 +452,8 @@ int venc_panel_init(void); | |||
464 | void venc_panel_exit(void); | 452 | void venc_panel_exit(void); |
465 | 453 | ||
466 | /* HDMI */ | 454 | /* HDMI */ |
467 | #ifdef CONFIG_OMAP4_DSS_HDMI | ||
468 | int hdmi_init_platform_driver(void) __init; | 455 | int hdmi_init_platform_driver(void) __init; |
469 | void hdmi_uninit_platform_driver(void) __exit; | 456 | void hdmi_uninit_platform_driver(void) __exit; |
470 | unsigned long hdmi_get_pixel_clock(void); | ||
471 | #else | ||
472 | static inline unsigned long hdmi_get_pixel_clock(void) | ||
473 | { | ||
474 | WARN("%s: HDMI not compiled in, returning pclk as 0\n", __func__); | ||
475 | return 0; | ||
476 | } | ||
477 | #endif | ||
478 | int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev); | 457 | int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev); |
479 | void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev); | 458 | void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev); |
480 | int omapdss_hdmi_core_enable(struct omap_dss_device *dssdev); | 459 | int omapdss_hdmi_core_enable(struct omap_dss_device *dssdev); |
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 77dbe0cfb34c..b9cfebb378a2 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c | |||
@@ -797,7 +797,6 @@ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = { | |||
797 | .phy_enable = ti_hdmi_4xxx_phy_enable, | 797 | .phy_enable = ti_hdmi_4xxx_phy_enable, |
798 | .phy_disable = ti_hdmi_4xxx_phy_disable, | 798 | .phy_disable = ti_hdmi_4xxx_phy_disable, |
799 | .read_edid = ti_hdmi_4xxx_read_edid, | 799 | .read_edid = ti_hdmi_4xxx_read_edid, |
800 | .detect = ti_hdmi_4xxx_detect, | ||
801 | .pll_enable = ti_hdmi_4xxx_pll_enable, | 800 | .pll_enable = ti_hdmi_4xxx_pll_enable, |
802 | .pll_disable = ti_hdmi_4xxx_pll_disable, | 801 | .pll_disable = ti_hdmi_4xxx_pll_disable, |
803 | .video_enable = ti_hdmi_4xxx_wp_video_start, | 802 | .video_enable = ti_hdmi_4xxx_wp_video_start, |
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index a109934c0478..44a885b92825 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c | |||
@@ -70,7 +70,9 @@ static struct { | |||
70 | int ls_oe_gpio; | 70 | int ls_oe_gpio; |
71 | int hpd_gpio; | 71 | int hpd_gpio; |
72 | 72 | ||
73 | struct omap_dss_output output; | 73 | bool core_enabled; |
74 | |||
75 | struct omap_dss_device output; | ||
74 | } hdmi; | 76 | } hdmi; |
75 | 77 | ||
76 | /* | 78 | /* |
@@ -328,6 +330,29 @@ static void hdmi_runtime_put(void) | |||
328 | WARN_ON(r < 0 && r != -ENOSYS); | 330 | WARN_ON(r < 0 && r != -ENOSYS); |
329 | } | 331 | } |
330 | 332 | ||
333 | static int hdmi_init_regulator(void) | ||
334 | { | ||
335 | struct regulator *reg; | ||
336 | |||
337 | if (hdmi.vdda_hdmi_dac_reg != NULL) | ||
338 | return 0; | ||
339 | |||
340 | reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac"); | ||
341 | |||
342 | /* DT HACK: try VDAC to make omapdss work for o4 sdp/panda */ | ||
343 | if (IS_ERR(reg)) | ||
344 | reg = devm_regulator_get(&hdmi.pdev->dev, "VDAC"); | ||
345 | |||
346 | if (IS_ERR(reg)) { | ||
347 | DSSERR("can't get VDDA_HDMI_DAC regulator\n"); | ||
348 | return PTR_ERR(reg); | ||
349 | } | ||
350 | |||
351 | hdmi.vdda_hdmi_dac_reg = reg; | ||
352 | |||
353 | return 0; | ||
354 | } | ||
355 | |||
331 | static int hdmi_init_display(struct omap_dss_device *dssdev) | 356 | static int hdmi_init_display(struct omap_dss_device *dssdev) |
332 | { | 357 | { |
333 | int r; | 358 | int r; |
@@ -342,22 +367,9 @@ static int hdmi_init_display(struct omap_dss_device *dssdev) | |||
342 | 367 | ||
343 | dss_init_hdmi_ip_ops(&hdmi.ip_data, omapdss_get_version()); | 368 | dss_init_hdmi_ip_ops(&hdmi.ip_data, omapdss_get_version()); |
344 | 369 | ||
345 | if (hdmi.vdda_hdmi_dac_reg == NULL) { | 370 | r = hdmi_init_regulator(); |
346 | struct regulator *reg; | 371 | if (r) |
347 | 372 | return r; | |
348 | reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac"); | ||
349 | |||
350 | /* DT HACK: try VDAC to make omapdss work for o4 sdp/panda */ | ||
351 | if (IS_ERR(reg)) | ||
352 | reg = devm_regulator_get(&hdmi.pdev->dev, "VDAC"); | ||
353 | |||
354 | if (IS_ERR(reg)) { | ||
355 | DSSERR("can't get VDDA_HDMI_DAC regulator\n"); | ||
356 | return PTR_ERR(reg); | ||
357 | } | ||
358 | |||
359 | hdmi.vdda_hdmi_dac_reg = reg; | ||
360 | } | ||
361 | 373 | ||
362 | r = gpio_request_array(gpios, ARRAY_SIZE(gpios)); | 374 | r = gpio_request_array(gpios, ARRAY_SIZE(gpios)); |
363 | if (r) | 375 | if (r) |
@@ -455,12 +467,6 @@ end: return cm; | |||
455 | 467 | ||
456 | } | 468 | } |
457 | 469 | ||
458 | unsigned long hdmi_get_pixel_clock(void) | ||
459 | { | ||
460 | /* HDMI Pixel Clock in Mhz */ | ||
461 | return hdmi.ip_data.cfg.timings.pixel_clock * 1000; | ||
462 | } | ||
463 | |||
464 | static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, | 470 | static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, |
465 | struct hdmi_pll_info *pi) | 471 | struct hdmi_pll_info *pi) |
466 | { | 472 | { |
@@ -511,8 +517,10 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev) | |||
511 | { | 517 | { |
512 | int r; | 518 | int r; |
513 | 519 | ||
514 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 1); | 520 | if (gpio_is_valid(hdmi.ct_cp_hpd_gpio)) |
515 | gpio_set_value(hdmi.ls_oe_gpio, 1); | 521 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 1); |
522 | if (gpio_is_valid(hdmi.ls_oe_gpio)) | ||
523 | gpio_set_value(hdmi.ls_oe_gpio, 1); | ||
516 | 524 | ||
517 | /* wait 300us after CT_CP_HPD for the 5V power output to reach 90% */ | 525 | /* wait 300us after CT_CP_HPD for the 5V power output to reach 90% */ |
518 | udelay(300); | 526 | udelay(300); |
@@ -528,29 +536,37 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev) | |||
528 | /* Make selection of HDMI in DSS */ | 536 | /* Make selection of HDMI in DSS */ |
529 | dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); | 537 | dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); |
530 | 538 | ||
539 | hdmi.core_enabled = true; | ||
540 | |||
531 | return 0; | 541 | return 0; |
532 | 542 | ||
533 | err_runtime_get: | 543 | err_runtime_get: |
534 | regulator_disable(hdmi.vdda_hdmi_dac_reg); | 544 | regulator_disable(hdmi.vdda_hdmi_dac_reg); |
535 | err_vdac_enable: | 545 | err_vdac_enable: |
536 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); | 546 | if (gpio_is_valid(hdmi.ct_cp_hpd_gpio)) |
537 | gpio_set_value(hdmi.ls_oe_gpio, 0); | 547 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); |
548 | if (gpio_is_valid(hdmi.ls_oe_gpio)) | ||
549 | gpio_set_value(hdmi.ls_oe_gpio, 0); | ||
538 | return r; | 550 | return r; |
539 | } | 551 | } |
540 | 552 | ||
541 | static void hdmi_power_off_core(struct omap_dss_device *dssdev) | 553 | static void hdmi_power_off_core(struct omap_dss_device *dssdev) |
542 | { | 554 | { |
555 | hdmi.core_enabled = false; | ||
556 | |||
543 | hdmi_runtime_put(); | 557 | hdmi_runtime_put(); |
544 | regulator_disable(hdmi.vdda_hdmi_dac_reg); | 558 | regulator_disable(hdmi.vdda_hdmi_dac_reg); |
545 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); | 559 | if (gpio_is_valid(hdmi.ct_cp_hpd_gpio)) |
546 | gpio_set_value(hdmi.ls_oe_gpio, 0); | 560 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); |
561 | if (gpio_is_valid(hdmi.ls_oe_gpio)) | ||
562 | gpio_set_value(hdmi.ls_oe_gpio, 0); | ||
547 | } | 563 | } |
548 | 564 | ||
549 | static int hdmi_power_on_full(struct omap_dss_device *dssdev) | 565 | static int hdmi_power_on_full(struct omap_dss_device *dssdev) |
550 | { | 566 | { |
551 | int r; | 567 | int r; |
552 | struct omap_video_timings *p; | 568 | struct omap_video_timings *p; |
553 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 569 | struct omap_overlay_manager *mgr = hdmi.output.manager; |
554 | unsigned long phy; | 570 | unsigned long phy; |
555 | 571 | ||
556 | r = hdmi_power_on_core(dssdev); | 572 | r = hdmi_power_on_core(dssdev); |
@@ -613,7 +629,7 @@ err_pll_enable: | |||
613 | 629 | ||
614 | static void hdmi_power_off_full(struct omap_dss_device *dssdev) | 630 | static void hdmi_power_off_full(struct omap_dss_device *dssdev) |
615 | { | 631 | { |
616 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 632 | struct omap_overlay_manager *mgr = hdmi.output.manager; |
617 | 633 | ||
618 | dss_mgr_disable(mgr); | 634 | dss_mgr_disable(mgr); |
619 | 635 | ||
@@ -653,9 +669,23 @@ void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev, | |||
653 | if (t != NULL) | 669 | if (t != NULL) |
654 | hdmi.ip_data.cfg = *t; | 670 | hdmi.ip_data.cfg = *t; |
655 | 671 | ||
672 | dispc_set_tv_pclk(t->timings.pixel_clock * 1000); | ||
673 | |||
656 | mutex_unlock(&hdmi.lock); | 674 | mutex_unlock(&hdmi.lock); |
657 | } | 675 | } |
658 | 676 | ||
677 | static void omapdss_hdmi_display_get_timings(struct omap_dss_device *dssdev, | ||
678 | struct omap_video_timings *timings) | ||
679 | { | ||
680 | const struct hdmi_config *cfg; | ||
681 | |||
682 | cfg = hdmi_get_timings(); | ||
683 | if (cfg == NULL) | ||
684 | cfg = &vesa_timings[0]; | ||
685 | |||
686 | memcpy(timings, &cfg->timings, sizeof(cfg->timings)); | ||
687 | } | ||
688 | |||
659 | static void hdmi_dump_regs(struct seq_file *s) | 689 | static void hdmi_dump_regs(struct seq_file *s) |
660 | { | 690 | { |
661 | mutex_lock(&hdmi.lock); | 691 | mutex_lock(&hdmi.lock); |
@@ -700,7 +730,7 @@ bool omapdss_hdmi_detect(void) | |||
700 | r = hdmi_runtime_get(); | 730 | r = hdmi_runtime_get(); |
701 | BUG_ON(r); | 731 | BUG_ON(r); |
702 | 732 | ||
703 | r = hdmi.ip_data.ops->detect(&hdmi.ip_data); | 733 | r = gpio_get_value(hdmi.hpd_gpio); |
704 | 734 | ||
705 | hdmi_runtime_put(); | 735 | hdmi_runtime_put(); |
706 | mutex_unlock(&hdmi.lock); | 736 | mutex_unlock(&hdmi.lock); |
@@ -710,7 +740,7 @@ bool omapdss_hdmi_detect(void) | |||
710 | 740 | ||
711 | int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) | 741 | int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) |
712 | { | 742 | { |
713 | struct omap_dss_output *out = dssdev->output; | 743 | struct omap_dss_device *out = &hdmi.output; |
714 | int r = 0; | 744 | int r = 0; |
715 | 745 | ||
716 | DSSDBG("ENTER hdmi_display_enable\n"); | 746 | DSSDBG("ENTER hdmi_display_enable\n"); |
@@ -723,25 +753,15 @@ int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) | |||
723 | goto err0; | 753 | goto err0; |
724 | } | 754 | } |
725 | 755 | ||
726 | hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio; | ||
727 | |||
728 | r = omap_dss_start_device(dssdev); | ||
729 | if (r) { | ||
730 | DSSERR("failed to start device\n"); | ||
731 | goto err0; | ||
732 | } | ||
733 | |||
734 | r = hdmi_power_on_full(dssdev); | 756 | r = hdmi_power_on_full(dssdev); |
735 | if (r) { | 757 | if (r) { |
736 | DSSERR("failed to power on device\n"); | 758 | DSSERR("failed to power on device\n"); |
737 | goto err1; | 759 | goto err0; |
738 | } | 760 | } |
739 | 761 | ||
740 | mutex_unlock(&hdmi.lock); | 762 | mutex_unlock(&hdmi.lock); |
741 | return 0; | 763 | return 0; |
742 | 764 | ||
743 | err1: | ||
744 | omap_dss_stop_device(dssdev); | ||
745 | err0: | 765 | err0: |
746 | mutex_unlock(&hdmi.lock); | 766 | mutex_unlock(&hdmi.lock); |
747 | return r; | 767 | return r; |
@@ -755,8 +775,6 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev) | |||
755 | 775 | ||
756 | hdmi_power_off_full(dssdev); | 776 | hdmi_power_off_full(dssdev); |
757 | 777 | ||
758 | omap_dss_stop_device(dssdev); | ||
759 | |||
760 | mutex_unlock(&hdmi.lock); | 778 | mutex_unlock(&hdmi.lock); |
761 | } | 779 | } |
762 | 780 | ||
@@ -768,8 +786,6 @@ int omapdss_hdmi_core_enable(struct omap_dss_device *dssdev) | |||
768 | 786 | ||
769 | mutex_lock(&hdmi.lock); | 787 | mutex_lock(&hdmi.lock); |
770 | 788 | ||
771 | hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio; | ||
772 | |||
773 | r = hdmi_power_on_core(dssdev); | 789 | r = hdmi_power_on_core(dssdev); |
774 | if (r) { | 790 | if (r) { |
775 | DSSERR("failed to power on device\n"); | 791 | DSSERR("failed to power on device\n"); |
@@ -1033,24 +1049,219 @@ static int hdmi_probe_pdata(struct platform_device *pdev) | |||
1033 | return 0; | 1049 | return 0; |
1034 | } | 1050 | } |
1035 | 1051 | ||
1052 | static int hdmi_connect(struct omap_dss_device *dssdev, | ||
1053 | struct omap_dss_device *dst) | ||
1054 | { | ||
1055 | struct omap_overlay_manager *mgr; | ||
1056 | int r; | ||
1057 | |||
1058 | dss_init_hdmi_ip_ops(&hdmi.ip_data, omapdss_get_version()); | ||
1059 | |||
1060 | r = hdmi_init_regulator(); | ||
1061 | if (r) | ||
1062 | return r; | ||
1063 | |||
1064 | mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel); | ||
1065 | if (!mgr) | ||
1066 | return -ENODEV; | ||
1067 | |||
1068 | r = dss_mgr_connect(mgr, dssdev); | ||
1069 | if (r) | ||
1070 | return r; | ||
1071 | |||
1072 | r = omapdss_output_set_device(dssdev, dst); | ||
1073 | if (r) { | ||
1074 | DSSERR("failed to connect output to new device: %s\n", | ||
1075 | dst->name); | ||
1076 | dss_mgr_disconnect(mgr, dssdev); | ||
1077 | return r; | ||
1078 | } | ||
1079 | |||
1080 | return 0; | ||
1081 | } | ||
1082 | |||
1083 | static void hdmi_disconnect(struct omap_dss_device *dssdev, | ||
1084 | struct omap_dss_device *dst) | ||
1085 | { | ||
1086 | WARN_ON(dst != dssdev->device); | ||
1087 | |||
1088 | if (dst != dssdev->device) | ||
1089 | return; | ||
1090 | |||
1091 | omapdss_output_unset_device(dssdev); | ||
1092 | |||
1093 | if (dssdev->manager) | ||
1094 | dss_mgr_disconnect(dssdev->manager, dssdev); | ||
1095 | } | ||
1096 | |||
1097 | static int hdmi_read_edid(struct omap_dss_device *dssdev, | ||
1098 | u8 *edid, int len) | ||
1099 | { | ||
1100 | bool need_enable; | ||
1101 | int r; | ||
1102 | |||
1103 | need_enable = hdmi.core_enabled == false; | ||
1104 | |||
1105 | if (need_enable) { | ||
1106 | r = omapdss_hdmi_core_enable(dssdev); | ||
1107 | if (r) | ||
1108 | return r; | ||
1109 | } | ||
1110 | |||
1111 | r = omapdss_hdmi_read_edid(edid, len); | ||
1112 | |||
1113 | if (need_enable) | ||
1114 | omapdss_hdmi_core_disable(dssdev); | ||
1115 | |||
1116 | return r; | ||
1117 | } | ||
1118 | |||
1119 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | ||
1120 | static int omapdss_hdmi_audio_enable(struct omap_dss_device *dssdev) | ||
1121 | { | ||
1122 | int r; | ||
1123 | |||
1124 | mutex_lock(&hdmi.lock); | ||
1125 | |||
1126 | if (!hdmi_mode_has_audio()) { | ||
1127 | r = -EPERM; | ||
1128 | goto err; | ||
1129 | } | ||
1130 | |||
1131 | r = hdmi_audio_enable(); | ||
1132 | if (r) | ||
1133 | goto err; | ||
1134 | |||
1135 | mutex_unlock(&hdmi.lock); | ||
1136 | return 0; | ||
1137 | |||
1138 | err: | ||
1139 | mutex_unlock(&hdmi.lock); | ||
1140 | return r; | ||
1141 | } | ||
1142 | |||
1143 | static void omapdss_hdmi_audio_disable(struct omap_dss_device *dssdev) | ||
1144 | { | ||
1145 | hdmi_audio_disable(); | ||
1146 | } | ||
1147 | |||
1148 | static int omapdss_hdmi_audio_start(struct omap_dss_device *dssdev) | ||
1149 | { | ||
1150 | return hdmi_audio_start(); | ||
1151 | } | ||
1152 | |||
1153 | static void omapdss_hdmi_audio_stop(struct omap_dss_device *dssdev) | ||
1154 | { | ||
1155 | hdmi_audio_stop(); | ||
1156 | } | ||
1157 | |||
1158 | static bool omapdss_hdmi_audio_supported(struct omap_dss_device *dssdev) | ||
1159 | { | ||
1160 | bool r; | ||
1161 | |||
1162 | mutex_lock(&hdmi.lock); | ||
1163 | |||
1164 | r = hdmi_mode_has_audio(); | ||
1165 | |||
1166 | mutex_unlock(&hdmi.lock); | ||
1167 | return r; | ||
1168 | } | ||
1169 | |||
1170 | static int omapdss_hdmi_audio_config(struct omap_dss_device *dssdev, | ||
1171 | struct omap_dss_audio *audio) | ||
1172 | { | ||
1173 | int r; | ||
1174 | |||
1175 | mutex_lock(&hdmi.lock); | ||
1176 | |||
1177 | if (!hdmi_mode_has_audio()) { | ||
1178 | r = -EPERM; | ||
1179 | goto err; | ||
1180 | } | ||
1181 | |||
1182 | r = hdmi_audio_config(audio); | ||
1183 | if (r) | ||
1184 | goto err; | ||
1185 | |||
1186 | mutex_unlock(&hdmi.lock); | ||
1187 | return 0; | ||
1188 | |||
1189 | err: | ||
1190 | mutex_unlock(&hdmi.lock); | ||
1191 | return r; | ||
1192 | } | ||
1193 | #else | ||
1194 | static int omapdss_hdmi_audio_enable(struct omap_dss_device *dssdev) | ||
1195 | { | ||
1196 | return -EPERM; | ||
1197 | } | ||
1198 | |||
1199 | static void omapdss_hdmi_audio_disable(struct omap_dss_device *dssdev) | ||
1200 | { | ||
1201 | } | ||
1202 | |||
1203 | static int omapdss_hdmi_audio_start(struct omap_dss_device *dssdev) | ||
1204 | { | ||
1205 | return -EPERM; | ||
1206 | } | ||
1207 | |||
1208 | static void omapdss_hdmi_audio_stop(struct omap_dss_device *dssdev) | ||
1209 | { | ||
1210 | } | ||
1211 | |||
1212 | static bool omapdss_hdmi_audio_supported(struct omap_dss_device *dssdev) | ||
1213 | { | ||
1214 | return false; | ||
1215 | } | ||
1216 | |||
1217 | static int omapdss_hdmi_audio_config(struct omap_dss_device *dssdev, | ||
1218 | struct omap_dss_audio *audio) | ||
1219 | { | ||
1220 | return -EPERM; | ||
1221 | } | ||
1222 | #endif | ||
1223 | |||
1224 | static const struct omapdss_hdmi_ops hdmi_ops = { | ||
1225 | .connect = hdmi_connect, | ||
1226 | .disconnect = hdmi_disconnect, | ||
1227 | |||
1228 | .enable = omapdss_hdmi_display_enable, | ||
1229 | .disable = omapdss_hdmi_display_disable, | ||
1230 | |||
1231 | .check_timings = omapdss_hdmi_display_check_timing, | ||
1232 | .set_timings = omapdss_hdmi_display_set_timing, | ||
1233 | .get_timings = omapdss_hdmi_display_get_timings, | ||
1234 | |||
1235 | .read_edid = hdmi_read_edid, | ||
1236 | |||
1237 | .audio_enable = omapdss_hdmi_audio_enable, | ||
1238 | .audio_disable = omapdss_hdmi_audio_disable, | ||
1239 | .audio_start = omapdss_hdmi_audio_start, | ||
1240 | .audio_stop = omapdss_hdmi_audio_stop, | ||
1241 | .audio_supported = omapdss_hdmi_audio_supported, | ||
1242 | .audio_config = omapdss_hdmi_audio_config, | ||
1243 | }; | ||
1244 | |||
1036 | static void hdmi_init_output(struct platform_device *pdev) | 1245 | static void hdmi_init_output(struct platform_device *pdev) |
1037 | { | 1246 | { |
1038 | struct omap_dss_output *out = &hdmi.output; | 1247 | struct omap_dss_device *out = &hdmi.output; |
1039 | 1248 | ||
1040 | out->pdev = pdev; | 1249 | out->dev = &pdev->dev; |
1041 | out->id = OMAP_DSS_OUTPUT_HDMI; | 1250 | out->id = OMAP_DSS_OUTPUT_HDMI; |
1042 | out->type = OMAP_DISPLAY_TYPE_HDMI; | 1251 | out->output_type = OMAP_DISPLAY_TYPE_HDMI; |
1043 | out->name = "hdmi.0"; | 1252 | out->name = "hdmi.0"; |
1044 | out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; | 1253 | out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; |
1254 | out->ops.hdmi = &hdmi_ops; | ||
1255 | out->owner = THIS_MODULE; | ||
1045 | 1256 | ||
1046 | dss_register_output(out); | 1257 | omapdss_register_output(out); |
1047 | } | 1258 | } |
1048 | 1259 | ||
1049 | static void __exit hdmi_uninit_output(struct platform_device *pdev) | 1260 | static void __exit hdmi_uninit_output(struct platform_device *pdev) |
1050 | { | 1261 | { |
1051 | struct omap_dss_output *out = &hdmi.output; | 1262 | struct omap_dss_device *out = &hdmi.output; |
1052 | 1263 | ||
1053 | dss_unregister_output(out); | 1264 | omapdss_unregister_output(out); |
1054 | } | 1265 | } |
1055 | 1266 | ||
1056 | /* HDMI HW IP initialisation */ | 1267 | /* HDMI HW IP initialisation */ |
@@ -1071,6 +1282,12 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) | |||
1071 | if (IS_ERR(hdmi.ip_data.base_wp)) | 1282 | if (IS_ERR(hdmi.ip_data.base_wp)) |
1072 | return PTR_ERR(hdmi.ip_data.base_wp); | 1283 | return PTR_ERR(hdmi.ip_data.base_wp); |
1073 | 1284 | ||
1285 | hdmi.ip_data.irq = platform_get_irq(pdev, 0); | ||
1286 | if (hdmi.ip_data.irq < 0) { | ||
1287 | DSSERR("platform_get_irq failed\n"); | ||
1288 | return -ENODEV; | ||
1289 | } | ||
1290 | |||
1074 | r = hdmi_get_clocks(pdev); | 1291 | r = hdmi_get_clocks(pdev); |
1075 | if (r) { | 1292 | if (r) { |
1076 | DSSERR("can't get clocks\n"); | 1293 | DSSERR("can't get clocks\n"); |
@@ -1084,6 +1301,10 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) | |||
1084 | hdmi.ip_data.pll_offset = HDMI_PLLCTRL; | 1301 | hdmi.ip_data.pll_offset = HDMI_PLLCTRL; |
1085 | hdmi.ip_data.phy_offset = HDMI_PHY; | 1302 | hdmi.ip_data.phy_offset = HDMI_PHY; |
1086 | 1303 | ||
1304 | hdmi.ct_cp_hpd_gpio = -1; | ||
1305 | hdmi.ls_oe_gpio = -1; | ||
1306 | hdmi.hpd_gpio = -1; | ||
1307 | |||
1087 | hdmi_init_output(pdev); | 1308 | hdmi_init_output(pdev); |
1088 | 1309 | ||
1089 | r = hdmi_panel_init(); | 1310 | r = hdmi_panel_init(); |
@@ -1094,15 +1315,19 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) | |||
1094 | 1315 | ||
1095 | dss_debugfs_create_file("hdmi", hdmi_dump_regs); | 1316 | dss_debugfs_create_file("hdmi", hdmi_dump_regs); |
1096 | 1317 | ||
1097 | r = hdmi_probe_pdata(pdev); | 1318 | if (pdev->dev.platform_data) { |
1098 | if (r) { | 1319 | r = hdmi_probe_pdata(pdev); |
1099 | hdmi_panel_exit(); | 1320 | if (r) |
1100 | hdmi_uninit_output(pdev); | 1321 | goto err_probe; |
1101 | pm_runtime_disable(&pdev->dev); | ||
1102 | return r; | ||
1103 | } | 1322 | } |
1104 | 1323 | ||
1105 | return 0; | 1324 | return 0; |
1325 | |||
1326 | err_probe: | ||
1327 | hdmi_panel_exit(); | ||
1328 | hdmi_uninit_output(pdev); | ||
1329 | pm_runtime_disable(&pdev->dev); | ||
1330 | return r; | ||
1106 | } | 1331 | } |
1107 | 1332 | ||
1108 | static int __exit hdmi_remove_child(struct device *dev, void *data) | 1333 | static int __exit hdmi_remove_child(struct device *dev, void *data) |
diff --git a/drivers/video/omap2/dss/manager-sysfs.c b/drivers/video/omap2/dss/manager-sysfs.c index 9a2fb59b6f89..de7e7b5b1b7c 100644 --- a/drivers/video/omap2/dss/manager-sysfs.c +++ b/drivers/video/omap2/dss/manager-sysfs.c | |||
@@ -50,6 +50,7 @@ static ssize_t manager_display_store(struct omap_overlay_manager *mgr, | |||
50 | int r = 0; | 50 | int r = 0; |
51 | size_t len = size; | 51 | size_t len = size; |
52 | struct omap_dss_device *dssdev = NULL; | 52 | struct omap_dss_device *dssdev = NULL; |
53 | struct omap_dss_device *old_dssdev; | ||
53 | 54 | ||
54 | int match(struct omap_dss_device *dssdev, void *data) | 55 | int match(struct omap_dss_device *dssdev, void *data) |
55 | { | 56 | { |
@@ -66,32 +67,44 @@ static ssize_t manager_display_store(struct omap_overlay_manager *mgr, | |||
66 | if (len > 0 && dssdev == NULL) | 67 | if (len > 0 && dssdev == NULL) |
67 | return -EINVAL; | 68 | return -EINVAL; |
68 | 69 | ||
69 | if (dssdev) | 70 | if (dssdev) { |
70 | DSSDBG("display %s found\n", dssdev->name); | 71 | DSSDBG("display %s found\n", dssdev->name); |
71 | 72 | ||
72 | if (mgr->output) { | 73 | if (omapdss_device_is_connected(dssdev)) { |
73 | r = mgr->unset_output(mgr); | 74 | DSSERR("new display is already connected\n"); |
74 | if (r) { | 75 | r = -EINVAL; |
75 | DSSERR("failed to unset current output\n"); | 76 | goto put_device; |
77 | } | ||
78 | |||
79 | if (omapdss_device_is_enabled(dssdev)) { | ||
80 | DSSERR("new display is not disabled\n"); | ||
81 | r = -EINVAL; | ||
76 | goto put_device; | 82 | goto put_device; |
77 | } | 83 | } |
78 | } | 84 | } |
79 | 85 | ||
80 | if (dssdev) { | 86 | old_dssdev = mgr->get_device(mgr); |
81 | struct omap_dss_output *out = dssdev->output; | 87 | if (old_dssdev) { |
82 | 88 | if (omapdss_device_is_enabled(old_dssdev)) { | |
83 | /* | 89 | DSSERR("old display is not disabled\n"); |
84 | * a registered device should have an output connected to it | 90 | r = -EINVAL; |
85 | * already | ||
86 | */ | ||
87 | if (!out) { | ||
88 | DSSERR("device has no output connected to it\n"); | ||
89 | goto put_device; | 91 | goto put_device; |
90 | } | 92 | } |
91 | 93 | ||
92 | r = mgr->set_output(mgr, out); | 94 | old_dssdev->driver->disconnect(old_dssdev); |
95 | } | ||
96 | |||
97 | if (dssdev) { | ||
98 | r = dssdev->driver->connect(dssdev); | ||
93 | if (r) { | 99 | if (r) { |
94 | DSSERR("failed to set manager output\n"); | 100 | DSSERR("failed to connect new device\n"); |
101 | goto put_device; | ||
102 | } | ||
103 | |||
104 | old_dssdev = mgr->get_device(mgr); | ||
105 | if (old_dssdev != dssdev) { | ||
106 | DSSERR("failed to connect device to this manager\n"); | ||
107 | dssdev->driver->disconnect(dssdev); | ||
95 | goto put_device; | 108 | goto put_device; |
96 | } | 109 | } |
97 | 110 | ||
@@ -509,4 +522,6 @@ void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr) | |||
509 | { | 522 | { |
510 | kobject_del(&mgr->kobj); | 523 | kobject_del(&mgr->kobj); |
511 | kobject_put(&mgr->kobj); | 524 | kobject_put(&mgr->kobj); |
525 | |||
526 | memset(&mgr->kobj, 0, sizeof(mgr->kobj)); | ||
512 | } | 527 | } |
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 2551eaa14c42..1aac9b4191a9 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c | |||
@@ -36,9 +36,9 @@ | |||
36 | static int num_managers; | 36 | static int num_managers; |
37 | static struct omap_overlay_manager *managers; | 37 | static struct omap_overlay_manager *managers; |
38 | 38 | ||
39 | int dss_init_overlay_managers(struct platform_device *pdev) | 39 | int dss_init_overlay_managers(void) |
40 | { | 40 | { |
41 | int i, r; | 41 | int i; |
42 | 42 | ||
43 | num_managers = dss_feat_get_num_mgrs(); | 43 | num_managers = dss_feat_get_num_mgrs(); |
44 | 44 | ||
@@ -76,6 +76,17 @@ int dss_init_overlay_managers(struct platform_device *pdev) | |||
76 | dss_feat_get_supported_outputs(mgr->id); | 76 | dss_feat_get_supported_outputs(mgr->id); |
77 | 77 | ||
78 | INIT_LIST_HEAD(&mgr->overlays); | 78 | INIT_LIST_HEAD(&mgr->overlays); |
79 | } | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | int dss_init_overlay_managers_sysfs(struct platform_device *pdev) | ||
85 | { | ||
86 | int i, r; | ||
87 | |||
88 | for (i = 0; i < num_managers; ++i) { | ||
89 | struct omap_overlay_manager *mgr = &managers[i]; | ||
79 | 90 | ||
80 | r = dss_manager_kobj_init(mgr, pdev); | 91 | r = dss_manager_kobj_init(mgr, pdev); |
81 | if (r) | 92 | if (r) |
@@ -85,18 +96,22 @@ int dss_init_overlay_managers(struct platform_device *pdev) | |||
85 | return 0; | 96 | return 0; |
86 | } | 97 | } |
87 | 98 | ||
88 | void dss_uninit_overlay_managers(struct platform_device *pdev) | 99 | void dss_uninit_overlay_managers(void) |
100 | { | ||
101 | kfree(managers); | ||
102 | managers = NULL; | ||
103 | num_managers = 0; | ||
104 | } | ||
105 | |||
106 | void dss_uninit_overlay_managers_sysfs(struct platform_device *pdev) | ||
89 | { | 107 | { |
90 | int i; | 108 | int i; |
91 | 109 | ||
92 | for (i = 0; i < num_managers; ++i) { | 110 | for (i = 0; i < num_managers; ++i) { |
93 | struct omap_overlay_manager *mgr = &managers[i]; | 111 | struct omap_overlay_manager *mgr = &managers[i]; |
112 | |||
94 | dss_manager_kobj_uninit(mgr); | 113 | dss_manager_kobj_uninit(mgr); |
95 | } | 114 | } |
96 | |||
97 | kfree(managers); | ||
98 | managers = NULL; | ||
99 | num_managers = 0; | ||
100 | } | 115 | } |
101 | 116 | ||
102 | int omap_dss_get_num_overlay_managers(void) | 117 | int omap_dss_get_num_overlay_managers(void) |
diff --git a/drivers/video/omap2/dss/output.c b/drivers/video/omap2/dss/output.c index 5214df63e0a9..3f5c0a758b32 100644 --- a/drivers/video/omap2/dss/output.c +++ b/drivers/video/omap2/dss/output.c | |||
@@ -27,7 +27,7 @@ | |||
27 | static LIST_HEAD(output_list); | 27 | static LIST_HEAD(output_list); |
28 | static DEFINE_MUTEX(output_lock); | 28 | static DEFINE_MUTEX(output_lock); |
29 | 29 | ||
30 | int omapdss_output_set_device(struct omap_dss_output *out, | 30 | int omapdss_output_set_device(struct omap_dss_device *out, |
31 | struct omap_dss_device *dssdev) | 31 | struct omap_dss_device *dssdev) |
32 | { | 32 | { |
33 | int r; | 33 | int r; |
@@ -41,7 +41,7 @@ int omapdss_output_set_device(struct omap_dss_output *out, | |||
41 | goto err; | 41 | goto err; |
42 | } | 42 | } |
43 | 43 | ||
44 | if (out->type != dssdev->type) { | 44 | if (out->output_type != dssdev->type) { |
45 | DSSERR("output type and display type don't match\n"); | 45 | DSSERR("output type and display type don't match\n"); |
46 | r = -EINVAL; | 46 | r = -EINVAL; |
47 | goto err; | 47 | goto err; |
@@ -60,7 +60,7 @@ err: | |||
60 | } | 60 | } |
61 | EXPORT_SYMBOL(omapdss_output_set_device); | 61 | EXPORT_SYMBOL(omapdss_output_set_device); |
62 | 62 | ||
63 | int omapdss_output_unset_device(struct omap_dss_output *out) | 63 | int omapdss_output_unset_device(struct omap_dss_device *out) |
64 | { | 64 | { |
65 | int r; | 65 | int r; |
66 | 66 | ||
@@ -92,19 +92,22 @@ err: | |||
92 | } | 92 | } |
93 | EXPORT_SYMBOL(omapdss_output_unset_device); | 93 | EXPORT_SYMBOL(omapdss_output_unset_device); |
94 | 94 | ||
95 | void dss_register_output(struct omap_dss_output *out) | 95 | int omapdss_register_output(struct omap_dss_device *out) |
96 | { | 96 | { |
97 | list_add_tail(&out->list, &output_list); | 97 | list_add_tail(&out->list, &output_list); |
98 | return 0; | ||
98 | } | 99 | } |
100 | EXPORT_SYMBOL(omapdss_register_output); | ||
99 | 101 | ||
100 | void dss_unregister_output(struct omap_dss_output *out) | 102 | void omapdss_unregister_output(struct omap_dss_device *out) |
101 | { | 103 | { |
102 | list_del(&out->list); | 104 | list_del(&out->list); |
103 | } | 105 | } |
106 | EXPORT_SYMBOL(omapdss_unregister_output); | ||
104 | 107 | ||
105 | struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id) | 108 | struct omap_dss_device *omap_dss_get_output(enum omap_dss_output_id id) |
106 | { | 109 | { |
107 | struct omap_dss_output *out; | 110 | struct omap_dss_device *out; |
108 | 111 | ||
109 | list_for_each_entry(out, &output_list, list) { | 112 | list_for_each_entry(out, &output_list, list) { |
110 | if (out->id == id) | 113 | if (out->id == id) |
@@ -115,6 +118,62 @@ struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id) | |||
115 | } | 118 | } |
116 | EXPORT_SYMBOL(omap_dss_get_output); | 119 | EXPORT_SYMBOL(omap_dss_get_output); |
117 | 120 | ||
121 | struct omap_dss_device *omap_dss_find_output(const char *name) | ||
122 | { | ||
123 | struct omap_dss_device *out; | ||
124 | |||
125 | list_for_each_entry(out, &output_list, list) { | ||
126 | if (strcmp(out->name, name) == 0) | ||
127 | return omap_dss_get_device(out); | ||
128 | } | ||
129 | |||
130 | return NULL; | ||
131 | } | ||
132 | EXPORT_SYMBOL(omap_dss_find_output); | ||
133 | |||
134 | struct omap_dss_device *omap_dss_find_output_by_node(struct device_node *node) | ||
135 | { | ||
136 | struct omap_dss_device *out; | ||
137 | |||
138 | list_for_each_entry(out, &output_list, list) { | ||
139 | if (out->dev->of_node == node) | ||
140 | return omap_dss_get_device(out); | ||
141 | } | ||
142 | |||
143 | return NULL; | ||
144 | } | ||
145 | EXPORT_SYMBOL(omap_dss_find_output_by_node); | ||
146 | |||
147 | struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev) | ||
148 | { | ||
149 | while (dssdev->output) | ||
150 | dssdev = dssdev->output; | ||
151 | |||
152 | if (dssdev->id != 0) | ||
153 | return omap_dss_get_device(dssdev); | ||
154 | |||
155 | return NULL; | ||
156 | } | ||
157 | EXPORT_SYMBOL(omapdss_find_output_from_display); | ||
158 | |||
159 | struct omap_overlay_manager *omapdss_find_mgr_from_display(struct omap_dss_device *dssdev) | ||
160 | { | ||
161 | struct omap_dss_device *out; | ||
162 | struct omap_overlay_manager *mgr; | ||
163 | |||
164 | out = omapdss_find_output_from_display(dssdev); | ||
165 | |||
166 | if (out == NULL) | ||
167 | return NULL; | ||
168 | |||
169 | mgr = out->manager; | ||
170 | |||
171 | omap_dss_put_device(out); | ||
172 | |||
173 | return mgr; | ||
174 | } | ||
175 | EXPORT_SYMBOL(omapdss_find_mgr_from_display); | ||
176 | |||
118 | static const struct dss_mgr_ops *dss_mgr_ops; | 177 | static const struct dss_mgr_ops *dss_mgr_ops; |
119 | 178 | ||
120 | int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops) | 179 | int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops) |
@@ -134,6 +193,20 @@ void dss_uninstall_mgr_ops(void) | |||
134 | } | 193 | } |
135 | EXPORT_SYMBOL(dss_uninstall_mgr_ops); | 194 | EXPORT_SYMBOL(dss_uninstall_mgr_ops); |
136 | 195 | ||
196 | int dss_mgr_connect(struct omap_overlay_manager *mgr, | ||
197 | struct omap_dss_device *dst) | ||
198 | { | ||
199 | return dss_mgr_ops->connect(mgr, dst); | ||
200 | } | ||
201 | EXPORT_SYMBOL(dss_mgr_connect); | ||
202 | |||
203 | void dss_mgr_disconnect(struct omap_overlay_manager *mgr, | ||
204 | struct omap_dss_device *dst) | ||
205 | { | ||
206 | dss_mgr_ops->disconnect(mgr, dst); | ||
207 | } | ||
208 | EXPORT_SYMBOL(dss_mgr_disconnect); | ||
209 | |||
137 | void dss_mgr_set_timings(struct omap_overlay_manager *mgr, | 210 | void dss_mgr_set_timings(struct omap_overlay_manager *mgr, |
138 | const struct omap_video_timings *timings) | 211 | const struct omap_video_timings *timings) |
139 | { | 212 | { |
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 1a17dd1447dc..fdfe6e6f25df 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c | |||
@@ -117,7 +117,7 @@ static struct { | |||
117 | int data_lines; | 117 | int data_lines; |
118 | struct rfbi_timings intf_timings; | 118 | struct rfbi_timings intf_timings; |
119 | 119 | ||
120 | struct omap_dss_output output; | 120 | struct omap_dss_device output; |
121 | } rfbi; | 121 | } rfbi; |
122 | 122 | ||
123 | static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val) | 123 | static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val) |
@@ -312,7 +312,7 @@ static int rfbi_transfer_area(struct omap_dss_device *dssdev, | |||
312 | { | 312 | { |
313 | u32 l; | 313 | u32 l; |
314 | int r; | 314 | int r; |
315 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 315 | struct omap_overlay_manager *mgr = rfbi.output.manager; |
316 | u16 width = rfbi.timings.x_res; | 316 | u16 width = rfbi.timings.x_res; |
317 | u16 height = rfbi.timings.y_res; | 317 | u16 height = rfbi.timings.y_res; |
318 | 318 | ||
@@ -852,7 +852,7 @@ static void rfbi_dump_regs(struct seq_file *s) | |||
852 | 852 | ||
853 | static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev) | 853 | static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev) |
854 | { | 854 | { |
855 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 855 | struct omap_overlay_manager *mgr = rfbi.output.manager; |
856 | struct dss_lcd_mgr_config mgr_config; | 856 | struct dss_lcd_mgr_config mgr_config; |
857 | 857 | ||
858 | mgr_config.io_pad_mode = DSS_IO_PAD_MODE_RFBI; | 858 | mgr_config.io_pad_mode = DSS_IO_PAD_MODE_RFBI; |
@@ -890,7 +890,7 @@ static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev) | |||
890 | 890 | ||
891 | int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) | 891 | int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) |
892 | { | 892 | { |
893 | struct omap_dss_output *out = dssdev->output; | 893 | struct omap_dss_device *out = &rfbi.output; |
894 | int r; | 894 | int r; |
895 | 895 | ||
896 | if (out == NULL || out->manager == NULL) { | 896 | if (out == NULL || out->manager == NULL) { |
@@ -902,12 +902,6 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) | |||
902 | if (r) | 902 | if (r) |
903 | return r; | 903 | return r; |
904 | 904 | ||
905 | r = omap_dss_start_device(dssdev); | ||
906 | if (r) { | ||
907 | DSSERR("failed to start device\n"); | ||
908 | goto err0; | ||
909 | } | ||
910 | |||
911 | r = dss_mgr_register_framedone_handler(out->manager, | 905 | r = dss_mgr_register_framedone_handler(out->manager, |
912 | framedone_callback, NULL); | 906 | framedone_callback, NULL); |
913 | if (r) { | 907 | if (r) { |
@@ -924,8 +918,6 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) | |||
924 | 918 | ||
925 | return 0; | 919 | return 0; |
926 | err1: | 920 | err1: |
927 | omap_dss_stop_device(dssdev); | ||
928 | err0: | ||
929 | rfbi_runtime_put(); | 921 | rfbi_runtime_put(); |
930 | return r; | 922 | return r; |
931 | } | 923 | } |
@@ -933,11 +925,10 @@ EXPORT_SYMBOL(omapdss_rfbi_display_enable); | |||
933 | 925 | ||
934 | void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev) | 926 | void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev) |
935 | { | 927 | { |
936 | struct omap_dss_output *out = dssdev->output; | 928 | struct omap_dss_device *out = &rfbi.output; |
937 | 929 | ||
938 | dss_mgr_unregister_framedone_handler(out->manager, | 930 | dss_mgr_unregister_framedone_handler(out->manager, |
939 | framedone_callback, NULL); | 931 | framedone_callback, NULL); |
940 | omap_dss_stop_device(dssdev); | ||
941 | 932 | ||
942 | rfbi_runtime_put(); | 933 | rfbi_runtime_put(); |
943 | } | 934 | } |
@@ -1022,22 +1013,23 @@ static int rfbi_probe_pdata(struct platform_device *rfbidev) | |||
1022 | 1013 | ||
1023 | static void rfbi_init_output(struct platform_device *pdev) | 1014 | static void rfbi_init_output(struct platform_device *pdev) |
1024 | { | 1015 | { |
1025 | struct omap_dss_output *out = &rfbi.output; | 1016 | struct omap_dss_device *out = &rfbi.output; |
1026 | 1017 | ||
1027 | out->pdev = pdev; | 1018 | out->dev = &pdev->dev; |
1028 | out->id = OMAP_DSS_OUTPUT_DBI; | 1019 | out->id = OMAP_DSS_OUTPUT_DBI; |
1029 | out->type = OMAP_DISPLAY_TYPE_DBI; | 1020 | out->output_type = OMAP_DISPLAY_TYPE_DBI; |
1030 | out->name = "rfbi.0"; | 1021 | out->name = "rfbi.0"; |
1031 | out->dispc_channel = OMAP_DSS_CHANNEL_LCD; | 1022 | out->dispc_channel = OMAP_DSS_CHANNEL_LCD; |
1023 | out->owner = THIS_MODULE; | ||
1032 | 1024 | ||
1033 | dss_register_output(out); | 1025 | omapdss_register_output(out); |
1034 | } | 1026 | } |
1035 | 1027 | ||
1036 | static void __exit rfbi_uninit_output(struct platform_device *pdev) | 1028 | static void __exit rfbi_uninit_output(struct platform_device *pdev) |
1037 | { | 1029 | { |
1038 | struct omap_dss_output *out = &rfbi.output; | 1030 | struct omap_dss_device *out = &rfbi.output; |
1039 | 1031 | ||
1040 | dss_unregister_output(out); | 1032 | omapdss_unregister_output(out); |
1041 | } | 1033 | } |
1042 | 1034 | ||
1043 | /* RFBI HW IP initialisation */ | 1035 | /* RFBI HW IP initialisation */ |
@@ -1093,15 +1085,16 @@ static int omap_rfbihw_probe(struct platform_device *pdev) | |||
1093 | 1085 | ||
1094 | rfbi_init_output(pdev); | 1086 | rfbi_init_output(pdev); |
1095 | 1087 | ||
1096 | r = rfbi_probe_pdata(pdev); | 1088 | if (pdev->dev.platform_data) { |
1097 | if (r) { | 1089 | r = rfbi_probe_pdata(pdev); |
1098 | rfbi_uninit_output(pdev); | 1090 | if (r) |
1099 | pm_runtime_disable(&pdev->dev); | 1091 | goto err_probe; |
1100 | return r; | ||
1101 | } | 1092 | } |
1102 | 1093 | ||
1103 | return 0; | 1094 | return 0; |
1104 | 1095 | ||
1096 | err_probe: | ||
1097 | rfbi_uninit_output(pdev); | ||
1105 | err_runtime_get: | 1098 | err_runtime_get: |
1106 | pm_runtime_disable(&pdev->dev); | 1099 | pm_runtime_disable(&pdev->dev); |
1107 | return r; | 1100 | return r; |
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 0bcd30272f69..856af2e89760 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c | |||
@@ -31,6 +31,8 @@ | |||
31 | #include "dss.h" | 31 | #include "dss.h" |
32 | 32 | ||
33 | static struct { | 33 | static struct { |
34 | struct platform_device *pdev; | ||
35 | |||
34 | bool update_enabled; | 36 | bool update_enabled; |
35 | struct regulator *vdds_sdi_reg; | 37 | struct regulator *vdds_sdi_reg; |
36 | 38 | ||
@@ -38,7 +40,7 @@ static struct { | |||
38 | struct omap_video_timings timings; | 40 | struct omap_video_timings timings; |
39 | int datapairs; | 41 | int datapairs; |
40 | 42 | ||
41 | struct omap_dss_output output; | 43 | struct omap_dss_device output; |
42 | } sdi; | 44 | } sdi; |
43 | 45 | ||
44 | struct sdi_clk_calc_ctx { | 46 | struct sdi_clk_calc_ctx { |
@@ -109,7 +111,7 @@ static int sdi_calc_clock_div(unsigned long pclk, | |||
109 | 111 | ||
110 | static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) | 112 | static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) |
111 | { | 113 | { |
112 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 114 | struct omap_overlay_manager *mgr = sdi.output.manager; |
113 | 115 | ||
114 | sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; | 116 | sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; |
115 | 117 | ||
@@ -124,7 +126,7 @@ static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) | |||
124 | 126 | ||
125 | int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) | 127 | int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) |
126 | { | 128 | { |
127 | struct omap_dss_output *out = dssdev->output; | 129 | struct omap_dss_device *out = &sdi.output; |
128 | struct omap_video_timings *t = &sdi.timings; | 130 | struct omap_video_timings *t = &sdi.timings; |
129 | struct dss_clock_info dss_cinfo; | 131 | struct dss_clock_info dss_cinfo; |
130 | struct dispc_clock_info dispc_cinfo; | 132 | struct dispc_clock_info dispc_cinfo; |
@@ -136,12 +138,6 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) | |||
136 | return -ENODEV; | 138 | return -ENODEV; |
137 | } | 139 | } |
138 | 140 | ||
139 | r = omap_dss_start_device(dssdev); | ||
140 | if (r) { | ||
141 | DSSERR("failed to start device\n"); | ||
142 | goto err_start_dev; | ||
143 | } | ||
144 | |||
145 | r = regulator_enable(sdi.vdds_sdi_reg); | 141 | r = regulator_enable(sdi.vdds_sdi_reg); |
146 | if (r) | 142 | if (r) |
147 | goto err_reg_enable; | 143 | goto err_reg_enable; |
@@ -213,15 +209,13 @@ err_calc_clock_div: | |||
213 | err_get_dispc: | 209 | err_get_dispc: |
214 | regulator_disable(sdi.vdds_sdi_reg); | 210 | regulator_disable(sdi.vdds_sdi_reg); |
215 | err_reg_enable: | 211 | err_reg_enable: |
216 | omap_dss_stop_device(dssdev); | ||
217 | err_start_dev: | ||
218 | return r; | 212 | return r; |
219 | } | 213 | } |
220 | EXPORT_SYMBOL(omapdss_sdi_display_enable); | 214 | EXPORT_SYMBOL(omapdss_sdi_display_enable); |
221 | 215 | ||
222 | void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) | 216 | void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) |
223 | { | 217 | { |
224 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 218 | struct omap_overlay_manager *mgr = sdi.output.manager; |
225 | 219 | ||
226 | dss_mgr_disable(mgr); | 220 | dss_mgr_disable(mgr); |
227 | 221 | ||
@@ -230,8 +224,6 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) | |||
230 | dispc_runtime_put(); | 224 | dispc_runtime_put(); |
231 | 225 | ||
232 | regulator_disable(sdi.vdds_sdi_reg); | 226 | regulator_disable(sdi.vdds_sdi_reg); |
233 | |||
234 | omap_dss_stop_device(dssdev); | ||
235 | } | 227 | } |
236 | EXPORT_SYMBOL(omapdss_sdi_display_disable); | 228 | EXPORT_SYMBOL(omapdss_sdi_display_disable); |
237 | 229 | ||
@@ -242,29 +234,51 @@ void omapdss_sdi_set_timings(struct omap_dss_device *dssdev, | |||
242 | } | 234 | } |
243 | EXPORT_SYMBOL(omapdss_sdi_set_timings); | 235 | EXPORT_SYMBOL(omapdss_sdi_set_timings); |
244 | 236 | ||
237 | static void sdi_get_timings(struct omap_dss_device *dssdev, | ||
238 | struct omap_video_timings *timings) | ||
239 | { | ||
240 | *timings = sdi.timings; | ||
241 | } | ||
242 | |||
243 | static int sdi_check_timings(struct omap_dss_device *dssdev, | ||
244 | struct omap_video_timings *timings) | ||
245 | { | ||
246 | struct omap_overlay_manager *mgr = sdi.output.manager; | ||
247 | |||
248 | if (mgr && !dispc_mgr_timings_ok(mgr->id, timings)) | ||
249 | return -EINVAL; | ||
250 | |||
251 | if (timings->pixel_clock == 0) | ||
252 | return -EINVAL; | ||
253 | |||
254 | return 0; | ||
255 | } | ||
256 | |||
245 | void omapdss_sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs) | 257 | void omapdss_sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs) |
246 | { | 258 | { |
247 | sdi.datapairs = datapairs; | 259 | sdi.datapairs = datapairs; |
248 | } | 260 | } |
249 | EXPORT_SYMBOL(omapdss_sdi_set_datapairs); | 261 | EXPORT_SYMBOL(omapdss_sdi_set_datapairs); |
250 | 262 | ||
251 | static int sdi_init_display(struct omap_dss_device *dssdev) | 263 | static int sdi_init_regulator(void) |
252 | { | 264 | { |
253 | DSSDBG("SDI init\n"); | 265 | struct regulator *vdds_sdi; |
254 | 266 | ||
255 | if (sdi.vdds_sdi_reg == NULL) { | 267 | if (sdi.vdds_sdi_reg) |
256 | struct regulator *vdds_sdi; | 268 | return 0; |
257 | 269 | ||
258 | vdds_sdi = dss_get_vdds_sdi(); | 270 | vdds_sdi = dss_get_vdds_sdi(); |
259 | 271 | ||
272 | if (IS_ERR(vdds_sdi)) { | ||
273 | vdds_sdi = devm_regulator_get(&sdi.pdev->dev, "vdds_sdi"); | ||
260 | if (IS_ERR(vdds_sdi)) { | 274 | if (IS_ERR(vdds_sdi)) { |
261 | DSSERR("can't get VDDS_SDI regulator\n"); | 275 | DSSERR("can't get VDDS_SDI regulator\n"); |
262 | return PTR_ERR(vdds_sdi); | 276 | return PTR_ERR(vdds_sdi); |
263 | } | 277 | } |
264 | |||
265 | sdi.vdds_sdi_reg = vdds_sdi; | ||
266 | } | 278 | } |
267 | 279 | ||
280 | sdi.vdds_sdi_reg = vdds_sdi; | ||
281 | |||
268 | return 0; | 282 | return 0; |
269 | } | 283 | } |
270 | 284 | ||
@@ -313,7 +327,7 @@ static int sdi_probe_pdata(struct platform_device *sdidev) | |||
313 | 327 | ||
314 | dss_copy_device_pdata(dssdev, plat_dssdev); | 328 | dss_copy_device_pdata(dssdev, plat_dssdev); |
315 | 329 | ||
316 | r = sdi_init_display(dssdev); | 330 | r = sdi_init_regulator(); |
317 | if (r) { | 331 | if (r) { |
318 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | 332 | DSSERR("device %s init failed: %d\n", dssdev->name, r); |
319 | dss_put_device(dssdev); | 333 | dss_put_device(dssdev); |
@@ -339,39 +353,104 @@ static int sdi_probe_pdata(struct platform_device *sdidev) | |||
339 | return 0; | 353 | return 0; |
340 | } | 354 | } |
341 | 355 | ||
356 | static int sdi_connect(struct omap_dss_device *dssdev, | ||
357 | struct omap_dss_device *dst) | ||
358 | { | ||
359 | struct omap_overlay_manager *mgr; | ||
360 | int r; | ||
361 | |||
362 | r = sdi_init_regulator(); | ||
363 | if (r) | ||
364 | return r; | ||
365 | |||
366 | mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel); | ||
367 | if (!mgr) | ||
368 | return -ENODEV; | ||
369 | |||
370 | r = dss_mgr_connect(mgr, dssdev); | ||
371 | if (r) | ||
372 | return r; | ||
373 | |||
374 | r = omapdss_output_set_device(dssdev, dst); | ||
375 | if (r) { | ||
376 | DSSERR("failed to connect output to new device: %s\n", | ||
377 | dst->name); | ||
378 | dss_mgr_disconnect(mgr, dssdev); | ||
379 | return r; | ||
380 | } | ||
381 | |||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | static void sdi_disconnect(struct omap_dss_device *dssdev, | ||
386 | struct omap_dss_device *dst) | ||
387 | { | ||
388 | WARN_ON(dst != dssdev->device); | ||
389 | |||
390 | if (dst != dssdev->device) | ||
391 | return; | ||
392 | |||
393 | omapdss_output_unset_device(dssdev); | ||
394 | |||
395 | if (dssdev->manager) | ||
396 | dss_mgr_disconnect(dssdev->manager, dssdev); | ||
397 | } | ||
398 | |||
399 | static const struct omapdss_sdi_ops sdi_ops = { | ||
400 | .connect = sdi_connect, | ||
401 | .disconnect = sdi_disconnect, | ||
402 | |||
403 | .enable = omapdss_sdi_display_enable, | ||
404 | .disable = omapdss_sdi_display_disable, | ||
405 | |||
406 | .check_timings = sdi_check_timings, | ||
407 | .set_timings = omapdss_sdi_set_timings, | ||
408 | .get_timings = sdi_get_timings, | ||
409 | |||
410 | .set_datapairs = omapdss_sdi_set_datapairs, | ||
411 | }; | ||
412 | |||
342 | static void sdi_init_output(struct platform_device *pdev) | 413 | static void sdi_init_output(struct platform_device *pdev) |
343 | { | 414 | { |
344 | struct omap_dss_output *out = &sdi.output; | 415 | struct omap_dss_device *out = &sdi.output; |
345 | 416 | ||
346 | out->pdev = pdev; | 417 | out->dev = &pdev->dev; |
347 | out->id = OMAP_DSS_OUTPUT_SDI; | 418 | out->id = OMAP_DSS_OUTPUT_SDI; |
348 | out->type = OMAP_DISPLAY_TYPE_SDI; | 419 | out->output_type = OMAP_DISPLAY_TYPE_SDI; |
349 | out->name = "sdi.0"; | 420 | out->name = "sdi.0"; |
350 | out->dispc_channel = OMAP_DSS_CHANNEL_LCD; | 421 | out->dispc_channel = OMAP_DSS_CHANNEL_LCD; |
422 | out->ops.sdi = &sdi_ops; | ||
423 | out->owner = THIS_MODULE; | ||
351 | 424 | ||
352 | dss_register_output(out); | 425 | omapdss_register_output(out); |
353 | } | 426 | } |
354 | 427 | ||
355 | static void __exit sdi_uninit_output(struct platform_device *pdev) | 428 | static void __exit sdi_uninit_output(struct platform_device *pdev) |
356 | { | 429 | { |
357 | struct omap_dss_output *out = &sdi.output; | 430 | struct omap_dss_device *out = &sdi.output; |
358 | 431 | ||
359 | dss_unregister_output(out); | 432 | omapdss_unregister_output(out); |
360 | } | 433 | } |
361 | 434 | ||
362 | static int omap_sdi_probe(struct platform_device *pdev) | 435 | static int omap_sdi_probe(struct platform_device *pdev) |
363 | { | 436 | { |
364 | int r; | 437 | int r; |
365 | 438 | ||
439 | sdi.pdev = pdev; | ||
440 | |||
366 | sdi_init_output(pdev); | 441 | sdi_init_output(pdev); |
367 | 442 | ||
368 | r = sdi_probe_pdata(pdev); | 443 | if (pdev->dev.platform_data) { |
369 | if (r) { | 444 | r = sdi_probe_pdata(pdev); |
370 | sdi_uninit_output(pdev); | 445 | if (r) |
371 | return r; | 446 | goto err_probe; |
372 | } | 447 | } |
373 | 448 | ||
374 | return 0; | 449 | return 0; |
450 | |||
451 | err_probe: | ||
452 | sdi_uninit_output(pdev); | ||
453 | return r; | ||
375 | } | 454 | } |
376 | 455 | ||
377 | static int __exit omap_sdi_remove(struct platform_device *pdev) | 456 | static int __exit omap_sdi_remove(struct platform_device *pdev) |
diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h index 216aa704f9d7..45215f44617c 100644 --- a/drivers/video/omap2/dss/ti_hdmi.h +++ b/drivers/video/omap2/dss/ti_hdmi.h | |||
@@ -73,8 +73,6 @@ struct ti_hdmi_ip_ops { | |||
73 | 73 | ||
74 | int (*read_edid)(struct hdmi_ip_data *ip_data, u8 *edid, int len); | 74 | int (*read_edid)(struct hdmi_ip_data *ip_data, u8 *edid, int len); |
75 | 75 | ||
76 | bool (*detect)(struct hdmi_ip_data *ip_data); | ||
77 | |||
78 | int (*pll_enable)(struct hdmi_ip_data *ip_data); | 76 | int (*pll_enable)(struct hdmi_ip_data *ip_data); |
79 | 77 | ||
80 | void (*pll_disable)(struct hdmi_ip_data *ip_data); | 78 | void (*pll_disable)(struct hdmi_ip_data *ip_data); |
@@ -155,19 +153,18 @@ struct hdmi_ip_data { | |||
155 | unsigned long core_av_offset; | 153 | unsigned long core_av_offset; |
156 | unsigned long pll_offset; | 154 | unsigned long pll_offset; |
157 | unsigned long phy_offset; | 155 | unsigned long phy_offset; |
156 | int irq; | ||
158 | const struct ti_hdmi_ip_ops *ops; | 157 | const struct ti_hdmi_ip_ops *ops; |
159 | struct hdmi_config cfg; | 158 | struct hdmi_config cfg; |
160 | struct hdmi_pll_info pll_data; | 159 | struct hdmi_pll_info pll_data; |
161 | struct hdmi_core_infoframe_avi avi_cfg; | 160 | struct hdmi_core_infoframe_avi avi_cfg; |
162 | 161 | ||
163 | /* ti_hdmi_4xxx_ip private data. These should be in a separate struct */ | 162 | /* ti_hdmi_4xxx_ip private data. These should be in a separate struct */ |
164 | int hpd_gpio; | ||
165 | struct mutex lock; | 163 | struct mutex lock; |
166 | }; | 164 | }; |
167 | int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data); | 165 | int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data); |
168 | void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data); | 166 | void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data); |
169 | int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, u8 *edid, int len); | 167 | int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, u8 *edid, int len); |
170 | bool ti_hdmi_4xxx_detect(struct hdmi_ip_data *ip_data); | ||
171 | int ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data); | 168 | int ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data); |
172 | void ti_hdmi_4xxx_wp_video_stop(struct hdmi_ip_data *ip_data); | 169 | void ti_hdmi_4xxx_wp_video_stop(struct hdmi_ip_data *ip_data); |
173 | int ti_hdmi_4xxx_pll_enable(struct hdmi_ip_data *ip_data); | 170 | int ti_hdmi_4xxx_pll_enable(struct hdmi_ip_data *ip_data); |
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c index e18b222ed739..e242ed85cb07 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c | |||
@@ -28,7 +28,6 @@ | |||
28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
29 | #include <linux/string.h> | 29 | #include <linux/string.h> |
30 | #include <linux/seq_file.h> | 30 | #include <linux/seq_file.h> |
31 | #include <linux/gpio.h> | ||
32 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | 31 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) |
33 | #include <sound/asound.h> | 32 | #include <sound/asound.h> |
34 | #include <sound/asoundef.h> | 33 | #include <sound/asoundef.h> |
@@ -38,6 +37,9 @@ | |||
38 | #include "dss.h" | 37 | #include "dss.h" |
39 | #include "dss_features.h" | 38 | #include "dss_features.h" |
40 | 39 | ||
40 | #define HDMI_IRQ_LINK_CONNECT (1 << 25) | ||
41 | #define HDMI_IRQ_LINK_DISCONNECT (1 << 26) | ||
42 | |||
41 | static inline void hdmi_write_reg(void __iomem *base_addr, | 43 | static inline void hdmi_write_reg(void __iomem *base_addr, |
42 | const u16 idx, u32 val) | 44 | const u16 idx, u32 val) |
43 | { | 45 | { |
@@ -233,37 +235,39 @@ void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data) | |||
233 | hdmi_set_pll_pwr(ip_data, HDMI_PLLPWRCMD_ALLOFF); | 235 | hdmi_set_pll_pwr(ip_data, HDMI_PLLPWRCMD_ALLOFF); |
234 | } | 236 | } |
235 | 237 | ||
236 | static int hdmi_check_hpd_state(struct hdmi_ip_data *ip_data) | 238 | static irqreturn_t hdmi_irq_handler(int irq, void *data) |
237 | { | 239 | { |
238 | bool hpd; | 240 | struct hdmi_ip_data *ip_data = data; |
239 | int r; | 241 | void __iomem *wp_base = hdmi_wp_base(ip_data); |
240 | 242 | u32 irqstatus; | |
241 | mutex_lock(&ip_data->lock); | 243 | |
242 | 244 | irqstatus = hdmi_read_reg(wp_base, HDMI_WP_IRQSTATUS); | |
243 | hpd = gpio_get_value(ip_data->hpd_gpio); | 245 | hdmi_write_reg(wp_base, HDMI_WP_IRQSTATUS, irqstatus); |
246 | /* flush posted write */ | ||
247 | hdmi_read_reg(wp_base, HDMI_WP_IRQSTATUS); | ||
248 | |||
249 | if ((irqstatus & HDMI_IRQ_LINK_CONNECT) && | ||
250 | irqstatus & HDMI_IRQ_LINK_DISCONNECT) { | ||
251 | /* | ||
252 | * If we get both connect and disconnect interrupts at the same | ||
253 | * time, turn off the PHY, clear interrupts, and restart, which | ||
254 | * raises connect interrupt if a cable is connected, or nothing | ||
255 | * if cable is not connected. | ||
256 | */ | ||
257 | hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); | ||
244 | 258 | ||
245 | if (hpd) | 259 | hdmi_write_reg(wp_base, HDMI_WP_IRQSTATUS, |
246 | r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_TXON); | 260 | HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT); |
247 | else | 261 | /* flush posted write */ |
248 | r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON); | 262 | hdmi_read_reg(wp_base, HDMI_WP_IRQSTATUS); |
249 | 263 | ||
250 | if (r) { | 264 | hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON); |
251 | DSSERR("Failed to %s PHY TX power\n", | 265 | } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) { |
252 | hpd ? "enable" : "disable"); | 266 | hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_TXON); |
253 | goto err; | 267 | } else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) { |
268 | hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON); | ||
254 | } | 269 | } |
255 | 270 | ||
256 | err: | ||
257 | mutex_unlock(&ip_data->lock); | ||
258 | return r; | ||
259 | } | ||
260 | |||
261 | static irqreturn_t hpd_irq_handler(int irq, void *data) | ||
262 | { | ||
263 | struct hdmi_ip_data *ip_data = data; | ||
264 | |||
265 | hdmi_check_hpd_state(ip_data); | ||
266 | |||
267 | return IRQ_HANDLED; | 271 | return IRQ_HANDLED; |
268 | } | 272 | } |
269 | 273 | ||
@@ -272,6 +276,12 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data) | |||
272 | u16 r = 0; | 276 | u16 r = 0; |
273 | void __iomem *phy_base = hdmi_phy_base(ip_data); | 277 | void __iomem *phy_base = hdmi_phy_base(ip_data); |
274 | 278 | ||
279 | hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_IRQENABLE_CLR, | ||
280 | 0xffffffff); | ||
281 | |||
282 | hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_IRQSTATUS, | ||
283 | HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT); | ||
284 | |||
275 | r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON); | 285 | r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON); |
276 | if (r) | 286 | if (r) |
277 | return r; | 287 | return r; |
@@ -297,29 +307,23 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data) | |||
297 | /* Write to phy address 3 to change the polarity control */ | 307 | /* Write to phy address 3 to change the polarity control */ |
298 | REG_FLD_MOD(phy_base, HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27); | 308 | REG_FLD_MOD(phy_base, HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27); |
299 | 309 | ||
300 | r = request_threaded_irq(gpio_to_irq(ip_data->hpd_gpio), | 310 | r = request_threaded_irq(ip_data->irq, NULL, hdmi_irq_handler, |
301 | NULL, hpd_irq_handler, | 311 | IRQF_ONESHOT, "OMAP HDMI", ip_data); |
302 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | | ||
303 | IRQF_ONESHOT, "hpd", ip_data); | ||
304 | if (r) { | 312 | if (r) { |
305 | DSSERR("HPD IRQ request failed\n"); | 313 | DSSERR("HDMI IRQ request failed\n"); |
306 | hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); | 314 | hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); |
307 | return r; | 315 | return r; |
308 | } | 316 | } |
309 | 317 | ||
310 | r = hdmi_check_hpd_state(ip_data); | 318 | hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_IRQENABLE_SET, |
311 | if (r) { | 319 | HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT); |
312 | free_irq(gpio_to_irq(ip_data->hpd_gpio), ip_data); | ||
313 | hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); | ||
314 | return r; | ||
315 | } | ||
316 | 320 | ||
317 | return 0; | 321 | return 0; |
318 | } | 322 | } |
319 | 323 | ||
320 | void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data) | 324 | void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data) |
321 | { | 325 | { |
322 | free_irq(gpio_to_irq(ip_data->hpd_gpio), ip_data); | 326 | free_irq(ip_data->irq, ip_data); |
323 | 327 | ||
324 | hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); | 328 | hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); |
325 | } | 329 | } |
@@ -476,11 +480,6 @@ int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, | |||
476 | return l; | 480 | return l; |
477 | } | 481 | } |
478 | 482 | ||
479 | bool ti_hdmi_4xxx_detect(struct hdmi_ip_data *ip_data) | ||
480 | { | ||
481 | return gpio_get_value(ip_data->hpd_gpio); | ||
482 | } | ||
483 | |||
484 | static void hdmi_core_init(struct hdmi_core_video_config *video_cfg, | 483 | static void hdmi_core_init(struct hdmi_core_video_config *video_cfg, |
485 | struct hdmi_core_infoframe_avi *avi_cfg, | 484 | struct hdmi_core_infoframe_avi *avi_cfg, |
486 | struct hdmi_core_packet_enable_repeat *repeat_cfg) | 485 | struct hdmi_core_packet_enable_repeat *repeat_cfg) |
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h index 8366ae19e82e..6ef2f929a76d 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h | |||
@@ -33,6 +33,7 @@ | |||
33 | #define HDMI_WP_IRQSTATUS 0x28 | 33 | #define HDMI_WP_IRQSTATUS 0x28 |
34 | #define HDMI_WP_PWR_CTRL 0x40 | 34 | #define HDMI_WP_PWR_CTRL 0x40 |
35 | #define HDMI_WP_IRQENABLE_SET 0x2C | 35 | #define HDMI_WP_IRQENABLE_SET 0x2C |
36 | #define HDMI_WP_IRQENABLE_CLR 0x30 | ||
36 | #define HDMI_WP_VIDEO_CFG 0x50 | 37 | #define HDMI_WP_VIDEO_CFG 0x50 |
37 | #define HDMI_WP_VIDEO_SIZE 0x60 | 38 | #define HDMI_WP_VIDEO_SIZE 0x60 |
38 | #define HDMI_WP_VIDEO_TIMING_H 0x68 | 39 | #define HDMI_WP_VIDEO_TIMING_H 0x68 |
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 74fdb3ee209e..496a106fe823 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c | |||
@@ -304,7 +304,7 @@ static struct { | |||
304 | enum omap_dss_venc_type type; | 304 | enum omap_dss_venc_type type; |
305 | bool invert_polarity; | 305 | bool invert_polarity; |
306 | 306 | ||
307 | struct omap_dss_output output; | 307 | struct omap_dss_device output; |
308 | } venc; | 308 | } venc; |
309 | 309 | ||
310 | static inline void venc_write_reg(int idx, u32 val) | 310 | static inline void venc_write_reg(int idx, u32 val) |
@@ -429,7 +429,7 @@ static const struct venc_config *venc_timings_to_config( | |||
429 | 429 | ||
430 | static int venc_power_on(struct omap_dss_device *dssdev) | 430 | static int venc_power_on(struct omap_dss_device *dssdev) |
431 | { | 431 | { |
432 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 432 | struct omap_overlay_manager *mgr = venc.output.manager; |
433 | u32 l; | 433 | u32 l; |
434 | int r; | 434 | int r; |
435 | 435 | ||
@@ -480,7 +480,7 @@ err0: | |||
480 | 480 | ||
481 | static void venc_power_off(struct omap_dss_device *dssdev) | 481 | static void venc_power_off(struct omap_dss_device *dssdev) |
482 | { | 482 | { |
483 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 483 | struct omap_overlay_manager *mgr = venc.output.manager; |
484 | 484 | ||
485 | venc_write_reg(VENC_OUTPUT_CONTROL, 0); | 485 | venc_write_reg(VENC_OUTPUT_CONTROL, 0); |
486 | dss_set_dac_pwrdn_bgz(0); | 486 | dss_set_dac_pwrdn_bgz(0); |
@@ -492,15 +492,9 @@ static void venc_power_off(struct omap_dss_device *dssdev) | |||
492 | venc_runtime_put(); | 492 | venc_runtime_put(); |
493 | } | 493 | } |
494 | 494 | ||
495 | unsigned long venc_get_pixel_clock(void) | ||
496 | { | ||
497 | /* VENC Pixel Clock in Mhz */ | ||
498 | return 13500000; | ||
499 | } | ||
500 | |||
501 | int omapdss_venc_display_enable(struct omap_dss_device *dssdev) | 495 | int omapdss_venc_display_enable(struct omap_dss_device *dssdev) |
502 | { | 496 | { |
503 | struct omap_dss_output *out = dssdev->output; | 497 | struct omap_dss_device *out = &venc.output; |
504 | int r; | 498 | int r; |
505 | 499 | ||
506 | DSSDBG("venc_display_enable\n"); | 500 | DSSDBG("venc_display_enable\n"); |
@@ -513,23 +507,15 @@ int omapdss_venc_display_enable(struct omap_dss_device *dssdev) | |||
513 | goto err0; | 507 | goto err0; |
514 | } | 508 | } |
515 | 509 | ||
516 | r = omap_dss_start_device(dssdev); | ||
517 | if (r) { | ||
518 | DSSERR("failed to start device\n"); | ||
519 | goto err0; | ||
520 | } | ||
521 | |||
522 | r = venc_power_on(dssdev); | 510 | r = venc_power_on(dssdev); |
523 | if (r) | 511 | if (r) |
524 | goto err1; | 512 | goto err0; |
525 | 513 | ||
526 | venc.wss_data = 0; | 514 | venc.wss_data = 0; |
527 | 515 | ||
528 | mutex_unlock(&venc.venc_lock); | 516 | mutex_unlock(&venc.venc_lock); |
529 | 517 | ||
530 | return 0; | 518 | return 0; |
531 | err1: | ||
532 | omap_dss_stop_device(dssdev); | ||
533 | err0: | 519 | err0: |
534 | mutex_unlock(&venc.venc_lock); | 520 | mutex_unlock(&venc.venc_lock); |
535 | return r; | 521 | return r; |
@@ -543,8 +529,6 @@ void omapdss_venc_display_disable(struct omap_dss_device *dssdev) | |||
543 | 529 | ||
544 | venc_power_off(dssdev); | 530 | venc_power_off(dssdev); |
545 | 531 | ||
546 | omap_dss_stop_device(dssdev); | ||
547 | |||
548 | mutex_unlock(&venc.venc_lock); | 532 | mutex_unlock(&venc.venc_lock); |
549 | } | 533 | } |
550 | 534 | ||
@@ -561,6 +545,8 @@ void omapdss_venc_set_timings(struct omap_dss_device *dssdev, | |||
561 | 545 | ||
562 | venc.timings = *timings; | 546 | venc.timings = *timings; |
563 | 547 | ||
548 | dispc_set_tv_pclk(13500000); | ||
549 | |||
564 | mutex_unlock(&venc.venc_lock); | 550 | mutex_unlock(&venc.venc_lock); |
565 | } | 551 | } |
566 | 552 | ||
@@ -578,6 +564,16 @@ int omapdss_venc_check_timings(struct omap_dss_device *dssdev, | |||
578 | return -EINVAL; | 564 | return -EINVAL; |
579 | } | 565 | } |
580 | 566 | ||
567 | static void venc_get_timings(struct omap_dss_device *dssdev, | ||
568 | struct omap_video_timings *timings) | ||
569 | { | ||
570 | mutex_lock(&venc.venc_lock); | ||
571 | |||
572 | *timings = venc.timings; | ||
573 | |||
574 | mutex_unlock(&venc.venc_lock); | ||
575 | } | ||
576 | |||
581 | u32 omapdss_venc_get_wss(struct omap_dss_device *dssdev) | 577 | u32 omapdss_venc_get_wss(struct omap_dss_device *dssdev) |
582 | { | 578 | { |
583 | /* Invert due to VENC_L21_WC_CTL:INV=1 */ | 579 | /* Invert due to VENC_L21_WC_CTL:INV=1 */ |
@@ -633,23 +629,22 @@ void omapdss_venc_invert_vid_out_polarity(struct omap_dss_device *dssdev, | |||
633 | mutex_unlock(&venc.venc_lock); | 629 | mutex_unlock(&venc.venc_lock); |
634 | } | 630 | } |
635 | 631 | ||
636 | static int venc_init_display(struct omap_dss_device *dssdev) | 632 | static int venc_init_regulator(void) |
637 | { | 633 | { |
638 | DSSDBG("init_display\n"); | 634 | struct regulator *vdda_dac; |
639 | |||
640 | if (venc.vdda_dac_reg == NULL) { | ||
641 | struct regulator *vdda_dac; | ||
642 | 635 | ||
643 | vdda_dac = regulator_get(&venc.pdev->dev, "vdda_dac"); | 636 | if (venc.vdda_dac_reg != NULL) |
637 | return 0; | ||
644 | 638 | ||
645 | if (IS_ERR(vdda_dac)) { | 639 | vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda_dac"); |
646 | DSSERR("can't get VDDA_DAC regulator\n"); | ||
647 | return PTR_ERR(vdda_dac); | ||
648 | } | ||
649 | 640 | ||
650 | venc.vdda_dac_reg = vdda_dac; | 641 | if (IS_ERR(vdda_dac)) { |
642 | DSSERR("can't get VDDA_DAC regulator\n"); | ||
643 | return PTR_ERR(vdda_dac); | ||
651 | } | 644 | } |
652 | 645 | ||
646 | venc.vdda_dac_reg = vdda_dac; | ||
647 | |||
653 | return 0; | 648 | return 0; |
654 | } | 649 | } |
655 | 650 | ||
@@ -765,19 +760,16 @@ static int venc_probe_pdata(struct platform_device *vencdev) | |||
765 | if (!plat_dssdev) | 760 | if (!plat_dssdev) |
766 | return 0; | 761 | return 0; |
767 | 762 | ||
763 | r = venc_init_regulator(); | ||
764 | if (r) | ||
765 | return r; | ||
766 | |||
768 | dssdev = dss_alloc_and_init_device(&vencdev->dev); | 767 | dssdev = dss_alloc_and_init_device(&vencdev->dev); |
769 | if (!dssdev) | 768 | if (!dssdev) |
770 | return -ENOMEM; | 769 | return -ENOMEM; |
771 | 770 | ||
772 | dss_copy_device_pdata(dssdev, plat_dssdev); | 771 | dss_copy_device_pdata(dssdev, plat_dssdev); |
773 | 772 | ||
774 | r = venc_init_display(dssdev); | ||
775 | if (r) { | ||
776 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | ||
777 | dss_put_device(dssdev); | ||
778 | return r; | ||
779 | } | ||
780 | |||
781 | r = omapdss_output_set_device(&venc.output, dssdev); | 773 | r = omapdss_output_set_device(&venc.output, dssdev); |
782 | if (r) { | 774 | if (r) { |
783 | DSSERR("failed to connect output to new device: %s\n", | 775 | DSSERR("failed to connect output to new device: %s\n", |
@@ -797,24 +789,87 @@ static int venc_probe_pdata(struct platform_device *vencdev) | |||
797 | return 0; | 789 | return 0; |
798 | } | 790 | } |
799 | 791 | ||
792 | static int venc_connect(struct omap_dss_device *dssdev, | ||
793 | struct omap_dss_device *dst) | ||
794 | { | ||
795 | struct omap_overlay_manager *mgr; | ||
796 | int r; | ||
797 | |||
798 | r = venc_init_regulator(); | ||
799 | if (r) | ||
800 | return r; | ||
801 | |||
802 | mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel); | ||
803 | if (!mgr) | ||
804 | return -ENODEV; | ||
805 | |||
806 | r = dss_mgr_connect(mgr, dssdev); | ||
807 | if (r) | ||
808 | return r; | ||
809 | |||
810 | r = omapdss_output_set_device(dssdev, dst); | ||
811 | if (r) { | ||
812 | DSSERR("failed to connect output to new device: %s\n", | ||
813 | dst->name); | ||
814 | dss_mgr_disconnect(mgr, dssdev); | ||
815 | return r; | ||
816 | } | ||
817 | |||
818 | return 0; | ||
819 | } | ||
820 | |||
821 | static void venc_disconnect(struct omap_dss_device *dssdev, | ||
822 | struct omap_dss_device *dst) | ||
823 | { | ||
824 | WARN_ON(dst != dssdev->device); | ||
825 | |||
826 | if (dst != dssdev->device) | ||
827 | return; | ||
828 | |||
829 | omapdss_output_unset_device(dssdev); | ||
830 | |||
831 | if (dssdev->manager) | ||
832 | dss_mgr_disconnect(dssdev->manager, dssdev); | ||
833 | } | ||
834 | |||
835 | static const struct omapdss_atv_ops venc_ops = { | ||
836 | .connect = venc_connect, | ||
837 | .disconnect = venc_disconnect, | ||
838 | |||
839 | .enable = omapdss_venc_display_enable, | ||
840 | .disable = omapdss_venc_display_disable, | ||
841 | |||
842 | .check_timings = omapdss_venc_check_timings, | ||
843 | .set_timings = omapdss_venc_set_timings, | ||
844 | .get_timings = venc_get_timings, | ||
845 | |||
846 | .set_type = omapdss_venc_set_type, | ||
847 | .invert_vid_out_polarity = omapdss_venc_invert_vid_out_polarity, | ||
848 | |||
849 | .set_wss = omapdss_venc_set_wss, | ||
850 | .get_wss = omapdss_venc_get_wss, | ||
851 | }; | ||
852 | |||
800 | static void venc_init_output(struct platform_device *pdev) | 853 | static void venc_init_output(struct platform_device *pdev) |
801 | { | 854 | { |
802 | struct omap_dss_output *out = &venc.output; | 855 | struct omap_dss_device *out = &venc.output; |
803 | 856 | ||
804 | out->pdev = pdev; | 857 | out->dev = &pdev->dev; |
805 | out->id = OMAP_DSS_OUTPUT_VENC; | 858 | out->id = OMAP_DSS_OUTPUT_VENC; |
806 | out->type = OMAP_DISPLAY_TYPE_VENC; | 859 | out->output_type = OMAP_DISPLAY_TYPE_VENC; |
807 | out->name = "venc.0"; | 860 | out->name = "venc.0"; |
808 | out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; | 861 | out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; |
862 | out->ops.atv = &venc_ops; | ||
863 | out->owner = THIS_MODULE; | ||
809 | 864 | ||
810 | dss_register_output(out); | 865 | omapdss_register_output(out); |
811 | } | 866 | } |
812 | 867 | ||
813 | static void __exit venc_uninit_output(struct platform_device *pdev) | 868 | static void __exit venc_uninit_output(struct platform_device *pdev) |
814 | { | 869 | { |
815 | struct omap_dss_output *out = &venc.output; | 870 | struct omap_dss_device *out = &venc.output; |
816 | 871 | ||
817 | dss_unregister_output(out); | 872 | omapdss_unregister_output(out); |
818 | } | 873 | } |
819 | 874 | ||
820 | /* VENC HW IP initialisation */ | 875 | /* VENC HW IP initialisation */ |
@@ -866,16 +921,17 @@ static int omap_venchw_probe(struct platform_device *pdev) | |||
866 | 921 | ||
867 | venc_init_output(pdev); | 922 | venc_init_output(pdev); |
868 | 923 | ||
869 | r = venc_probe_pdata(pdev); | 924 | if (pdev->dev.platform_data) { |
870 | if (r) { | 925 | r = venc_probe_pdata(pdev); |
871 | venc_panel_exit(); | 926 | if (r) |
872 | venc_uninit_output(pdev); | 927 | goto err_probe; |
873 | pm_runtime_disable(&pdev->dev); | ||
874 | return r; | ||
875 | } | 928 | } |
876 | 929 | ||
877 | return 0; | 930 | return 0; |
878 | 931 | ||
932 | err_probe: | ||
933 | venc_panel_exit(); | ||
934 | venc_uninit_output(pdev); | ||
879 | err_panel_init: | 935 | err_panel_init: |
880 | err_runtime_get: | 936 | err_runtime_get: |
881 | pm_runtime_disable(&pdev->dev); | 937 | pm_runtime_disable(&pdev->dev); |
@@ -886,11 +942,6 @@ static int __exit omap_venchw_remove(struct platform_device *pdev) | |||
886 | { | 942 | { |
887 | dss_unregister_child_devices(&pdev->dev); | 943 | dss_unregister_child_devices(&pdev->dev); |
888 | 944 | ||
889 | if (venc.vdda_dac_reg != NULL) { | ||
890 | regulator_put(venc.vdda_dac_reg); | ||
891 | venc.vdda_dac_reg = NULL; | ||
892 | } | ||
893 | |||
894 | venc_panel_exit(); | 945 | venc_panel_exit(); |
895 | 946 | ||
896 | venc_uninit_output(pdev); | 947 | venc_uninit_output(pdev); |
diff --git a/drivers/video/omap2/dss/venc_panel.c b/drivers/video/omap2/dss/venc_panel.c index 0d2b1a0834a0..f7d92c57bd73 100644 --- a/drivers/video/omap2/dss/venc_panel.c +++ b/drivers/video/omap2/dss/venc_panel.c | |||
@@ -107,19 +107,19 @@ static int venc_panel_probe(struct omap_dss_device *dssdev) | |||
107 | 107 | ||
108 | dssdev->panel.timings = default_timings; | 108 | dssdev->panel.timings = default_timings; |
109 | 109 | ||
110 | return device_create_file(&dssdev->dev, &dev_attr_output_type); | 110 | return device_create_file(dssdev->dev, &dev_attr_output_type); |
111 | } | 111 | } |
112 | 112 | ||
113 | static void venc_panel_remove(struct omap_dss_device *dssdev) | 113 | static void venc_panel_remove(struct omap_dss_device *dssdev) |
114 | { | 114 | { |
115 | device_remove_file(&dssdev->dev, &dev_attr_output_type); | 115 | device_remove_file(dssdev->dev, &dev_attr_output_type); |
116 | } | 116 | } |
117 | 117 | ||
118 | static int venc_panel_enable(struct omap_dss_device *dssdev) | 118 | static int venc_panel_enable(struct omap_dss_device *dssdev) |
119 | { | 119 | { |
120 | int r; | 120 | int r; |
121 | 121 | ||
122 | dev_dbg(&dssdev->dev, "venc_panel_enable\n"); | 122 | dev_dbg(dssdev->dev, "venc_panel_enable\n"); |
123 | 123 | ||
124 | mutex_lock(&venc_panel.lock); | 124 | mutex_lock(&venc_panel.lock); |
125 | 125 | ||
@@ -150,7 +150,7 @@ err: | |||
150 | 150 | ||
151 | static void venc_panel_disable(struct omap_dss_device *dssdev) | 151 | static void venc_panel_disable(struct omap_dss_device *dssdev) |
152 | { | 152 | { |
153 | dev_dbg(&dssdev->dev, "venc_panel_disable\n"); | 153 | dev_dbg(dssdev->dev, "venc_panel_disable\n"); |
154 | 154 | ||
155 | mutex_lock(&venc_panel.lock); | 155 | mutex_lock(&venc_panel.lock); |
156 | 156 | ||
@@ -167,7 +167,7 @@ end: | |||
167 | static void venc_panel_set_timings(struct omap_dss_device *dssdev, | 167 | static void venc_panel_set_timings(struct omap_dss_device *dssdev, |
168 | struct omap_video_timings *timings) | 168 | struct omap_video_timings *timings) |
169 | { | 169 | { |
170 | dev_dbg(&dssdev->dev, "venc_panel_set_timings\n"); | 170 | dev_dbg(dssdev->dev, "venc_panel_set_timings\n"); |
171 | 171 | ||
172 | mutex_lock(&venc_panel.lock); | 172 | mutex_lock(&venc_panel.lock); |
173 | 173 | ||
@@ -180,21 +180,21 @@ static void venc_panel_set_timings(struct omap_dss_device *dssdev, | |||
180 | static int venc_panel_check_timings(struct omap_dss_device *dssdev, | 180 | static int venc_panel_check_timings(struct omap_dss_device *dssdev, |
181 | struct omap_video_timings *timings) | 181 | struct omap_video_timings *timings) |
182 | { | 182 | { |
183 | dev_dbg(&dssdev->dev, "venc_panel_check_timings\n"); | 183 | dev_dbg(dssdev->dev, "venc_panel_check_timings\n"); |
184 | 184 | ||
185 | return omapdss_venc_check_timings(dssdev, timings); | 185 | return omapdss_venc_check_timings(dssdev, timings); |
186 | } | 186 | } |
187 | 187 | ||
188 | static u32 venc_panel_get_wss(struct omap_dss_device *dssdev) | 188 | static u32 venc_panel_get_wss(struct omap_dss_device *dssdev) |
189 | { | 189 | { |
190 | dev_dbg(&dssdev->dev, "venc_panel_get_wss\n"); | 190 | dev_dbg(dssdev->dev, "venc_panel_get_wss\n"); |
191 | 191 | ||
192 | return omapdss_venc_get_wss(dssdev); | 192 | return omapdss_venc_get_wss(dssdev); |
193 | } | 193 | } |
194 | 194 | ||
195 | static int venc_panel_set_wss(struct omap_dss_device *dssdev, u32 wss) | 195 | static int venc_panel_set_wss(struct omap_dss_device *dssdev, u32 wss) |
196 | { | 196 | { |
197 | dev_dbg(&dssdev->dev, "venc_panel_set_wss\n"); | 197 | dev_dbg(dssdev->dev, "venc_panel_set_wss\n"); |
198 | 198 | ||
199 | return omapdss_venc_set_wss(dssdev, wss); | 199 | return omapdss_venc_set_wss(dssdev, wss); |
200 | } | 200 | } |
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index d30b45d72649..146b6f5428db 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c | |||
@@ -770,12 +770,17 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) | |||
770 | 770 | ||
771 | case OMAPFB_WAITFORVSYNC: | 771 | case OMAPFB_WAITFORVSYNC: |
772 | DBG("ioctl WAITFORVSYNC\n"); | 772 | DBG("ioctl WAITFORVSYNC\n"); |
773 | if (!display || !display->output || !display->output->manager) { | 773 | |
774 | if (!display) { | ||
774 | r = -EINVAL; | 775 | r = -EINVAL; |
775 | break; | 776 | break; |
776 | } | 777 | } |
777 | 778 | ||
778 | mgr = display->output->manager; | 779 | mgr = omapdss_find_mgr_from_display(display); |
780 | if (!mgr) { | ||
781 | r = -EINVAL; | ||
782 | break; | ||
783 | } | ||
779 | 784 | ||
780 | r = mgr->wait_for_vsync(mgr); | 785 | r = mgr->wait_for_vsync(mgr); |
781 | break; | 786 | break; |
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 856917b33616..27d6905683f3 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c | |||
@@ -1853,6 +1853,8 @@ static void omapfb_free_resources(struct omapfb2_device *fbdev) | |||
1853 | if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) | 1853 | if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) |
1854 | dssdev->driver->disable(dssdev); | 1854 | dssdev->driver->disable(dssdev); |
1855 | 1855 | ||
1856 | dssdev->driver->disconnect(dssdev); | ||
1857 | |||
1856 | omap_dss_put_device(dssdev); | 1858 | omap_dss_put_device(dssdev); |
1857 | } | 1859 | } |
1858 | 1860 | ||
@@ -2363,27 +2365,26 @@ static int omapfb_init_connections(struct omapfb2_device *fbdev, | |||
2363 | int i, r; | 2365 | int i, r; |
2364 | struct omap_overlay_manager *mgr; | 2366 | struct omap_overlay_manager *mgr; |
2365 | 2367 | ||
2366 | if (!def_dssdev->output) { | 2368 | r = def_dssdev->driver->connect(def_dssdev); |
2367 | dev_err(fbdev->dev, "no output for the default display\n"); | 2369 | if (r) { |
2368 | return -EINVAL; | 2370 | dev_err(fbdev->dev, "failed to connect default display\n"); |
2371 | return r; | ||
2369 | } | 2372 | } |
2370 | 2373 | ||
2371 | for (i = 0; i < fbdev->num_displays; ++i) { | 2374 | for (i = 0; i < fbdev->num_displays; ++i) { |
2372 | struct omap_dss_device *dssdev = fbdev->displays[i].dssdev; | 2375 | struct omap_dss_device *dssdev = fbdev->displays[i].dssdev; |
2373 | struct omap_dss_output *out = dssdev->output; | ||
2374 | |||
2375 | mgr = omap_dss_get_overlay_manager(out->dispc_channel); | ||
2376 | 2376 | ||
2377 | if (!mgr || !out) | 2377 | if (dssdev == def_dssdev) |
2378 | continue; | 2378 | continue; |
2379 | 2379 | ||
2380 | if (mgr->output) | 2380 | /* |
2381 | mgr->unset_output(mgr); | 2381 | * We don't care if the connect succeeds or not. We just want to |
2382 | 2382 | * connect as many displays as possible. | |
2383 | mgr->set_output(mgr, out); | 2383 | */ |
2384 | dssdev->driver->connect(dssdev); | ||
2384 | } | 2385 | } |
2385 | 2386 | ||
2386 | mgr = def_dssdev->output->manager; | 2387 | mgr = omapdss_find_mgr_from_display(def_dssdev); |
2387 | 2388 | ||
2388 | if (!mgr) { | 2389 | if (!mgr) { |
2389 | dev_err(fbdev->dev, "no ovl manager for the default display\n"); | 2390 | dev_err(fbdev->dev, "no ovl manager for the default display\n"); |
@@ -2502,7 +2503,7 @@ static int omapfb_probe(struct platform_device *pdev) | |||
2502 | 2503 | ||
2503 | if (def_display == NULL) { | 2504 | if (def_display == NULL) { |
2504 | dev_err(fbdev->dev, "failed to find default display\n"); | 2505 | dev_err(fbdev->dev, "failed to find default display\n"); |
2505 | r = -EINVAL; | 2506 | r = -EPROBE_DEFER; |
2506 | goto cleanup; | 2507 | goto cleanup; |
2507 | } | 2508 | } |
2508 | 2509 | ||
diff --git a/drivers/video/pxa3xx-gcu.c b/drivers/video/pxa3xx-gcu.c index 7cf0b13d061b..ad382b3396cd 100644 --- a/drivers/video/pxa3xx-gcu.c +++ b/drivers/video/pxa3xx-gcu.c | |||
@@ -710,7 +710,6 @@ err_misc_deregister: | |||
710 | misc_deregister(&priv->misc_dev); | 710 | misc_deregister(&priv->misc_dev); |
711 | 711 | ||
712 | err_free_priv: | 712 | err_free_priv: |
713 | platform_set_drvdata(dev, NULL); | ||
714 | free_buffers(dev, priv); | 713 | free_buffers(dev, priv); |
715 | kfree(priv); | 714 | kfree(priv); |
716 | return ret; | 715 | return ret; |
@@ -728,7 +727,6 @@ static int pxa3xx_gcu_remove(struct platform_device *dev) | |||
728 | priv->shared, priv->shared_phys); | 727 | priv->shared, priv->shared_phys); |
729 | iounmap(priv->mmio_base); | 728 | iounmap(priv->mmio_base); |
730 | release_mem_region(r->start, resource_size(r)); | 729 | release_mem_region(r->start, resource_size(r)); |
731 | platform_set_drvdata(dev, NULL); | ||
732 | clk_disable(priv->clk); | 730 | clk_disable(priv->clk); |
733 | free_buffers(dev, priv); | 731 | free_buffers(dev, priv); |
734 | kfree(priv); | 732 | kfree(priv); |
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 580f80cc586f..eca2de45f7a6 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c | |||
@@ -2256,7 +2256,6 @@ failed_free_res: | |||
2256 | release_mem_region(r->start, resource_size(r)); | 2256 | release_mem_region(r->start, resource_size(r)); |
2257 | failed_fbi: | 2257 | failed_fbi: |
2258 | clk_put(fbi->clk); | 2258 | clk_put(fbi->clk); |
2259 | platform_set_drvdata(dev, NULL); | ||
2260 | kfree(fbi); | 2259 | kfree(fbi); |
2261 | failed: | 2260 | failed: |
2262 | return ret; | 2261 | return ret; |
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 76a0e7fbd692..21a32adbb8ea 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c | |||
@@ -1005,7 +1005,6 @@ release_regs: | |||
1005 | release_mem: | 1005 | release_mem: |
1006 | release_mem_region(res->start, size); | 1006 | release_mem_region(res->start, size); |
1007 | dealloc_fb: | 1007 | dealloc_fb: |
1008 | platform_set_drvdata(pdev, NULL); | ||
1009 | framebuffer_release(fbinfo); | 1008 | framebuffer_release(fbinfo); |
1010 | return ret; | 1009 | return ret; |
1011 | } | 1010 | } |
@@ -1051,7 +1050,6 @@ static int s3c2410fb_remove(struct platform_device *pdev) | |||
1051 | 1050 | ||
1052 | release_mem_region(info->mem->start, resource_size(info->mem)); | 1051 | release_mem_region(info->mem->start, resource_size(info->mem)); |
1053 | 1052 | ||
1054 | platform_set_drvdata(pdev, NULL); | ||
1055 | framebuffer_release(fbinfo); | 1053 | framebuffer_release(fbinfo); |
1056 | 1054 | ||
1057 | return 0; | 1055 | return 0; |
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c index f34c858642e8..de76da0c6429 100644 --- a/drivers/video/sa1100fb.c +++ b/drivers/video/sa1100fb.c | |||
@@ -1271,7 +1271,6 @@ static int sa1100fb_probe(struct platform_device *pdev) | |||
1271 | failed: | 1271 | failed: |
1272 | if (fbi) | 1272 | if (fbi) |
1273 | iounmap(fbi->base); | 1273 | iounmap(fbi->base); |
1274 | platform_set_drvdata(pdev, NULL); | ||
1275 | kfree(fbi); | 1274 | kfree(fbi); |
1276 | release_mem_region(res->start, resource_size(res)); | 1275 | release_mem_region(res->start, resource_size(res)); |
1277 | return ret; | 1276 | return ret; |
diff --git a/drivers/video/sh7760fb.c b/drivers/video/sh7760fb.c index 5fbb0c7ab0c8..a8c6c43a4658 100644 --- a/drivers/video/sh7760fb.c +++ b/drivers/video/sh7760fb.c | |||
@@ -571,7 +571,6 @@ static int sh7760fb_remove(struct platform_device *dev) | |||
571 | iounmap(par->base); | 571 | iounmap(par->base); |
572 | release_mem_region(par->ioarea->start, resource_size(par->ioarea)); | 572 | release_mem_region(par->ioarea->start, resource_size(par->ioarea)); |
573 | framebuffer_release(info); | 573 | framebuffer_release(info); |
574 | platform_set_drvdata(dev, NULL); | ||
575 | 574 | ||
576 | return 0; | 575 | return 0; |
577 | } | 576 | } |
diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c index 6cad53075e99..8f6e8ff620d4 100644 --- a/drivers/video/sh_mipi_dsi.c +++ b/drivers/video/sh_mipi_dsi.c | |||
@@ -567,7 +567,6 @@ static int sh_mipi_remove(struct platform_device *pdev) | |||
567 | iounmap(mipi->base); | 567 | iounmap(mipi->base); |
568 | if (res) | 568 | if (res) |
569 | release_mem_region(res->start, resource_size(res)); | 569 | release_mem_region(res->start, resource_size(res)); |
570 | platform_set_drvdata(pdev, NULL); | ||
571 | kfree(mipi); | 570 | kfree(mipi); |
572 | 571 | ||
573 | return 0; | 572 | return 0; |
diff --git a/drivers/video/smscufx.c b/drivers/video/smscufx.c index b2b33fc1ac3f..e188ada2ffd1 100644 --- a/drivers/video/smscufx.c +++ b/drivers/video/smscufx.c | |||
@@ -1622,7 +1622,7 @@ static int ufx_usb_probe(struct usb_interface *interface, | |||
1622 | { | 1622 | { |
1623 | struct usb_device *usbdev; | 1623 | struct usb_device *usbdev; |
1624 | struct ufx_data *dev; | 1624 | struct ufx_data *dev; |
1625 | struct fb_info *info = 0; | 1625 | struct fb_info *info = NULL; |
1626 | int retval = -ENOMEM; | 1626 | int retval = -ENOMEM; |
1627 | u32 id_rev, fpga_rev; | 1627 | u32 id_rev, fpga_rev; |
1628 | 1628 | ||
diff --git a/drivers/video/ssd1307fb.c b/drivers/video/ssd1307fb.c index 9ef05d3ef68a..44967c8fef2b 100644 --- a/drivers/video/ssd1307fb.c +++ b/drivers/video/ssd1307fb.c | |||
@@ -16,24 +16,50 @@ | |||
16 | #include <linux/pwm.h> | 16 | #include <linux/pwm.h> |
17 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
18 | 18 | ||
19 | #define SSD1307FB_WIDTH 96 | ||
20 | #define SSD1307FB_HEIGHT 16 | ||
21 | |||
22 | #define SSD1307FB_DATA 0x40 | 19 | #define SSD1307FB_DATA 0x40 |
23 | #define SSD1307FB_COMMAND 0x80 | 20 | #define SSD1307FB_COMMAND 0x80 |
24 | 21 | ||
22 | #define SSD1307FB_SET_ADDRESS_MODE 0x20 | ||
23 | #define SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL (0x00) | ||
24 | #define SSD1307FB_SET_ADDRESS_MODE_VERTICAL (0x01) | ||
25 | #define SSD1307FB_SET_ADDRESS_MODE_PAGE (0x02) | ||
26 | #define SSD1307FB_SET_COL_RANGE 0x21 | ||
27 | #define SSD1307FB_SET_PAGE_RANGE 0x22 | ||
25 | #define SSD1307FB_CONTRAST 0x81 | 28 | #define SSD1307FB_CONTRAST 0x81 |
29 | #define SSD1307FB_CHARGE_PUMP 0x8d | ||
26 | #define SSD1307FB_SEG_REMAP_ON 0xa1 | 30 | #define SSD1307FB_SEG_REMAP_ON 0xa1 |
27 | #define SSD1307FB_DISPLAY_OFF 0xae | 31 | #define SSD1307FB_DISPLAY_OFF 0xae |
32 | #define SSD1307FB_SET_MULTIPLEX_RATIO 0xa8 | ||
28 | #define SSD1307FB_DISPLAY_ON 0xaf | 33 | #define SSD1307FB_DISPLAY_ON 0xaf |
29 | #define SSD1307FB_START_PAGE_ADDRESS 0xb0 | 34 | #define SSD1307FB_START_PAGE_ADDRESS 0xb0 |
35 | #define SSD1307FB_SET_DISPLAY_OFFSET 0xd3 | ||
36 | #define SSD1307FB_SET_CLOCK_FREQ 0xd5 | ||
37 | #define SSD1307FB_SET_PRECHARGE_PERIOD 0xd9 | ||
38 | #define SSD1307FB_SET_COM_PINS_CONFIG 0xda | ||
39 | #define SSD1307FB_SET_VCOMH 0xdb | ||
40 | |||
41 | struct ssd1307fb_par; | ||
42 | |||
43 | struct ssd1307fb_ops { | ||
44 | int (*init)(struct ssd1307fb_par *); | ||
45 | int (*remove)(struct ssd1307fb_par *); | ||
46 | }; | ||
30 | 47 | ||
31 | struct ssd1307fb_par { | 48 | struct ssd1307fb_par { |
32 | struct i2c_client *client; | 49 | struct i2c_client *client; |
50 | u32 height; | ||
33 | struct fb_info *info; | 51 | struct fb_info *info; |
52 | struct ssd1307fb_ops *ops; | ||
53 | u32 page_offset; | ||
34 | struct pwm_device *pwm; | 54 | struct pwm_device *pwm; |
35 | u32 pwm_period; | 55 | u32 pwm_period; |
36 | int reset; | 56 | int reset; |
57 | u32 width; | ||
58 | }; | ||
59 | |||
60 | struct ssd1307fb_array { | ||
61 | u8 type; | ||
62 | u8 data[0]; | ||
37 | }; | 63 | }; |
38 | 64 | ||
39 | static struct fb_fix_screeninfo ssd1307fb_fix = { | 65 | static struct fb_fix_screeninfo ssd1307fb_fix = { |
@@ -43,68 +69,87 @@ static struct fb_fix_screeninfo ssd1307fb_fix = { | |||
43 | .xpanstep = 0, | 69 | .xpanstep = 0, |
44 | .ypanstep = 0, | 70 | .ypanstep = 0, |
45 | .ywrapstep = 0, | 71 | .ywrapstep = 0, |
46 | .line_length = SSD1307FB_WIDTH / 8, | ||
47 | .accel = FB_ACCEL_NONE, | 72 | .accel = FB_ACCEL_NONE, |
48 | }; | 73 | }; |
49 | 74 | ||
50 | static struct fb_var_screeninfo ssd1307fb_var = { | 75 | static struct fb_var_screeninfo ssd1307fb_var = { |
51 | .xres = SSD1307FB_WIDTH, | ||
52 | .yres = SSD1307FB_HEIGHT, | ||
53 | .xres_virtual = SSD1307FB_WIDTH, | ||
54 | .yres_virtual = SSD1307FB_HEIGHT, | ||
55 | .bits_per_pixel = 1, | 76 | .bits_per_pixel = 1, |
56 | }; | 77 | }; |
57 | 78 | ||
58 | static int ssd1307fb_write_array(struct i2c_client *client, u8 type, u8 *cmd, u32 len) | 79 | static struct ssd1307fb_array *ssd1307fb_alloc_array(u32 len, u8 type) |
59 | { | 80 | { |
60 | u8 *buf; | 81 | struct ssd1307fb_array *array; |
61 | int ret = 0; | ||
62 | |||
63 | buf = kzalloc(len + 1, GFP_KERNEL); | ||
64 | if (!buf) { | ||
65 | dev_err(&client->dev, "Couldn't allocate sending buffer.\n"); | ||
66 | return -ENOMEM; | ||
67 | } | ||
68 | 82 | ||
69 | buf[0] = type; | 83 | array = kzalloc(sizeof(struct ssd1307fb_array) + len, GFP_KERNEL); |
70 | memcpy(buf + 1, cmd, len); | 84 | if (!array) |
85 | return NULL; | ||
71 | 86 | ||
72 | ret = i2c_master_send(client, buf, len + 1); | 87 | array->type = type; |
73 | if (ret != len + 1) { | ||
74 | dev_err(&client->dev, "Couldn't send I2C command.\n"); | ||
75 | goto error; | ||
76 | } | ||
77 | 88 | ||
78 | error: | 89 | return array; |
79 | kfree(buf); | ||
80 | return ret; | ||
81 | } | 90 | } |
82 | 91 | ||
83 | static inline int ssd1307fb_write_cmd_array(struct i2c_client *client, u8 *cmd, u32 len) | 92 | static int ssd1307fb_write_array(struct i2c_client *client, |
93 | struct ssd1307fb_array *array, u32 len) | ||
84 | { | 94 | { |
85 | return ssd1307fb_write_array(client, SSD1307FB_COMMAND, cmd, len); | 95 | int ret; |
96 | |||
97 | len += sizeof(struct ssd1307fb_array); | ||
98 | |||
99 | ret = i2c_master_send(client, (u8 *)array, len); | ||
100 | if (ret != len) { | ||
101 | dev_err(&client->dev, "Couldn't send I2C command.\n"); | ||
102 | return ret; | ||
103 | } | ||
104 | |||
105 | return 0; | ||
86 | } | 106 | } |
87 | 107 | ||
88 | static inline int ssd1307fb_write_cmd(struct i2c_client *client, u8 cmd) | 108 | static inline int ssd1307fb_write_cmd(struct i2c_client *client, u8 cmd) |
89 | { | 109 | { |
90 | return ssd1307fb_write_cmd_array(client, &cmd, 1); | 110 | struct ssd1307fb_array *array; |
91 | } | 111 | int ret; |
92 | 112 | ||
93 | static inline int ssd1307fb_write_data_array(struct i2c_client *client, u8 *cmd, u32 len) | 113 | array = ssd1307fb_alloc_array(1, SSD1307FB_COMMAND); |
94 | { | 114 | if (!array) |
95 | return ssd1307fb_write_array(client, SSD1307FB_DATA, cmd, len); | 115 | return -ENOMEM; |
116 | |||
117 | array->data[0] = cmd; | ||
118 | |||
119 | ret = ssd1307fb_write_array(client, array, 1); | ||
120 | kfree(array); | ||
121 | |||
122 | return ret; | ||
96 | } | 123 | } |
97 | 124 | ||
98 | static inline int ssd1307fb_write_data(struct i2c_client *client, u8 data) | 125 | static inline int ssd1307fb_write_data(struct i2c_client *client, u8 data) |
99 | { | 126 | { |
100 | return ssd1307fb_write_data_array(client, &data, 1); | 127 | struct ssd1307fb_array *array; |
128 | int ret; | ||
129 | |||
130 | array = ssd1307fb_alloc_array(1, SSD1307FB_DATA); | ||
131 | if (!array) | ||
132 | return -ENOMEM; | ||
133 | |||
134 | array->data[0] = data; | ||
135 | |||
136 | ret = ssd1307fb_write_array(client, array, 1); | ||
137 | kfree(array); | ||
138 | |||
139 | return ret; | ||
101 | } | 140 | } |
102 | 141 | ||
103 | static void ssd1307fb_update_display(struct ssd1307fb_par *par) | 142 | static void ssd1307fb_update_display(struct ssd1307fb_par *par) |
104 | { | 143 | { |
144 | struct ssd1307fb_array *array; | ||
105 | u8 *vmem = par->info->screen_base; | 145 | u8 *vmem = par->info->screen_base; |
106 | int i, j, k; | 146 | int i, j, k; |
107 | 147 | ||
148 | array = ssd1307fb_alloc_array(par->width * par->height / 8, | ||
149 | SSD1307FB_DATA); | ||
150 | if (!array) | ||
151 | return; | ||
152 | |||
108 | /* | 153 | /* |
109 | * The screen is divided in pages, each having a height of 8 | 154 | * The screen is divided in pages, each having a height of 8 |
110 | * pixels, and the width of the screen. When sending a byte of | 155 | * pixels, and the width of the screen. When sending a byte of |
@@ -134,24 +179,23 @@ static void ssd1307fb_update_display(struct ssd1307fb_par *par) | |||
134 | * (5) A4 B4 C4 D4 E4 F4 G4 H4 | 179 | * (5) A4 B4 C4 D4 E4 F4 G4 H4 |
135 | */ | 180 | */ |
136 | 181 | ||
137 | for (i = 0; i < (SSD1307FB_HEIGHT / 8); i++) { | 182 | for (i = 0; i < (par->height / 8); i++) { |
138 | ssd1307fb_write_cmd(par->client, SSD1307FB_START_PAGE_ADDRESS + (i + 1)); | 183 | for (j = 0; j < par->width; j++) { |
139 | ssd1307fb_write_cmd(par->client, 0x00); | 184 | u32 array_idx = i * par->width + j; |
140 | ssd1307fb_write_cmd(par->client, 0x10); | 185 | array->data[array_idx] = 0; |
141 | |||
142 | for (j = 0; j < SSD1307FB_WIDTH; j++) { | ||
143 | u8 buf = 0; | ||
144 | for (k = 0; k < 8; k++) { | 186 | for (k = 0; k < 8; k++) { |
145 | u32 page_length = SSD1307FB_WIDTH * i; | 187 | u32 page_length = par->width * i; |
146 | u32 index = page_length + (SSD1307FB_WIDTH * k + j) / 8; | 188 | u32 index = page_length + (par->width * k + j) / 8; |
147 | u8 byte = *(vmem + index); | 189 | u8 byte = *(vmem + index); |
148 | u8 bit = byte & (1 << (j % 8)); | 190 | u8 bit = byte & (1 << (j % 8)); |
149 | bit = bit >> (j % 8); | 191 | bit = bit >> (j % 8); |
150 | buf |= bit << k; | 192 | array->data[array_idx] |= bit << k; |
151 | } | 193 | } |
152 | ssd1307fb_write_data(par->client, buf); | ||
153 | } | 194 | } |
154 | } | 195 | } |
196 | |||
197 | ssd1307fb_write_array(par->client, array, par->width * par->height / 8); | ||
198 | kfree(array); | ||
155 | } | 199 | } |
156 | 200 | ||
157 | 201 | ||
@@ -227,16 +271,167 @@ static struct fb_deferred_io ssd1307fb_defio = { | |||
227 | .deferred_io = ssd1307fb_deferred_io, | 271 | .deferred_io = ssd1307fb_deferred_io, |
228 | }; | 272 | }; |
229 | 273 | ||
274 | static int ssd1307fb_ssd1307_init(struct ssd1307fb_par *par) | ||
275 | { | ||
276 | int ret; | ||
277 | |||
278 | par->pwm = pwm_get(&par->client->dev, NULL); | ||
279 | if (IS_ERR(par->pwm)) { | ||
280 | dev_err(&par->client->dev, "Could not get PWM from device tree!\n"); | ||
281 | return PTR_ERR(par->pwm); | ||
282 | } | ||
283 | |||
284 | par->pwm_period = pwm_get_period(par->pwm); | ||
285 | /* Enable the PWM */ | ||
286 | pwm_config(par->pwm, par->pwm_period / 2, par->pwm_period); | ||
287 | pwm_enable(par->pwm); | ||
288 | |||
289 | dev_dbg(&par->client->dev, "Using PWM%d with a %dns period.\n", | ||
290 | par->pwm->pwm, par->pwm_period); | ||
291 | |||
292 | /* Map column 127 of the OLED to segment 0 */ | ||
293 | ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SEG_REMAP_ON); | ||
294 | if (ret < 0) | ||
295 | return ret; | ||
296 | |||
297 | /* Turn on the display */ | ||
298 | ret = ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON); | ||
299 | if (ret < 0) | ||
300 | return ret; | ||
301 | |||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | static int ssd1307fb_ssd1307_remove(struct ssd1307fb_par *par) | ||
306 | { | ||
307 | pwm_disable(par->pwm); | ||
308 | pwm_put(par->pwm); | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static struct ssd1307fb_ops ssd1307fb_ssd1307_ops = { | ||
313 | .init = ssd1307fb_ssd1307_init, | ||
314 | .remove = ssd1307fb_ssd1307_remove, | ||
315 | }; | ||
316 | |||
317 | static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par) | ||
318 | { | ||
319 | int ret; | ||
320 | |||
321 | /* Set initial contrast */ | ||
322 | ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CONTRAST); | ||
323 | ret = ret & ssd1307fb_write_cmd(par->client, 0x7f); | ||
324 | if (ret < 0) | ||
325 | return ret; | ||
326 | |||
327 | /* Set COM direction */ | ||
328 | ret = ssd1307fb_write_cmd(par->client, 0xc8); | ||
329 | if (ret < 0) | ||
330 | return ret; | ||
331 | |||
332 | /* Set segment re-map */ | ||
333 | ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SEG_REMAP_ON); | ||
334 | if (ret < 0) | ||
335 | return ret; | ||
336 | |||
337 | /* Set multiplex ratio value */ | ||
338 | ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_MULTIPLEX_RATIO); | ||
339 | ret = ret & ssd1307fb_write_cmd(par->client, par->height - 1); | ||
340 | if (ret < 0) | ||
341 | return ret; | ||
342 | |||
343 | /* set display offset value */ | ||
344 | ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_DISPLAY_OFFSET); | ||
345 | ret = ssd1307fb_write_cmd(par->client, 0x20); | ||
346 | if (ret < 0) | ||
347 | return ret; | ||
348 | |||
349 | /* Set clock frequency */ | ||
350 | ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_CLOCK_FREQ); | ||
351 | ret = ret & ssd1307fb_write_cmd(par->client, 0xf0); | ||
352 | if (ret < 0) | ||
353 | return ret; | ||
354 | |||
355 | /* Set precharge period in number of ticks from the internal clock */ | ||
356 | ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PRECHARGE_PERIOD); | ||
357 | ret = ret & ssd1307fb_write_cmd(par->client, 0x22); | ||
358 | if (ret < 0) | ||
359 | return ret; | ||
360 | |||
361 | /* Set COM pins configuration */ | ||
362 | ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COM_PINS_CONFIG); | ||
363 | ret = ret & ssd1307fb_write_cmd(par->client, 0x22); | ||
364 | if (ret < 0) | ||
365 | return ret; | ||
366 | |||
367 | /* Set VCOMH */ | ||
368 | ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_VCOMH); | ||
369 | ret = ret & ssd1307fb_write_cmd(par->client, 0x49); | ||
370 | if (ret < 0) | ||
371 | return ret; | ||
372 | |||
373 | /* Turn on the DC-DC Charge Pump */ | ||
374 | ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CHARGE_PUMP); | ||
375 | ret = ret & ssd1307fb_write_cmd(par->client, 0x14); | ||
376 | if (ret < 0) | ||
377 | return ret; | ||
378 | |||
379 | /* Switch to horizontal addressing mode */ | ||
380 | ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_ADDRESS_MODE); | ||
381 | ret = ret & ssd1307fb_write_cmd(par->client, | ||
382 | SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL); | ||
383 | if (ret < 0) | ||
384 | return ret; | ||
385 | |||
386 | ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COL_RANGE); | ||
387 | ret = ret & ssd1307fb_write_cmd(par->client, 0x0); | ||
388 | ret = ret & ssd1307fb_write_cmd(par->client, par->width - 1); | ||
389 | if (ret < 0) | ||
390 | return ret; | ||
391 | |||
392 | ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PAGE_RANGE); | ||
393 | ret = ret & ssd1307fb_write_cmd(par->client, 0x0); | ||
394 | ret = ret & ssd1307fb_write_cmd(par->client, | ||
395 | par->page_offset + (par->height / 8) - 1); | ||
396 | if (ret < 0) | ||
397 | return ret; | ||
398 | |||
399 | /* Turn on the display */ | ||
400 | ret = ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON); | ||
401 | if (ret < 0) | ||
402 | return ret; | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static struct ssd1307fb_ops ssd1307fb_ssd1306_ops = { | ||
408 | .init = ssd1307fb_ssd1306_init, | ||
409 | }; | ||
410 | |||
411 | static const struct of_device_id ssd1307fb_of_match[] = { | ||
412 | { | ||
413 | .compatible = "solomon,ssd1306fb-i2c", | ||
414 | .data = (void *)&ssd1307fb_ssd1306_ops, | ||
415 | }, | ||
416 | { | ||
417 | .compatible = "solomon,ssd1307fb-i2c", | ||
418 | .data = (void *)&ssd1307fb_ssd1307_ops, | ||
419 | }, | ||
420 | {}, | ||
421 | }; | ||
422 | MODULE_DEVICE_TABLE(of, ssd1307fb_of_match); | ||
423 | |||
230 | static int ssd1307fb_probe(struct i2c_client *client, | 424 | static int ssd1307fb_probe(struct i2c_client *client, |
231 | const struct i2c_device_id *id) | 425 | const struct i2c_device_id *id) |
232 | { | 426 | { |
233 | struct fb_info *info; | 427 | struct fb_info *info; |
234 | u32 vmem_size = SSD1307FB_WIDTH * SSD1307FB_HEIGHT / 8; | 428 | struct device_node *node = client->dev.of_node; |
429 | u32 vmem_size; | ||
235 | struct ssd1307fb_par *par; | 430 | struct ssd1307fb_par *par; |
236 | u8 *vmem; | 431 | u8 *vmem; |
237 | int ret; | 432 | int ret; |
238 | 433 | ||
239 | if (!client->dev.of_node) { | 434 | if (!node) { |
240 | dev_err(&client->dev, "No device tree data found!\n"); | 435 | dev_err(&client->dev, "No device tree data found!\n"); |
241 | return -EINVAL; | 436 | return -EINVAL; |
242 | } | 437 | } |
@@ -247,6 +442,31 @@ static int ssd1307fb_probe(struct i2c_client *client, | |||
247 | return -ENOMEM; | 442 | return -ENOMEM; |
248 | } | 443 | } |
249 | 444 | ||
445 | par = info->par; | ||
446 | par->info = info; | ||
447 | par->client = client; | ||
448 | |||
449 | par->ops = (struct ssd1307fb_ops *)of_match_device(ssd1307fb_of_match, | ||
450 | &client->dev)->data; | ||
451 | |||
452 | par->reset = of_get_named_gpio(client->dev.of_node, | ||
453 | "reset-gpios", 0); | ||
454 | if (!gpio_is_valid(par->reset)) { | ||
455 | ret = -EINVAL; | ||
456 | goto fb_alloc_error; | ||
457 | } | ||
458 | |||
459 | if (of_property_read_u32(node, "solomon,width", &par->width)) | ||
460 | par->width = 96; | ||
461 | |||
462 | if (of_property_read_u32(node, "solomon,height", &par->height)) | ||
463 | par->width = 16; | ||
464 | |||
465 | if (of_property_read_u32(node, "solomon,page-offset", &par->page_offset)) | ||
466 | par->page_offset = 1; | ||
467 | |||
468 | vmem_size = par->width * par->height / 8; | ||
469 | |||
250 | vmem = devm_kzalloc(&client->dev, vmem_size, GFP_KERNEL); | 470 | vmem = devm_kzalloc(&client->dev, vmem_size, GFP_KERNEL); |
251 | if (!vmem) { | 471 | if (!vmem) { |
252 | dev_err(&client->dev, "Couldn't allocate graphical memory.\n"); | 472 | dev_err(&client->dev, "Couldn't allocate graphical memory.\n"); |
@@ -256,9 +476,15 @@ static int ssd1307fb_probe(struct i2c_client *client, | |||
256 | 476 | ||
257 | info->fbops = &ssd1307fb_ops; | 477 | info->fbops = &ssd1307fb_ops; |
258 | info->fix = ssd1307fb_fix; | 478 | info->fix = ssd1307fb_fix; |
479 | info->fix.line_length = par->width / 8; | ||
259 | info->fbdefio = &ssd1307fb_defio; | 480 | info->fbdefio = &ssd1307fb_defio; |
260 | 481 | ||
261 | info->var = ssd1307fb_var; | 482 | info->var = ssd1307fb_var; |
483 | info->var.xres = par->width; | ||
484 | info->var.xres_virtual = par->width; | ||
485 | info->var.yres = par->height; | ||
486 | info->var.yres_virtual = par->height; | ||
487 | |||
262 | info->var.red.length = 1; | 488 | info->var.red.length = 1; |
263 | info->var.red.offset = 0; | 489 | info->var.red.offset = 0; |
264 | info->var.green.length = 1; | 490 | info->var.green.length = 1; |
@@ -272,17 +498,6 @@ static int ssd1307fb_probe(struct i2c_client *client, | |||
272 | 498 | ||
273 | fb_deferred_io_init(info); | 499 | fb_deferred_io_init(info); |
274 | 500 | ||
275 | par = info->par; | ||
276 | par->info = info; | ||
277 | par->client = client; | ||
278 | |||
279 | par->reset = of_get_named_gpio(client->dev.of_node, | ||
280 | "reset-gpios", 0); | ||
281 | if (!gpio_is_valid(par->reset)) { | ||
282 | ret = -EINVAL; | ||
283 | goto reset_oled_error; | ||
284 | } | ||
285 | |||
286 | ret = devm_gpio_request_one(&client->dev, par->reset, | 501 | ret = devm_gpio_request_one(&client->dev, par->reset, |
287 | GPIOF_OUT_INIT_HIGH, | 502 | GPIOF_OUT_INIT_HIGH, |
288 | "oled-reset"); | 503 | "oled-reset"); |
@@ -293,23 +508,6 @@ static int ssd1307fb_probe(struct i2c_client *client, | |||
293 | goto reset_oled_error; | 508 | goto reset_oled_error; |
294 | } | 509 | } |
295 | 510 | ||
296 | par->pwm = pwm_get(&client->dev, NULL); | ||
297 | if (IS_ERR(par->pwm)) { | ||
298 | dev_err(&client->dev, "Could not get PWM from device tree!\n"); | ||
299 | ret = PTR_ERR(par->pwm); | ||
300 | goto pwm_error; | ||
301 | } | ||
302 | |||
303 | par->pwm_period = pwm_get_period(par->pwm); | ||
304 | |||
305 | dev_dbg(&client->dev, "Using PWM%d with a %dns period.\n", par->pwm->pwm, par->pwm_period); | ||
306 | |||
307 | ret = register_framebuffer(info); | ||
308 | if (ret) { | ||
309 | dev_err(&client->dev, "Couldn't register the framebuffer\n"); | ||
310 | goto fbreg_error; | ||
311 | } | ||
312 | |||
313 | i2c_set_clientdata(client, info); | 511 | i2c_set_clientdata(client, info); |
314 | 512 | ||
315 | /* Reset the screen */ | 513 | /* Reset the screen */ |
@@ -318,34 +516,25 @@ static int ssd1307fb_probe(struct i2c_client *client, | |||
318 | gpio_set_value(par->reset, 1); | 516 | gpio_set_value(par->reset, 1); |
319 | udelay(4); | 517 | udelay(4); |
320 | 518 | ||
321 | /* Enable the PWM */ | 519 | if (par->ops->init) { |
322 | pwm_config(par->pwm, par->pwm_period / 2, par->pwm_period); | 520 | ret = par->ops->init(par); |
323 | pwm_enable(par->pwm); | 521 | if (ret) |
324 | 522 | goto reset_oled_error; | |
325 | /* Map column 127 of the OLED to segment 0 */ | ||
326 | ret = ssd1307fb_write_cmd(client, SSD1307FB_SEG_REMAP_ON); | ||
327 | if (ret < 0) { | ||
328 | dev_err(&client->dev, "Couldn't remap the screen.\n"); | ||
329 | goto remap_error; | ||
330 | } | 523 | } |
331 | 524 | ||
332 | /* Turn on the display */ | 525 | ret = register_framebuffer(info); |
333 | ret = ssd1307fb_write_cmd(client, SSD1307FB_DISPLAY_ON); | 526 | if (ret) { |
334 | if (ret < 0) { | 527 | dev_err(&client->dev, "Couldn't register the framebuffer\n"); |
335 | dev_err(&client->dev, "Couldn't turn the display on.\n"); | 528 | goto panel_init_error; |
336 | goto remap_error; | ||
337 | } | 529 | } |
338 | 530 | ||
339 | dev_info(&client->dev, "fb%d: %s framebuffer device registered, using %d bytes of video memory\n", info->node, info->fix.id, vmem_size); | 531 | dev_info(&client->dev, "fb%d: %s framebuffer device registered, using %d bytes of video memory\n", info->node, info->fix.id, vmem_size); |
340 | 532 | ||
341 | return 0; | 533 | return 0; |
342 | 534 | ||
343 | remap_error: | 535 | panel_init_error: |
344 | unregister_framebuffer(info); | 536 | if (par->ops->remove) |
345 | pwm_disable(par->pwm); | 537 | par->ops->remove(par); |
346 | fbreg_error: | ||
347 | pwm_put(par->pwm); | ||
348 | pwm_error: | ||
349 | reset_oled_error: | 538 | reset_oled_error: |
350 | fb_deferred_io_cleanup(info); | 539 | fb_deferred_io_cleanup(info); |
351 | fb_alloc_error: | 540 | fb_alloc_error: |
@@ -359,8 +548,8 @@ static int ssd1307fb_remove(struct i2c_client *client) | |||
359 | struct ssd1307fb_par *par = info->par; | 548 | struct ssd1307fb_par *par = info->par; |
360 | 549 | ||
361 | unregister_framebuffer(info); | 550 | unregister_framebuffer(info); |
362 | pwm_disable(par->pwm); | 551 | if (par->ops->remove) |
363 | pwm_put(par->pwm); | 552 | par->ops->remove(par); |
364 | fb_deferred_io_cleanup(info); | 553 | fb_deferred_io_cleanup(info); |
365 | framebuffer_release(info); | 554 | framebuffer_release(info); |
366 | 555 | ||
@@ -368,17 +557,12 @@ static int ssd1307fb_remove(struct i2c_client *client) | |||
368 | } | 557 | } |
369 | 558 | ||
370 | static const struct i2c_device_id ssd1307fb_i2c_id[] = { | 559 | static const struct i2c_device_id ssd1307fb_i2c_id[] = { |
560 | { "ssd1306fb", 0 }, | ||
371 | { "ssd1307fb", 0 }, | 561 | { "ssd1307fb", 0 }, |
372 | { } | 562 | { } |
373 | }; | 563 | }; |
374 | MODULE_DEVICE_TABLE(i2c, ssd1307fb_i2c_id); | 564 | MODULE_DEVICE_TABLE(i2c, ssd1307fb_i2c_id); |
375 | 565 | ||
376 | static const struct of_device_id ssd1307fb_of_match[] = { | ||
377 | { .compatible = "solomon,ssd1307fb-i2c" }, | ||
378 | {}, | ||
379 | }; | ||
380 | MODULE_DEVICE_TABLE(of, ssd1307fb_of_match); | ||
381 | |||
382 | static struct i2c_driver ssd1307fb_driver = { | 566 | static struct i2c_driver ssd1307fb_driver = { |
383 | .probe = ssd1307fb_probe, | 567 | .probe = ssd1307fb_probe, |
384 | .remove = ssd1307fb_remove, | 568 | .remove = ssd1307fb_remove, |
diff --git a/drivers/video/tmiofb.c b/drivers/video/tmiofb.c index dc4fb8620156..deb8733f3c70 100644 --- a/drivers/video/tmiofb.c +++ b/drivers/video/tmiofb.c | |||
@@ -794,7 +794,6 @@ err_hw_init: | |||
794 | cell->disable(dev); | 794 | cell->disable(dev); |
795 | err_enable: | 795 | err_enable: |
796 | err_find_mode: | 796 | err_find_mode: |
797 | platform_set_drvdata(dev, NULL); | ||
798 | free_irq(irq, info); | 797 | free_irq(irq, info); |
799 | err_request_irq: | 798 | err_request_irq: |
800 | iounmap(info->screen_base); | 799 | iounmap(info->screen_base); |
@@ -823,8 +822,6 @@ static int tmiofb_remove(struct platform_device *dev) | |||
823 | if (cell->disable) | 822 | if (cell->disable) |
824 | cell->disable(dev); | 823 | cell->disable(dev); |
825 | 824 | ||
826 | platform_set_drvdata(dev, NULL); | ||
827 | |||
828 | free_irq(irq, info); | 825 | free_irq(irq, info); |
829 | 826 | ||
830 | iounmap(info->screen_base); | 827 | iounmap(info->screen_base); |
diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c index ec03e726c940..d2e5bc3cf969 100644 --- a/drivers/video/udlfb.c +++ b/drivers/video/udlfb.c | |||
@@ -434,10 +434,10 @@ static void dlfb_compress_hline( | |||
434 | 434 | ||
435 | while ((pixel_end > pixel) && | 435 | while ((pixel_end > pixel) && |
436 | (cmd_buffer_end - MIN_RLX_CMD_BYTES > cmd)) { | 436 | (cmd_buffer_end - MIN_RLX_CMD_BYTES > cmd)) { |
437 | uint8_t *raw_pixels_count_byte = 0; | 437 | uint8_t *raw_pixels_count_byte = NULL; |
438 | uint8_t *cmd_pixels_count_byte = 0; | 438 | uint8_t *cmd_pixels_count_byte = NULL; |
439 | const uint16_t *raw_pixel_start = 0; | 439 | const uint16_t *raw_pixel_start = NULL; |
440 | const uint16_t *cmd_pixel_start, *cmd_pixel_end = 0; | 440 | const uint16_t *cmd_pixel_start, *cmd_pixel_end = NULL; |
441 | 441 | ||
442 | prefetchw((void *) cmd); /* pull in one cache line at least */ | 442 | prefetchw((void *) cmd); /* pull in one cache line at least */ |
443 | 443 | ||
@@ -573,7 +573,7 @@ static int dlfb_render_hline(struct dlfb_data *dev, struct urb **urb_ptr, | |||
573 | return 0; | 573 | return 0; |
574 | } | 574 | } |
575 | 575 | ||
576 | int dlfb_handle_damage(struct dlfb_data *dev, int x, int y, | 576 | static int dlfb_handle_damage(struct dlfb_data *dev, int x, int y, |
577 | int width, int height, char *data) | 577 | int width, int height, char *data) |
578 | { | 578 | { |
579 | int i, ret; | 579 | int i, ret; |
@@ -1588,7 +1588,7 @@ static int dlfb_usb_probe(struct usb_interface *interface, | |||
1588 | const struct usb_device_id *id) | 1588 | const struct usb_device_id *id) |
1589 | { | 1589 | { |
1590 | struct usb_device *usbdev; | 1590 | struct usb_device *usbdev; |
1591 | struct dlfb_data *dev = 0; | 1591 | struct dlfb_data *dev = NULL; |
1592 | int retval = -ENOMEM; | 1592 | int retval = -ENOMEM; |
1593 | 1593 | ||
1594 | /* usb initialization */ | 1594 | /* usb initialization */ |
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index e328a61b64ba..10138b60fd70 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c | |||
@@ -819,8 +819,8 @@ static int uvesafb_vbe_init(struct fb_info *info) | |||
819 | if (par->pmi_setpal || par->ypan) { | 819 | if (par->pmi_setpal || par->ypan) { |
820 | if (__supported_pte_mask & _PAGE_NX) { | 820 | if (__supported_pte_mask & _PAGE_NX) { |
821 | par->pmi_setpal = par->ypan = 0; | 821 | par->pmi_setpal = par->ypan = 0; |
822 | printk(KERN_WARNING "uvesafb: NX protection is actively." | 822 | printk(KERN_WARNING "uvesafb: NX protection is active, " |
823 | "We have better not to use the PMI.\n"); | 823 | "better not use the PMI.\n"); |
824 | } else { | 824 | } else { |
825 | uvesafb_vbe_getpmi(task, par); | 825 | uvesafb_vbe_getpmi(task, par); |
826 | } | 826 | } |
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c index 545faeccdb44..830ded45fd47 100644 --- a/drivers/video/vga16fb.c +++ b/drivers/video/vga16fb.c | |||
@@ -1269,7 +1269,6 @@ static void vga16fb_destroy(struct fb_info *info) | |||
1269 | iounmap(info->screen_base); | 1269 | iounmap(info->screen_base); |
1270 | fb_dealloc_cmap(&info->cmap); | 1270 | fb_dealloc_cmap(&info->cmap); |
1271 | /* XXX unshare VGA regions */ | 1271 | /* XXX unshare VGA regions */ |
1272 | platform_set_drvdata(dev, NULL); | ||
1273 | framebuffer_release(info); | 1272 | framebuffer_release(info); |
1274 | } | 1273 | } |
1275 | 1274 | ||
diff --git a/drivers/video/vt8500lcdfb.c b/drivers/video/vt8500lcdfb.c index 9547e1831e03..897484903c30 100644 --- a/drivers/video/vt8500lcdfb.c +++ b/drivers/video/vt8500lcdfb.c | |||
@@ -448,7 +448,6 @@ failed_free_io: | |||
448 | failed_free_res: | 448 | failed_free_res: |
449 | release_mem_region(res->start, resource_size(res)); | 449 | release_mem_region(res->start, resource_size(res)); |
450 | failed_fbi: | 450 | failed_fbi: |
451 | platform_set_drvdata(pdev, NULL); | ||
452 | kfree(fbi); | 451 | kfree(fbi); |
453 | failed: | 452 | failed: |
454 | return ret; | 453 | return ret; |
diff --git a/drivers/video/wm8505fb.c b/drivers/video/wm8505fb.c index 01f9ace068e2..3072f30cad19 100644 --- a/drivers/video/wm8505fb.c +++ b/drivers/video/wm8505fb.c | |||
@@ -173,7 +173,7 @@ static ssize_t contrast_store(struct device *dev, | |||
173 | struct wm8505fb_info *fbi = to_wm8505fb_info(info); | 173 | struct wm8505fb_info *fbi = to_wm8505fb_info(info); |
174 | unsigned long tmp; | 174 | unsigned long tmp; |
175 | 175 | ||
176 | if (strict_strtoul(buf, 10, &tmp) || (tmp > 0xff)) | 176 | if (kstrtoul(buf, 10, &tmp) || (tmp > 0xff)) |
177 | return -EINVAL; | 177 | return -EINVAL; |
178 | fbi->contrast = tmp; | 178 | fbi->contrast = tmp; |
179 | 179 | ||
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index af0b4fdf9aa9..f3d4a69e1e4e 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c | |||
@@ -44,7 +44,7 @@ | |||
44 | 44 | ||
45 | 45 | ||
46 | /* | 46 | /* |
47 | * Xilinx calls it "PLB TFT LCD Controller" though it can also be used for | 47 | * Xilinx calls it "TFT LCD Controller" though it can also be used for |
48 | * the VGA port on the Xilinx ML40x board. This is a hardware display | 48 | * the VGA port on the Xilinx ML40x board. This is a hardware display |
49 | * controller for a 640x480 resolution TFT or VGA screen. | 49 | * controller for a 640x480 resolution TFT or VGA screen. |
50 | * | 50 | * |
@@ -54,11 +54,11 @@ | |||
54 | * don't start thinking about scrolling). The second allows the LCD to | 54 | * don't start thinking about scrolling). The second allows the LCD to |
55 | * be turned on or off as well as rotated 180 degrees. | 55 | * be turned on or off as well as rotated 180 degrees. |
56 | * | 56 | * |
57 | * In case of direct PLB access the second control register will be at | 57 | * In case of direct BUS access the second control register will be at |
58 | * an offset of 4 as compared to the DCR access where the offset is 1 | 58 | * an offset of 4 as compared to the DCR access where the offset is 1 |
59 | * i.e. REG_CTRL. So this is taken care in the function | 59 | * i.e. REG_CTRL. So this is taken care in the function |
60 | * xilinx_fb_out_be32 where it left shifts the offset 2 times in case of | 60 | * xilinx_fb_out32 where it left shifts the offset 2 times in case of |
61 | * direct PLB access. | 61 | * direct BUS access. |
62 | */ | 62 | */ |
63 | #define NUM_REGS 2 | 63 | #define NUM_REGS 2 |
64 | #define REG_FB_ADDR 0 | 64 | #define REG_FB_ADDR 0 |
@@ -116,7 +116,8 @@ static struct fb_var_screeninfo xilinx_fb_var = { | |||
116 | }; | 116 | }; |
117 | 117 | ||
118 | 118 | ||
119 | #define PLB_ACCESS_FLAG 0x1 /* 1 = PLB, 0 = DCR */ | 119 | #define BUS_ACCESS_FLAG 0x1 /* 1 = BUS, 0 = DCR */ |
120 | #define LITTLE_ENDIAN_ACCESS 0x2 /* LITTLE ENDIAN IO functions */ | ||
120 | 121 | ||
121 | struct xilinxfb_drvdata { | 122 | struct xilinxfb_drvdata { |
122 | 123 | ||
@@ -146,21 +147,40 @@ struct xilinxfb_drvdata { | |||
146 | container_of(_info, struct xilinxfb_drvdata, info) | 147 | container_of(_info, struct xilinxfb_drvdata, info) |
147 | 148 | ||
148 | /* | 149 | /* |
149 | * The XPS TFT Controller can be accessed through PLB or DCR interface. | 150 | * The XPS TFT Controller can be accessed through BUS or DCR interface. |
150 | * To perform the read/write on the registers we need to check on | 151 | * To perform the read/write on the registers we need to check on |
151 | * which bus its connected and call the appropriate write API. | 152 | * which bus its connected and call the appropriate write API. |
152 | */ | 153 | */ |
153 | static void xilinx_fb_out_be32(struct xilinxfb_drvdata *drvdata, u32 offset, | 154 | static void xilinx_fb_out32(struct xilinxfb_drvdata *drvdata, u32 offset, |
154 | u32 val) | 155 | u32 val) |
155 | { | 156 | { |
156 | if (drvdata->flags & PLB_ACCESS_FLAG) | 157 | if (drvdata->flags & BUS_ACCESS_FLAG) { |
157 | out_be32(drvdata->regs + (offset << 2), val); | 158 | if (drvdata->flags & LITTLE_ENDIAN_ACCESS) |
159 | iowrite32(val, drvdata->regs + (offset << 2)); | ||
160 | else | ||
161 | iowrite32be(val, drvdata->regs + (offset << 2)); | ||
162 | } | ||
158 | #ifdef CONFIG_PPC_DCR | 163 | #ifdef CONFIG_PPC_DCR |
159 | else | 164 | else |
160 | dcr_write(drvdata->dcr_host, offset, val); | 165 | dcr_write(drvdata->dcr_host, offset, val); |
161 | #endif | 166 | #endif |
162 | } | 167 | } |
163 | 168 | ||
169 | static u32 xilinx_fb_in32(struct xilinxfb_drvdata *drvdata, u32 offset) | ||
170 | { | ||
171 | if (drvdata->flags & BUS_ACCESS_FLAG) { | ||
172 | if (drvdata->flags & LITTLE_ENDIAN_ACCESS) | ||
173 | return ioread32(drvdata->regs + (offset << 2)); | ||
174 | else | ||
175 | return ioread32be(drvdata->regs + (offset << 2)); | ||
176 | } | ||
177 | #ifdef CONFIG_PPC_DCR | ||
178 | else | ||
179 | return dcr_read(drvdata->dcr_host, offset); | ||
180 | #endif | ||
181 | return 0; | ||
182 | } | ||
183 | |||
164 | static int | 184 | static int |
165 | xilinx_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, | 185 | xilinx_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, |
166 | unsigned transp, struct fb_info *fbi) | 186 | unsigned transp, struct fb_info *fbi) |
@@ -197,7 +217,7 @@ xilinx_fb_blank(int blank_mode, struct fb_info *fbi) | |||
197 | switch (blank_mode) { | 217 | switch (blank_mode) { |
198 | case FB_BLANK_UNBLANK: | 218 | case FB_BLANK_UNBLANK: |
199 | /* turn on panel */ | 219 | /* turn on panel */ |
200 | xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default); | 220 | xilinx_fb_out32(drvdata, REG_CTRL, drvdata->reg_ctrl_default); |
201 | break; | 221 | break; |
202 | 222 | ||
203 | case FB_BLANK_NORMAL: | 223 | case FB_BLANK_NORMAL: |
@@ -205,7 +225,7 @@ xilinx_fb_blank(int blank_mode, struct fb_info *fbi) | |||
205 | case FB_BLANK_HSYNC_SUSPEND: | 225 | case FB_BLANK_HSYNC_SUSPEND: |
206 | case FB_BLANK_POWERDOWN: | 226 | case FB_BLANK_POWERDOWN: |
207 | /* turn off panel */ | 227 | /* turn off panel */ |
208 | xilinx_fb_out_be32(drvdata, REG_CTRL, 0); | 228 | xilinx_fb_out32(drvdata, REG_CTRL, 0); |
209 | default: | 229 | default: |
210 | break; | 230 | break; |
211 | 231 | ||
@@ -227,33 +247,23 @@ static struct fb_ops xilinxfb_ops = | |||
227 | * Bus independent setup/teardown | 247 | * Bus independent setup/teardown |
228 | */ | 248 | */ |
229 | 249 | ||
230 | static int xilinxfb_assign(struct device *dev, | 250 | static int xilinxfb_assign(struct platform_device *pdev, |
231 | struct xilinxfb_drvdata *drvdata, | 251 | struct xilinxfb_drvdata *drvdata, |
232 | unsigned long physaddr, | ||
233 | struct xilinxfb_platform_data *pdata) | 252 | struct xilinxfb_platform_data *pdata) |
234 | { | 253 | { |
235 | int rc; | 254 | int rc; |
255 | struct device *dev = &pdev->dev; | ||
236 | int fbsize = pdata->xvirt * pdata->yvirt * BYTES_PER_PIXEL; | 256 | int fbsize = pdata->xvirt * pdata->yvirt * BYTES_PER_PIXEL; |
237 | 257 | ||
238 | if (drvdata->flags & PLB_ACCESS_FLAG) { | 258 | if (drvdata->flags & BUS_ACCESS_FLAG) { |
239 | /* | 259 | struct resource *res; |
240 | * Map the control registers in if the controller | ||
241 | * is on direct PLB interface. | ||
242 | */ | ||
243 | if (!request_mem_region(physaddr, 8, DRIVER_NAME)) { | ||
244 | dev_err(dev, "Couldn't lock memory region at 0x%08lX\n", | ||
245 | physaddr); | ||
246 | rc = -ENODEV; | ||
247 | goto err_region; | ||
248 | } | ||
249 | 260 | ||
250 | drvdata->regs_phys = physaddr; | 261 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
251 | drvdata->regs = ioremap(physaddr, 8); | 262 | drvdata->regs_phys = res->start; |
263 | drvdata->regs = devm_request_and_ioremap(&pdev->dev, res); | ||
252 | if (!drvdata->regs) { | 264 | if (!drvdata->regs) { |
253 | dev_err(dev, "Couldn't lock memory region at 0x%08lX\n", | 265 | rc = -EADDRNOTAVAIL; |
254 | physaddr); | 266 | goto err_region; |
255 | rc = -ENODEV; | ||
256 | goto err_map; | ||
257 | } | 267 | } |
258 | } | 268 | } |
259 | 269 | ||
@@ -270,7 +280,7 @@ static int xilinxfb_assign(struct device *dev, | |||
270 | if (!drvdata->fb_virt) { | 280 | if (!drvdata->fb_virt) { |
271 | dev_err(dev, "Could not allocate frame buffer memory\n"); | 281 | dev_err(dev, "Could not allocate frame buffer memory\n"); |
272 | rc = -ENOMEM; | 282 | rc = -ENOMEM; |
273 | if (drvdata->flags & PLB_ACCESS_FLAG) | 283 | if (drvdata->flags & BUS_ACCESS_FLAG) |
274 | goto err_fbmem; | 284 | goto err_fbmem; |
275 | else | 285 | else |
276 | goto err_region; | 286 | goto err_region; |
@@ -280,13 +290,19 @@ static int xilinxfb_assign(struct device *dev, | |||
280 | memset_io((void __iomem *)drvdata->fb_virt, 0, fbsize); | 290 | memset_io((void __iomem *)drvdata->fb_virt, 0, fbsize); |
281 | 291 | ||
282 | /* Tell the hardware where the frame buffer is */ | 292 | /* Tell the hardware where the frame buffer is */ |
283 | xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys); | 293 | xilinx_fb_out32(drvdata, REG_FB_ADDR, drvdata->fb_phys); |
294 | rc = xilinx_fb_in32(drvdata, REG_FB_ADDR); | ||
295 | /* Endianess detection */ | ||
296 | if (rc != drvdata->fb_phys) { | ||
297 | drvdata->flags |= LITTLE_ENDIAN_ACCESS; | ||
298 | xilinx_fb_out32(drvdata, REG_FB_ADDR, drvdata->fb_phys); | ||
299 | } | ||
284 | 300 | ||
285 | /* Turn on the display */ | 301 | /* Turn on the display */ |
286 | drvdata->reg_ctrl_default = REG_CTRL_ENABLE; | 302 | drvdata->reg_ctrl_default = REG_CTRL_ENABLE; |
287 | if (pdata->rotate_screen) | 303 | if (pdata->rotate_screen) |
288 | drvdata->reg_ctrl_default |= REG_CTRL_ROTATE; | 304 | drvdata->reg_ctrl_default |= REG_CTRL_ROTATE; |
289 | xilinx_fb_out_be32(drvdata, REG_CTRL, | 305 | xilinx_fb_out32(drvdata, REG_CTRL, |
290 | drvdata->reg_ctrl_default); | 306 | drvdata->reg_ctrl_default); |
291 | 307 | ||
292 | /* Fill struct fb_info */ | 308 | /* Fill struct fb_info */ |
@@ -323,9 +339,9 @@ static int xilinxfb_assign(struct device *dev, | |||
323 | goto err_regfb; | 339 | goto err_regfb; |
324 | } | 340 | } |
325 | 341 | ||
326 | if (drvdata->flags & PLB_ACCESS_FLAG) { | 342 | if (drvdata->flags & BUS_ACCESS_FLAG) { |
327 | /* Put a banner in the log (for DEBUG) */ | 343 | /* Put a banner in the log (for DEBUG) */ |
328 | dev_dbg(dev, "regs: phys=%lx, virt=%p\n", physaddr, | 344 | dev_dbg(dev, "regs: phys=%x, virt=%p\n", drvdata->regs_phys, |
329 | drvdata->regs); | 345 | drvdata->regs); |
330 | } | 346 | } |
331 | /* Put a banner in the log (for DEBUG) */ | 347 | /* Put a banner in the log (for DEBUG) */ |
@@ -345,15 +361,11 @@ err_cmap: | |||
345 | iounmap(drvdata->fb_virt); | 361 | iounmap(drvdata->fb_virt); |
346 | 362 | ||
347 | /* Turn off the display */ | 363 | /* Turn off the display */ |
348 | xilinx_fb_out_be32(drvdata, REG_CTRL, 0); | 364 | xilinx_fb_out32(drvdata, REG_CTRL, 0); |
349 | 365 | ||
350 | err_fbmem: | 366 | err_fbmem: |
351 | if (drvdata->flags & PLB_ACCESS_FLAG) | 367 | if (drvdata->flags & BUS_ACCESS_FLAG) |
352 | iounmap(drvdata->regs); | 368 | devm_iounmap(dev, drvdata->regs); |
353 | |||
354 | err_map: | ||
355 | if (drvdata->flags & PLB_ACCESS_FLAG) | ||
356 | release_mem_region(physaddr, 8); | ||
357 | 369 | ||
358 | err_region: | 370 | err_region: |
359 | kfree(drvdata); | 371 | kfree(drvdata); |
@@ -381,13 +393,11 @@ static int xilinxfb_release(struct device *dev) | |||
381 | iounmap(drvdata->fb_virt); | 393 | iounmap(drvdata->fb_virt); |
382 | 394 | ||
383 | /* Turn off the display */ | 395 | /* Turn off the display */ |
384 | xilinx_fb_out_be32(drvdata, REG_CTRL, 0); | 396 | xilinx_fb_out32(drvdata, REG_CTRL, 0); |
385 | 397 | ||
386 | /* Release the resources, as allocated based on interface */ | 398 | /* Release the resources, as allocated based on interface */ |
387 | if (drvdata->flags & PLB_ACCESS_FLAG) { | 399 | if (drvdata->flags & BUS_ACCESS_FLAG) |
388 | iounmap(drvdata->regs); | 400 | devm_iounmap(dev, drvdata->regs); |
389 | release_mem_region(drvdata->regs_phys, 8); | ||
390 | } | ||
391 | #ifdef CONFIG_PPC_DCR | 401 | #ifdef CONFIG_PPC_DCR |
392 | else | 402 | else |
393 | dcr_unmap(drvdata->dcr_host, drvdata->dcr_len); | 403 | dcr_unmap(drvdata->dcr_host, drvdata->dcr_len); |
@@ -406,11 +416,9 @@ static int xilinxfb_release(struct device *dev) | |||
406 | static int xilinxfb_of_probe(struct platform_device *op) | 416 | static int xilinxfb_of_probe(struct platform_device *op) |
407 | { | 417 | { |
408 | const u32 *prop; | 418 | const u32 *prop; |
409 | u32 *p; | 419 | u32 tft_access = 0; |
410 | u32 tft_access; | ||
411 | struct xilinxfb_platform_data pdata; | 420 | struct xilinxfb_platform_data pdata; |
412 | struct resource res; | 421 | int size; |
413 | int size, rc; | ||
414 | struct xilinxfb_drvdata *drvdata; | 422 | struct xilinxfb_drvdata *drvdata; |
415 | 423 | ||
416 | /* Copy with the default pdata (not a ptr reference!) */ | 424 | /* Copy with the default pdata (not a ptr reference!) */ |
@@ -424,34 +432,29 @@ static int xilinxfb_of_probe(struct platform_device *op) | |||
424 | } | 432 | } |
425 | 433 | ||
426 | /* | 434 | /* |
427 | * To check whether the core is connected directly to DCR or PLB | 435 | * To check whether the core is connected directly to DCR or BUS |
428 | * interface and initialize the tft_access accordingly. | 436 | * interface and initialize the tft_access accordingly. |
429 | */ | 437 | */ |
430 | p = (u32 *)of_get_property(op->dev.of_node, "xlnx,dcr-splb-slave-if", NULL); | 438 | of_property_read_u32(op->dev.of_node, "xlnx,dcr-splb-slave-if", |
431 | tft_access = p ? *p : 0; | 439 | &tft_access); |
432 | 440 | ||
433 | /* | 441 | /* |
434 | * Fill the resource structure if its direct PLB interface | 442 | * Fill the resource structure if its direct BUS interface |
435 | * otherwise fill the dcr_host structure. | 443 | * otherwise fill the dcr_host structure. |
436 | */ | 444 | */ |
437 | if (tft_access) { | 445 | if (tft_access) { |
438 | drvdata->flags |= PLB_ACCESS_FLAG; | 446 | drvdata->flags |= BUS_ACCESS_FLAG; |
439 | rc = of_address_to_resource(op->dev.of_node, 0, &res); | ||
440 | if (rc) { | ||
441 | dev_err(&op->dev, "invalid address\n"); | ||
442 | goto err; | ||
443 | } | ||
444 | } | 447 | } |
445 | #ifdef CONFIG_PPC_DCR | 448 | #ifdef CONFIG_PPC_DCR |
446 | else { | 449 | else { |
447 | int start; | 450 | int start; |
448 | res.start = 0; | ||
449 | start = dcr_resource_start(op->dev.of_node, 0); | 451 | start = dcr_resource_start(op->dev.of_node, 0); |
450 | drvdata->dcr_len = dcr_resource_len(op->dev.of_node, 0); | 452 | drvdata->dcr_len = dcr_resource_len(op->dev.of_node, 0); |
451 | drvdata->dcr_host = dcr_map(op->dev.of_node, start, drvdata->dcr_len); | 453 | drvdata->dcr_host = dcr_map(op->dev.of_node, start, drvdata->dcr_len); |
452 | if (!DCR_MAP_OK(drvdata->dcr_host)) { | 454 | if (!DCR_MAP_OK(drvdata->dcr_host)) { |
453 | dev_err(&op->dev, "invalid DCR address\n"); | 455 | dev_err(&op->dev, "invalid DCR address\n"); |
454 | goto err; | 456 | kfree(drvdata); |
457 | return -ENODEV; | ||
455 | } | 458 | } |
456 | } | 459 | } |
457 | #endif | 460 | #endif |
@@ -478,11 +481,7 @@ static int xilinxfb_of_probe(struct platform_device *op) | |||
478 | pdata.rotate_screen = 1; | 481 | pdata.rotate_screen = 1; |
479 | 482 | ||
480 | dev_set_drvdata(&op->dev, drvdata); | 483 | dev_set_drvdata(&op->dev, drvdata); |
481 | return xilinxfb_assign(&op->dev, drvdata, res.start, &pdata); | 484 | return xilinxfb_assign(op, drvdata, &pdata); |
482 | |||
483 | err: | ||
484 | kfree(drvdata); | ||
485 | return -ENODEV; | ||
486 | } | 485 | } |
487 | 486 | ||
488 | static int xilinxfb_of_remove(struct platform_device *op) | 487 | static int xilinxfb_of_remove(struct platform_device *op) |
diff --git a/include/linux/fb.h b/include/linux/fb.h index d49c60f5aa4c..ffac70aab3e9 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h | |||
@@ -624,7 +624,7 @@ extern void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u3 | |||
624 | extern void fb_set_suspend(struct fb_info *info, int state); | 624 | extern void fb_set_suspend(struct fb_info *info, int state); |
625 | extern int fb_get_color_depth(struct fb_var_screeninfo *var, | 625 | extern int fb_get_color_depth(struct fb_var_screeninfo *var, |
626 | struct fb_fix_screeninfo *fix); | 626 | struct fb_fix_screeninfo *fix); |
627 | extern int fb_get_options(char *name, char **option); | 627 | extern int fb_get_options(const char *name, char **option); |
628 | extern int fb_new_modelist(struct fb_info *info); | 628 | extern int fb_new_modelist(struct fb_info *info); |
629 | 629 | ||
630 | extern struct fb_info *registered_fb[FB_MAX]; | 630 | extern struct fb_info *registered_fb[FB_MAX]; |
diff --git a/include/video/of_display_timing.h b/include/video/of_display_timing.h index 8016eb727cf3..79e6697af6cf 100644 --- a/include/video/of_display_timing.h +++ b/include/video/of_display_timing.h | |||
@@ -10,10 +10,13 @@ | |||
10 | #define __LINUX_OF_DISPLAY_TIMING_H | 10 | #define __LINUX_OF_DISPLAY_TIMING_H |
11 | 11 | ||
12 | struct device_node; | 12 | struct device_node; |
13 | struct display_timing; | ||
13 | struct display_timings; | 14 | struct display_timings; |
14 | 15 | ||
15 | #define OF_USE_NATIVE_MODE -1 | 16 | #define OF_USE_NATIVE_MODE -1 |
16 | 17 | ||
18 | int of_get_display_timing(struct device_node *np, const char *name, | ||
19 | struct display_timing *dt); | ||
17 | struct display_timings *of_get_display_timings(struct device_node *np); | 20 | struct display_timings *of_get_display_timings(struct device_node *np); |
18 | int of_display_timings_exist(struct device_node *np); | 21 | int of_display_timings_exist(struct device_node *np); |
19 | 22 | ||
diff --git a/include/video/omap-panel-data.h b/include/video/omap-panel-data.h index 0c3b46d3daf3..6b2366fb6e53 100644 --- a/include/video/omap-panel-data.h +++ b/include/video/omap-panel-data.h | |||
@@ -27,6 +27,9 @@ | |||
27 | #ifndef __OMAP_PANEL_DATA_H | 27 | #ifndef __OMAP_PANEL_DATA_H |
28 | #define __OMAP_PANEL_DATA_H | 28 | #define __OMAP_PANEL_DATA_H |
29 | 29 | ||
30 | #include <video/omapdss.h> | ||
31 | #include <video/display_timing.h> | ||
32 | |||
30 | struct omap_dss_device; | 33 | struct omap_dss_device; |
31 | 34 | ||
32 | /** | 35 | /** |
@@ -147,4 +150,210 @@ struct panel_tpo_td043_data { | |||
147 | int nreset_gpio; | 150 | int nreset_gpio; |
148 | }; | 151 | }; |
149 | 152 | ||
153 | /** | ||
154 | * encoder_tfp410 platform data | ||
155 | * @name: name for this display entity | ||
156 | * @power_down_gpio: gpio number for PD pin (or -1 if not available) | ||
157 | * @data_lines: number of DPI datalines | ||
158 | */ | ||
159 | struct encoder_tfp410_platform_data { | ||
160 | const char *name; | ||
161 | const char *source; | ||
162 | int power_down_gpio; | ||
163 | int data_lines; | ||
164 | }; | ||
165 | |||
166 | /** | ||
167 | * encoder_tpd12s015 platform data | ||
168 | * @name: name for this display entity | ||
169 | * @ct_cp_hpd_gpio: CT_CP_HPD gpio number | ||
170 | * @ls_oe_gpio: LS_OE gpio number | ||
171 | * @hpd_gpio: HPD gpio number | ||
172 | */ | ||
173 | struct encoder_tpd12s015_platform_data { | ||
174 | const char *name; | ||
175 | const char *source; | ||
176 | |||
177 | int ct_cp_hpd_gpio; | ||
178 | int ls_oe_gpio; | ||
179 | int hpd_gpio; | ||
180 | }; | ||
181 | |||
182 | /** | ||
183 | * connector_dvi platform data | ||
184 | * @name: name for this display entity | ||
185 | * @source: name of the display entity used as a video source | ||
186 | * @i2c_bus_num: i2c bus number to be used for reading EDID | ||
187 | */ | ||
188 | struct connector_dvi_platform_data { | ||
189 | const char *name; | ||
190 | const char *source; | ||
191 | int i2c_bus_num; | ||
192 | }; | ||
193 | |||
194 | /** | ||
195 | * connector_hdmi platform data | ||
196 | * @name: name for this display entity | ||
197 | * @source: name of the display entity used as a video source | ||
198 | */ | ||
199 | struct connector_hdmi_platform_data { | ||
200 | const char *name; | ||
201 | const char *source; | ||
202 | }; | ||
203 | |||
204 | /** | ||
205 | * connector_atv platform data | ||
206 | * @name: name for this display entity | ||
207 | * @source: name of the display entity used as a video source | ||
208 | * @connector_type: composite/svideo | ||
209 | * @invert_polarity: invert signal polarity | ||
210 | */ | ||
211 | struct connector_atv_platform_data { | ||
212 | const char *name; | ||
213 | const char *source; | ||
214 | |||
215 | enum omap_dss_venc_type connector_type; | ||
216 | bool invert_polarity; | ||
217 | }; | ||
218 | |||
219 | /** | ||
220 | * panel_dpi platform data | ||
221 | * @name: name for this display entity | ||
222 | * @source: name of the display entity used as a video source | ||
223 | * @data_lines: number of DPI datalines | ||
224 | * @display_timing: timings for this panel | ||
225 | * @backlight_gpio: gpio to enable/disable the backlight (or -1) | ||
226 | * @enable_gpio: gpio to enable/disable the panel (or -1) | ||
227 | */ | ||
228 | struct panel_dpi_platform_data { | ||
229 | const char *name; | ||
230 | const char *source; | ||
231 | |||
232 | int data_lines; | ||
233 | |||
234 | const struct display_timing *display_timing; | ||
235 | |||
236 | int backlight_gpio; | ||
237 | int enable_gpio; | ||
238 | }; | ||
239 | |||
240 | /** | ||
241 | * panel_dsicm platform data | ||
242 | * @name: name for this display entity | ||
243 | * @source: name of the display entity used as a video source | ||
244 | * @reset_gpio: gpio to reset the panel (or -1) | ||
245 | * @use_ext_te: use external TE GPIO | ||
246 | * @ext_te_gpio: external TE GPIO | ||
247 | * @ulps_timeout: time to wait before entering ULPS, 0 = disabled (ms) | ||
248 | * @use_dsi_backlight: true if panel uses DSI command to control backlight | ||
249 | * @pin_config: DSI pin configuration | ||
250 | */ | ||
251 | struct panel_dsicm_platform_data { | ||
252 | const char *name; | ||
253 | const char *source; | ||
254 | |||
255 | int reset_gpio; | ||
256 | |||
257 | bool use_ext_te; | ||
258 | int ext_te_gpio; | ||
259 | |||
260 | unsigned ulps_timeout; | ||
261 | |||
262 | bool use_dsi_backlight; | ||
263 | |||
264 | struct omap_dsi_pin_config pin_config; | ||
265 | }; | ||
266 | |||
267 | /** | ||
268 | * panel_acx565akm platform data | ||
269 | * @name: name for this display entity | ||
270 | * @source: name of the display entity used as a video source | ||
271 | * @reset_gpio: gpio to reset the panel (or -1) | ||
272 | * @datapairs: number of SDI datapairs | ||
273 | */ | ||
274 | struct panel_acx565akm_platform_data { | ||
275 | const char *name; | ||
276 | const char *source; | ||
277 | |||
278 | int reset_gpio; | ||
279 | |||
280 | int datapairs; | ||
281 | }; | ||
282 | |||
283 | /** | ||
284 | * panel_lb035q02 platform data | ||
285 | * @name: name for this display entity | ||
286 | * @source: name of the display entity used as a video source | ||
287 | * @data_lines: number of DPI datalines | ||
288 | * @backlight_gpio: gpio to enable/disable the backlight (or -1) | ||
289 | * @enable_gpio: gpio to enable/disable the panel (or -1) | ||
290 | */ | ||
291 | struct panel_lb035q02_platform_data { | ||
292 | const char *name; | ||
293 | const char *source; | ||
294 | |||
295 | int data_lines; | ||
296 | |||
297 | int backlight_gpio; | ||
298 | int enable_gpio; | ||
299 | }; | ||
300 | |||
301 | /** | ||
302 | * panel_sharp_ls037v7dw01 platform data | ||
303 | * @name: name for this display entity | ||
304 | * @source: name of the display entity used as a video source | ||
305 | * @data_lines: number of DPI datalines | ||
306 | * @resb_gpio: reset signal GPIO | ||
307 | * @ini_gpio: power on control GPIO | ||
308 | * @mo_gpio: selection for resolution(VGA/QVGA) GPIO | ||
309 | * @lr_gpio: selection for horizontal scanning direction GPIO | ||
310 | * @ud_gpio: selection for vertical scanning direction GPIO | ||
311 | */ | ||
312 | struct panel_sharp_ls037v7dw01_platform_data { | ||
313 | const char *name; | ||
314 | const char *source; | ||
315 | |||
316 | int data_lines; | ||
317 | |||
318 | int resb_gpio; | ||
319 | int ini_gpio; | ||
320 | int mo_gpio; | ||
321 | int lr_gpio; | ||
322 | int ud_gpio; | ||
323 | }; | ||
324 | |||
325 | /** | ||
326 | * panel-tpo-td043mtea1 platform data | ||
327 | * @name: name for this display entity | ||
328 | * @source: name of the display entity used as a video source | ||
329 | * @data_lines: number of DPI datalines | ||
330 | * @nreset_gpio: reset signal | ||
331 | */ | ||
332 | struct panel_tpo_td043mtea1_platform_data { | ||
333 | const char *name; | ||
334 | const char *source; | ||
335 | |||
336 | int data_lines; | ||
337 | |||
338 | int nreset_gpio; | ||
339 | }; | ||
340 | |||
341 | /** | ||
342 | * panel-nec-nl8048hl11 platform data | ||
343 | * @name: name for this display entity | ||
344 | * @source: name of the display entity used as a video source | ||
345 | * @data_lines: number of DPI datalines | ||
346 | * @res_gpio: reset signal | ||
347 | * @qvga_gpio: selection for resolution(QVGA/WVGA) | ||
348 | */ | ||
349 | struct panel_nec_nl8048hl11_platform_data { | ||
350 | const char *name; | ||
351 | const char *source; | ||
352 | |||
353 | int data_lines; | ||
354 | |||
355 | int res_gpio; | ||
356 | int qvga_gpio; | ||
357 | }; | ||
358 | |||
150 | #endif /* __OMAP_PANEL_DATA_H */ | 359 | #endif /* __OMAP_PANEL_DATA_H */ |
diff --git a/include/video/omapdss.h b/include/video/omapdss.h index aeb4e9a0c5d1..b39463553845 100644 --- a/include/video/omapdss.h +++ b/include/video/omapdss.h | |||
@@ -23,6 +23,8 @@ | |||
23 | #include <linux/device.h> | 23 | #include <linux/device.h> |
24 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
25 | 25 | ||
26 | #include <video/videomode.h> | ||
27 | |||
26 | #define DISPC_IRQ_FRAMEDONE (1 << 0) | 28 | #define DISPC_IRQ_FRAMEDONE (1 << 0) |
27 | #define DISPC_IRQ_VSYNC (1 << 1) | 29 | #define DISPC_IRQ_VSYNC (1 << 1) |
28 | #define DISPC_IRQ_EVSYNC_EVEN (1 << 2) | 30 | #define DISPC_IRQ_EVSYNC_EVEN (1 << 2) |
@@ -68,6 +70,7 @@ enum omap_display_type { | |||
68 | OMAP_DISPLAY_TYPE_DSI = 1 << 3, | 70 | OMAP_DISPLAY_TYPE_DSI = 1 << 3, |
69 | OMAP_DISPLAY_TYPE_VENC = 1 << 4, | 71 | OMAP_DISPLAY_TYPE_VENC = 1 << 4, |
70 | OMAP_DISPLAY_TYPE_HDMI = 1 << 5, | 72 | OMAP_DISPLAY_TYPE_HDMI = 1 << 5, |
73 | OMAP_DISPLAY_TYPE_DVI = 1 << 6, | ||
71 | }; | 74 | }; |
72 | 75 | ||
73 | enum omap_plane { | 76 | enum omap_plane { |
@@ -169,6 +172,11 @@ enum omap_dss_audio_state { | |||
169 | OMAP_DSS_AUDIO_PLAYING, | 172 | OMAP_DSS_AUDIO_PLAYING, |
170 | }; | 173 | }; |
171 | 174 | ||
175 | struct omap_dss_audio { | ||
176 | struct snd_aes_iec958 *iec; | ||
177 | struct snd_cea_861_aud_if *cea; | ||
178 | }; | ||
179 | |||
172 | enum omap_dss_rotation_type { | 180 | enum omap_dss_rotation_type { |
173 | OMAP_DSS_ROT_DMA = 1 << 0, | 181 | OMAP_DSS_ROT_DMA = 1 << 0, |
174 | OMAP_DSS_ROT_VRFB = 1 << 1, | 182 | OMAP_DSS_ROT_VRFB = 1 << 1, |
@@ -365,6 +373,7 @@ struct omap_dss_board_info { | |||
365 | int num_devices; | 373 | int num_devices; |
366 | struct omap_dss_device **devices; | 374 | struct omap_dss_device **devices; |
367 | struct omap_dss_device *default_device; | 375 | struct omap_dss_device *default_device; |
376 | const char *default_display_name; | ||
368 | int (*dsi_enable_pads)(int dsi_id, unsigned lane_mask); | 377 | int (*dsi_enable_pads)(int dsi_id, unsigned lane_mask); |
369 | void (*dsi_disable_pads)(int dsi_id, unsigned lane_mask); | 378 | void (*dsi_disable_pads)(int dsi_id, unsigned lane_mask); |
370 | int (*set_min_bus_tput)(struct device *dev, unsigned long r); | 379 | int (*set_min_bus_tput)(struct device *dev, unsigned long r); |
@@ -512,7 +521,7 @@ struct omap_overlay_manager { | |||
512 | enum omap_dss_output_id supported_outputs; | 521 | enum omap_dss_output_id supported_outputs; |
513 | 522 | ||
514 | /* dynamic fields */ | 523 | /* dynamic fields */ |
515 | struct omap_dss_output *output; | 524 | struct omap_dss_device *output; |
516 | 525 | ||
517 | /* | 526 | /* |
518 | * The following functions do not block: | 527 | * The following functions do not block: |
@@ -526,7 +535,7 @@ struct omap_overlay_manager { | |||
526 | */ | 535 | */ |
527 | 536 | ||
528 | int (*set_output)(struct omap_overlay_manager *mgr, | 537 | int (*set_output)(struct omap_overlay_manager *mgr, |
529 | struct omap_dss_output *output); | 538 | struct omap_dss_device *output); |
530 | int (*unset_output)(struct omap_overlay_manager *mgr); | 539 | int (*unset_output)(struct omap_overlay_manager *mgr); |
531 | 540 | ||
532 | int (*set_manager_info)(struct omap_overlay_manager *mgr, | 541 | int (*set_manager_info)(struct omap_overlay_manager *mgr, |
@@ -569,33 +578,192 @@ struct omap_dss_writeback_info { | |||
569 | u8 pre_mult_alpha; | 578 | u8 pre_mult_alpha; |
570 | }; | 579 | }; |
571 | 580 | ||
572 | struct omap_dss_output { | 581 | struct omapdss_dpi_ops { |
573 | struct list_head list; | 582 | int (*connect)(struct omap_dss_device *dssdev, |
583 | struct omap_dss_device *dst); | ||
584 | void (*disconnect)(struct omap_dss_device *dssdev, | ||
585 | struct omap_dss_device *dst); | ||
574 | 586 | ||
575 | const char *name; | 587 | int (*enable)(struct omap_dss_device *dssdev); |
588 | void (*disable)(struct omap_dss_device *dssdev); | ||
576 | 589 | ||
577 | /* display type supported by the output */ | 590 | int (*check_timings)(struct omap_dss_device *dssdev, |
578 | enum omap_display_type type; | 591 | struct omap_video_timings *timings); |
592 | void (*set_timings)(struct omap_dss_device *dssdev, | ||
593 | struct omap_video_timings *timings); | ||
594 | void (*get_timings)(struct omap_dss_device *dssdev, | ||
595 | struct omap_video_timings *timings); | ||
579 | 596 | ||
580 | /* DISPC channel for this output */ | 597 | void (*set_data_lines)(struct omap_dss_device *dssdev, int data_lines); |
581 | enum omap_channel dispc_channel; | 598 | }; |
582 | 599 | ||
583 | /* output instance */ | 600 | struct omapdss_sdi_ops { |
584 | enum omap_dss_output_id id; | 601 | int (*connect)(struct omap_dss_device *dssdev, |
602 | struct omap_dss_device *dst); | ||
603 | void (*disconnect)(struct omap_dss_device *dssdev, | ||
604 | struct omap_dss_device *dst); | ||
585 | 605 | ||
586 | /* output's platform device pointer */ | 606 | int (*enable)(struct omap_dss_device *dssdev); |
587 | struct platform_device *pdev; | 607 | void (*disable)(struct omap_dss_device *dssdev); |
588 | 608 | ||
589 | /* dynamic fields */ | 609 | int (*check_timings)(struct omap_dss_device *dssdev, |
590 | struct omap_overlay_manager *manager; | 610 | struct omap_video_timings *timings); |
611 | void (*set_timings)(struct omap_dss_device *dssdev, | ||
612 | struct omap_video_timings *timings); | ||
613 | void (*get_timings)(struct omap_dss_device *dssdev, | ||
614 | struct omap_video_timings *timings); | ||
591 | 615 | ||
592 | struct omap_dss_device *device; | 616 | void (*set_datapairs)(struct omap_dss_device *dssdev, int datapairs); |
617 | }; | ||
618 | |||
619 | struct omapdss_dvi_ops { | ||
620 | int (*connect)(struct omap_dss_device *dssdev, | ||
621 | struct omap_dss_device *dst); | ||
622 | void (*disconnect)(struct omap_dss_device *dssdev, | ||
623 | struct omap_dss_device *dst); | ||
624 | |||
625 | int (*enable)(struct omap_dss_device *dssdev); | ||
626 | void (*disable)(struct omap_dss_device *dssdev); | ||
627 | |||
628 | int (*check_timings)(struct omap_dss_device *dssdev, | ||
629 | struct omap_video_timings *timings); | ||
630 | void (*set_timings)(struct omap_dss_device *dssdev, | ||
631 | struct omap_video_timings *timings); | ||
632 | void (*get_timings)(struct omap_dss_device *dssdev, | ||
633 | struct omap_video_timings *timings); | ||
634 | }; | ||
635 | |||
636 | struct omapdss_atv_ops { | ||
637 | int (*connect)(struct omap_dss_device *dssdev, | ||
638 | struct omap_dss_device *dst); | ||
639 | void (*disconnect)(struct omap_dss_device *dssdev, | ||
640 | struct omap_dss_device *dst); | ||
641 | |||
642 | int (*enable)(struct omap_dss_device *dssdev); | ||
643 | void (*disable)(struct omap_dss_device *dssdev); | ||
644 | |||
645 | int (*check_timings)(struct omap_dss_device *dssdev, | ||
646 | struct omap_video_timings *timings); | ||
647 | void (*set_timings)(struct omap_dss_device *dssdev, | ||
648 | struct omap_video_timings *timings); | ||
649 | void (*get_timings)(struct omap_dss_device *dssdev, | ||
650 | struct omap_video_timings *timings); | ||
651 | |||
652 | void (*set_type)(struct omap_dss_device *dssdev, | ||
653 | enum omap_dss_venc_type type); | ||
654 | void (*invert_vid_out_polarity)(struct omap_dss_device *dssdev, | ||
655 | bool invert_polarity); | ||
656 | |||
657 | int (*set_wss)(struct omap_dss_device *dssdev, u32 wss); | ||
658 | u32 (*get_wss)(struct omap_dss_device *dssdev); | ||
659 | }; | ||
660 | |||
661 | struct omapdss_hdmi_ops { | ||
662 | int (*connect)(struct omap_dss_device *dssdev, | ||
663 | struct omap_dss_device *dst); | ||
664 | void (*disconnect)(struct omap_dss_device *dssdev, | ||
665 | struct omap_dss_device *dst); | ||
666 | |||
667 | int (*enable)(struct omap_dss_device *dssdev); | ||
668 | void (*disable)(struct omap_dss_device *dssdev); | ||
669 | |||
670 | int (*check_timings)(struct omap_dss_device *dssdev, | ||
671 | struct omap_video_timings *timings); | ||
672 | void (*set_timings)(struct omap_dss_device *dssdev, | ||
673 | struct omap_video_timings *timings); | ||
674 | void (*get_timings)(struct omap_dss_device *dssdev, | ||
675 | struct omap_video_timings *timings); | ||
676 | |||
677 | int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len); | ||
678 | bool (*detect)(struct omap_dss_device *dssdev); | ||
679 | |||
680 | /* | ||
681 | * Note: These functions might sleep. Do not call while | ||
682 | * holding a spinlock/readlock. | ||
683 | */ | ||
684 | int (*audio_enable)(struct omap_dss_device *dssdev); | ||
685 | void (*audio_disable)(struct omap_dss_device *dssdev); | ||
686 | bool (*audio_supported)(struct omap_dss_device *dssdev); | ||
687 | int (*audio_config)(struct omap_dss_device *dssdev, | ||
688 | struct omap_dss_audio *audio); | ||
689 | /* Note: These functions may not sleep */ | ||
690 | int (*audio_start)(struct omap_dss_device *dssdev); | ||
691 | void (*audio_stop)(struct omap_dss_device *dssdev); | ||
692 | }; | ||
693 | |||
694 | struct omapdss_dsi_ops { | ||
695 | int (*connect)(struct omap_dss_device *dssdev, | ||
696 | struct omap_dss_device *dst); | ||
697 | void (*disconnect)(struct omap_dss_device *dssdev, | ||
698 | struct omap_dss_device *dst); | ||
699 | |||
700 | int (*enable)(struct omap_dss_device *dssdev); | ||
701 | void (*disable)(struct omap_dss_device *dssdev, bool disconnect_lanes, | ||
702 | bool enter_ulps); | ||
703 | |||
704 | /* bus configuration */ | ||
705 | int (*set_config)(struct omap_dss_device *dssdev, | ||
706 | const struct omap_dss_dsi_config *cfg); | ||
707 | int (*configure_pins)(struct omap_dss_device *dssdev, | ||
708 | const struct omap_dsi_pin_config *pin_cfg); | ||
709 | |||
710 | void (*enable_hs)(struct omap_dss_device *dssdev, int channel, | ||
711 | bool enable); | ||
712 | int (*enable_te)(struct omap_dss_device *dssdev, bool enable); | ||
713 | |||
714 | int (*update)(struct omap_dss_device *dssdev, int channel, | ||
715 | void (*callback)(int, void *), void *data); | ||
716 | |||
717 | void (*bus_lock)(struct omap_dss_device *dssdev); | ||
718 | void (*bus_unlock)(struct omap_dss_device *dssdev); | ||
719 | |||
720 | int (*enable_video_output)(struct omap_dss_device *dssdev, int channel); | ||
721 | void (*disable_video_output)(struct omap_dss_device *dssdev, | ||
722 | int channel); | ||
723 | |||
724 | int (*request_vc)(struct omap_dss_device *dssdev, int *channel); | ||
725 | int (*set_vc_id)(struct omap_dss_device *dssdev, int channel, | ||
726 | int vc_id); | ||
727 | void (*release_vc)(struct omap_dss_device *dssdev, int channel); | ||
728 | |||
729 | /* data transfer */ | ||
730 | int (*dcs_write)(struct omap_dss_device *dssdev, int channel, | ||
731 | u8 *data, int len); | ||
732 | int (*dcs_write_nosync)(struct omap_dss_device *dssdev, int channel, | ||
733 | u8 *data, int len); | ||
734 | int (*dcs_read)(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, | ||
735 | u8 *data, int len); | ||
736 | |||
737 | int (*gen_write)(struct omap_dss_device *dssdev, int channel, | ||
738 | u8 *data, int len); | ||
739 | int (*gen_write_nosync)(struct omap_dss_device *dssdev, int channel, | ||
740 | u8 *data, int len); | ||
741 | int (*gen_read)(struct omap_dss_device *dssdev, int channel, | ||
742 | u8 *reqdata, int reqlen, | ||
743 | u8 *data, int len); | ||
744 | |||
745 | int (*bta_sync)(struct omap_dss_device *dssdev, int channel); | ||
746 | |||
747 | int (*set_max_rx_packet_size)(struct omap_dss_device *dssdev, | ||
748 | int channel, u16 plen); | ||
593 | }; | 749 | }; |
594 | 750 | ||
595 | struct omap_dss_device { | 751 | struct omap_dss_device { |
596 | struct device dev; | 752 | /* old device, to be removed */ |
753 | struct device old_dev; | ||
754 | |||
755 | /* new device, pointer to panel device */ | ||
756 | struct device *dev; | ||
757 | |||
758 | struct module *owner; | ||
759 | |||
760 | struct list_head panel_list; | ||
761 | |||
762 | /* alias in the form of "display%d" */ | ||
763 | char alias[16]; | ||
597 | 764 | ||
598 | enum omap_display_type type; | 765 | enum omap_display_type type; |
766 | enum omap_display_type output_type; | ||
599 | 767 | ||
600 | /* obsolete, to be removed */ | 768 | /* obsolete, to be removed */ |
601 | enum omap_channel channel; | 769 | enum omap_channel channel; |
@@ -616,9 +784,6 @@ struct omap_dss_device { | |||
616 | 784 | ||
617 | struct { | 785 | struct { |
618 | int module; | 786 | int module; |
619 | |||
620 | bool ext_te; | ||
621 | u8 ext_te_gpio; | ||
622 | } dsi; | 787 | } dsi; |
623 | 788 | ||
624 | struct { | 789 | struct { |
@@ -639,10 +804,6 @@ struct omap_dss_device { | |||
639 | struct rfbi_timings rfbi_timings; | 804 | struct rfbi_timings rfbi_timings; |
640 | } ctrl; | 805 | } ctrl; |
641 | 806 | ||
642 | int reset_gpio; | ||
643 | |||
644 | int max_backlight_level; | ||
645 | |||
646 | const char *name; | 807 | const char *name; |
647 | 808 | ||
648 | /* used to match device to driver */ | 809 | /* used to match device to driver */ |
@@ -652,22 +813,40 @@ struct omap_dss_device { | |||
652 | 813 | ||
653 | struct omap_dss_driver *driver; | 814 | struct omap_dss_driver *driver; |
654 | 815 | ||
816 | union { | ||
817 | const struct omapdss_dpi_ops *dpi; | ||
818 | const struct omapdss_sdi_ops *sdi; | ||
819 | const struct omapdss_dvi_ops *dvi; | ||
820 | const struct omapdss_hdmi_ops *hdmi; | ||
821 | const struct omapdss_atv_ops *atv; | ||
822 | const struct omapdss_dsi_ops *dsi; | ||
823 | } ops; | ||
824 | |||
655 | /* helper variable for driver suspend/resume */ | 825 | /* helper variable for driver suspend/resume */ |
656 | bool activate_after_resume; | 826 | bool activate_after_resume; |
657 | 827 | ||
658 | enum omap_display_caps caps; | 828 | enum omap_display_caps caps; |
659 | 829 | ||
660 | struct omap_dss_output *output; | 830 | struct omap_dss_device *output; |
661 | 831 | ||
662 | enum omap_dss_display_state state; | 832 | enum omap_dss_display_state state; |
663 | 833 | ||
664 | enum omap_dss_audio_state audio_state; | 834 | enum omap_dss_audio_state audio_state; |
665 | 835 | ||
666 | /* platform specific */ | 836 | /* OMAP DSS output specific fields */ |
667 | int (*platform_enable)(struct omap_dss_device *dssdev); | 837 | |
668 | void (*platform_disable)(struct omap_dss_device *dssdev); | 838 | struct list_head list; |
669 | int (*set_backlight)(struct omap_dss_device *dssdev, int level); | 839 | |
670 | int (*get_backlight)(struct omap_dss_device *dssdev); | 840 | /* DISPC channel for this output */ |
841 | enum omap_channel dispc_channel; | ||
842 | |||
843 | /* output instance */ | ||
844 | enum omap_dss_output_id id; | ||
845 | |||
846 | /* dynamic fields */ | ||
847 | struct omap_overlay_manager *manager; | ||
848 | |||
849 | struct omap_dss_device *device; | ||
671 | }; | 850 | }; |
672 | 851 | ||
673 | struct omap_dss_hdmi_data | 852 | struct omap_dss_hdmi_data |
@@ -677,17 +856,15 @@ struct omap_dss_hdmi_data | |||
677 | int hpd_gpio; | 856 | int hpd_gpio; |
678 | }; | 857 | }; |
679 | 858 | ||
680 | struct omap_dss_audio { | ||
681 | struct snd_aes_iec958 *iec; | ||
682 | struct snd_cea_861_aud_if *cea; | ||
683 | }; | ||
684 | |||
685 | struct omap_dss_driver { | 859 | struct omap_dss_driver { |
686 | struct device_driver driver; | 860 | struct device_driver driver; |
687 | 861 | ||
688 | int (*probe)(struct omap_dss_device *); | 862 | int (*probe)(struct omap_dss_device *); |
689 | void (*remove)(struct omap_dss_device *); | 863 | void (*remove)(struct omap_dss_device *); |
690 | 864 | ||
865 | int (*connect)(struct omap_dss_device *dssdev); | ||
866 | void (*disconnect)(struct omap_dss_device *dssdev); | ||
867 | |||
691 | int (*enable)(struct omap_dss_device *display); | 868 | int (*enable)(struct omap_dss_device *display); |
692 | void (*disable)(struct omap_dss_device *display); | 869 | void (*disable)(struct omap_dss_device *display); |
693 | int (*run_test)(struct omap_dss_device *display, int test); | 870 | int (*run_test)(struct omap_dss_device *display, int test); |
@@ -753,7 +930,10 @@ bool omapdss_is_initialized(void); | |||
753 | int omap_dss_register_driver(struct omap_dss_driver *); | 930 | int omap_dss_register_driver(struct omap_dss_driver *); |
754 | void omap_dss_unregister_driver(struct omap_dss_driver *); | 931 | void omap_dss_unregister_driver(struct omap_dss_driver *); |
755 | 932 | ||
756 | void omap_dss_get_device(struct omap_dss_device *dssdev); | 933 | int omapdss_register_display(struct omap_dss_device *dssdev); |
934 | void omapdss_unregister_display(struct omap_dss_device *dssdev); | ||
935 | |||
936 | struct omap_dss_device *omap_dss_get_device(struct omap_dss_device *dssdev); | ||
757 | void omap_dss_put_device(struct omap_dss_device *dssdev); | 937 | void omap_dss_put_device(struct omap_dss_device *dssdev); |
758 | #define for_each_dss_dev(d) while ((d = omap_dss_get_next_device(d)) != NULL) | 938 | #define for_each_dss_dev(d) while ((d = omap_dss_get_next_device(d)) != NULL) |
759 | struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from); | 939 | struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from); |
@@ -761,8 +941,10 @@ struct omap_dss_device *omap_dss_find_device(void *data, | |||
761 | int (*match)(struct omap_dss_device *dssdev, void *data)); | 941 | int (*match)(struct omap_dss_device *dssdev, void *data)); |
762 | const char *omapdss_get_default_display_name(void); | 942 | const char *omapdss_get_default_display_name(void); |
763 | 943 | ||
764 | int omap_dss_start_device(struct omap_dss_device *dssdev); | 944 | void videomode_to_omap_video_timings(const struct videomode *vm, |
765 | void omap_dss_stop_device(struct omap_dss_device *dssdev); | 945 | struct omap_video_timings *ovt); |
946 | void omap_video_timings_to_videomode(const struct omap_video_timings *ovt, | ||
947 | struct videomode *vm); | ||
766 | 948 | ||
767 | int dss_feat_get_num_mgrs(void); | 949 | int dss_feat_get_num_mgrs(void); |
768 | int dss_feat_get_num_ovls(void); | 950 | int dss_feat_get_num_ovls(void); |
@@ -778,10 +960,17 @@ struct omap_overlay_manager *omap_dss_get_overlay_manager(int num); | |||
778 | int omap_dss_get_num_overlays(void); | 960 | int omap_dss_get_num_overlays(void); |
779 | struct omap_overlay *omap_dss_get_overlay(int num); | 961 | struct omap_overlay *omap_dss_get_overlay(int num); |
780 | 962 | ||
781 | struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id); | 963 | int omapdss_register_output(struct omap_dss_device *output); |
782 | int omapdss_output_set_device(struct omap_dss_output *out, | 964 | void omapdss_unregister_output(struct omap_dss_device *output); |
965 | struct omap_dss_device *omap_dss_get_output(enum omap_dss_output_id id); | ||
966 | struct omap_dss_device *omap_dss_find_output(const char *name); | ||
967 | struct omap_dss_device *omap_dss_find_output_by_node(struct device_node *node); | ||
968 | int omapdss_output_set_device(struct omap_dss_device *out, | ||
783 | struct omap_dss_device *dssdev); | 969 | struct omap_dss_device *dssdev); |
784 | int omapdss_output_unset_device(struct omap_dss_output *out); | 970 | int omapdss_output_unset_device(struct omap_dss_device *out); |
971 | |||
972 | struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev); | ||
973 | struct omap_overlay_manager *omapdss_find_mgr_from_display(struct omap_dss_device *dssdev); | ||
785 | 974 | ||
786 | void omapdss_default_get_resolution(struct omap_dss_device *dssdev, | 975 | void omapdss_default_get_resolution(struct omap_dss_device *dssdev, |
787 | u16 *xres, u16 *yres); | 976 | u16 *xres, u16 *yres); |
@@ -832,7 +1021,7 @@ int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, | |||
832 | bool mem_to_mem); | 1021 | bool mem_to_mem); |
833 | 1022 | ||
834 | #define to_dss_driver(x) container_of((x), struct omap_dss_driver, driver) | 1023 | #define to_dss_driver(x) container_of((x), struct omap_dss_driver, driver) |
835 | #define to_dss_device(x) container_of((x), struct omap_dss_device, dev) | 1024 | #define to_dss_device(x) container_of((x), struct omap_dss_device, old_dev) |
836 | 1025 | ||
837 | void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel, | 1026 | void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel, |
838 | bool enable); | 1027 | bool enable); |
@@ -883,6 +1072,11 @@ int omapdss_compat_init(void); | |||
883 | void omapdss_compat_uninit(void); | 1072 | void omapdss_compat_uninit(void); |
884 | 1073 | ||
885 | struct dss_mgr_ops { | 1074 | struct dss_mgr_ops { |
1075 | int (*connect)(struct omap_overlay_manager *mgr, | ||
1076 | struct omap_dss_device *dst); | ||
1077 | void (*disconnect)(struct omap_overlay_manager *mgr, | ||
1078 | struct omap_dss_device *dst); | ||
1079 | |||
886 | void (*start_update)(struct omap_overlay_manager *mgr); | 1080 | void (*start_update)(struct omap_overlay_manager *mgr); |
887 | int (*enable)(struct omap_overlay_manager *mgr); | 1081 | int (*enable)(struct omap_overlay_manager *mgr); |
888 | void (*disable)(struct omap_overlay_manager *mgr); | 1082 | void (*disable)(struct omap_overlay_manager *mgr); |
@@ -899,6 +1093,10 @@ struct dss_mgr_ops { | |||
899 | int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops); | 1093 | int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops); |
900 | void dss_uninstall_mgr_ops(void); | 1094 | void dss_uninstall_mgr_ops(void); |
901 | 1095 | ||
1096 | int dss_mgr_connect(struct omap_overlay_manager *mgr, | ||
1097 | struct omap_dss_device *dst); | ||
1098 | void dss_mgr_disconnect(struct omap_overlay_manager *mgr, | ||
1099 | struct omap_dss_device *dst); | ||
902 | void dss_mgr_set_timings(struct omap_overlay_manager *mgr, | 1100 | void dss_mgr_set_timings(struct omap_overlay_manager *mgr, |
903 | const struct omap_video_timings *timings); | 1101 | const struct omap_video_timings *timings); |
904 | void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, | 1102 | void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, |
@@ -910,4 +1108,15 @@ int dss_mgr_register_framedone_handler(struct omap_overlay_manager *mgr, | |||
910 | void (*handler)(void *), void *data); | 1108 | void (*handler)(void *), void *data); |
911 | void dss_mgr_unregister_framedone_handler(struct omap_overlay_manager *mgr, | 1109 | void dss_mgr_unregister_framedone_handler(struct omap_overlay_manager *mgr, |
912 | void (*handler)(void *), void *data); | 1110 | void (*handler)(void *), void *data); |
1111 | |||
1112 | static inline bool omapdss_device_is_connected(struct omap_dss_device *dssdev) | ||
1113 | { | ||
1114 | return dssdev->output; | ||
1115 | } | ||
1116 | |||
1117 | static inline bool omapdss_device_is_enabled(struct omap_dss_device *dssdev) | ||
1118 | { | ||
1119 | return dssdev->state == OMAP_DSS_DISPLAY_ACTIVE; | ||
1120 | } | ||
1121 | |||
913 | #endif | 1122 | #endif |