OMAP: DSS2: OMAPFB: Implement auto-update mode

Implement auto-update mode for manual-update displays. omapfb driver
uses a delayed work to update the display with a constant rate.

The update mode can be changed via OMAPFB_SET_UPDATE_MODE ioctl, which
previously called omapdss but is now handled inside omapfb, and a new
sysfs file, "update_mode".

The update interval is by default 20 times per second, but can be
changed via "auto_update_freq" module parameter. There is also a new
module parameter "auto_update", which will make omapfb start manual
update displays in auto-update mode.

This auto-update mode can be used for testing if the userspace does not
support manual update displays properly. However, it is a very
inefficient solution, and should be considered more as a hack for
testing than something that could be used as a long term solution.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c
index cff4503..6b1ac23 100644
--- a/drivers/video/omap2/omapfb/omapfb-ioctl.c
+++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c
@@ -316,68 +316,68 @@
 }
 EXPORT_SYMBOL(omapfb_update_window);
 
-static int omapfb_set_update_mode(struct fb_info *fbi,
+int omapfb_set_update_mode(struct fb_info *fbi,
 				   enum omapfb_update_mode mode)
 {
 	struct omap_dss_device *display = fb2display(fbi);
-	enum omap_dss_update_mode um;
+	struct omapfb_info *ofbi = FB2OFB(fbi);
+	struct omapfb2_device *fbdev = ofbi->fbdev;
+	struct omapfb_display_data *d;
 	int r;
 
-	if (!display || !display->driver->set_update_mode)
-		return -EINVAL;
-
-	switch (mode) {
-	case OMAPFB_UPDATE_DISABLED:
-		um = OMAP_DSS_UPDATE_DISABLED;
-		break;
-
-	case OMAPFB_AUTO_UPDATE:
-		um = OMAP_DSS_UPDATE_AUTO;
-		break;
-
-	case OMAPFB_MANUAL_UPDATE:
-		um = OMAP_DSS_UPDATE_MANUAL;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	r = display->driver->set_update_mode(display, um);
-
-	return r;
-}
-
-static int omapfb_get_update_mode(struct fb_info *fbi,
-		enum omapfb_update_mode *mode)
-{
-	struct omap_dss_device *display = fb2display(fbi);
-	enum omap_dss_update_mode m;
-
 	if (!display)
 		return -EINVAL;
 
-	if (!display->driver->get_update_mode) {
-		*mode = OMAPFB_AUTO_UPDATE;
+	if (mode != OMAPFB_AUTO_UPDATE && mode != OMAPFB_MANUAL_UPDATE)
+		return -EINVAL;
+
+	omapfb_lock(fbdev);
+
+	d = get_display_data(fbdev, display);
+
+	if (d->update_mode == mode) {
+		omapfb_unlock(fbdev);
 		return 0;
 	}
 
-	m = display->driver->get_update_mode(display);
+	r = 0;
 
-	switch (m) {
-	case OMAP_DSS_UPDATE_DISABLED:
-		*mode = OMAPFB_UPDATE_DISABLED;
-		break;
-	case OMAP_DSS_UPDATE_AUTO:
-		*mode = OMAPFB_AUTO_UPDATE;
-		break;
-	case OMAP_DSS_UPDATE_MANUAL:
-		*mode = OMAPFB_MANUAL_UPDATE;
-		break;
-	default:
-		BUG();
+	if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
+		if (mode == OMAPFB_AUTO_UPDATE)
+			omapfb_start_auto_update(fbdev, display);
+		else /* MANUAL_UPDATE */
+			omapfb_stop_auto_update(fbdev, display);
+
+		d->update_mode = mode;
+	} else { /* AUTO_UPDATE */
+		if (mode == OMAPFB_MANUAL_UPDATE)
+			r = -EINVAL;
 	}
 
+	omapfb_unlock(fbdev);
+
+	return r;
+}
+
+int omapfb_get_update_mode(struct fb_info *fbi,
+		enum omapfb_update_mode *mode)
+{
+	struct omap_dss_device *display = fb2display(fbi);
+	struct omapfb_info *ofbi = FB2OFB(fbi);
+	struct omapfb2_device *fbdev = ofbi->fbdev;
+	struct omapfb_display_data *d;
+
+	if (!display)
+		return -EINVAL;
+
+	omapfb_lock(fbdev);
+
+	d = get_display_data(fbdev, display);
+
+	*mode = d->update_mode;
+
+	omapfb_unlock(fbdev);
+
 	return 0;
 }