diff options
Diffstat (limited to 'drivers/video/mxc')
-rw-r--r-- | drivers/video/mxc/mipi_dsi.c | 1 | ||||
-rw-r--r-- | drivers/video/mxc/mxc_dispdrv.c | 15 | ||||
-rw-r--r-- | drivers/video/mxc/mxc_dispdrv.h | 2 | ||||
-rw-r--r-- | drivers/video/mxc/mxc_hdmi.c | 22 | ||||
-rw-r--r-- | drivers/video/mxc/mxc_ipuv3_fb.c | 115 |
5 files changed, 153 insertions, 2 deletions
diff --git a/drivers/video/mxc/mipi_dsi.c b/drivers/video/mxc/mipi_dsi.c index ca1b53f61b59..1ec02317aa64 100644 --- a/drivers/video/mxc/mipi_dsi.c +++ b/drivers/video/mxc/mipi_dsi.c @@ -890,6 +890,7 @@ static int mipi_dsi_probe(struct platform_device *pdev) mxc_dispdrv_setdata(mipi_dsi->disp_mipi, mipi_dsi); dev_set_drvdata(&pdev->dev, mipi_dsi); + mxc_dispdrv_setdev(mipi_dsi->disp_mipi, &pdev->dev); dev_info(&pdev->dev, "i.MX MIPI DSI driver probed\n"); return ret; diff --git a/drivers/video/mxc/mxc_dispdrv.c b/drivers/video/mxc/mxc_dispdrv.c index 805c1c98b0f9..9a36f9159c05 100644 --- a/drivers/video/mxc/mxc_dispdrv.c +++ b/drivers/video/mxc/mxc_dispdrv.c @@ -48,8 +48,23 @@ struct mxc_dispdrv_entry { bool active; void *priv; struct list_head list; + struct device *dev; }; +void mxc_dispdrv_setdev(struct mxc_dispdrv_handle *drv_handle, struct device *dev) +{ + struct mxc_dispdrv_entry *dentry; + dentry = (struct mxc_dispdrv_entry *)drv_handle; + dentry->dev = dev; +} + +struct device *mxc_dispdrv_getdev(struct mxc_dispdrv_handle *drv_handle) +{ + struct mxc_dispdrv_entry *dentry; + dentry = (struct mxc_dispdrv_entry *)drv_handle; + return dentry->dev; +} + struct mxc_dispdrv_handle *mxc_dispdrv_register(struct mxc_dispdrv_driver *drv) { struct mxc_dispdrv_entry *new; diff --git a/drivers/video/mxc/mxc_dispdrv.h b/drivers/video/mxc/mxc_dispdrv.h index 58d8a07d3380..893fd81a7b42 100644 --- a/drivers/video/mxc/mxc_dispdrv.h +++ b/drivers/video/mxc/mxc_dispdrv.h @@ -49,4 +49,6 @@ struct mxc_dispdrv_handle *mxc_dispdrv_gethandle(char *name, void mxc_dispdrv_puthandle(struct mxc_dispdrv_handle *handle); int mxc_dispdrv_setdata(struct mxc_dispdrv_handle *handle, void *data); void *mxc_dispdrv_getdata(struct mxc_dispdrv_handle *handle); +void mxc_dispdrv_setdev(struct mxc_dispdrv_handle *drv_handle, struct device *dev); +struct device *mxc_dispdrv_getdev(struct mxc_dispdrv_handle *drv_handle); #endif diff --git a/drivers/video/mxc/mxc_hdmi.c b/drivers/video/mxc/mxc_hdmi.c index bcd031df5b9d..e51443d0f840 100644 --- a/drivers/video/mxc/mxc_hdmi.c +++ b/drivers/video/mxc/mxc_hdmi.c @@ -54,6 +54,7 @@ #include <linux/console.h> #include <linux/types.h> +#include <linux/switch.h> #include "../edid.h" #include <video/mxc_edid.h> @@ -176,6 +177,8 @@ struct mxc_hdmi { struct fb_videomode default_mode; struct fb_videomode previous_non_vga_mode; bool requesting_vga_for_initialization; + struct switch_dev sdev_audio; + struct switch_dev sdev_display; int *gpr_base; int *gpr_hdmi_base; @@ -2008,14 +2011,22 @@ static void hotplug_worker(struct work_struct *work) hdmi_set_cable_state(1); + if (!hdmi->hdmi_data.video_mode.mDVI) + switch_set_state(&hdmi->sdev_audio, 1); + switch_set_state(&hdmi->sdev_display, 1); + sprintf(event_string, "EVENT=plugin"); kobject_uevent_env(&hdmi->pdev->dev.kobj, KOBJ_CHANGE, envp); #ifdef CONFIG_MXC_HDMI_CEC mxc_hdmi_cec_handle(0x80); #endif + } else if (!(phy_int_pol & HDMI_PHY_HPD)) { /* Plugout event */ dev_dbg(&hdmi->pdev->dev, "EVENT=plugout\n"); + switch_set_state(&hdmi->sdev_audio, 0); + switch_set_state(&hdmi->sdev_display, 0); + hdmi_set_cable_state(0); mxc_hdmi_abort_stream(); mxc_hdmi_cable_disconnected(hdmi); @@ -2794,10 +2805,18 @@ static int mxc_hdmi_probe(struct platform_device *pdev) ret = (int)hdmi->disp_mxc_hdmi; goto edispdrv; } + + hdmi->sdev_audio.name = "hdmi_audio"; + hdmi->sdev_display.name = "hdmi"; + switch_dev_register(&hdmi->sdev_audio); + switch_dev_register(&hdmi->sdev_display); + mxc_dispdrv_setdata(hdmi->disp_mxc_hdmi, hdmi); platform_set_drvdata(pdev, hdmi); + mxc_dispdrv_setdev(hdmi->disp_mxc_hdmi, &pdev->dev); + return 0; edispdrv: iounmap(hdmi->gpr_base); @@ -2821,6 +2840,9 @@ static int mxc_hdmi_remove(struct platform_device *pdev) fb_unregister_client(&hdmi->nb); + switch_dev_unregister(&hdmi->sdev_audio); + switch_dev_unregister(&hdmi->sdev_display); + mxc_dispdrv_puthandle(hdmi->disp_mxc_hdmi); mxc_dispdrv_unregister(hdmi->disp_mxc_hdmi); iounmap(hdmi->gpr_base); diff --git a/drivers/video/mxc/mxc_ipuv3_fb.c b/drivers/video/mxc/mxc_ipuv3_fb.c index 9d074f9e7a80..bc853225d6c3 100644 --- a/drivers/video/mxc/mxc_ipuv3_fb.c +++ b/drivers/video/mxc/mxc_ipuv3_fb.c @@ -49,6 +49,7 @@ #include <linux/string.h> #include <linux/uaccess.h> +#include <linux/earlysuspend.h> #include "mxc_dispdrv.h" /* @@ -98,6 +99,10 @@ struct mxcfb_info { struct mxc_dispdrv_handle *dispdrv; struct fb_var_screeninfo cur_var; + ktime_t vsync_nf_timestamp; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend fbdrv_earlysuspend; +#endif }; struct mxcfb_pfmt { @@ -135,6 +140,10 @@ enum { static bool g_dp_in_use[2]; LIST_HEAD(fb_alloc_list); +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mxcfb_early_suspend(struct early_suspend *h); +static void mxcfb_later_resume(struct early_suspend *h); +#endif /* Return default standard(RGB) pixel format */ static uint32_t bpp_to_pixfmt(int bpp) @@ -1143,6 +1152,7 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) } case MXCFB_WAIT_FOR_VSYNC: { + unsigned long long timestamp; if (mxc_fbi->ipu_ch == MEM_FG_SYNC) { /* BG should poweron */ struct mxcfb_info *bg_mxcfbi = NULL; @@ -1171,6 +1181,15 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) ipu_enable_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_nf_irq); retval = wait_for_completion_interruptible_timeout( &mxc_fbi->vsync_complete, 1 * HZ); + + timestamp = ktime_to_ns(mxc_fbi->vsync_nf_timestamp); + dev_vdbg(fbi->device, "ts = %llu", timestamp); + + if (copy_to_user((void *)arg, ×tamp, sizeof(timestamp))) { + retval = -EFAULT; + break; + } + if (retval == 0) { dev_err(fbi->device, "MXCFB_WAIT_FOR_VSYNC: timeout %d\n", @@ -1656,6 +1675,8 @@ static irqreturn_t mxcfb_nf_irq_handler(int irq, void *dev_id) struct fb_info *fbi = dev_id; struct mxcfb_info *mxc_fbi = fbi->par; + mxc_fbi->vsync_nf_timestamp = ktime_get(); + complete(&mxc_fbi->vsync_complete); return IRQ_HANDLED; } @@ -1672,7 +1693,7 @@ static irqreturn_t mxcfb_alpha_irq_handler(int irq, void *dev_id) /* * Suspends the framebuffer and blanks the screen. Power management support */ -static int mxcfb_suspend(struct platform_device *pdev, pm_message_t state) +static int mxcfb_core_suspend(struct platform_device *pdev, pm_message_t state) { struct fb_info *fbi = platform_get_drvdata(pdev); struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par; @@ -1704,9 +1725,22 @@ static int mxcfb_suspend(struct platform_device *pdev, pm_message_t state) } /* + * Suspends the framebuffer and blanks the screen. Power management support + */ +static int mxcfb_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct fb_info *fbi = platform_get_drvdata(pdev); + struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par; + + if (strstr(mxc_fbi->dispdrv->drv->name, "hdmi")) + return mxcfb_core_suspend(pdev, state); + + return 0; +} +/* * Resumes the framebuffer and unblanks the screen. Power management support */ -static int mxcfb_resume(struct platform_device *pdev) +static int mxcfb_core_resume(struct platform_device *pdev) { struct fb_info *fbi = platform_get_drvdata(pdev); struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par; @@ -1724,6 +1758,18 @@ static int mxcfb_resume(struct platform_device *pdev) fb_set_suspend(mxc_fbi->ovfbi, 0); console_unlock(); } + return 0; +} +/* + * Resumes the framebuffer and unblanks the screen. Power management support + */ +static int mxcfb_resume(struct platform_device *pdev) +{ + struct fb_info *fbi = platform_get_drvdata(pdev); + struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par; + + if (strstr(mxc_fbi->dispdrv->drv->name, "hdmi")) + return mxcfb_core_resume(pdev); return 0; } @@ -2361,6 +2407,7 @@ static int mxcfb_probe(struct platform_device *pdev) struct ipuv3_fb_platform_data *plat_data; struct fb_info *fbi; struct mxcfb_info *mxcfbi; + struct device *disp_dev; struct resource *res; int ret = 0; @@ -2492,6 +2539,22 @@ static int mxcfb_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Error %d on creating file for disp " " device propety\n", ret); + disp_dev = mxc_dispdrv_getdev(mxcfbi->dispdrv); + if (disp_dev) { + ret = sysfs_create_link(&fbi->dev->kobj, + &disp_dev->kobj, "disp_dev"); + if (ret) + dev_err(&pdev->dev, + "Error %d on creating file\n", ret); + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + mxcfbi->fbdrv_earlysuspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB; + mxcfbi->fbdrv_earlysuspend.suspend = mxcfb_early_suspend; + mxcfbi->fbdrv_earlysuspend.resume = mxcfb_later_resume; + mxcfbi->fbdrv_earlysuspend.data = pdev; + register_early_suspend(&mxcfbi->fbdrv_earlysuspend); +#endif return 0; mxcfb_setupoverlay_failed: @@ -2514,6 +2577,9 @@ static int mxcfb_remove(struct platform_device *pdev) if (!fbi) return 0; +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&mxc_fbi->fbdrv_earlysuspend); +#endif device_remove_file(fbi->dev, &dev_attr_fsl_disp_dev_property); device_remove_file(fbi->dev, &dev_attr_fsl_disp_property); @@ -2556,6 +2622,51 @@ static struct platform_driver mxcfb_driver = { .suspend = mxcfb_suspend, .resume = mxcfb_resume, }; +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mxcfb_early_suspend(struct early_suspend *h) +{ + struct platform_device *pdev = (struct platform_device *)h->data; + struct fb_info *fbi = platform_get_drvdata(pdev); + struct mxcfb_info *mxcfbi = (struct mxcfb_info *)fbi->par; + pm_message_t state = { .event = PM_EVENT_SUSPEND }; + struct fb_event event; + int blank = FB_BLANK_POWERDOWN; + + if (mxcfbi->ipu_ch == MEM_FG_SYNC) + return; + + if (strstr(mxcfbi->dispdrv->drv->name, "hdmi")) { + /* Only black the hdmi fb due to audio dependency */ + memset(fbi->screen_base, 0, fbi->fix.smem_len); + return; + } + + mxcfb_core_suspend(pdev, state); + event.info = fbi; + event.data = ␣ + fb_notifier_call_chain(FB_EVENT_BLANK, &event); +} + +static void mxcfb_later_resume(struct early_suspend *h) +{ + struct platform_device *pdev = (struct platform_device *)h->data; + struct fb_info *fbi = platform_get_drvdata(pdev); + struct mxcfb_info *mxcfbi = (struct mxcfb_info *)fbi->par; + struct fb_event event; + + if (mxcfbi->ipu_ch == MEM_FG_SYNC) + return; + + /* HDMI resume function has been called */ + if (strstr(mxcfbi->dispdrv->drv->name, "hdmi")) + return; + + mxcfb_core_resume(pdev); + event.info = fbi; + event.data = &mxcfbi->next_blank; + fb_notifier_call_chain(FB_EVENT_BLANK, &event); +} +#endif /*! * Main entry function for the framebuffer. The function registers the power |