Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* [PATCH v2 12/23] OMAPDSS: DSI: Pass omap_dss_output within the driver
From: Archit Taneja @ 2012-08-30 11:52 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: rob, linux-omap, linux-fbdev, Archit Taneja
In-Reply-To: <1346326845-16583-1-git-send-email-archit@ti.com>

When a panel driver calls a DSI function, it passes the omap_dss_device
pointer, this pointer currently propagates within the DSI driver to configure
the interface.

Extract the omap_dss_output pointer from omap_dss_device received from the panel
driver, pass the output pointer to DSI functions local to the driver to
configure the interface, these functions no longer need omap_dss_device since
the driver now maintains a copy of output parameters.

Replace dssdev->manager references with out->manager references as only these
will be valid later.

With the addition of outputs. There is a possibility that an omap_dss_device
isn't connected to an output, or a manager isn't connected to an output yet.
Ensure that the DSI interface functions proceed only if the output is non NULL.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/dss/dsi.c |  219 ++++++++++++++++++++++++-----------------
 1 file changed, 131 insertions(+), 88 deletions(-)

diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 78212c4..228510f 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -356,9 +356,9 @@ static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dside
 	return dev_get_drvdata(&dsidev->dev);
 }
 
-static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev)
+static inline struct platform_device *dsi_get_dsidev_from_output(struct omap_dss_output *out)
 {
-	return dssdev->output->pdev;
+	return out->pdev;
 }
 
 struct platform_device *dsi_get_dsidev_from_id(int module)
@@ -391,7 +391,8 @@ static inline u32 dsi_read_reg(struct platform_device *dsidev,
 
 void dsi_bus_lock(struct omap_dss_device *dssdev)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
 	down(&dsi->bus_lock);
@@ -400,7 +401,8 @@ EXPORT_SYMBOL(dsi_bus_lock);
 
 void dsi_bus_unlock(struct omap_dss_device *dssdev)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
 	up(&dsi->bus_lock);
@@ -1205,15 +1207,15 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
 	return r;
 }
 
-static int dsi_set_lp_clk_divisor(struct omap_dss_device *dssdev)
+static int dsi_set_lp_clk_divisor(struct omap_dss_output *out)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 	unsigned long dsi_fclk;
 	unsigned lp_clk_div;
 	unsigned long lp_clk;
 
-	lp_clk_div = dssdev->clocks.dsi.lp_clk_div;
+	lp_clk_div = out->device->clocks.dsi.lp_clk_div;
 
 	if (lp_clk_div = 0 || lp_clk_div > dsi->lpdiv_max)
 		return -EINVAL;
@@ -2689,7 +2691,8 @@ static int dsi_vc_config_source(struct platform_device *dsidev, int channel,
 void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
 		bool enable)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
 	DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable);
@@ -2817,7 +2820,8 @@ static int dsi_vc_send_bta(struct platform_device *dsidev, int channel)
 
 int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	DECLARE_COMPLETION_ONSTACK(completion);
 	int r = 0;
 	u32 err;
@@ -2986,7 +2990,8 @@ static int dsi_vc_send_short(struct platform_device *dsidev, int channel,
 
 int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 
 	return dsi_vc_send_long(dsidev, channel, MIPI_DSI_NULL_PACKET, NULL,
 		0, 0);
@@ -3026,7 +3031,8 @@ static int dsi_vc_write_nosync_common(struct platform_device *dsidev,
 int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel,
 		u8 *data, int len)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 
 	return dsi_vc_write_nosync_common(dsidev, channel, data, len,
 			DSS_DSI_CONTENT_DCS);
@@ -3036,24 +3042,25 @@ EXPORT_SYMBOL(dsi_vc_dcs_write_nosync);
 int dsi_vc_generic_write_nosync(struct omap_dss_device *dssdev, int channel,
 		u8 *data, int len)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 
 	return dsi_vc_write_nosync_common(dsidev, channel, data, len,
 			DSS_DSI_CONTENT_GENERIC);
 }
 EXPORT_SYMBOL(dsi_vc_generic_write_nosync);
 
-static int dsi_vc_write_common(struct omap_dss_device *dssdev, int channel,
+static int dsi_vc_write_common(struct omap_dss_output *out, int channel,
 		u8 *data, int len, enum dss_dsi_content_type type)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	int r;
 
 	r = dsi_vc_write_nosync_common(dsidev, channel, data, len, type);
 	if (r)
 		goto err;
 
-	r = dsi_vc_send_bta_sync(dssdev, channel);
+	r = dsi_vc_send_bta_sync(out->device, channel);
 	if (r)
 		goto err;
 
@@ -3075,7 +3082,9 @@ err:
 int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data,
 		int len)
 {
-	return dsi_vc_write_common(dssdev, channel, data, len,
+	struct omap_dss_output *out = dssdev->output;
+
+	return dsi_vc_write_common(out, channel, data, len,
 			DSS_DSI_CONTENT_DCS);
 }
 EXPORT_SYMBOL(dsi_vc_dcs_write);
@@ -3083,7 +3092,9 @@ EXPORT_SYMBOL(dsi_vc_dcs_write);
 int dsi_vc_generic_write(struct omap_dss_device *dssdev, int channel, u8 *data,
 		int len)
 {
-	return dsi_vc_write_common(dssdev, channel, data, len,
+	struct omap_dss_output *out = dssdev->output;
+
+	return dsi_vc_write_common(out, channel, data, len,
 			DSS_DSI_CONTENT_GENERIC);
 }
 EXPORT_SYMBOL(dsi_vc_generic_write);
@@ -3295,7 +3306,8 @@ err:
 int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
 		u8 *buf, int buflen)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	int r;
 
 	r = dsi_vc_dcs_send_read_request(dsidev, channel, dcs_cmd);
@@ -3323,17 +3335,17 @@ err:
 }
 EXPORT_SYMBOL(dsi_vc_dcs_read);
 
-static int dsi_vc_generic_read(struct omap_dss_device *dssdev, int channel,
+static int dsi_vc_generic_read(struct omap_dss_output *out, int channel,
 		u8 *reqdata, int reqlen, u8 *buf, int buflen)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	int r;
 
 	r = dsi_vc_generic_send_read_request(dsidev, channel, reqdata, reqlen);
 	if (r)
 		return r;
 
-	r = dsi_vc_send_bta_sync(dssdev, channel);
+	r = dsi_vc_send_bta_sync(out->device, channel);
 	if (r)
 		return r;
 
@@ -3353,9 +3365,10 @@ static int dsi_vc_generic_read(struct omap_dss_device *dssdev, int channel,
 int dsi_vc_generic_read_0(struct omap_dss_device *dssdev, int channel, u8 *buf,
 		int buflen)
 {
+	struct omap_dss_output *out = dssdev->output;
 	int r;
 
-	r = dsi_vc_generic_read(dssdev, channel, NULL, 0, buf, buflen);
+	r = dsi_vc_generic_read(out, channel, NULL, 0, buf, buflen);
 	if (r) {
 		DSSERR("dsi_vc_generic_read_0(ch %d) failed\n", channel);
 		return r;
@@ -3368,9 +3381,10 @@ EXPORT_SYMBOL(dsi_vc_generic_read_0);
 int dsi_vc_generic_read_1(struct omap_dss_device *dssdev, int channel, u8 param,
 		u8 *buf, int buflen)
 {
+	struct omap_dss_output *out = dssdev->output;
 	int r;
 
-	r = dsi_vc_generic_read(dssdev, channel, &param, 1, buf, buflen);
+	r = dsi_vc_generic_read(out, channel, &param, 1, buf, buflen);
 	if (r) {
 		DSSERR("dsi_vc_generic_read_1(ch %d) failed\n", channel);
 		return r;
@@ -3383,13 +3397,14 @@ EXPORT_SYMBOL(dsi_vc_generic_read_1);
 int dsi_vc_generic_read_2(struct omap_dss_device *dssdev, int channel,
 		u8 param1, u8 param2, u8 *buf, int buflen)
 {
+	struct omap_dss_output *out = dssdev->output;
 	int r;
 	u8 reqdata[2];
 
 	reqdata[0] = param1;
 	reqdata[1] = param2;
 
-	r = dsi_vc_generic_read(dssdev, channel, reqdata, 2, buf, buflen);
+	r = dsi_vc_generic_read(out, channel, reqdata, 2, buf, buflen);
 	if (r) {
 		DSSERR("dsi_vc_generic_read_2(ch %d) failed\n", channel);
 		return r;
@@ -3402,7 +3417,8 @@ EXPORT_SYMBOL(dsi_vc_generic_read_2);
 int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int channel,
 		u16 len)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 
 	return dsi_vc_send_short(dsidev, channel,
 			MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, len, 0);
@@ -3738,10 +3754,11 @@ static int dsi_compute_interleave_lp(int blank, int enter_hs, int exit_hs,
 	return max(lp_inter, 0);
 }
 
-static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
+static void dsi_config_cmd_mode_interleaving(struct omap_dss_output *out)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+	struct omap_dss_device *dssdev = out->device;
 	int blanking_mode;
 	int hfp_blanking_mode, hbp_blanking_mode, hsa_blanking_mode;
 	int hsa, hfp, hbp, width_bytes, bllp, lp_clk_div;
@@ -3856,9 +3873,9 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
 	dsi_write_reg(dsidev, DSI_VM_TIMING6, r);
 }
 
-static int dsi_proto_config(struct omap_dss_device *dssdev)
+static int dsi_proto_config(struct omap_dss_output *out)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 	u32 r;
 	int buswidth = 0;
@@ -3916,7 +3933,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
 	if (dsi->mode = OMAP_DSS_DSI_VIDEO_MODE) {
 		dsi_config_vp_sync_events(dsidev);
 		dsi_config_blanking_modes(dsidev);
-		dsi_config_cmd_mode_interleaving(dssdev);
+		dsi_config_cmd_mode_interleaving(out);
 	}
 
 	dsi_vc_initial_config(dsidev, 0);
@@ -4042,7 +4059,8 @@ static void dsi_proto_timings(struct platform_device *dsidev)
 int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev,
 		const struct omap_dsi_pin_config *pin_cfg)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 	int num_pins;
 	const int *pins;
@@ -4109,7 +4127,8 @@ EXPORT_SYMBOL(omapdss_dsi_configure_pins);
 
 int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 	int bpp = dsi_get_pixel_size(dsi->pix_fmt);
 	u8 data_type;
@@ -4150,7 +4169,7 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
 		dsi_if_enable(dsidev, true);
 	}
 
-	r = dss_mgr_enable(dssdev->manager);
+	r = dss_mgr_enable(out->manager);
 	if (r) {
 		if (dsi->mode = OMAP_DSS_DSI_VIDEO_MODE) {
 			dsi_if_enable(dsidev, false);
@@ -4166,7 +4185,8 @@ EXPORT_SYMBOL(dsi_enable_video_output);
 
 void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
 	if (dsi->mode = OMAP_DSS_DSI_VIDEO_MODE) {
@@ -4180,13 +4200,13 @@ void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel)
 		dsi_if_enable(dsidev, true);
 	}
 
-	dss_mgr_disable(dssdev->manager);
+	dss_mgr_disable(out->manager);
 }
 EXPORT_SYMBOL(dsi_disable_video_output);
 
-static void dsi_update_screen_dispc(struct omap_dss_device *dssdev)
+static void dsi_update_screen_dispc(struct omap_dss_output *out)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 	unsigned bytespp;
 	unsigned bytespl;
@@ -4249,9 +4269,9 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev)
 		msecs_to_jiffies(250));
 	BUG_ON(r = 0);
 
-	dss_mgr_set_timings(dssdev->manager, &dsi->timings);
+	dss_mgr_set_timings(out->manager, &dsi->timings);
 
-	dss_mgr_start_update(dssdev->manager);
+	dss_mgr_start_update(out->manager);
 
 	if (dsi->te_enabled) {
 		/* disable LP_RX_TO, so that we can receive TE.  Time to wait
@@ -4325,7 +4345,8 @@ static void dsi_framedone_irq_callback(void *data, u32 mask)
 int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
 		void (*callback)(int, void *), void *data)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 	u16 dw, dh;
 
@@ -4343,7 +4364,7 @@ int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
 	dsi->update_bytes = dw * dh *
 		dsi_get_pixel_size(dsi->pix_fmt) / 8;
 #endif
-	dsi_update_screen_dispc(dssdev);
+	dsi_update_screen_dispc(out);
 
 	return 0;
 }
@@ -4351,10 +4372,11 @@ EXPORT_SYMBOL(omap_dsi_update);
 
 /* Display funcs */
 
-static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
+static int dsi_configure_dispc_clocks(struct omap_dss_output *out)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+	struct omap_dss_device *dssdev = out->device;
 	struct dispc_clock_info dispc_cinfo;
 	int r;
 	unsigned long long fck;
@@ -4375,10 +4397,11 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
 	return 0;
 }
 
-static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
+static int dsi_display_init_dispc(struct omap_dss_output *out)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+	struct omap_overlay_manager *mgr = out->manager;
 	int r;
 	u32 irq = 0;
 
@@ -4390,7 +4413,7 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
 		dsi->timings.vfp = 0;
 		dsi->timings.vbp = 0;
 
-		irq = dispc_mgr_get_framedone_irq(dssdev->manager->id);
+		irq = dispc_mgr_get_framedone_irq(mgr->id);
 
 		r = omap_dispc_register_isr(dsi_framedone_irq_callback,
 			(void *) dsidev, irq);
@@ -4417,9 +4440,9 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
 	dsi->timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
 	dsi->timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
 
-	dss_mgr_set_timings(dssdev->manager, &dsi->timings);
+	dss_mgr_set_timings(mgr, &dsi->timings);
 
-	r = dsi_configure_dispc_clocks(dssdev);
+	r = dsi_configure_dispc_clocks(out);
 	if (r)
 		goto err1;
 
@@ -4428,7 +4451,7 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
 			dsi_get_pixel_size(dsi->pix_fmt);
 	dsi->mgr_config.lcden_sig_polarity = 0;
 
-	dss_mgr_set_lcd_config(dssdev->manager, &dsi->mgr_config);
+	dss_mgr_set_lcd_config(mgr, &dsi->mgr_config);
 
 	return 0;
 err1:
@@ -4439,24 +4462,25 @@ err:
 	return r;
 }
 
-static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev)
+static void dsi_display_uninit_dispc(struct omap_dss_output *out)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
 	if (dsi->mode = OMAP_DSS_DSI_CMD_MODE) {
 		u32 irq;
 
-		irq = dispc_mgr_get_framedone_irq(dssdev->manager->id);
+		irq = dispc_mgr_get_framedone_irq(out->manager->id);
 
 		omap_dispc_unregister_isr(dsi_framedone_irq_callback,
 			(void *) dsidev, irq);
 	}
 }
 
-static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
+static int dsi_configure_dsi_clocks(struct omap_dss_output *out)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
+	struct omap_dss_device *dssdev = out->device;
 	struct dsi_clock_info cinfo;
 	int r;
 
@@ -4479,23 +4503,25 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
 	return 0;
 }
 
-static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
+static int dsi_display_init_dsi(struct omap_dss_output *out)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+	struct omap_overlay_manager *mgr = out->manager;
+	struct omap_dss_device *dssdev = out->device;
 	int r;
 
 	r = dsi_pll_init(dsidev, true, true);
 	if (r)
 		goto err0;
 
-	r = dsi_configure_dsi_clocks(dssdev);
+	r = dsi_configure_dsi_clocks(out);
 	if (r)
 		goto err1;
 
 	dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
 	dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src);
-	dss_select_lcd_clk_source(dssdev->manager->id,
+	dss_select_lcd_clk_source(out->manager->id,
 			dssdev->clocks.dispc.channel.lcd_clk_src);
 
 	DSSDBG("PLL OK\n");
@@ -4507,12 +4533,12 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
 	_dsi_print_reset_status(dsidev);
 
 	dsi_proto_timings(dsidev);
-	dsi_set_lp_clk_divisor(dssdev);
+	dsi_set_lp_clk_divisor(out);
 
 	if (1)
 		_dsi_print_reset_status(dsidev);
 
-	r = dsi_proto_config(dssdev);
+	r = dsi_proto_config(out);
 	if (r)
 		goto err3;
 
@@ -4530,7 +4556,7 @@ err3:
 err2:
 	dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
 	dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
-	dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK);
+	dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
 
 err1:
 	dsi_pll_uninit(dsidev, true);
@@ -4538,11 +4564,12 @@ err0:
 	return r;
 }
 
-static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
+static void dsi_display_uninit_dsi(struct omap_dss_output *out,
 		bool disconnect_lanes, bool enter_ulps)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+	struct omap_overlay_manager *mgr = out->manager;
 
 	if (enter_ulps && !dsi->ulps_enabled)
 		dsi_enter_ulps(dsidev);
@@ -4556,29 +4583,33 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
 
 	dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
 	dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
-	dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK);
+	dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
 	dsi_cio_uninit(dsidev);
 	dsi_pll_uninit(dsidev, disconnect_lanes);
 }
 
 int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
-	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev;
+	struct dsi_data *dsi;
 	int r = 0;
 
 	DSSDBG("dsi_display_enable\n");
 
+	if (out = NULL || out->manager = NULL) {
+		DSSERR("failed to enable display: no output/manager\n");
+		r = -ENODEV;
+		goto err_no_out_mgr;
+	}
+
+	dsidev = dsi_get_dsidev_from_output(out);
+	dsi = dsi_get_dsidrv_data(dsidev);
+
 	WARN_ON(!dsi_bus_is_locked(dsidev));
 
 	mutex_lock(&dsi->lock);
 
-	if (dssdev->manager = NULL) {
-		DSSERR("failed to enable display: no manager\n");
-		r = -ENODEV;
-		goto err_start_dev;
-	}
-
 	r = omap_dss_start_device(dssdev);
 	if (r) {
 		DSSERR("failed to start device\n");
@@ -4593,11 +4624,11 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
 
 	_dsi_initialize_irq(dsidev);
 
-	r = dsi_display_init_dispc(dssdev);
+	r = dsi_display_init_dispc(out);
 	if (r)
 		goto err_init_dispc;
 
-	r = dsi_display_init_dsi(dssdev);
+	r = dsi_display_init_dsi(out);
 	if (r)
 		goto err_init_dsi;
 
@@ -4606,7 +4637,7 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
 	return 0;
 
 err_init_dsi:
-	dsi_display_uninit_dispc(dssdev);
+	dsi_display_uninit_dispc(out);
 err_init_dispc:
 	dsi_enable_pll_clock(dsidev, 0);
 	dsi_runtime_put(dsidev);
@@ -4614,6 +4645,7 @@ err_get_dsi:
 	omap_dss_stop_device(dssdev);
 err_start_dev:
 	mutex_unlock(&dsi->lock);
+err_no_out_mgr:
 	DSSDBG("dsi_display_enable FAILED\n");
 	return r;
 }
@@ -4622,7 +4654,8 @@ EXPORT_SYMBOL(omapdss_dsi_display_enable);
 void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
 		bool disconnect_lanes, bool enter_ulps)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
 	DSSDBG("dsi_display_disable\n");
@@ -4636,9 +4669,9 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
 	dsi_sync_vc(dsidev, 2);
 	dsi_sync_vc(dsidev, 3);
 
-	dsi_display_uninit_dispc(dssdev);
+	dsi_display_uninit_dispc(out);
 
-	dsi_display_uninit_dsi(dssdev, disconnect_lanes, enter_ulps);
+	dsi_display_uninit_dsi(out, disconnect_lanes, enter_ulps);
 
 	dsi_runtime_put(dsidev);
 	dsi_enable_pll_clock(dsidev, 0);
@@ -4651,7 +4684,8 @@ EXPORT_SYMBOL(omapdss_dsi_display_disable);
 
 int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
 	dsi->te_enabled = enable;
@@ -4662,7 +4696,8 @@ EXPORT_SYMBOL(omapdss_dsi_enable_te);
 void omapdss_dsi_set_timings(struct omap_dss_device *dssdev,
 		struct omap_video_timings *timings)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
 	mutex_lock(&dsi->lock);
@@ -4675,7 +4710,8 @@ EXPORT_SYMBOL(omapdss_dsi_set_timings);
 
 void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
 	mutex_lock(&dsi->lock);
