summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorXinyu Chen <xinyu.chen@freescale.com>2012-10-09 16:47:47 +0800
committerXinyu Chen <xinyu.chen@freescale.com>2012-10-09 16:47:47 +0800
commiteba86309d9ba74153b7853cd8fb97f2484679219 (patch)
tree2eca312c9a1dde28c0e376156e5cad1704de08c9 /drivers
parent58d8257e51439a6c1ac2c95441f7ec119568dd5b (diff)
parent45c27e3123e45eb27f3e5933862936e9beda38cd (diff)
Merge remote branch 'fsl-linux-sdk/imx_3.0.35' into imx_3.0.35_android
Conflicts: arch/arm/configs/imx6s_updater_defconfig arch/arm/include/asm/hardware/coresight.h arch/arm/kernel/etm.c arch/arm/mach-mx6/board-mx6q_sabresd.c arch/arm/mach-mx6/cpu_op-mx6.c arch/arm/mach-mx6/mx6_suspend.S arch/arm/mach-mx6/pm.c arch/arm/mach-mx6/system.c arch/arm/plat-mxc/cpufreq.c drivers/mfd/mxc-hdmi-core.c drivers/power/sabresd_battery.c drivers/video/mxc/mxc_ipuv3_fb.c drivers/video/mxc_hdmi.c include/linux/mfd/mxc-hdmi-core.h
Diffstat (limited to 'drivers')
-rw-r--r--drivers/dma/pxp/pxp_dma_v2.c5
-rw-r--r--drivers/media/video/mxc/capture/Kconfig2
-rw-r--r--drivers/media/video/mxc/capture/csi_v4l2_capture.c223
-rw-r--r--drivers/media/video/mxc/capture/fsl_csi.c58
-rw-r--r--drivers/media/video/mxc/capture/fsl_csi.h35
-rw-r--r--drivers/media/video/mxc/capture/mt9v111.c4
-rw-r--r--drivers/media/video/mxc/capture/mxc_v4l2_capture.h18
-rw-r--r--drivers/media/video/mxc/capture/ov2640.c4
-rw-r--r--drivers/media/video/mxc/capture/sensor_clock.c28
-rw-r--r--drivers/media/video/mxc/output/mxc_vout.c45
-rw-r--r--drivers/mfd/mxc-hdmi-core.c12
-rw-r--r--drivers/mmc/core/sdio.c6
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.c35
-rw-r--r--drivers/mtd/nand/nand_base.c60
-rw-r--r--drivers/mxc/gpu-viv/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.c2
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_command.c21
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.c9
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.h3
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_linux.h1
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c12
-rw-r--r--drivers/mxc/ipu3/ipu_device.c24
-rw-r--r--drivers/mxc/thermal/cooling.c3
-rw-r--r--drivers/mxc/vpu/mxc_vpu.c30
-rwxr-xr-xdrivers/net/fec.c14
-rwxr-xr-xdrivers/power/Kconfig1
-rwxr-xr-xdrivers/power/sabresd_battery.c178
-rwxr-xr-xdrivers/usb/gadget/arcotg_udc.c7
-rwxr-xr-xdrivers/usb/host/ehci-arc.c3
-rw-r--r--drivers/video/mxc/Kconfig6
-rw-r--r--drivers/video/mxc/Makefile7
-rw-r--r--drivers/video/mxc/mxc_elcdif_fb.c134
-rw-r--r--drivers/video/mxc/mxc_epdc_fb.c311
-rw-r--r--drivers/video/mxc/mxcfb_sii902x_elcdif.c560
33 files changed, 1620 insertions, 241 deletions
diff --git a/drivers/dma/pxp/pxp_dma_v2.c b/drivers/dma/pxp/pxp_dma_v2.c
index 87b8f558ae8c..b74f62cac032 100644
--- a/drivers/dma/pxp/pxp_dma_v2.c
+++ b/drivers/dma/pxp/pxp_dma_v2.c
@@ -264,6 +264,9 @@ static void pxp_set_ctrl(struct pxps *pxp)
case PXP_PIX_FMT_YUV422P:
fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV422;
break;
+ case PXP_PIX_FMT_UYVY:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__UYVY1P422;
+ break;
default:
fmt_ctrl = 0;
}
@@ -654,7 +657,7 @@ static void pxp_set_csc(struct pxps *pxp)
/* CSC1 - YUV->RGB */
__raw_writel(0x84ab01f0, pxp->base + HW_PXP_CSC1_COEF0);
- __raw_writel(0x01230204, pxp->base + HW_PXP_CSC1_COEF1);
+ __raw_writel(0x01980204, pxp->base + HW_PXP_CSC1_COEF1);
__raw_writel(0x0730079c, pxp->base + HW_PXP_CSC1_COEF2);
/* CSC2 - Bypass */
diff --git a/drivers/media/video/mxc/capture/Kconfig b/drivers/media/video/mxc/capture/Kconfig
index a7b14cb23b9b..febe9d874fb8 100644
--- a/drivers/media/video/mxc/capture/Kconfig
+++ b/drivers/media/video/mxc/capture/Kconfig
@@ -13,7 +13,7 @@ config VIDEO_MXC_EMMA_CAMERA
default y
config VIDEO_MXC_CSI_CAMERA
- tristate "MX25 CSI camera support"
+ tristate "CSI camera support"
depends on !VIDEO_MXC_EMMA_CAMERA
config VIDEO_MXC_CSI_DMA
diff --git a/drivers/media/video/mxc/capture/csi_v4l2_capture.c b/drivers/media/video/mxc/capture/csi_v4l2_capture.c
index eb824ddf5eb3..ada6d5e8afbd 100644
--- a/drivers/media/video/mxc/capture/csi_v4l2_capture.c
+++ b/drivers/media/video/mxc/capture/csi_v4l2_capture.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2009-2012 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -15,7 +15,7 @@
* @file drivers/media/video/mxc/capture/csi_v4l2_capture.c
* This file is derived from mxc_v4l2_capture.c
*
- * @brief MX25 Video For Linux 2 driver
+ * @brief Video For Linux 2 capture driver
*
* @ingroup MXC_V4L2_CAPTURE
*/
@@ -61,6 +61,198 @@ static struct v4l2_int_device csi_v4l2_int_device = {
},
};
+/* Callback function triggered after PxP receives an EOF interrupt */
+static void pxp_dma_done(void *arg)
+{
+ struct pxp_tx_desc *tx_desc = to_tx_desc(arg);
+ struct dma_chan *chan = tx_desc->txd.chan;
+ struct pxp_channel *pxp_chan = to_pxp_channel(chan);
+ cam_data *cam = pxp_chan->client;
+
+ /* This call will signal wait_for_completion_timeout() */
+ complete(&cam->pxp_tx_cmpl);
+}
+
+static bool chan_filter(struct dma_chan *chan, void *arg)
+{
+ if (imx_dma_is_pxp(chan))
+ return true;
+ else
+ return false;
+}
+
+/* Function to request PXP DMA channel */
+static int pxp_chan_init(cam_data *cam)
+{
+ dma_cap_mask_t mask;
+ struct dma_chan *chan;
+
+ /* Request a free channel */
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_cap_set(DMA_PRIVATE, mask);
+ chan = dma_request_channel(mask, chan_filter, NULL);
+ if (!chan) {
+ pr_err("Unsuccessfully request channel!\n");
+ return -EBUSY;
+ }
+
+ cam->pxp_chan = to_pxp_channel(chan);
+ cam->pxp_chan->client = cam;
+
+ init_completion(&cam->pxp_tx_cmpl);
+
+ return 0;
+}
+
+/*
+ * Function to call PxP DMA driver and send our new V4L2 buffer
+ * through the PxP and PxP will process this buffer in place.
+ * Note: This is a blocking call, so upon return the PxP tx should be complete.
+ */
+static int pxp_process_update(cam_data *cam)
+{
+ dma_cookie_t cookie;
+ struct scatterlist *sg = cam->sg;
+ struct dma_chan *dma_chan;
+ struct pxp_tx_desc *desc;
+ struct dma_async_tx_descriptor *txd;
+ struct pxp_config_data *pxp_conf = &cam->pxp_conf;
+ struct pxp_proc_data *proc_data = &cam->pxp_conf.proc_data;
+ int i, ret;
+ int length;
+
+ pr_debug("Starting PxP Send Buffer\n");
+
+ /* First, check to see that we have acquired a PxP Channel object */
+ if (cam->pxp_chan == NULL) {
+ /*
+ * PxP Channel has not yet been created and initialized,
+ * so let's go ahead and try
+ */
+ ret = pxp_chan_init(cam);
+ if (ret) {
+ /*
+ * PxP channel init failed, and we can't use the
+ * PxP until the PxP DMA driver has loaded, so we abort
+ */
+ pr_err("PxP chan init failed\n");
+ return -ENODEV;
+ }
+ }
+
+ /*
+ * Init completion, so that we can be properly informed of
+ * the completion of the PxP task when it is done.
+ */
+ init_completion(&cam->pxp_tx_cmpl);
+
+ dma_chan = &cam->pxp_chan->dma_chan;
+
+ txd = dma_chan->device->device_prep_slave_sg(dma_chan, sg, 2,
+ DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT);
+ if (!txd) {
+ pr_err("Error preparing a DMA transaction descriptor.\n");
+ return -EIO;
+ }
+
+ txd->callback_param = txd;
+ txd->callback = pxp_dma_done;
+
+ /*
+ * Configure PxP for processing of new v4l2 buf
+ */
+ pxp_conf->s0_param.pixel_fmt = PXP_PIX_FMT_UYVY;
+ pxp_conf->s0_param.color_key = -1;
+ pxp_conf->s0_param.color_key_enable = false;
+ pxp_conf->s0_param.width = cam->v2f.fmt.pix.width;
+ pxp_conf->s0_param.height = cam->v2f.fmt.pix.height;
+
+ pxp_conf->ol_param[0].combine_enable = false;
+
+ proc_data->srect.top = 0;
+ proc_data->srect.left = 0;
+ proc_data->srect.width = pxp_conf->s0_param.width;
+ proc_data->srect.height = pxp_conf->s0_param.height;
+
+ proc_data->drect.top = 0;
+ proc_data->drect.left = 0;
+ proc_data->drect.width = proc_data->srect.width;
+ proc_data->drect.height = proc_data->srect.height;
+ proc_data->scaling = 0;
+ proc_data->hflip = 0;
+ proc_data->vflip = 0;
+ proc_data->rotate = 0;
+ proc_data->bgcolor = 0;
+
+ pxp_conf->out_param.pixel_fmt = PXP_PIX_FMT_RGB565;
+ pxp_conf->out_param.width = proc_data->drect.width;
+ pxp_conf->out_param.height = proc_data->drect.height;
+
+ if (cam->rotation >= IPU_ROTATE_90_RIGHT)
+ pxp_conf->out_param.stride = pxp_conf->out_param.height;
+ else
+ pxp_conf->out_param.stride = pxp_conf->out_param.width;
+
+ desc = to_tx_desc(txd);
+ length = desc->len;
+ for (i = 0; i < length; i++) {
+ if (i == 0) {/* S0 */
+ memcpy(&desc->proc_data, proc_data,
+ sizeof(struct pxp_proc_data));
+ pxp_conf->s0_param.paddr = sg_dma_address(&sg[0]);
+ memcpy(&desc->layer_param.s0_param, &pxp_conf->s0_param,
+ sizeof(struct pxp_layer_param));
+ } else if (i == 1) {
+ pxp_conf->out_param.paddr = sg_dma_address(&sg[1]);
+ memcpy(&desc->layer_param.out_param,
+ &pxp_conf->out_param,
+ sizeof(struct pxp_layer_param));
+ }
+
+ desc = desc->next;
+ }
+
+ /* Submitting our TX starts the PxP processing task */
+ cookie = txd->tx_submit(txd);
+ if (cookie < 0) {
+ pr_err("Error sending FB through PxP\n");
+ return -EIO;
+ }
+
+ cam->txd = txd;
+
+ /* trigger PxP */
+ dma_async_issue_pending(dma_chan);
+
+ return 0;
+}
+
+static int pxp_complete_update(cam_data *cam)
+{
+ int ret;
+ /*
+ * Wait for completion event, which will be set
+ * through our TX callback function.
+ */
+ ret = wait_for_completion_timeout(&cam->pxp_tx_cmpl, HZ / 10);
+ if (ret <= 0) {
+ pr_warning("PxP operation failed due to %s\n",
+ ret < 0 ? "user interrupt" : "timeout");
+ dma_release_channel(&cam->pxp_chan->dma_chan);
+ cam->pxp_chan = NULL;
+ return ret ? : -ETIMEDOUT;
+ }
+
+ dma_release_channel(&cam->pxp_chan->dma_chan);
+ cam->pxp_chan = NULL;
+
+ pr_debug("TX completed\n");
+
+ return 0;
+}
+
/*!
* Camera V4l2 callback function.
*
@@ -666,6 +858,23 @@ static int csi_v4l_dqueue(cam_data *cam, struct v4l2_buffer *buf)
buf->flags = frame->buffer.flags;
buf->m = cam->frame[frame->index].buffer.m;
+ /*
+ * Note:
+ * If want to do preview on LCD, use PxP CSC to convert from UYVY
+ * to RGB565; but for encoding, usually we don't use RGB format.
+ */
+ if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) {
+ /* PxP processes it in place */
+ sg_dma_address(&cam->sg[0]) = buf->m.offset;
+ sg_dma_address(&cam->sg[1]) = buf->m.offset;
+ retval = pxp_process_update(cam);
+ if (retval) {
+ pr_err("Unable to submit PxP update task.\n");
+ return retval;
+ }
+ pxp_complete_update(cam);
+ }
+
return retval;
}
@@ -1186,8 +1395,8 @@ static void init_camera_struct(cam_data *cam)
/* Default everything to 0 */
memset(cam, 0, sizeof(cam_data));
- init_MUTEX(&cam->param_lock);
- init_MUTEX(&cam->busy_lock);
+ sema_init(&cam->param_lock, 1);
+ sema_init(&cam->busy_lock, 1);
cam->video_dev = video_device_alloc();
if (cam->video_dev == NULL)
@@ -1382,6 +1591,7 @@ static void csi_v4l2_master_detach(struct v4l2_int_device *slave)
*/
static __init int camera_init(void)
{
+ struct scatterlist *sg;
u8 err = 0;
/* Register the device driver structure. */
@@ -1430,6 +1640,11 @@ static __init int camera_init(void)
pr_debug(" Video device registered: %s #%d\n",
g_cam->video_dev->name, g_cam->video_dev->minor);
+ g_cam->pxp_chan = NULL;
+ /* Initialize Scatter-gather list containing 2 buffer addresses. */
+ sg = g_cam->sg;
+ sg_init_table(sg, 2);
+
return err;
}
diff --git a/drivers/media/video/mxc/capture/fsl_csi.c b/drivers/media/video/mxc/capture/fsl_csi.c
index dba35c4499e2..33a82242e95e 100644
--- a/drivers/media/video/mxc/capture/fsl_csi.c
+++ b/drivers/media/video/mxc/capture/fsl_csi.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2009-2012 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -20,6 +20,7 @@
*/
#include <linux/types.h>
#include <linux/init.h>
+#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/interrupt.h>
@@ -27,11 +28,14 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/clk.h>
+#include <linux/sched.h>
#include <mach/clock.h>
#include "mxc_v4l2_capture.h"
#include "fsl_csi.h"
+void __iomem *csi_regbase;
+static int irq_nr;
static bool g_csi_mclk_on;
static csi_irq_callback_t g_callback;
static void *g_callback_data;
@@ -164,7 +168,7 @@ void csi_start_callback(void *data)
{
cam_data *cam = (cam_data *) data;
- if (request_irq(MXC_INT_CSI, csi_irq_handler, 0, "csi", cam) < 0)
+ if (request_irq(irq_nr, csi_irq_handler, 0, "csi", cam) < 0)
pr_debug("CSI error: irq request fail\n");
}
@@ -174,7 +178,7 @@ void csi_stop_callback(void *data)
{
cam_data *cam = (cam_data *) data;
- free_irq(MXC_INT_CSI, cam);
+ free_irq(irq_nr, cam);
}
EXPORT_SYMBOL(csi_stop_callback);
@@ -254,10 +258,32 @@ void csi_mclk_disable(void)
__raw_writel(__raw_readl(CSI_CSICR1) & ~BIT_MCLKEN, CSI_CSICR1);
}
-int32_t __init csi_init_module(void)
+static int __devinit csi_probe(struct platform_device *pdev)
{
int ret = 0;
struct clk *per_clk;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "No csi irq found.\n");
+ ret = -ENODEV;
+ goto err;
+ }
+ irq_nr = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "No csi base address found.\n");
+ ret = -ENODEV;
+ goto err;
+ }
+ csi_regbase = ioremap(res->start, resource_size(res));
+ if (!csi_regbase) {
+ dev_err(&pdev->dev, "ioremap failed with csi base\n");
+ ret = -ENOMEM;
+ goto err;
+ }
csihw_reset();
csi_init_interface();
@@ -271,12 +297,34 @@ int32_t __init csi_init_module(void)
clk_enable(per_clk);
csi_mclk_recalc(&csi_mclk);
+err:
return ret;
}
-void __exit csi_cleanup_module(void)
+static int __devexit csi_remove(struct platform_device *pdev)
{
clk_disable(&csi_mclk);
+ iounmap(csi_regbase);
+
+ return 0;
+}
+
+static struct platform_driver csi_driver = {
+ .driver = {
+ .name = "fsl_csi",
+ },
+ .probe = csi_probe,
+ .remove = __devexit_p(csi_remove),
+};
+
+int32_t __init csi_init_module(void)
+{
+ return platform_driver_register(&csi_driver);
+}
+
+void __exit csi_cleanup_module(void)
+{
+ platform_driver_unregister(&csi_driver);
}
module_init(csi_init_module);
diff --git a/drivers/media/video/mxc/capture/fsl_csi.h b/drivers/media/video/mxc/capture/fsl_csi.h
index 00c389892224..8dfce286fe53 100644
--- a/drivers/media/video/mxc/capture/fsl_csi.h
+++ b/drivers/media/video/mxc/capture/fsl_csi.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2009-2012 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -102,23 +102,22 @@
#define CSI_MCLK_I2C 8
#endif
-#define CSI_CSICR1 (IO_ADDRESS(CSI_BASE_ADDR))
-#define CSI_CSICR2 (IO_ADDRESS(CSI_BASE_ADDR + 0x4))
-#define CSI_CSICR3 (IO_ADDRESS(CSI_BASE_ADDR + 0x8))
-#define CSI_STATFIFO (IO_ADDRESS(CSI_BASE_ADDR + 0xC))
-#define CSI_CSIRXFIFO (IO_ADDRESS(CSI_BASE_ADDR + 0x10))
-#define CSI_CSIRXCNT (IO_ADDRESS(CSI_BASE_ADDR + 0x14))
-#define CSI_CSISR (IO_ADDRESS(CSI_BASE_ADDR + 0x18))
-
-#define CSI_CSIDBG (IO_ADDRESS(CSI_BASE_ADDR + 0x1C))
-#define CSI_CSIDMASA_STATFIFO (IO_ADDRESS(CSI_BASE_ADDR + 0x20))
-#define CSI_CSIDMATS_STATFIFO (IO_ADDRESS(CSI_BASE_ADDR + 0x24))
-#define CSI_CSIDMASA_FB1 (IO_ADDRESS(CSI_BASE_ADDR + 0x28))
-#define CSI_CSIDMASA_FB2 (IO_ADDRESS(CSI_BASE_ADDR + 0x2C))
-#define CSI_CSIFBUF_PARA (IO_ADDRESS(CSI_BASE_ADDR + 0x30))
-#define CSI_CSIIMAG_PARA (IO_ADDRESS(CSI_BASE_ADDR + 0x34))
-
-#define CSI_CSIRXFIFO_PHYADDR (CSI_BASE_ADDR + 0x10)
+extern void __iomem *csi_regbase;
+#define CSI_CSICR1 (csi_regbase)
+#define CSI_CSICR2 (csi_regbase + 0x4)
+#define CSI_CSICR3 (csi_regbase + 0x8)
+#define CSI_STATFIFO (csi_regbase + 0xC)
+#define CSI_CSIRXFIFO (csi_regbase + 0x10)
+#define CSI_CSIRXCNT (csi_regbase + 0x14)
+#define CSI_CSISR (csi_regbase + 0x18)
+
+#define CSI_CSIDBG (csi_regbase + 0x1C)
+#define CSI_CSIDMASA_STATFIFO (csi_regbase + 0x20)
+#define CSI_CSIDMATS_STATFIFO (csi_regbase + 0x24)
+#define CSI_CSIDMASA_FB1 (csi_regbase + 0x28)
+#define CSI_CSIDMASA_FB2 (csi_regbase + 0x2C)
+#define CSI_CSIFBUF_PARA (csi_regbase + 0x30)
+#define CSI_CSIIMAG_PARA (csi_regbase + 0x34)
static inline void csi_clear_status(unsigned long status)
{
diff --git a/drivers/media/video/mxc/capture/mt9v111.c b/drivers/media/video/mxc/capture/mt9v111.c
index 4305c56c82d9..3ae65db04486 100644
--- a/drivers/media/video/mxc/capture/mt9v111.c
+++ b/drivers/media/video/mxc/capture/mt9v111.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2004-2012 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -879,7 +879,7 @@ static int ioctl_dev_init(struct v4l2_int_device *s)
gpio_sensor_active();
- set_mclk_rate(&clock_rate);
+ set_mclk_rate(&clock_rate, 0);
mt9v111_rate_cal(&reset_frame_rate, clock_rate);
mt9v111_sensor_lib(mt9v111_device.coreReg, mt9v111_device.ifpReg);
diff --git a/drivers/media/video/mxc/capture/mxc_v4l2_capture.h b/drivers/media/video/mxc/capture/mxc_v4l2_capture.h
index 27f8a78a93b3..034fd168290f 100644
--- a/drivers/media/video/mxc/capture/mxc_v4l2_capture.h
+++ b/drivers/media/video/mxc/capture/mxc_v4l2_capture.h
@@ -31,6 +31,10 @@
#include <linux/list.h>
#include <linux/ipu.h>
#include <linux/mxc_v4l2.h>
+#include <linux/completion.h>
+#include <linux/dmaengine.h>
+#include <linux/pxp_dma.h>
+#include <mach/dma.h>
#include <mach/ipu-v3.h>
#include <media/v4l2-dev.h>
@@ -205,6 +209,14 @@ typedef struct _cam_data {
struct v4l2_int_device *self;
int sensor_index;
void *ipu;
+
+ /* v4l2 buf elements related to PxP DMA */
+ struct completion pxp_tx_cmpl;
+ struct pxp_channel *pxp_chan;
+ struct pxp_config_data pxp_conf;
+ struct dma_async_tx_descriptor *txd;
+ dma_cookie_t cookie;
+ struct scatterlist sg[2];
} cam_data;
struct sensor_data {
@@ -232,11 +244,5 @@ struct sensor_data {
void (*io_init)(void);
};
-#if defined(CONFIG_MXC_IPU_V1) || defined(CONFIG_VIDEO_MXC_EMMA_CAMERA) \
- || defined(CONFIG_VIDEO_MXC_CSI_CAMERA_MODULE) \
- || defined(CONFIG_VIDEO_MXC_CSI_CAMERA)
-void set_mclk_rate(uint32_t *p_mclk_freq);
-#else
void set_mclk_rate(uint32_t *p_mclk_freq, uint32_t csi);
-#endif
#endif /* __MXC_V4L2_CAPTURE_H__ */
diff --git a/drivers/media/video/mxc/capture/ov2640.c b/drivers/media/video/mxc/capture/ov2640.c
index a0a050bca2e9..24ebd5027ff1 100644
--- a/drivers/media/video/mxc/capture/ov2640.c
+++ b/drivers/media/video/mxc/capture/ov2640.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2005-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -801,7 +801,7 @@ static int ioctl_dev_init(struct v4l2_int_device *s)
pr_debug(" Setting mclk to %d MHz\n",
tgt_xclk / 1000000);
- set_mclk_rate(&ov2640_data.mclk);
+ set_mclk_rate(&ov2640_data.mclk, 0);
return ov2640_init_mode(sensor);
}
diff --git a/drivers/media/video/mxc/capture/sensor_clock.c b/drivers/media/video/mxc/capture/sensor_clock.c
index 8004aeee5dc2..150659fa5dc0 100644
--- a/drivers/media/video/mxc/capture/sensor_clock.c
+++ b/drivers/media/video/mxc/capture/sensor_clock.c
@@ -26,31 +26,6 @@
#include <mach/hardware.h>
#include <asm/mach-types.h>
-#if defined(CONFIG_MXC_IPU_V1) || defined(CONFIG_VIDEO_MXC_EMMA_CAMERA) \
- || defined(CONFIG_VIDEO_MXC_CSI_CAMERA_MODULE) \
- || defined(CONFIG_VIDEO_MXC_CSI_CAMERA)
-/*
- * set_mclk_rate
- *
- * @param p_mclk_freq mclk frequence
- *
- */
-void set_mclk_rate(uint32_t *p_mclk_freq)
-{
- struct clk *clk;
- uint32_t freq = 0;
-
- clk = clk_get(NULL, "csi_clk");
-
- freq = clk_round_rate(clk, *p_mclk_freq);
- clk_set_rate(clk, freq);
-
- *p_mclk_freq = freq;
-
- clk_put(clk);
- pr_debug("mclk frequency = %d\n", *p_mclk_freq);
-}
-#else
/*
* set_mclk_rate
*
@@ -81,6 +56,8 @@ void set_mclk_rate(uint32_t *p_mclk_freq, uint32_t csi)
pr_err("invalid csi num %d\n", csi);
return;
};
+ } else if (cpu_is_mx25() || cpu_is_mx6sl()) { /* only has CSI0 */
+ mclk = "csi_clk";
} else {
if (csi == 0) {
mclk = "csi_mclk1";
@@ -102,7 +79,6 @@ void set_mclk_rate(uint32_t *p_mclk_freq, uint32_t csi)
clk_put(clk);
pr_debug("%s frequency = %d\n", mclk, *p_mclk_freq);
}
-#endif
/* Exported symbols for modules. */
EXPORT_SYMBOL(set_mclk_rate);
diff --git a/drivers/media/video/mxc/output/mxc_vout.c b/drivers/media/video/mxc/output/mxc_vout.c
index 366d27a92286..388c4b39570f 100644
--- a/drivers/media/video/mxc/output/mxc_vout.c
+++ b/drivers/media/video/mxc/output/mxc_vout.c
@@ -861,6 +861,7 @@ static int mxc_vout_open(struct file *file)
vout->win_pos.x = 0;
vout->win_pos.y = 0;
+ vout->release = true;
}
file->private_data = vout;
@@ -973,6 +974,7 @@ static inline int vdoaipu_try_task(struct mxc_vout_output *vout)
int is_1080p_stream;
size_t size;
struct ipu_task *ipu_task = &vout->task;
+ struct ipu_crop *icrop = &ipu_task->input.crop;
struct ipu_task *vdoa_task = &vout->vdoa_task;
u32 deinterlace = 0;
u32 in_fmt;
@@ -981,15 +983,23 @@ static inline int vdoaipu_try_task(struct mxc_vout_output *vout)
deinterlace = 1;
memset(vdoa_task, 0, sizeof(*vdoa_task));
- memcpy(&vdoa_task->input, &ipu_task->input, sizeof(ipu_task->input));
vdoa_task->output.format = IPU_PIX_FMT_NV12;
- vdoa_task->output.width = ipu_task->input.crop.w;
- vdoa_task->output.height = ipu_task->input.crop.h;
- vdoa_task->output.crop.w = ipu_task->input.crop.w;
- vdoa_task->output.crop.h = ipu_task->input.crop.h;
-
- size = PAGE_ALIGN(ipu_task->input.crop.w *
- ipu_task->input.crop.h *
+ memcpy(&vdoa_task->input, &ipu_task->input,
+ sizeof(ipu_task->input));
+ if ((icrop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN) ||
+ (icrop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN)) {
+ vdoa_task->input.crop.w =
+ ALIGN(icrop->w, IPU_PIX_FMT_TILED_NV12_MBALIGN);
+ vdoa_task->input.crop.h =
+ ALIGN(icrop->h, IPU_PIX_FMT_TILED_NV12_MBALIGN);
+ }
+ vdoa_task->output.width = vdoa_task->input.crop.w;
+ vdoa_task->output.height = vdoa_task->input.crop.h;
+ vdoa_task->output.crop.w = vdoa_task->input.crop.w;
+ vdoa_task->output.crop.h = vdoa_task->input.crop.h;
+
+ size = PAGE_ALIGN(vdoa_task->input.crop.w *
+ vdoa_task->input.crop.h *
fmt_to_bpp(vdoa_task->output.format)/8);
if (size > vout->vdoa_work.size) {
if (vout->vdoa_work.vaddr)
@@ -1029,6 +1039,7 @@ static int mxc_vout_try_task(struct mxc_vout_output *vout)
u32 o_height = 0;
u32 ocrop_h = 0;
bool tiled_fmt = false;
+ bool tiled_need_pp = false;
vout->vdoa_1080p = CHECK_TILED_1080P_DISPLAY(vout);
if (vout->vdoa_1080p) {
@@ -1041,10 +1052,17 @@ static int mxc_vout_try_task(struct mxc_vout_output *vout)
if ((IPU_PIX_FMT_TILED_NV12 == input->format) ||
(IPU_PIX_FMT_TILED_NV12F == input->format)) {
- crop->w -= crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN;
- crop->h -= crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN;
- crop->pos.x -= crop->pos.x % IPU_PIX_FMT_TILED_NV12_MBALIGN;
- crop->pos.y -= crop->pos.y % IPU_PIX_FMT_TILED_NV12_MBALIGN;
+ if ((input->width % IPU_PIX_FMT_TILED_NV12_MBALIGN) ||
+ (input->height % IPU_PIX_FMT_TILED_NV12_MBALIGN) ||
+ (crop->pos.x % IPU_PIX_FMT_TILED_NV12_MBALIGN) ||
+ (crop->pos.y % IPU_PIX_FMT_TILED_NV12_MBALIGN)) {
+ v4l2_err(vout->vfd->v4l2_dev,
+ "ERR: tiled fmt needs 16 pixel align.\n");
+ return -EINVAL;
+ }
+ if ((crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN) ||
+ (crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN))
+ tiled_need_pp = true;
} else {
crop->w -= crop->w % 8;
crop->h -= crop->h % 8;
@@ -1072,7 +1090,8 @@ static int mxc_vout_try_task(struct mxc_vout_output *vout)
if ((IPU_PIX_FMT_TILED_NV12 == input->format) ||
(IPU_PIX_FMT_TILED_NV12F == input->format)) {
/* check resize/rotate/flip, or csc task */
- if (!((IPU_ROTATE_NONE != output->rotate) ||
+ if (!(tiled_need_pp ||
+ (IPU_ROTATE_NONE != output->rotate) ||
(input->crop.w != output->crop.w) ||
(input->crop.h != output->crop.h) ||
(!vout->disp_support_csc &&
diff --git a/drivers/mfd/mxc-hdmi-core.c b/drivers/mfd/mxc-hdmi-core.c
index e9322477ff6d..a07db1b0c070 100644
--- a/drivers/mfd/mxc-hdmi-core.c
+++ b/drivers/mfd/mxc-hdmi-core.c
@@ -41,6 +41,7 @@
#include <linux/mfd/mxc-hdmi-core.h>
#include <linux/fsl_devices.h>
#include <mach/hardware.h>
+#include <linux/mfd/mxc-hdmi-core.h>
struct mxc_hdmi_data {
struct platform_device *pdev;
@@ -72,22 +73,29 @@ static spinlock_t hdmi_audio_lock, hdmi_blank_state_lock, hdmi_cable_state_lock;
unsigned int hdmi_set_cable_state(unsigned int state)
{
unsigned long flags;
+ struct snd_pcm_substream *substream = hdmi_audio_stream_playback;
spin_lock_irqsave(&hdmi_cable_state_lock, flags);
hdmi_cable_state = state;
spin_unlock_irqrestore(&hdmi_cable_state_lock, flags);
+ if (check_hdmi_state() && substream)
+ substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START);
return 0;
}
unsigned int hdmi_set_blank_state(unsigned int state)
{
unsigned long flags;
+ struct snd_pcm_substream *substream = hdmi_audio_stream_playback;
spin_lock_irqsave(&hdmi_blank_state_lock, flags);
hdmi_blank_state = state;
spin_unlock_irqrestore(&hdmi_blank_state_lock, flags);
+ if (check_hdmi_state() && substream)
+ substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START);
+
return 0;
}
@@ -98,7 +106,7 @@ static void hdmi_audio_abort_stream(struct snd_pcm_substream *substream)
snd_pcm_stream_lock_irqsave(substream, flags);
if (snd_pcm_running(substream))
- snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
+ substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP);
snd_pcm_stream_unlock_irqrestore(substream, flags);
}
@@ -114,7 +122,7 @@ int mxc_hdmi_abort_stream(void)
return 0;
}
-static int check_hdmi_state(void)
+int check_hdmi_state(void)
{
unsigned long flags1, flags2;
unsigned int ret;
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index e4cd11b97c24..9db650f00734 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -658,6 +658,9 @@ static int mmc_sdio_suspend(struct mmc_host *host)
mmc_release_host(host);
}
+ if (!err)
+ mmc_claim_host(host);
+
return err;
}
@@ -668,9 +671,6 @@ static int mmc_sdio_resume(struct mmc_host *host)
BUG_ON(!host);
BUG_ON(!host->card);
- /* Basic card reinitialization. */
- mmc_claim_host(host);
-
/* No need to reinitialize powered-resumed nonremovable cards */
if (mmc_card_is_removable(host) && !mmc_card_keep_power(host))
err = mmc_sdio_init_card(host, host->ocr, host->card,
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index f25b7c27b101..cc353ce5ae7e 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -873,7 +873,7 @@ static void block_mark_swapping(struct gpmi_nand_data *this,
}
static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int page)
+ uint8_t *buf, int oob_required, int page)
{
struct gpmi_nand_data *this = chip->priv;
struct bch_geometry *nfc_geo = &this->bch_geometry;
@@ -939,17 +939,20 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
mtd->ecc_stats.corrected += corrected;
}
- /*
- * It's time to deliver the OOB bytes. See gpmi_ecc_read_oob() for
- * details about our policy for delivering the OOB.
- *
- * We fill the caller's buffer with set bits, and then copy the block
- * mark to th caller's buffer. Note that, if block mark swapping was
- * necessary, it has already been done, so we can rely on the first
- * byte of the auxiliary buffer to contain the block mark.
- */
- memset(chip->oob_poi, ~0, mtd->oobsize);
- chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0];
+ if (oob_required) {
+ /*
+ * It's time to deliver the OOB bytes. See gpmi_ecc_read_oob()
+ * for details about our policy for delivering the OOB.
+ *
+ * We fill the caller's buffer with set bits, and then copy the
+ * block mark to th caller's buffer. Note that, if block mark
+ * swapping was necessary, it has already been done, so we can
+ * rely on the first byte of the auxiliary buffer to contain
+ * the block mark.
+ */
+ memset(chip->oob_poi, ~0, mtd->oobsize);
+ chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0];
+ }
read_page_swap_end(this, buf, mtd->writesize,
this->payload_virt, this->payload_phys,
@@ -959,8 +962,8 @@ exit_nfc:
return ret;
}
-static void gpmi_ecc_write_page(struct mtd_info *mtd,
- struct nand_chip *chip, const uint8_t *buf)
+static void gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf, int oob_required)
{
struct gpmi_nand_data *this = chip->priv;
struct bch_geometry *nfc_geo = &this->bch_geometry;
@@ -1040,7 +1043,7 @@ static int gpmi_verify_buf(struct mtd_info *mtd, const uint8_t * buf, int len)
{
struct nand_chip *nand = mtd->priv;
- gpmi_ecc_read_page(mtd, nand, verify_buf, len);
+ gpmi_ecc_read_page(mtd, nand, verify_buf, 0, len);
if (memcmp(buf, verify_buf, len))
return -EFAULT;
return 0;
@@ -1353,7 +1356,7 @@ static int __devinit mx23_write_transcription_stamp(struct gpmi_nand_data *this)
/* Write the first page of the current stride. */
dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page);
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
- chip->ecc.write_page_raw(mtd, chip, buffer);
+ chip->ecc.write_page_raw(mtd, chip, buffer, 0);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
/* Wait for the write to finish. */
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index e14f8284e79f..6367eac4461b 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1051,12 +1051,13 @@ EXPORT_SYMBOL(nand_lock);
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
* @page: page number to read
*
* Not for syndrome calculating ecc controllers, which use a special oob layout
*/
static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int page)
+ uint8_t *buf, int oob_required, int page)
{
chip->read_buf(mtd, buf, mtd->writesize);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
@@ -1068,13 +1069,14 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
* @page: page number to read
*
* We need a special oob layout and handling even when OOB isn't used.
*/
static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip,
- uint8_t *buf, int page)
+ struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
int eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
@@ -1111,10 +1113,11 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
* @page: page number to read
*/
static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int page)
+ uint8_t *buf, int oob_required, int page)
{
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
@@ -1124,7 +1127,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *ecc_code = chip->buffers->ecccode;
uint32_t *eccpos = chip->ecc.layout->eccpos;
- chip->ecc.read_page_raw(mtd, chip, buf, page);
+ chip->ecc.read_page_raw(mtd, chip, buf, 1, page);
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
@@ -1239,12 +1242,13 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
* @page: page number to read
*
* Not for syndrome calculating ecc controllers which need a special oob layout
*/
static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int page)
+ uint8_t *buf, int oob_required, int page)
{
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
@@ -1284,6 +1288,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
* @page: page number to read
*
* Hardware ECC for large page chips, require OOB to be read first.
@@ -1294,7 +1299,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
* overwriting the NAND manufacturer bad block markings.
*/
static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
- struct nand_chip *chip, uint8_t *buf, int page)
+ struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
{
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
@@ -1333,13 +1338,14 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
* @page: page number to read
*
* The hw generator calculates the error syndrome automatically. Therefor
* we need a special oob layout and handling.
*/
static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int page)
+ uint8_t *buf, int oob_required, int page)
{
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
@@ -1443,7 +1449,7 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops)
{
- int chipnr, page, realpage, col, bytes, aligned;
+ int chipnr, page, realpage, col, bytes, aligned, oob_required;
struct nand_chip *chip = mtd->priv;
struct mtd_ecc_stats stats;
int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
@@ -1468,6 +1474,7 @@ int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
buf = ops->datbuf;
oob = ops->oobbuf;
+ oob_required = oob ? 1 : 0;
while (1) {
bytes = min(mtd->writesize - col, readlen);
@@ -1485,13 +1492,15 @@ int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
/* Now read the page into the buffer */
if (unlikely(ops->mode == MTD_OOB_RAW))
ret = chip->ecc.read_page_raw(mtd, chip,
- bufpoi, page);
+ bufpoi,
+ oob_required,
+ page);
else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob)
ret = chip->ecc.read_subpage(mtd, chip,
col, bytes, bufpoi);
else
ret = chip->ecc.read_page(mtd, chip, bufpoi,
- page);
+ oob_required, page);
if (ret < 0)
break;
@@ -1893,11 +1902,12 @@ out:
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
+ * @oob_required: must write chip->oob_poi to OOB
*
* Not for syndrome calculating ecc controllers, which use a special oob layout
*/
static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf)
+ const uint8_t *buf, int oob_required)
{
chip->write_buf(mtd, buf, mtd->writesize);
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
@@ -1908,12 +1918,13 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
+ * @oob_required: must write chip->oob_poi to OOB
*
* We need a special oob layout and handling even when ECC isn't checked.
*/
static void nand_write_page_raw_syndrome(struct mtd_info *mtd,
struct nand_chip *chip,
- const uint8_t *buf)
+ const uint8_t *buf, int oob_required)
{
int eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
@@ -1947,9 +1958,10 @@ static void nand_write_page_raw_syndrome(struct mtd_info *mtd,
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
+ * @oob_required: must write chip->oob_poi to OOB
*/
static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf)
+ const uint8_t *buf, int oob_required)
{
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
@@ -1965,7 +1977,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
for (i = 0; i < chip->ecc.total; i++)
chip->oob_poi[eccpos[i]] = ecc_calc[i];
- chip->ecc.write_page_raw(mtd, chip, buf);
+ chip->ecc.write_page_raw(mtd, chip, buf, 1);
}
/**
@@ -1973,9 +1985,10 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
+ * @oob_required: must write chip->oob_poi to OOB
*/
static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf)
+ const uint8_t *buf, int oob_required)
{
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
@@ -2001,12 +2014,14 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
+ * @oob_required: must write chip->oob_poi to OOB
*
* The hw generator calculates the error syndrome automatically. Therefor
* we need a special oob layout and handling.
*/
static void nand_write_page_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip, const uint8_t *buf)
+ struct nand_chip *chip,
+ const uint8_t *buf, int oob_required)
{
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
@@ -2045,21 +2060,23 @@ static void nand_write_page_syndrome(struct mtd_info *mtd,
* @mtd: MTD device structure
* @chip: NAND chip descriptor
* @buf: the data to write
+ * @oob_required: must write chip->oob_poi to OOB
* @page: page number to write
* @cached: cached programming
* @raw: use _raw version of write_page
*/
static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int page, int cached, int raw)
+ const uint8_t *buf, int oob_required, int page,
+ int cached, int raw)
{
int status;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
if (unlikely(raw))
- chip->ecc.write_page_raw(mtd, chip, buf);
+ chip->ecc.write_page_raw(mtd, chip, buf, oob_required);
else
- chip->ecc.write_page(mtd, chip, buf);
+ chip->ecc.write_page(mtd, chip, buf, oob_required);
/*
* Cached progamming disabled for now, Not sure if its worth the
@@ -2176,6 +2193,7 @@ int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
uint8_t *oob = ops->oobbuf;
uint8_t *buf = ops->datbuf;
int ret, subpage;
+ int oob_required = oob ? 1 : 0;
ops->retlen = 0;
if (!writelen)
@@ -2238,7 +2256,7 @@ int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
memset(chip->oob_poi, 0xff, mtd->oobsize);
}
- ret = chip->write_page(mtd, chip, wbuf, page, cached,
+ ret = chip->write_page(mtd, chip, wbuf, oob_required, page, cached,
(ops->mode == MTD_OOB_RAW));
if (ret)
break;
diff --git a/drivers/mxc/gpu-viv/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.c b/drivers/mxc/gpu-viv/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.c
index e09a46b3d7b5..36b7bcfab997 100644
--- a/drivers/mxc/gpu-viv/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.c
+++ b/drivers/mxc/gpu-viv/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.c
@@ -4282,7 +4282,7 @@ gckHARDWARE_SetFscaleValue(
gctUINT32 clock;
gctBOOL acquired = gcvFALSE;
- gcmkHEADER_ARG("Hardware=0x%x FscaleVal=%d", Hardware, FscaleVal);
+ gcmkHEADER_ARG("Hardware=0x%x FscaleValue=%d", Hardware, FscaleValue);
gcmkVERIFY_ARGUMENT(FscaleValue > 0 && FscaleValue <= 64);
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_command.c b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_command.c
index 8cf0509cfd92..e05a143f41c3 100644
--- a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_command.c
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_command.c
@@ -30,6 +30,9 @@
#define _GC_OBJ_ZONE gcvZONE_COMMAND
+#if gcdENABLE_FSCALE_VAL_ADJUST
+extern int thermal_hot;
+#endif
/******************************************************************************\
********************************* Support Code *********************************
\******************************************************************************/
@@ -1080,6 +1083,24 @@ gckCOMMAND_Commit(
/* Extract the gckHARDWARE and gckEVENT objects. */
hardware = Command->kernel->hardware;
+#if gcdENABLE_FSCALE_VAL_ADJUST
+ if(hardware->core == gcvCORE_MAJOR){
+ static gctUINT orgFscale,minFscale,maxFscale;
+ static gctBOOL bAlreadyTooHot = gcvFALSE;
+ if((thermal_hot > 0) && (!bAlreadyTooHot)) {
+ gckHARDWARE_GetFscaleValue(hardware,&orgFscale,&minFscale, &maxFscale);
+ gckHARDWARE_SetFscaleValue(hardware, minFscale);
+ bAlreadyTooHot = gcvTRUE;
+ gckOS_Print("System is too hot. GPU3D will work at %d/64 clock.\n", minFscale);
+ } else if((!(thermal_hot > 0)) && bAlreadyTooHot) {
+ gckHARDWARE_SetFscaleValue(hardware, orgFscale);
+ gckOS_Print("Hot alarm is canceled. GPU3D clock will return to %d/64\n", orgFscale);
+ bAlreadyTooHot = gcvFALSE;
+ }
+
+ }
+#endif
+
/* Check wehther we need to copy the structures or not. */
gcmkONERROR(gckOS_QueryNeedCopy(Command->os, ProcessID, &needCopy));
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.c
index 890d13e17c50..eba81b64be92 100644
--- a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.c
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.c
@@ -358,6 +358,15 @@ gckGALDEVICE_Construct(
gckDebugFileSystemSetCurrentNode(device->dbgnode);
}
}
+ /*get gpu regulator*/
+ device->gpu_regulator = regulator_get(NULL, "cpu_vddgpu");
+ if (IS_ERR(device->gpu_regulator)) {
+ gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): Failed to get gpu regulator %s/%s \n",
+ __FUNCTION__, __LINE__,
+ PARENT_FILE, DEBUG_FILE);
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
/*Initialize the clock structure*/
if (IrqLine != -1) {
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.h b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.h
index 03f7f9b2201e..c15989894600 100644
--- a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.h
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.h
@@ -89,6 +89,9 @@ typedef struct _gckGALDEVICE
struct clk *clk_2d_axi;
struct clk *clk_vg_axi;
+ /*Power management.*/
+ struct regulator *gpu_regulator;
+
}
* gckGALDEVICE;
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_linux.h b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_linux.h
index 30fb13596dda..a6ed03ffc0f9 100644
--- a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_linux.h
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_linux.h
@@ -47,6 +47,7 @@
#if ENABLE_GPU_CLOCK_BY_DRIVER && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
#endif
#define NTSTRSAFE_NO_CCH_FUNCTIONS
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c
index 4d1a71dfa91a..4091ccdb61d4 100644
--- a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c
@@ -6947,6 +6947,7 @@ gckOS_SetGPUPower(
struct clk *clk_vg_axi = Os->device->clk_vg_axi;
gctBOOL oldClockState = gcvFALSE;
+ gctBOOL oldPowerState = gcvFALSE;
gcmkHEADER_ARG("Os=0x%X Core=%d Clock=%d Power=%d", Os, Core, Clock, Power);
@@ -6956,15 +6957,20 @@ gckOS_SetGPUPower(
if (Core == gcvCORE_VG)
{
oldClockState = Os->device->kernels[Core]->vg->hardware->clockState;
+ oldPowerState = Os->device->kernels[Core]->vg->hardware->powerState;
}
else
{
#endif
oldClockState = Os->device->kernels[Core]->hardware->clockState;
+ oldPowerState = Os->device->kernels[Core]->hardware->powerState;
#if gcdENABLE_VG
}
#endif
}
+ if((Power == gcvTRUE) && (oldPowerState == gcvFALSE) &&
+ !IS_ERR(Os->device->gpu_regulator))
+ regulator_enable(Os->device->gpu_regulator);
if (Clock == gcvTRUE) {
if (oldClockState == gcvFALSE) {
@@ -7007,8 +7013,10 @@ gckOS_SetGPUPower(
}
}
}
-
-
+ if((Power == gcvFALSE) && (oldPowerState == gcvTRUE) &&
+ !IS_ERR(Os->device->gpu_regulator))
+ regulator_disable(Os->device->gpu_regulator);
+ /* TODO: Put your code here. */
gcmkFOOTER_NO();
return gcvSTATUS_OK;
}
diff --git a/drivers/mxc/ipu3/ipu_device.c b/drivers/mxc/ipu3/ipu_device.c
index d12ffdfc7847..be1725129ce2 100644
--- a/drivers/mxc/ipu3/ipu_device.c
+++ b/drivers/mxc/ipu3/ipu_device.c
@@ -340,6 +340,7 @@ struct ipu_alloc_list {
dma_addr_t phy_addr;
void *cpu_addr;
u32 size;
+ void *file_index;
};
static LIST_HEAD(ipu_alloc_list);
@@ -350,6 +351,7 @@ static DEFINE_SPINLOCK(ipu_task_list_lock);
static DECLARE_WAIT_QUEUE_HEAD(thread_waitq);
static DECLARE_WAIT_QUEUE_HEAD(res_waitq);
static atomic_t req_cnt;
+static atomic_t file_index = ATOMIC_INIT(1);
static int major;
static int max_ipu_no;
static int thread_id;
@@ -3274,6 +3276,7 @@ EXPORT_SYMBOL_GPL(ipu_queue_task);
static int mxc_ipu_open(struct inode *inode, struct file *file)
{
+ file->private_data = (void *)atomic_inc_return(&file_index);
return 0;
}
@@ -3330,6 +3333,7 @@ static long mxc_ipu_ioctl(struct file *file,
kfree(mem);
return -ENOMEM;
}
+ mem->file_index = file->private_data;
mutex_lock(&ipu_alloc_lock);
list_add(&mem->list, &ipu_alloc_list);
mutex_unlock(&ipu_alloc_lock);
@@ -3413,6 +3417,26 @@ static int mxc_ipu_mmap(struct file *file, struct vm_area_struct *vma)
static int mxc_ipu_release(struct inode *inode, struct file *file)
{
+ struct ipu_alloc_list *mem;
+ struct ipu_alloc_list *n;
+
+ mutex_lock(&ipu_alloc_lock);
+ list_for_each_entry_safe(mem, n, &ipu_alloc_list, list) {
+ if ((mem->cpu_addr != 0) &&
+ (file->private_data == mem->file_index)) {
+ list_del(&mem->list);
+ dma_free_coherent(ipu_dev,
+ mem->size,
+ mem->cpu_addr,
+ mem->phy_addr);
+ dev_dbg(ipu_dev, "rel-free %d bytes @ 0x%08X\n",
+ mem->size, mem->phy_addr);
+ kfree(mem);
+ }
+ }
+ mutex_unlock(&ipu_alloc_lock);
+ atomic_dec(&file_index);
+
return 0;
}
diff --git a/drivers/mxc/thermal/cooling.c b/drivers/mxc/thermal/cooling.c
index 0feefeaa6008..7019d9949c8a 100644
--- a/drivers/mxc/thermal/cooling.c
+++ b/drivers/mxc/thermal/cooling.c
@@ -57,6 +57,7 @@ cpufreq, it minor 1, and when we promote cpufreq, it add 1, so
if it is 0, mean we didn't change the cpufreq */
static int cpufreq_change_count;
+extern int thermal_hot;
int anatop_thermal_get_cpufreq_cur(void)
{
int ret = -EINVAL;
@@ -237,6 +238,7 @@ imx_processor_set_cur_state(struct thermal_cooling_device *cdev,
secondary CPUs that detached by thermal driver */
if (cooling_cpuhotplug) {
if (!state) {
+ thermal_hot = 0;
for (i = 1; i < 4; i++) {
if (cpu_mask && (0x1 << i)) {
anatop_thermal_cpu_hotplug(true);
@@ -247,6 +249,7 @@ imx_processor_set_cur_state(struct thermal_cooling_device *cdev,
}
} else {
if (!state) {
+ thermal_hot = 0;
if (cpufreq_change_count < 0)
anatop_thermal_cpufreq_up();
else if (cpufreq_change_count > 0)
diff --git a/drivers/mxc/vpu/mxc_vpu.c b/drivers/mxc/vpu/mxc_vpu.c
index 92a1d0dc98c7..8178824ab80a 100644
--- a/drivers/mxc/vpu/mxc_vpu.c
+++ b/drivers/mxc/vpu/mxc_vpu.c
@@ -39,6 +39,7 @@
#include <linux/workqueue.h>
#include <linux/sched.h>
#include <linux/vmalloc.h>
+#include <linux/regulator/consumer.h>
#include <linux/page-flags.h>
#include <linux/mm_types.h>
#include <linux/types.h>
@@ -110,6 +111,7 @@ static int vpu_jpu_irq;
#endif
static unsigned int regBk[64];
+static struct regulator *vpu_regulator;
#define READ_REG(x) __raw_readl(vpu_base + x)
#define WRITE_REG(val, x) __raw_writel(val, vpu_base + x)
@@ -245,8 +247,12 @@ bool vpu_is_valid_phy_memory(u32 paddr)
*/
static int vpu_open(struct inode *inode, struct file *filp)
{
+
mutex_lock(&vpu_data.lock);
- open_count++;
+
+ if (open_count++ == 0 && !IS_ERR(vpu_regulator))
+ regulator_enable(vpu_regulator);
+
filp->private_data = (void *)(&vpu_data);
mutex_unlock(&vpu_data.lock);
return 0;
@@ -531,6 +537,9 @@ static int vpu_release(struct inode *inode, struct file *filp)
mutex_lock(&vpu_data.lock);
if (open_count > 0 && !(--open_count)) {
+ if (!IS_ERR(vpu_regulator))
+ regulator_disable(vpu_regulator);
+
vpu_free_buffers();
/* Free shared memory when vpu device is idle */
@@ -705,6 +714,12 @@ static int vpu_dev_probe(struct platform_device *pdev)
(void *)(&vpu_data));
if (err)
goto err_out_class;
+ vpu_regulator = regulator_get(NULL, "cpu_vddvpu");
+ if (IS_ERR(vpu_regulator)) {
+ printk(KERN_ERR
+ "%s: failed to get vpu regulator\n", __func__);
+ goto err_out_class;
+ }
#ifdef MXC_VPU_HAS_JPU
vpu_jpu_irq = platform_get_irq_byname(pdev, "vpu_jpu_irq");
@@ -752,7 +767,8 @@ static int vpu_dev_remove(struct platform_device *pdev)
iounmap(vpu_base);
if (vpu_plat && vpu_plat->iram_enable && vpu_plat->iram_size)
iram_free(iram.start, vpu_plat->iram_size);
-
+ if (!IS_ERR(vpu_regulator))
+ regulator_put(vpu_regulator);
return 0;
}
@@ -762,6 +778,8 @@ static int vpu_suspend(struct platform_device *pdev, pm_message_t state)
int i;
unsigned long timeout;
+ if (!IS_ERR(vpu_regulator))
+ regulator_enable(vpu_regulator);
/* Wait for vpu go to idle state, suspect vpu cannot be changed
to idle state after about 1 sec */
if (open_count > 0) {
@@ -794,10 +812,14 @@ static int vpu_suspend(struct platform_device *pdev, pm_message_t state)
if (vpu_plat->pg)
vpu_plat->pg(1);
+ if (!IS_ERR(vpu_regulator))
+ regulator_disable(vpu_regulator);
return 0;
out:
clk_disable(vpu_clk);
+ if (!IS_ERR(vpu_regulator))
+ regulator_disable(vpu_regulator);
return -EAGAIN;
}
@@ -809,6 +831,8 @@ static int vpu_resume(struct platform_device *pdev)
if (cpu_is_mx53())
goto recover_clk;
+ if (!IS_ERR(vpu_regulator))
+ regulator_enable(vpu_regulator);
if (vpu_plat->pg)
vpu_plat->pg(0);
@@ -869,6 +893,8 @@ recover_clk:
/* Recover vpu clock */
for (i = 0; i < vpu_clk_usercount; i++)
clk_enable(vpu_clk);
+ if (!IS_ERR(vpu_regulator))
+ regulator_disable(vpu_regulator);
return 0;
}
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index 5af378f391ee..86e4ea3404b3 100755
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -397,7 +397,12 @@ fec_timeout(struct net_device *ndev)
ndev->stats.tx_errors++;
+ netif_device_detach(ndev);
+ fec_stop(ndev);
+
fec_restart(ndev, fep->full_duplex);
+ netif_device_attach(ndev);
+ ndev->trans_start = jiffies; /* prevent tx timeout */
if (fep->link && !fep->tx_full)
netif_wake_queue(ndev);
}
@@ -1320,10 +1325,7 @@ fec_enet_close(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- /* Don't know what to do yet. */
fep->opened = 0;
- netif_stop_queue(ndev);
- netif_carrier_off(ndev);
if (fep->use_napi)
napi_disable(&fep->napi);
@@ -1760,7 +1762,10 @@ fec_stop(struct net_device *dev)
if (fep->ptimer_present)
fec_ptp_stop(fep->ptp_priv);
writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
- netif_stop_queue(dev);
+
+ if (netif_running(dev))
+ netif_stop_queue(dev);
+ netif_carrier_off(dev); /* prevent tx timeout */
fep->link = 0;
}
@@ -1921,7 +1926,6 @@ fec_suspend(struct device *dev)
if (netif_running(ndev)) {
netif_device_detach(ndev);
fec_stop(ndev);
- netif_carrier_off(ndev);
clk_disable(fep->clk);
}
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 6e53cce3c7fd..a24653787d1d 100755
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -222,7 +222,6 @@ config CHARGER_MAX8903
config SABRESD_MAX8903
tristate "Sabresd Board Battery DC-DC Charger for USB and Adapter Power"
depends on GENERIC_HARDIRQS
- depends on TOUCHSCREEN_MAX11801
help
Say Y to enable support for the MAX8903 DC-DC charger and sysfs on
sabresd board.The driver supports controlling charger and battery
diff --git a/drivers/power/sabresd_battery.c b/drivers/power/sabresd_battery.c
index c7318a6eb02c..648922139790 100755
--- a/drivers/power/sabresd_battery.c
+++ b/drivers/power/sabresd_battery.c
@@ -65,13 +65,11 @@ typedef struct {
u32 voltage;
u32 percent;
} battery_capacity , *pbattery_capacity;
-
static int cpu_type_flag;
static int offset_discharger;
static int offset_charger;
static int offset_usb_charger;
-
static battery_capacity chargingTable[] = {
{4050, 99},
{4040, 98},
@@ -188,9 +186,9 @@ static enum power_supply_property max8903_battery_props[] = {
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_CAPACITY_LEVEL,
};
-
+#ifdef CONFIG_TOUCHSCREEN_MAX11801
extern u32 max11801_read_adc(void);
-
+#endif
static void max8903_charger_update_status(struct max8903_data *data)
{
if (data->usb_in || data->ta_in) {
@@ -205,26 +203,35 @@ static void max8903_charger_update_status(struct max8903_data *data)
}
if (data->charger_online == 0 && data->usb_charger_online == 0) {
data->battery_status = POWER_SUPPLY_STATUS_DISCHARGING;
- } else {
- if (gpio_get_value(data->pdata->chg) == 0) {
- data->battery_status = POWER_SUPPLY_STATUS_CHARGING;
- } else if (data->ta_in &&
- gpio_get_value(data->pdata->chg) == 1) {
- if (data->percent >= 99)
- data->battery_status = POWER_SUPPLY_STATUS_FULL;
- else
- data->battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
- }
- else if (data->usb_in &&
- gpio_get_value(data->pdata->chg) == 1) {
- if (data->percent >= 99)
- data->battery_status = POWER_SUPPLY_STATUS_FULL;
- else
- data->battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
- }
+ } else {
+ if (gpio_get_value(data->pdata->chg) == 0) {
+ data->battery_status = POWER_SUPPLY_STATUS_CHARGING;
+ } else if (data->ta_in && gpio_get_value(data->pdata->chg) == 1) {
+ if (!data->pdata->feature_flag) {
+ if (data->percent >= 99)
+ data->battery_status = POWER_SUPPLY_STATUS_FULL;
+ else
+ data->battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ } else {
+ data->battery_status = POWER_SUPPLY_STATUS_FULL;
+ }
+ } else if (data->usb_in && gpio_get_value(data->pdata->chg) == 1) {
+ if (!data->pdata->feature_flag) {
+ if (data->percent >= 99)
+ data->battery_status = POWER_SUPPLY_STATUS_FULL;
+ else
+ data->battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ } else {
+ data->battery_status = POWER_SUPPLY_STATUS_FULL;
+ }
}
- pr_debug("chg: %d \n", gpio_get_value(data->pdata->chg));
+ }
+ pr_debug("chg: %d\n", gpio_get_value(data->pdata->chg));
+ pr_debug("dc: %d\n", gpio_get_value(data->pdata->dok));
+ pr_debug("flt: %d\n", gpio_get_value(data->pdata->flt));
}
+
+#ifdef CONFIG_TOUCHSCREEN_MAX11801
static int cmp_func(const void *_a, const void *_b)
{
const int *a = _a, *b = _b;
@@ -235,6 +242,7 @@ static int cmp_func(const void *_a, const void *_b)
return -1;
return 0;
}
+
u32 calibration_voltage(struct max8903_data *data)
{
int volt[ADC_SAMPLE_COUNT];
@@ -275,51 +283,54 @@ u32 calibration_voltage(struct max8903_data *data)
voltage_data = (volt[2] + volt[ADC_SAMPLE_COUNT - 3]) / 2;
return voltage_data;
}
-
+#endif
static void max8903_battery_update_status(struct max8903_data *data)
{
- int temp;
+ int temp = 0;
static int temp_last;
bool changed_flag;
changed_flag = false;
mutex_lock(&data->work_lock);
- temp = calibration_voltage(data);
- if (temp_last == 0) {
- data->voltage_uV = temp;
- temp_last = temp;
- }
- if (data->charger_online == 0 && temp_last != 0) {
- if (temp < temp_last) {
- temp_last = temp;
- data->voltage_uV = temp;
- } else {
- data->voltage_uV = temp_last;
+ if (!data->pdata->feature_flag) {
+#ifdef CONFIG_TOUCHSCREEN_MAX11801
+ temp = calibration_voltage(data);
+#endif
+ if (temp_last == 0) {
+ data->voltage_uV = temp;
+ temp_last = temp;
+ }
+ if (data->charger_online == 0 && temp_last != 0) {
+ if (temp < temp_last) {
+ temp_last = temp;
+ data->voltage_uV = temp;
+ } else {
+ data->voltage_uV = temp_last;
+ }
+ }
+ if (data->charger_online == 1 || data->usb_charger_online == 1) {
+ data->voltage_uV = temp;
+ temp_last = temp;
+ }
+ data->percent = calibrate_battery_capability_percent(data);
+ if (data->percent != data->old_percent) {
+ data->old_percent = data->percent;
+ changed_flag = true;
+ }
+ if (changed_flag) {
+ changed_flag = false;
+ power_supply_changed(&data->bat);
+ }
+ /*
+ *because boot time gap between led framwork and charger
+ *framwork,when system boots with charger attatched,
+ *charger led framwork loses the first charger online event,
+ *add once extra power_supply_changed can fix this issure
+ */
+ if (data->first_delay_count < 200) {
+ data->first_delay_count = data->first_delay_count + 1 ;
+ power_supply_changed(&data->bat);
}
}
- if (data->charger_online == 1 || data->usb_charger_online == 1) {
- data->voltage_uV = temp;
- temp_last = temp;
- }
- data->percent = calibrate_battery_capability_percent(data);
- if (data->percent != data->old_percent) {
- data->old_percent = data->percent;
- changed_flag = true;
- }
- if (changed_flag) {
- changed_flag = false;
- power_supply_changed(&data->bat);
- }
- /*
- because boot time gap between led framwork and charger
- framwork,when system boots with charger attatched, charger
- led framwork loses the first charger online event,add once extra
- power_supply_changed can fix this issure
- */
- if (data->first_delay_count < 200) {
- data->first_delay_count = data->first_delay_count + 1 ;
- power_supply_changed(&data->bat);
- }
-
mutex_unlock(&data->work_lock);
}
@@ -332,22 +343,27 @@ static int max8903_battery_get_property(struct power_supply *bat,
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
- if (gpio_get_value(di->pdata->chg) == 0) {
- di->battery_status = POWER_SUPPLY_STATUS_CHARGING;
- } else if (di->ta_in &&
- gpio_get_value(di->pdata->chg) == 1) {
+ if (gpio_get_value(di->pdata->chg) == 0) {
+ di->battery_status = POWER_SUPPLY_STATUS_CHARGING;
+ } else if (di->ta_in && gpio_get_value(di->pdata->chg) == 1) {
+ if (!di->pdata->feature_flag) {
if (di->percent >= 99)
di->battery_status = POWER_SUPPLY_STATUS_FULL;
else
di->battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ } else {
+ di->battery_status = POWER_SUPPLY_STATUS_FULL;
}
- else if (di->usb_in &&
- gpio_get_value(di->pdata->chg) == 1) {
+ } else if (di->usb_in && gpio_get_value(di->pdata->chg) == 1) {
+ if (!di->pdata->feature_flag) {
if (di->percent >= 99)
di->battery_status = POWER_SUPPLY_STATUS_FULL;
else
- di->battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ di->battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ } else {
+ di->battery_status = POWER_SUPPLY_STATUS_FULL;
}
+ }
val->intval = di->battery_status;
return 0;
default:
@@ -795,14 +811,13 @@ static __devinit int max8903_probe(struct platform_device *pdev)
ret = request_threaded_irq(gpio_to_irq(pdata->chg),
NULL, max8903_chg,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- "MAX8903 Fault", data);
+ "MAX8903 Status", data);
if (ret) {
- dev_err(dev, "Cannot request irq %d for Fault (%d)\n",
+ dev_err(dev, "Cannot request irq %d for Status (%d)\n",
gpio_to_irq(pdata->flt), ret);
goto err_chg_irq;
}
}
-
ret = device_create_file(&pdev->dev, &max8903_discharger_dev_attr);
if (ret)
dev_err(&pdev->dev, "create device file failed!\n");
@@ -822,7 +837,6 @@ static __devinit int max8903_probe(struct platform_device *pdev)
offset_charger = 1485;
offset_usb_charger = 1285;
}
-
max8903_charger_update_status(data);
max8903_battery_update_status(data);
return 0;
@@ -888,10 +902,14 @@ static int max8903_suspend(struct platform_device *pdev,
if (data) {
struct max8903_pdata *pdata = data->pdata;
if (pdata) {
- irq = gpio_to_irq(pdata->dok);
- enable_irq_wake(irq);
- irq = gpio_to_irq(pdata->uok);
- enable_irq_wake(irq);
+ if (pdata->dc_valid) {
+ irq = gpio_to_irq(pdata->dok);
+ enable_irq_wake(irq);
+ }
+ if (pdata->usb_valid) {
+ irq = gpio_to_irq(pdata->uok);
+ enable_irq_wake(irq);
+ }
cancel_delayed_work(&data->work);
}
}
@@ -923,10 +941,14 @@ static int max8903_resume(struct platform_device *pdev)
max8903_charger_update_status(data);
power_supply_changed(&data->usb);
}
- irq = gpio_to_irq(pdata->dok);
- disable_irq_wake(irq);
- irq = gpio_to_irq(pdata->uok);
- disable_irq_wake(irq);
+ if (pdata->dc_valid) {
+ irq = gpio_to_irq(pdata->dok);
+ disable_irq_wake(irq);
+ }
+ if (pdata->usb_valid) {
+ irq = gpio_to_irq(pdata->uok);
+ disable_irq_wake(irq);
+ }
schedule_delayed_work(&data->work, BATTERY_UPDATE_INTERVAL);
}
}
diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c
index c3a48307c918..b91cf9f82543 100755
--- a/drivers/usb/gadget/arcotg_udc.c
+++ b/drivers/usb/gadget/arcotg_udc.c
@@ -3323,10 +3323,13 @@ static int udc_suspend(struct fsl_udc *udc)
* charge using usb
*/
if (pdata->pmflags == 0) {
- if (!udc_can_wakeup_system())
+ if (!udc_can_wakeup_system()) {
dr_wake_up_enable(udc, false);
- else
+ } else {
+ if (pdata->platform_phy_power_on)
+ pdata->platform_phy_power_on();
dr_wake_up_enable(udc, true);
+ }
}
/*
diff --git a/drivers/usb/host/ehci-arc.c b/drivers/usb/host/ehci-arc.c
index b872d94b3fc3..e09f4dfd05d9 100755
--- a/drivers/usb/host/ehci-arc.c
+++ b/drivers/usb/host/ehci-arc.c
@@ -678,6 +678,9 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev,
usb_host_set_wakeup(hcd->self.controller, false);
fsl_usb_clk_gate(hcd->self.controller->platform_data, false);
+ } else {
+ if (pdata->platform_phy_power_on)
+ pdata->platform_phy_power_on();
}
printk(KERN_DEBUG "host suspend ends\n");
diff --git a/drivers/video/mxc/Kconfig b/drivers/video/mxc/Kconfig
index f0afddc95bd3..8a4a0792724f 100644
--- a/drivers/video/mxc/Kconfig
+++ b/drivers/video/mxc/Kconfig
@@ -1,6 +1,6 @@
config FB_MXC
tristate "MXC Framebuffer support"
- depends on FB && (MXC_IPU || ARCH_MX21 || ARCH_MX27 || ARCH_MX25)
+ depends on FB && (MXC_IPU || ARCH_MX21 || ARCH_MX27 || ARCH_MX25 || ARCH_MX6)
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -60,6 +60,10 @@ config FB_MXC_SII902X
depends on FB_MXC_SYNC_PANEL && I2C
tristate "Si Image SII9022 DVI/HDMI Interface Chip"
+config FB_MXC_SII902X_ELCDIF
+ depends on FB_MXC_SYNC_PANEL && I2C
+ tristate "Si Image SII9022 DVI/HDMI Interface Chip for ELCDIF FB"
+
config FB_MXC_CH7026
depends on FB_MXC_SYNC_PANEL
tristate "Chrontel CH7026 VGA Interface Chip"
diff --git a/drivers/video/mxc/Makefile b/drivers/video/mxc/Makefile
index 21aef052ecd6..092d0aacba27 100644
--- a/drivers/video/mxc/Makefile
+++ b/drivers/video/mxc/Makefile
@@ -1,9 +1,10 @@
obj-$(CONFIG_FB_MXC_TVOUT_TVE) += tve.o
obj-$(CONFIG_FB_MXC_SII902X) += mxcfb_sii902x.o
+obj-$(CONFIG_FB_MXC_SII902X_ELCDIF) += mxcfb_sii902x_elcdif.o
obj-$(CONFIG_FB_MXC_LDB) += ldb.o
obj-$(CONFIG_FB_MXC_MIPI_DSI) += mipi_dsi.o
obj-$(CONFIG_FB_MXC_TRULY_WVGA_SYNC_PANEL) += mxcfb_hx8369_wvga.o
-obj-$(CONFIG_FB_MXC_EDID) += mxc_edid.o mxc_dvi.o
+obj-$(CONFIG_FB_MXC_EDID) += mxc_edid.o
ifeq ($(CONFIG_ARCH_MX21)$(CONFIG_ARCH_MX27)$(CONFIG_ARCH_MX25),y)
obj-$(CONFIG_FB_MXC_TVOUT) += fs453.o
obj-$(CONFIG_FB_MXC_SYNC_PANEL) += mx2fb.o mxcfb_modedb.o
@@ -11,8 +12,10 @@ ifeq ($(CONFIG_ARCH_MX21)$(CONFIG_ARCH_MX27)$(CONFIG_ARCH_MX25),y)
else
ifeq ($(CONFIG_MXC_IPU_V1),y)
obj-$(CONFIG_FB_MXC_SYNC_PANEL) += mxcfb.o mxcfb_modedb.o
-else
+endif
+ifeq ($(CONFIG_MXC_IPU_V3),y)
obj-$(CONFIG_FB_MXC_SYNC_PANEL) += mxc_dispdrv.o mxc_lcdif.o mxc_ipuv3_fb.o
+ obj-$(CONFIG_FB_MXC_EDID) += mxc_dvi.o
endif
obj-$(CONFIG_FB_MXC_EPSON_PANEL) += mxcfb_epson.o
obj-$(CONFIG_FB_MXC_EPSON_QVGA_PANEL) += mxcfb_epson_qvga.o
diff --git a/drivers/video/mxc/mxc_elcdif_fb.c b/drivers/video/mxc/mxc_elcdif_fb.c
index 9c3b7b99a411..be521ddbdf9d 100644
--- a/drivers/video/mxc/mxc_elcdif_fb.c
+++ b/drivers/video/mxc/mxc_elcdif_fb.c
@@ -86,6 +86,12 @@ struct elcdif_signal_cfg {
unsigned Vsync_pol:1; /* true = active high */
};
+struct mxcfb_mode {
+ int dev_mode;
+ int num_modes;
+ struct fb_videomode *mode;
+};
+
static int mxc_elcdif_fb_blank(int blank, struct fb_info *info);
static int mxc_elcdif_fb_map_video_memory(struct fb_info *info);
static int mxc_elcdif_fb_unmap_video_memory(struct fb_info *info);
@@ -97,6 +103,15 @@ static bool g_elcdif_axi_clk_enable;
static bool g_elcdif_pix_clk_enable;
static struct clk *g_elcdif_axi_clk;
static struct clk *g_elcdif_pix_clk;
+static struct mxcfb_mode mxc_disp_mode;
+
+static void dump_fb_videomode(struct fb_videomode *m)
+{
+ pr_debug("fb_videomode = %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
+ m->refresh, m->xres, m->yres, m->pixclock, m->left_margin,
+ m->right_margin, m->upper_margin, m->lower_margin,
+ m->hsync_len, m->vsync_len, m->sync, m->vmode, m->flag);
+}
static inline void setup_dotclk_panel(u32 pixel_clk,
u16 v_pulse_width,
@@ -113,16 +128,39 @@ static inline void setup_dotclk_panel(u32 pixel_clk,
int enable_present)
{
u32 val, rounded_pixel_clk;
+ u32 rounded_parent_clk;
+ struct clk *clk_parent;
if (!g_elcdif_axi_clk_enable) {
clk_enable(g_elcdif_axi_clk);
g_elcdif_axi_clk_enable = true;
}
+ /* Init clocking */
dev_dbg(g_elcdif_dev, "pixel clk = %d\n", pixel_clk);
- rounded_pixel_clk = clk_round_rate(g_elcdif_pix_clk, pixel_clk);
+
+ clk_parent = clk_get_parent(g_elcdif_pix_clk);
+ if (clk_parent == NULL)
+ dev_err(g_elcdif_dev, "%s Failed get clk parent\n", __func__);
+
+ rounded_pixel_clk = pixel_clk * 2;
+
+ rounded_parent_clk = clk_round_rate(clk_parent,
+ rounded_pixel_clk);
+
+ while (rounded_pixel_clk < rounded_parent_clk) {
+ /* the max divider from parent to di is 8 */
+ if (rounded_parent_clk / pixel_clk < 8)
+ rounded_pixel_clk += pixel_clk * 2;
+ }
+
+ clk_set_rate(clk_parent, rounded_pixel_clk);
+ rounded_pixel_clk =
+ clk_round_rate(g_elcdif_pix_clk, pixel_clk);
clk_set_rate(g_elcdif_pix_clk, rounded_pixel_clk);
+ msleep(5);
+
__raw_writel(BM_ELCDIF_CTRL_DATA_SHIFT_DIR,
elcdif_base + HW_ELCDIF_CTRL_CLR);
@@ -519,6 +557,35 @@ static inline void mxc_init_elcdif(void)
return;
}
+void mxcfb_elcdif_register_mode(const struct fb_videomode *modedb,
+ int num_modes, int dev_mode)
+{
+ struct fb_videomode *mode;
+
+ mode = kzalloc(num_modes * sizeof(struct fb_videomode), GFP_KERNEL);
+
+ if (!mode) {
+ dev_err(g_elcdif_dev, "%s Failed to allocate mode data\n", __func__);
+ return;
+ }
+
+ if (mxc_disp_mode.num_modes)
+ memcpy(mode, mxc_disp_mode.mode,
+ mxc_disp_mode.num_modes * sizeof(struct fb_videomode));
+ if (modedb)
+ memcpy(mode + mxc_disp_mode.num_modes, modedb,
+ num_modes * sizeof(struct fb_videomode));
+
+ if (mxc_disp_mode.num_modes)
+ kfree(mxc_disp_mode.mode);
+
+ mxc_disp_mode.mode = mode;
+ mxc_disp_mode.num_modes += num_modes;
+ mxc_disp_mode.dev_mode = dev_mode;
+
+ return;
+}
+
int mxc_elcdif_frame_addr_setup(dma_addr_t phys)
{
int ret = 0;
@@ -1236,6 +1303,9 @@ static int mxc_elcdif_fb_probe(struct platform_device *pdev)
struct resource *res;
struct fb_info *fbi;
struct mxc_fb_platform_data *pdata = pdev->dev.platform_data;
+ const struct fb_videomode *mode;
+ struct fb_videomode m;
+ int num;
fbi = framebuffer_alloc(sizeof(struct mxc_elcdif_fb_data), &pdev->dev);
if (fbi == NULL) {
@@ -1296,20 +1366,63 @@ static int mxc_elcdif_fb_probe(struct platform_device *pdev)
if (pdata && !data->output_pix_fmt)
data->output_pix_fmt = pdata->interface_pix_fmt;
+ INIT_LIST_HEAD(&fbi->modelist);
+
if (pdata && pdata->mode && pdata->num_modes)
fb_videomode_to_modelist(pdata->mode, pdata->num_modes,
&fbi->modelist);
+ if (mxc_disp_mode.num_modes) {
+ int i;
+ mode = mxc_disp_mode.mode;
+ num = mxc_disp_mode.num_modes;
+
+ for (i = 0; i < num; i++) {
+ /*
+ * FIXME now we do not support interlaced
+ * mode for ddc mode
+ */
+ if ((mxc_disp_mode.dev_mode
+ & MXC_DISP_DDC_DEV) &&
+ (mode[i].vmode & FB_VMODE_INTERLACED))
+ continue;
+ else {
+ dev_dbg(&pdev->dev, "Added mode %d:", i);
+ dev_dbg(&pdev->dev,
+ "xres = %d, yres = %d, freq = %d, vmode = %d, flag = %d\n",
+ mode[i].xres, mode[i].yres, mode[i].refresh, mode[i].vmode,
+ mode[i].flag);
+ fb_add_videomode(&mode[i], &fbi->modelist);
+ }
+ }
+ }
+
if (!fb_mode && pdata && pdata->mode_str)
fb_mode = pdata->mode_str;
if (fb_mode) {
+ dev_dbg(&pdev->dev, "default video mode %s\n", fb_mode);
ret = fb_find_mode(&fbi->var, fbi, fb_mode, NULL, 0, NULL,
default_bpp);
- if ((!ret || (ret > 2)) && pdata && pdata->mode &&
- pdata->num_modes)
- fb_find_mode(&fbi->var, fbi, fb_mode, pdata->mode,
+ if ((ret == 1) || (ret == 2)) {
+ fb_var_to_videomode(&m, &fbi->var);
+ dump_fb_videomode(&m);
+ mode = fb_find_nearest_mode(&m,
+ &fbi->modelist);
+ fb_videomode_to_var(&fbi->var, mode);
+ } else if (pdata && pdata->mode && pdata->num_modes) {
+ ret = fb_find_mode(&fbi->var, fbi, fb_mode, pdata->mode,
pdata->num_modes, NULL, default_bpp);
+ if (!ret) {
+ dev_err(fbi->device,
+ "No valid video mode found");
+ goto err2;
+ }
+ } else {
+ dev_err(fbi->device,
+ "No valid video mode found");
+ goto err2;
+ }
}
mxc_elcdif_fb_check_var(&fbi->var, fbi);
@@ -1343,6 +1456,19 @@ static int mxc_elcdif_fb_probe(struct platform_device *pdev)
*/
clk_set_rate(g_elcdif_pix_clk, 25000000);
+ fbi->var.activate |= FB_ACTIVATE_FORCE;
+ console_lock();
+ fbi->flags |= FBINFO_MISC_USEREVENT;
+ ret = fb_set_var(fbi, &fbi->var);
+ fbi->flags &= ~FBINFO_MISC_USEREVENT;
+ console_unlock();
+
+ if (data->cur_blank == FB_BLANK_UNBLANK) {
+ console_lock();
+ fb_blank(fbi, FB_BLANK_UNBLANK);
+ console_unlock();
+ }
+
ret = register_framebuffer(fbi);
if (ret)
goto err3;
diff --git a/drivers/video/mxc/mxc_epdc_fb.c b/drivers/video/mxc/mxc_epdc_fb.c
index 0b3923c2cea6..b702788ae823 100644
--- a/drivers/video/mxc/mxc_epdc_fb.c
+++ b/drivers/video/mxc/mxc_epdc_fb.c
@@ -50,6 +50,7 @@
#include <linux/bitops.h>
#include <mach/epdc.h>
#include <mach/dma.h>
+#include <asm/cacheflush.h>
#include "epdc_regs.h"
@@ -69,6 +70,10 @@
#define INVALID_LUT (-1)
#define DRY_RUN_NO_LUT 100
+/* Maximum update buffer image width due to v2.0 and v2.1 errata ERR005313. */
+#define EPDC_V2_MAX_UPDATE_WIDTH 2047
+#define EPDC_V2_ROTATION_ALIGNMENT 8
+
#define DEFAULT_TEMP_INDEX 0
#define DEFAULT_TEMP 20 /* room temp in deg Celsius */
@@ -202,6 +207,8 @@ struct mxc_epdc_fb_data {
bool updates_active;
int pwrdown_delay;
unsigned long tce_prevent;
+ bool restrict_width; /* work around rev >=2.0 width and
+ stride restriction */
/* FB elements related to PxP DMA */
struct completion pxp_tx_cmpl;
@@ -262,6 +269,16 @@ static int pxp_complete_update(struct mxc_epdc_fb_data *fb_data, u32 *hist_stat)
static void draw_mode0(struct mxc_epdc_fb_data *fb_data);
static bool is_free_list_full(struct mxc_epdc_fb_data *fb_data);
+static void do_dithering_processing_Y1_v1_0(
+ unsigned char *update_region_ptr,
+ struct mxcfb_rect *update_region,
+ unsigned long update_region_stride,
+ int *err_dist);
+static void do_dithering_processing_Y4_v1_0(
+ unsigned char *update_region_ptr,
+ struct mxcfb_rect *update_region,
+ unsigned long update_region_stride,
+ int *err_dist);
#ifdef DEBUG
static void dump_pxp_config(struct mxc_epdc_fb_data *fb_data,
@@ -1930,10 +1947,10 @@ static int epdc_process_update(struct update_data_list *upd_data_list,
* to copybuf in addition to the PxP structures */
mutex_lock(&fb_data->pxp_mutex);
- if ((((width_unaligned || height_unaligned || input_unaligned) &&
+ if (((((width_unaligned || height_unaligned || input_unaligned) &&
(upd_desc_list->upd_data.waveform_mode == WAVEFORM_MODE_AUTO))
- || line_overflow) && (fb_data->rev < 20)) {
-
+ || line_overflow) && (fb_data->rev < 20)) ||
+ fb_data->restrict_width) {
dev_dbg(fb_data->dev, "Copying update before processing.\n");
/* Update to reflect what the new source buffer will be */
@@ -2137,7 +2154,8 @@ static int epdc_process_update(struct update_data_list *upd_data_list,
}
static int epdc_submit_merge(struct update_desc_list *upd_desc_list,
- struct update_desc_list *update_to_merge)
+ struct update_desc_list *update_to_merge,
+ struct mxc_epdc_fb_data *fb_data)
{
struct mxcfb_update_data *a, *b;
struct mxcfb_rect *arect, *brect;
@@ -2195,6 +2213,19 @@ static int epdc_submit_merge(struct update_desc_list *upd_desc_list,
(arect->top + arect->height - combine.top) :
(brect->top + brect->height - combine.top);
+ /* Don't merge if combined width exceeds max width */
+ if (fb_data->restrict_width) {
+ u32 max_width = EPDC_V2_MAX_UPDATE_WIDTH;
+ u32 combined_width = combine.width;
+ if (fb_data->epdc_fb_var.rotate != FB_ROTATE_UR)
+ max_width -= EPDC_V2_ROTATION_ALIGNMENT;
+ if ((fb_data->epdc_fb_var.rotate == FB_ROTATE_CW) ||
+ (fb_data->epdc_fb_var.rotate == FB_ROTATE_CCW))
+ combined_width = combine.height;
+ if (combined_width > max_width)
+ return MERGE_FAIL;
+ }
+
*arect = combine;
/* Use flags of the later update */
@@ -2226,6 +2257,7 @@ static void epdc_submit_work_func(struct work_struct *work)
bool end_merge = false;
bool is_transform;
u32 update_addr;
+ int *err_dist;
int ret;
/* Protect access to buffer queues and to update HW */
@@ -2260,7 +2292,8 @@ static void epdc_submit_work_func(struct work_struct *work)
break;
} else {
switch (epdc_submit_merge(upd_data_list->update_desc,
- next_update->update_desc)) {
+ next_update->update_desc,
+ fb_data)) {
case MERGE_OK:
dev_dbg(fb_data->dev,
"Update merged [collision]\n");
@@ -2330,7 +2363,7 @@ static void epdc_submit_work_func(struct work_struct *work)
break;
} else {
switch (epdc_submit_merge(upd_data_list->update_desc,
- next_desc)) {
+ next_desc, fb_data)) {
case MERGE_OK:
dev_dbg(fb_data->dev,
"Update merged [queue]\n");
@@ -2371,12 +2404,14 @@ static void epdc_submit_work_func(struct work_struct *work)
* PxP in versions 2.0 and earlier of EPDC.
*/
is_transform = upd_data_list->update_desc->upd_data.flags &
- (EPDC_FLAG_ENABLE_INVERSION |
- EPDC_FLAG_FORCE_MONOCHROME | EPDC_FLAG_USE_CMAP) ?
- true : false;
+ (EPDC_FLAG_ENABLE_INVERSION | EPDC_FLAG_USE_DITHERING_Y1 |
+ EPDC_FLAG_USE_DITHERING_Y4 | EPDC_FLAG_FORCE_MONOCHROME |
+ EPDC_FLAG_USE_CMAP) ? true : false;
+
if ((fb_data->epdc_fb_var.rotate == FB_ROTATE_UR) &&
(fb_data->epdc_fb_var.grayscale == GRAYSCALE_8BIT) &&
- !is_transform && (fb_data->rev > 20)) {
+ !is_transform && (fb_data->rev > 20) &&
+ !fb_data->restrict_width) {
/* If needed, enable EPDC HW while ePxP is processing */
if ((fb_data->power_state == POWER_STATE_OFF)
@@ -2391,7 +2426,6 @@ static void epdc_submit_work_func(struct work_struct *work)
update_addr = fb_data->info.fix.smem_start +
((upd_region->top * fb_data->info.var.xres_virtual) +
upd_region->left) * fb_data->info.var.bits_per_pixel/8;
-
upd_data_list->update_desc->epdc_stride =
fb_data->info.var.xres_virtual *
fb_data->info.var.bits_per_pixel/8;
@@ -2457,6 +2491,45 @@ static void epdc_submit_work_func(struct work_struct *work)
}
/*
+ * Dithering Processing (Version 1.0 - for i.MX508 and i.MX6SL)
+ */
+ if (upd_data_list->update_desc->upd_data.flags &
+ EPDC_FLAG_USE_DITHERING_Y1) {
+
+ err_dist = kzalloc((fb_data->info.var.xres_virtual + 3) * 3
+ * sizeof(int), GFP_KERNEL);
+
+ /* Dithering Y8 -> Y1 */
+ do_dithering_processing_Y1_v1_0(
+ (uint8_t *)(upd_data_list->virt_addr +
+ upd_data_list->update_desc->epdc_offs),
+ &adj_update_region,
+ (fb_data->rev < 20) ?
+ ALIGN(adj_update_region.width, 8) :
+ adj_update_region.width,
+ err_dist);
+
+ kfree(err_dist);
+ } else if (upd_data_list->update_desc->upd_data.flags &
+ EPDC_FLAG_USE_DITHERING_Y4) {
+
+ err_dist = kzalloc((fb_data->info.var.xres_virtual + 3) * 3
+ * sizeof(int), GFP_KERNEL);
+
+ /* Dithering Y8 -> Y1 */
+ do_dithering_processing_Y4_v1_0(
+ (uint8_t *)(upd_data_list->virt_addr +
+ upd_data_list->update_desc->epdc_offs),
+ &adj_update_region,
+ (fb_data->rev < 20) ?
+ ALIGN(adj_update_region.width, 8) :
+ adj_update_region.width,
+ err_dist);
+
+ kfree(err_dist);
+ }
+
+ /*
* If there are no LUTs available,
* then we must wait for the resource to become free.
* The IST will signal this event.
@@ -2572,8 +2645,7 @@ static void epdc_submit_work_func(struct work_struct *work)
mutex_unlock(&fb_data->queue_mutex);
}
-
-int mxc_epdc_fb_send_update(struct mxcfb_update_data *upd_data,
+static int mxc_epdc_fb_send_single_update(struct mxcfb_update_data *upd_data,
struct fb_info *info)
{
struct mxc_epdc_fb_data *fb_data = info ?
@@ -2868,6 +2940,63 @@ int mxc_epdc_fb_send_update(struct mxcfb_update_data *upd_data,
mutex_unlock(&fb_data->queue_mutex);
return 0;
}
+
+int mxc_epdc_fb_send_update(struct mxcfb_update_data *upd_data,
+ struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = info ?
+ (struct mxc_epdc_fb_data *)info:g_fb_data;
+
+ if (!fb_data->restrict_width) {
+ /* No width restriction, send entire update region */
+ return mxc_epdc_fb_send_single_update(upd_data, info);
+ } else {
+ int ret;
+ __u32 width, left;
+ __u32 marker;
+ __u32 *region_width, *region_left;
+ u32 max_upd_width = EPDC_V2_MAX_UPDATE_WIDTH;
+
+ /* Further restrict max width due to pxp rotation
+ * alignment requirement
+ */
+ if (fb_data->epdc_fb_var.rotate != FB_ROTATE_UR)
+ max_upd_width -= EPDC_V2_ROTATION_ALIGNMENT;
+
+ /* Select split of width or height based on rotation */
+ if ((fb_data->epdc_fb_var.rotate == FB_ROTATE_UR) ||
+ (fb_data->epdc_fb_var.rotate == FB_ROTATE_UD)) {
+ region_width = &upd_data->update_region.width;
+ region_left = &upd_data->update_region.left;
+ } else {
+ region_width = &upd_data->update_region.height;
+ region_left = &upd_data->update_region.top;
+ }
+
+ if (*region_width <= max_upd_width)
+ return mxc_epdc_fb_send_single_update(upd_data, info);
+
+ width = *region_width;
+ left = *region_left;
+ marker = upd_data->update_marker;
+ upd_data->update_marker = 0;
+
+ do {
+ *region_width = max_upd_width;
+ *region_left = left;
+ ret = mxc_epdc_fb_send_single_update(upd_data, info);
+ if (ret)
+ return ret;
+ width -= max_upd_width;
+ left += max_upd_width;
+ } while (width > max_upd_width);
+
+ *region_width = width;
+ *region_left = left;
+ upd_data->update_marker = marker;
+ return mxc_epdc_fb_send_single_update(upd_data, info);
+ }
+}
EXPORT_SYMBOL(mxc_epdc_fb_send_update);
int mxc_epdc_fb_wait_update_complete(struct mxcfb_update_marker_data *marker_data,
@@ -3041,6 +3170,25 @@ static int mxc_epdc_fb_ioctl(struct fb_info *info, unsigned int cmd,
ret = 0;
break;
}
+
+ case MXCFB_GET_WORK_BUFFER:
+ {
+ /* copy the epdc working buffer to the user space */
+ struct mxc_epdc_fb_data *fb_data = info ?
+ (struct mxc_epdc_fb_data *)info:g_fb_data;
+ flush_cache_all();
+ outer_flush_all();
+ if (copy_to_user((void __user *)arg,
+ (const void *) fb_data->working_buffer_virt,
+ fb_data->working_buffer_size))
+ ret = -EFAULT;
+ else
+ ret = 0;
+ flush_cache_all();
+ outer_flush_all();
+ break;
+ }
+
default:
break;
}
@@ -4076,7 +4224,8 @@ static void mxc_epdc_fb_fw_handler(const struct firmware *fw,
&fb_data->info);
if (ret < 0)
dev_err(fb_data->dev,
- "Wait for update complete failed. Error = 0x%x", ret);
+ "Wait for initial update complete failed."
+ " Error = 0x%x", ret);
}
static int mxc_epdc_fb_init_hw(struct fb_info *info)
@@ -4417,6 +4566,8 @@ int __devinit mxc_epdc_fb_probe(struct platform_device *pdev)
} else {
fb_data->num_luts = EPDC_V2_NUM_LUTS;
fb_data->max_num_updates = EPDC_V2_MAX_NUM_UPDATES;
+ if (vmode->xres > EPDC_V2_MAX_UPDATE_WIDTH)
+ fb_data->restrict_width = true;
}
fb_data->max_num_buffers = EPDC_MAX_NUM_BUFFERS;
@@ -4454,8 +4605,9 @@ int __devinit mxc_epdc_fb_probe(struct platform_device *pdev)
* be as big as the full-screen frame buffer
*/
fb_data->virt_addr_updbuf[i] =
- dma_alloc_coherent(fb_data->info.device, fb_data->max_pix_size,
- &fb_data->phys_addr_updbuf[i], GFP_DMA);
+ kmalloc(fb_data->max_pix_size, GFP_KERNEL);
+ fb_data->phys_addr_updbuf[i] =
+ virt_to_phys(fb_data->virt_addr_updbuf[i]);
if (fb_data->virt_addr_updbuf[i] == NULL) {
ret = -ENOMEM;
goto out_upd_buffers;
@@ -4737,10 +4889,7 @@ out_copybuffer:
out_upd_buffers:
for (i = 0; i < fb_data->max_num_buffers; i++)
if (fb_data->virt_addr_updbuf[i] != NULL)
- dma_free_writecombine(&pdev->dev,
- fb_data->max_pix_size,
- fb_data->virt_addr_updbuf[i],
- fb_data->phys_addr_updbuf[i]);
+ kfree(fb_data->virt_addr_updbuf[i]);
if (fb_data->virt_addr_updbuf != NULL)
kfree(fb_data->virt_addr_updbuf);
if (fb_data->phys_addr_updbuf != NULL)
@@ -4785,9 +4934,7 @@ static int mxc_epdc_fb_remove(struct platform_device *pdev)
for (i = 0; i < fb_data->max_num_buffers; i++)
if (fb_data->virt_addr_updbuf[i] != NULL)
- dma_free_writecombine(&pdev->dev, fb_data->max_pix_size,
- fb_data->virt_addr_updbuf[i],
- fb_data->phys_addr_updbuf[i]);
+ kfree(fb_data->virt_addr_updbuf[i]);
if (fb_data->virt_addr_updbuf != NULL)
kfree(fb_data->virt_addr_updbuf);
if (fb_data->phys_addr_updbuf != NULL)
@@ -5082,6 +5229,124 @@ static int pxp_complete_update(struct mxc_epdc_fb_data *fb_data, u32 *hist_stat)
return 0;
}
+/*
+ * Different dithering algorithm can be used. We chose
+ * to implement Bill Atkinson's algorithm as an example
+ * Thanks Bill Atkinson for his dithering algorithm.
+ */
+
+/*
+ * Dithering algorithm implementation - Y8->Y1 version 1.0 for i.MX
+ */
+static void do_dithering_processing_Y1_v1_0(
+ unsigned char *update_region_ptr,
+ struct mxcfb_rect *update_region,
+ unsigned long update_region_stride,
+ int *err_dist)
+{
+
+ /* create a temp error distribution array */
+ int bwPix;
+ int y;
+ int col;
+ int *err_dist_l0, *err_dist_l1, *err_dist_l2, distrib_error;
+ int width_3 = update_region->width + 3;
+ char *y8buf;
+ int x_offset = 0;
+
+ /* prime a few elements the error distribution array */
+ for (y = 0; y < update_region->height; y++) {
+ /* Dithering the Y8 in sbuf to BW suitable for A2 waveform */
+ err_dist_l0 = err_dist + (width_3) * (y % 3);
+ err_dist_l1 = err_dist + (width_3) * ((y + 1) % 3);
+ err_dist_l2 = err_dist + (width_3) * ((y + 2) % 3);
+
+ y8buf = update_region_ptr + x_offset;
+
+ /* scan the line and convert the Y8 to BW */
+ for (col = 1; col <= update_region->width; col++) {
+ bwPix = *(err_dist_l0 + col) + *y8buf;
+
+ if (bwPix >= 128) {
+ *y8buf++ = 0xff;
+ distrib_error = (bwPix - 255) >> 3;
+ } else {
+ *y8buf++ = 0;
+ distrib_error = bwPix >> 3;
+ }
+
+ /* modify the error distribution buffer */
+ *(err_dist_l0 + col + 2) += distrib_error;
+ *(err_dist_l1 + col + 1) += distrib_error;
+ *(err_dist_l0 + col + 1) += distrib_error;
+ *(err_dist_l1 + col - 1) += distrib_error;
+ *(err_dist_l1 + col) += distrib_error;
+ *(err_dist_l2 + col) = distrib_error;
+ }
+ x_offset += update_region_stride;
+ }
+
+ flush_cache_all();
+ outer_flush_all();
+}
+
+/*
+ * Dithering algorithm implementation - Y8->Y4 version 1.0 for i.MX
+ */
+
+static void do_dithering_processing_Y4_v1_0(
+ unsigned char *update_region_ptr,
+ struct mxcfb_rect *update_region,
+ unsigned long update_region_stride,
+ int *err_dist)
+{
+
+ /* create a temp error distribution array */
+ int gcPix;
+ int y;
+ int col;
+ int *err_dist_l0, *err_dist_l1, *err_dist_l2, distrib_error;
+ int width_3 = update_region->width + 3;
+ char *y8buf;
+ int x_offset = 0;
+
+ /* prime a few elements the error distribution array */
+ for (y = 0; y < update_region->height; y++) {
+ /* Dithering the Y8 in sbuf to Y4 */
+ err_dist_l0 = err_dist + (width_3) * (y % 3);
+ err_dist_l1 = err_dist + (width_3) * ((y + 1) % 3);
+ err_dist_l2 = err_dist + (width_3) * ((y + 2) % 3);
+
+ y8buf = update_region_ptr + x_offset;
+
+ /* scan the line and convert the Y8 to Y4 */
+ for (col = 1; col <= update_region->width; col++) {
+ gcPix = *(err_dist_l0 + col) + *y8buf;
+
+ if (gcPix > 255)
+ gcPix = 255;
+ else if (gcPix < 0)
+ gcPix = 0;
+
+ distrib_error = (*y8buf - (gcPix & 0xf0)) >> 3;
+
+ *y8buf++ = gcPix & 0xf0;
+
+ /* modify the error distribution buffer */
+ *(err_dist_l0 + col + 2) += distrib_error;
+ *(err_dist_l1 + col + 1) += distrib_error;
+ *(err_dist_l0 + col + 1) += distrib_error;
+ *(err_dist_l1 + col - 1) += distrib_error;
+ *(err_dist_l1 + col) += distrib_error;
+ *(err_dist_l2 + col) = distrib_error;
+ }
+ x_offset += update_region_stride;
+ }
+
+ flush_cache_all();
+ outer_flush_all();
+}
+
static int __init mxc_epdc_fb_init(void)
{
return platform_driver_register(&mxc_epdc_fb_driver);
diff --git a/drivers/video/mxc/mxcfb_sii902x_elcdif.c b/drivers/video/mxc/mxcfb_sii902x_elcdif.c
new file mode 100644
index 000000000000..ceab3e66e91c
--- /dev/null
+++ b/drivers/video/mxc/mxcfb_sii902x_elcdif.c
@@ -0,0 +1,560 @@
+/*
+ * Copyright (C) 2010-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * 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.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*!
+ * @defgroup Framebuffer Framebuffer Driver for SDC and ADC.
+ */
+
+/*!
+ * @file mxcfb_sii902x_elcdif.c
+ *
+ * @brief MXC ELCDIF Frame buffer driver for SII902x
+ *
+ * @ingroup Framebuffer
+ */
+
+/*!
+ * Include files
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/i2c.h>
+#include <linux/mxcfb.h>
+#include <linux/fsl_devices.h>
+#include <linux/interrupt.h>
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/mxc_edid.h>
+
+#define SII_EDID_LEN 512
+#define MXC_ENABLE 1
+#define MXC_DISABLE 2
+
+struct sii902x_data {
+ struct platform_device *pdev;
+ struct i2c_client *client;
+ struct delayed_work det_work;
+ struct fb_info *fbi;
+ struct mxc_edid_cfg edid_cfg;
+ u8 cable_plugin;
+ u8 edid[SII_EDID_LEN];
+ bool waiting_for_fb;
+} sii902x;
+
+static void sii902x_poweron(void);
+static void sii902x_poweroff(void);
+static void (*sii902x_reset) (void);
+
+#ifdef DEBUG
+static void dump_fb_videomode(struct fb_videomode *m)
+{
+ pr_debug("fb_videomode = %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
+ m->refresh, m->xres, m->yres, m->pixclock, m->left_margin,
+ m->right_margin, m->upper_margin, m->lower_margin,
+ m->hsync_len, m->vsync_len, m->sync, m->vmode, m->flag);
+}
+#else
+static void dump_fb_videomode(struct fb_videomode *m)
+{}
+#endif
+
+static __attribute__ ((unused)) void dump_regs(u8 reg, int len)
+{
+ u8 buf[50];
+ int i;
+
+ i2c_smbus_read_i2c_block_data(sii902x.client, reg, len, buf);
+ for (i = 0; i < len; i++)
+ dev_dbg(&sii902x.client->dev, "reg[0x%02X]: 0x%02X\n",
+ i+reg, buf[i]);
+}
+
+static ssize_t sii902x_show_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ strcpy(buf, sii902x.fbi->fix.id);
+ sprintf(buf+strlen(buf), "\n");
+
+ return strlen(buf);
+}
+
+static DEVICE_ATTR(fb_name, S_IRUGO, sii902x_show_name, NULL);
+
+static ssize_t sii902x_show_state(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ if (sii902x.cable_plugin == 0)
+ strcpy(buf, "plugout\n");
+ else
+ strcpy(buf, "plugin\n");
+
+ return strlen(buf);
+}
+
+static DEVICE_ATTR(cable_state, S_IRUGO, sii902x_show_state, NULL);
+
+static ssize_t sii902x_show_edid(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int i, j, len = 0;
+
+ for (j = 0; j < SII_EDID_LEN/16; j++) {
+ for (i = 0; i < 16; i++)
+ len += sprintf(buf+len, "0x%02X ",
+ sii902x.edid[j*16 + i]);
+ len += sprintf(buf+len, "\n");
+ }
+
+ return len;
+}
+
+static DEVICE_ATTR(edid, S_IRUGO, sii902x_show_edid, NULL);
+
+static void sii902x_setup(struct fb_info *fbi)
+{
+ u16 data[4];
+ u32 refresh;
+ u8 *tmp;
+ int i;
+
+ dev_dbg(&sii902x.client->dev, "Sii902x: setup..\n");
+
+ /* Power up */
+ i2c_smbus_write_byte_data(sii902x.client, 0x1E, 0x00);
+
+ /* set TPI video mode */
+ data[0] = PICOS2KHZ(fbi->var.pixclock) / 10;
+ data[2] = fbi->var.hsync_len + fbi->var.left_margin +
+ fbi->var.xres + fbi->var.right_margin;
+ data[3] = fbi->var.vsync_len + fbi->var.upper_margin +
+ fbi->var.yres + fbi->var.lower_margin;
+ refresh = data[2] * data[3];
+ refresh = (PICOS2KHZ(fbi->var.pixclock) * 1000) / refresh;
+ data[1] = refresh * 100;
+ tmp = (u8 *)data;
+ for (i = 0; i < 8; i++)
+ i2c_smbus_write_byte_data(sii902x.client, i, tmp[i]);
+
+ /* input bus/pixel: full pixel wide (24bit), rising edge */
+ i2c_smbus_write_byte_data(sii902x.client, 0x08, 0x70);
+ /* Set input format to RGB */
+ i2c_smbus_write_byte_data(sii902x.client, 0x09, 0x00);
+ /* set output format to RGB */
+ i2c_smbus_write_byte_data(sii902x.client, 0x0A, 0x00);
+ /* audio setup */
+ i2c_smbus_write_byte_data(sii902x.client, 0x25, 0x00);
+ i2c_smbus_write_byte_data(sii902x.client, 0x26, 0x40);
+ i2c_smbus_write_byte_data(sii902x.client, 0x27, 0x00);
+}
+
+#ifdef CONFIG_FB_MODE_HELPERS
+static int sii902x_read_edid(struct fb_info *fbi)
+{
+ int old, dat, ret, cnt = 100;
+ unsigned short addr = 0x50;
+
+ dev_dbg(&sii902x.pdev->dev, "%s\n", __func__);
+
+ old = i2c_smbus_read_byte_data(sii902x.client, 0x1A);
+
+ i2c_smbus_write_byte_data(sii902x.client, 0x1A, old | 0x4);
+ do {
+ cnt--;
+ msleep(10);
+ dat = i2c_smbus_read_byte_data(sii902x.client, 0x1A);
+ } while ((!(dat & 0x2)) && cnt);
+
+ if (!cnt) {
+ ret = -1;
+ goto done;
+ }
+
+ i2c_smbus_write_byte_data(sii902x.client, 0x1A, old | 0x06);
+
+ /* edid reading */
+ ret = mxc_edid_read(sii902x.client->adapter, addr,
+ sii902x.edid, &sii902x.edid_cfg, fbi);
+
+ cnt = 100;
+ do {
+ cnt--;
+ i2c_smbus_write_byte_data(sii902x.client, 0x1A, old & ~0x6);
+ msleep(10);
+ dat = i2c_smbus_read_byte_data(sii902x.client, 0x1A);
+ } while ((dat & 0x6) && cnt);
+
+ if (!cnt)
+ ret = -1;
+
+done:
+
+ i2c_smbus_write_byte_data(sii902x.client, 0x1A, old);
+ return ret;
+}
+#else
+static int sii902x_read_edid(struct fb_info *fbi)
+{
+ return -1;
+}
+#endif
+
+static void det_worker(struct work_struct *work)
+{
+ int dat;
+ char event_string[16];
+ char *envp[] = { event_string, NULL };
+
+ dev_dbg(&sii902x.pdev->dev, "%s\n", __func__);
+
+ dat = i2c_smbus_read_byte_data(sii902x.client, 0x3D);
+ if (dat & 0x1) {
+ /* cable connection changes */
+ if (dat & 0x4) {
+ sii902x.cable_plugin = 1;
+ dev_dbg(&sii902x.pdev->dev, "EVENT=plugin\n");
+ sprintf(event_string, "EVENT=plugin");
+
+ /* make sure fb is powerdown */
+ console_lock();
+ fb_blank(sii902x.fbi, FB_BLANK_POWERDOWN);
+ console_unlock();
+
+ if (sii902x_read_edid(sii902x.fbi) < 0)
+ dev_err(&sii902x.client->dev,
+ "Sii902x: read edid fail\n");
+ else {
+ if (sii902x.fbi->monspecs.modedb_len > 0) {
+
+ int i;
+ const struct fb_videomode *mode;
+ struct fb_videomode m;
+
+ fb_destroy_modelist(&sii902x.fbi->modelist);
+
+ for (i = 0; i < sii902x.fbi->monspecs.modedb_len; i++) {
+ /*FIXME now we do not support interlaced mode */
+ mode = &sii902x.fbi->monspecs.modedb[i];
+
+ if (!(mode->vmode & FB_VMODE_INTERLACED)) {
+
+ dev_dbg(&sii902x.pdev->dev, "Added mode %d:", i);
+ dev_dbg(&sii902x.pdev->dev,
+ "xres = %d, yres = %d, freq = %d, vmode = %d, flag = %d\n",
+ mode->xres, mode->yres, mode->refresh,
+ mode->vmode, mode->flag);
+
+ fb_add_videomode(mode, &sii902x.fbi->modelist);
+ }
+ }
+
+ fb_var_to_videomode(&m, &sii902x.fbi->var);
+ dump_fb_videomode(&m);
+
+ mode = fb_find_nearest_mode(&m,
+ &sii902x.fbi->modelist);
+
+ fb_videomode_to_var(&sii902x.fbi->var, mode);
+
+ sii902x.fbi->var.activate |= FB_ACTIVATE_FORCE;
+ console_lock();
+ sii902x.fbi->flags |= FBINFO_MISC_USEREVENT;
+ fb_set_var(sii902x.fbi, &sii902x.fbi->var);
+ sii902x.fbi->flags &= ~FBINFO_MISC_USEREVENT;
+ console_unlock();
+ }
+
+ console_lock();
+ fb_blank(sii902x.fbi, FB_BLANK_UNBLANK);
+ console_unlock();
+ }
+ } else {
+ sii902x.cable_plugin = 0;
+ dev_dbg(&sii902x.pdev->dev, "EVENT=plugout\n");
+ sprintf(event_string, "EVENT=plugout");
+ console_lock();
+ fb_blank(sii902x.fbi, FB_BLANK_POWERDOWN);
+ console_unlock();
+ }
+ kobject_uevent_env(&sii902x.pdev->dev.kobj, KOBJ_CHANGE, envp);
+ }
+ i2c_smbus_write_byte_data(sii902x.client, 0x3D, dat);
+
+ dev_dbg(&sii902x.pdev->dev, "exit %s\n", __func__);
+
+}
+
+static irqreturn_t sii902x_detect_handler(int irq, void *data)
+{
+ if (sii902x.fbi)
+ schedule_delayed_work(&(sii902x.det_work), msecs_to_jiffies(20));
+ else
+ sii902x.waiting_for_fb = true;
+
+ return IRQ_HANDLED;
+}
+
+static int sii902x_fb_event(struct notifier_block *nb, unsigned long val, void *v)
+{
+ struct fb_event *event = v;
+ struct fb_info *fbi = event->info;
+
+ dev_dbg(&sii902x.pdev->dev, "%s\n", __func__);
+
+ switch (val) {
+ case FB_EVENT_FB_REGISTERED:
+ if (sii902x.fbi == NULL) {
+ sii902x.fbi = fbi;
+ if (sii902x.waiting_for_fb)
+ det_worker(NULL);
+ }
+ fb_show_logo(fbi, 0);
+ break;
+ case FB_EVENT_MODE_CHANGE:
+ sii902x_setup(fbi);
+ break;
+ case FB_EVENT_BLANK:
+ if (*((int *)event->data) == FB_BLANK_UNBLANK) {
+ dev_dbg(&sii902x.pdev->dev, "FB_BLANK_UNBLANK\n");
+ sii902x_poweron();
+ } else {
+ dev_dbg(&sii902x.pdev->dev, "FB_BLANK_BLANK\n");
+ sii902x_poweroff();
+ }
+ break;
+ }
+ return 0;
+}
+
+static struct notifier_block nb = {
+ .notifier_call = sii902x_fb_event,
+};
+
+static int __devinit sii902x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int i, dat, ret;
+ struct fsl_mxc_lcd_platform_data *plat = client->dev.platform_data;
+ struct fb_info edid_fbi;
+
+ dev_dbg(&sii902x.pdev->dev, "%s\n", __func__);;
+
+ sii902x.client = client;
+
+ /* Claim HDMI pins */
+ if (plat->get_pins)
+ if (!plat->get_pins())
+ return -EACCES;
+
+ if (plat->reset) {
+ sii902x_reset = plat->reset;
+ sii902x_reset();
+ }
+
+ /* Set 902x in hardware TPI mode on and jump out of D3 state */
+ if (i2c_smbus_write_byte_data(sii902x.client, 0xc7, 0x00) < 0) {
+ dev_err(&sii902x.client->dev,
+ "Sii902x: cound not find device\n");
+ return -ENODEV;
+ }
+
+ /* read device ID */
+ for (i = 10; i > 0; i--) {
+ dat = i2c_smbus_read_byte_data(sii902x.client, 0x1B);
+ printk(KERN_DEBUG "Sii902x: read id = 0x%02X", dat);
+ if (dat == 0xb0) {
+ dat = i2c_smbus_read_byte_data(sii902x.client, 0x1C);
+ printk(KERN_DEBUG "-0x%02X", dat);
+ dat = i2c_smbus_read_byte_data(sii902x.client, 0x1D);
+ printk(KERN_DEBUG "-0x%02X", dat);
+ dat = i2c_smbus_read_byte_data(sii902x.client, 0x30);
+ printk(KERN_DEBUG "-0x%02X\n", dat);
+ break;
+ }
+ }
+ if (i == 0) {
+ dev_err(&sii902x.client->dev,
+ "Sii902x: cound not find device\n");
+ return -ENODEV;
+ }
+
+ /* try to read edid */
+ ret = sii902x_read_edid(&edid_fbi);
+ if (ret < 0)
+ dev_warn(&sii902x.client->dev, "Can not read edid\n");
+
+ if (ret >= 0)
+ mxcfb_elcdif_register_mode(edid_fbi.monspecs.modedb,
+ edid_fbi.monspecs.modedb_len, MXC_DISP_DDC_DEV);
+
+ if (sii902x.client->irq) {
+ ret = request_irq(sii902x.client->irq, sii902x_detect_handler,
+ IRQF_TRIGGER_FALLING,
+ "SII902x_det", &sii902x);
+ if (ret < 0)
+ dev_warn(&sii902x.client->dev,
+ "Sii902x: cound not request det irq %d\n",
+ sii902x.client->irq);
+ else {
+ /*enable cable hot plug irq*/
+ i2c_smbus_write_byte_data(sii902x.client, 0x3c, 0x01);
+ INIT_DELAYED_WORK(&(sii902x.det_work), det_worker);
+ }
+ ret = device_create_file(&sii902x.pdev->dev, &dev_attr_fb_name);
+ if (ret < 0)
+ dev_warn(&sii902x.client->dev,
+ "Sii902x: cound not create sys node for fb name\n");
+ ret = device_create_file(&sii902x.pdev->dev, &dev_attr_cable_state);
+ if (ret < 0)
+ dev_warn(&sii902x.client->dev,
+ "Sii902x: cound not create sys node for cable state\n");
+ ret = device_create_file(&sii902x.pdev->dev, &dev_attr_edid);
+ if (ret < 0)
+ dev_warn(&sii902x.client->dev,
+ "Sii902x: cound not create sys node for edid\n");
+
+ }
+
+ fb_register_client(&nb);
+
+ dev_dbg(&sii902x.pdev->dev, "%s exit\n", __func__);;
+
+ return 0;
+}
+
+static int __devexit sii902x_remove(struct i2c_client *client)
+{
+ struct fsl_mxc_lcd_platform_data *plat = sii902x.client->dev.platform_data;
+
+ dev_dbg(&sii902x.pdev->dev, "%s\n", __func__);
+
+ fb_unregister_client(&nb);
+ sii902x_poweroff();
+
+ /* Release HDMI pins */
+ if (plat->put_pins)
+ plat->put_pins();
+
+ return 0;
+}
+
+static int sii902x_suspend(struct i2c_client *client, pm_message_t message)
+{
+ /*TODO*/
+ return 0;
+}
+
+static int sii902x_resume(struct i2c_client *client)
+{
+ /*TODO*/
+ return 0;
+}
+
+static void sii902x_poweron(void)
+{
+ struct fsl_mxc_lcd_platform_data *plat = sii902x.client->dev.platform_data;
+
+ dev_dbg(&sii902x.pdev->dev, "%s\n", __func__);
+
+ /* Enable pins to HDMI */
+ if (plat->enable_pins)
+ plat->enable_pins();
+
+ /* Turn on DVI or HDMI */
+ if (sii902x.edid_cfg.hdmi_cap)
+ i2c_smbus_write_byte_data(sii902x.client, 0x1A, 0x01);
+ else
+ i2c_smbus_write_byte_data(sii902x.client, 0x1A, 0x00);
+ return;
+}
+
+static void sii902x_poweroff(void)
+{
+ struct fsl_mxc_lcd_platform_data *plat = sii902x.client->dev.platform_data;
+
+ dev_dbg(&sii902x.pdev->dev, "%s\n", __func__);
+
+ /* disable tmds before changing resolution */
+ if (sii902x.edid_cfg.hdmi_cap)
+ i2c_smbus_write_byte_data(sii902x.client, 0x1A, 0x11);
+ else
+ i2c_smbus_write_byte_data(sii902x.client, 0x1A, 0x10);
+
+ /* Disable pins to HDMI */
+ if (plat->disable_pins)
+ plat->disable_pins();
+
+ return;
+}
+
+static const struct i2c_device_id sii902x_id[] = {
+ { "sii902x", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, sii902x_id);
+
+static struct i2c_driver sii902x_i2c_driver = {
+ .driver = {
+ .name = "sii902x",
+ },
+ .probe = sii902x_probe,
+ .remove = sii902x_remove,
+ .suspend = sii902x_suspend,
+ .resume = sii902x_resume,
+ .id_table = sii902x_id,
+};
+
+static int __init sii902x_init(void)
+{
+ int ret;
+
+ memset(&sii902x, 0, sizeof(sii902x));
+
+ sii902x.pdev = platform_device_register_simple("sii902x", 0, NULL, 0);
+ if (IS_ERR(sii902x.pdev)) {
+ printk(KERN_ERR
+ "Unable to register Sii902x as a platform device\n");
+ ret = PTR_ERR(sii902x.pdev);
+ goto err;
+ }
+
+ return i2c_add_driver(&sii902x_i2c_driver);
+err:
+ return ret;
+}
+
+static void __exit sii902x_exit(void)
+{
+ i2c_del_driver(&sii902x_i2c_driver);
+ platform_device_unregister(sii902x.pdev);
+}
+
+module_init(sii902x_init);
+module_exit(sii902x_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("SII902x DVI/HDMI driver");
+MODULE_LICENSE("GPL");