From mboxrd@z Thu Jan 1 00:00:00 1970 From: a0393947@ti.com (Archit) Date: Mon, 23 Jan 2012 08:43:10 +0530 Subject: [PATCH v7 1/2] video: support MIPI-DSI controller driver In-Reply-To: <4F18BAB0.6070107@samsung.com> References: <4F17AA10.7080604@samsung.com> <4F182ACF.8010302@ti.com> <4F18BAB0.6070107@samsung.com> Message-ID: <4F1CD046.5040400@ti.com> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org Hi, On Friday 20 January 2012 06:22 AM, Donghwa Lee wrote: > 2012? 01? 19? 23:38, Archit ? ?: > >> Hi, >> >> On Thursday 19 January 2012 10:58 AM, Donghwa Lee wrote: >>> Samsung S5PC210 and EXYNOS SoC platform has MIPI-DSI controller and MIPI-DSI >>> based LCD Panel could be used with it. This patch supports MIPI-DSI driver >>> based Samsung SoC chip. >>> >>> LCD panel driver based MIPI-DSI should be registered to MIPI-DSI driver at >>> machine code and LCD panel driver specific function registered to mipi_dsim_ddi >>> structure at lcd panel init function called system init. >>> In the MIPI-DSI driver, find lcd panel driver by using registered >>> lcd panel name, and then initialize lcd panel driver. >>> >>> Changes since v6: >>> - remove obscure compile problems. >>> - remove useless codes. >>> - modify return errno codes properly >> >> One more comment about 'mipi_dsim.h', it would be better to put it in >> include/video and not 'include/linux'. >> >> Regards, >> Archit >> > > > Yes, I agree with your opinion. But I had missed your nearly opinion yesterday. > If you don't have any other suggestions from this patch set, I hope to re-patch > or fix bugs after merging it. These were the only suggestions I had. Thanks, Archit > > Thank you, > Donghwa lee > >>> >>> Signed-off-by: Donghwa Lee >>> Signed-off-by: Inki Dae >>> Signed-off-by: Kyungmin Park >>> --- >>> drivers/video/Kconfig | 6 + >>> drivers/video/Makefile | 2 + >>> drivers/video/s5p_mipi_dsi.c | 599 ++++++++++++++++++++++ >>> drivers/video/s5p_mipi_dsi_common.c | 896 +++++++++++++++++++++++++++++++++ >>> drivers/video/s5p_mipi_dsi_common.h | 46 ++ >>> drivers/video/s5p_mipi_dsi_lowlevel.c | 617 +++++++++++++++++++++++ >>> drivers/video/s5p_mipi_dsi_lowlevel.h | 112 ++++ >>> drivers/video/s5p_mipi_dsi_regs.h | 149 ++++++ >>> include/linux/mipi_dsim.h | 359 +++++++++++++ >>> 9 files changed, 2786 insertions(+), 0 deletions(-) >>> create mode 100644 drivers/video/s5p_mipi_dsi.c >>> create mode 100644 drivers/video/s5p_mipi_dsi_common.c >>> create mode 100644 drivers/video/s5p_mipi_dsi_common.h >>> create mode 100644 drivers/video/s5p_mipi_dsi_lowlevel.c >>> create mode 100644 drivers/video/s5p_mipi_dsi_lowlevel.h >>> create mode 100644 drivers/video/s5p_mipi_dsi_regs.h >>> create mode 100644 include/linux/mipi_dsim.h >>> >>> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig >>> index d83e967..bdc382e 100644 >>> --- a/drivers/video/Kconfig >>> +++ b/drivers/video/Kconfig >>> @@ -2082,6 +2082,12 @@ config FB_S3C2410_DEBUG >>> Turn on debugging messages. Note that you can set/unset at run time >>> through sysfs >>> >>> +config S5P_MIPI_DSI >>> + tristate "Samsung SoC MIPI-DSI support." >>> + depends on FB_S3C&& (ARCH_S5PV210 || ARCH_EXYNOS) >>> + help >>> + This enables support for MIPI-DSI device. >>> + >>> config FB_NUC900 >>> bool "NUC900 LCD framebuffer support" >>> depends on FB&& ARCH_W90X900 >>> diff --git a/drivers/video/Makefile b/drivers/video/Makefile >>> index 9b9d8ff..29eb7c9 100644 >>> --- a/drivers/video/Makefile >>> +++ b/drivers/video/Makefile >>> @@ -120,6 +120,8 @@ obj-$(CONFIG_FB_SH7760) += sh7760fb.o >>> obj-$(CONFIG_FB_IMX) += imxfb.o >>> obj-$(CONFIG_FB_S3C) += s3c-fb.o >>> obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o >>> +obj-$(CONFIG_S5P_MIPI_DSI) += s5p_mipi_dsi.o s5p_mipi_dsi_common.o \ >>> + s5p_mipi_dsi_lowlevel.o >>> obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o >>> obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o >>> obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/ >>> diff --git a/drivers/video/s5p_mipi_dsi.c b/drivers/video/s5p_mipi_dsi.c >>> new file mode 100644 >>> index 0000000..5ca6618 >>> --- /dev/null >>> +++ b/drivers/video/s5p_mipi_dsi.c >>> @@ -0,0 +1,599 @@ >>> +/* linux/drivers/video/s5p_mipi_dsi.c >>> + * >>> + * Samsung SoC MIPI-DSIM driver. >>> + * >>> + * Copyright (c) 2011 Samsung Electronics Co., Ltd >>> + * >>> + * InKi Dae, >>> + * Donghwa Lee, >>> + * >>> + * This program is free software; you can redistribute it and/or modify >>> + * it under the terms of the GNU General Public License version 2 as >>> + * published by the Free Software Foundation. >>> +*/ >>> + >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> + >>> +#include >>> + >>> +#include "s5p_mipi_dsi_common.h" >>> +#include "s5p_mipi_dsi_lowlevel.h" >>> + >>> +struct mipi_dsim_ddi { >>> + int bus_id; >>> + struct list_head list; >>> + struct mipi_dsim_lcd_device *dsim_lcd_dev; >>> + struct mipi_dsim_lcd_driver *dsim_lcd_drv; >>> +}; >>> + >>> +static LIST_HEAD(dsim_ddi_list); >>> + >>> +static DEFINE_MUTEX(mipi_dsim_lock); >>> + >>> +static struct mipi_dsim_platform_data *to_dsim_plat(struct platform_device >>> + *pdev) >>> +{ >>> + return pdev->dev.platform_data; >>> +} >>> + >>> +static struct regulator_bulk_data supplies[] = { >>> + { .supply = "vdd10", }, >>> + { .supply = "vdd18", }, >>> +}; >>> + >>> +static int s5p_mipi_regulator_enable(struct mipi_dsim_device *dsim) >>> +{ >>> + int ret; >>> + >>> + mutex_lock(&dsim->lock); >>> + ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies); >>> + mutex_unlock(&dsim->lock); >>> + >>> + return ret; >>> +} >>> + >>> +static int s5p_mipi_regulator_disable(struct mipi_dsim_device *dsim) >>> +{ >>> + int ret; >>> + >>> + mutex_lock(&dsim->lock); >>> + ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies); >>> + mutex_unlock(&dsim->lock); >>> + >>> + return ret; >>> +} >>> + >>> +/* update all register settings to MIPI DSI controller. */ >>> +static void s5p_mipi_update_cfg(struct mipi_dsim_device *dsim) >>> +{ >>> + /* >>> + * data from Display controller(FIMD) is not transferred in video mode >>> + * but in case of command mode, all settings is not updated to >>> + * registers. >>> + */ >>> + s5p_mipi_dsi_stand_by(dsim, 0); >>> + >>> + s5p_mipi_dsi_init_dsim(dsim); >>> + s5p_mipi_dsi_init_link(dsim); >>> + >>> + s5p_mipi_dsi_set_hs_enable(dsim); >>> + >>> + /* set display timing. */ >>> + s5p_mipi_dsi_set_display_mode(dsim, dsim->dsim_config); >>> + >>> + /* >>> + * data from Display controller(FIMD) is transferred in video mode >>> + * but in case of command mode, all settigs is updated to registers. >>> + */ >>> + s5p_mipi_dsi_stand_by(dsim, 1); >>> +} >>> + >>> +static int s5p_mipi_dsi_early_blank_mode(struct mipi_dsim_device *dsim, >>> + int power) >>> +{ >>> + struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv; >>> + struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev; >>> + >>> + switch (power) { >>> + case FB_BLANK_POWERDOWN: >>> + if (dsim->suspended) >>> + return 0; >>> + >>> + if (client_drv&& client_drv->suspend) >>> + client_drv->suspend(client_dev); >>> + >>> + clk_disable(dsim->clock); >>> + >>> + s5p_mipi_regulator_disable(dsim); >>> + >>> + dsim->suspended = true; >>> + >>> + break; >>> + default: >>> + break; >>> + } >>> + >>> + return 0; >>> +} >>> + >>> +static int s5p_mipi_dsi_blank_mode(struct mipi_dsim_device *dsim, int power) >>> +{ >>> + struct platform_device *pdev = to_platform_device(dsim->dev); >>> + struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv; >>> + struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev; >>> + >>> + switch (power) { >>> + case FB_BLANK_UNBLANK: >>> + if (!dsim->suspended) >>> + return 0; >>> + >>> + /* lcd panel power on. */ >>> + if (client_drv&& client_drv->power_on) >>> + client_drv->power_on(client_dev, 1); >>> + >>> + s5p_mipi_regulator_disable(dsim); >>> + >>> + /* enable MIPI-DSI PHY. */ >>> + if (dsim->pd->phy_enable) >>> + dsim->pd->phy_enable(pdev, true); >>> + >>> + clk_enable(dsim->clock); >>> + >>> + s5p_mipi_update_cfg(dsim); >>> + >>> + /* set lcd panel sequence commands. */ >>> + if (client_drv&& client_drv->set_sequence) >>> + client_drv->set_sequence(client_dev); >>> + >>> + dsim->suspended = false; >>> + >>> + break; >>> + case FB_BLANK_NORMAL: >>> + /* TODO. */ >>> + break; >>> + default: >>> + break; >>> + } >>> + >>> + return 0; >>> +} >>> + >>> +int s5p_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev) >>> +{ >>> + struct mipi_dsim_ddi *dsim_ddi; >>> + >>> + if (!lcd_dev->name) { >>> + pr_err("dsim_lcd_device name is NULL.\n"); >>> + return -EFAULT; >>> + } >>> + >>> + dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL); >>> + if (!dsim_ddi) { >>> + pr_err("failed to allocate dsim_ddi object.\n"); >>> + return -ENOMEM; >>> + } >>> + >>> + dsim_ddi->dsim_lcd_dev = lcd_dev; >>> + >>> + mutex_lock(&mipi_dsim_lock); >>> + list_add_tail(&dsim_ddi->list,&dsim_ddi_list); >>> + mutex_unlock(&mipi_dsim_lock); >>> + >>> + return 0; >>> +} >>> + >>> +struct mipi_dsim_ddi *s5p_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv) >>> +{ >>> + struct mipi_dsim_ddi *dsim_ddi, *next; >>> + struct mipi_dsim_lcd_device *lcd_dev; >>> + >>> + mutex_lock(&mipi_dsim_lock); >>> + >>> + list_for_each_entry_safe(dsim_ddi, next,&dsim_ddi_list, list) { >>> + if (!dsim_ddi) >>> + goto out; >>> + >>> + lcd_dev = dsim_ddi->dsim_lcd_dev; >>> + if (!lcd_dev) >>> + continue; >>> + >>> + if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0) { >>> + /** >>> + * bus_id would be used to identify >>> + * connected bus. >>> + */ >>> + dsim_ddi->bus_id = lcd_dev->bus_id; >>> + mutex_unlock(&mipi_dsim_lock); >>> + >>> + return dsim_ddi; >>> + } >>> + >>> + list_del(&dsim_ddi->list); >>> + kfree(dsim_ddi); >>> + } >>> + >>> +out: >>> + mutex_unlock(&mipi_dsim_lock); >>> + >>> + return NULL; >>> +} >>> + >>> +int s5p_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv) >>> +{ >>> + struct mipi_dsim_ddi *dsim_ddi; >>> + >>> + if (!lcd_drv->name) { >>> + pr_err("dsim_lcd_driver name is NULL.\n"); >>> + return -EFAULT; >>> + } >>> + >>> + dsim_ddi = s5p_mipi_dsi_find_lcd_device(lcd_drv); >>> + if (!dsim_ddi) { >>> + pr_err("mipi_dsim_ddi object not found.\n"); >>> + return -EFAULT; >>> + } >>> + >>> + dsim_ddi->dsim_lcd_drv = lcd_drv; >>> + >>> + pr_info("registered panel driver(%s) to mipi-dsi driver.\n", >>> + lcd_drv->name); >>> + >>> + return 0; >>> + >>> +} >>> + >>> +struct mipi_dsim_ddi *s5p_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim, >>> + const char *name) >>> +{ >>> + struct mipi_dsim_ddi *dsim_ddi, *next; >>> + struct mipi_dsim_lcd_driver *lcd_drv; >>> + struct mipi_dsim_lcd_device *lcd_dev; >>> + int ret; >>> + >>> + mutex_lock(&dsim->lock); >>> + >>> + list_for_each_entry_safe(dsim_ddi, next,&dsim_ddi_list, list) { >>> + lcd_drv = dsim_ddi->dsim_lcd_drv; >>> + lcd_dev = dsim_ddi->dsim_lcd_dev; >>> + if (!lcd_drv || !lcd_dev || >>> + (dsim->id != dsim_ddi->bus_id)) >>> + continue; >>> + >>> + dev_dbg(dsim->dev, "lcd_drv->id = %d, lcd_dev->id = %d\n", >>> + lcd_drv->id, lcd_dev->id); >>> + dev_dbg(dsim->dev, "lcd_dev->bus_id = %d, dsim->id = %d\n", >>> + lcd_dev->bus_id, dsim->id); >>> + >>> + if ((strcmp(lcd_drv->name, name) == 0)) { >>> + lcd_dev->master = dsim; >>> + >>> + lcd_dev->dev.parent = dsim->dev; >>> + dev_set_name(&lcd_dev->dev, "%s", lcd_drv->name); >>> + >>> + ret = device_register(&lcd_dev->dev); >>> + if (ret< 0) { >>> + dev_err(dsim->dev, >>> + "can't register %s, status %d\n", >>> + dev_name(&lcd_dev->dev), ret); >>> + mutex_unlock(&dsim->lock); >>> + >>> + return NULL; >>> + } >>> + >>> + dsim->dsim_lcd_dev = lcd_dev; >>> + dsim->dsim_lcd_drv = lcd_drv; >>> + >>> + mutex_unlock(&dsim->lock); >>> + >>> + return dsim_ddi; >>> + } >>> + } >>> + >>> + mutex_unlock(&dsim->lock); >>> + >>> + return NULL; >>> +} >>> + >>> +/* define MIPI-DSI Master operations. */ >>> +static struct mipi_dsim_master_ops master_ops = { >>> + .cmd_read = s5p_mipi_dsi_rd_data, >>> + .cmd_write = s5p_mipi_dsi_wr_data, >>> + .get_dsim_frame_done = s5p_mipi_dsi_get_frame_done_status, >>> + .clear_dsim_frame_done = s5p_mipi_dsi_clear_frame_done, >>> + .set_early_blank_mode = s5p_mipi_dsi_early_blank_mode, >>> + .set_blank_mode = s5p_mipi_dsi_blank_mode, >>> +}; >>> + >>> +static int s5p_mipi_dsi_probe(struct platform_device *pdev) >>> +{ >>> + struct resource *res; >>> + struct mipi_dsim_device *dsim; >>> + struct mipi_dsim_config *dsim_config; >>> + struct mipi_dsim_platform_data *dsim_pd; >>> + struct mipi_dsim_ddi *dsim_ddi; >>> + int ret = -EINVAL; >>> + >>> + dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL); >>> + if (!dsim) { >>> + dev_err(&pdev->dev, "failed to allocate dsim object.\n"); >>> + return -ENOMEM; >>> + } >>> + >>> + dsim->pd = to_dsim_plat(pdev); >>> + dsim->dev =&pdev->dev; >>> + dsim->id = pdev->id; >>> + >>> + /* get mipi_dsim_platform_data. */ >>> + dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd; >>> + if (dsim_pd == NULL) { >>> + dev_err(&pdev->dev, "failed to get platform data for dsim.\n"); >>> + goto err_clock_get; >>> + } >>> + /* get mipi_dsim_config. */ >>> + dsim_config = dsim_pd->dsim_config; >>> + if (dsim_config == NULL) { >>> + dev_err(&pdev->dev, "failed to get dsim config data.\n"); >>> + goto err_clock_get; >>> + } >>> + >>> + dsim->dsim_config = dsim_config; >>> + dsim->master_ops =&master_ops; >>> + >>> + mutex_init(&dsim->lock); >>> + >>> + ret = regulator_bulk_get(&pdev->dev, ARRAY_SIZE(supplies), supplies); >>> + if (ret) { >>> + dev_err(&pdev->dev, "Failed to get regulators: %d\n", ret); >>> + goto err_clock_get; >>> + } >>> + >>> + dsim->clock = clk_get(&pdev->dev, "dsim0"); >>> + if (IS_ERR(dsim->clock)) { >>> + dev_err(&pdev->dev, "failed to get dsim clock source\n"); >>> + goto err_clock_get; >>> + } >>> + >>> + clk_enable(dsim->clock); >>> + >>> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); >>> + if (!res) { >>> + dev_err(&pdev->dev, "failed to get io memory region\n"); >>> + goto err_platform_get; >>> + } >>> + >>> + dsim->res = request_mem_region(res->start, resource_size(res), >>> + dev_name(&pdev->dev)); >>> + if (!dsim->res) { >>> + dev_err(&pdev->dev, "failed to request io memory region\n"); >>> + ret = -ENOMEM; >>> + goto err_mem_region; >>> + } >>> + >>> + dsim->reg_base = ioremap(res->start, resource_size(res)); >>> + if (!dsim->reg_base) { >>> + dev_err(&pdev->dev, "failed to remap io region\n"); >>> + ret = -ENOMEM; >>> + goto err_ioremap; >>> + } >>> + >>> + mutex_init(&dsim->lock); >>> + >>> + /* bind lcd ddi matched with panel name. */ >>> + dsim_ddi = s5p_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name); >>> + if (!dsim_ddi) { >>> + dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n"); >>> + goto err_bind; >>> + } >>> + >>> + dsim->irq = platform_get_irq(pdev, 0); >>> + if (dsim->irq< 0) { >>> + dev_err(&pdev->dev, "failed to request dsim irq resource\n"); >>> + ret = -EINVAL; >>> + goto err_platform_get_irq; >>> + } >>> + >>> + ret = request_irq(dsim->irq, s5p_mipi_dsi_interrupt_handler, >>> + IRQF_SHARED, pdev->name, dsim); >>> + if (ret != 0) { >>> + dev_err(&pdev->dev, "failed to request dsim irq\n"); >>> + ret = -EINVAL; >>> + goto err_bind; >>> + } >>> + >>> + init_completion(&dsim_wr_comp); >>> + init_completion(&dsim_rd_comp); >>> + >>> + /* enable interrupt */ >>> + s5p_mipi_dsi_init_interrupt(dsim); >>> + >>> + /* initialize mipi-dsi client(lcd panel). */ >>> + if (dsim_ddi->dsim_lcd_drv&& dsim_ddi->dsim_lcd_drv->probe) >>> + dsim_ddi->dsim_lcd_drv->probe(dsim_ddi->dsim_lcd_dev); >>> + >>> + /* in case that mipi got enabled at bootloader. */ >>> + if (dsim_pd->enabled) >>> + goto out; >>> + >>> + /* lcd panel power on. */ >>> + if (dsim_ddi->dsim_lcd_drv&& dsim_ddi->dsim_lcd_drv->power_on) >>> + dsim_ddi->dsim_lcd_drv->power_on(dsim_ddi->dsim_lcd_dev, 1); >>> + >>> + s5p_mipi_regulator_enable(dsim); >>> + >>> + /* enable MIPI-DSI PHY. */ >>> + if (dsim->pd->phy_enable) >>> + dsim->pd->phy_enable(pdev, true); >>> + >>> + s5p_mipi_update_cfg(dsim); >>> + >>> + /* set lcd panel sequence commands. */ >>> + if (dsim_ddi->dsim_lcd_drv&& dsim_ddi->dsim_lcd_drv->set_sequence) >>> + dsim_ddi->dsim_lcd_drv->set_sequence(dsim_ddi->dsim_lcd_dev); >>> + >>> + dsim->suspended = false; >>> + >>> +out: >>> + platform_set_drvdata(pdev, dsim); >>> + >>> + dev_dbg(&pdev->dev, "mipi-dsi driver(%s mode) has been probed.\n", >>> + (dsim_config->e_interface == DSIM_COMMAND) ? >>> + "CPU" : "RGB"); >>> + >>> + return 0; >>> + >>> +err_bind: >>> + iounmap(dsim->reg_base); >>> + >>> +err_ioremap: >>> + release_mem_region(dsim->res->start, resource_size(dsim->res)); >>> + >>> +err_mem_region: >>> + release_resource(dsim->res); >>> + >>> +err_platform_get: >>> + clk_disable(dsim->clock); >>> + clk_put(dsim->clock); >>> +err_clock_get: >>> + kfree(dsim); >>> + >>> +err_platform_get_irq: >>> + return ret; >>> +} >>> + >>> +static int __devexit s5p_mipi_dsi_remove(struct platform_device *pdev) >>> +{ >>> + struct mipi_dsim_device *dsim = platform_get_drvdata(pdev); >>> + struct mipi_dsim_ddi *dsim_ddi, *next; >>> + struct mipi_dsim_lcd_driver *dsim_lcd_drv; >>> + >>> + iounmap(dsim->reg_base); >>> + >>> + clk_disable(dsim->clock); >>> + clk_put(dsim->clock); >>> + >>> + release_resource(dsim->res); >>> + release_mem_region(dsim->res->start, resource_size(dsim->res)); >>> + >>> + list_for_each_entry_safe(dsim_ddi, next,&dsim_ddi_list, list) { >>> + if (dsim_ddi) { >>> + if (dsim->id != dsim_ddi->bus_id) >>> + continue; >>> + >>> + dsim_lcd_drv = dsim_ddi->dsim_lcd_drv; >>> + >>> + if (dsim_lcd_drv->remove) >>> + dsim_lcd_drv->remove(dsim_ddi->dsim_lcd_dev); >>> + >>> + kfree(dsim_ddi); >>> + } >>> + } >>> + >>> + regulator_bulk_free(ARRAY_SIZE(supplies), supplies); >>> + kfree(dsim); >>> + >>> + return 0; >>> +} >>> + >>> +#ifdef CONFIG_PM >>> +static int s5p_mipi_dsi_suspend(struct platform_device *pdev, >>> + pm_message_t state) >>> +{ >>> + struct mipi_dsim_device *dsim = platform_get_drvdata(pdev); >>> + struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv; >>> + struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev; >>> + >>> + disable_irq(dsim->irq); >>> + >>> + if (dsim->suspended) >>> + return 0; >>> + >>> + if (client_drv&& client_drv->suspend) >>> + client_drv->suspend(client_dev); >>> + >>> + /* enable MIPI-DSI PHY. */ >>> + if (dsim->pd->phy_enable) >>> + dsim->pd->phy_enable(pdev, false); >>> + >>> + clk_disable(dsim->clock); >>> + >>> + s5p_mipi_regulator_disable(dsim); >>> + >>> + dsim->suspended = true; >>> + >>> + return 0; >>> +} >>> + >>> +static int s5p_mipi_dsi_resume(struct platform_device *pdev) >>> +{ >>> + struct mipi_dsim_device *dsim = platform_get_drvdata(pdev); >>> + struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv; >>> + struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev; >>> + >>> + enable_irq(dsim->irq); >>> + >>> + if (!dsim->suspended) >>> + return 0; >>> + >>> + /* lcd panel power on. */ >>> + if (client_drv&& client_drv->power_on) >>> + client_drv->power_on(client_dev, 1); >>> + >>> + s5p_mipi_regulator_enable(dsim); >>> + >>> + /* enable MIPI-DSI PHY. */ >>> + if (dsim->pd->phy_enable) >>> + dsim->pd->phy_enable(pdev, true); >>> + >>> + clk_enable(dsim->clock); >>> + >>> + s5p_mipi_update_cfg(dsim); >>> + >>> + /* set lcd panel sequence commands. */ >>> + if (client_drv&& client_drv->set_sequence) >>> + client_drv->set_sequence(client_dev); >>> + >>> + dsim->suspended = false; >>> + >>> + return 0; >>> +} >>> +#else >>> +#define s5p_mipi_dsi_suspend NULL >>> +#define s5p_mipi_dsi_resume NULL >>> +#endif >>> + >>> +static struct platform_driver s5p_mipi_dsi_driver = { >>> + .probe = s5p_mipi_dsi_probe, >>> + .remove = __devexit_p(s5p_mipi_dsi_remove), >>> + .suspend = s5p_mipi_dsi_suspend, >>> + .resume = s5p_mipi_dsi_resume, >>> + .driver = { >>> + .name = "s5p-mipi-dsim", >>> + .owner = THIS_MODULE, >>> + }, >>> +}; >>> + >>> +module_platform_driver(s5p_mipi_dsi_driver); >>> + >>> +MODULE_AUTHOR("InKi Dae"); >>> +MODULE_DESCRIPTION("Samusung SoC MIPI-DSI driver"); >>> +MODULE_LICENSE("GPL"); >>> diff --git a/drivers/video/s5p_mipi_dsi_common.c b/drivers/video/s5p_mipi_dsi_common.c >>> new file mode 100644 >>> index 0000000..3e9537f >>> --- /dev/null >>> +++ b/drivers/video/s5p_mipi_dsi_common.c >>> @@ -0,0 +1,896 @@ >>> +/* linux/drivers/video/s5p_mipi_dsi_common.c >>> + * >>> + * Samsung SoC MIPI-DSI common driver. >>> + * >>> + * Copyright (c) 2011 Samsung Electronics Co., Ltd >>> + * >>> + * InKi Dae, >>> + * Donghwa Lee, >>> + * >>> + * This program is free software; you can redistribute it and/or modify >>> + * it under the terms of the GNU General Public License version 2 as >>> + * published by the Free Software Foundation. >>> +*/ >>> + >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> + >>> +#include