diff options
-rw-r--r-- | drivers/video/fbdev/mxc/Kconfig | 6 | ||||
-rw-r--r-- | drivers/video/fbdev/mxc/Makefile | 1 | ||||
-rw-r--r-- | drivers/video/fbdev/mxc/mxc_dcic.c | 592 | ||||
-rw-r--r-- | include/linux/mfd/syscon/imx6q-iomuxc-gpr.h | 14 | ||||
-rw-r--r-- | include/linux/mxc_dcic.h | 126 |
5 files changed, 732 insertions, 7 deletions
diff --git a/drivers/video/fbdev/mxc/Kconfig b/drivers/video/fbdev/mxc/Kconfig index caf6d3449fe5..cd56871017c7 100644 --- a/drivers/video/fbdev/mxc/Kconfig +++ b/drivers/video/fbdev/mxc/Kconfig @@ -52,6 +52,12 @@ config FB_MXS_SII902X tristate "Si Image SII9022 DVI/HDMI Interface Chip" depends on FB_MXS && I2C +config FB_MXC_DCIC + tristate "MXC DCIC" + depends on FB_MXC_SYNC_PANEL + depends on MXC_IPU_V3 || FB_MXS + select VIDEOMODE_HELPERS + config HANNSTAR_CABC tristate "Hannstar CABC function" help diff --git a/drivers/video/fbdev/mxc/Makefile b/drivers/video/fbdev/mxc/Makefile index f63dc58a47f2..8b2e4361db9b 100644 --- a/drivers/video/fbdev/mxc/Makefile +++ b/drivers/video/fbdev/mxc/Makefile @@ -7,4 +7,5 @@ obj-$(CONFIG_FB_MXC_SYNC_PANEL) += mxc_dispdrv.o mxc_lcdif.o mxc_ipuv3_fb.o obj-$(CONFIG_FB_MXC_EINK_PANEL) += mxc_epdc_fb.o obj-$(CONFIG_FB_MXC_EINK_V2_PANEL) += mxc_epdc_v2_fb.o obj-$(CONFIG_FB_MXS_SII902X) += mxsfb_sii902x.o +obj-$(CONFIG_FB_MXC_DCIC) += mxc_dcic.o obj-$(CONFIG_HANNSTAR_CABC) += hannstar_cabc.o diff --git a/drivers/video/fbdev/mxc/mxc_dcic.c b/drivers/video/fbdev/mxc/mxc_dcic.c new file mode 100644 index 000000000000..cae872a05f7f --- /dev/null +++ b/drivers/video/fbdev/mxc/mxc_dcic.c @@ -0,0 +1,592 @@ +/* + * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/clk.h> +#include <linux/cdev.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/fs.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/ioctl.h> +#include <linux/interrupt.h> +#include <linux/mfd/syscon.h> +#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> +#include <linux/module.h> +#include <linux/mxc_dcic.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/types.h> +#include <linux/uaccess.h> +#include <video/videomode.h> +#include <video/of_videomode.h> + +#define DRIVER_NAME "mxc_dcic" + +#define DCIC_IPU1_DI0 "dcic-ipu1-di0" +#define DCIC_IPU1_DI1 "dcic-ipu1-di1" +#define DCIC_IPU2_DI0 "dcic-ipu2-di0" +#define DCIC_IPU2_DI1 "dcic-ipu2-di1" +#define DCIC_LCDIF "dcic-lcdif" +#define DCIC_LCDIF1 "dcic-lcdif1" +#define DCIC_LCDIF2 "dcic-lcdif2" +#define DCIC_LVDS "dcic-lvds" +#define DCIC_LVDS0 "dcic-lvds0" +#define DCIC_LVDS1 "dcic-lvds1" +#define DCIC_HDMI "dcic-hdmi" + +#define DCIC0_DEV_NAME "mxc_dcic0" +#define DCIC1_DEV_NAME "mxc_dcic1" + +#define FB_SYNC_OE_LOW_ACT 0x80000000 +#define FB_SYNC_CLK_LAT_FALL 0x40000000 + +static const struct dcic_mux imx6q_dcic0_mux[] = { + { + .dcic = DCIC_IPU1_DI0, + .val = IMX6Q_GPR10_DCIC1_MUX_CTL_IPU1_DI0, + }, { + .dcic = DCIC_LVDS0, + .val = IMX6Q_GPR10_DCIC1_MUX_CTL_LVDS0, + }, { + .dcic = DCIC_LVDS1, + .val = IMX6Q_GPR10_DCIC1_MUX_CTL_LVDS1, + }, { + .dcic = DCIC_HDMI, + .val = IMX6Q_GPR10_DCIC1_MUX_CTL_HDMI, + } +}; + +static const struct dcic_mux imx6q_dcic1_mux[] = { + { + .dcic = DCIC_IPU1_DI1, + .val = IMX6Q_GPR10_DCIC2_MUX_CTL_IPU1_DI1, + }, { + .dcic = DCIC_LVDS0, + .val = IMX6Q_GPR10_DCIC2_MUX_CTL_LVDS0, + }, { + .dcic = DCIC_LVDS1, + .val = IMX6Q_GPR10_DCIC2_MUX_CTL_LVDS1, + }, { + .dcic = DCIC_HDMI, + .val = IMX6Q_GPR10_DCIC2_MUX_CTL_MIPI, + } +}; + +static const struct bus_mux imx6q_dcic_buses[] = { + { + .name = DCIC0_DEV_NAME, + .reg = IOMUXC_GPR10, + .shift = 0, + .mask = IMX6Q_GPR10_DCIC1_MUX_CTL_MASK, + .dcic_mux_num = ARRAY_SIZE(imx6q_dcic0_mux), + .dcics = imx6q_dcic0_mux, + }, { + .name = DCIC1_DEV_NAME, + .reg = IOMUXC_GPR10, + .shift = 2, + .mask = IMX6Q_GPR10_DCIC2_MUX_CTL_MASK, + .dcic_mux_num = ARRAY_SIZE(imx6q_dcic1_mux), + .dcics = imx6q_dcic1_mux, + } +}; + +static const struct dcic_info imx6q_dcic_info = { + .bus_mux_num = ARRAY_SIZE(imx6q_dcic_buses), + .buses = imx6q_dcic_buses, +}; + +static const struct dcic_mux imx6sx_dcic0_mux[] = { + { + .dcic = DCIC_LCDIF1, + .val = IMX6SX_GPR5_DISP_MUX_DCIC1_LCDIF1, + }, { + .dcic = DCIC_LVDS, + .val = IMX6SX_GPR5_DISP_MUX_DCIC1_LVDS, + } +}; + +static const struct dcic_mux imx6sx_dcic1_mux[] = { + { + .dcic = DCIC_LCDIF2, + .val = IMX6SX_GPR5_DISP_MUX_DCIC2_LCDIF2, + }, { + .dcic = DCIC_LVDS, + .val = IMX6SX_GPR5_DISP_MUX_DCIC2_LVDS, + } +}; + +static const struct bus_mux imx6sx_dcic_buses[] = { + { + .name = DCIC0_DEV_NAME, + .reg = IOMUXC_GPR5, + .shift = 1, + .mask = IMX6SX_GPR5_DISP_MUX_DCIC1_MASK, + .dcic_mux_num = ARRAY_SIZE(imx6sx_dcic0_mux), + .dcics = imx6sx_dcic0_mux, + }, { + .name = DCIC1_DEV_NAME, + .reg = IOMUXC_GPR5, + .shift = 2, + .mask = IMX6SX_GPR5_DISP_MUX_DCIC2_MASK, + .dcic_mux_num = ARRAY_SIZE(imx6sx_dcic1_mux), + .dcics = imx6sx_dcic1_mux, + } +}; + +static const struct dcic_info imx6sx_dcic_info = { + .bus_mux_num = ARRAY_SIZE(imx6sx_dcic_buses), + .buses = imx6sx_dcic_buses, +}; + +static const struct of_device_id dcic_dt_ids[] = { + { .compatible = "fsl,imx6q-dcic", .data = &imx6q_dcic_info, }, + { .compatible = "fsl,imx6sx-dcic", .data = &imx6sx_dcic_info, }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, dcic_dt_ids); + +static int of_get_dcic_val(struct device_node *np, struct dcic_data *dcic) +{ + const char *mux; + int ret; + u32 i, dcic_id; + + ret = of_property_read_string(np, "dcic_mux", &mux); + if (ret < 0) { + dev_err(dcic->dev, "Can not get dcic_mux\n"); + return ret; + } + ret = of_property_read_u32(np, "dcic_id", &dcic_id); + if (ret < 0) { + dev_err(dcic->dev, "Can not get dcic_id\n"); + return ret; + } + + dcic->bus_n = dcic_id; + + for (i = 0; i < dcic->buses[dcic_id].dcic_mux_num; i++) + if (!strcmp(mux, dcic->buses[dcic_id].dcics[i].dcic)) { + dcic->mux_n = i; + return dcic->buses[dcic_id].dcics[i].val; + } + + return -EINVAL; +} + +static void dcic_enable(struct dcic_data *dcic) +{ + u32 val; + + val = readl(&dcic->regs->dcicc); + val |= DCICC_IC_ENABLE; + writel(val, &dcic->regs->dcicc); +} + +void dcic_disable(struct dcic_data *dcic) +{ + u32 val; + + val = readl(&dcic->regs->dcicc); + val &= ~DCICC_IC_MASK; + val |= DCICC_IC_DISABLE; + writel(val, &dcic->regs->dcicc); +} + +static void roi_enable(struct dcic_data *dcic, struct roi_params *roi_param) +{ + u32 val; + u32 roi_n = roi_param->roi_n; + + val = readl(&dcic->regs->ROI[roi_n].dcicrc); + val |= DCICRC_ROI_ENABLE; + if (roi_param->freeze) + val |= DCICRC_ROI_FROZEN; + writel(val, &dcic->regs->ROI[roi_n].dcicrc); +} + +static void roi_disable(struct dcic_data *dcic, u32 roi_n) +{ + u32 val; + + val = readl(&dcic->regs->ROI[roi_n].dcicrc); + val &= ~DCICRC_ROI_ENABLE; + writel(val, &dcic->regs->ROI[roi_n].dcicrc); +} + +static bool roi_configure(struct dcic_data *dcic, struct roi_params *roi_param) +{ + struct roi_regs *roi_reg; + u32 val; + + if (roi_param->roi_n < 0 || roi_param->roi_n >= 16) { + printk(KERN_ERR "Error, Wrong ROI number %d\n", roi_param->roi_n); + return false; + } + + if (roi_param->end_x <= roi_param->start_x || + roi_param->end_y <= roi_param->start_y) { + printk(KERN_ERR "Error, Wrong ROI\n"); + return false; + } + + roi_reg = (struct roi_regs *) &dcic->regs->ROI[roi_param->roi_n]; + + /* init roi block size */ + val = roi_param->start_y << 16 | roi_param->start_x; + writel(val, &roi_reg->dcicrc); + + val = roi_param->end_y << 16 | roi_param->end_x; + writel(val, &roi_reg->dcicrs); + + writel(roi_param->ref_sig, &roi_reg->dcicrrs); + + roi_enable(dcic, roi_param); + return true; +} + +static void dcic_int_enable(struct dcic_data *dcic) +{ + u32 val; + + /* Clean pending interrupt before enable int */ + writel(DCICS_FI_STAT_PENDING, &dcic->regs->dcics); + writel(0xffffffff, &dcic->regs->dcics); + + /* Enable function interrupt */ + val = readl(&dcic->regs->dcicic); + val &= ~DCICIC_FUN_INT_MASK; + val |= DCICIC_FUN_INT_ENABLE; + writel(val, &dcic->regs->dcicic); +} + +static void dcic_int_disable(struct dcic_data *dcic) +{ + u32 val; + + /* Disable both function and error interrupt */ + val = readl(&dcic->regs->dcicic); + val = DCICIC_ERROR_INT_DISABLE | DCICIC_FUN_INT_DISABLE; + writel(val, &dcic->regs->dcicic); +} + +static irqreturn_t dcic_irq_handler(int irq, void *data) +{ + u32 i; + + struct dcic_data *dcic = data; + u32 dcics = readl(&dcic->regs->dcics); + + dcic->result = dcics & 0xffff; + + dcic_int_disable(dcic); + + /* clean dcic interrupt state */ + writel(DCICS_FI_STAT_PENDING, &dcic->regs->dcics); + writel(dcics, &dcic->regs->dcics); + + for (i = 0; i < 16; i++) { + printk(KERN_INFO "ROI=%d,crcRS=0x%x, crcCS=0x%x\n", i, + readl(&dcic->regs->ROI[i].dcicrrs), + readl(&dcic->regs->ROI[i].dcicrcs)); + } + complete(&dcic->roi_crc_comp); + + return 0; +} + +static int dcic_configure(struct dcic_data *dcic, unsigned int sync) +{ + u32 val; + val = 0; + + /* vsync, hsync, DE, clk_pol */ + if (!(sync & FB_SYNC_HOR_HIGH_ACT)) + val |= DCICC_HSYNC_POL_ACTIVE_LOW; + if (!(sync & FB_SYNC_VERT_HIGH_ACT)) + val |= DCICC_VSYNC_POL_ACTIVE_LOW; + if (sync & FB_SYNC_OE_LOW_ACT) + val |= DCICC_DE_ACTIVE_LOW; + if (sync & FB_SYNC_CLK_LAT_FALL) + val |= DCICC_CLK_POL_INVERTED; + + writel(val, &dcic->regs->dcicc); + return 0; +} + +static int dcic_open(struct inode *inode, struct file *file) +{ + struct dcic_data *dcic; + + dcic = container_of(inode->i_cdev, struct dcic_data, cdev); + + mutex_lock(&dcic->lock); + + clk_prepare_enable(dcic->disp_axi_clk); + clk_prepare_enable(dcic->dcic_clk); + + file->private_data = dcic; + mutex_unlock(&dcic->lock); + return 0; +} + +static int dcic_release(struct inode *inode, struct file *file) +{ + struct dcic_data *dcic = file->private_data; + u32 i; + + mutex_lock(&dcic->lock); + + for (i = 0; i < 16; i++) + roi_disable(dcic, i); + + clk_disable_unprepare(dcic->dcic_clk); + clk_disable_unprepare(dcic->disp_axi_clk); + + mutex_unlock(&dcic->lock); + return 0; +} + +static int dcic_init(struct device_node *np, struct dcic_data *dcic) +{ + u32 val, bus; + + val = of_get_dcic_val(np, dcic); + if (val < 0) { + printk(KERN_ERR "Error incorrect\n"); + return -1; + } + + bus = dcic->bus_n; + + regmap_update_bits(dcic->regmap, dcic->buses[bus].reg , + dcic->buses[bus].mask, val); + + return 0; +} + +static long dcic_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int __user *argp = (void __user *)arg; + struct dcic_data *dcic = file->private_data; + struct roi_params roi_param; + unsigned int sync; + int ret = 0; + + switch (cmd) { + case DCIC_IOC_CONFIG_DCIC: + if (!copy_from_user(&sync, argp, sizeof(unsigned int))) + dcic_configure(dcic, sync); + break; + case DCIC_IOC_CONFIG_ROI: + if (copy_from_user(&roi_param, argp, sizeof(roi_param))) + return -EFAULT; + else + if (!roi_configure(dcic, &roi_param)) + return -EINVAL; + break; + case DCIC_IOC_GET_RESULT: + init_completion(&dcic->roi_crc_comp); + + dcic_enable(dcic); + + dcic->result = 0; + msleep(25); + + dcic_int_enable(dcic); + + ret = wait_for_completion_interruptible_timeout( + &dcic->roi_crc_comp, 1 * HZ); + if (ret == 0) { + dev_err(dcic->dev, + "dcic wait for roi crc cal timeout\n"); + ret = -ETIME; + } else if (ret > 0) { + if (copy_to_user(argp, &dcic->result, sizeof(dcic->result))) + return -EFAULT; + ret = 0; + } + dcic_disable(dcic); + break; + default: + printk(KERN_ERR "%s, Unsupport cmd %d\n", __func__, cmd); + break; + } + return ret; +} + + +static const struct file_operations mxc_dcic_fops = { + .owner = THIS_MODULE, + .open = dcic_open, + .release = dcic_release, + .unlocked_ioctl = dcic_ioctl, +}; + +static int dcic_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct of_device_id *of_id = + of_match_device(dcic_dt_ids, dev); + const struct dcic_info *dcic_info = + (const struct dcic_info *)of_id->data; + struct device_node *np = dev->of_node; + struct dcic_data *dcic; + struct resource *res; + const char *name; + dev_t devt; + int ret = 0; + int irq; + + dcic = devm_kzalloc(&pdev->dev, + sizeof(struct dcic_data), + GFP_KERNEL); + if (!dcic) { + dev_err(&pdev->dev, "Cannot allocate device data\n"); + ret = -ENOMEM; + goto ealloc; + } + + platform_set_drvdata(pdev, dcic); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "No dcic base address found.\n"); + ret = -ENODEV; + goto ealloc; + } + + dcic->regs = (struct dcic_regs *) devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!dcic->regs) { + dev_err(&pdev->dev, "ioremap failed with dcic base\n"); + ret = -ENOMEM; + goto ealloc; + } + + dcic->dev = dev; + dcic->buses = dcic_info->buses; + + dcic->regmap = syscon_regmap_lookup_by_phandle(np, "gpr"); + if (IS_ERR(dcic->regmap)) { + dev_err(dev, "failed to get parent regmap\n"); + ret = PTR_ERR(dcic->regmap); + goto ealloc; + } + + /* clock */ + dcic->disp_axi_clk = devm_clk_get(&pdev->dev, "disp-axi"); + if (IS_ERR(dcic->disp_axi_clk)) { + dev_err(&pdev->dev, "get disp-axi clock failed\n"); + ret = PTR_ERR(dcic->disp_axi_clk); + goto ealloc; + } + + dcic->dcic_clk = devm_clk_get(&pdev->dev, "dcic"); + if (IS_ERR(dcic->dcic_clk)) { + dev_err(&pdev->dev, "get dcic clk failed\n"); + ret = PTR_ERR(dcic->dcic_clk); + goto ealloc; + } + + mutex_init(&dcic->lock); + ret = dcic_init(np, dcic); + if (ret < 0) { + printk(KERN_ERR "Failed init dcic\n"); + goto ealloc; + } + + /* register device */ + name = dcic->buses[dcic->bus_n].name; + dcic->major = register_chrdev(0, name, &mxc_dcic_fops); + if (dcic->major < 0) { + printk(KERN_ERR "DCIC: unable to get a major for dcic\n"); + ret = -EBUSY; + goto ealloc; + } + + dcic->class = class_create(THIS_MODULE, name); + if (IS_ERR(dcic->class)) { + ret = PTR_ERR(dcic->class); + goto err_out_chrdev; + } + + /* create char device */ + devt = MKDEV(dcic->major, 0); + dcic->devt = devt; + + cdev_init(&dcic->cdev, &mxc_dcic_fops); + dcic->cdev.owner = THIS_MODULE; + ret = cdev_add(&dcic->cdev, devt, 1); + if (ret) + goto err_out_class; + + device_create(dcic->class, NULL, devt, + NULL, name); + + /* IRQ */ + irq = platform_get_irq(pdev, 0); + + ret = devm_request_irq(&pdev->dev, irq, dcic_irq_handler, 0, + dev_name(&pdev->dev), dcic); + if (ret) { + dev_err(&pdev->dev, "request_irq (%d) failed with error %d\n", + irq, ret); + goto err_out_cdev; + } + + return 0; + +err_out_cdev: + cdev_del(&dcic->cdev); +err_out_class: + device_destroy(dcic->class, devt); + class_destroy(dcic->class); +err_out_chrdev: + unregister_chrdev(dcic->major, name); +ealloc: + return ret; +} + +static int dcic_remove(struct platform_device *pdev) +{ + struct dcic_data *dcic = platform_get_drvdata(pdev); + const char *name; + + name = dcic->buses[dcic->bus_n].name; + + device_destroy(dcic->class, dcic->devt); + cdev_del(&dcic->cdev); + class_destroy(dcic->class); + unregister_chrdev(dcic->major, name); + mutex_destroy(&dcic->lock); + + return 0; +} + +static struct platform_driver dcic_driver = { + .driver = { + .name = DRIVER_NAME, + .of_match_table = dcic_dt_ids, + }, + .probe = dcic_probe, + .remove = dcic_remove, +}; + +module_platform_driver(dcic_driver); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("MXC DCIC driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h index 7eb2848b2122..29f225235782 100644 --- a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h +++ b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h @@ -304,15 +304,15 @@ #define IMX6Q_GPR10_OCRAM_TZ_ADDR_MASK (0x3f << 5) #define IMX6Q_GPR10_OCRAM_TZ_EN_MASK BIT(4) #define IMX6Q_GPR10_DCIC2_MUX_CTL_MASK (0x3 << 2) -#define IMX6Q_GPR10_DCIC2_MUX_CTL_IPU1_DI0 (0x0 << 2) -#define IMX6Q_GPR10_DCIC2_MUX_CTL_IPU1_DI1 (0x1 << 2) -#define IMX6Q_GPR10_DCIC2_MUX_CTL_IPU2_DI0 (0x2 << 2) -#define IMX6Q_GPR10_DCIC2_MUX_CTL_IPU2_DI1 (0x3 << 2) +#define IMX6Q_GPR10_DCIC2_MUX_CTL_IPU1_DI1 (0x0 << 2) +#define IMX6Q_GPR10_DCIC2_MUX_CTL_LVDS0 (0x1 << 2) +#define IMX6Q_GPR10_DCIC2_MUX_CTL_LVDS1 (0x2 << 2) +#define IMX6Q_GPR10_DCIC2_MUX_CTL_MIPI (0x3 << 2) #define IMX6Q_GPR10_DCIC1_MUX_CTL_MASK (0x3 << 0) #define IMX6Q_GPR10_DCIC1_MUX_CTL_IPU1_DI0 (0x0 << 0) -#define IMX6Q_GPR10_DCIC1_MUX_CTL_IPU1_DI1 (0x1 << 0) -#define IMX6Q_GPR10_DCIC1_MUX_CTL_IPU2_DI0 (0x2 << 0) -#define IMX6Q_GPR10_DCIC1_MUX_CTL_IPU2_DI1 (0x3 << 0) +#define IMX6Q_GPR10_DCIC1_MUX_CTL_LVDS0 (0x1 << 0) +#define IMX6Q_GPR10_DCIC1_MUX_CTL_LVDS1 (0x2 << 0) +#define IMX6Q_GPR10_DCIC1_MUX_CTL_HDMI (0x3 << 0) #define IMX6Q_GPR12_ARMP_IPG_CLK_EN BIT(27) #define IMX6Q_GPR12_ARMP_AHB_CLK_EN BIT(26) diff --git a/include/linux/mxc_dcic.h b/include/linux/mxc_dcic.h new file mode 100644 index 000000000000..8e330bd466da --- /dev/null +++ b/include/linux/mxc_dcic.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +/*! + * @file linux/mxc_dcic.h + * + * @brief Global header file for the MXC DCIC driver + * + * @ingroup MXC DCIC + */ + +#ifndef __LINUX_DCIC_H__ +#define __LINUX_DCIC_H__ + +#include <uapi/linux/mxc_dcic.h> + +#define DCICC_IC_ENABLE 0x1 +#define DCICC_IC_DISABLE 0x0 +#define DCICC_IC_MASK 0x1 +#define DCICC_DE_ACTIVE_HIGH 0 +#define DCICC_DE_ACTIVE_LOW (0x1 << 4) +#define DCICC_DE_ACTIVE_MASK (0x1 << 4) +#define DCICC_HSYNC_POL_ACTIVE_HIGH 0 +#define DCICC_HSYNC_POL_ACTIVE_LOW (0x1 << 5) +#define DCICC_HSYNC_POL_ACTIVE_MASK (0x1 << 5) +#define DCICC_VSYNC_POL_ACTIVE_HIGH 0 +#define DCICC_VSYNC_POL_ACTIVE_LOW (0x1 << 6) +#define DCICC_VSYNC_POL_ACTIVE_MASK (0x1 << 6) +#define DCICC_CLK_POL_NO_INVERTED 0 +#define DCICC_CLK_POL_INVERTED (0x1 << 7) +#define DCICC_CLK_POL_INVERTED_MASK (0x1 << 7) + +#define DCICIC_ERROR_INT_DISABLE 1 +#define DCICIC_ERROR_INT_ENABLE 0 +#define DCICIC_ERROR_INT_MASK_MASK 1 +#define DCICIC_FUN_INT_DISABLE (0x1 << 1) +#define DCICIC_FUN_INT_ENABLE 0 +#define DCICIC_FUN_INT_MASK (0x1 << 1) +#define DCICIC_FREEZE_MASK_CHANGED 0 +#define DCICIC_FREEZE_MASK_FORZEN (0x1 << 3) +#define DCICIC_FREEZE_MASK_MASK (0x1 << 3) +#define DCICIC_EXT_SIG_EX_DISABLE 0 +#define DCICIC_EXT_SIG_EN_ENABLE (0x1 << 16) +#define DCICIC_EXT_SIG_EN_MASK (0x1 << 16) + +#define DCICS_ROI_MATCH_STAT_MASK 0xFFFF +#define DCICS_EI_STAT_PENDING (0x1 << 16) +#define DCICS_EI_STAT_NO_PENDING 0 +#define DCICS_FI_STAT_PENDING (0x1 << 17) +#define DCICS_FI_STAT_NO_PENDING 0 + +#define DCICRC_ROI_START_OFFSET_X_MASK 0x1FFF +#define DCICRC_ROI_START_OFFSET_X_SHIFT 0 +#define DCICRC_ROI_START_OFFSET_Y_MASK (0xFFF << 16) +#define DCICRC_ROI_START_OFFSET_Y_SHIFT 16 +#define DCICRC_ROI_CHANGED 0 +#define DCICRC_ROI_FROZEN (0x1 << 30) +#define DCICRC_ROI_ENABLE (0x1 << 31) +#define DCICRC_ROI_DISABLE 0 + +#define DCICRS_ROI_END_OFFSET_X_MASK 0x1FFF +#define DCICRS_ROI_END_OFFSET_X_SHIFT 0 +#define DCICRS_ROI_END_OFFSET_Y_MASK (0xFFF << 16) +#define DCICRS_ROI_END_OFFSET_Y_SHIFT 16 + +struct roi_regs { + u32 dcicrc; + u32 dcicrs; + u32 dcicrrs; + u32 dcicrcs; +}; + +struct dcic_regs { + u32 dcicc; + u32 dcicic; + u32 dcics; + u32 dcic_reserved; + struct roi_regs ROI[16]; +}; + +struct dcic_mux { + char dcic[16]; + u32 val; +}; + +struct bus_mux { + char name[16]; + int reg; + int shift; + int mask; + int dcic_mux_num; + const struct dcic_mux *dcics; +}; + +struct dcic_info { + int bus_mux_num; + const struct bus_mux *buses; +}; + +struct dcic_data { + struct regmap *regmap; + struct device *dev; + struct dcic_regs *regs; + const struct bus_mux *buses; + u32 bus_n; + u32 mux_n; + struct clk *disp_axi_clk; + struct clk *dcic_clk; + struct mutex lock; + struct completion roi_crc_comp; + struct class *class; + int major; + struct cdev cdev; /* Char device structure */ + dev_t devt; + unsigned int result; +}; +#endif |