@@ -4690,7 +4726,8 @@ EXPORT_SYMBOL(omapdss_dsi_set_size);
 void omapdss_dsi_set_pixel_format(struct omap_dss_device *dssdev,
 		enum omap_dss_dsi_pixel_format fmt)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
 	mutex_lock(&dsi->lock);
@@ -4704,7 +4741,8 @@ EXPORT_SYMBOL(omapdss_dsi_set_pixel_format);
 void omapdss_dsi_set_operation_mode(struct omap_dss_device *dssdev,
 		enum omap_dss_dsi_mode mode)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
 	mutex_lock(&dsi->lock);
@@ -4718,7 +4756,8 @@ EXPORT_SYMBOL(omapdss_dsi_set_operation_mode);
 void omapdss_dsi_set_videomode_timings(struct omap_dss_device *dssdev,
 		struct omap_dss_dsi_videomode_timings *timings)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
 	mutex_lock(&dsi->lock);
@@ -4731,7 +4770,8 @@ EXPORT_SYMBOL(omapdss_dsi_set_videomode_timings);
 
 static int __init dsi_init_display(struct omap_dss_device *dssdev)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct platform_device *dsidev +			dsi_get_dsidev_from_id(dssdev->phy.dsi.module);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
 	DSSDBG("DSI init\n");
@@ -4759,7 +4799,8 @@ static int __init dsi_init_display(struct omap_dss_device *dssdev)
 
 int omap_dsi_request_vc(struct omap_dss_device *dssdev, int *channel)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 	int i;
 
