@@ -27,6 +27,7 @@
#include <linux/clk.h>
#include <linux/mutex.h>
#include <linux/dma/ipu-dma.h>
+#include <linux/regulator/consumer.h>
#include <linux/platform_data/dma-imx.h>
#include <linux/platform_data/video-mx3fb.h>
@@ -269,6 +270,7 @@ struct mx3fb_info {
struct dma_async_tx_descriptor *txd;
dma_cookie_t cookie;
struct scatterlist sg[2];
+ struct regulator *reg_lcd;
struct fb_var_screeninfo cur_var; /* current var info */
};
@@ -1005,6 +1007,7 @@ static void __blank(int blank, struct fb_info *fbi)
struct mx3fb_info *mx3_fbi = fbi->par;
struct mx3fb_data *mx3fb = mx3_fbi->mx3fb;
int was_blank = mx3_fbi->blank;
+ int ret;
mx3_fbi->blank = blank;
@@ -1023,6 +1026,15 @@ static void __blank(int blank, struct fb_info *fbi)
case FB_BLANK_HSYNC_SUSPEND:
case FB_BLANK_NORMAL:
sdc_set_brightness(mx3fb, 0);
+ if (mx3_fbi->reg_lcd) {
+ if (regulator_is_enabled(mx3_fbi->reg_lcd)) {
+ ret = regulator_disable(mx3_fbi->reg_lcd);
+ if (ret)
+ dev_warn(fbi->device,
+ "lcd regulator disable failed with error: %d\n",
+ ret);
+ }
+ }
memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
/* Give LCD time to update - enough for 50 and 60 Hz */
msleep(25);
@@ -1030,6 +1042,15 @@ static void __blank(int blank, struct fb_info *fbi)
break;
case FB_BLANK_UNBLANK:
sdc_enable_channel(mx3_fbi);
+ if (mx3_fbi->reg_lcd) {
+ if (!regulator_is_enabled(mx3_fbi->reg_lcd)) {
+ ret = regulator_enable(mx3_fbi->reg_lcd);
+ if (ret)
+ dev_warn(fbi->device,
+ "lcd regulator enable failed with error: %d\n",
+ ret);
+ }
+ }
sdc_set_brightness(mx3fb, mx3fb->backlight_level);
break;
}
@@ -1206,6 +1227,7 @@ static int mx3fb_suspend(struct platform_device *pdev, pm_message_t state)
{
struct mx3fb_data *mx3fb = platform_get_drvdata(pdev);
struct mx3fb_info *mx3_fbi = mx3fb->fbi->par;
+ int ret;
console_lock();
fb_set_suspend(mx3fb->fbi, 1);
@@ -1214,7 +1236,15 @@ static int mx3fb_suspend(struct platform_device *pdev, pm_message_t state)
if (mx3_fbi->blank == FB_BLANK_UNBLANK) {
sdc_disable_channel(mx3_fbi);
sdc_set_brightness(mx3fb, 0);
-
+ if (mx3_fbi->reg_lcd) {
+ if (regulator_is_enabled(mx3_fbi->reg_lcd)) {
+ ret = regulator_disable(mx3_fbi->reg_lcd);
+ if (ret)
+ dev_warn(&pdev->dev,
+ "lcd regulator disable failed with error: %d\n",
+ ret);
+ }
+ }
}
return 0;
}
@@ -1226,10 +1256,20 @@ static int mx3fb_resume(struct platform_device *pdev)
{
struct mx3fb_data *mx3fb = platform_get_drvdata(pdev);
struct mx3fb_info *mx3_fbi = mx3fb->fbi->par;
+ int ret;
if (mx3_fbi->blank == FB_BLANK_UNBLANK) {
sdc_enable_channel(mx3_fbi);
sdc_set_brightness(mx3fb, mx3fb->backlight_level);
+ if (mx3_fbi->reg_lcd) {
+ if (!regulator_is_enabled(mx3_fbi->reg_lcd)) {
+ ret = regulator_enable(mx3_fbi->reg_lcd);
+ if (ret)
+ dev_warn(&pdev->dev,
+ "lcd regulator enable failed with error: %d\n",
+ ret);
+ }
+ }
}
console_lock();
@@ -1373,6 +1413,7 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan)
struct mx3fb_platform_data *mx3fb_pdata = dev->platform_data;
struct device_node *np = dev->of_node;
const char *name;
+ const char *regulator_name;
const char *ipu_disp_format;
unsigned int irq;
struct fb_info *fbi;
@@ -1389,6 +1430,9 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan)
return -EINVAL;
}
+ of_property_read_string(display_np, "regulator-name",
+ ®ulator_name);
+
of_property_read_string(display_np, "interface-pix-fmt",
&ipu_disp_format);
if (!ipu_disp_format) {
@@ -1503,6 +1547,25 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan)
if (ret < 0)
goto erfb;
+ /* In dt mode,
+ * using devm_regulator_get would require that the proprety referencing
+ * the regulator phandle has to be inside the mx3fb node.
+ */
+ if (np) {
+ if (regulator_name)
+ mx3fbi->reg_lcd = regulator_get(NULL, regulator_name);
+ } else {
+ mx3fbi->reg_lcd = devm_regulator_get(dev, "lcd");
+ }
+
+ if (IS_ERR(mx3fbi->reg_lcd)) {
+ dev_warn(mx3fb->dev, "Operating without regulator \"lcd\"\n");
+ mx3fbi->reg_lcd = NULL;
+ } else {
+ dev_info(mx3fb->dev, "Using \"%s\" Regulator\n",
+ regulator_name);
+ }
+
return 0;
erfb:
@@ -1557,6 +1620,7 @@ static int mx3fb_probe(struct platform_device *pdev)
struct dma_chan *chan;
struct dma_chan_request rq;
struct device_node *np = dev->of_node;
+ struct mx3fb_info *mx3_fbi;
/*
* Display Interface (DI) and Synchronous Display Controller (SDC)
@@ -1621,6 +1685,11 @@ ersdc0:
dmaengine_put();
iounmap(mx3fb->reg_base);
eremap:
+ if (mx3fb->fbi) {
+ mx3_fbi = mx3fb->fbi->par;
+ if (mx3_fbi->reg_lcd)
+ regulator_put(mx3_fbi->reg_lcd);
+ }
kfree(mx3fb);
dev_err(dev, "mx3fb: failed to register fb\n");
return ret;
This commit is based on the following commit by Fabio Estevam: 4344429 video: mxsfb: Introduce regulator support Cc: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com> Cc: Tomi Valkeinen <tomi.valkeinen@ti.com> Cc: linux-fbdev@vger.kernel.org Cc: Sascha Hauer <kernel@pengutronix.de> Cc: Shawn Guo <shawn.guo@linaro.org> Cc: linux-arm-kernel@lists.infradead.org Cc: Eric BĂ©nard <eric@eukrea.com> Signed-off-by: Denis Carikli <denis@eukrea.com> --- ChangeLog v4->v5: - Added Shawn Guo in the Cc list. - Rebased to make it apply. ChangeLog v3->v4: - Some code style fixes. - Improved error handling in eremap. ChangeLog v2->v3: - The prints are now replaced with non line wrapped prints. - The regulator retrival has been adapted to the new DT bindings which looks more like the IPUv3 ones. - The regulator_is_enabled checks were kept, because regulator_disable do not do such check. --- drivers/video/mx3fb.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-)