diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-09 18:51:32 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-09 18:51:32 -0400 |
| commit | 5f097cd249f00683442c3e265d6f27d80fc83563 (patch) | |
| tree | 6b354913fcb2a099aa26e017895e1e6fdf6385e2 | |
| parent | a82a729f04232ccd0b59406574ba4cf20027a49d (diff) | |
| parent | 1b6c79361ba5ce30b40f0f7d6fc2421dc5fcbe0c (diff) | |
Merge tag 'fbdev-for-3.11' of git://git.kernel.org/pub/scm/linux/kernel/git/plagnioj/linux-fbdev
Pull fbdev update from Jean-Christophe PLAGNIOL-VILLARD:
"Various fbdev changes for 3.11
- xilinxfb updates
- Small cleanups and fixes to multiple drivers
- OMAP display subsystem bug updates
- imxfb dt support"
* tag 'fbdev-for-3.11' of git://git.kernel.org/pub/scm/linux/kernel/git/plagnioj/linux-fbdev: (95 commits)
video: imxfb: Add DT support
video: i740fb: Make i740fb_init static
fb: make fp_get_options name argument const
video: mmp: fix graphics/video layer enable/mask swap issue
video: mmp: fix memcpy wrong size for mmp_addr issue
radeon: use pdev->pm_cap instead of pci_find_capability(..,PCI_CAP_ID_PM)
aty128fb: use pdev->pm_cap instead of pci_find_capability(..,PCI_CAP_ID_PM)
video: of_display_timing.h: Declare 'display_timing'
fbdev: bfin-lq035q1-fb: Use dev_pm_ops
fbmem: return -EFAULT on copy_to_user() failure
OMAPDSS: DPI: Fix wrong pixel clock limit
video: replace strict_strtoul() with kstrtoul()
uvesafb: Correct/simplify warning message
fb: fix atyfb unused data warnings
fb: fix atyfb build warning
video: imxfb: Make local symbols static
video: udlfb: Make local symbol static
video: udlfb: Use NULL instead of 0
video: smscufx: Use NULL instead of 0
video: remove unnecessary platform_set_drvdata()
...
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 |