@@ -4778,7 +4819,8 @@ EXPORT_SYMBOL(omap_dsi_request_vc);
 
 int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
 	if (vc_id < 0 || vc_id > 3) {
@@ -4805,7 +4847,8 @@ EXPORT_SYMBOL(omap_dsi_set_vc_id);
 
 void omap_dsi_release_vc(struct omap_dss_device *dssdev, int channel)
 {
-	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+	struct omap_dss_output *out = dssdev->output;
+	struct platform_device *dsidev = dsi_get_dsidev_from_output(out);
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
 	if ((channel >= 0 && channel <= 3) &&
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 13/23] OMAPDSS: SDI: Pass omap_dss_output within the driver
From: Archit Taneja @ 2012-08-30 11:52 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: rob, linux-omap, linux-fbdev, Archit Taneja
In-Reply-To: <1346326845-16583-1-git-send-email-archit@ti.com>

When a panel driver calls a SDI function, it passes the omap_dss_device
pointer, this pointer currently propagates within the SDI driver to configure
the interface.

Extract the omap_dss_output pointer from omap_dss_device received from the panel
driver, pass the output pointer to SDI functions local to the driver to
configure the interface, these functions no longer need omap_dss_device since
the driver now maintains a copy of output parameters.

Replace dssdev->manager references with out->manager references as only these
will be valid later.

With the addition of outputs. There is a possibility that an omap_dss_device
isn't connected to an output, or a manager isn't connected to an output yet.
Ensure that the SDI interface functions proceed only if the output is non NULL.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/dss/sdi.c |   20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
index d8879f3..24f9ba0 100644
--- a/drivers/video/omap2/dss/sdi.c
+++ b/drivers/video/omap2/dss/sdi.c
@@ -40,7 +40,7 @@ static struct {
 	struct omap_dss_output output;
 } sdi;
 
-static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
+static void sdi_config_lcd_manager(struct omap_dss_output *out)
 {
 	sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
 
@@ -50,19 +50,20 @@ static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
 	sdi.mgr_config.video_port_width = 24;
 	sdi.mgr_config.lcden_sig_polarity = 1;
 
-	dss_mgr_set_lcd_config(dssdev->manager, &sdi.mgr_config);
+	dss_mgr_set_lcd_config(out->manager, &sdi.mgr_config);
 }
 
 int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
 {
+	struct omap_dss_output *out = dssdev->output;
 	struct omap_video_timings *t = &sdi.timings;
 	struct dss_clock_info dss_cinfo;
 	struct dispc_clock_info dispc_cinfo;
 	unsigned long pck;
 	int r;
 
-	if (dssdev->manager = NULL) {
-		DSSERR("failed to enable display: no manager\n");
+	if (out = NULL || out->manager = NULL) {
+		DSSERR("failed to enable display: no output/manager\n");
 		return -ENODEV;
 	}
 
@@ -100,14 +101,13 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
 		t->pixel_clock = pck;
 	}
 
-
-	dss_mgr_set_timings(dssdev->manager, t);
+	dss_mgr_set_timings(out->manager, t);
 
 	r = dss_set_clock_div(&dss_cinfo);
 	if (r)
 		goto err_set_dss_clock_div;
 
-	sdi_config_lcd_manager(dssdev);
+	sdi_config_lcd_manager(out);
 
 	dss_sdi_init(sdi.datapairs);
 
@@ -116,7 +116,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
 		goto err_sdi_enable;
 	mdelay(2);
 
-	r = dss_mgr_enable(dssdev->manager);
+	r = dss_mgr_enable(out->manager);
 	if (r)
 		goto err_mgr_enable;
 
@@ -139,7 +139,9 @@ EXPORT_SYMBOL(omapdss_sdi_display_enable);
 
 void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
 {
-	dss_mgr_disable(dssdev->manager);
+	struct omap_dss_output *out = dssdev->output;
+
+	dss_mgr_disable(out->manager);
 
 	dss_sdi_disable();
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 14/23] OMAPDSS: RFBI: Pass omap_dss_output within the driver
From: Archit Taneja @ 2012-08-30 11:52 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: rob, linux-omap, linux-fbdev, Archit Taneja
In-Reply-To: <1346326845-16583-1-git-send-email-archit@ti.com>

When a panel driver calls a RFBI function, it passes the omap_dss_device
pointer, this pointer currently propagates within the RFBI driver to configure
the interface.

Extract the omap_dss_output pointer from omap_dss_device received from the panel
driver, pass the output pointer to RFBI functions local to the driver to
configure the interface, these functions no longer need omap_dss_device since
the driver now maintains a copy of output parameters.

Replace dssdev->manager references with out->manager references as only these
will be valid later.

With the addition of outputs. There is a possibility that an omap_dss_device
isn't connected to an output, or a manager isn't connected to an output yet.
Ensure that the RFBI interface functions proceed only if the output is non NULL.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/dss/rfbi.c |   24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c
index 3450f51..545e14f 100644
--- a/drivers/video/omap2/dss/rfbi.c
+++ b/drivers/video/omap2/dss/rfbi.c
@@ -307,11 +307,12 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
 }
 EXPORT_SYMBOL(omap_rfbi_write_pixels);
 
-static int rfbi_transfer_area(struct omap_dss_device *dssdev,
+static int rfbi_transfer_area(struct omap_dss_output *out,
 		void (*callback)(void *data), void *data)
 {
 	u32 l;
 	int r;
+	struct omap_overlay_manager *mgr = out->manager;
 	u16 width = rfbi.timings.x_res;
 	u16 height = rfbi.timings.y_res;
 
@@ -320,9 +321,9 @@ static int rfbi_transfer_area(struct omap_dss_device *dssdev,
 
 	DSSDBG("rfbi_transfer_area %dx%d\n", width, height);
 
-	dss_mgr_set_timings(dssdev->manager, &rfbi.timings);
+	dss_mgr_set_timings(mgr, &rfbi.timings);
 
-	r = dss_mgr_enable(dssdev->manager);
+	r = dss_mgr_enable(mgr);
 	if (r)
 		return r;
 
@@ -779,7 +780,9 @@ EXPORT_SYMBOL(omap_rfbi_configure);
 int omap_rfbi_update(struct omap_dss_device *dssdev, void (*callback)(void *),
 		void *data)
 {
-	return rfbi_transfer_area(dssdev, callback, data);
+	struct omap_dss_output *out = dssdev->output;
+
+	return rfbi_transfer_area(out, callback, data);
 }
 EXPORT_SYMBOL(omap_rfbi_update);
 
@@ -849,7 +852,7 @@ static void rfbi_dump_regs(struct seq_file *s)
 #undef DUMPREG
 }
 
-static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev)
+static void rfbi_config_lcd_manager(struct omap_dss_output *out)
 {
 	struct dss_lcd_mgr_config mgr_config;
 
@@ -862,7 +865,7 @@ static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev)
 	mgr_config.video_port_width = rfbi.pixel_size;
 	mgr_config.lcden_sig_polarity = 0;
 
-	dss_mgr_set_lcd_config(dssdev->manager, &mgr_config);
+	dss_mgr_set_lcd_config(out->manager, &mgr_config);
 
 	/*
 	 * Set rfbi.timings with default values, the x_res and y_res fields
@@ -883,15 +886,16 @@ static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev)
 	rfbi.timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
 	rfbi.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
 
-	dss_mgr_set_timings(dssdev->manager, &rfbi.timings);
+	dss_mgr_set_timings(out->manager, &rfbi.timings);
 }
 
 int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
 {
+	struct omap_dss_output *out = dssdev->output;
 	int r;
 
-	if (dssdev->manager = NULL) {
-		DSSERR("failed to enable display: no manager\n");
+	if (out = NULL || out->manager = NULL) {
+		DSSERR("failed to enable display: no output/manager\n");
 		return -ENODEV;
 	}
 
@@ -912,7 +916,7 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
 		goto err1;
 	}
 
-	rfbi_config_lcd_manager(dssdev);
+	rfbi_config_lcd_manager(out);
 
 	rfbi_configure(dssdev->phy.rfbi.channel, rfbi.pixel_size,
 			rfbi.data_lines);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 15/23] OMAPDSS: RFBI: Add dssdev pointers as arguments to all exported functions
From: Archit Taneja @ 2012-08-30 11:52 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: rob, linux-omap, linux-fbdev, Archit Taneja
In-Reply-To: <1346326845-16583-1-git-send-email-archit@ti.com>

All functions of an interface driver used by a panel driver should have an
omap_dss_device pointer as an argument. This may not be needed by some of the
interfaces now as driver data is globally visible in them. The correct way
to retrieve driver data is to extract the platform device from the output,
and then extract the driver data from the platform device.

Add dssdev arguments from functions used by panel drivers which currently miss
it. This will come to use when the RFBI functions retrieve the driver data
in the correct manner.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/displays/panel-n8x0.c |   55 ++++++++++++++++-------------
 drivers/video/omap2/dss/rfbi.c            |   25 +++++++------
 include/video/omapdss.h                   |   25 +++++++------
 3 files changed, 60 insertions(+), 45 deletions(-)

diff --git a/drivers/video/omap2/displays/panel-n8x0.c b/drivers/video/omap2/displays/panel-n8x0.c
index 17ae85e..e3a8c44 100644
--- a/drivers/video/omap2/displays/panel-n8x0.c
+++ b/drivers/video/omap2/displays/panel-n8x0.c
@@ -88,27 +88,30 @@ struct panel_drv_data *get_drv_data(const struct omap_dss_device *dssdev)
 }
 
 
-static inline void blizzard_cmd(u8 cmd)
+static inline void blizzard_cmd(struct omap_dss_device *dssdev, u8 cmd)
 {
-	omap_rfbi_write_command(&cmd, 1);
+	omap_rfbi_write_command(dssdev, &cmd, 1);
 }
 
-static inline void blizzard_write(u8 cmd, const u8 *buf, int len)
+static inline void blizzard_write(struct omap_dss_device *dssdev, u8 cmd,
+		const u8 *buf, int len)
 {
-	omap_rfbi_write_command(&cmd, 1);
-	omap_rfbi_write_data(buf, len);
+	omap_rfbi_write_command(dssdev, &cmd, 1);
+	omap_rfbi_write_data(dssdev, buf, len);
 }
 
-static inline void blizzard_read(u8 cmd, u8 *buf, int len)
+static inline void blizzard_read(struct omap_dss_device *dssdev, u8 cmd,
+		u8 *buf, int len)
 {
-	omap_rfbi_write_command(&cmd, 1);
-	omap_rfbi_read_data(buf, len);
+	omap_rfbi_write_command(dssdev, &cmd, 1);
+	omap_rfbi_read_data(dssdev, buf, len);
 }
 
-static u8 blizzard_read_reg(u8 cmd)
+static u8 blizzard_read_reg(struct omap_dss_device *dssdev, u8 cmd)
 {
 	u8 data;
-	blizzard_read(cmd, &data, 1);
+
+	blizzard_read(dssdev, cmd, &data, 1);
 	return data;
 }
 
@@ -155,7 +158,7 @@ static void blizzard_ctrl_setup_update(struct omap_dss_device *dssdev,
 
 	omap_rfbi_configure(dssdev);
 
-	blizzard_write(BLIZZARD_INPUT_WIN_X_START_0, tmp, 18);
+	blizzard_write(dssdev, BLIZZARD_INPUT_WIN_X_START_0, tmp, 18);
 
 	omapdss_rfbi_set_pixel_size(dssdev, 16);
 	omapdss_rfbi_set_data_lines(dssdev, 16);
@@ -313,8 +316,8 @@ static int n8x0_panel_power_on(struct omap_dss_device *dssdev)
 	if (r)
 		goto err_rfbi_en;
 
-	rev = blizzard_read_reg(BLIZZARD_REV_CODE);
-	conf = blizzard_read_reg(BLIZZARD_CONFIG);
+	rev = blizzard_read_reg(dssdev, BLIZZARD_REV_CODE);
+	conf = blizzard_read_reg(dssdev, BLIZZARD_CONFIG);
 
 	switch (rev & 0xfc) {
 	case 0x9c:
@@ -536,11 +539,11 @@ static int n8x0_panel_enable(struct omap_dss_device *dssdev)
 
 	mutex_lock(&ddata->lock);
 
-	rfbi_bus_lock();
+	rfbi_bus_lock(dssdev);
 
 	r = n8x0_panel_power_on(dssdev);
 
-	rfbi_bus_unlock();
+	rfbi_bus_unlock(dssdev);
 
 	if (r) {
 		mutex_unlock(&ddata->lock);
@@ -562,11 +565,11 @@ static void n8x0_panel_disable(struct omap_dss_device *dssdev)
 
 	mutex_lock(&ddata->lock);
 
-	rfbi_bus_lock();
+	rfbi_bus_lock(dssdev);
 
 	n8x0_panel_power_off(dssdev);
 
-	rfbi_bus_unlock();
+	rfbi_bus_unlock(dssdev);
 
 	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 
@@ -581,11 +584,11 @@ static int n8x0_panel_suspend(struct omap_dss_device *dssdev)
 
 	mutex_lock(&ddata->lock);
 
-	rfbi_bus_lock();
+	rfbi_bus_lock(dssdev);
 
 	n8x0_panel_power_off(dssdev);
 
-	rfbi_bus_unlock();
+	rfbi_bus_unlock(dssdev);
 
 	dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
 
@@ -603,11 +606,11 @@ static int n8x0_panel_resume(struct omap_dss_device *dssdev)
 
 	mutex_lock(&ddata->lock);
 
-	rfbi_bus_lock();
+	rfbi_bus_lock(dssdev);
 
 	r = n8x0_panel_power_on(dssdev);
 
-	rfbi_bus_unlock();
+	rfbi_bus_unlock(dssdev);
 
 	if (r) {
 		mutex_unlock(&ddata->lock);
@@ -630,7 +633,9 @@ static void n8x0_panel_get_resolution(struct omap_dss_device *dssdev,
 
 static void update_done(void *data)
 {
-	rfbi_bus_unlock();
+	struct omap_dss_device *dssdev = (struct omap_dss_device *) data;
+
+	rfbi_bus_unlock(dssdev);
 }
 
 static int n8x0_panel_update(struct omap_dss_device *dssdev,
@@ -651,7 +656,7 @@ static int n8x0_panel_update(struct omap_dss_device *dssdev,
 	}
 
 	mutex_lock(&ddata->lock);
-	rfbi_bus_lock();
+	rfbi_bus_lock(dssdev);
 
 	blizzard_ctrl_setup_update(dssdev, x, y, w, h);
 
@@ -669,8 +674,8 @@ static int n8x0_panel_sync(struct omap_dss_device *dssdev)
 	dev_dbg(&dssdev->dev, "sync\n");
 
 	mutex_lock(&ddata->lock);
-	rfbi_bus_lock();
-	rfbi_bus_unlock();
+	rfbi_bus_lock(dssdev);
+	rfbi_bus_unlock(dssdev);
 	mutex_unlock(&ddata->lock);
 
 	return 0;
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c
index 545e14f..b9d5b96 100644
--- a/drivers/video/omap2/dss/rfbi.c
+++ b/drivers/video/omap2/dss/rfbi.c
@@ -151,19 +151,20 @@ static void rfbi_runtime_put(void)
 	WARN_ON(r < 0 && r != -ENOSYS);
 }
 
-void rfbi_bus_lock(void)
+void rfbi_bus_lock(struct omap_dss_device *dssdev)
 {
 	down(&rfbi.bus_lock);
 }
 EXPORT_SYMBOL(rfbi_bus_lock);
 
-void rfbi_bus_unlock(void)
+void rfbi_bus_unlock(struct omap_dss_device *dssdev)
 {
 	up(&rfbi.bus_lock);
 }
 EXPORT_SYMBOL(rfbi_bus_unlock);
 
-void omap_rfbi_write_command(const void *buf, u32 len)
+void omap_rfbi_write_command(struct omap_dss_device *dssdev, const void *buf,
+		u32 len)
 {
 	switch (rfbi.parallelmode) {
 	case OMAP_DSS_RFBI_PARALLELMODE_8:
@@ -191,7 +192,7 @@ void omap_rfbi_write_command(const void *buf, u32 len)
 }
 EXPORT_SYMBOL(omap_rfbi_write_command);
 
-void omap_rfbi_read_data(void *buf, u32 len)
+void omap_rfbi_read_data(struct omap_dss_device *dssdev, void *buf, u32 len)
 {
 	switch (rfbi.parallelmode) {
 	case OMAP_DSS_RFBI_PARALLELMODE_8:
@@ -223,7 +224,8 @@ void omap_rfbi_read_data(void *buf, u32 len)
 }
 EXPORT_SYMBOL(omap_rfbi_read_data);
 
-void omap_rfbi_write_data(const void *buf, u32 len)
+void omap_rfbi_write_data(struct omap_dss_device *dssdev, const void *buf,
+		u32 len)
 {
 	switch (rfbi.parallelmode) {
 	case OMAP_DSS_RFBI_PARALLELMODE_8:
@@ -252,7 +254,8 @@ void omap_rfbi_write_data(const void *buf, u32 len)
 }
 EXPORT_SYMBOL(omap_rfbi_write_data);
 
-void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
+void omap_rfbi_write_pixels(struct omap_dss_device *dssdev,
+		const void __iomem *buf, int scr_width,
 		u16 x, u16 y,
 		u16 w, u16 h)
 {
@@ -574,9 +577,10 @@ static int rfbi_convert_timings(struct rfbi_timings *t)
 }
 
 /* xxx FIX module selection missing */
-int omap_rfbi_setup_te(enum omap_rfbi_te_mode mode,
-			     unsigned hs_pulse_time, unsigned vs_pulse_time,
-			     int hs_pol_inv, int vs_pol_inv, int extif_div)
+int omap_rfbi_setup_te(struct omap_dss_device *dssdev,
+			enum omap_rfbi_te_mode mode, unsigned hs_pulse_time,
+			unsigned vs_pulse_time, int hs_pol_inv, int vs_pol_inv,
+			int extif_div)
 {
 	int hs, vs;
 	int min;
@@ -616,7 +620,8 @@ int omap_rfbi_setup_te(enum omap_rfbi_te_mode mode,
 EXPORT_SYMBOL(omap_rfbi_setup_te);
 
 /* xxx FIX module selection missing */
-int omap_rfbi_enable_te(bool enable, unsigned line)
+int omap_rfbi_enable_te(struct omap_dss_device *dssdev, bool enable,
+		unsigned line)
 {
 	u32 l;
 
diff --git a/include/video/omapdss.h b/include/video/omapdss.h
index 29c1440..0e73ef8 100644
--- a/include/video/omapdss.h
+++ b/include/video/omapdss.h
@@ -238,18 +238,23 @@ struct rfbi_timings {
 	int converted;
 };
 
-void omap_rfbi_write_command(const void *buf, u32 len);
-void omap_rfbi_read_data(void *buf, u32 len);
-void omap_rfbi_write_data(const void *buf, u32 len);
-void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
+void omap_rfbi_write_command(struct omap_dss_device *dssdev, const void *buf,
+		u32 len);
+void omap_rfbi_read_data(struct omap_dss_device *dssdev, void *buf, u32 len);
+void omap_rfbi_write_data(struct omap_dss_device *dssdev, const void *buf,
+		u32 len);
+void omap_rfbi_write_pixels(struct omap_dss_device *dssdev,
+		const void __iomem *buf, int scr_width,
 		u16 x, u16 y,
 		u16 w, u16 h);
-int omap_rfbi_enable_te(bool enable, unsigned line);
-int omap_rfbi_setup_te(enum omap_rfbi_te_mode mode,
-			     unsigned hs_pulse_time, unsigned vs_pulse_time,
-			     int hs_pol_inv, int vs_pol_inv, int extif_div);
-void rfbi_bus_lock(void);
-void rfbi_bus_unlock(void);
+int omap_rfbi_enable_te(struct omap_dss_device *dssdev, bool enable,
+		unsigned line);
+int omap_rfbi_setup_te(struct omap_dss_device *dssdev,
+			enum omap_rfbi_te_mode mode, unsigned hs_pulse_time,
+			unsigned vs_pulse_time, int hs_pol_inv, int vs_pol_inv,
+			int extif_div);
+void rfbi_bus_lock(struct omap_dss_device *dssdev);
+void rfbi_bus_unlock(struct omap_dss_device *dssdev);
 
 /* DSI */
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 16/23] OMAPDSS: VENC: Pass omap_dss_output within the driver
From: Archit Taneja @ 2012-08-30 11:52 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: rob, linux-omap, linux-fbdev, Archit Taneja
In-Reply-To: <1346326845-16583-1-git-send-email-archit@ti.com>

When a panel driver calls a VENC function, it passes the omap_dss_device
pointer, this pointer currently propagates within the VENC driver to configure
the interface.

Extract the omap_dss_output pointer from omap_dss_device received from the panel
driver, pass the output pointer to VENC functions local to the driver to
configure the interface, these functions no longer need omap_dss_device since
the driver now maintains a copy of output parameters.

Replace dssdev->manager references with out->manager references as only these
will be valid later.

With the addition of outputs. There is a possibility that an omap_dss_device
isn't connected to an output, or a manager isn't connected to an output yet.
Ensure that the VENC interface functions proceed only if the output is non NULL.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/dss/venc.c |   32 ++++++++++++++++++++------------
 1 file changed, 20 insertions(+), 12 deletions(-)

diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index 942a378..3fe974f 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -428,7 +428,7 @@ static const struct venc_config *venc_timings_to_config(
 	return NULL;
 }
 
-static int venc_power_on(struct omap_dss_device *dssdev)
+static int venc_power_on(struct omap_dss_output *out)
 {
 	u32 l;
 	int r;
@@ -455,13 +455,13 @@ static int venc_power_on(struct omap_dss_device *dssdev)
 
 	venc_write_reg(VENC_OUTPUT_CONTROL, l);
 
-	dss_mgr_set_timings(dssdev->manager, &venc.timings);
+	dss_mgr_set_timings(out->manager, &venc.timings);
 
 	r = regulator_enable(venc.vdda_dac_reg);
 	if (r)
 		goto err1;
 
-	r = dss_mgr_enable(dssdev->manager);
+	r = dss_mgr_enable(out->manager);
 	if (r)
 		goto err2;
 
@@ -478,12 +478,12 @@ err0:
 	return r;
 }
 
-static void venc_power_off(struct omap_dss_device *dssdev)
+static void venc_power_off(struct omap_dss_output *out)
 {
 	venc_write_reg(VENC_OUTPUT_CONTROL, 0);
 	dss_set_dac_pwrdn_bgz(0);
 
-	dss_mgr_disable(dssdev->manager);
+	dss_mgr_disable(out->manager);
 
 	regulator_disable(venc.vdda_dac_reg);
 
@@ -498,14 +498,15 @@ unsigned long venc_get_pixel_clock(void)
 
 int omapdss_venc_display_enable(struct omap_dss_device *dssdev)
 {
+	struct omap_dss_output *out = dssdev->output;
 	int r;
 
 	DSSDBG("venc_display_enable\n");
 
 	mutex_lock(&venc.venc_lock);
 
-	if (dssdev->manager = NULL) {
-		DSSERR("Failed to enable display: no manager\n");
+	if (out = NULL || out->manager = NULL) {
+		DSSERR("Failed to enable display: no output/manager\n");
 		r = -ENODEV;
 		goto err0;
 	}
@@ -520,7 +521,7 @@ int omapdss_venc_display_enable(struct omap_dss_device *dssdev)
 		dssdev->platform_enable(dssdev);
 
 
-	r = venc_power_on(dssdev);
+	r = venc_power_on(out);
 	if (r)
 		goto err1;
 
@@ -540,11 +541,13 @@ err0:
 
 void omapdss_venc_display_disable(struct omap_dss_device *dssdev)
 {
+	struct omap_dss_output *out = dssdev->output;
+
 	DSSDBG("venc_display_disable\n");
 
 	mutex_lock(&venc.venc_lock);
 
-	venc_power_off(dssdev);
+	venc_power_off(out);
 
 	omap_dss_stop_device(dssdev);
 
@@ -557,8 +560,13 @@ void omapdss_venc_display_disable(struct omap_dss_device *dssdev)
 void omapdss_venc_set_timings(struct omap_dss_device *dssdev,
 		struct omap_video_timings *timings)
 {
+	struct omap_dss_output *out = dssdev->output;
+
 	DSSDBG("venc_set_timings\n");
 
+	if (out = NULL)
+		return;
+
 	mutex_lock(&venc.venc_lock);
 
 	/* Reset WSS data when the TV standard changes. */
@@ -571,13 +579,13 @@ void omapdss_venc_set_timings(struct omap_dss_device *dssdev,
 		int r;
 
 		/* turn the venc off and on to get new timings to use */
-		venc_power_off(dssdev);
+		venc_power_off(out);
 
-		r = venc_power_on(dssdev);
+		r = venc_power_on(out);
 		if (r)
 			DSSERR("failed to power on VENC\n");
 	} else {
-		dss_mgr_set_timings(dssdev->manager, timings);
+		dss_mgr_set_timings(out->manager, timings);
 	}
 
 	mutex_unlock(&venc.venc_lock);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 17/23] OMAPDSS: HDMI: Pass omap_dss_output within the driver
From: Archit Taneja @ 2012-08-30 11:52 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: rob, linux-omap, linux-fbdev, Archit Taneja
In-Reply-To: <1346326845-16583-1-git-send-email-archit@ti.com>

When a panel driver calls a HDMI function, it passes the omap_dss_device
pointer, this pointer currently propagates within the HDMI driver to configure
the interface.

Extract the omap_dss_output pointer from omap_dss_device received from the panel
driver, pass the output pointer to HDMI functions local to the driver to
configure the interface, these functions no longer need omap_dss_device since
the driver now maintains a copy of output parameters.

Replace dssdev->manager references with out->manager references as only these
will be valid later.

With the addition of outputs. There is a possibility that an omap_dss_device
isn't connected to an output, or a manager isn't connected to an output yet.
Ensure that the HDMI interface functions proceed only if the output is non NULL.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/dss/hdmi.c |   40 ++++++++++++++++++++++++----------------
 1 file changed, 24 insertions(+), 16 deletions(-)

diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index d93954d..3c89904 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -407,9 +407,10 @@ unsigned long hdmi_get_pixel_clock(void)
 	return hdmi.ip_data.cfg.timings.pixel_clock * 1000;
 }
 
-static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
+static void hdmi_compute_pll(struct omap_dss_output *out, int phy,
 		struct hdmi_pll_info *pi)
 {
+	struct omap_dss_device *dssdev = out->device;
 	unsigned long clkin, refclk;
 	u32 mf;
 
@@ -458,7 +459,7 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
 	DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
 }
 
-static int hdmi_power_on(struct omap_dss_device *dssdev)
+static int hdmi_power_on(struct omap_dss_output *out)
 {
 	int r;
 	struct omap_video_timings *p;
@@ -468,7 +469,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
 	if (r)
 		return r;
 
-	dss_mgr_disable(dssdev->manager);
+	dss_mgr_disable(out->manager);
 
 	p = &hdmi.ip_data.cfg.timings;
 
@@ -476,7 +477,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
 
 	phy = p->pixel_clock;
 
-	hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data);
+	hdmi_compute_pll(out, phy, &hdmi.ip_data.pll_data);
 
 	hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
 
@@ -504,19 +505,19 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
 	 * dynamically by user. This can be moved to single location , say
 	 * Boardfile.
 	 */
-	dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
+	dss_select_dispc_clk_source(out->device->clocks.dispc.dispc_fclk_src);
 
 	/* bypass TV gamma table */
 	dispc_enable_gamma_table(0);
 
 	/* tv size */
-	dss_mgr_set_timings(dssdev->manager, p);
+	dss_mgr_set_timings(out->manager, p);
 
 	r = hdmi.ip_data.ops->video_enable(&hdmi.ip_data);
 	if (r)
 		goto err_vid_enable;
 
-	r = dss_mgr_enable(dssdev->manager);
+	r = dss_mgr_enable(out->manager);
 	if (r)
 		goto err_mgr_enable;
 
@@ -533,9 +534,9 @@ err:
 	return -EIO;
 }
 
-static void hdmi_power_off(struct omap_dss_device *dssdev)
+static void hdmi_power_off(struct omap_dss_output *out)
 {
-	dss_mgr_disable(dssdev->manager);
+	dss_mgr_disable(out->manager);
 
 	hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
 	hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
@@ -560,9 +561,13 @@ int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
 void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev,
 		struct omap_video_timings *timings)
 {
+	struct omap_dss_output *out = dssdev->output;
 	struct hdmi_cm cm;
 	const struct hdmi_config *t;
 
+	if (out = NULL)
+		return;
+
 	mutex_lock(&hdmi.lock);
 
 	cm = hdmi_get_code(timings);
@@ -575,13 +580,13 @@ void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev,
 	if (dssdev->state = OMAP_DSS_DISPLAY_ACTIVE) {
 		int r;
 
-		hdmi_power_off(dssdev);
+		hdmi_power_off(out);
 
-		r = hdmi_power_on(dssdev);
+		r = hdmi_power_on(out);
 		if (r)
 			DSSERR("failed to power on device\n");
 	} else {
-		dss_mgr_set_timings(dssdev->manager, &t->timings);
+		dss_mgr_set_timings(out->manager, &t->timings);
 	}
 
 	mutex_unlock(&hdmi.lock);
@@ -640,14 +645,15 @@ bool omapdss_hdmi_detect(void)
 int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev)
 {
 	struct omap_dss_hdmi_data *priv = dssdev->data;
+	struct omap_dss_output *out = dssdev->output;
 	int r = 0;
 
 	DSSDBG("ENTER hdmi_display_enable\n");
 
 	mutex_lock(&hdmi.lock);
 
-	if (dssdev->manager = NULL) {
-		DSSERR("failed to enable display: no manager\n");
+	if (out = NULL || out->manager = NULL) {
+		DSSERR("failed to enable display: no output/manager\n");
 		r = -ENODEV;
 		goto err0;
 	}
@@ -668,7 +674,7 @@ int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev)
 		}
 	}
 
-	r = hdmi_power_on(dssdev);
+	r = hdmi_power_on(out);
 	if (r) {
 		DSSERR("failed to power on device\n");
 		goto err2;
@@ -689,11 +695,13 @@ err0:
 
 void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev)
 {
+	struct omap_dss_output *out = dssdev->output;
+
 	DSSDBG("Enter hdmi_display_disable\n");
 
 	mutex_lock(&hdmi.lock);
 
-	hdmi_power_off(dssdev);
+	hdmi_power_off(out);
 
 	if (dssdev->platform_disable)
 		dssdev->platform_disable(dssdev);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 18/23] OMAPDSS: HDMI: Add dssdev pointer as an argument to all functions used by hdmi pane
From: Archit Taneja @ 2012-08-30 11:52 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: rob, linux-omap, linux-fbdev, Archit Taneja
In-Reply-To: <1346326845-16583-1-git-send-email-archit@ti.com>

All functions of an output driver used by a panel driver should have an
omap_dss_device pointer as an argument. This is needed as the function would
somehow need to retrieve the output driver's private data. It may not be needed
by some of the outputs for now as driver data is globally visible within them.
The correct way to retrieve driver data is to extract the platform device from
the output, and then extract the driver data from the platform device.

Add dssdev arguments to functions used by panel drivers which currently miss it.
This will come to use when the HDMI functions retrieve the driver data in the
correct manner.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/dss/dss.h        |   17 +++++++++--------
 drivers/video/omap2/dss/hdmi.c       |   17 +++++++++--------
 drivers/video/omap2/dss/hdmi_panel.c |   20 ++++++++++----------
 3 files changed, 28 insertions(+), 26 deletions(-)

diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index de2fb9d..11c245d 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -506,17 +506,18 @@ void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev,
 		struct omap_video_timings *timings);
 int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
 					struct omap_video_timings *timings);
-int omapdss_hdmi_read_edid(u8 *buf, int len);
-bool omapdss_hdmi_detect(void);
+int omapdss_hdmi_read_edid(struct omap_dss_device *dssdev, u8 *buf, int len);
+bool omapdss_hdmi_detect(struct omap_dss_device *dssdev);
 int hdmi_panel_init(void);
 void hdmi_panel_exit(void);
 #ifdef CONFIG_OMAP4_DSS_HDMI_AUDIO
-int hdmi_audio_enable(void);
-void hdmi_audio_disable(void);
-int hdmi_audio_start(void);
-void hdmi_audio_stop(void);
-bool hdmi_mode_has_audio(void);
-int hdmi_audio_config(struct omap_dss_audio *audio);
+int hdmi_audio_enable(struct omap_dss_device *dssdev);
+void hdmi_audio_disable(struct omap_dss_device *dssdev);
+int hdmi_audio_start(struct omap_dss_device *dssdev);
+void hdmi_audio_stop(struct omap_dss_device *dssdev);
+bool hdmi_mode_has_audio(struct omap_dss_device *dssdev);
+int hdmi_audio_config(struct omap_dss_device *dssdev,
+		struct omap_dss_audio *audio);
 #endif
 
 /* RFBI */
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index 3c89904..2d3b959 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -608,7 +608,7 @@ static void hdmi_dump_regs(struct seq_file *s)
 	mutex_unlock(&hdmi.lock);
 }
 
-int omapdss_hdmi_read_edid(u8 *buf, int len)
+int omapdss_hdmi_read_edid(struct omap_dss_device *dssdev, u8 *buf, int len)
 {
 	int r;
 
@@ -625,7 +625,7 @@ int omapdss_hdmi_read_edid(u8 *buf, int len)
 	return r;
 }
 
-bool omapdss_hdmi_detect(void)
+bool omapdss_hdmi_detect(struct omap_dss_device *dssdev)
 {
 	int r;
 
@@ -833,35 +833,35 @@ int hdmi_compute_acr(u32 sample_freq, u32 *n, u32 *cts)
 	return 0;
 }
 
-int hdmi_audio_enable(void)
+int hdmi_audio_enable(struct omap_dss_device *dssdev)
 {
 	DSSDBG("audio_enable\n");
 
 	return hdmi.ip_data.ops->audio_enable(&hdmi.ip_data);
 }
 
-void hdmi_audio_disable(void)
+void hdmi_audio_disable(struct omap_dss_device *dssdev)
 {
 	DSSDBG("audio_disable\n");
 
 	hdmi.ip_data.ops->audio_disable(&hdmi.ip_data);
 }
 
-int hdmi_audio_start(void)
+int hdmi_audio_start(struct omap_dss_device *dssdev)
 {
 	DSSDBG("audio_start\n");
 
 	return hdmi.ip_data.ops->audio_start(&hdmi.ip_data);
 }
 
-void hdmi_audio_stop(void)
+void hdmi_audio_stop(struct omap_dss_device *dssdev)
 {
 	DSSDBG("audio_stop\n");
 
 	hdmi.ip_data.ops->audio_stop(&hdmi.ip_data);
 }
 
-bool hdmi_mode_has_audio(void)
+bool hdmi_mode_has_audio(struct omap_dss_device *dssdev)
 {
 	if (hdmi.ip_data.cfg.cm.mode = HDMI_HDMI)
 		return true;
@@ -869,7 +869,8 @@ bool hdmi_mode_has_audio(void)
 		return false;
 }
 
-int hdmi_audio_config(struct omap_dss_audio *audio)
+int hdmi_audio_config(struct omap_dss_device *dssdev,
+		struct omap_dss_audio *audio)
 {
 	return hdmi.ip_data.ops->audio_config(&hdmi.ip_data, audio);
 }
diff --git a/drivers/video/omap2/dss/hdmi_panel.c b/drivers/video/omap2/dss/hdmi_panel.c
index 69fb115..ef3fc86 100644
--- a/drivers/video/omap2/dss/hdmi_panel.c
+++ b/drivers/video/omap2/dss/hdmi_panel.c
@@ -88,13 +88,13 @@ static int hdmi_panel_audio_enable(struct omap_dss_device *dssdev)
 
 	/* enable audio only if the display is active and supports audio */
 	if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE ||
-	    !hdmi_mode_has_audio()) {
+	    !hdmi_mode_has_audio(dssdev)) {
 		DSSERR("audio not supported or display is off\n");
 		r = -EPERM;
 		goto err;
 	}
 
-	r = hdmi_audio_enable();
+	r = hdmi_audio_enable(dssdev);
 
 	if (!r)
 		dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED;
@@ -111,7 +111,7 @@ static void hdmi_panel_audio_disable(struct omap_dss_device *dssdev)
 
 	spin_lock_irqsave(&hdmi.audio_lock, flags);
 
-	hdmi_audio_disable();
+	hdmi_audio_disable(dssdev);
 
 	dssdev->audio_state = OMAP_DSS_AUDIO_DISABLED;
 
@@ -134,7 +134,7 @@ static int hdmi_panel_audio_start(struct omap_dss_device *dssdev)
 		goto err;
 	}
 
-	r = hdmi_audio_start();
+	r = hdmi_audio_start(dssdev);
 
 	if (!r)
 		dssdev->audio_state = OMAP_DSS_AUDIO_PLAYING;
@@ -150,7 +150,7 @@ static void hdmi_panel_audio_stop(struct omap_dss_device *dssdev)
 
 	spin_lock_irqsave(&hdmi.audio_lock, flags);
 
-	hdmi_audio_stop();
+	hdmi_audio_stop(dssdev);
 	dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED;
 
 	spin_unlock_irqrestore(&hdmi.audio_lock, flags);
@@ -165,7 +165,7 @@ static bool hdmi_panel_audio_supported(struct omap_dss_device *dssdev)
 	if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
 		goto err;
 
-	if (!hdmi_mode_has_audio())
+	if (!hdmi_mode_has_audio(dssdev))
 		goto err;
 
 	r = true;
@@ -185,13 +185,13 @@ static int hdmi_panel_audio_config(struct omap_dss_device *dssdev,
 
 	/* config audio only if the display is active and supports audio */
 	if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE ||
-	    !hdmi_mode_has_audio()) {
+	    !hdmi_mode_has_audio(dssdev)) {
 		DSSERR("audio not supported or display is off\n");
 		r = -EPERM;
 		goto err;
 	}
 
-	r = hdmi_audio_config(audio);
+	r = hdmi_audio_config(dssdev, audio);
 
 	if (!r)
 		dssdev->audio_state = OMAP_DSS_AUDIO_CONFIGURED;
@@ -388,7 +388,7 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *buf, int len)
 			goto err;
 	}
 
-	r = omapdss_hdmi_read_edid(buf, len);
+	r = omapdss_hdmi_read_edid(dssdev, buf, len);
 
 	if (dssdev->state = OMAP_DSS_DISPLAY_DISABLED ||
 			dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED)
@@ -411,7 +411,7 @@ static bool hdmi_detect(struct omap_dss_device *dssdev)
 			goto err;
 	}
 
