summaryrefslogtreecommitdiff
path: root/drivers/video
diff options
context:
space:
mode:
authorHyungwon Hwang <human.hwang@samsung.com>2013-08-02 17:09:48 +0900
committerChanho Park <chanho61.park@samsung.com>2014-11-18 11:43:57 +0900
commita76b1878856e6fdea50085adea1d155c4159e991 (patch)
tree48631298153c601677b6a2582e198484a0531541 /drivers/video
parent1c852da45f98678e75c14f6fcc87fb9a5416ebab (diff)
downloadlinux-3.10-a76b1878856e6fdea50085adea1d155c4159e991.tar.gz
linux-3.10-a76b1878856e6fdea50085adea1d155c4159e991.tar.bz2
linux-3.10-a76b1878856e6fdea50085adea1d155c4159e991.zip
DT: support l5f31188 panel
Signed-off-by: Hyungwon Hwang <human.hwang@samsung.com>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/display/Kconfig5
-rw-r--r--drivers/video/display/Makefile1
-rw-r--r--drivers/video/display/panel-l5f31188.c674
3 files changed, 680 insertions, 0 deletions
diff --git a/drivers/video/display/Kconfig b/drivers/video/display/Kconfig
index 49f6dab34b2..f0ab8d2d64e 100644
--- a/drivers/video/display/Kconfig
+++ b/drivers/video/display/Kconfig
@@ -13,6 +13,11 @@ config DISPLAY_PANEL_S6E8AA0
tristate "S6E8AA0 DSI video mode panel"
select OF_VIDEOMODE
+config DISPLAY_PANEL_L5F31188
+ tristate "L5F31188 DSI video mode panel"
+ depends on OF
+ select VIDEOMODE_HELPERS
+
config DISPLAY_SOURCE_EXYNOS_DSI
tristate "Samsung SoC MIPI DSI Master"
diff --git a/drivers/video/display/Makefile b/drivers/video/display/Makefile
index 55ab7112307..4cfab97112f 100644
--- a/drivers/video/display/Makefile
+++ b/drivers/video/display/Makefile
@@ -1,4 +1,5 @@
obj-$(CONFIG_DISPLAY_CORE) += display-core.o
obj-$(CONFIG_DISPLAY_PANEL_S6D6AA1) += panel-s6d6aa1.o
obj-$(CONFIG_DISPLAY_PANEL_S6E8AA0) += panel-s6e8aa0.o
+obj-$(CONFIG_DISPLAY_PANEL_L5F31188) += panel-l5f31188.o
obj-$(CONFIG_DISPLAY_SOURCE_EXYNOS_DSI) += source-exynos_dsi.o
diff --git a/drivers/video/display/panel-l5f31188.c b/drivers/video/display/panel-l5f31188.c
new file mode 100644
index 00000000000..4330a6806e4
--- /dev/null
+++ b/drivers/video/display/panel-l5f31188.c
@@ -0,0 +1,674 @@
+/*
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ * Hyungwon Hwang <human.hwang@samsung.com>
+ *
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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/module.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/delay.h>
+#include <linux/lcd.h>
+#include <linux/fb.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/display.h>
+#include <video/mipi_display.h>
+#include <video/videomode.h>
+#include <video/of_videomode.h>
+
+#define NUM_REGULATOR_CONSUMERS 2
+
+#define MIN_BRIGHTNESS (0)
+#define MAX_BRIGHTNESS (255)
+
+#define SCAN_FROM_LEFT_TO_RIGHT 0
+#define SCAN_FROM_RIGHT_TO_LEFT 1
+#define SCAN_FROM_TOP_TO_BOTTOM 0
+#define SCAN_FROM_BOTTOM_TO_TOP 1
+
+#define to_panel(p) container_of(p, struct l5f31188, entity)
+
+enum cabc_mode {
+ CABC_OFF,
+ USER_INTERFACE_IMAGE,
+ STILL_PICTURE,
+ MOVING_IMAGE
+};
+
+struct l5f31188_platform_data {
+ unsigned long width; /* Panel width in mm */
+ unsigned long height; /* Panel height in mm */
+ struct videomode mode;
+
+ /* time needed while resetting */
+ unsigned int reset_delay1;
+
+ /* time needed after reset */
+ unsigned int reset_delay2;
+
+ /* stable time needing to become panel power on. */
+ unsigned int power_on_delay;
+
+ /* time needed after display off */
+ unsigned int power_off_delay1;
+
+ /* time needed after sleep off */
+ unsigned int power_off_delay2;
+};
+
+struct l5f31188 {
+ struct display_entity entity;
+ struct device *dev;
+
+ struct l5f31188_platform_data *pdata;
+ struct backlight_device *bd;
+ struct regulator_bulk_data regs[NUM_REGULATOR_CONSUMERS];
+
+ unsigned int power;
+ enum cabc_mode cabc_mode;
+
+ unsigned int reset_gpio;
+};
+
+static void l5f31188_delay(unsigned int msecs)
+{
+ /* refer from documentation/timers/timers-howto.txt */
+ if (msecs < 20)
+ usleep_range(msecs * 1000, (msecs + 1) * 1000);
+ else
+ msleep(msecs);
+}
+
+static void l5f31188_sleep_in(struct video_source *source)
+{
+
+ const unsigned char data_to_send[] = {
+ 0x10, 0x00
+ };
+ dsi_dcs_write(source, 0,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void l5f31188_sleep_out(struct video_source *source)
+{
+ const unsigned char data_to_send[] = {
+ 0x11, 0x00
+ };
+ dsi_dcs_write(source, 0,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void l5f31188_set_gamma(struct video_source *source)
+{
+ const unsigned char data_to_send[] = {
+ 0x26, 0x00
+ };
+ dsi_dcs_write(source, 0,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void l5f31188_display_off(struct video_source *source)
+{
+ const unsigned char data_to_send[] = {
+ 0x28, 0x00
+ };
+ dsi_dcs_write(source, 0,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void l5f31188_display_on(struct video_source *source)
+{
+ const unsigned char data_to_send[] = {
+ 0x29, 0x00
+ };
+ dsi_dcs_write(source, 0,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void l5f31188_ctl_memory_access(struct video_source *source,
+ int h_direction, int v_direction)
+{
+ const unsigned char data_to_send[] = {
+ 0x36, ((h_direction & 0x1) << 1) | (v_direction & 0x1)
+ };
+ dsi_dcs_write(source, 0,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void l5f31188_set_pixel_format(struct video_source *source)
+{
+ const unsigned char data_to_send[] = {
+ 0x3A, 0x70
+ };
+ dsi_dcs_write(source, 0,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void l5f31188_write_disbv(struct video_source *source,
+ unsigned int brightness)
+{
+ const unsigned char data_to_send[] = {
+ 0x51, brightness
+ };
+ dsi_dcs_write(source, 0,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void l5f31188_write_ctrld(struct video_source *source)
+{
+ const unsigned char data_to_send[] = {
+ 0x53, 0x2C
+ };
+ dsi_dcs_write(source, 0,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void l5f31188_write_cabc(struct video_source *source,
+ enum cabc_mode cabc_mode)
+{
+ const unsigned char data_to_send[] = {
+ 0x55, cabc_mode
+ };
+ dsi_dcs_write(source, 0,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void l5f31188_write_cabcmb(struct video_source *source,
+ unsigned int min_brightness)
+{
+ const unsigned char data_to_send[] = {
+ 0x5E, min_brightness
+ };
+ dsi_dcs_write(source, 0,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void l5f31188_set_extension(struct video_source *source)
+{
+ const unsigned char data_to_send[] = {
+ 0xB9, 0xFF, 0x83, 0x94
+ };
+
+ dsi_dcs_write(source, 0,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void l5f31188_set_dgc_lut(struct video_source *source)
+{
+ const unsigned char data_to_send[] = {
+ 0xC1, 0x01, 0x00, 0x04, 0x0E, 0x18, 0x1E,
+ 0x26, 0x2F, 0x36, 0x3E, 0x47, 0x4E, 0x56,
+ 0x5D, 0x65, 0x6D, 0x75, 0x7D, 0x84, 0x8C,
+ 0x94, 0x9C, 0xA4, 0xAD, 0xB5, 0xBD, 0xC5,
+ 0xCC, 0xD4, 0xDE, 0xE5, 0xEE, 0xF7, 0xFF,
+ 0x3F, 0x9A, 0xCE, 0xD4, 0x21, 0xA1, 0x26,
+ 0x54, 0x00, 0x00, 0x04, 0x0E, 0x19, 0x1F,
+ 0x27, 0x30, 0x37, 0x40, 0x48, 0x50, 0x58,
+ 0x60, 0x67, 0x6F, 0x77, 0x7F, 0x87, 0x8F,
+ 0x97, 0x9F, 0xA7, 0xB0, 0xB8, 0xC0, 0xC8,
+ 0xCE, 0xD8, 0xE0, 0xE7, 0xF0, 0xF7, 0xFF,
+ 0x3C, 0xEB, 0xFD, 0x2F, 0x66, 0xA8, 0x2C,
+ 0x46, 0x00, 0x00, 0x04, 0x0E, 0x18, 0x1E,
+ 0x26, 0x30, 0x38, 0x41, 0x4A, 0x52, 0x5A,
+ 0x62, 0x6B, 0x73, 0x7B, 0x83, 0x8C, 0x94,
+ 0x9C, 0xA5, 0xAD, 0xB6, 0xBD, 0xC5, 0xCC,
+ 0xD4, 0xDD, 0xE3, 0xEB, 0xF2, 0xF9, 0xFF,
+ 0x3F, 0xA4, 0x8A, 0x8F, 0xC7, 0x33, 0xF5,
+ 0xE9, 0x00
+ };
+ dsi_dcs_write(source, 0,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void l5f31188_set_tcon(struct video_source *source)
+{
+ const unsigned char data_to_send[] = {
+ 0xC7, 0x00, 0x20
+ };
+ dsi_dcs_write(source, 0,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void l5f31188_set_ptba(struct video_source *source)
+{
+ const unsigned char data_to_send[] = {
+ 0xBF, 0x06, 0x10
+ };
+ dsi_dcs_write(source, 0,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void l5f31188_set_eco(struct video_source *source)
+{
+ const unsigned char data_to_send[] = {
+ 0xC6, 0x0C
+ };
+ dsi_dcs_write(source, 0,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static int l5f31188_get_brightness(struct backlight_device *bd)
+{
+ return bd->props.brightness;
+}
+
+
+static int l5f31188_set_brightness(struct backlight_device *bd)
+{
+ int brightness = bd->props.brightness;
+ struct l5f31188 *panel = bl_get_data(bd);
+ enum display_entity_state state;
+ int ret;
+
+ if (bd->props.power == FB_BLANK_POWERDOWN
+ || bd->props.state & BL_CORE_SUSPENDED)
+ state = DISPLAY_ENTITY_STATE_OFF;
+ else if (bd->props.power != FB_BLANK_UNBLANK)
+ state = DISPLAY_ENTITY_STATE_STANDBY;
+ else
+ state = DISPLAY_ENTITY_STATE_ON;
+
+ if (panel->power == FB_BLANK_POWERDOWN) {
+ dev_err(panel->dev,
+ "panel off: brightness set failed.\n");
+ return -EINVAL;
+ }
+
+ if (brightness < 0 || brightness > bd->props.max_brightness) {
+ dev_err(panel->dev, "panel brightness should be 0 to %d.\n",
+ MAX_BRIGHTNESS);
+ return -EINVAL;
+ }
+
+ ret = display_entity_set_state(&panel->entity, state);
+ if (ret)
+ return ret;
+
+ if (state == DISPLAY_ENTITY_STATE_OFF)
+ return 0;
+
+ l5f31188_write_disbv(panel->entity.source, brightness);
+
+ return 0;
+}
+
+static const struct backlight_ops l5f31188_backlight_ops = {
+ .get_brightness = l5f31188_get_brightness,
+ .update_status = l5f31188_set_brightness,
+};
+
+static void l5f31188_set_sequence(struct l5f31188 *panel)
+{
+ int brightness = panel->bd->props.brightness;
+ struct video_source *source = panel->entity.source;
+
+ l5f31188_set_extension(source);
+ l5f31188_set_dgc_lut(source);
+
+ l5f31188_set_eco(source);
+ l5f31188_set_tcon(source);
+ l5f31188_set_ptba(source);
+ l5f31188_set_gamma(source);
+ l5f31188_ctl_memory_access(source, SCAN_FROM_LEFT_TO_RIGHT,
+ SCAN_FROM_TOP_TO_BOTTOM);
+ l5f31188_set_pixel_format(source);
+ l5f31188_write_disbv(source, brightness);
+ l5f31188_write_ctrld(source);
+ l5f31188_write_cabc(source, 0x0);
+ l5f31188_write_cabcmb(source, 0x0);
+
+ l5f31188_sleep_out(source);
+ l5f31188_delay(panel->pdata->power_on_delay);
+ l5f31188_display_on(source);
+
+ dev_info(panel->dev, "%s:done.\n", __func__);
+}
+
+#ifdef CONFIG_OF
+static int l5f31188_reset(struct device *dev)
+{
+ struct l5f31188 *panel = dev_get_drvdata(dev);
+
+ gpio_set_value(panel->reset_gpio, 0);
+ l5f31188_delay(panel->pdata->reset_delay1);
+ gpio_set_value(panel->reset_gpio, 1);
+ l5f31188_delay(panel->pdata->reset_delay2);
+
+ return 0;
+}
+
+static struct l5f31188_platform_data *l5f31188_parse_dt(struct l5f31188 *panel)
+{
+ struct device_node *node = panel->dev->of_node;
+ struct l5f31188_platform_data *data;
+ const __be32 *prop_data;
+
+ data = devm_kzalloc(panel->dev, sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ dev_err(panel->dev, "failed to allocate platform data.\n");
+ return NULL;
+ }
+
+ if (of_get_videomode(node, &data->mode, 0)) {
+ dev_err(panel->dev, "failed to read video mode from DT\n");
+ return NULL;
+ }
+
+ panel->reset_gpio = of_get_named_gpio(node, "reset-gpio", 0);
+ if (panel->reset_gpio < 0)
+ return NULL;
+
+ prop_data = of_get_property(node, "width", NULL);
+ if (!prop_data)
+ return NULL;
+ data->width = be32_to_cpu(*prop_data);
+
+ prop_data = of_get_property(node, "height", NULL);
+ if (!prop_data)
+ return NULL;
+ data->height = be32_to_cpu(*prop_data);
+
+ prop_data = of_get_property(node, "reset-delay1", NULL);
+ if (!prop_data)
+ return NULL;
+ data->reset_delay1 = be32_to_cpu(*prop_data);
+
+ prop_data = of_get_property(node, "reset-delay2", NULL);
+ if (!prop_data)
+ return NULL;
+ data->reset_delay2 = be32_to_cpu(*prop_data);
+
+ prop_data = of_get_property(node, "power-on-delay", NULL);
+ if (!prop_data)
+ return NULL;
+ data->power_on_delay = be32_to_cpu(*prop_data);
+
+ prop_data = of_get_property(node, "power-off-delay1", NULL);
+ if (!prop_data)
+ return NULL;
+ data->power_off_delay1 = be32_to_cpu(*prop_data);
+
+ prop_data = of_get_property(node, "power-off-delay2", NULL);
+ if (!prop_data)
+ return NULL;
+ data->power_off_delay2 = be32_to_cpu(*prop_data);
+
+ prop_data = of_get_property(node, "vdd-supply", NULL);
+ if (!prop_data)
+ return NULL;
+
+ return data;
+}
+
+static struct of_device_id l5f31188_of_match[] = {
+ { .compatible = "samsung,l5f31188" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, l5f31188_of_match);
+#else
+static struct l5f31188_platform_data *l5f31188_parse_dt(struct l5f31188 *panel)
+{
+ return NULL;
+}
+#endif
+
+static const struct display_entity_interface_params l5f31188_params = {
+ .type = DISPLAY_ENTITY_INTERFACE_DSI,
+ .p.dsi = {
+ .format = DSI_FMT_RGB888,
+ .mode = DSI_MODE_VIDEO | DSI_MODE_VIDEO_BURST
+ | DSI_MODE_VIDEO_HFP | DSI_MODE_VIDEO_HBP
+ | DSI_MODE_VIDEO_HSA | DSI_MODE_EOT_PACKET
+ | DSI_MODE_VSYNC_FLUSH,
+ .data_lanes = 0xf,
+ .hs_clk_freq = 500000000,
+ .esc_clk_freq = 10000000,
+ },
+};
+
+static void l5f31188_power_on(struct l5f31188 *panel)
+{
+ struct video_source *src = panel->entity.source;
+ int ret;
+
+ ret = regulator_bulk_enable(NUM_REGULATOR_CONSUMERS,
+ panel->regs);
+ if (ret != 0) {
+ dev_err(panel->dev, "failed to enable regulators (%d)\n", ret);
+ return;
+ }
+
+ /* panel reset */
+ l5f31188_reset(panel->dev);
+
+ src->ops.dsi->enable(src);
+
+ l5f31188_set_sequence(panel);
+
+ return;
+}
+
+static void l5f31188_power_off(struct l5f31188 *panel)
+{
+ struct video_source *src = panel->entity.source;
+
+ l5f31188_display_off(src);
+ l5f31188_delay(panel->pdata->power_off_delay1);
+ l5f31188_sleep_in(src);
+ l5f31188_delay(panel->pdata->power_off_delay2);
+
+ src->ops.dsi->disable(src);
+
+ regulator_bulk_disable(NUM_REGULATOR_CONSUMERS,
+ panel->regs);
+}
+
+static int l5f31188_set_state(struct display_entity *entity,
+ enum display_entity_state state)
+{
+ struct l5f31188 *panel = to_panel(entity);
+ struct video_source *src = panel->entity.source;
+
+ switch (state) {
+ case DISPLAY_ENTITY_STATE_OFF:
+ if (entity->state == DISPLAY_ENTITY_STATE_ON)
+ src->common_ops->set_stream(src,
+ DISPLAY_ENTITY_STREAM_STOPPED);
+
+ l5f31188_power_off(panel);
+ break;
+ case DISPLAY_ENTITY_STATE_ON:
+ if (entity->state == DISPLAY_ENTITY_STATE_OFF)
+ l5f31188_power_on(panel);
+
+ src->common_ops->set_stream(src,
+ DISPLAY_ENTITY_STREAM_CONTINUOUS);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int l5f31188_get_modes(struct display_entity *entity,
+ const struct videomode **modes)
+{
+ struct l5f31188 *panel = to_panel(entity);
+
+ *modes = &panel->pdata->mode;
+ return 1;
+}
+
+static int l5f31188_get_size(struct display_entity *entity,
+ unsigned int *width, unsigned int *height)
+{
+ struct l5f31188 *panel = to_panel(entity);
+
+ *width = panel->pdata->width;
+ *height = panel->pdata->height;
+ return 0;
+}
+
+static int l5f31188_get_params(struct display_entity *entity,
+ struct display_entity_interface_params *params)
+{
+ *params = l5f31188_params;
+ return 0;
+}
+
+static const struct display_entity_control_ops l5f31188_control_ops = {
+ .set_state = l5f31188_set_state,
+ .get_modes = l5f31188_get_modes,
+ .get_size = l5f31188_get_size,
+ .get_params = l5f31188_get_params,
+};
+
+static void l5f31188_release(struct display_entity *entity)
+{
+ struct l5f31188 *panel = to_panel(entity);
+
+ backlight_device_unregister(panel->bd);
+ regulator_bulk_free(NUM_REGULATOR_CONSUMERS, panel->regs);
+ kfree(panel);
+}
+
+static int l5f31188_probe(struct platform_device *pdev)
+{
+ struct l5f31188 *panel;
+ int ret;
+
+ panel = kzalloc(sizeof(struct l5f31188), GFP_KERNEL);
+ if (!panel) {
+ dev_err(&pdev->dev,
+ "failed to allocate l5f31188 structure.\n");
+ return -ENOMEM;
+ }
+
+ panel->dev = &pdev->dev;
+ panel->pdata =
+ (struct l5f31188_platform_data *)pdev->dev.platform_data;
+
+ if (!panel->pdata) {
+ panel->pdata = l5f31188_parse_dt(panel);
+ if (!panel->pdata) {
+ dev_err(&pdev->dev, "failed to find platform data\n");
+ return -ENODEV;
+ }
+ }
+
+ panel->regs[0].supply = "vddi";
+ panel->regs[1].supply = "vdd";
+
+ ret = regulator_bulk_get(&pdev->dev, NUM_REGULATOR_CONSUMERS,
+ panel->regs);
+ if (ret != 0) {
+ dev_err(panel->dev, "failed to get regulators (%d)\n", ret);
+ goto err_regulator_bulk_get;
+ }
+
+ panel->bd = backlight_device_register("l5f31188_bd", &pdev->dev, panel,
+ &l5f31188_backlight_ops, NULL);
+ if (IS_ERR(panel->bd)) {
+ dev_err(&pdev->dev, "failed to register backlight ops.\n");
+ ret = PTR_ERR(panel->bd);
+ goto err_backlight_register;
+ }
+
+ panel->cabc_mode = CABC_OFF;
+ panel->bd->props.max_brightness = MAX_BRIGHTNESS;
+ panel->bd->props.brightness = MAX_BRIGHTNESS;
+
+ panel->entity.of_node = pdev->dev.of_node;
+ panel->entity.dev = &pdev->dev;
+ panel->entity.release = l5f31188_release;
+ panel->entity.ops = &l5f31188_control_ops;
+
+ platform_set_drvdata(pdev, panel);
+
+ ret = display_entity_register(&panel->entity);
+ if (ret < 0)
+ goto err_display_register;
+
+ display_entity_set_state(&panel->entity, DISPLAY_ENTITY_STATE_ON);
+
+ dev_dbg(&pdev->dev, "probed l5f31188 panel driver.\n");
+
+
+ return 0;
+
+err_display_register:
+ backlight_device_unregister(panel->bd);
+err_backlight_register:
+ regulator_bulk_free(NUM_REGULATOR_CONSUMERS, panel->regs);
+err_regulator_bulk_get:
+ kfree(panel);
+
+ return ret;
+}
+
+static int l5f31188_remove(struct platform_device *pdev)
+{
+ struct l5f31188 *panel = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ display_entity_unregister(&panel->entity);
+
+ return 0;
+}
+
+static int l5f31188_suspend(struct device *dev)
+{
+ struct l5f31188 *panel = dev_get_drvdata(dev);
+
+ if (panel->power != FB_BLANK_UNBLANK)
+ return 0;
+
+ return display_entity_set_state(&panel->entity,
+ DISPLAY_ENTITY_STATE_OFF);
+}
+
+static int l5f31188_resume(struct device *dev)
+{
+ struct l5f31188 *panel = dev_get_drvdata(dev);
+
+ if (panel->power != FB_BLANK_UNBLANK)
+ return 0;
+
+ return display_entity_set_state(&panel->entity,
+ DISPLAY_ENTITY_STATE_ON);
+}
+
+static const struct dev_pm_ops l5f31188_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(l5f31188_suspend, l5f31188_resume)
+};
+
+static struct platform_driver l5f31188_driver = {
+ .probe = l5f31188_probe,
+ .remove = l5f31188_remove,
+ .driver = {
+ .name = "panel_l5f31188",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(l5f31188_of_match),
+ .pm = &l5f31188_pm_ops,
+ }
+};
+
+module_platform_driver(l5f31188_driver);
+
+MODULE_AUTHOR("Hyungwon Hwang<human.hwang@samsung.com>");
+MODULE_DESCRIPTION("MIPI-DSI based l5f31188 TFT-LCD Panel Driver");
+MODULE_LICENSE("GPL");