-	r = omapdss_hdmi_detect();
+	r = omapdss_hdmi_detect(dssdev);
 
 	if (dssdev->state = OMAP_DSS_DISPLAY_DISABLED ||
 			dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED)
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 19/23] OMAPDSS/OMAPFB: Change dssdev->manager references
From: Archit Taneja @ 2012-08-30 11:52 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: rob, linux-omap, linux-fbdev, Archit Taneja
In-Reply-To: <1346326845-16583-1-git-send-email-archit@ti.com>

To retrieve the manager pointer via a device, we need to now access it via the
output to which the device is connected. Make this change in the places where
such a reference is made.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/dss/display.c         |   11 +++++++++--
 drivers/video/omap2/omapfb/omapfb-ioctl.c |    7 +++++--
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c
index 5bd957e..07fd1c7 100644
--- a/drivers/video/omap2/dss/display.c
+++ b/drivers/video/omap2/dss/display.c
@@ -349,8 +349,15 @@ void dss_uninit_device(struct platform_device *pdev,
 	while ((attr = display_sysfs_attrs[i++]) != NULL)
 		device_remove_file(&dssdev->dev, attr);
 
-	if (dssdev->manager)
-		dssdev->manager->unset_device(dssdev->manager);
+	if (dssdev->output) {
+		if (dssdev->output->manager) {
+			struct omap_overlay_manager *mgr +					dssdev->output->manager;
+
+			mgr->unset_output(mgr);
+		}
+		dssdev->output->unset_device(dssdev->output);
+	}
 }
 
 static int dss_suspend_device(struct device *dev, void *data)
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c
index c6cf372..606b89f 100644
--- a/drivers/video/omap2/omapfb/omapfb-ioctl.c
+++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c
@@ -599,6 +599,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
 	struct omapfb_info *ofbi = FB2OFB(fbi);
 	struct omapfb2_device *fbdev = ofbi->fbdev;
 	struct omap_dss_device *display = fb2display(fbi);
+	struct omap_overlay_manager *mgr;
 
 	union {
 		struct omapfb_update_window_old	uwnd_o;
@@ -786,12 +787,14 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
 
 	case OMAPFB_WAITFORVSYNC:
 		DBG("ioctl WAITFORVSYNC\n");
-		if (!display) {
+		if (!display && !display->output && !display->output->manager) {
 			r = -EINVAL;
 			break;
 		}
 
-		r = display->manager->wait_for_vsync(display->manager);
+		mgr = display->output->manager;
+
+		r = mgr->wait_for_vsync(mgr);
 		break;
 
 	case OMAPFB_WAITFORGO:
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 20/23] OMAPDSS: MANAGER: Update display sysfs store
From: Archit Taneja @ 2012-08-30 11:52 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: rob, linux-omap, linux-fbdev, Archit Taneja
In-Reply-To: <1346326845-16583-1-git-send-email-archit@ti.com>

The display sysfs attribute's store function needs to be changed with the
introduction of outputs.

Providing a manager to the display isn't enough to create a link now, the
manager needs and output to connect to. A manager's display store file only
has the information of the manager and the desired display, it is not aware
of which output should the manager connect to.

Because of this, a new constraint needs to be set up when setting a display via
this sysfs file. The constraint is that the desired display should already be
connected to an output before calling this sysfs function.

This might break some existing user space stuff which uses sysfs directly. But
in most cases dss_recheck_connections will connect displays to floating outputs.
DSS sysfs files are being planned to be remove anyway, so it's not much of a
harm.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/dss/manager.c |   25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
index fd39f66..d808ce2 100644
--- a/drivers/video/omap2/dss/manager.c
+++ b/drivers/video/omap2/dss/manager.c
@@ -74,18 +74,33 @@ static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
 	if (dssdev)
 		DSSDBG("display %s found\n", dssdev->name);
 
-	if (mgr->get_device(mgr)) {
-		r = mgr->unset_device(mgr);
+	if (mgr->output) {
+		if (mgr->output->device) {
+			r = mgr->output->unset_device(mgr->output);
+			if (r) {
+				goto put_device;
+				DSSERR("failed to unset device from output\n");
+			}
+		}
+
+		r = mgr->unset_output(mgr);
 		if (r) {
-			DSSERR("failed to unset display\n");
+			DSSERR("failed to unset current output\n");
 			goto put_device;
 		}
 	}
 
 	if (dssdev) {
-		r = mgr->set_device(mgr, dssdev);
+		struct omap_dss_output *out = dssdev->output;
+
+		if (!out) {
+			DSSERR("no output connected to device\n");
+			goto put_device;
+		}
+
+		r = mgr->set_output(mgr, out);
 		if (r) {
-			DSSERR("failed to set manager\n");
+			DSSERR("failed to set manager output\n");
 			goto put_device;
 		}
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 21/23] OMAPDSS: MANAGER: Get device via output
From: Archit Taneja @ 2012-08-30 11:52 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: rob, linux-omap, linux-fbdev, Archit Taneja
In-Reply-To: <1346326845-16583-1-git-send-email-archit@ti.com>

A manager is not connected to a device directly any more. It first connects
to an output, and then to the display. Update the manager's get_device op to
return the device via the connected output.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/dss/manager.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
index d808ce2..d14ffc5 100644
--- a/drivers/video/omap2/dss/manager.c
+++ b/drivers/video/omap2/dss/manager.c
@@ -509,7 +509,7 @@ static struct kobj_type manager_ktype = {
 
 static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr)
 {
-	return mgr->device;
+	return mgr->output ? mgr->output->device : NULL;
 }
 
 static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 22/23] OMAPDSS: APPLY: Remove omap_dss_device references from dss_ovl_enable/disable
From: Archit Taneja @ 2012-08-30 11:52 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: rob, linux-omap, linux-fbdev, Archit Taneja
In-Reply-To: <1346326845-16583-1-git-send-email-archit@ti.com>

An overlay isn't allowed to be enabled/disabled if it isn't connected to an
omap_dss_device. This requirement isn't needed any more. An overlay can be
enabled/disabled as long as it has an output connected to it. The output may
not be connected to a device, but we can be assured that the connected
manager's output is in use by an output interface.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/dss/apply.c |    6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c
index 8a05cbc..d584f0c 100644
--- a/drivers/video/omap2/dss/apply.c
+++ b/drivers/video/omap2/dss/apply.c
@@ -1607,8 +1607,7 @@ int dss_ovl_enable(struct omap_overlay *ovl)
 		goto err1;
 	}
 
-	if (ovl->manager = NULL ||
-			ovl->manager->get_device(ovl->manager) = NULL) {
+	if (ovl->manager = NULL || ovl->manager->output = NULL) {
 		r = -EINVAL;
 		goto err1;
 	}
@@ -1677,8 +1676,7 @@ int dss_ovl_disable(struct omap_overlay *ovl)
 		goto err;
 	}
 
-	if (ovl->manager = NULL ||
-			ovl->manager->get_device(ovl->manager) = NULL) {
+	if (ovl->manager = NULL || ovl->manager->output = NULL) {
 		r = -EINVAL;
 		goto err;
 	}
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 23/23] OMAPDSS: Remove old way of setting manager and device links
From: Archit Taneja @ 2012-08-30 11:52 UTC (permalink / raw)
  To: tomi.valkeinen; +Cc: rob, linux-omap, linux-fbdev, Archit Taneja
In-Reply-To: <1346326845-16583-1-git-send-email-archit@ti.com>

Now that an omap_dss_output can be used to link between managers and devices, we
can remove the old way of setting manager and device links. This involves
removing the device and manager pointers from omap_overlay_manager and
omap_dss_device respectively, and removing the set_device/unset_device ops from
omap_overlay_manager.

Signed-off-by: Archit Taneja <archit@ti.com>
---
 drivers/video/omap2/dss/apply.c   |   64 -------------------------------------
 drivers/video/omap2/dss/manager.c |    2 --
 include/video/omapdss.h           |    5 ---
 3 files changed, 71 deletions(-)

diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c
index d584f0c..0ae70ab 100644
--- a/drivers/video/omap2/dss/apply.c
+++ b/drivers/video/omap2/dss/apply.c
@@ -1247,70 +1247,6 @@ void dss_mgr_get_info(struct omap_overlay_manager *mgr,
 	spin_unlock_irqrestore(&data_lock, flags);
 }
 
-int dss_mgr_set_device(struct omap_overlay_manager *mgr,
-		struct omap_dss_device *dssdev)
-{
-	int r;
-
-	mutex_lock(&apply_lock);
-
-	if (dssdev->manager) {
-		DSSERR("display '%s' already has a manager '%s'\n",
-			       dssdev->name, dssdev->manager->name);
-		r = -EINVAL;
-		goto err;
-	}
-
-	if ((mgr->supported_displays & dssdev->type) = 0) {
-		DSSERR("display '%s' does not support manager '%s'\n",
-			       dssdev->name, mgr->name);
-		r = -EINVAL;
-		goto err;
-	}
-
-	dssdev->manager = mgr;
-	mgr->device = dssdev;
-
-	mutex_unlock(&apply_lock);
-
-	return 0;
-err:
-	mutex_unlock(&apply_lock);
-	return r;
-}
-
-int dss_mgr_unset_device(struct omap_overlay_manager *mgr)
-{
-	int r;
-
-	mutex_lock(&apply_lock);
-
-	if (!mgr->device) {
-		DSSERR("failed to unset display, display not set.\n");
-		r = -EINVAL;
-		goto err;
-	}
-
-	/*
-	 * Don't allow currently enabled displays to have the overlay manager
-	 * pulled out from underneath them
-	 */
-	if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) {
-		r = -EINVAL;
-		goto err;
-	}
-
-	mgr->device->manager = NULL;
-	mgr->device = NULL;
-
-	mutex_unlock(&apply_lock);
-
-	return 0;
-err:
-	mutex_unlock(&apply_lock);
-	return r;
-}
-
 int dss_mgr_set_output(struct omap_overlay_manager *mgr,
 		struct omap_dss_output *output)
 {
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
index d14ffc5..953f5ee 100644
--- a/drivers/video/omap2/dss/manager.c
+++ b/drivers/video/omap2/dss/manager.c
@@ -570,8 +570,6 @@ int dss_init_overlay_managers(struct platform_device *pdev)
 			break;
 		}
 
-		mgr->set_device = &dss_mgr_set_device;
-		mgr->unset_device = &dss_mgr_unset_device;
 		mgr->set_output = &dss_mgr_set_output;
 		mgr->unset_output = &dss_mgr_unset_output;
 		mgr->apply = &omap_dss_mgr_apply;
diff --git a/include/video/omapdss.h b/include/video/omapdss.h
index 0e73ef8..4ff43e6 100644
--- a/include/video/omapdss.h
+++ b/include/video/omapdss.h
@@ -466,7 +466,6 @@ struct omap_overlay_manager {
 	enum omap_dss_output_id supported_outputs;
 
 	/* dynamic fields */
-	struct omap_dss_device *device;
 	struct omap_dss_output *output;
 
 	/*
@@ -480,9 +479,6 @@ struct omap_overlay_manager {
 	 * interrupt context
 	 */
 
-	int (*set_device)(struct omap_overlay_manager *mgr,
-		struct omap_dss_device *dssdev);
-	int (*unset_device)(struct omap_overlay_manager *mgr);
 	int (*set_output)(struct omap_overlay_manager *mgr,
 		struct omap_dss_output *output);
 	int (*unset_output)(struct omap_overlay_manager *mgr);
@@ -634,7 +630,6 @@ struct omap_dss_device {
 
 	enum omap_display_caps caps;
 
-	struct omap_overlay_manager *manager;
 	struct omap_dss_output *output;
 
 	enum omap_dss_display_state state;
-- 
1.7.9.5


^ permalink raw reply related

* Re: [PATCH V5 0/6] OMAPDSS: Cleanup cpu_is checks
From: Tony Lindgren @ 2012-08-30 17:19 UTC (permalink / raw)
  To: Tomi Valkeinen; +Cc: Chandrabhanu Mahapatra, paul, linux-omap, linux-fbdev
In-Reply-To: <1346312061.2327.27.camel@deskari>

Hi,

* Tomi Valkeinen <tomi.valkeinen@ti.com> [120830 00:35]:
> On Wed, 2012-08-29 at 17:20 -0700, Tony Lindgren wrote:
> > 
> > Good to see this, we need this badly to avoid blocking
> > single zImage effort on omaps. Can you also please take
> 
> What is the issue with single zImage? How do cpu_is_ check affect it?

The usage for that should only be limited to arch/arm/mach-omap2
so we can make cpu.h local as we can't include mach and plat
header files from the drivers with single zImage.
 
> I had a brief look at drivers/video/omap*. Here's a brief status. I
> don't really know much about the old fb driver (drivers/video/omap) so
> my comments may not be totally correct. And all fixing I do there is
> done in blind, I don't have any omap1 devices.
> 
> I've left out the trivial cleanups from the list (i.e. file includes a
> header that it doesn't need), there were a bunch of those. I'll make a
> patch for these.
> 
> 
> $ git grep -E "<plat|<mach" drivers/video/omap*
> drivers/video/omap/lcd_ams_delta.c:#include <plat/board-ams-delta.h>
> * Needs to be moved

Yes, that should be either mach/board-ams-delta.h, or separate driver
specific headers in include/linux/platform_data. For omap1 we are not
planning common zImage support, so let's just make sure we're not
breaking anything there as people are still using it.

> * lcd_ams_delta uses also omap_write/read

Limiting omap_write/read to omap1 is OK for now, unless the fix
is trivial to do with ioremap + readw/writew.
 
> drivers/video/omap/lcd_inn1510.c:#include <plat/fpga.h>
> * No idea about this. Who wants to convert the fpga support? =)

I'll move it to mach/fpga.h as it's omap1 specifc.
 
> drivers/video/omap/lcd_mipid.c:#include <plat/lcd_mipid.h>
> * Needs to be moved
> 
> drivers/video/omap/lcd_osk.c:#include <plat/mux.h>
> * Uses omap_cfg_reg(PWL). I don't know what this is...

I'll move plat/mux.h into mach for omap1. For omap2+, we have
a local mux.h and are moving to use device tree based pinctrl-single
driver.

> * lcd_osk.c uses omap_write/read
> 
> drivers/video/omap/lcdc.c:#include <mach/lcdc.h>
> * Needs to be moved

This you can move to platform_data or mach for omap1?
 
> drivers/video/omap/lcdc.c:#include <plat/dma.h>
> * Uses arch/arm/mach-omap1/lcd_dma.c. Any idea about this? Will DMA
> engine support OMAP1's LCD DMA?

I think it should eventually as it can detect the device and could
automatically call those functions. Not sure if all options for
configuring it are available yet in dma engine.
 
> drivers/video/omap/omapfb_main.c:#include <plat/dma.h>
> * Uses DMA API to set DMA priority
> 
> drivers/video/omap/sossi.c:#include <plat/dma.h>
> * Uses arch/arm/mach-omap1/lcd_dma.c
> 
> drivers/video/omap2/dss/dss.c:#include <plat/cpu.h>
> * Uses cpu_is_* to find out the DSS version. dispc.c also uses cpu_is_*
> functions, but doesn't include plat/cpu.h. I know cpu_is_* checks should
> be removed, but is there some other file to include for the time being
> than plat/cpu.h?

We could make it mach/cpu.h for omap1, but ideally we would just
pass DSS_VERSION_XYZ type flag in platform data on omap1.
 
> drivers/video/omap2/dss/dss_features.c:#include <plat/cpu.h>
> * Uses cpu_is_* to find out the DSS version

Here too.
 
> drivers/video/omap2/omapfb/omapfb-ioctl.c:#include <plat/vrfb.h>
> drivers/video/omap2/omapfb/omapfb-ioctl.c:#include <plat/vram.h>
> drivers/video/omap2/omapfb/omapfb-main.c:#include <plat/vram.h>
> drivers/video/omap2/omapfb/omapfb-main.c:#include <plat/vrfb.h>
> drivers/video/omap2/omapfb/omapfb-sysfs.c:#include <plat/vrfb.h>
> drivers/video/omap2/vram.c:#include <plat/vram.h>
> drivers/video/omap2/vram.c:#include <plat/dma.h>
> drivers/video/omap2/vrfb.c:#include <plat/vrfb.h>
> drivers/video/omap2/vrfb.c:#include <plat/sdrc.h>
> 
> Of these, I'm not sure how to handle.

These should eventually be in platform_data as driver specific headers.
 
> Grep shows that vram.c is only used by (the newer) omapfb, so it could
> be considered a part of that driver. It still needs to be built-in, as
> it needs to reserve memory early in the boot process (done with a call
> from arch/arm/plat-omap/common.c).

Hmm it sounds like omap_vram_reserve_sdram_memblock() should be in
plat-omap and just pass the pointer for later use for vram.c.
 
> Also board files can use a func call to define the amount of memory to
> allocate, but only rx51 seems to do this in the mainline.
> 
> Anyway, I believe vram.c is going away when we start to use CMA.

OK cool. 
 
> As for vrfb... I'm not really sure where it belongs. It is used by the
> newer omapfb and OMAP V4L2 driver. VRFB is a part of the OMAP's memory
> controller, so I'm not sure if it's really a normal driver.

Maybe just split it to platform code for the memblock stuff and pass
the necessary information to the driver in platform_data?

Regards,

Tony


^ permalink raw reply

* Re: [PATCH V5 0/6] OMAPDSS: Cleanup cpu_is checks
From: Tomi Valkeinen @ 2012-08-31 11:23 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: Chandrabhanu Mahapatra, paul, linux-omap, linux-fbdev
In-Reply-To: <20120830171908.GQ1303@atomide.com>

[-- Attachment #1: Type: text/plain, Size: 3923 bytes --]

On Thu, 2012-08-30 at 10:19 -0700, Tony Lindgren wrote:
> Hi,
> 
> * Tomi Valkeinen <tomi.valkeinen@ti.com> [120830 00:35]:
> > On Wed, 2012-08-29 at 17:20 -0700, Tony Lindgren wrote:
> > > 
> > > Good to see this, we need this badly to avoid blocking
> > > single zImage effort on omaps. Can you also please take
> > 
> > What is the issue with single zImage? How do cpu_is_ check affect it?
> 
> The usage for that should only be limited to arch/arm/mach-omap2
> so we can make cpu.h local as we can't include mach and plat
> header files from the drivers with single zImage.

Ok.

> > $ git grep -E "<plat|<mach" drivers/video/omap*
> > drivers/video/omap/lcd_ams_delta.c:#include <plat/board-ams-delta.h>
> > * Needs to be moved
> 
> Yes, that should be either mach/board-ams-delta.h, or separate driver
> specific headers in include/linux/platform_data. For omap1 we are not
> planning common zImage support, so let's just make sure we're not
> breaking anything there as people are still using it.

Hmm, so did I understand right, for omap1 stuff we can still include
from arch/arm/mach-omap1/include/mach?

If so, that makes things easier. I can manage the omap2+ stuff fine, but
I have no experience with omap1, nor do I have any omap1 devices. So I'd
rather keep the omap1 code as it is, in fear that I'd just break it
totally, and I'd rather spend my time on omap2+ code.

> > drivers/video/omap2/dss/dss.c:#include <plat/cpu.h>
> > * Uses cpu_is_* to find out the DSS version. dispc.c also uses cpu_is_*
> > functions, but doesn't include plat/cpu.h. I know cpu_is_* checks should
> > be removed, but is there some other file to include for the time being
> > than plat/cpu.h?
> 
> We could make it mach/cpu.h for omap1, but ideally we would just
> pass DSS_VERSION_XYZ type flag in platform data on omap1.

Ok. The omap1 fb driver seems to contain a few cpu_is_omap15xx() checks,
nothing else.

> > drivers/video/omap2/dss/dss_features.c:#include <plat/cpu.h>
> > * Uses cpu_is_* to find out the DSS version
> 
> Here too.

Yep, for omap2+ I'll create a version ID that we'll pass via plat data.
 
> > drivers/video/omap2/omapfb/omapfb-ioctl.c:#include <plat/vrfb.h>
> > drivers/video/omap2/omapfb/omapfb-ioctl.c:#include <plat/vram.h>
> > drivers/video/omap2/omapfb/omapfb-main.c:#include <plat/vram.h>
> > drivers/video/omap2/omapfb/omapfb-main.c:#include <plat/vrfb.h>
> > drivers/video/omap2/omapfb/omapfb-sysfs.c:#include <plat/vrfb.h>
> > drivers/video/omap2/vram.c:#include <plat/vram.h>
> > drivers/video/omap2/vram.c:#include <plat/dma.h>
> > drivers/video/omap2/vrfb.c:#include <plat/vrfb.h>
> > drivers/video/omap2/vrfb.c:#include <plat/sdrc.h>
> > 
> > Of these, I'm not sure how to handle.
> 
> These should eventually be in platform_data as driver specific headers.
>  
> > Grep shows that vram.c is only used by (the newer) omapfb, so it could
> > be considered a part of that driver. It still needs to be built-in, as
> > it needs to reserve memory early in the boot process (done with a call
> > from arch/arm/plat-omap/common.c).
> 
> Hmm it sounds like omap_vram_reserve_sdram_memblock() should be in
> plat-omap and just pass the pointer for later use for vram.c.
>  
> > Also board files can use a func call to define the amount of memory to
> > allocate, but only rx51 seems to do this in the mainline.
> > 
> > Anyway, I believe vram.c is going away when we start to use CMA.
> 
> OK cool. 
>  
> > As for vrfb... I'm not really sure where it belongs. It is used by the
> > newer omapfb and OMAP V4L2 driver. VRFB is a part of the OMAP's memory
> > controller, so I'm not sure if it's really a normal driver.
> 
> Maybe just split it to platform code for the memblock stuff and pass
> the necessary information to the driver in platform_data?

I'll try to figure out something for vrfb.

 Tomi


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* [PATCH v5 0/4] Runtime Interpreted Power Sequences
From: Alexandre Courbot @ 2012-08-31 11:34 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Simon Glass, Grant Likely,
	Rob Herring, Mark Brown, Anton Vorontsov, David Woodhouse,
	Arnd Bergmann
  Cc: Leela Krishna Amudala, linux-tegra, linux-kernel, linux-fbdev,
	devicetree-discuss, linux-pm, linux-doc, Alexandre Courbot

New revision taking (hopefully) all the feedback received from the previous
version into account. It's funny how a 30 lines patch to switch my backlight
turned into a 1500 lines patchset introducing a new framework. And in the end
my backlight switches just the same.

So anyway, the main updates are:

* Types of DT steps are now determined by a "type" property and not by the
  presence of a specific property.
* Power sequences and their resources are now encapsulated into a "set"
  structure. I was reluctant to this idea but have to admit now that it is way
  cleaner.
* GPIO steps now refer the GPIO phandle directly in the DT instead of by name.
  The GPIO framework does not work like regulator or PWM in that GPIOs cannot be
  accessed by name, so it did not make sense anyway. And thanks to that we now
  have perfect matching between the platform data members and the DT properties,
  which makes everything more consistent.
* Moved the implementations of resources into their own file (directly included
  from the main file) and added an "ops" structure to abstract them. This
  clearly separates the framework from the resources implementations and should
  make it easier to add new resources types.

Alexandre Courbot (4):
  Runtime Interpreted Power Sequences
  pwm_backlight: use power sequences
  tegra: dt: add label to tegra20's PWM
  tegra: ventana: add pwm backlight DT nodes

 .../devicetree/bindings/power_seq/power_seq.txt    | 117 ++++++
 .../bindings/video/backlight/pwm-backlight.txt     |  67 +++-
 Documentation/power/power_seq.txt                  | 225 +++++++++++
 arch/arm/boot/dts/tegra20-ventana.dts              |  59 ++-
 arch/arm/boot/dts/tegra20.dtsi                     |   2 +-
 drivers/power/Kconfig                              |   1 +
 drivers/power/Makefile                             |   1 +
 drivers/power/power_seq/Kconfig                    |   2 +
 drivers/power/power_seq/Makefile                   |   1 +
 drivers/power/power_seq/power_seq.c                | 446 +++++++++++++++++++++
 drivers/power/power_seq/power_seq_delay.c          |  51 +++
 drivers/power/power_seq/power_seq_gpio.c           |  81 ++++
 drivers/power/power_seq/power_seq_pwm.c            |  85 ++++
 drivers/power/power_seq/power_seq_regulator.c      |  86 ++++
 drivers/video/backlight/Kconfig                    |   1 +
 drivers/video/backlight/pwm_bl.c                   | 179 ++++++---
 include/linux/power_seq.h                          | 174 ++++++++
 include/linux/pwm_backlight.h                      |  15 +-
 18 files changed, 1537 insertions(+), 56 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/power_seq/power_seq.txt
 create mode 100644 Documentation/power/power_seq.txt
 create mode 100644 drivers/power/power_seq/Kconfig
 create mode 100644 drivers/power/power_seq/Makefile
 create mode 100644 drivers/power/power_seq/power_seq.c
 create mode 100644 drivers/power/power_seq/power_seq_delay.c
 create mode 100644 drivers/power/power_seq/power_seq_gpio.c
 create mode 100644 drivers/power/power_seq/power_seq_pwm.c
 create mode 100644 drivers/power/power_seq/power_seq_regulator.c
 create mode 100644 include/linux/power_seq.h

-- 
1.7.12


^ permalink raw reply

* [PATCH v5 1/4] Runtime Interpreted Power Sequences
From: Alexandre Courbot @ 2012-08-31 11:34 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Simon Glass, Grant Likely,
	Rob Herring, Mark Brown, Anton Vorontsov, David Woodhouse,
	Arnd Bergmann
  Cc: Leela Krishna Amudala, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, linux-doc-u79uwXL29TY76Z2rM5mHXA,
	Alexandre Courbot
In-Reply-To: <1346412846-17102-1-git-send-email-acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

Some device drivers (panel backlights especially) need to follow precise
sequences for powering on and off, involving gpios, regulators, PWMs
with a precise powering order and delays to respect between each steps.
These sequences are board-specific, and do not belong to a particular
driver - therefore they have been performed by board-specific hook
functions to far.

With the advent of the device tree and of ARM kernels that are not
board-tied, we cannot rely on these board-specific hooks anymore but
need a way to implement these sequences in a portable manner. This patch
introduces a simple interpreter that can execute such power sequences
encoded either as platform data or within the device tree.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
 .../devicetree/bindings/power_seq/power_seq.txt    | 117 ++++++
 Documentation/power/power_seq.txt                  | 225 +++++++++++
 drivers/power/Kconfig                              |   1 +
 drivers/power/Makefile                             |   1 +
 drivers/power/power_seq/Kconfig                    |   2 +
 drivers/power/power_seq/Makefile                   |   1 +
 drivers/power/power_seq/power_seq.c                | 446 +++++++++++++++++++++
 drivers/power/power_seq/power_seq_delay.c          |  51 +++
 drivers/power/power_seq/power_seq_gpio.c           |  81 ++++
 drivers/power/power_seq/power_seq_pwm.c            |  85 ++++
 drivers/power/power_seq/power_seq_regulator.c      |  86 ++++
 include/linux/power_seq.h                          | 174 ++++++++
 12 files changed, 1270 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power_seq/power_seq.txt
 create mode 100644 Documentation/power/power_seq.txt
 create mode 100644 drivers/power/power_seq/Kconfig
 create mode 100644 drivers/power/power_seq/Makefile
 create mode 100644 drivers/power/power_seq/power_seq.c
 create mode 100644 drivers/power/power_seq/power_seq_delay.c
 create mode 100644 drivers/power/power_seq/power_seq_gpio.c
 create mode 100644 drivers/power/power_seq/power_seq_pwm.c
 create mode 100644 drivers/power/power_seq/power_seq_regulator.c
 create mode 100644 include/linux/power_seq.h

diff --git a/Documentation/devicetree/bindings/power_seq/power_seq.txt b/Documentation/devicetree/bindings/power_seq/power_seq.txt
new file mode 100644
index 0000000..d3e3f6a
--- /dev/null
+++ b/Documentation/devicetree/bindings/power_seq/power_seq.txt
@@ -0,0 +1,117 @@
+Runtime Interpreted Power Sequences
+=================+
+Power sequences are sequential descriptions of actions to be performed on
+power-related resources. Having these descriptions in a precise data format
+allows us to take much of the board-specific power control code out of the
+kernel and place it into the device tree instead, making kernels less
+board-dependant.
+
+In the device tree, power sequences are grouped into a set. The set is always
+declared as the "power-sequences" sub-node of the device node. Power sequences
+may reference resources declared by that device.
+
+Power Sequences Structure
+-------------------------
+Every device that makes use of power sequences must have a "power-sequences"
+sub-node. Power sequences are sub-nodes of this set node, and their node name
+indicates the id of the sequence.
+
+Every power sequence in turn contains its steps as sub-nodes of itself. Step
+must be named sequentially, with the first step named step0, the second step1,
+etc. Failure to follow this rule will result in a parsing error.
+
+Power Sequences Steps
+---------------------
+Step of a sequence describes an action to be performed on a resource. They
+always include a "type" property which indicates what kind of resource this
+step works on. Depending on the resource type, additional properties are defined
+to control the action to be performed.
+
+"delay" type required properties:
+  - delay_us: delay to wait in microseconds
+
+"regulator" type required properties:
+  - id: name of the regulator to use. Regulator is obtained by
+        regulator_get(dev, id)
+  - enable / disable: one of these two empty properties must be present to
+                      enable or disable the resource
+
+"pwm" type required properties:
+  - id: name of the PWM to use. PWM is obtained by pwm_get(dev, id)
+  - enable / disable: one of these two empty properties must be present to
+                      enable or disable the resource
+
+"gpio" type required properties:
+  - number: phandle of the GPIO to use.
+  - enable / disable: one of these two empty properties must be present to
+                      enable or disable the resource
+
+Example
+-------
+Here are example sequences declared within a backlight device that use all the
+supported resources types:
+
+	backlight {
+		compatible = "pwm-backlight";
+		...
+
+		/* resources used by the power sequences */
+		pwms = <&pwm 2 5000000>;
+		pwm-names = "backlight";
+		power-supply = <&backlight_reg>;
+
+		power-sequences {
+			power-on {
+				step0 {
+					type = "regulator";
+					id = "power";
+					enable;
+				};
+				step1 {
+					type = "delay";
+					delay_us = <10000>;
+				};
+				step2 {
+					type = "pwm";
+					id = "backlight";
+					enable;
+				};
+				step3 {
+					type = "gpio";
+					number = <&gpio 28 0>;
+					enable;
+				};
+			};
+
+			power-off {
+				step0 {
+					type = "gpio";
+					number = <&gpio 28 0>;
+					disable;
+				};
+				step1 {
+					type = "pwm";
+					id = "backlight";
+					disable;
+				};
+				step2 {
+					type = "delay";
+					delay_us = <10000>;
+				};
+				step3 {
+					type = "regulator";
+					id = "power";
+					disable;
+				};
+			};
+		};
+	};
+
+The first part lists the PWM and regulator resources used by the sequences.
+These resources will be requested on behalf of the backlight device when the
+sequences are built and are declared according to their own framework in a way
+that makes them accessible by name.
+
+After the resources declaration, two sequences follow for powering the backlight
+on and off. Their names are specified by the pwm-backlight driver.
diff --git a/Documentation/power/power_seq.txt b/Documentation/power/power_seq.txt
new file mode 100644
index 0000000..48d1f6b
--- /dev/null
+++ b/Documentation/power/power_seq.txt
@@ -0,0 +1,225 @@
+Runtime Interpreted Power Sequences
+=================+
+Problem
+-------
+Very commonly, boards need the help of out-of-driver code to turn some of their
+devices on and off. For instance, SoC boards very commonly use a GPIO
+(abstracted to a regulator or not) to control the power supply of a backlight,
+disabling it when the backlight is not used in order to save power. The GPIO
+that should be used, however, as well as the exact power sequence that may
+also involve other resources, is board-dependent and thus unknown to the driver.
+
+This was previously addressed by having hooks in the device's platform data that
+are called whenever the state of the device might reflect a power change. This
+approach, however, introduces board-dependant code into the kernel and is not
+compatible with the device tree.
+
+The Runtime Interpreted Power Sequences (or power sequences for short) aim at
+turning this code into platform data or device tree nodes. Power sequences are
+described using a simple format and run by a lightweight interpreter whenever
+needed. This allows to remove the callback mechanism and makes the kernel less
+board-dependant.
+
+What are Power Sequences?
+-------------------------
+Power sequences are a series of sequential steps during which an action is
+performed on a resource. The supported resources and actions operations are:
+- delay (just wait for a given number of microseconds)
+- GPIO (enable or disable)
+- regulator (enable or disable)
+- PWM (enable or disable)
+
+When a power sequence is run, each of its steps is executed sequentially until
+one step fails or the end of the sequence is reached.
+
+Power sequences are grouped in "sets" and declared per-device. Every sequence
+must be attributed a name that can be used to retrieve it from its set when it
+is needed.
+
+Power sequences can be declared as platform data or in the device tree.
+
+Platform Data Format
+--------------------
+All relevant data structures for declaring power sequences are located in
+include/linux/power_seq.h.
+
+The platform data for a given device is an instance of platform_power_seq_set
+which points to instances of platform_power_seq. Every platform_power_seq is a
+single power sequence, and is itself composed of a variable length array of
+steps.
+
+A step is a union of all the step structures. Which one is to be used depends on
+the type of the step. Step structures are documented in the
+include/linux/power_seq.h file ; please refer to it for all details, but the
+following example will probably make it clear how power sequences should be
+defined. It defines two power sequences named "power_on" and "power_off". The
+"power_on" sequence enables a regulator called "power" (retrieved from the
+device using regulator_get()), waits for 10ms, and then enabled GPIO 110.
+"power_off" does the opposite.
+
+static struct platform_power_seq power_on_seq = {
+	.id = "power_on",
+	.num_steps = 3,
+	.steps = {
+		{
+			.type = POWER_SEQ_REGULATOR,
+			.regulator = {
+				.id = "power",
+				.enable = true,
+			},
+		},
+		{
+			.type = POWER_SEQ_DELAY,
+			.delay = {
+				.delay_us = 10000,
+			},
+		},
+		{
+			.type = POWER_SEQ_GPIO,
+			.gpio = {
+				.number = 110,
+				.enable = true,
+			},
+		},
+	},
+};
+
+static struct platform_power_seq power_off_seq = {
+	.id = "power_off",
+	.num_steps = 3,
+	.steps = {
+		{
+			.type = POWER_SEQ_GPIO,
+			.gpio = {
+				.number = 110,
+				.enable = false,
+			},
+		},
+		{
+			.type = POWER_SEQ_DELAY,
+			.delay = {
+				.delay_us = 10000,
+			},
+		},
+		{
+			.type = POWER_SEQ_REGULATOR,
+			.regulator = {
+				.id = "power",
+				.enable = false,
+			},
+		},
+	},
+};
+
+static struct platform_power_seq_set power_sequences = {
+	.num_seqs = 2,
+	.seqs = {
+		&power_on_seq,
+		&power_off_seq,
+	},
+};
+
+Device Tree
+-----------
+Power sequences can also be encoded as device tree nodes. The following
+properties and nodes are equivalent to the platform data defined previously:
+
+power-supply = <&power_reg>;
+
+power-sequences {
+	power-on {
+		step0 {
+			type = "regulator";
+			id = "power";
+			enable;
+		};
+		step1 {
+			type = "delay";
+			delay = <10000>;
+		};
+		step2 {
+			type = "gpio";
+			number = <&gpio 110 0>;
+			enable;
+		};
+	}
+	power-off {
+		step0 {
+			type = "gpio";
+			number = <&gpio 110 0>;
+			disable;
+		};
+		step1 {
+			type = "delay";
+			delay = <10000>;
+		};
+		step2 {
+			type = "regulator";
+			id = "power";
+			disable;
+		};
+	}
+};
+
+See Documentation/devicetree/bindings/power_seq/power_seq.txt for the complete
+syntax of the bindings.
+
+Usage by Drivers and Resources Management
+-----------------------------------------
+Power sequences make use of resources that must be properly allocated and
+managed. The devm_power_seq_set_build() function builds a power sequence set
+from platform data. It also takes care of resolving and allocating the resources
+referenced by the sequence:
+
+  struct power_seq_set *devm_power_seq_set_build(struct device *dev,
+					   struct platform_power_seq_set *pseq);
+
+As its name states, all memory and resources are devm-allocated. The 'dev'
+argument is the device in the name of which the resources are to be allocated.
+
+On success, the function returns a devm allocated resolved sequences set for
+which all the resources are allocated. In case of failure, an error code is
+returned.
+
+Power sequences can then be retrieved by their name using power_seq_lookup:
+
+  struct power_seq *power_seq_lookup(struct power_seq_set *seqs,
+				     const char *id);
+
+A power sequence can be executed by power_seq_run:
+
+  int power_seq_run(struct power_seq *seq);
+
+It returns 0 if the sequence has successfully been run, or an error code if a
+problem occured.
+
+Sometimes, you may want to browse the list of resources allocated by a sequence,
+to for instance ensure that a resource of a given type is present. The
+power_seq_set_resources() function returns a list head that can be used with
+the power_seq_for_each_resource() macro to browse all the resources of a set:
+
+  struct list_head *power_seq_set_resources(struct power_seq_set *seqs);
+  power_seq_for_each_resource(pos, seqs)
+
+Here "pos" will be of type struct power_seq_resource. This structure contains a
+"pdata" pointer that can be used to explore the platform data of this resource,
+as well as the resolved resource, if applicable.
+
+Finally, users of the device tree can build the platform data corresponding to
+the tree node using this function:
+
+  struct platform_power_seq_set *devm_of_parse_power_seq_set(struct device *dev);
+
+As the device tree syntax unambiguously states the name of the node containing
+the power sequences, it only needs a pointer to the device to work. The result
+can then be passed to devm_power_seq_set_build() in order to get a set of
+runnable sequences.
+
+devm_of_parse_power_seq_set allocates its memory using devm, but the platform
+data becomes unneeded after devm_power_seq_set_build() is called on it and can
+thus be freed. Be aware though that one allocation is performed for the set and
+for every sequence. The devm_power_seq_platform_data_free() function takes care
+of freeing the memory properly:
+
+  void devm_platform_power_seq_set_free(struct platform_power_seq_set *pseq);
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index fcc1bb0..5fdfd84 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -312,3 +312,4 @@ config AB8500_BATTERY_THERM_ON_BATCTRL
 endif # POWER_SUPPLY
 
 source "drivers/power/avs/Kconfig"
+source "drivers/power/power_seq/Kconfig"
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index ee58afb..d3c893b 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -45,3 +45,4 @@ obj-$(CONFIG_CHARGER_MAX8997)	+= max8997_charger.o
 obj-$(CONFIG_CHARGER_MAX8998)	+= max8998_charger.o
 obj-$(CONFIG_POWER_AVS)		+= avs/
 obj-$(CONFIG_CHARGER_SMB347)	+= smb347-charger.o
+obj-$(CONFIG_POWER_SEQ)		+= power_seq/
diff --git a/drivers/power/power_seq/Kconfig b/drivers/power/power_seq/Kconfig
new file mode 100644
index 0000000..3bff26e
--- /dev/null
+++ b/drivers/power/power_seq/Kconfig
@@ -0,0 +1,2 @@
+config POWER_SEQ
+	bool
diff --git a/drivers/power/power_seq/Makefile b/drivers/power/power_seq/Makefile
new file mode 100644
index 0000000..f77a359
--- /dev/null
+++ b/drivers/power/power_seq/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_POWER_SEQ)		+= power_seq.o
diff --git a/drivers/power/power_seq/power_seq.c b/drivers/power/power_seq/power_seq.c
new file mode 100644
index 0000000..e4d482c
--- /dev/null
+++ b/drivers/power/power_seq/power_seq.c
@@ -0,0 +1,446 @@
+/*
+ * power_seq.c - A simple power sequence interpreter for platform devices
+ *               and device tree.
+ *
+ * Author: Alexandre Courbot <acourbot@nvidia.com>
+ *
+ * Copyright (c) 2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/power_seq.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/device.h>
+
+#include <linux/of.h>
+
+struct power_seq_set {
+	struct device *dev;
+	struct list_head resources;
+	struct list_head sequences;
+};
+
+struct power_seq_step {
+	/* Copy of the platform data */
+	struct platform_power_seq_step pdata;
+	/* Resolved resource */
+	struct power_seq_resource *resource;
+};
+
+struct power_seq {
+	/* Set this sequence belongs to */
+	struct power_seq_set *parent_set;
+	const char *id;
+	/* To thread into power_seqs structure */
+	struct list_head list;
+	unsigned int num_steps;
+	struct power_seq_step steps[];
+};
+
+#define power_seq_err(dev, seq, step_nbr, format, ...)			     \
+	dev_err(dev, "%s[%d]: " format, seq->id, step_nbr, ##__VA_ARGS__);
+
+/**
+ * struct power_seq_res_type - operators for power sequences resources
+ * @name:		Name of the resource type. Set to null when a resource
+ *			type support is not compiled in
+ * @need_resource:	Whether a resource needs to be allocated when steps of
+ *			this kind are met. If set to false, res_compare and
+ *			res_alloc need not be set
+ * @of_parse:		Parse a step for this kind of resource from a device
+ *			tree node. The result of parsing must be written into
+ *			step step_nbr of seq
+ * @step_run:		Run a step for this kind of resource
+ * @res_compare:	Return true if the resource used by both steps is the
+ *			same, false otherwise
+ * @res_alloc:		Resolve and allocate the resource passed from seq
+ *			Return error code if the resource cannot be allocated
+ */
+struct power_seq_res_ops {
+	const char *name;
+	bool need_resource;
+	int (*of_parse)(struct device *dev, struct device_node *node,
+			struct platform_power_seq *seq, unsigned int step_nbr);
+	int (*step_run)(struct power_seq_step *step);
+	bool (*res_compare)(struct platform_power_seq_step *step1,
+			    struct platform_power_seq_step *step2);
+	int (*res_alloc)(struct device *dev, struct power_seq_resource *seq);
+};
+
+static const struct power_seq_res_ops power_seq_types[POWER_SEQ_NUM_TYPES];
+
+#ifdef CONFIG_OF
+static int of_power_seq_parse_enable_properties(struct device *dev,
+						struct device_node *node,
+						struct platform_power_seq *seq,
+						unsigned int step_nbr,
+						bool *enable)
+{
+	if (of_find_property(node, "enable", NULL)) {
+		*enable = true;
+	} else if (of_find_property(node, "disable", NULL)) {
+		*enable = false;
+	} else {
+		power_seq_err(dev, seq, step_nbr, 
+			      "missing enable or disable property\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int of_power_seq_parse_step(struct device *dev, struct device_node *node,
+				   struct platform_power_seq *seq,
+				   unsigned int step_nbr)
+{
+	struct platform_power_seq_step *step = &seq->steps[step_nbr];
+	const char *type;
+	int i, err;
+
+	err = of_property_read_string(node, "type", &type);
+	if (err < 0) {
+		power_seq_err(dev, seq, step_nbr,
+			      "cannot read type property\n");
+		return err;
+	}
+	for (i = 0; i < POWER_SEQ_NUM_TYPES; i++) {
+		if (power_seq_types[i].name = NULL)
+			continue;
+		if (!strcmp(type, power_seq_types[i].name))
+			break;
+	}
+	if (i >= POWER_SEQ_NUM_TYPES) {
+		power_seq_err(dev, seq, step_nbr, "unknown type %s\n", type);
+		return -EINVAL;
+	}
+	step->type = i;
+	err = power_seq_types[step->type].of_parse(dev, node, seq, step_nbr);
+
+	return err;
+}
+
+static struct platform_power_seq *of_parse_power_seq(struct device *dev,
+						     struct device_node *node)
+{
+	struct device_node *child = NULL;
+	struct platform_power_seq *pseq;
+	int num_steps, sz;
+	int err;
+
+	if (!node)
+		return ERR_PTR(-EINVAL);
+
+	num_steps = of_get_child_count(node);
+	sz = sizeof(*pseq) + sizeof(pseq->steps[0]) * num_steps;
+	pseq = devm_kzalloc(dev, sz, GFP_KERNEL);
+	if (!pseq)
+		return ERR_PTR(-ENOMEM);
+	pseq->num_steps = num_steps;
+	pseq->id = node->name;
+
+	for_each_child_of_node(node, child) {
+		unsigned int pos;
+
+		/* Check that the name's format is correct and within bounds */
+		if (strncmp("step", child->name, 4)) {
+			err = -EINVAL;
+			goto parse_error;
+		}
+
+		err = kstrtouint(child->name + 4, 10, &pos);
+		if (err < 0)
+			goto parse_error;
+
+		if (pos >= num_steps || pseq->steps[pos].type != 0) {
+			err = -EINVAL;
+			goto parse_error;
+		}
+
+		err = of_power_seq_parse_step(dev, child, pseq, pos);
+		if (err)
+			return ERR_PTR(err);
+	}
+
+	return pseq;
+
+parse_error:
+	dev_err(dev, "%s: invalid power step name %s!\n", pseq->id,
+		child->name);
+	return ERR_PTR(err);
+}
+
+/**
+ * of_parse_power_seq_set() - build platform data corresponding to a DT node
+ * @dev:	Device on behalf of which the sequence is to be built
+ *
+ * Sequences must be contained into a subnode named "power-sequences" of the
+ * device root node.
+ *
+ * Memory for the platform sequence is allocated using devm_kzalloc on dev and
+ * can be freed by devm_kfree after power_seq_set_build returned. Beware that on
+ * top of the set itself, platform data for individual sequences should also be
+ * freed.
+ *
+ * Returns the built power sequence set on success, or an error code in case of
+ * failure.
+ */
+struct platform_power_seq_set *devm_of_parse_power_seq_set(struct device *dev)
+{
+	struct platform_power_seq_set *seqs;
+	struct device_node *root = dev->of_node;
+	struct device_node *seq;
+	int num_seqs, sz, i = 0;
+
+	if (!root)
+		return NULL;
+
+	root = of_find_node_by_name(root, "power-sequences");
+	if (!root)
+		return NULL;
+
+	num_seqs = of_get_child_count(root);
+	sz = sizeof(*seqs) + sizeof(seqs->seqs[0]) * num_seqs;
+	seqs = devm_kzalloc(dev, sz, GFP_KERNEL);
+	if (!seqs)
+		return ERR_PTR(-ENOMEM);
+	seqs->num_seqs = num_seqs;
+
+	for_each_child_of_node(root, seq) {
+		struct platform_power_seq *pseq;
+
+		pseq = of_parse_power_seq(dev, seq);
+		if (IS_ERR(pseq))
+			return (void *)pseq;
+
+		seqs->seqs[i++] = pseq;
+	}
+
+	return seqs;
+}
+EXPORT_SYMBOL_GPL(devm_of_parse_power_seq_set);
+#endif /* CONFIG_OF */
+
+/**
+ * devm_platform_power_seq_set_free() - free data allocated by of_parse_power_seq_set
+ * @pseq:	Platform data to free
+ *
+ * This function can be called *only* on data returned by of_parse_power_seq_set
+ * and *after* devm_power_seq_set_build has been called on it.
+ */
+void devm_platform_power_seq_set_free(struct device *dev,
+				      struct platform_power_seq_set *pseq)
+{
+	int i;
+
+	for (i = 0; i < pseq->num_seqs; i++)
+		devm_kfree(dev, pseq->seqs[i]);
+
+	devm_kfree(dev, pseq);
+}
+EXPORT_SYMBOL_GPL(devm_platform_power_seq_set_free);
+
+static struct power_seq_resource *
+power_seq_find_resource(struct list_head *ress,
+			struct platform_power_seq_step *step)
+{
+	struct power_seq_resource *res;
+
+	list_for_each_entry(res, ress, list) {
+		struct platform_power_seq_step *pdata = res->pdata;
+
+		if (pdata->type != step->type)
+			continue;
+
+		if (power_seq_types[pdata->type].res_compare(pdata, step))
+			return res;
+	}
+
+	return NULL;
+}
+
+static struct power_seq *power_seq_build_one(struct device *dev,
+					     struct power_seq_set *seqs,
+					     struct platform_power_seq *pseq)
+{
+	struct power_seq *seq;
+	struct power_seq_resource *res;
+	int i, err;
+
+	seq = devm_kzalloc(dev, sizeof(*seq) + sizeof(seq->steps[0]) *
+			   pseq->num_steps, GFP_KERNEL);
+	if (!seq)
+		return ERR_PTR(-ENOMEM);
+
+	INIT_LIST_HEAD(&seq->list);
+	seq->parent_set = seqs;
+	seq->num_steps = pseq->num_steps;
+	seq->id = pseq->id;
+
+	for (i = 0; i < seq->num_steps; i++) {
+		struct platform_power_seq_step *pstep = &pseq->steps[i];
+		struct power_seq_step *step = &seq->steps[i];
+
+		if (pstep->type >= POWER_SEQ_NUM_TYPES ||
+		    power_seq_types[pstep->type].name = NULL) {
+			power_seq_err(dev, seq, i,
+				      "invalid power sequence type %d!",
+		 		      pstep->type);
+			return ERR_PTR(-EINVAL);
+		}
+
+		memcpy(&step->pdata, pstep, sizeof(step->pdata));
+
+		/* Steps without resource need not to continue */
+		if (!power_seq_types[pstep->type].need_resource)
+			continue;
+
+		/* create resource node if not referenced already */
+		res = power_seq_find_resource(&seqs->resources, pstep);
+		if (!res) {
+			res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
+			if (!res)
+				return ERR_PTR(-ENOMEM);
+
+			res->pdata = &step->pdata;
+
+			err = power_seq_types[res->pdata->type].res_alloc(dev, res);
+			if (err < 0) {
+				power_seq_err(dev, seq, i,
+					      "error building sequence\n");
+				return ERR_PTR(err);
+			}
+
+			list_add_tail(&res->list, &seqs->resources);
+		}
+		step->resource = res;
+	}
+
+	return seq;
+}
+
+/**
+ * power_seq_set_build() - build a set of runnable sequences from platform data
+ * @dev:	Device that will use the power sequences. All resources will be
+ *		devm-allocated against it
+ * @pseq:	Platform data for the power sequences. It can be freed after
+ *		this function returns
+ *
+ * All memory and resources (regulators, GPIOs, etc.) are allocated using devm
+ * functions.
+ *
+ * Returns the built sequence on success, an error code in case or failure.
+ */
+struct power_seq_set *devm_power_seq_set_build(struct device *dev,
+					    struct platform_power_seq_set *pseq)
+{
+	struct power_seq_set *seqs;
+	int i;
+
+	seqs = devm_kzalloc(dev, sizeof(*seqs), GFP_KERNEL);
+
+	if (!seqs)
+		return ERR_PTR(-ENOMEM);
+
+	INIT_LIST_HEAD(&seqs->resources);
+	INIT_LIST_HEAD(&seqs->sequences);
+	for (i = 0; i < pseq->num_seqs; i++) {
+		struct power_seq *seq;
+
+		seq = power_seq_build_one(dev, seqs, pseq->seqs[i]);
+		if (IS_ERR(seq))
+			return (void *)seq;
+
+		list_add_tail(&seq->list, &seqs->sequences);
+	}
+
+	return seqs;
+}
+EXPORT_SYMBOL_GPL(devm_power_seq_set_build);
+
+/**
+ * power_seq_lookup - Lookup a power sequence by name from a set
+ * @seqs:	The set to look in
+ * @id:		Name to look after
+ *
+ * Returns a matching power sequence if it exists, NULL if it does not.
+ */
+struct power_seq *power_seq_lookup(struct power_seq_set *seqs, const char *id)
+{
+	struct power_seq *seq;
+
+	list_for_each_entry(seq, &seqs->sequences, list) {
+		if (!strcmp(seq->id, id))
+			return seq;
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(power_seq_lookup);
+
+/**
+ * power_seq_set_resources - return a list of all the resources used by a set
+ * @seqs:	Power sequences set we are interested in getting the resources
+ *
+ * The returned list can be parsed using the power_seq_for_each_resource macro.
+ */
+struct list_head *power_seq_set_resources(struct power_seq_set *seqs)
+{
+	return &seqs->resources;
+}
+EXPORT_SYMBOL_GPL(power_seq_set_resources);
+
+/**
+ * power_seq_run() - run a power sequence
+ * @seq:	The power sequence to run
+ *
+ * Returns 0 on success, error code in case of failure.
+ */
+int power_seq_run(struct power_seq *seq)
+{
+	unsigned int i;
+	int err;
+
+	if (!seq)
+		return 0;
+
+	for (i = 0; i < seq->num_steps; i++) {
+		unsigned int type = seq->steps[i].pdata.type;
+
+		err = power_seq_types[type].step_run(&seq->steps[i]);
+		if (err) {
+			power_seq_err(seq->parent_set->dev, seq, i,
+				"error %d while running power sequence step\n",
+				err);
+			return err;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(power_seq_run);
+
+#include "power_seq_delay.c"
+#include "power_seq_regulator.c"
+#include "power_seq_pwm.c"
+#include "power_seq_gpio.c"
+
+static const struct power_seq_res_ops power_seq_types[POWER_SEQ_NUM_TYPES] = {
+	[POWER_SEQ_DELAY] = POWER_SEQ_DELAY_TYPE,
+	[POWER_SEQ_REGULATOR] = POWER_SEQ_REGULATOR_TYPE,
+	[POWER_SEQ_PWM] = POWER_SEQ_PWM_TYPE,
+	[POWER_SEQ_GPIO] = POWER_SEQ_GPIO_TYPE,
+};
+
+MODULE_AUTHOR("Alexandre Courbot <acourbot@nvidia.com>");
+MODULE_DESCRIPTION("Runtime Interpreted Power Sequences");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/power_seq/power_seq_delay.c b/drivers/power/power_seq/power_seq_delay.c
new file mode 100644
index 0000000..072bf50
--- /dev/null
+++ b/drivers/power/power_seq/power_seq_delay.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/delay.h>
+
+#ifdef CONFIG_OF
+static int of_power_seq_parse_delay(struct device *dev,
+				    struct device_node *node,
+				    struct platform_power_seq *seq,
+				    unsigned int step_nbr)
+{
+	struct platform_power_seq_step *step = &seq->steps[step_nbr];
+	int err;
+
+	err = of_property_read_u32(node, "delay_us",
+				   &step->delay.delay_us);
+	if (err < 0)
+		power_seq_err(dev, seq, step_nbr,
+			      "error reading delay_us property\n");
+
+	return err;
+}
+#else
+#define of_power_seq_parse_delay NULL
+#endif
+
+static int power_seq_step_run_delay(struct power_seq_step *step)
+{
+	usleep_range(step->pdata.delay.delay_us,
+		     step->pdata.delay.delay_us + 1000);
+
+	return 0;
+}
+
+#define POWER_SEQ_DELAY_TYPE {			\
+	.name = "delay",			\
+	.need_resource = false,			\
+	.of_parse = of_power_seq_parse_delay,	\
+	.step_run = power_seq_step_run_delay,	\
+}
diff --git a/drivers/power/power_seq/power_seq_gpio.c b/drivers/power/power_seq/power_seq_gpio.c
new file mode 100644
index 0000000..2e9a49f
--- /dev/null
+++ b/drivers/power/power_seq/power_seq_gpio.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#ifdef CONFIG_OF
+static int power_seq_of_parse_gpio(struct device *dev,
+				   struct device_node *node,
+				   struct platform_power_seq *seq,
+				   unsigned int step_nbr)
+{
+	struct platform_power_seq_step *step = &seq->steps[step_nbr];
+	int gpio;
+	int err;
+
+	gpio = of_get_named_gpio(node, "number", 0);
+	if (gpio < 0) {
+		power_seq_err(dev, seq, step_nbr,
+			      "error reading number property\n");
+		return gpio;
+	}
+	step->gpio.number = gpio;
+
+	err = of_power_seq_parse_enable_properties(dev, node, seq, step_nbr,
+					     &step->gpio.enable);
+
+	return err;
+}
+#else
+#define of_power_seq_parse_gpio NULL
+#endif
+
+static bool power_seq_res_compare_gpio(struct platform_power_seq_step *step1,
+				       struct platform_power_seq_step *step2)
+{
+	return step1->gpio.number = step2->gpio.number;
+}
+
+static int power_seq_res_alloc_gpio(struct device *dev,
+					struct power_seq_resource *res)
+{
+	int err;
+
+	err = devm_gpio_request_one(dev, res->pdata->gpio.number,
+				    GPIOF_OUT_INIT_LOW, dev_name(dev));
+	if (err) {
+		dev_err(dev, "cannot get gpio %d\n", res->pdata->gpio.number);
+		return err;
+	}
+
+	return 0;
+}
+
+static int power_seq_step_run_gpio(struct power_seq_step *step)
+{
+	gpio_set_value_cansleep(step->pdata.gpio.number,
+				step->pdata.gpio.enable);
+
+	return 0;
+}
+
+#define POWER_SEQ_GPIO_TYPE {					\
+	.name = "gpio",					\
+	.need_resource = true,				\
+	.of_parse = power_seq_of_parse_gpio,		\
+	.step_run = power_seq_step_run_gpio,		\
+	.res_compare = power_seq_res_compare_gpio,	\
+	.res_alloc = power_seq_res_alloc_gpio,		\
+}
diff --git a/drivers/power/power_seq/power_seq_pwm.c b/drivers/power/power_seq/power_seq_pwm.c
new file mode 100644
index 0000000..a80514f
--- /dev/null
+++ b/drivers/power/power_seq/power_seq_pwm.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifdef CONFIG_PWM
+
+#include <linux/pwm.h>
+
+#ifdef CONFIG_OF
+static int power_seq_of_parse_pwm(struct device *dev,
+				  struct device_node *node,
+				  struct platform_power_seq *seq,
+				  unsigned int step_nbr)
+{
+	struct platform_power_seq_step *step = &seq->steps[step_nbr];
+	int err;
+
+	err = of_property_read_string(node, "id",
+				      &step->pwm.id);
+	if (err) {
+		power_seq_err(dev, seq, step_nbr,
+			      "error reading id property\n");
+		return err;
+	}
+
+	err = of_power_seq_parse_enable_properties(dev, node, seq, step_nbr,
+						   &step->pwm.enable);
+	return err;
+}
+#else
+#define of_power_seq_parse_pwm NULL
+#endif
+
+static bool power_seq_res_compare_pwm(struct platform_power_seq_step *step1,
+				      struct platform_power_seq_step *step2)
+{
+	return (!strcmp(step1->pwm.id, step2->pwm.id));
+}
+
+static int power_seq_res_alloc_pwm(struct device *dev,
+				  struct power_seq_resource *res)
+{
+	res->pwm = devm_pwm_get(dev, res->pdata->pwm.id);
+	if (IS_ERR(res->pwm)) {
+		dev_err(dev, "cannot get pwm \"%s\"\n", res->pdata->pwm.id);
+		return PTR_ERR(res->pwm);
+	}
+
+	return 0;
+}
+
+static int power_seq_step_run_pwm(struct power_seq_step *step)
+{
+	if (step->pdata.gpio.enable) {
+		return pwm_enable(step->resource->pwm);
+	} else {
+		pwm_disable(step->resource->pwm);
+		return 0;
+	}
+}
+
+#define POWER_SEQ_PWM_TYPE {				\
+	.name = "pwm",					\
+	.need_resource = true,				\
+	.of_parse = power_seq_of_parse_pwm,		\
+	.step_run = power_seq_step_run_pwm,		\
+	.res_compare = power_seq_res_compare_pwm,	\
+	.res_alloc = power_seq_res_alloc_pwm,		\
+}
+
+#else
+
+#define POWER_SEQ_PWM_TYPE {}
+
+#endif
diff --git a/drivers/power/power_seq/power_seq_regulator.c b/drivers/power/power_seq/power_seq_regulator.c
new file mode 100644
index 0000000..915eac1
--- /dev/null
+++ b/drivers/power/power_seq/power_seq_regulator.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifdef CONFIG_REGULATOR
+
+#include <linux/regulator/consumer.h>
+
+/* TODO change "which" */
+#ifdef CONFIG_OF
+static int power_seq_of_parse_regulator(struct device *dev,
+					struct device_node *node,
+					struct platform_power_seq *seq,
+					unsigned int step_nbr)
+{
+	struct platform_power_seq_step *step = &seq->steps[step_nbr];
+	int err;
+
+	err = of_property_read_string(node, "id",
+				      &step->regulator.id);
+	if (err) {
+		power_seq_err(dev, seq, step_nbr,
+			      "error reading id property\n");
+		return err;
+	}
+
+	err = of_power_seq_parse_enable_properties(dev, node, seq, step_nbr,
+						   &step->regulator.enable);
+	return err;
+}
+#else
+#define of_power_seq_parse_regulator NULL
+#endif
+
+static bool
+power_seq_res_compare_regulator(struct platform_power_seq_step *step1,
+				struct platform_power_seq_step *step2)
+{
+	return (!strcmp(step1->regulator.id, step2->regulator.id));
+}
+
+static int power_seq_res_alloc_regulator(struct device *dev,
+					struct power_seq_resource *res)
+{
+	res->regulator = devm_regulator_get(dev, res->pdata->regulator.id);
+	if (IS_ERR(res->regulator)) {
+		dev_err(dev, "cannot get regulator \"%s\"\n",
+			res->pdata->regulator.id);
+		return PTR_ERR(res->regulator);
+	}
+
+	return 0;
+}
+
+static int power_seq_step_run_regulator(struct power_seq_step *step)
+{
+	if (step->pdata.regulator.enable)
+		return regulator_enable(step->resource->regulator);
+	else
+		return regulator_disable(step->resource->regulator);
+}
+
+#define POWER_SEQ_REGULATOR_TYPE {			\
+	.name = "regulator",				\
+	.need_resource = true,				\
+	.of_parse = power_seq_of_parse_regulator,	\
+	.step_run = power_seq_step_run_regulator,	\
+	.res_compare = power_seq_res_compare_regulator,	\
+	.res_alloc = power_seq_res_alloc_regulator,	\
+}
+
+#else
+
+#define POWER_SEQ_REGULATOR_TYPE {}
+
+#endif
diff --git a/include/linux/power_seq.h b/include/linux/power_seq.h
new file mode 100644
index 0000000..78e8d77
--- /dev/null
+++ b/include/linux/power_seq.h
@@ -0,0 +1,174 @@
+/*
+ * power_seq.h
+ *
+ * Simple interpreter for defining power sequences as platform data or device
+ * tree properties.
+ *
+ * Power sequences are designed to replace the callbacks typically used in
+ * board-specific files that implement board-specific power sequences of devices
+ * such as backlights. A power sequence is an array of resources (which can a
+ * regulator, a GPIO, a PWM, ...) with an action to perform on it (enable or
+ * disable) and optional pre and post step delays. By having them interpreted
+ * instead of arbitrarily executed, it is possible to describe these in the
+ * device tree and thus remove board-specific code from the kernel.
+ *
+ * Author: Alexandre Courbot <acourbot@nvidia.com>
+ *
+ * Copyright (c) 2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __LINUX_POWER_SEQ_H
+#define __LINUX_POWER_SEQ_H
+
+#include <linux/types.h>
+
+struct device;
+struct regulator;
+struct pwm_device;
+struct device_node;
+
+/**
+ * The different kinds of resources that can be controlled during the sequences.
+ */
+enum power_seq_res_type {
+	POWER_SEQ_DELAY,
+	POWER_SEQ_REGULATOR,
+	POWER_SEQ_PWM,
+	POWER_SEQ_GPIO,
+	POWER_SEQ_NUM_TYPES,
+};
+
+/**
+ * struct platform_power_seq_delay_step - platform data for delay steps
+ * @delay_us:	Amount of time to wait, in microseconds.
+ */
+struct platform_power_seq_delay_step {
+	unsigned int delay_us;
+};
+
+/**
+ * struct platform_power_seq_regulator_step - platform data for regulator steps
+ * @id:		Name of the regulator to use. The regulator will be obtained
+ *		using devm_regulator_get(dev, name)
+ * @enable:	Whether to enable or disable the regulator during this step
+ */
+struct platform_power_seq_regulator_step {
+	const char *id;
+	bool enable;
+};
+
+/**
+ * struct platform_power_seq_pwm_step - platform data for PWM steps
+ * @id:		Name of the pwm to use. The PWM will be obtained using
+ *		devm_pwm_get(dev, name)
+ * @enable:	Whether to enable or disable the PWM during this step
+ */
+struct platform_power_seq_pwm_step {
+	const char *id;
+	bool enable;
+};
+
+/**
+ * struct platform_power_seq_gpio_step - platform data for GPIO steps
+ * @number:	Number of the GPIO to use. The GPIO will be obtained using
+ *		devm_gpio_request_one(dev, number)
+ * @enable:	Whether to enable or disable the GPIO during this step
+ */
+struct platform_power_seq_gpio_step {
+	int number;
+	bool enable;
+};
+
+/**
+ * struct platform_power_seq_step - platform data for power sequences steps
+ * @type:	The type of this step. This decides which member of the union is
+ *		valid for this step.
+ * @delay:	Used if type = POWER_SEQ_DELAY
+ * @regulator:	Used if type = POWER_SEQ_REGULATOR
+ * @pwm:	Used if type = POWER_SEQ_PWN
+ * @gpio:	Used if type = POWER_SEQ_GPIO
+ */
+struct platform_power_seq_step {
+	enum power_seq_res_type type;
+	union {
+		struct platform_power_seq_delay_step delay;
+		struct platform_power_seq_regulator_step regulator;
+		struct platform_power_seq_pwm_step pwm;
+		struct platform_power_seq_gpio_step gpio;
+	};
+};
+
+/**
+ * struct platform_power_seq - platform data for power sequences
+ * @id:		Name through which this sequence is refered
+ * @num_steps:	Number of steps in that sequence
+ * @steps:	Array of num_steps steps describing the sequence
+ */
+struct platform_power_seq {
+	const char *id;
+	unsigned int num_steps;
+	struct platform_power_seq_step steps[];
+};
+
+/**
+ * struct platform_power_seq_set - platform data for sets of sequences
+ * @num_seqs:	Number of sequences in this set
+ * @seqs:	Array of pointers to individual sequences
+ */
+struct platform_power_seq_set {
+	unsigned int num_seqs;
+	struct platform_power_seq* seqs[];
+};
+
+/**
+ * struct power_seq_resource - resource used by a power sequence set
+ * @pdata:	Pointer to the platform data used to resolve this resource
+ * @regulator:	Resolved regulator if of type POWER_SEQ_REGULATOR
+ * @pwm:	Resolved PWM if of type POWER_SEQ_PWM
+ * @list:	Used to link resources together
+ */
+struct power_seq_resource {
+	/* relevant for resolving the resource and knowing its type */
+	struct platform_power_seq_step *pdata;
+	/* resolved resource (if any) */
+	union {
+		struct regulator *regulator;
+		struct pwm_device *pwm;
+	};
+	struct list_head list;
+};
+#define power_seq_for_each_resource(pos, seqs)				\
+	list_for_each_entry(pos, power_seq_set_resources(seqs), list)
+
+struct power_seq_resource;
+struct power_seq;
+struct power_seq_set;
+
+#ifdef CONFIG_OF
+struct platform_power_seq_set *devm_of_parse_power_seq_set(struct device *dev);
+#else
+inline struct platform_power_seq_set *of_parse_power_seq_set(struct device *dev)
+{
+	return NULL;
+}
+#endif
+void devm_platform_power_seq_set_free(struct device *dev,
+				      struct platform_power_seq_set *pseq);
+
+struct power_seq_set *devm_power_seq_set_build(struct device *dev,
+					   struct platform_power_seq_set *pseq);
+struct list_head *power_seq_set_resources(struct power_seq_set *seqs);
+struct power_seq *power_seq_lookup(struct power_seq_set *seqs, const char *id);
+int power_seq_run(struct power_seq *seq);
+
+#endif
-- 
1.7.12


^ permalink raw reply related

* [PATCH v5 2/4] pwm_backlight: use power sequences
From: Alexandre Courbot @ 2012-08-31 11:34 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Simon Glass, Grant Likely,
	Rob Herring, Mark Brown, Anton Vorontsov, David Woodhouse,
	Arnd Bergmann
  Cc: linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1346412846-17102-1-git-send-email-acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

Make use of the power sequences specified in the device tree or platform
data to control how the backlight is powered on and off.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
 .../bindings/video/backlight/pwm-backlight.txt     |  67 +++++++-
 drivers/video/backlight/Kconfig                    |   1 +
 drivers/video/backlight/pwm_bl.c                   | 179 +++++++++++++++------
 include/linux/pwm_backlight.h                      |  15 +-
 4 files changed, 208 insertions(+), 54 deletions(-)

diff --git a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt
index 1e4fc72..873b993 100644
--- a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt
+++ b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt
@@ -2,7 +2,8 @@ pwm-backlight bindings
 
 Required properties:
   - compatible: "pwm-backlight"
-  - pwms: OF device-tree PWM specification (see PWM binding[0])
+  - pwms: OF device-tree PWM specification (see PWM binding[0]). Exactly one PWM
+      must be specified
   - brightness-levels: Array of distinct brightness levels. Typically these
       are in the range from 0 to 255, but any range starting at 0 will do.
       The actual brightness level (PWM duty cycle) will be interpolated
@@ -12,17 +13,73 @@ Required properties:
       array defined by the "brightness-levels" property)
 
 Optional properties:
-  - pwm-names: a list of names for the PWM devices specified in the
-               "pwms" property (see PWM binding[0])
+  - pwm-names: name for the PWM device specified in the "pwms" property (see PWM
+      binding[0]). Necessary if power sequences are used
+  - power-sequences: Power sequences (see Power sequences[1]) used to bring the
+      backlight on and off. If this property is present, then two power
+      sequences named "power-on" and "power-off" must be defined to control how
+      the backlight is to be powered on and off. These sequences must reference
+      the PWM specified in the pwms property by its name, and can also reference
+      other resources supported by the power sequences mechanism
 
 [0]: Documentation/devicetree/bindings/pwm/pwm.txt
+[1]: Documentation/devicetree/bindings/power_seq/power_seq.txt
 
 Example:
 
 	backlight {
 		compatible = "pwm-backlight";
-		pwms = <&pwm 0 5000000>;
-
 		brightness-levels = <0 4 8 16 32 64 128 255>;
 		default-brightness-level = <6>;
+
+		/* resources used by the sequences */
+		pwms = <&pwm 2 5000000>;
+		pwm-names = "backlight";
+		power-supply = <&backlight_reg>;
+
+		power-sequences {
+			power-on {
+				step0 {
+					type = "regulator";
+					id = "power";
+					enable;
+				};
+				step1 {
+					type = "delay";
+					delay_us = <10000>;
+				};
+				step2 {
+					type = "pwm";
+					id = "backlight";
+					enable;
+				};
+				step3 {
+					type = "gpio";
+					number = <&gpio 28 0>;
+					enable;
+				};
+			};
+
+			power-off {
+				step0 {
+					type = "gpio";
+					number = <&gpio 28 0>;
+					disable;
+				};
+				step1 {
+					type = "pwm";
+					id = "backlight";
+					disable;
+				};
+				step2 {
+					type = "delay";
+					delay_us = <10000>;
+				};
+				step3 {
+					type = "regulator";
+					id = "power";
+					disable;
+				};
+			};
+		};
 	};
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index cf28276..6fb8aa3 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -246,6 +246,7 @@ config BACKLIGHT_CARILLO_RANCH
 config BACKLIGHT_PWM
 	tristate "Generic PWM based Backlight Driver"
 	depends on PWM
+	select POWER_SEQ
 	help
 	  If you have a LCD backlight adjustable by PWM, say Y to enable
 	  this driver.
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 995f016..45d6edd 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -27,6 +27,12 @@ struct pwm_bl_data {
 	unsigned int		period;
 	unsigned int		lth_brightness;
 	unsigned int		*levels;
+	bool			enabled;
+	bool			use_power_seqs;
+	struct power_seq	*power_on_seq;
+	struct power_seq	*power_off_seq;
+
+	/* Legacy callbacks */
 	int			(*notify)(struct device *,
 					  int brightness);
 	void			(*notify_after)(struct device *,
@@ -35,6 +41,49 @@ struct pwm_bl_data {
 	void			(*exit)(struct device *);
 };
 
+static void pwm_backlight_on(struct backlight_device *bl)
+{
+	struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
+	int ret;
+
+	if (pb->enabled)
+		return;
+
+	/* Legacy framework? */
+	if (!pb->use_power_seqs) {
+		pwm_config(pb->pwm, 0, pb->period);
+		pwm_disable(pb->pwm);
+		return;
+	}
+
+	ret = power_seq_run(pb->power_on_seq);
+	if (ret < 0)
+		dev_err(&bl->dev, "cannot run power on sequence\n");
+
+	pb->enabled = true;
+}
+
+static void pwm_backlight_off(struct backlight_device *bl)
+{
+	struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
+	int ret;
+
+	if (!pb->enabled)
+		return;
+
+	/* Legacy framework? */
+	if (!pb->use_power_seqs) {
+		pwm_enable(pb->pwm);
+		return;
+	}
+
+	ret = power_seq_run(pb->power_off_seq);
+	if (ret < 0)
+		dev_err(&bl->dev, "cannot run power off sequence\n");
+
+	pb->enabled = false;
+}
+
 static int pwm_backlight_update_status(struct backlight_device *bl)
 {
 	struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
@@ -51,8 +100,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
 		brightness = pb->notify(pb->dev, brightness);
 
 	if (brightness = 0) {
-		pwm_config(pb->pwm, 0, pb->period);
-		pwm_disable(pb->pwm);
+		pwm_backlight_off(bl);
 	} else {
 		int duty_cycle;
 
@@ -66,7 +114,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
 		duty_cycle = pb->lth_brightness +
 		     (duty_cycle * (pb->period - pb->lth_brightness) / max);
 		pwm_config(pb->pwm, duty_cycle, pb->period);
-		pwm_enable(pb->pwm);
+		pwm_backlight_on(bl);
 	}
 
 	if (pb->notify_after)
@@ -145,11 +193,10 @@ static int pwm_backlight_parse_dt(struct device *dev,
 		data->max_brightness--;
 	}
 
-	/*
-	 * TODO: Most users of this driver use a number of GPIOs to control
-	 *       backlight power. Support for specifying these needs to be
-	 *       added.
-	 */
+	/* parse power sequences and extract those we will use */
+	data->power_seqs = devm_of_parse_power_seq_set(dev);
+	if (IS_ERR(data->power_seqs))
+		return PTR_ERR(data->power_seqs);
 
 	return 0;
 }
@@ -172,33 +219,96 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 {
 	struct platform_pwm_backlight_data *data = pdev->dev.platform_data;
 	struct platform_pwm_backlight_data defdata;
+	struct power_seq_resource *res;
 	struct backlight_properties props;
 	struct backlight_device *bl;
 	struct pwm_bl_data *pb;
+	bool use_dt = false;
 	unsigned int max;
 	int ret;
 
+	pb = devm_kzalloc(&pdev->dev, sizeof(*pb), GFP_KERNEL);
+	if (!pb) {
+		dev_err(&pdev->dev, "no memory for state\n");
+		return -ENOMEM;
+	}
+
+	/* using new interface or device tree */
 	if (!data) {
+		/* build platform data from device tree */
 		ret = pwm_backlight_parse_dt(&pdev->dev, &defdata);
-		if (ret < 0) {
+		if (ret = -EPROBE_DEFER) {
+			return ret;
+		} else if (ret < 0) {
 			dev_err(&pdev->dev, "failed to find platform data\n");
 			return ret;
 		}
-
 		data = &defdata;
+		use_dt = true;
+	}
+
+	/* using legacy interface? */
+	if (!data->power_seqs) {
+		pb->pwm = devm_pwm_get(&pdev->dev, NULL);
+		if (IS_ERR(pb->pwm)) {
+			dev_err(&pdev->dev,
+				"unable to request PWM, trying legacy API\n");
+
+			pb->pwm = pwm_request(data->pwm_id, "pwm-backlight");
+			if (IS_ERR(pb->pwm)) {
+				dev_err(&pdev->dev,
+					"unable to request legacy PWM\n");
+				return PTR_ERR(pb->pwm);
+			}
+		}
+
+		/*
+		* The DT case will set the pwm_period_ns field to 0 and store
+		* the period, parsed from the DT, in the PWM device. For the
+		* non-DT case, set the period from platform data.
+		*/
+		if (data->pwm_period_ns > 0)
+			pwm_set_period(pb->pwm, data->pwm_period_ns);
+	} else {
+		/* build power sequences from platform data */
+		struct power_seq_set *seqs;
+
+		seqs = devm_power_seq_set_build(&pdev->dev, data->power_seqs);
+		if (IS_ERR(seqs))
+			return PTR_ERR(seqs);
+
+		if (use_dt)
+			devm_platform_power_seq_set_free(&pdev->dev,
+							 data->power_seqs);
+
+		pb->power_on_seq = power_seq_lookup(seqs, "power-on");
+		pb->power_off_seq = power_seq_lookup(seqs, "power-off");
+
+		/* we must have exactly one PWM for this driver */
+		power_seq_for_each_resource(res, seqs) {
+			if (res->pdata->type != POWER_SEQ_PWM)
+				continue;
+			if (pb->pwm) {
+				dev_err(&pdev->dev, "more than one PWM used\n");
+				return -EINVAL;
+			}
+			/* keep the pwm at hand */
+			pb->pwm = res->pwm;
+		}
+
+		pb->use_power_seqs = true;
 	}
 
 	if (data->init) {
 		ret = data->init(&pdev->dev);
 		if (ret < 0)
-			return ret;
+			goto err;
 	}
 
-	pb = devm_kzalloc(&pdev->dev, sizeof(*pb), GFP_KERNEL);
-	if (!pb) {
-		dev_err(&pdev->dev, "no memory for state\n");
-		ret = -ENOMEM;
-		goto err_alloc;
+	/* from here we should have a PWM */
+	if (!pb->pwm) {
+		dev_err(&pdev->dev, "no PWM defined!\n");
+		return -EINVAL;
 	}
 
 	if (data->levels) {
@@ -213,28 +323,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 	pb->exit = data->exit;
 	pb->dev = &pdev->dev;
 
-	pb->pwm = pwm_get(&pdev->dev, NULL);
-	if (IS_ERR(pb->pwm)) {
-		dev_err(&pdev->dev, "unable to request PWM, trying legacy API\n");
-
-		pb->pwm = pwm_request(data->pwm_id, "pwm-backlight");
-		if (IS_ERR(pb->pwm)) {
-			dev_err(&pdev->dev, "unable to request legacy PWM\n");
-			ret = PTR_ERR(pb->pwm);
-			goto err_alloc;
-		}
-	}
-
-	dev_dbg(&pdev->dev, "got pwm for backlight\n");
-
-	/*
-	 * The DT case will set the pwm_period_ns field to 0 and store the
-	 * period, parsed from the DT, in the PWM device. For the non-DT case,
-	 * set the period from platform data.
-	 */
-	if (data->pwm_period_ns > 0)
-		pwm_set_period(pb->pwm, data->pwm_period_ns);
-
 	pb->period = pwm_get_period(pb->pwm);
 	pb->lth_brightness = data->lth_brightness * (pb->period / max);
 
@@ -246,18 +334,17 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 	if (IS_ERR(bl)) {
 		dev_err(&pdev->dev, "failed to register backlight\n");
 		ret = PTR_ERR(bl);
-		goto err_bl;
+		goto err;
 	}
 
 	bl->props.brightness = data->dft_brightness;
 	backlight_update_status(bl);
 
 	platform_set_drvdata(pdev, bl);
+
 	return 0;
 
-err_bl:
-	pwm_put(pb->pwm);
-err_alloc:
+err:
 	if (data->exit)
 		data->exit(&pdev->dev);
 	return ret;
@@ -269,9 +356,8 @@ static int pwm_backlight_remove(struct platform_device *pdev)
 	struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
 
 	backlight_device_unregister(bl);
-	pwm_config(pb->pwm, 0, pb->period);
-	pwm_disable(pb->pwm);
-	pwm_put(pb->pwm);
+	pwm_backlight_off(bl);
+
 	if (pb->exit)
 		pb->exit(&pdev->dev);
 	return 0;
@@ -285,8 +371,7 @@ static int pwm_backlight_suspend(struct device *dev)
 
 	if (pb->notify)
 		pb->notify(pb->dev, 0);
-	pwm_config(pb->pwm, 0, pb->period);
-	pwm_disable(pb->pwm);
+	pwm_backlight_off(bl);
 	if (pb->notify_after)
 		pb->notify_after(pb->dev, 0);
 	return 0;
diff --git a/include/linux/pwm_backlight.h b/include/linux/pwm_backlight.h
index 56f4a86..70d22f2 100644
--- a/include/linux/pwm_backlight.h
+++ b/include/linux/pwm_backlight.h
@@ -5,14 +5,25 @@
 #define __LINUX_PWM_BACKLIGHT_H
 
 #include <linux/backlight.h>
+#include <linux/power_seq.h>
 
 struct platform_pwm_backlight_data {
-	int pwm_id;
 	unsigned int max_brightness;
 	unsigned int dft_brightness;
 	unsigned int lth_brightness;
-	unsigned int pwm_period_ns;
 	unsigned int *levels;
+	/*
+	 * New interface using power sequences
+	 */
+	struct platform_power_seq_set *power_seqs;
+	/*
+	 * Legacy interface - use power sequences instead!
+	 *
+	 * pwm_id and pwm_period_ns need only be specified
+	 * if get_pwm(dev, NULL) would return NULL.
+	 */
+	int pwm_id;
+	unsigned int pwm_period_ns;
 	int (*init)(struct device *dev);
 	int (*notify)(struct device *dev, int brightness);
 	void (*notify_after)(struct device *dev, int brightness);
-- 
1.7.12


^ permalink raw reply related

* [PATCH v5 3/4] tegra: dt: add label to tegra20's PWM
From: Alexandre Courbot @ 2012-08-31 11:34 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Simon Glass, Grant Likely,
	Rob Herring, Mark Brown, Anton Vorontsov, David Woodhouse,
	Arnd Bergmann
  Cc: linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1346412846-17102-1-git-send-email-acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

This is necessary to reference the PWM in board device trees.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
 arch/arm/boot/dts/tegra20.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index 405d167..67a6cd9 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -123,7 +123,7 @@
 		status = "disabled";
 	};
 
-	pwm {
+	pwm: pwm {
 		compatible = "nvidia,tegra20-pwm";
 		reg = <0x7000a000 0x100>;
 		#pwm-cells = <2>;
-- 
1.7.12


^ permalink raw reply related

* [PATCH v5 4/4] tegra: ventana: add pwm backlight DT nodes
From: Alexandre Courbot @ 2012-08-31 11:34 UTC (permalink / raw)
  To: Stephen Warren, Thierry Reding, Simon Glass, Grant Likely,
	Rob Herring, Mark Brown, Anton Vorontsov, David Woodhouse,
	Arnd Bergmann
  Cc: Leela Krishna Amudala, linux-tegra, linux-kernel, linux-fbdev,
	devicetree-discuss, linux-pm, linux-doc, Alexandre Courbot
In-Reply-To: <1346412846-17102-1-git-send-email-acourbot@nvidia.com>

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
 arch/arm/boot/dts/tegra20-ventana.dts | 59 ++++++++++++++++++++++++++++++++++-
 1 file changed, 58 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/tegra20-ventana.dts b/arch/arm/boot/dts/tegra20-ventana.dts
index 4ec6b4c..025928d 100644
--- a/arch/arm/boot/dts/tegra20-ventana.dts
+++ b/arch/arm/boot/dts/tegra20-ventana.dts
@@ -467,6 +467,63 @@
 		bus-width = <8>;
 	};
 
+	backlight {
+		compatible = "pwm-backlight";
+		brightness-levels = <0 16 32 48 64 80 96 112 128 144 160 176 192 208 224 240 255>;
+		default-brightness-level = <12>;
+
+		/* resources used by the power sequences */
+		pwms = <&pwm 2 5000000>;
+		pwm-names = "backlight";
+		power-supply = <&vdd_bl_reg>;
+
+		power-sequences {
+			power-on {
+				step0 {
+					type = "regulator";
+					id = "power";
+					enable;
+				};
+				step1 {
+					type = "delay";
+					delay_us = <10000>;
+				};
+				step2 {
+					type = "pwm";
+					id = "backlight";
+					enable;
+				};
+				step3 {
+					type = "gpio";
+					number = <&gpio 28 0>;
+					enable;
+				};
+			};
+
+			power-off {
+				step0 {
+					type = "gpio";
+					number = <&gpio 28 0>;
+					disable;
+				};
+				step1 {
+					type = "pwm";
+					id = "backlight";
+					disable;
+				};
+				step2 {
+					type = "delay";
+					delay_us = <10000>;
+				};
+				step3 {
+					type = "regulator";
+					id = "power";
+					disable;
+				};
+			};
+		};
+	};
+
 	regulators {
 		compatible = "simple-bus";
 		#address-cells = <1>;
@@ -510,7 +567,7 @@
 			enable-active-high;
 		};
 
-		regulator@4 {
+		vdd_bl_reg: regulator@4 {
 			compatible = "regulator-fixed";
 			reg = <4>;
 			regulator-name = "vdd_bl";
-- 
1.7.12


^ permalink raw reply related

* [PATCH] video: s3c2410fb: Use pr_* and dev_* instead of printk
From: Sachin Kamat @ 2012-08-31 11:52 UTC (permalink / raw)
  To: linux-fbdev

printk calls are replaced by pr_* and dev_* calls to silence
checkpatch warnings.

Signed-off-by: Sachin Kamat <sachin.kamat@linaro.org>
---
 drivers/video/s3c2410fb.c |   18 ++++++++++--------
 1 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index 77f34c6..a54e3f9 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -11,6 +11,8 @@
  * Driver based on skeletonfb.c, sa1100fb.c and others.
 */
 
+#define pr_fmt(fmt) "s3c2410fb: " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/err.h>
@@ -48,7 +50,7 @@ static int debug	= 1;
 static int debug;
 #endif
 
-#define dprintk(msg...)	if (debug) printk(KERN_DEBUG "s3c2410fb: " msg);
+#define dprintk(msg...)	if (debug) pr_debug(msg);
 
 /* useful functions */
 
@@ -598,11 +600,11 @@ static int s3c2410fb_debug_store(struct device *dev,
 	if (strnicmp(buf, "on", 2) = 0 ||
 	    strnicmp(buf, "1", 1) = 0) {
 		debug = 1;
-		printk(KERN_DEBUG "s3c2410fb: Debug On");
+		dev_dbg(dev, "s3c2410fb: Debug On");
 	} else if (strnicmp(buf, "off", 3) = 0 ||
 		   strnicmp(buf, "0", 1) = 0) {
 		debug = 0;
-		printk(KERN_DEBUG "s3c2410fb: Debug Off");
+		dev_dbg(dev, "s3c2410fb: Debug Off");
 	} else {
 		return -EINVAL;
 	}
@@ -921,7 +923,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
 
 	info->clk = clk_get(NULL, "lcd");
 	if (IS_ERR(info->clk)) {
-		printk(KERN_ERR "failed to get lcd clock source\n");
+		dev_err(&pdev->dev, "failed to get lcd clock source\n");
 		ret = PTR_ERR(info->clk);
 		goto release_irq;
 	}
@@ -947,7 +949,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
 	/* Initialize video memory */
 	ret = s3c2410fb_map_video_memory(fbinfo);
 	if (ret) {
-		printk(KERN_ERR "Failed to allocate video RAM: %d\n", ret);
+		dev_err(&pdev->dev, "Failed to allocate video RAM: %d\n", ret);
 		ret = -ENOMEM;
 		goto release_clock;
 	}
@@ -970,7 +972,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
 
 	ret = register_framebuffer(fbinfo);
 	if (ret < 0) {
-		printk(KERN_ERR "Failed to register framebuffer device: %d\n",
+		dev_err(&pdev->dev, "Failed to register framebuffer device: %d\n",
 			ret);
 		goto free_cpufreq;
 	}
@@ -978,9 +980,9 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
 	/* create device files */
 	ret = device_create_file(&pdev->dev, &dev_attr_debug);
 	if (ret)
-		printk(KERN_ERR "failed to add debug attribute\n");
+		dev_err(&pdev->dev, "failed to add debug attribute\n");
 
-	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+	dev_info(&pdev->dev, "fb%d: %s frame buffer device\n",
 		fbinfo->node, fbinfo->fix.id);
 
 	return 0;
-- 
1.7.4.1


^ permalink raw reply related

* Re: [PATCH v2 02/23] OMAPDSS: outputs: Create and register output instances
From: Tomi Valkeinen @ 2012-08-31 11:57 UTC (permalink / raw)
  To: Archit Taneja; +Cc: rob, linux-omap, linux-fbdev
In-Reply-To: <1346326845-16583-3-git-send-email-archit@ti.com>

[-- Attachment #1: Type: text/plain, Size: 2480 bytes --]

On Thu, 2012-08-30 at 17:10 +0530, Archit Taneja wrote:
> Add output structs to output driver's private data. Register output instances by
> having an init function in the probes of the platform device drivers for
> different outputs. The *_init_output for each output registers the output and
> fill up the output's plaform device, type and id fields.
> 
> In the probe of each interface driver, the output entities are initialized
> before the *_probe_pdata() functions intentionally. This is done to ensure that
> the output entity is prepared before the panels connected to the output are
> registered. We need the output entities to be ready because OMAPDSS will try
> to make connections between overlays, managers, outputs and devices during the
> panel's probe.
> 
> Signed-off-by: Archit Taneja <archit@ti.com>
> ---
>  drivers/video/omap2/dss/dpi.c  |   15 +++++++++++++++
>  drivers/video/omap2/dss/dsi.c  |   18 ++++++++++++++++++
>  drivers/video/omap2/dss/hdmi.c |   15 +++++++++++++++
>  drivers/video/omap2/dss/rfbi.c |   17 +++++++++++++++++
>  drivers/video/omap2/dss/sdi.c  |   15 +++++++++++++++
>  drivers/video/omap2/dss/venc.c |   15 +++++++++++++++
>  6 files changed, 95 insertions(+)
> 
> diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
> index 25fb895..9a7aee5 100644
> --- a/drivers/video/omap2/dss/dpi.c
> +++ b/drivers/video/omap2/dss/dpi.c
> @@ -45,6 +45,8 @@ static struct {
>  	struct omap_video_timings timings;
>  	struct dss_lcd_mgr_config mgr_config;
>  	int data_lines;
> +
> +	struct omap_dss_output output;
>  } dpi;
>  
>  static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk)
> @@ -410,10 +412,23 @@ static void __init dpi_probe_pdata(struct platform_device *pdev)
>  	}
>  }
>  
> +static void __init dpi_init_output(struct platform_device *pdev)
> +{
> +	struct omap_dss_output *out = &dpi.output;
> +
> +	dss_register_output(out);
> +
> +	out->pdev = pdev;
> +	out->id = OMAP_DSS_OUTPUT_DPI;
> +	out->type = OMAP_DISPLAY_TYPE_DPI;
> +}

I think you should first initialize the output, and then register it.
Not the other way around.

I believe you need to implement unregister also. Normally unregister
won't be done, but the probe of an output driver can fail after the
output has been registered, and thus the output needs to be unregistered
at cleanup.

And it doesn't harm to unregister at the driver's remove.

 Tomi


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH v2 03/23] OMAPDSS: output: Add set/unset device ops for omap_dss_output
From: Tomi Valkeinen @ 2012-08-31 12:03 UTC (permalink / raw)
  To: Archit Taneja; +Cc: rob, linux-omap, linux-fbdev
In-Reply-To: <1346326845-16583-4-git-send-email-archit@ti.com>

[-- Attachment #1: Type: text/plain, Size: 3243 bytes --]

On Thu, 2012-08-30 at 17:10 +0530, Archit Taneja wrote:
> An output entity represented by the struct omap_dss_output connects to a
> omap_dss_device entity. Add functions to set or unset an output's device. This
> is similar to how managers and devices were connected previously. An output can
> connect to a device without being connected to a manager. However, the output
> needs to eventually connect to a manager so that the connected panel can be
> enabled.
> 
> Keep the omap_overlay_manager pointer in omap_dss_device for now to prevent
> breaking things. This will be removed later when outputs are supported
> completely.
> 
> Signed-off-by: Archit Taneja <archit@ti.com>
> ---
>  drivers/video/omap2/dss/output.c |   67 ++++++++++++++++++++++++++++++++++++++
>  include/video/omapdss.h          |    5 +++
>  2 files changed, 72 insertions(+)
> 
> diff --git a/drivers/video/omap2/dss/output.c b/drivers/video/omap2/dss/output.c
> index 7d81be5..abc3aa2 100644
> --- a/drivers/video/omap2/dss/output.c
> +++ b/drivers/video/omap2/dss/output.c
> @@ -24,9 +24,76 @@
>  #include "dss.h"
>  
>  static LIST_HEAD(output_list);
> +static DEFINE_MUTEX(output_lock);
> +
> +static int dss_output_set_device(struct omap_dss_output *out,
> +		struct omap_dss_device *dssdev)
> +{
> +	int r;
> +
> +	mutex_lock(&output_lock);
> +
> +	if (out->device) {
> +		DSSERR("output already has device %s connected to it\n",
> +			out->device->name);
> +		r = -EINVAL;
> +		goto err;
> +	}
> +
> +	if (out->type != dssdev->type) {
> +		DSSERR("output type and display type don't match\n");
> +		r = -EINVAL;
> +		goto err;
> +	}
> +
> +	out->device = dssdev;
> +	dssdev->output = out;
> +
> +	mutex_unlock(&output_lock);
> +
> +	return 0;
> +err:
> +	mutex_unlock(&output_lock);
> +
> +	return r;
> +}
> +
> +static int dss_output_unset_device(struct omap_dss_output *out)
> +{
> +	int r;
> +
> +	mutex_lock(&output_lock);
> +
> +	if (!out->device) {
> +		DSSERR("output doesn't have a device connected to it\n");
> +		r = -EINVAL;
> +		goto err;
> +	}
> +
> +	if (out->device->state != OMAP_DSS_DISPLAY_DISABLED) {
> +		DSSERR("device %s is not disabled, cannot unset device\n",
> +				out->device->name);
> +		r = -EINVAL;
> +		goto err;
> +	}
> +
> +	out->device->output = NULL;
> +	out->device = NULL;
> +
> +	mutex_unlock(&output_lock);
> +
> +	return 0;
> +err:
> +	mutex_unlock(&output_lock);
> +
> +	return r;
> +}
>  
>  void dss_register_output(struct omap_dss_output *out)
>  {
> +	out->set_device = &dss_output_set_device;
> +	out->unset_device = &dss_output_unset_device;
> +
>  	list_add_tail(&out->list, &output_list);
>  }

I don't think there's need for this indirection. We should use function
pointers only when the func pointer may lead to different functions.
Here we'll always have just one function, dss_output_set_device. We can
as well call the function directly.

I know we have similar func pointers for ovls/mgrs currently, but I
don't think they are good either. They are a relic from the time we
supported "virtual" overlays and managers, and thus could have different
implementations for the operations.

 Tomi


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH v2 06/23] OMAP_VOUT: Remove manager->device references
From: Tomi Valkeinen @ 2012-08-31 12:11 UTC (permalink / raw)
  To: Archit Taneja; +Cc: rob, linux-omap, linux-fbdev, Vaibhav Hiremath
In-Reply-To: <1346326845-16583-7-git-send-email-archit@ti.com>

[-- Attachment #1: Type: text/plain, Size: 700 bytes --]

On Thu, 2012-08-30 at 17:10 +0530, Archit Taneja wrote:
> With the introduction of output entities, managers will now connect to outputs.
> Use the helper op for managers named get_device. This will abstract away the
> information on how to get the device from an overlay manager.
> 
> Using the helper function will reduce the number of pointer dereferences a user
> of OMAPDSS needs to do and reduce risk of a NULL dereference.

Almost all the uses here seem to be getting the dssdev from an overlay.
Would it make sense to implement get_device for an ovl? That would
reduce all the ovl->manager ? ovl->manager->get_device(ovl->manager) :
NULL; code to ovl->get_device(ovl).

 Tomi


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH v2 02/23] OMAPDSS: outputs: Create and register output instances
From: Archit Taneja @ 2012-08-31 12:15 UTC (permalink / raw)
  To: Tomi Valkeinen; +Cc: Archit Taneja, rob, linux-omap, linux-fbdev
In-Reply-To: <1346414265.18766.9.camel@lappyti>

On Friday 31 August 2012 05:27 PM, Tomi Valkeinen wrote:
> On Thu, 2012-08-30 at 17:10 +0530, Archit Taneja wrote:
>> Add output structs to output driver's private data. Register output instances by
>> having an init function in the probes of the platform device drivers for
>> different outputs. The *_init_output for each output registers the output and
>> fill up the output's plaform device, type and id fields.
>>
>> In the probe of each interface driver, the output entities are initialized
>> before the *_probe_pdata() functions intentionally. This is done to ensure that
>> the output entity is prepared before the panels connected to the output are
>> registered. We need the output entities to be ready because OMAPDSS will try
>> to make connections between overlays, managers, outputs and devices during the
>> panel's probe.
>>
>> Signed-off-by: Archit Taneja <archit@ti.com>
>> ---
>>   drivers/video/omap2/dss/dpi.c  |   15 +++++++++++++++
>>   drivers/video/omap2/dss/dsi.c  |   18 ++++++++++++++++++
>>   drivers/video/omap2/dss/hdmi.c |   15 +++++++++++++++
>>   drivers/video/omap2/dss/rfbi.c |   17 +++++++++++++++++
>>   drivers/video/omap2/dss/sdi.c  |   15 +++++++++++++++
>>   drivers/video/omap2/dss/venc.c |   15 +++++++++++++++
>>   6 files changed, 95 insertions(+)
>>
>> diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
>> index 25fb895..9a7aee5 100644
>> --- a/drivers/video/omap2/dss/dpi.c
>> +++ b/drivers/video/omap2/dss/dpi.c
>> @@ -45,6 +45,8 @@ static struct {
>>   	struct omap_video_timings timings;
>>   	struct dss_lcd_mgr_config mgr_config;
>>   	int data_lines;
>> +
>> +	struct omap_dss_output output;
>>   } dpi;
>>
>>   static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk)
>> @@ -410,10 +412,23 @@ static void __init dpi_probe_pdata(struct platform_device *pdev)
>>   	}
>>   }
>>
>> +static void __init dpi_init_output(struct platform_device *pdev)
>> +{
>> +	struct omap_dss_output *out = &dpi.output;
>> +
>> +	dss_register_output(out);
>> +
>> +	out->pdev = pdev;
>> +	out->id = OMAP_DSS_OUTPUT_DPI;
>> +	out->type = OMAP_DISPLAY_TYPE_DPI;
>> +}
>
> I think you should first initialize the output, and then register it.
> Not the other way around.

Ok.

>
> I believe you need to implement unregister also. Normally unregister
> won't be done, but the probe of an output driver can fail after the
> output has been registered, and thus the output needs to be unregistered
> at cleanup.

Ah, right.

>
> And it doesn't harm to unregister at the driver's remove.

I'll fix these, thanks.

Archit


^ permalink raw reply

* Re: [PATCH v2 03/23] OMAPDSS: output: Add set/unset device ops for omap_dss_output
From: Tomi Valkeinen @ 2012-08-31 12:28 UTC (permalink / raw)
  To: Archit Taneja; +Cc: rob, linux-omap, linux-fbdev
In-Reply-To: <5040ACE1.8080502@ti.com>

[-- Attachment #1: Type: text/plain, Size: 1008 bytes --]

On Fri, 2012-08-31 at 17:54 +0530, Archit Taneja wrote:
> On Friday 31 August 2012 05:33 PM, Tomi Valkeinen wrote:

> > I don't think there's need for this indirection. We should use function
> > pointers only when the func pointer may lead to different functions.
> > Here we'll always have just one function, dss_output_set_device. We can
> > as well call the function directly.
> 
> Okay. I understand that. But in general, don't func pointers prevent us 
> from exporting more symbols?

Yes. But I'm not sure if there's any real downside to exporting, as long
as the names are prefixed properly so that there are no name clashes.

> > I know we have similar func pointers for ovls/mgrs currently, but I
> > don't think they are good either. They are a relic from the time we
> > supported "virtual" overlays and managers, and thus could have different
> > implementations for the operations.
> 
> Oh okay, I guess you mean the L4/sDMA updates for DSI command mode.

Yep.

 Tomi


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox