};
+ isp_pin {
+ isp_mipi:isp_mipi{
+ rockchip,pins = <CIF_CLKOUT>;
+ rockchip,pull = <VALUE_PULL_DISABLE>;
+ //rockchip,voltage = <VALUE_VOL_DEFAULT>;
+ rockchip,drive = <VALUE_DRV_DEFAULT>;
+ //rockchip,tristate = <VALUE_TRI_DEFAULT>;
+ };
+ isp_dvp_sync_d2d9:isp_dvp_force {
+ rockchip,pins = <CIF_DATA2>,<CIF_DATA3>,
+ <CIF_DATA4>,<CIF_DATA5>,
+ <CIF_DATA6>,<CIF_DATA7>,
+ <CIF_DATA8>,<CIF_DATA9>,
+ <CIF_VSYNC>,<CIF_HREF>,
+ <CIF_CLKIN>,<CIF_CLKOUT>;
+ rockchip,pull = <VALUE_PULL_DISABLE>;
+ //rockchip,voltage = <VALUE_VOL_DEFAULT>;
+ rockchip,drive = <VALUE_DRV_DEFAULT>;
+ //rockchip,tristate = <VALUE_TRI_DEFAULT>;
+
+ };
+
+ isp_dvp_d0d1:isp_d0d1 {
+ rockchip,pins = <CIF_DATA0>,<CIF_DATA1>;
+ rockchip,pull = <VALUE_PULL_DISABLE>;
+ //rockchip,voltage = <VALUE_VOL_DEFAULT>;
+ rockchip,drive = <VALUE_DRV_DEFAULT>;
+ //rockchip,tristate = <VALUE_TRI_DEFAULT>;
+ };
+
+ isp_dvpd10d11:ispd10d11 {
+ rockchip,pins = <CIF_DATA10>,<CIF_DATA11>;
+ rockchip,pull = <VALUE_PULL_DISABLE>;
+ //rockchip,voltage = <VALUE_VOL_DEFAULT>;
+ rockchip,drive = <VALUE_DRV_DEFAULT>;
+ //rockchip,tristate = <VALUE_TRI_DEFAULT>;
+ };
+
+ isp_shutter:isp_shutter {
+ rockchip,pins = <ISP_SHUTTEREN>,<ISP_SHUTTERTRIG>;
+ rockchip,pull = <VALUE_PULL_DISABLE>;
+ //rockchip,voltage = <VALUE_VOL_DEFAULT>;
+ rockchip,drive = <VALUE_DRV_DEFAULT>;
+ //rockchip,tristate = <VALUE_TRI_DEFAULT>;
+ };
+
+ isp_flash_trigger:isp_trigger {
+ rockchip,pins = <ISP_FLASHTRIGOUTSPI1_CS0>;
+ rockchip,pull = <VALUE_PULL_DISABLE>;
+ //rockchip,voltage = <VALUE_VOL_DEFAULT>;
+ rockchip,drive = <VALUE_DRV_DEFAULT>;
+ //rockchip,tristate = <VALUE_TRI_DEFAULT>;
+ };
+
+ isp_prelight:isp_prelight {
+ rockchip,pins = <ISP_PRELIGHTTRIGSPI1_RXD>;
+ rockchip,pull = <VALUE_PULL_DISABLE>;
+ //rockchip,voltage = <VALUE_VOL_DEFAULT>;
+ rockchip,drive = <VALUE_DRV_DEFAULT>;
+ //rockchip,tristate = <VALUE_TRI_DEFAULT>;
+ };
+ };
};
};
>;
};
+ isp:isp@0xFF910000{
+ compatible = "rockchip,isp";
+ reg = <0xFF910000 0x10000>;
+ interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk_gates16 2>, <&clk_gates16 1>, <&clk_isp>, <&clk_isp_jpe>, <&dummy>, <&clk_cif_out>;
+ clock_names = "aclk_isp", "hclk_isp", "clk_isp", "clk_isp_jpe", "pclkin_isp", "clk_vipout";
+ pinctrl-names = "default", "isp_dvp8bit","isp_dvp10bit","isp_dvp12bit";
+ pinctrl-0 = <&isp_mipi>;
+ pinctrl-1 = <&isp_mipi &isp_dvp_sync_d2d9>;
+ pinctrl-2 = <&isp_mipi &isp_dvp_sync_d2d9 &isp_dvp_d0d1>;
+ pinctrl-3 = <&isp_mipi &isp_dvp_sync_d2d9 &isp_dvp_d0d1 &isp_dvpd10d11>;
+
+ status = "disabled";
+ };
+
+
};
source "drivers/media/i2c/Kconfig"
source "drivers/media/tuners/Kconfig"
source "drivers/media/dvb-frontends/Kconfig"
+source "drivers/media/video/rk_camsys/Kconfig"
endif # MEDIA_SUPPORT
obj-y += common/ platform/ pci/ usb/ mmc/ firewire/ parport/
obj-$(CONFIG_VIDEO_DEV) += radio/
+obj-y += video/rk_camsys/
--- /dev/null
+config CAMSYS_DRV
+ tristate "camsys driver "
+ default n
+
+menu "RockChip camera system driver"
+ depends on CAMSYS_DRV
+
+config CAMSYS_MRV
+ tristate "camsys driver for marvin isp "
+ default n
+ ---help---
+
+config CAMSYS_CIF
+ tristate "camsys driver for cif "
+ default n
+ ---help---
+
+endmenu
--- /dev/null
+#
+# Makefile for rockchip camsys driver
+#
+obj-$(CONFIG_CAMSYS_DRV) += camsys_drv.o
+obj-$(CONFIG_CAMSYS_MRV) += camsys_marvin.o camsys_mipicsi_phy.o
+obj-$(CONFIG_CAMSYS_CIF) += camsys_cif.o
+
--- /dev/null
+#include "camsys_cif.h"
+
+static const char miscdev_cif0_name[] = CAMSYS_CIF0_DEVNAME;
+static const char miscdev_cif1_name[] = CAMSYS_CIF1_DEVNAME;
+
+static int camsys_cif_iomux_cb(camsys_extdev_t *extdev,void *ptr)
+{
+ unsigned int cif_index;
+ camsys_dev_t *camsys_dev = (camsys_dev_t*)ptr;
+
+ if (strcmp(dev_name(camsys_dev->miscdev.this_device), CAMSYS_CIF1_DEVNAME)==0) {
+ cif_index = 1;
+ } else {
+ cif_index = 0;
+ }
+
+#if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)
+ switch(cif_index){
+ case 0:
+ {
+ iomux_set(CIF0_CLKOUT);
+ write_grf_reg(GRF_IO_CON3, (CIF_DRIVER_STRENGTH_MASK|CIF_DRIVER_STRENGTH_8MA));
+ write_grf_reg(GRF_IO_CON4, (CIF_CLKOUT_AMP_MASK|CIF_CLKOUT_AMP_1V8));
+ break;
+ }
+ default:
+ camsys_err("Cif index(%d) is invalidate!!!\n",cif_index);
+ break;
+ }
+#elif defined(CONFIG_ARCH_RK30)
+ switch(cif_index){
+ case 0:
+ {
+ rk30_mux_api_set(GPIO1B3_CIF0CLKOUT_NAME, GPIO1B_CIF0_CLKOUT);
+ break;
+ }
+ case 1:
+ {
+ rk30_mux_api_set(GPIO1C0_CIF1DATA2_RMIICLKOUT_RMIICLKIN_NAME,GPIO1C_CIF1_DATA2);
+ rk30_mux_api_set(GPIO1C1_CIFDATA3_RMIITXEN_NAME,GPIO1C_CIF_DATA3);
+ rk30_mux_api_set(GPIO1C2_CIF1DATA4_RMIITXD1_NAME,GPIO1C_CIF1_DATA4);
+ rk30_mux_api_set(GPIO1C3_CIFDATA5_RMIITXD0_NAME,GPIO1C_CIF_DATA5);
+ rk30_mux_api_set(GPIO1C4_CIFDATA6_RMIIRXERR_NAME,GPIO1C_CIF_DATA6);
+ rk30_mux_api_set(GPIO1C5_CIFDATA7_RMIICRSDVALID_NAME,GPIO1C_CIF_DATA7);
+ rk30_mux_api_set(GPIO1C6_CIFDATA8_RMIIRXD1_NAME,GPIO1C_CIF_DATA8);
+ rk30_mux_api_set(GPIO1C7_CIFDATA9_RMIIRXD0_NAME,GPIO1C_CIF_DATA9);
+
+ rk30_mux_api_set(GPIO1D0_CIF1VSYNC_MIIMD_NAME,GPIO1D_CIF1_VSYNC);
+ rk30_mux_api_set(GPIO1D1_CIF1HREF_MIIMDCLK_NAME,GPIO1D_CIF1_HREF);
+ rk30_mux_api_set(GPIO1D2_CIF1CLKIN_NAME,GPIO1D_CIF1_CLKIN);
+ rk30_mux_api_set(GPIO1D3_CIF1DATA0_NAME,GPIO1D_CIF1_DATA0);
+ rk30_mux_api_set(GPIO1D4_CIF1DATA1_NAME,GPIO1D_CIF1_DATA1);
+ rk30_mux_api_set(GPIO1D5_CIF1DATA10_NAME,GPIO1D_CIF1_DATA10);
+ rk30_mux_api_set(GPIO1D6_CIF1DATA11_NAME,GPIO1D_CIF1_DATA11);
+ rk30_mux_api_set(GPIO1D7_CIF1CLKOUT_NAME,GPIO1D_CIF1_CLKOUT);
+ break;
+ }
+ default:
+ camsys_err("Cif index(%d) is invalidate!!!\n", cif_index);
+ break;
+ }
+#elif defined(CONFIG_ARCH_RK319X)
+ switch(cif_index){
+ case 0:
+ {
+ unsigned int cif_vol_sel;
+ //set cif vol domain
+ cif_vol_sel = __raw_readl(RK30_GRF_BASE+0x018c);
+ __raw_writel( (cif_vol_sel |0x20002),RK30_GRF_BASE+0x018c);
+ //set driver strength
+ __raw_writel(0xffffffff, RK30_GRF_BASE+0x01dc);
+
+ iomux_set(CIF0_CLKOUT);
+ iomux_set(CIF0_CLKIN);
+ iomux_set(CIF0_HREF);
+ iomux_set(CIF0_VSYNC);
+ iomux_set(CIF0_D0);
+ iomux_set(CIF0_D1);
+ iomux_set(CIF0_D2);
+ iomux_set(CIF0_D3);
+ iomux_set(CIF0_D4);
+ iomux_set(CIF0_D5);
+ iomux_set(CIF0_D6);
+ iomux_set(CIF0_D7);
+ iomux_set(CIF0_D8);
+ iomux_set(CIF0_D9);
+ camsys_trace(1, "%s cif iomux success\n",dev_name(camsys_dev->miscdev.this_device));
+ break;
+ }
+ case 1:
+ default:
+ camsys_err("Cif index(%d) is invalidate!!!\n", cif_index);
+ break;
+ }
+#endif
+
+ return 0;
+}
+static int camsys_cif_clkin_cb(void *ptr, unsigned int on)
+{
+ camsys_dev_t *camsys_dev = (camsys_dev_t*)ptr;
+ camsys_cif_clk_t *clk = (camsys_cif_clk_t*)camsys_dev->clk;
+
+ spin_lock(&clk->lock);
+ if (on && !clk->in_on) {
+ clk_enable(clk->pd_cif);
+ clk_enable(clk->aclk_cif);
+ clk_enable(clk->hclk_cif);
+ clk_enable(clk->cif_clk_in);
+
+ clk->in_on = true;
+ camsys_trace(1, "%s clock in turn on",dev_name(camsys_dev->miscdev.this_device));
+ } else if (!on && clk->in_on) {
+ clk_disable(clk->aclk_cif);
+ clk_disable(clk->hclk_cif);
+ clk_disable(clk->cif_clk_in);
+ clk_disable(clk->pd_cif);
+ clk->in_on = false;
+ camsys_trace(1, "%s clock in turn off",dev_name(camsys_dev->miscdev.this_device));
+ }
+ spin_unlock(&clk->lock);
+ return 0;
+}
+
+static int camsys_cif_clkout_cb(void *ptr, unsigned int on)
+{
+ camsys_dev_t *camsys_dev = (camsys_dev_t*)ptr;
+ camsys_cif_clk_t *clk = (camsys_cif_clk_t*)camsys_dev->clk;
+ struct clk *cif_clk_out_div;
+
+
+ spin_lock(&clk->lock);
+ if (on && (clk->out_on != on)) {
+ clk_enable(clk->cif_clk_out);
+ clk_set_rate(clk->cif_clk_out,on);
+
+ clk->out_on = on;
+ camsys_trace(1, "%s clock out(rate: %dHz) turn on",dev_name(camsys_dev->miscdev.this_device),
+ clk->out_on);
+ } else if (!on && clk->out_on) {
+ if (strcmp(dev_name(camsys_dev->miscdev.this_device),miscdev_cif1_name)==0) {
+ cif_clk_out_div = clk_get(NULL, "cif1_out_div");
+ } else{
+ cif_clk_out_div = clk_get(NULL, "cif0_out_div");
+ if(IS_ERR_OR_NULL(cif_clk_out_div)) {
+ cif_clk_out_div = clk_get(NULL, "cif_out_div");
+ }
+ }
+
+ if(!IS_ERR_OR_NULL(cif_clk_out_div)) {
+ clk_set_parent(clk->cif_clk_out, cif_clk_out_div);
+ clk_put(cif_clk_out_div);
+ } else {
+ camsys_warn("%s clock out may be not off!", dev_name(camsys_dev->miscdev.this_device));
+ }
+ clk_disable(clk->cif_clk_out);
+ clk->out_on = 0;
+
+ camsys_trace(1, "%s clock out turn off",dev_name(camsys_dev->miscdev.this_device));
+ }
+ spin_unlock(&clk->lock);
+
+ {
+ // __raw_writel(0x00, CRU_PCLK_REG30+RK30_CRU_BASE);
+ }
+
+ return 0;
+}
+
+static irqreturn_t camsys_cif_irq(int irq, void *data)
+{
+ camsys_dev_t *camsys_dev = (camsys_dev_t*)data;
+ camsys_irqstas_t *irqsta;
+ camsys_irqpool_t *irqpool;
+ unsigned int intsta,frmsta;
+
+ intsta = __raw_readl(camsys_dev->devmems.registermem->vir_base + CIF_INITSTA);
+ frmsta = __raw_readl(camsys_dev->devmems.registermem->vir_base + CIF_FRAME_STATUS);
+ printk("get oneframe,intsta = 0x%x \n",intsta);
+
+ if (intsta & 0x200) {
+ __raw_writel(0x200,camsys_dev->devmems.registermem->vir_base + CIF_INITSTA);
+ __raw_writel(0xf000,camsys_dev->devmems.registermem->vir_base + CIF_CTRL);
+ }
+
+ if (intsta &0x01) {
+ __raw_writel(0x01,camsys_dev->devmems.registermem->vir_base + CIF_INITSTA);
+ __raw_writel(0x02,camsys_dev->devmems.registermem->vir_base + CIF_FRAME_STATUS);
+ __raw_writel(0xf001,camsys_dev->devmems.registermem->vir_base + CIF_CTRL);
+ }
+
+ spin_lock(&camsys_dev->irq.lock);
+ list_for_each_entry(irqpool, &camsys_dev->irq.irq_pool, list) {
+ spin_lock(&irqpool->lock);
+ if (!list_empty(&irqpool->deactive)) {
+ irqsta = list_first_entry(&irqpool->deactive, camsys_irqstas_t, list);
+ irqsta->sta.mis = intsta;
+ irqsta->sta.ris = intsta;
+ list_del_init(&irqsta->list);
+ list_add_tail(&irqsta->list,&irqpool->active);
+ irqsta = list_first_entry(&irqpool->active, camsys_irqstas_t, list);
+ //wake_up_all(&camsys_dev->irq.irq_done);
+ wake_up(&irqpool->done);
+ }
+ spin_unlock(&irqpool->lock);
+ }
+ spin_unlock(&camsys_dev->irq.lock);
+
+ return IRQ_HANDLED;
+}
+
+static int camsys_cif_remove(struct platform_device *pdev)
+{
+ camsys_dev_t *camsys_dev = platform_get_drvdata(pdev);
+ camsys_cif_clk_t *cif_clk;
+
+ if (camsys_dev->clk != NULL) {
+ cif_clk = (camsys_cif_clk_t*)camsys_dev->clk;
+ if (cif_clk->out_on)
+ camsys_cif_clkout_cb(camsys_dev->clk, 0);
+ if (cif_clk->in_on)
+ camsys_cif_clkin_cb(camsys_dev->clk, 0);
+
+ if (cif_clk->pd_cif)
+ clk_put(cif_clk->pd_cif);
+ if (cif_clk->aclk_cif)
+ clk_put(cif_clk->aclk_cif);
+ if (cif_clk->hclk_cif)
+ clk_put(cif_clk->hclk_cif);
+ if (cif_clk->cif_clk_in)
+ clk_put(cif_clk->cif_clk_in);
+ if (cif_clk->cif_clk_out)
+ clk_put(cif_clk->cif_clk_out);
+
+ kfree(cif_clk);
+ cif_clk = NULL;
+ }
+
+ return 0;
+}
+
+int camsys_cif_probe_cb(struct platform_device *pdev, camsys_dev_t *camsys_dev)
+{
+ int err = 0;
+ camsys_cif_clk_t *cif_clk;
+
+ //Irq init
+ err = request_irq(camsys_dev->irq.irq_id, camsys_cif_irq, 0, CAMSYS_CIF_IRQNAME,camsys_dev);
+ if (err) {
+ camsys_err("request irq for %s failed",CAMSYS_CIF_IRQNAME);
+ goto end;
+ }
+
+ //Clk and Iomux init
+ cif_clk = kzalloc(sizeof(camsys_cif_clk_t),GFP_KERNEL);
+ if (cif_clk == NULL) {
+ camsys_err("Allocate camsys_cif_clk_t failed!");
+ err = -EINVAL;
+ goto end;
+ }
+
+ if (strcmp(dev_name(&pdev->dev),CAMSYS_PLATFORM_CIF1_NAME) == 0) {
+ cif_clk->pd_cif = clk_get(NULL, "pd_cif1");
+ cif_clk->aclk_cif = clk_get(NULL, "aclk_cif1");
+ cif_clk->hclk_cif = clk_get(NULL, "hclk_cif1");
+ cif_clk->cif_clk_in = clk_get(NULL, "cif1_in");
+ cif_clk->cif_clk_out = clk_get(NULL, "cif1_out");
+ spin_lock_init(&cif_clk->lock);
+ cif_clk->in_on = false;
+ cif_clk->out_on = false;
+ } else {
+ cif_clk->pd_cif = clk_get(NULL, "pd_cif0");
+ cif_clk->aclk_cif = clk_get(NULL, "aclk_cif0");
+ cif_clk->hclk_cif = clk_get(NULL, "hclk_cif0");
+ cif_clk->cif_clk_in = clk_get(NULL, "pclkin_cif0");
+ cif_clk->cif_clk_out = clk_get(NULL, "cif0_out");
+ spin_lock_init(&cif_clk->lock);
+ cif_clk->in_on = false;
+ cif_clk->out_on = false;
+ }
+ camsys_dev->clk = (void*)cif_clk;
+ camsys_dev->clkin_cb = camsys_cif_clkin_cb;
+ camsys_dev->clkout_cb = camsys_cif_clkout_cb;
+ camsys_dev->iomux = camsys_cif_iomux_cb;
+
+ //Misc device init
+ camsys_dev->miscdev.minor = MISC_DYNAMIC_MINOR;
+ if (strcmp(dev_name(&pdev->dev),CAMSYS_PLATFORM_CIF1_NAME) == 0) {
+ camsys_dev->miscdev.name = miscdev_cif1_name;
+ camsys_dev->miscdev.nodename = miscdev_cif1_name;
+ } else {
+ camsys_dev->miscdev.name = miscdev_cif0_name;
+ camsys_dev->miscdev.nodename = miscdev_cif0_name;
+ }
+ camsys_dev->miscdev.fops = &camsys_fops;
+ err = misc_register(&camsys_dev->miscdev);
+ if (err < 0) {
+ camsys_trace(1,"Register /dev/%s misc device failed",camsys_dev->miscdev.name);
+ goto misc_register_failed;
+ } else {
+ camsys_trace(1,"Register /dev/%s misc device success",camsys_dev->miscdev.name);
+ }
+
+ //Variable init
+ if (strcmp(dev_name(&pdev->dev),CAMSYS_PLATFORM_CIF1_NAME) == 0) {
+ camsys_dev->dev_id = CAMSYS_DEVID_CIF_1;
+ } else {
+ camsys_dev->dev_id = CAMSYS_DEVID_CIF_0;
+ }
+ camsys_dev->platform_remove = camsys_cif_remove;
+
+ return 0;
+
+misc_register_failed:
+ if (!IS_ERR(camsys_dev->miscdev.this_device)) {
+ misc_deregister(&camsys_dev->miscdev);
+ }
+
+ if (cif_clk) {
+
+ if (cif_clk->pd_cif)
+ clk_put(cif_clk->pd_cif);
+ if (cif_clk->aclk_cif)
+ clk_put(cif_clk->aclk_cif);
+ if (cif_clk->hclk_cif)
+ clk_put(cif_clk->hclk_cif);
+ if (cif_clk->cif_clk_in)
+ clk_put(cif_clk->cif_clk_in);
+ if (cif_clk->cif_clk_out)
+ clk_put(cif_clk->cif_clk_out);
+
+ kfree(cif_clk);
+ cif_clk = NULL;
+ }
+
+end:
+ return err;
+}
+EXPORT_SYMBOL_GPL(camsys_cif_probe_cb);
+
--- /dev/null
+#ifndef __CAMSYS_CIF_H__
+#define __CAMSYS_CIF_H__
+
+#include "camsys_internal.h"
+
+#define CAMSYS_CIF_IRQNAME "CifIrq"
+
+
+#define CIF_BASE 0x00
+#define CIF_CTRL (CIF_BASE)
+#define CIF_INITSTA (CIF_BASE+0x08)
+#define CIF_FRAME_STATUS (CIF_BASE+0x60)
+#define CIF_LAST_LINE (CIF_BASE+0x68)
+#define CIF_LAST_PIX (CIF_BASE+0x6c)
+#define CRU_PCLK_REG30 0xbc
+
+
+#if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188) || defined(CONFIG_ARCH_ROCKCHIP)
+//GRF_IO_CON3 0x100
+#define CIF_DRIVER_STRENGTH_2MA (0x00 << 12)
+#define CIF_DRIVER_STRENGTH_4MA (0x01 << 12)
+#define CIF_DRIVER_STRENGTH_8MA (0x02 << 12)
+#define CIF_DRIVER_STRENGTH_12MA (0x03 << 12)
+#define CIF_DRIVER_STRENGTH_MASK (0x03 << 28)
+
+//GRF_IO_CON4 0x104
+#define CIF_CLKOUT_AMP_3V3 (0x00 << 10)
+#define CIF_CLKOUT_AMP_1V8 (0x01 << 10)
+#define CIF_CLKOUT_AMP_MASK (0x01 << 26)
+
+#define write_grf_reg(addr, val) __raw_writel(val, addr+RK_GRF_VIRT)
+#define read_grf_reg(addr) __raw_readl(addr+RK_GRF_VIRT)
+#define mask_grf_reg(addr, msk, val) write_grf_reg(addr,(val)|((~(msk))&read_grf_reg(addr)))
+#else
+#define write_grf_reg(addr, val)
+#define read_grf_reg(addr) 0
+#define mask_grf_reg(addr, msk, val)
+#endif
+
+
+typedef struct camsys_cif_clk_s {
+ struct clk *pd_cif;
+ struct clk *aclk_cif;
+ struct clk *hclk_cif;
+ struct clk *cif_clk_in;
+ bool in_on;
+
+ struct clk *cif_clk_out;
+ unsigned int out_on;
+
+ spinlock_t lock;
+} camsys_cif_clk_t;
+
+
+int camsys_cif_probe_cb(struct platform_device *pdev, camsys_dev_t *camsys_dev);
+
+#endif
+
--- /dev/null
+#include <media/camsys_head.h>
+
+#include "camsys_cif.h"
+#include "camsys_marvin.h"
+#include "camsys_mipicsi_phy.h"
+#include "camsys_gpio.h"
+
+unsigned int camsys_debug=1;
+module_param(camsys_debug, int, S_IRUGO|S_IWUSR);
+
+static int drv_version = CAMSYS_DRIVER_VERSION;
+module_param(drv_version, int, S_IRUGO);
+static int head_version = CAMSYS_HEAD_VERSION;
+module_param(head_version, int, S_IRUGO);
+
+
+typedef struct camsys_devs_s {
+ spinlock_t lock;
+ struct list_head devs;
+} camsys_devs_t;
+
+static camsys_devs_t camsys_devs;
+
+static int camsys_i2c_write(camsys_i2c_info_t *i2cinfo, camsys_dev_t *camsys_dev)
+{
+ int err = 0,i,j;
+ unsigned char buf[8],*bufp;
+ unsigned short msg_times,totallen,onelen;
+ struct i2c_msg msg[1];
+ struct i2c_adapter *adapter;
+ camsys_extdev_t *extdev;
+
+ adapter = i2c_get_adapter(i2cinfo->bus_num);
+ if (adapter == NULL) {
+ camsys_err("Get %d i2c adapter is failed!",i2cinfo->bus_num);
+ err = -EINVAL;
+ goto end;
+ }
+
+ if (i2cinfo->i2cbuf_directly) {
+ if (camsys_dev->devmems.i2cmem == NULL) {
+ camsys_err("%s has not i2c mem, it isn't support i2c buf write!",dev_name(camsys_dev->miscdev.this_device));
+ err = -EINVAL;
+ goto end;
+ }
+ totallen = (i2cinfo->i2cbuf_bytes&0xffff);
+ onelen = (i2cinfo->i2cbuf_bytes&0xffff0000)>>16;
+ msg_times = totallen/onelen;
+ if (totallen > camsys_dev->devmems.i2cmem->size) {
+ camsys_err("Want to write 0x%x bytes, i2c memory(size: 0x%x) is overlap",totallen,camsys_dev->devmems.i2cmem->size);
+ err = -EINVAL;
+ goto end;
+ }
+ bufp = (unsigned char*)camsys_dev->devmems.i2cmem->vir_base;
+ } else {
+ for (i=0; i<i2cinfo->reg_size; i++) {
+ buf[i] = (i2cinfo->reg_addr>>((i2cinfo->reg_size-1-i)*8))&0xff;
+ }
+ for (j=0; j<i2cinfo->val_size; j++) {
+ buf[i+j] = (i2cinfo->val>>(i2cinfo->val_size-1-j))&0xff;
+ }
+ bufp = buf;
+ onelen = i2cinfo->val_size + i2cinfo->reg_size;
+ msg_times = 1;
+ }
+
+ err = -EAGAIN;
+ msg->addr = (i2cinfo->slave_addr>>1);
+ msg->flags = 0;
+ msg->scl_rate = i2cinfo->speed;
+ // msg->read_type = 0;
+ msg->len = onelen;
+ for (i=0; i<msg_times; i++) {
+ msg->buf = bufp+i*onelen;
+ err = i2c_transfer(adapter, msg, 1);
+ if (err < 0) {
+ camsys_err("i2c write dev(addr:0x%x) failed!",i2cinfo->slave_addr);
+ udelay(10);
+ }
+ }
+
+end:
+ #if ((defined CONFIG_ARCH_RK319X) || (CONFIG_ARCH_ROCKCHIP))
+ if (!list_empty(&camsys_dev->extdevs.active)) {
+ list_for_each_entry(extdev, &camsys_dev->extdevs.active, active) {
+ if (extdev->phy.type == CamSys_Phy_Cif) {
+ if (extdev->phy.info.cif.fmt >= CamSys_Fmt_Raw_10b) {
+ //iomux_set(CIF0_D0); // ZYC FOR 32
+ //iomux_set(CIF0_D1); // ZYC FOR 32
+ }
+ }
+ }
+ }
+ #endif
+ return err;
+}
+
+static int camsys_i2c_read(camsys_i2c_info_t *i2cinfo, camsys_dev_t *camsys_dev)
+{
+ int err = 0,i,retry=2,tmp;
+ unsigned char buf[8];
+ struct i2c_msg msg[2];
+ struct i2c_adapter *adapter;
+ camsys_extdev_t *extdev;
+
+ adapter = i2c_get_adapter(i2cinfo->bus_num);
+ if (adapter == NULL) {
+ camsys_err("Get %d i2c adapter is failed!",i2cinfo->bus_num);
+ err = -EINVAL;
+ goto end;
+ }
+
+ for (i=0; i<i2cinfo->reg_size; i++) {
+ buf[i] = (i2cinfo->reg_addr>>((i2cinfo->reg_size-1-i)*8))&0xff;
+ }
+
+ msg[0].addr = (i2cinfo->slave_addr>>1);
+ msg[0].flags = 0;
+ msg[0].scl_rate = i2cinfo->speed;
+ //msg[0].read_type = 0;
+ msg[0].buf = buf;
+ msg[0].len = i2cinfo->reg_size;
+
+ msg[1].addr = (i2cinfo->slave_addr>>1);
+ msg[1].flags = I2C_M_RD;
+ msg[1].scl_rate = i2cinfo->speed;
+// msg[1].read_type = 0;
+ msg[1].buf = buf;
+ msg[1].len = (unsigned short)i2cinfo->val_size;
+ err = -EAGAIN;
+
+ while ((retry-- > 0) && (err < 0)) { /* ddl@rock-chips.com : Transfer again if transent is failed */
+ err = i2c_transfer(adapter, msg, 2);
+
+ if (err >= 0) {
+ err = 0;
+ } else {
+ camsys_err("i2c read dev(addr:0x%x) failed,try again-%d!",i2cinfo->slave_addr,retry);
+ udelay(10);
+ }
+ }
+
+ if (err==0) {
+ i2cinfo->val = 0x00;
+ for(i=0; i<i2cinfo->val_size; i++) {
+ tmp = buf[i];
+ i2cinfo->val |= (tmp<<((i2cinfo->val_size-1-i)*8));
+ }
+ }
+
+end:
+ #if ((defined CONFIG_ARCH_RK319X) || (CONFIG_ARCH_ROCKCHIP))
+ if (!list_empty(&camsys_dev->extdevs.active)) {
+ list_for_each_entry(extdev, &camsys_dev->extdevs.active, active) {
+ if (extdev->phy.type == CamSys_Phy_Cif) {
+ if (extdev->phy.info.cif.fmt >= CamSys_Fmt_Raw_10b) {
+ //iomux_set(CIF0_D0);//ZYC FOR 32
+ //iomux_set(CIF0_D1);//ZYC FOR 32
+ }
+ }
+ }
+ }
+ #endif
+ return err;
+}
+
+
+static int camsys_extdev_register(camsys_devio_name_t *devio, camsys_dev_t *camsys_dev)
+{
+ int err = 0,i;
+ camsys_extdev_t *extdev;
+ camsys_regulator_info_t *regulator_info;
+ camsys_regulator_t *regulator;
+ camsys_gpio_info_t *gpio_info;
+ camsys_gpio_t *gpio;
+
+
+ if ((devio->dev_id & CAMSYS_DEVID_EXTERNAL) == 0) {
+ err = -EINVAL;
+ camsys_err("dev_id: 0x%x is not support for camsys!",devio->dev_id);
+ goto end;
+ }
+
+ if (devio->phy.type == CamSys_Phy_Mipi) {
+ if (camsys_find_devmem(CAMSYS_REGISTER_MIPIPHY_RES_NAME, camsys_dev) == NULL) {
+ camsys_err("dev_id: 0x%x is connect to MIPI CSI, but %s isn't support",devio->dev_id,
+ dev_name(camsys_dev->miscdev.this_device));
+
+ err = -EINVAL;
+ goto end;
+ }
+ }
+
+
+ extdev = camsys_find_extdev(devio->dev_id, camsys_dev);
+ if (extdev != NULL) {
+ err = 0;
+ camsys_warn("Extdev(dev_id: 0x%x) has been registered in %s!",
+ devio->dev_id, dev_name(camsys_dev->miscdev.this_device));
+ goto end;
+ }
+
+ extdev = kzalloc(sizeof(camsys_extdev_t),GFP_KERNEL);
+ if (extdev == NULL) {
+ camsys_err("alloc camsys_extdev_t failed!");
+ err = -ENOMEM;
+ goto end;
+ }
+
+ regulator_info = &devio->avdd;
+ regulator = &extdev->avdd;
+ for (i=0; i<4; i++) {
+ if (strcmp(regulator_info->name,"NC")) {
+ regulator->ldo = regulator_get(NULL,regulator_info->name);
+ if (IS_ERR(regulator->ldo)) {
+ camsys_err("Get %s regulator for dev_id 0x%x failed!",regulator_info->name,devio->dev_id);
+ err = -EINVAL;
+ goto fail;
+ }
+
+ regulator->min_uv = regulator_info->min_uv;
+ regulator->max_uv = regulator_info->max_uv;
+ camsys_trace(1,"Get %s regulator(min: %duv max: %duv) for dev_id 0x%x success",
+ regulator_info->name,regulator->min_uv,regulator->max_uv,
+ devio->dev_id);
+ } else {
+ regulator->ldo = NULL;
+ regulator->min_uv = 0;
+ regulator->max_uv = 0;
+ }
+
+ regulator++;
+ regulator_info++;
+ }
+
+ gpio_info = &devio->pwrdn;
+ gpio = &extdev->pwrdn;
+ for (i=0; i<4; i++) {
+ if (strcmp(gpio_info->name,"NC")) {
+ gpio->io = camsys_gpio_get(gpio_info->name);
+ if (gpio->io < 0) {
+ camsys_err("Get %s gpio for dev_id 0x%x failed!",gpio_info->name,devio->dev_id);
+ err = -EINVAL;
+ goto fail;
+ }
+ if (gpio_request(gpio->io,"camsys_gpio")<0) {
+ camsys_err("Request %s(%d) failed",gpio_info->name,gpio->io);
+ }
+ gpio->active = gpio_info->active;
+ camsys_trace(1,"Get %s(%d) gpio(active: %d) for dev_id 0x%x success!",
+ gpio_info->name,gpio->io,gpio->active,devio->dev_id);
+ } else {
+ gpio->io = 0xffffffff;
+ gpio->active = 0xffffffff;
+ }
+
+ gpio++;
+ gpio_info++;
+ }
+
+ extdev->pdev = camsys_dev->pdev;
+ extdev->phy = devio->phy;
+ extdev->clk = devio->clk;
+ extdev->dev_id = devio->dev_id;
+ //spin_lock(&camsys_dev->lock);
+ mutex_lock(&camsys_dev->extdevs.mut);
+ list_add_tail(&extdev->list, &camsys_dev->extdevs.list);
+ //spin_unlock(&camsys_dev->lock);
+ mutex_unlock(&camsys_dev->extdevs.mut);
+
+ camsys_dev->iomux(extdev, (void*)camsys_dev);
+
+ camsys_trace(1,"Extdev(dev_id: 0x%x) register success",extdev->dev_id);
+
+ return 0;
+fail:
+ if (extdev) {
+ kfree(extdev);
+ extdev = NULL;
+ }
+end:
+
+ return err;
+}
+
+static int camsys_extdev_deregister(unsigned int dev_id, camsys_dev_t *camsys_dev, bool all)
+{
+ int err = 0,i;
+ camsys_extdev_t *extdev;
+ camsys_regulator_t *regulator;
+ camsys_gpio_t *gpio;
+
+ if (all == false) {
+ if ((dev_id & CAMSYS_DEVID_EXTERNAL) == 0) {
+ err = -EINVAL;
+ camsys_err("dev_id: 0x%x is not support for %s!",dev_id, dev_name(camsys_dev->miscdev.this_device));
+ goto end;
+ }
+
+ extdev = camsys_find_extdev(dev_id, camsys_dev);
+ if (extdev != NULL) {
+ err = -EINVAL;
+ camsys_warn("Extdev(dev_id: 0x%x) isn't registered in %s!",
+ dev_id, dev_name(camsys_dev->miscdev.this_device));
+ goto end;
+ }
+
+ regulator = &extdev->avdd;
+ for (i=0; i<4; i++) {
+ if (!IS_ERR_OR_NULL(regulator->ldo)) {
+ while(regulator_is_enabled(regulator->ldo)>0)
+ regulator_disable(regulator->ldo);
+ regulator_put(regulator->ldo);
+ }
+ regulator++;
+ }
+
+ gpio = &extdev->pwrdn;
+ for (i=0; i<4; i++) {
+ if (gpio->io!=0xffffffff) {
+ gpio_free(gpio->io);
+ }
+ gpio++;
+ }
+
+ //spin_lock(&camsys_dev->lock);
+ mutex_lock(&camsys_dev->extdevs.mut);
+ list_del_init(&extdev->list);
+ list_del_init(&extdev->active);
+ //spin_unlock(&camsys_dev->lock);
+ mutex_unlock(&camsys_dev->extdevs.mut);
+ kfree(extdev);
+ extdev = NULL;
+ camsys_trace(1,"Extdev(dev_id: 0x%x) is deregister success", extdev->dev_id);
+ } else {
+ //spin_lock(&camsys_dev->lock);
+ mutex_lock(&camsys_dev->extdevs.mut);
+ while (!list_empty(&camsys_dev->extdevs.list)) {
+
+ extdev = list_first_entry(&camsys_dev->extdevs.list, camsys_extdev_t, list);
+ if (extdev) {
+ regulator = &extdev->avdd;
+ for (i=0; i<4; i++) {
+ if (!IS_ERR(regulator->ldo)) {
+ while(regulator_is_enabled(regulator->ldo)>0)
+ regulator_disable(regulator->ldo);
+ regulator_put(regulator->ldo);
+ }
+ regulator++;
+ }
+
+ gpio = &extdev->pwrdn;
+ for (i=0; i<4; i++) {
+ if (gpio->io!=0xffffffff) {
+ gpio_free(gpio->io);
+ }
+ gpio++;
+ }
+ camsys_trace(1,"Extdev(dev_id: 0x%x) is deregister success", extdev->dev_id);
+ list_del_init(&extdev->list);
+ list_del_init(&extdev->active);
+ kfree(extdev);
+ extdev=NULL;
+ }
+ }
+ //spin_unlock(&camsys_dev->lock);
+ mutex_unlock(&camsys_dev->extdevs.mut);
+ camsys_trace(1, "All extdev is deregister success!");
+ }
+
+
+end:
+ return err;
+
+}
+
+static int camsys_sysctl(camsys_sysctrl_t *devctl, camsys_dev_t *camsys_dev)
+{
+ int i;
+ int err = 0;
+ camsys_extdev_t *extdev,*extdev2;
+
+ //spin_lock(&camsys_dev->lock);
+ mutex_lock(&camsys_dev->extdevs.mut);
+ if(devctl->ops == 0xaa){
+ dump_stack();
+ return 0;
+ }
+ //Internal
+ if (camsys_dev->dev_id & devctl->dev_mask) {
+ switch (devctl->ops)
+ {
+ case CamSys_ClkIn:
+ {
+ camsys_dev->clkin_cb(camsys_dev,devctl->on);
+ break;
+ }
+
+ case CamSys_Rst:
+ {
+ camsys_dev->reset_cb(camsys_dev);
+ break;
+ }
+ default:
+ break;
+
+ }
+ }
+
+ //External
+ for (i=0; i<8; i++) {
+ if (devctl->dev_mask & (1<<(i+24))) {
+ extdev = camsys_find_extdev((1<<(i+24)), camsys_dev);
+ if (extdev) {
+ camsys_sysctl_extdev(extdev, devctl, camsys_dev);
+
+ if (devctl->ops == CamSys_ClkIn) {
+ if (devctl->on) {
+ list_add_tail(&extdev->active,&camsys_dev->extdevs.active);
+ } else {
+ if (!list_empty(&camsys_dev->extdevs.active)) { /* ddla@rock-chips.com: v0.0.7 */
+ list_for_each_entry(extdev2, &camsys_dev->extdevs.active, active) {
+ if (extdev2 == extdev) {
+ list_del_init(&extdev->active);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ } else {
+ camsys_err("Can not find dev_id 0x%x device in %s!", (1<<(i+24)), dev_name(camsys_dev->miscdev.this_device));
+ }
+ }
+ }
+
+ //spin_unlock(&camsys_dev->lock);
+ mutex_unlock(&camsys_dev->extdevs.mut);
+ return err;
+}
+static int camsys_phy_ops (camsys_extdev_phy_t *phy, void* ptr, unsigned int on)
+{
+ camsys_dev_t *camsys_dev = (camsys_dev_t*)ptr;
+ int err = 0;
+
+ if (phy->type == CamSys_Phy_Mipi) {
+ if (camsys_dev->mipiphy.ops && camsys_dev->mipiphy.clkin_cb) {
+ err = camsys_dev->mipiphy.clkin_cb(camsys_dev,on);
+ err = camsys_dev->mipiphy.ops(&phy->info.mipi,&camsys_dev->mipiphy, on);
+ } else {
+ camsys_err("%s isn't support mipi phy",dev_name(camsys_dev->miscdev.this_device));
+ err = -EINVAL;
+ }
+ } else if (phy->type == CamSys_Phy_Cif) {
+ if (camsys_dev->cifphy.ops && camsys_dev->cifphy.clkin_cb) {
+ err = camsys_dev->cifphy.clkin_cb(camsys_dev,on);
+ err = camsys_dev->cifphy.ops(&phy->info.cif,&camsys_dev->cifphy, on);
+ } else {
+ //camsys_err("%s isn't support cif phy",dev_name(camsys_dev->miscdev.this_device));
+ //err = -EINVAL;
+ }
+ }
+
+ return err;
+}
+static int camsys_irq_connect(camsys_irqcnnt_t *irqcnnt, camsys_dev_t *camsys_dev)
+{
+ int err = 0,i;
+ camsys_irqpool_t *irqpool;
+ unsigned long int flags;
+
+ if ((irqcnnt->mis != MRV_ISP_MIS) &&
+ (irqcnnt->mis != MRV_MIPI_MIS) &&
+ (irqcnnt->mis != MRV_MI_MIS)) {
+
+ camsys_err("this thread(pid: %d) irqcnnt->mis(0x%x) is invalidate, irq connect failed!",
+ irqcnnt->pid, irqcnnt->mis);
+
+ err = -EINVAL;
+ goto end;
+ }
+
+ spin_lock_irqsave(&camsys_dev->irq.lock,flags);
+ if (!list_empty(&camsys_dev->irq.irq_pool)) {
+ list_for_each_entry(irqpool, &camsys_dev->irq.irq_pool, list) {
+ if (irqpool->pid == irqcnnt->pid) {
+ camsys_warn("this thread(pid: %d) had been connect irq!",current->pid);
+ spin_unlock(&camsys_dev->irq.lock);
+ goto end;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&camsys_dev->irq.lock,flags);
+
+ irqpool = kzalloc(sizeof(camsys_irqpool_t),GFP_KERNEL);
+ if (irqpool) {
+ spin_lock_init(&irqpool->lock);
+ irqpool->pid = irqcnnt->pid;
+ irqpool->timeout = irqcnnt->timeout;
+ irqpool->mis = irqcnnt->mis;
+ irqpool->icr = irqcnnt->icr;
+ INIT_LIST_HEAD(&irqpool->active);
+ INIT_LIST_HEAD(&irqpool->deactive);
+ init_waitqueue_head(&irqpool->done);
+ for (i=0; i<CAMSYS_IRQPOOL_NUM; i++) {
+ list_add_tail(&irqpool->pool[i].list, &irqpool->deactive);
+ }
+ }
+
+ spin_lock_irqsave(&camsys_dev->irq.lock,flags);
+ //camsys_dev->irq.timeout = irqcnnt->timeout;
+ list_add_tail(&irqpool->list, &camsys_dev->irq.irq_pool);
+ spin_unlock_irqrestore(&camsys_dev->irq.lock,flags);
+ camsys_trace(1, "Thread(pid: %d) connect %s irq success! mis: 0x%x icr: 0x%x ", irqpool->pid, dev_name(camsys_dev->miscdev.this_device),
+ irqpool->mis,irqpool->icr);
+
+end:
+ return err;
+}
+static int active_list_isnot_empty(camsys_irqpool_t *irqpool)
+{
+ int err;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&irqpool->lock,flags);
+ err = list_empty(&irqpool->active);
+ spin_unlock_irqrestore(&irqpool->lock,flags);
+
+ return !err;
+
+}
+static int camsys_irq_wait(camsys_irqsta_t *irqsta, camsys_dev_t *camsys_dev)
+{
+ int err = 0;
+ bool find_pool = false;
+ camsys_irqstas_t *irqstas;
+ camsys_irqpool_t *irqpool;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&camsys_dev->irq.lock,flags);
+ if (!list_empty(&camsys_dev->irq.irq_pool)) {
+ list_for_each_entry(irqpool, &camsys_dev->irq.irq_pool, list) {
+ if (irqpool->pid == current->pid) {
+ find_pool = true;
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&camsys_dev->irq.lock,flags);
+
+ if (find_pool == false) {
+ camsys_err("this thread(pid: %d) hasn't been connect irq, so wait irq failed!",current->pid);
+ err = -EINVAL;
+ goto end;
+ }
+
+
+ spin_lock_irqsave(&irqpool->lock,flags);
+ if (!list_empty(&irqpool->active)) {
+ irqstas = list_first_entry(&irqpool->active, camsys_irqstas_t, list);
+ *irqsta = irqstas->sta;
+ list_del_init(&irqstas->list);
+ list_add_tail(&irqstas->list,&irqpool->deactive);
+ spin_unlock_irqrestore(&irqpool->lock,flags);
+ } else {
+ spin_unlock_irqrestore(&irqpool->lock,flags);
+
+ wait_event_interruptible_timeout(irqpool->done,
+ active_list_isnot_empty(irqpool),
+ usecs_to_jiffies(irqpool->timeout));
+
+ if (irqpool->pid == current->pid) {
+ if (active_list_isnot_empty(irqpool)) {
+ spin_lock_irqsave(&irqpool->lock,flags);
+ irqstas = list_first_entry(&irqpool->active, camsys_irqstas_t, list);
+ *irqsta = irqstas->sta;
+ list_del_init(&irqstas->list);
+ list_add_tail(&irqstas->list,&irqpool->deactive);
+ spin_unlock_irqrestore(&irqpool->lock,flags);
+ } else {
+ camsys_warn("Thread(pid: %d) wait irq timeout!!",current->pid);
+ err = -EAGAIN;
+ }
+ } else {
+ camsys_warn("Thread(pid: %d) has been disconnect!",current->pid);
+ err = -EAGAIN;
+ }
+ }
+
+ if (err == 0) {
+ camsys_trace(3,"Thread(pid: %d) has been wake up for irq(mis: 0x%x ris:0x%x)!",
+ current->pid, irqsta->mis, irqsta->ris);
+ }
+
+end:
+ return err;
+}
+
+static int camsys_irq_disconnect(camsys_irqcnnt_t *irqcnnt, camsys_dev_t *camsys_dev, bool all)
+{
+ int err = 0;
+ bool find_pool = false;
+ camsys_irqpool_t *irqpool;
+ unsigned long int flags;
+
+ if (all == false) {
+ spin_lock_irqsave(&camsys_dev->irq.lock,flags);
+ printk("%s++++++++++++++++\n",__func__);
+ if (!list_empty(&camsys_dev->irq.irq_pool)) {
+ list_for_each_entry(irqpool, &camsys_dev->irq.irq_pool, list) {
+ if (irqpool->pid == irqcnnt->pid) {
+ find_pool = true;
+ irqpool->pid = 0;
+ break;
+ }
+ }
+ }
+ printk("%s -------------\n",__func__);
+ spin_unlock_irqrestore(&camsys_dev->irq.lock,flags);
+
+ if (find_pool == false) {
+ camsys_err("this thread(pid: %d) have not been connect irq!, disconnect failed",current->pid);
+ } else {
+ wake_up_all(&irqpool->done);
+ }
+
+ camsys_trace(1, "Thread(pid: %d) disconnect %s irq success!", irqcnnt->pid, dev_name(camsys_dev->miscdev.this_device));
+ } else {
+ spin_lock_irqsave(&camsys_dev->irq.lock,flags);
+ while (!list_empty(&camsys_dev->irq.irq_pool)) {
+ irqpool = list_first_entry(&camsys_dev->irq.irq_pool, camsys_irqpool_t, list);
+ list_del_init(&irqpool->list);
+ irqpool->pid = 0;
+ wake_up_all(&irqpool->done);
+ kfree(irqpool);
+ irqpool = NULL;
+ }
+ spin_unlock_irqrestore(&camsys_dev->irq.lock,flags);
+
+ camsys_trace(1, "All thread disconnect %s irq success!", dev_name(camsys_dev->miscdev.this_device));
+ }
+
+
+ return err;
+}
+
+static int camsys_querymem (camsys_dev_t *camsys_dev, camsys_querymem_t *qmem)
+{
+ int err = 0;
+
+ if (qmem->mem_type == CamSys_Mmap_RegisterMem) {
+ if (camsys_dev->devmems.registermem == NULL) {
+ camsys_err("%s register memory isn't been register!", dev_name(camsys_dev->miscdev.this_device));
+ err = -EINVAL;
+ goto end;
+ }
+
+ qmem->mem_size = camsys_dev->devmems.registermem->size;
+ qmem->mem_offset = CamSys_Mmap_RegisterMem*PAGE_SIZE;
+ } else if (qmem->mem_type == CamSys_Mmap_I2cMem) {
+ if (camsys_dev->devmems.i2cmem== NULL) {
+ camsys_err("%s i2c memory isn't been register!", dev_name(camsys_dev->miscdev.this_device));
+ err = -EINVAL;
+ goto end;
+ }
+
+ qmem->mem_size = camsys_dev->devmems.i2cmem->size;
+ qmem->mem_offset = CamSys_Mmap_I2cMem*PAGE_SIZE;
+ } else {
+ camsys_err("%d memory type have not in %s memory list",qmem->mem_type,dev_name(camsys_dev->miscdev.this_device));
+ err = -EINVAL;
+ goto end;
+ }
+
+
+ return 0;
+end:
+ return err;
+}
+static int camsys_open(struct inode *inode, struct file *file)
+{
+ int err = 0;
+ int minor = iminor(inode);
+ camsys_dev_t *camsys_dev;
+
+ spin_lock(&camsys_devs.lock);
+ list_for_each_entry(camsys_dev, &camsys_devs.devs, list) {
+ if (camsys_dev->miscdev.minor == minor) {
+ file->private_data = (void*)(camsys_dev);
+ break;
+ }
+ }
+ spin_unlock(&camsys_devs.lock);
+
+ if (file->private_data == NULL) {
+ camsys_err("Cann't find camsys_dev!");
+ err = -ENODEV;
+ goto end;
+ } else {
+ camsys_trace(1,"%s(%p) is opened!",dev_name(camsys_dev->miscdev.this_device),camsys_dev);
+ }
+
+end:
+ return err;
+}
+
+static int camsys_release(struct inode *inode, struct file *file)
+{
+ camsys_dev_t *camsys_dev = (camsys_dev_t*)file->private_data;
+
+ camsys_irq_disconnect(NULL,camsys_dev, true);
+
+ camsys_trace(1,"%s(%p) is closed",dev_name(camsys_dev->miscdev.this_device),camsys_dev);
+
+ return 0;
+}
+
+/*
+* The ioctl() implementation
+*/
+
+static long camsys_ioctl(struct file *filp,unsigned int cmd, unsigned long arg)
+{
+ long err = 0;
+ camsys_dev_t *camsys_dev = (camsys_dev_t*)filp->private_data;
+
+ if (_IOC_TYPE(cmd) != CAMSYS_IOC_MAGIC) {
+ camsys_err("ioctl type(%c!=%c) is invalidate\n",_IOC_TYPE(cmd),CAMSYS_IOC_MAGIC);
+ err = -ENOTTY;
+ goto end;
+ }
+ if (_IOC_NR(cmd) > CAMSYS_IOC_MAXNR) {
+ camsys_err("ioctl index(%d>%d) is invalidate\n",_IOC_NR(cmd),CAMSYS_IOC_MAXNR);
+ err = -ENOTTY;
+ goto end;
+ }
+
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
+
+ if (err) {
+ camsys_err("ioctl(0x%x) operation not permitted for %s",cmd,dev_name(camsys_dev->miscdev.this_device));
+ err = -EFAULT;
+ goto end;
+ }
+
+ switch (cmd) {
+
+ case CAMSYS_VERCHK:
+ {
+ camsys_version_t camsys_ver;
+
+ camsys_ver.drv_ver = CAMSYS_DRIVER_VERSION;
+ camsys_ver.head_ver = CAMSYS_HEAD_VERSION;
+ if (copy_to_user((void __user *)arg,(void*)&camsys_ver, sizeof(camsys_version_t)))
+ return -EFAULT;
+ break;
+ }
+
+ case CAMSYS_I2CRD:
+ {
+ camsys_i2c_info_t i2cinfo;
+
+ if (copy_from_user((void*)&i2cinfo,(void __user *)arg, sizeof(camsys_i2c_info_t)))
+ return -EFAULT;
+
+ err = camsys_i2c_read(&i2cinfo,camsys_dev);
+ if (err==0) {
+ if (copy_to_user((void __user *)arg,(void*)&i2cinfo, sizeof(camsys_i2c_info_t)))
+ return -EFAULT;
+ }
+ break;
+ }
+
+ case CAMSYS_I2CWR:
+ {
+ camsys_i2c_info_t i2cinfo;
+
+ if (copy_from_user((void*)&i2cinfo,(void __user *)arg, sizeof(camsys_i2c_info_t)))
+ return -EFAULT;
+
+ err = camsys_i2c_write(&i2cinfo,camsys_dev);
+ break;
+ }
+
+ case CAMSYS_SYSCTRL:
+ {
+ camsys_sysctrl_t devctl;
+
+ if (copy_from_user((void*)&devctl,(void __user *)arg, sizeof(camsys_sysctrl_t)))
+ return -EFAULT;
+
+ err = camsys_sysctl(&devctl, camsys_dev);
+ break;
+ }
+
+ case CAMSYS_REGRD:
+ {
+
+ break;
+ }
+
+ case CAMSYS_REGWR:
+ {
+
+ break;
+ }
+
+ case CAMSYS_REGISTER_DEVIO:
+ {
+ camsys_devio_name_t devio;
+
+ if (copy_from_user((void*)&devio,(void __user *)arg, sizeof(camsys_devio_name_t)))
+ return -EFAULT;
+
+ err = camsys_extdev_register(&devio,camsys_dev);
+ break;
+ }
+
+ case CAMSYS_DEREGISTER_DEVIO:
+ {
+ unsigned int dev_id;
+
+ if (copy_from_user((void*)&dev_id,(void __user *)arg, sizeof(unsigned int)))
+ return -EFAULT;
+
+ err = camsys_extdev_deregister(dev_id, camsys_dev, false);
+ break;
+ }
+
+ case CAMSYS_IRQCONNECT:
+ {
+ camsys_irqcnnt_t irqcnnt;
+
+ if (copy_from_user((void*)&irqcnnt,(void __user *)arg, sizeof(camsys_irqcnnt_t)))
+ return -EFAULT;
+
+ err = camsys_irq_connect(&irqcnnt, camsys_dev);
+
+ break;
+ }
+
+ case CAMSYS_IRQWAIT:
+ {
+ camsys_irqsta_t irqsta;
+
+ err = camsys_irq_wait(&irqsta, camsys_dev);
+ if (err==0) {
+ if (copy_to_user((void __user *)arg,(void*)&irqsta, sizeof(camsys_irqsta_t)))
+ return -EFAULT;
+ }
+ break;
+ }
+
+ case CAMSYS_IRQDISCONNECT:
+ {
+ camsys_irqcnnt_t irqcnnt;
+
+ if (copy_from_user((void*)&irqcnnt,(void __user *)arg, sizeof(camsys_irqcnnt_t)))
+ return -EFAULT;
+ printk("disconnect ++++++++++++++++\n");
+ err = camsys_irq_disconnect(&irqcnnt,camsys_dev,false);
+ printk("disconnect ----------------\n");
+ break;
+ }
+
+
+ case CAMSYS_QUREYMEM:
+ {
+ camsys_querymem_t qmem;
+
+ if (copy_from_user((void*)&qmem,(void __user *)arg, sizeof(camsys_querymem_t)))
+ return -EFAULT;
+
+ err = camsys_querymem(camsys_dev,&qmem);
+ if (err == 0) {
+ if (copy_to_user((void __user *)arg,(void*)&qmem, sizeof(camsys_querymem_t)))
+ return -EFAULT;
+ }
+ break;
+ }
+
+ default :
+ break;
+ }
+
+end:
+ return err;
+
+}
+/*
+ * VMA operations.
+ */
+static void camsys_vm_open(struct vm_area_struct *vma)
+{
+ camsys_meminfo_t *meminfo = (camsys_meminfo_t*)vma->vm_private_data;
+
+ meminfo->vmas++;
+ return;
+}
+
+static void camsys_vm_close(struct vm_area_struct *vma)
+{
+ camsys_meminfo_t *meminfo = (camsys_meminfo_t*)vma->vm_private_data;
+
+ meminfo->vmas--;
+ return;
+}
+
+static const struct vm_operations_struct camsys_vm_ops = {
+ .open = camsys_vm_open,
+ .close = camsys_vm_close,
+};
+
+int camsys_mmap(struct file *flip, struct vm_area_struct *vma)
+{
+ camsys_dev_t *camsys_dev = (camsys_dev_t*)flip->private_data;
+ unsigned long addr, start, size;
+ camsys_mmap_type_t mem_type;
+ camsys_meminfo_t *meminfo;
+ int ret = 0;
+
+ mem_type = vma->vm_pgoff;
+
+ if (mem_type == CamSys_Mmap_RegisterMem) {
+ if (camsys_dev->devmems.registermem != NULL) {
+ meminfo = camsys_dev->devmems.registermem;
+ } else {
+ camsys_err("this camsys device has not register mem!");
+ ret = -EINVAL;
+ goto done;
+ }
+ } else if (mem_type == CamSys_Mmap_I2cMem) {
+ if (camsys_dev->devmems.i2cmem != NULL) {
+ meminfo = camsys_dev->devmems.i2cmem;
+ } else {
+ camsys_err("this camsys device has not i2c mem!");
+ ret = -EINVAL;
+ goto done;
+ }
+ } else {
+ camsys_err("mmap buffer type %d is invalidate!",mem_type);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ size = vma->vm_end - vma->vm_start;
+ if (size > meminfo->size) {
+ ret = -ENOMEM;
+ camsys_err("mmap size(0x%lx) > memory size(0x%x), so failed!",size,meminfo->size);
+ goto done;
+ }
+
+ start = vma->vm_start;
+ addr = __phys_to_pfn(meminfo->phy_base);
+
+ if (remap_pfn_range(vma, start, addr,size,pgprot_noncached(vma->vm_page_prot))) {
+
+ ret = -EAGAIN;
+ goto done;
+ }
+
+ vma->vm_ops = &camsys_vm_ops;
+ vma->vm_flags |= VM_IO;
+ vma->vm_flags |=VM_ACCOUNT;//same as VM_RESERVED;
+ vma->vm_private_data = (void*)meminfo;
+ camsys_vm_open(vma);
+
+done:
+ return ret;
+}
+
+struct file_operations camsys_fops = {
+ .owner = THIS_MODULE,
+ .open = camsys_open,
+ .release = camsys_release,
+ .unlocked_ioctl = camsys_ioctl,
+ .mmap = camsys_mmap,
+};
+
+static int camsys_platform_probe_new(struct platform_device *pdev){
+ int err = 0;
+ camsys_dev_t *camsys_dev;
+ struct resource register_res ;
+ struct device *dev = &pdev->dev;
+ unsigned long i2cmem;
+ camsys_meminfo_t *meminfo;
+ unsigned int irq_id;
+
+ err = of_address_to_resource(dev->of_node, 0, ®ister_res);
+ if (err < 0){
+ camsys_err("Get register resource from %s platform device failed!",pdev->name);
+ err = -ENODEV;
+ goto fail_end;
+ }
+
+
+ //map irqs
+ irq_id = irq_of_parse_and_map(dev->of_node, 0);
+ if (irq_id < 0) {
+ camsys_err("Get irq resource from %s platform device failed!",pdev->name);
+ err = -ENODEV;
+ goto fail_end;
+ }
+
+ camsys_dev = (camsys_dev_t*)devm_kzalloc(&pdev->dev,sizeof(camsys_dev_t), GFP_KERNEL);
+ if (camsys_dev == NULL) {
+ camsys_err("Allocate camsys_dev for %s platform device failed",pdev->name);
+ err = -ENOMEM;
+ goto fail_end;
+ }
+
+ //spin_lock_init(&camsys_dev->lock);
+ mutex_init(&camsys_dev->extdevs.mut);
+ INIT_LIST_HEAD(&camsys_dev->extdevs.list);
+ INIT_LIST_HEAD(&camsys_dev->extdevs.active);
+ INIT_LIST_HEAD(&camsys_dev->list);
+
+
+ //IRQ init
+ camsys_dev->irq.irq_id = irq_id;
+ spin_lock_init(&camsys_dev->irq.lock);
+ INIT_LIST_HEAD(&camsys_dev->irq.irq_pool);
+ //init_waitqueue_head(&camsys_dev->irq.irq_done);
+
+ INIT_LIST_HEAD(&camsys_dev->devmems.memslist);
+
+
+ //Register mem init
+ meminfo = kzalloc(sizeof(camsys_meminfo_t),GFP_KERNEL);
+ if (meminfo == NULL) {
+ err = -ENOMEM;
+ goto request_mem_fail;
+ }
+
+ meminfo->vir_base = (unsigned int)devm_ioremap_resource(dev, ®ister_res);
+ if (!meminfo->vir_base){
+ camsys_err("%s ioremap %s failed",dev_name(&pdev->dev), CAMSYS_REGISTER_MEM_NAME);
+ err = -ENXIO;
+ goto request_mem_fail;
+ }
+
+ strlcpy(meminfo->name, CAMSYS_REGISTER_MEM_NAME,sizeof(meminfo->name));
+ meminfo->phy_base = register_res.start;
+ meminfo->size = register_res.end - register_res.start + 1;
+ list_add_tail(&meminfo->list, &camsys_dev->devmems.memslist);
+
+
+ //I2c mem init
+ i2cmem = __get_free_page(GFP_KERNEL);
+ if (i2cmem == 0) {
+ camsys_err("Allocate i2cmem failed!");
+ err = -ENOMEM;
+ goto request_mem_fail;
+ }
+ SetPageReserved(virt_to_page(i2cmem));
+
+ meminfo = kzalloc(sizeof(camsys_meminfo_t),GFP_KERNEL);
+ if (meminfo == NULL) {
+ err = -ENOMEM;
+ goto request_mem_fail;
+ }
+ strlcpy(meminfo->name,CAMSYS_I2C_MEM_NAME,sizeof(meminfo->name));
+ meminfo->vir_base = i2cmem;
+ meminfo->phy_base = virt_to_phys((void*)i2cmem);
+ meminfo->size = PAGE_SIZE;
+ list_add_tail(&meminfo->list, &camsys_dev->devmems.memslist);
+
+ {
+ unsigned int *tmpp;
+
+ tmpp = (unsigned int*)meminfo->vir_base;
+ *tmpp = 0xfa561243;
+ }
+
+ //Special init
+
+ {
+ if (camsys_mipiphy_probe_cb(pdev, camsys_dev) <0) {
+ camsys_err("Mipi phy probe failed!");
+ }
+ }
+
+ if (strcmp(dev_name(&pdev->dev),CAMSYS_PLATFORM_MARVIN_NAME) == 0) {
+ #if (defined(CONFIG_CAMSYS_MRV))
+ camsys_mrv_probe_cb(pdev, camsys_dev);
+ #else
+ camsys_err("Marvin controller camsys driver haven't been complie!!!");
+ #endif
+ } else {
+ #if (defined(CONFIG_CAMSYS_CIF))
+ camsys_cif_probe_cb(pdev,camsys_dev);
+ #else
+ camsys_err("CIF controller camsys driver haven't been complie!!!");
+ #endif
+ }
+
+ camsys_trace(1, "%s memory:",dev_name(&pdev->dev));
+ list_for_each_entry(meminfo, &camsys_dev->devmems.memslist, list) {
+ if (strcmp(meminfo->name,CAMSYS_I2C_MEM_NAME) == 0) {
+ camsys_dev->devmems.i2cmem = meminfo;
+ camsys_trace(1," I2c memory (phy: 0x%x vir: 0x%x size: 0x%x)",
+ meminfo->phy_base,meminfo->vir_base,meminfo->size);
+ }
+ if (strcmp(meminfo->name,CAMSYS_REGISTER_MEM_NAME) == 0) {
+ camsys_dev->devmems.registermem = meminfo;
+ camsys_trace(1," Register memory (phy: 0x%x vir: 0x%x size: 0x%x)",
+ meminfo->phy_base,meminfo->vir_base,meminfo->size);
+ }
+ }
+
+ camsys_dev->phy_cb = camsys_phy_ops;
+ platform_set_drvdata(pdev,(void*)camsys_dev);
+ //Camsys_devs list add
+ spin_lock(&camsys_devs.lock);
+ list_add_tail(&camsys_dev->list, &camsys_devs.devs);
+ spin_unlock(&camsys_devs.lock);
+
+
+ camsys_trace(1, "Probe %s device success ", dev_name(&pdev->dev));
+ return 0;
+request_mem_fail:
+ if (camsys_dev != NULL) {
+
+ while(!list_empty(&camsys_dev->devmems.memslist)) {
+ meminfo = list_first_entry(&camsys_dev->devmems.memslist, camsys_meminfo_t, list);
+ if (meminfo) {
+ list_del_init(&meminfo->list);
+ if (strcmp(meminfo->name,CAMSYS_REGISTER_MEM_NAME)==0) {
+ iounmap((void __iomem *)meminfo->vir_base);
+ release_mem_region(meminfo->phy_base,meminfo->size);
+ } else if (strcmp(meminfo->name,CAMSYS_I2C_MEM_NAME)==0) {
+ kfree((void*)meminfo->vir_base);
+ }
+ kfree(meminfo);
+ meminfo = NULL;
+ }
+ }
+
+ kfree(camsys_dev);
+ camsys_dev = NULL;
+ }
+fail_end:
+ return -1;
+
+
+}
+#if 0
+static int camsys_platform_probe(struct platform_device *pdev)
+{
+ int err = 0;
+ unsigned int irq_id;
+ camsys_dev_t *camsys_dev;
+ unsigned long i2cmem;
+ camsys_meminfo_t *meminfo;
+ struct resource *register_res, *mipiphy_register_res;
+
+ camsys_trace(1, "Probe %s device now", dev_name(&pdev->dev));
+ register_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, CAMSYS_REGISTER_RES_NAME);
+ if (register_res == NULL) {
+ camsys_err("Get register resource from %s platform device failed!",pdev->name);
+ err = -ENODEV;
+ goto fail_end;
+ }
+
+ mipiphy_register_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, CAMSYS_REGISTER_MIPIPHY_RES_NAME);
+
+ irq_id = platform_get_irq_byname(pdev, CAMSYS_IRQ_RES_NAME);
+ if (irq_id < 0) {
+ camsys_err("Get irq resource from %s platform device failed!",pdev->name);
+ err = -ENODEV;
+ goto fail_end;
+ }
+
+ camsys_dev = (camsys_dev_t*)kzalloc(sizeof(camsys_dev_t), GFP_KERNEL);
+ if (camsys_dev == NULL) {
+ camsys_err("Allocate camsys_dev for %s platform device failed",pdev->name);
+ err = -ENOMEM;
+ goto fail_end;
+ }
+
+ //spin_lock_init(&camsys_dev->lock);
+ mutex_init(&camsys_dev->extdevs.mut);
+ INIT_LIST_HEAD(&camsys_dev->extdevs.list);
+ INIT_LIST_HEAD(&camsys_dev->extdevs.active);
+ INIT_LIST_HEAD(&camsys_dev->list);
+
+
+ //IRQ init
+ camsys_dev->irq.irq_id = irq_id;
+ spin_lock_init(&camsys_dev->irq.lock);
+ INIT_LIST_HEAD(&camsys_dev->irq.irq_pool);
+ //init_waitqueue_head(&camsys_dev->irq.irq_done);
+
+ INIT_LIST_HEAD(&camsys_dev->devmems.memslist);
+ if (!request_mem_region(register_res->start, register_res->end - register_res->start + 1,
+ dev_name(&pdev->dev))) {
+ err = -ENOMEM;
+ goto request_mem_fail;
+ }
+
+ //Register mem init
+ meminfo = kzalloc(sizeof(camsys_meminfo_t),GFP_KERNEL);
+ if (meminfo == NULL) {
+ err = -ENOMEM;
+ goto request_mem_fail;
+ }
+
+ meminfo->vir_base = (unsigned int)ioremap(register_res->start, register_res->end - register_res->start + 1);
+ if (meminfo->vir_base == 0) {
+ camsys_err("%s ioremap %s failed",dev_name(&pdev->dev), CAMSYS_REGISTER_MEM_NAME);
+ err = -ENXIO;
+ goto request_mem_fail;
+ }
+
+ strlcpy(meminfo->name, CAMSYS_REGISTER_MEM_NAME,sizeof(meminfo->name));
+ meminfo->phy_base = register_res->start;
+ meminfo->size = register_res->end - register_res->start + 1;
+ list_add_tail(&meminfo->list, &camsys_dev->devmems.memslist);
+
+ //I2c mem init
+ i2cmem = __get_free_page(GFP_KERNEL);
+ if (i2cmem == 0) {
+ camsys_err("Allocate i2cmem failed!");
+ err = -ENOMEM;
+ goto request_mem_fail;
+ }
+ SetPageReserved(virt_to_page(i2cmem));
+
+ meminfo = kzalloc(sizeof(camsys_meminfo_t),GFP_KERNEL);
+ if (meminfo == NULL) {
+ err = -ENOMEM;
+ goto request_mem_fail;
+ }
+ strlcpy(meminfo->name,CAMSYS_I2C_MEM_NAME,sizeof(meminfo->name));
+ meminfo->vir_base = i2cmem;
+ meminfo->phy_base = virt_to_phys((void*)i2cmem);
+ meminfo->size = PAGE_SIZE;
+ list_add_tail(&meminfo->list, &camsys_dev->devmems.memslist);
+
+ {
+ unsigned int *tmpp;
+
+ tmpp = (unsigned int*)meminfo->vir_base;
+ *tmpp = 0xfa561243;
+ }
+
+ //Special init
+
+ if (mipiphy_register_res) {
+ if (camsys_mipiphy_probe_cb(pdev, camsys_dev) <0) {
+ camsys_err("Mipi phy probe failed!");
+ }
+ }
+
+ if (strcmp(dev_name(&pdev->dev),CAMSYS_PLATFORM_MARVIN_NAME) == 0) {
+ #if (defined(CONFIG_CAMSYS_MRV))
+ camsys_mrv_probe_cb(pdev, camsys_dev);
+ #else
+ camsys_err("Marvin controller camsys driver haven't been complie!!!");
+ #endif
+ } else {
+ #if (defined(CONFIG_CAMSYS_CIF))
+ camsys_cif_probe_cb(pdev,camsys_dev);
+ #else
+ camsys_err("CIF controller camsys driver haven't been complie!!!");
+ #endif
+ }
+
+ camsys_trace(1, "%s memory:",dev_name(&pdev->dev));
+ list_for_each_entry(meminfo, &camsys_dev->devmems.memslist, list) {
+ if (strcmp(meminfo->name,CAMSYS_I2C_MEM_NAME) == 0) {
+ camsys_dev->devmems.i2cmem = meminfo;
+ camsys_trace(1," I2c memory (phy: 0x%x vir: 0x%x size: 0x%x)",
+ meminfo->phy_base,meminfo->vir_base,meminfo->size);
+ }
+ if (strcmp(meminfo->name,CAMSYS_REGISTER_MEM_NAME) == 0) {
+ camsys_dev->devmems.registermem = meminfo;
+ camsys_trace(1," Register memory (phy: 0x%x vir: 0x%x size: 0x%x)",
+ meminfo->phy_base,meminfo->vir_base,meminfo->size);
+ }
+ }
+
+ camsys_dev->phy_cb = camsys_phy_ops;
+ camsys_dev->pdev = pdev;
+ platform_set_drvdata(pdev,(void*)camsys_dev);
+
+ //Camsys_devs list add
+ spin_lock(&camsys_devs.lock);
+ list_add_tail(&camsys_dev->list, &camsys_devs.devs);
+ spin_unlock(&camsys_devs.lock);
+
+
+ camsys_trace(1, "Probe %s device success ", dev_name(&pdev->dev));
+ return 0;
+request_mem_fail:
+ if (camsys_dev != NULL) {
+
+ while(!list_empty(&camsys_dev->devmems.memslist)) {
+ meminfo = list_first_entry(&camsys_dev->devmems.memslist, camsys_meminfo_t, list);
+ if (meminfo) {
+ list_del_init(&meminfo->list);
+ if (strcmp(meminfo->name,CAMSYS_REGISTER_MEM_NAME)==0) {
+ iounmap((void __iomem *)meminfo->vir_base);
+ release_mem_region(meminfo->phy_base,meminfo->size);
+ } else if (strcmp(meminfo->name,CAMSYS_I2C_MEM_NAME)==0) {
+ kfree((void*)meminfo->vir_base);
+ }
+ kfree(meminfo);
+ meminfo = NULL;
+ }
+ }
+
+ kfree(camsys_dev);
+ camsys_dev = NULL;
+ }
+fail_end:
+ return -1;
+}
+#endif
+static int camsys_platform_remove(struct platform_device *pdev)
+{
+ camsys_dev_t *camsys_dev = platform_get_drvdata(pdev);
+ camsys_meminfo_t *meminfo;
+
+ if (camsys_dev) {
+
+ //Mem deinit
+ while(!list_empty(&camsys_dev->devmems.memslist)) {
+ meminfo = list_first_entry(&camsys_dev->devmems.memslist, camsys_meminfo_t, list);
+ if (meminfo) {
+ list_del_init(&meminfo->list);
+ if (strcmp(meminfo->name,CAMSYS_REGISTER_MEM_NAME)==0) {
+ iounmap((void __iomem *)meminfo->vir_base);
+ release_mem_region(meminfo->phy_base,meminfo->size);
+ } else if (strcmp(meminfo->name,CAMSYS_I2C_MEM_NAME)==0) {
+ kfree((void*)meminfo->vir_base);
+ }
+ kfree(meminfo);
+ meminfo = NULL;
+ }
+ }
+
+ //Irq deinit
+ if (camsys_dev->irq.irq_id) {
+ free_irq(camsys_dev->irq.irq_id, camsys_dev);
+ camsys_irq_disconnect(NULL,camsys_dev,true);
+ }
+
+ //Extdev deinit
+ if (!list_empty(&camsys_dev->extdevs.list)) {
+ camsys_extdev_deregister(0,camsys_dev,true);
+ }
+
+ if (camsys_dev->mipiphy.remove)
+ camsys_dev->mipiphy.remove(pdev);
+ if (camsys_dev->cifphy.remove)
+ camsys_dev->cifphy.remove(pdev);
+ camsys_dev->platform_remove(pdev);
+
+ misc_deregister(&camsys_dev->miscdev);
+
+ spin_lock(&camsys_devs.lock);
+ list_del_init(&camsys_dev->list);
+ spin_unlock(&camsys_devs.lock);
+
+ kfree(camsys_dev);
+ camsys_dev=NULL;
+ } else {
+ camsys_err("This platform device havn't obtain camsys_dev!");
+ }
+
+ return 0;
+}
+
+
+static const struct of_device_id cif_of_match[] = {
+ { .compatible = "rodkchip,isp" },
+};
+MODULE_DEVICE_TABLE(of, cif_of_match);
+
+static struct platform_driver camsys_platform_driver =
+{
+ .driver = {
+ .name = CAMSYS_PLATFORM_DRV_NAME,
+ .of_match_table = cif_of_match,
+ },
+ .probe = camsys_platform_probe_new,
+ .remove = (camsys_platform_remove),
+};
+
+
+static int __init camsys_platform_init(void)
+{
+ printk("CamSys driver version: v%d.%d.%d, CamSys head file version: v%d.%d.%d\n",
+ (CAMSYS_DRIVER_VERSION&0xff0000)>>16, (CAMSYS_DRIVER_VERSION&0xff00)>>8,
+ CAMSYS_DRIVER_VERSION&0xff,
+ (CAMSYS_HEAD_VERSION&0xff0000)>>16, (CAMSYS_HEAD_VERSION&0xff00)>>8,
+ CAMSYS_HEAD_VERSION&0xff);
+ spin_lock_init(&camsys_devs.lock);
+ INIT_LIST_HEAD(&camsys_devs.devs);
+ platform_driver_register(&camsys_platform_driver);
+
+
+ return 0;
+}
+
+static void __exit camsys_platform_exit(void)
+{
+ platform_driver_unregister(&camsys_platform_driver);
+}
+
+module_init(camsys_platform_init);
+module_exit(camsys_platform_exit);
+
+MODULE_DESCRIPTION("RockChip Camera System");
+MODULE_AUTHOR("<ddl@rock-chips>");
+MODULE_LICENSE("GPL");
+
--- /dev/null
+#ifndef __RKCAMSYS_GPIO_H__
+#define __RKCAMSYS_GPIO_H__
+
+//#include <mach/gpio.h>
+#include <asm/gpio.h>
+#if defined(CONFIG_ARCH_ROCKCHIP)
+#define RK30_PIN0_PA0 (0)
+#define NUM_GROUP (32)
+#define GPIO_BANKS (9)
+#endif
+
+static inline unsigned int camsys_gpio_group_pin(unsigned char *io_name)
+{
+ unsigned char *pin_char;
+ unsigned char pin;
+
+ if (strstr(io_name, "PA")) {
+ pin_char = strstr(io_name, "PA");
+ pin_char += 2;
+ pin = *pin_char - 0x30;
+ } else if (strstr(io_name, "PB")) {
+ pin_char = strstr(io_name, "PB");
+ pin_char += 2;
+ pin = *pin_char - 0x30;
+ pin += 8;
+ } else if (strstr(io_name, "PC")) {
+ pin_char = strstr(io_name, "PC");
+ pin_char += 2;
+ pin = *pin_char - 0x30;
+ pin += 16;
+ } else if (strstr(io_name, "PD")) {
+ pin_char = strstr(io_name, "PD");
+ pin_char += 2;
+ pin = *pin_char - 0x30;
+ pin += 24;
+ }
+
+ return pin;
+}
+
+static inline unsigned int camsys_gpio_group(unsigned char *io_name)
+{
+ unsigned int group;
+
+ if (strstr(io_name,"PIN0")) {
+ group = 0;
+ } else if (strstr(io_name,"PIN1")) {
+ group = 1;
+ } else if (strstr(io_name,"PIN2")) {
+ group = 2;
+ } else if (strstr(io_name,"PIN3")) {
+ group = 3;
+ } else if (strstr(io_name,"PIN4")) {
+ group = 4;
+ } else if (strstr(io_name,"PIN5")) {
+ group = 5;
+ } else if (strstr(io_name,"PIN6")) {
+ group = 6;
+ }
+
+ return group;
+}
+
+static inline unsigned int camsys_gpio_get(unsigned char *io_name)
+{
+ unsigned int gpio;
+ unsigned int group;
+ unsigned int group_pin;
+
+#if (defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188) || defined(CONFIG_ARCH_RK319X) ||defined(CONFIG_ARCH_ROCKCHIP))
+ if (strstr(io_name, "RK30_")) {
+ gpio = RK30_PIN0_PA0;
+ group = camsys_gpio_group(io_name);
+ group_pin = camsys_gpio_group_pin(io_name);
+
+ if (group >= GPIO_BANKS) {
+ gpio = 0xffffffff;
+ } else {
+ gpio += group*NUM_GROUP + group_pin;
+ }
+ }
+
+#endif
+
+
+ return gpio;
+}
+
+#endif
+
--- /dev/null
+#ifndef __RKCAMSYS_INTERNAL_H__
+#define __RKCAMSYS_INTERNAL_H__
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/fcntl.h>
+#include <linux/clk.h>
+#include <linux/seq_file.h>
+#include <linux/cdev.h>
+#include <linux/miscdevice.h>
+#include <linux/version.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/regulator/machine.h>
+#include <linux/log2.h>
+//#include <mach/io.h>
+//#include <mach/gpio.h>
+//#include <mach/iomux.h>
+//#include <mach/cru.h>
+#include <linux/rockchip/cpu.h>
+#include <linux/rockchip/iomap.h>
+#include <linux/rockchip/grf.h>
+
+#include <asm/gpio.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <media/camsys_head.h>
+/*
+* C A M S Y S D R I V E R V E R S I O N
+*
+*v0.0.1:
+* 1) test version;
+*v0.0.2:
+* 1) add mipi csi phy;
+*v0.0.3:
+* 1) add support cif phy for marvin;
+*v0.0.4:
+* 1) add clock information in struct camsys_devio_name_s;
+*v0.0.5:
+* 1) set isp clock at 32MHz;
+*v0.0.6:
+* 1) iomux d0 d1 for cif phy raw10 in rk319x after i2c operated;
+* 2) check mis value in camsys_irq_connect;
+* 3) add soft rest callback;
+*v0.0.7:
+* 1) check extdev is activate or not before delete from camsys_dev active list;
+*/
+#define CAMSYS_DRIVER_VERSION KERNEL_VERSION(0,0,6)
+
+
+#define CAMSYS_PLATFORM_DRV_NAME "RockChip-CamSys"
+#define CAMSYS_PLATFORM_MARVIN_NAME "Platform_MarvinDev"
+#define CAMSYS_PLATFORM_CIF0_NAME "Platform_Cif0Dev"
+#define CAMSYS_PLATFORM_CIF1_NAME "Platform_Cif1Dev"
+
+#define CAMSYS_REGISTER_RES_NAME "CamSys_RegMem"
+#define CAMSYS_REGISTER_MIPIPHY_RES_NAME "CamSys_RegMem_MipiPhy"
+#define CAMSYS_IRQ_RES_NAME "CamSys_Irq"
+
+#define CAMSYS_REGISTER_MEM_NAME CAMSYS_REGISTER_RES_NAME
+#define CAMSYS_I2C_MEM_NAME "CamSys_I2cMem"
+
+#define CAMSYS_NAMELEN_MIN(a) ((strlen(a)>(CAMSYS_NAME_LEN-1))?(CAMSYS_NAME_LEN-1):strlen(a))
+#define CAMSYS_IRQPOOL_NUM 128
+
+extern unsigned int camsys_debug;
+
+#define camsys_trace(level, msg,...) \
+ do { \
+ if (1/*camsys_debug >= level*/) \
+ printk("D%d:%s(%d): " msg "\n",level, __FUNCTION__,__LINE__, ## __VA_ARGS__); \
+ } while (0)
+
+#define camsys_warn(msg,...) printk(KERN_ERR "W:%s(%d): " msg "\n", __FUNCTION__,__LINE__, ## __VA_ARGS__)
+#define camsys_err(msg,...) printk(KERN_ERR "E:%s(%d): " msg "\n", __FUNCTION__,__LINE__, ## __VA_ARGS__)
+
+
+typedef struct camsys_irqstas_s {
+ camsys_irqsta_t sta;
+ struct list_head list;
+} camsys_irqstas_t;
+
+typedef struct camsys_irqpool_s {
+ pid_t pid;
+ unsigned int timeout; //us
+ unsigned int mis;
+ unsigned int icr;
+
+
+ spinlock_t lock; // lock for list
+ camsys_irqstas_t pool[CAMSYS_IRQPOOL_NUM];
+ struct list_head active;
+ struct list_head deactive;
+
+ struct list_head list;
+
+ wait_queue_head_t done;
+} camsys_irqpool_t;
+
+typedef struct camsys_irq_s {
+ unsigned int irq_id;
+
+ spinlock_t lock; //lock for timeout and irq_connect in ioctl
+ //unsigned int timeout;
+
+ //wait_queue_head_t irq_done;
+
+ struct list_head irq_pool;
+} camsys_irq_t;
+
+typedef struct camsys_meminfo_s {
+ unsigned char name[32];
+ unsigned int phy_base;
+ unsigned int vir_base;
+ unsigned int size;
+ unsigned int vmas;
+
+ struct list_head list;
+
+} camsys_meminfo_t;
+
+typedef struct camsys_devmems_s {
+ camsys_meminfo_t *registermem;
+ camsys_meminfo_t *i2cmem;
+ struct list_head memslist;
+} camsys_devmems_t;
+
+typedef struct camsys_regulator_s {
+ struct regulator *ldo;
+ int min_uv;
+ int max_uv;
+} camsys_regulator_t;
+
+typedef struct camsys_gpio_s {
+ unsigned int io;
+ unsigned int active;
+} camsys_gpio_t;
+typedef struct camsys_flash_s {
+ camsys_gpio_t fl;
+} camsys_flash_t;
+typedef struct camsys_extdev_s {
+ unsigned int dev_id;
+ camsys_regulator_t avdd;
+ camsys_regulator_t dovdd;
+ camsys_regulator_t dvdd;
+ camsys_regulator_t afvdd;
+
+ camsys_gpio_t pwrdn;
+ camsys_gpio_t rst;
+ camsys_gpio_t afpwr;
+ camsys_gpio_t afpwrdn;
+
+ camsys_flash_t fl;
+
+ camsys_extdev_phy_t phy;
+ camsys_extdev_clk_t clk;
+
+ unsigned int dev_cfg;
+
+ struct platform_device *pdev;
+
+ struct list_head list;
+ struct list_head active;
+} camsys_extdev_t;
+
+typedef struct camsys_phyinfo_s {
+ void *clk;
+ camsys_meminfo_t *reg;
+
+ int (*clkin_cb)(void *ptr, unsigned int on);
+ int (*ops) (void *phy, void *phyinfo, unsigned int on);
+ int (*remove)(struct platform_device *pdev);
+} camsys_phyinfo_t;
+
+typedef struct camsys_exdevs_s {
+ struct mutex mut;
+ struct list_head list;
+ struct list_head active;
+} camsys_exdevs_t;
+
+typedef struct camsys_dev_s {
+ unsigned int dev_id;
+
+ camsys_irq_t irq;
+ camsys_devmems_t devmems;
+ struct miscdevice miscdev;
+ void *clk;
+
+ camsys_phyinfo_t mipiphy;
+ camsys_phyinfo_t cifphy;
+
+ camsys_exdevs_t extdevs;
+ struct list_head list;
+ struct platform_device *pdev;
+
+ int (*clkin_cb)(void *ptr, unsigned int on);
+ int (*clkout_cb)(void *ptr,unsigned int on);
+ int (*reset_cb)(void *ptr);
+ int (*phy_cb) (camsys_extdev_phy_t *phy,void* ptr, unsigned int on);
+ int (*iomux)(camsys_extdev_t *extdev,void *ptr);
+ int (*platform_remove)(struct platform_device *pdev);
+} camsys_dev_t;
+
+
+static inline camsys_extdev_t* camsys_find_extdev(unsigned int dev_id, camsys_dev_t *camsys_dev)
+{
+ camsys_extdev_t *extdev;
+
+ if (!list_empty(&camsys_dev->extdevs.list)) {
+ list_for_each_entry(extdev, &camsys_dev->extdevs.list, list) {
+ if (extdev->dev_id == dev_id) {
+ return extdev;
+ }
+ }
+ }
+ return NULL;
+}
+
+static inline camsys_meminfo_t* camsys_find_devmem(char *name, camsys_dev_t *camsys_dev)
+{
+ camsys_meminfo_t *devmem;
+
+ if (!list_empty(&camsys_dev->devmems.memslist)) {
+ list_for_each_entry(devmem, &camsys_dev->devmems.memslist, list) {
+ if (strcmp(devmem->name, name) == 0) {
+ return devmem;
+ }
+ }
+ }
+ camsys_err("%s memory have not been find in %s!",name,dev_name(camsys_dev->miscdev.this_device));
+ return NULL;
+}
+
+
+static inline int camsys_sysctl_extdev(camsys_extdev_t *extdev, camsys_sysctrl_t *devctl, camsys_dev_t *camsys_dev)
+{
+ int err = 0;
+ camsys_regulator_t *regulator;
+ camsys_gpio_t *gpio;
+
+ if (devctl->ops < CamSys_Vdd_Tag) {
+ regulator = &extdev->avdd;
+ regulator += devctl->ops;
+
+ //printk("regulator: %p regulator->ldo: %p\n",regulator,regulator->ldo);
+ if (!IS_ERR_OR_NULL(regulator->ldo)) {
+ if (devctl->on) {
+ regulator_set_voltage(regulator->ldo,regulator->min_uv,regulator->max_uv);
+ regulator_enable(regulator->ldo);
+ camsys_trace(1,"Sysctl %d success, regulator set (%d,%d) uv!",devctl->ops, regulator->min_uv,regulator->max_uv);
+ } else {
+ while(regulator_is_enabled(regulator->ldo)>0)
+ regulator_disable(regulator->ldo);
+ camsys_trace(1,"Sysctl %d success, regulator off!",devctl->ops);
+ }
+ } else {
+ camsys_err("Sysctl %d failed, because regulator ldo is NULL!",devctl->ops);
+ err = -EINVAL;
+ goto end;
+ }
+ } else if (devctl->ops < CamSys_Gpio_Tag) {
+ gpio = &extdev->pwrdn;
+ gpio += devctl->ops - CamSys_Vdd_Tag -1;
+
+ if (gpio->io != 0xffffffff) {
+ if (devctl->on) {
+ gpio_direction_output(gpio->io, gpio->active);
+ gpio_set_value(gpio->io, gpio->active);
+ camsys_trace(1,"Sysctl %d success, gpio(%d) set %d",devctl->ops, gpio->io, gpio->active);
+ } else {
+ gpio_direction_output(gpio->io, !gpio->active);
+ gpio_set_value(gpio->io, !gpio->active);
+ camsys_trace(1,"Sysctl %d success, gpio(%d) set %d",devctl->ops, gpio->io, !gpio->active);
+ }
+ } else {
+ camsys_err("Sysctl %d failed, because gpio is NULL!",devctl->ops);
+ err = -EINVAL;
+ goto end;
+ }
+ } else if (devctl->ops == CamSys_ClkIn) {
+ if (camsys_dev->clkout_cb)
+ camsys_dev->clkout_cb(camsys_dev, extdev->clk.in_rate);
+ if (camsys_dev->phy_cb)
+ camsys_dev->phy_cb(&extdev->phy, camsys_dev, devctl->on);
+ }
+
+end:
+ return err;
+}
+
+extern struct file_operations camsys_fops;
+#endif
--- /dev/null
+#include "camsys_marvin.h"
+
+static const char miscdev_name[] = CAMSYS_MARVIN_DEVNAME;
+
+
+static int camsys_mrv_iomux_cb(camsys_extdev_t *extdev,void *ptr)
+{
+ unsigned int cif_vol_sel;
+#if 0
+ if (extdev->dev_cfg & CAMSYS_DEVCFG_FLASHLIGHT) {
+ iomux_set(ISP_FLASH_TRIG);
+ if (extdev->fl.fl.io != 0xffffffff) {
+ iomux_set(ISP_FL_TRIG);
+ }
+ }
+
+ if (extdev->dev_cfg & CAMSYS_DEVCFG_PREFLASHLIGHT) {
+ iomux_set(ISP_PRELIGHT_TRIG);
+ }
+
+ if (extdev->dev_cfg & CAMSYS_DEVCFG_SHUTTER) {
+ iomux_set(ISP_SHUTTER_OPEN);
+ iomux_set(ISP_SHUTTER_TRIG);
+ }
+
+ iomux_set(CIF0_CLKOUT);
+#endif
+
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *state;
+ int retval = 0;
+ char state_str[20] = {0};
+
+ struct device *dev = &(extdev->pdev->dev);
+
+ if (extdev->phy.type == CamSys_Phy_Cif) {
+ if ((extdev->phy.info.cif.fmt >= CamSys_Fmt_Raw_8b)&& (extdev->phy.info.cif.fmt <= CamSys_Fmt_Raw_12b)) {
+
+ strcpy(state_str,"isp_dvp8bit");
+
+ }
+
+ if ((extdev->phy.info.cif.fmt >= CamSys_Fmt_Raw_10b)&& (extdev->phy.info.cif.fmt <= CamSys_Fmt_Raw_12b)) {
+ strcpy(state_str,"isp_dvp10bit");
+ }
+
+ if (extdev->phy.info.cif.fmt == CamSys_Fmt_Raw_12b) {
+ strcpy(state_str,"isp_dvp12bit");
+
+ }
+ }else{
+ strcpy(state_str,"default");
+ }
+
+ //mux CIF0_CLKOUT
+
+ pinctrl = devm_pinctrl_get(dev);
+ if (IS_ERR(pinctrl)) {
+ camsys_err("%s:Get pinctrl failed!\n",__func__);
+ return -1;
+ }
+ state = pinctrl_lookup_state(pinctrl,
+ state_str);
+ if (IS_ERR(state)){
+ dev_err(dev, "%s:could not get %s pinstate\n",__func__,state_str);
+ return -1;
+ }
+
+ if (!IS_ERR(state)) {
+ retval = pinctrl_select_state(pinctrl, state);
+ if (retval){
+ dev_err(dev,
+ "%s:could not set %s pins\n",__func__,state_str);
+ return -1;
+
+ }
+ }
+
+ //set cif vol domain
+ if (extdev->phy.type == CamSys_Phy_Cif) {
+
+ #if 0
+ if (!IS_ERR_OR_NULL(extdev->dovdd.ldo)) {
+ if (extdev->dovdd.max_uv >= 25000000) {
+ __raw_writel(((1<<1)|(1<<(1+16))),RK30_GRF_BASE+0x018c);
+ } else {
+ __raw_writel((1<<(1+16)),RK30_GRF_BASE+0x018c);
+ }
+ } else {
+ __raw_writel(((1<<1)|(1<<(1+16))),RK30_GRF_BASE+0x018c);
+ }
+ #else
+ __raw_writel(((1<<1)|(1<<(1+16))),RK_GRF_VIRT+0x018c);
+ #endif
+
+ //set driver strength
+ __raw_writel(0xffffffff, RK_GRF_VIRT+0x01dc);
+ }
+
+ return 0;
+}
+
+static int camsys_mrv_reset_cb(void *ptr)
+{
+ camsys_dev_t *camsys_dev = (camsys_dev_t*)ptr;
+ #if 0 //do nothing ,zyc
+ cru_set_soft_reset(SOFT_RST_ISP,true);
+ udelay(100);
+ cru_set_soft_reset(SOFT_RST_ISP,false);
+ #endif
+ camsys_trace(1, "%s soft reset\n",dev_name(camsys_dev->miscdev.this_device));
+ return 0;
+}
+
+static int camsys_mrv_clkin_cb(void *ptr, unsigned int on)
+{
+ camsys_dev_t *camsys_dev = (camsys_dev_t*)ptr;
+ camsys_mrv_clk_t *clk = (camsys_mrv_clk_t*)camsys_dev->clk;
+
+ spin_lock(&clk->lock);
+ if (on && !clk->in_on) {
+ clk_enable(clk->pd_isp);
+ clk_enable(clk->aclk_isp);
+ clk_enable(clk->hclk_isp);
+ clk_enable(clk->isp);
+ clk_enable(clk->isp_jpe);
+ clk_enable(clk->pclkin_isp);
+
+ clk->in_on = true;
+
+ camsys_trace(1, "%s clock in turn on",dev_name(camsys_dev->miscdev.this_device));
+ camsys_mrv_reset_cb(ptr);
+
+ } else if (!on && clk->in_on) {
+ clk_disable(clk->pd_isp);
+ clk_disable(clk->aclk_isp);
+ clk_disable(clk->hclk_isp);
+ clk_disable(clk->isp);
+ clk_disable(clk->isp_jpe);
+ clk_disable(clk->pclkin_isp);
+ clk->in_on = false;
+ camsys_trace(1, "%s clock in turn off",dev_name(camsys_dev->miscdev.this_device));
+ }
+ spin_unlock(&clk->lock);
+ return 0;
+}
+
+static int camsys_mrv_clkout_cb(void *ptr, unsigned int on)
+{
+ camsys_dev_t *camsys_dev = (camsys_dev_t*)ptr;
+ camsys_mrv_clk_t *clk = (camsys_mrv_clk_t*)camsys_dev->clk;
+ struct clk *cif_clk_out_div;
+
+ spin_lock(&clk->lock);
+ if (on && (clk->out_on != on)) {
+ clk_enable(clk->cif_clk_out);
+ clk_set_rate(clk->cif_clk_out,on);
+
+ clk->out_on = on;
+ camsys_trace(1, "%s clock out(rate: %dHz) turn on",dev_name(camsys_dev->miscdev.this_device),
+ clk->out_on);
+ } else if (!on && clk->out_on) {
+ cif_clk_out_div = clk_get(NULL, "cif0_out_div");
+ if(IS_ERR_OR_NULL(cif_clk_out_div)) {
+ cif_clk_out_div = clk_get(NULL, "cif_out_div");
+ }
+
+ if(!IS_ERR_OR_NULL(cif_clk_out_div)) {
+ clk_set_parent(clk->cif_clk_out, cif_clk_out_div);
+ clk_put(cif_clk_out_div);
+ } else {
+ camsys_warn("%s clock out may be not off!", dev_name(camsys_dev->miscdev.this_device));
+ }
+ clk_disable(clk->cif_clk_out);
+ clk->out_on = 0;
+
+ camsys_trace(1, "%s clock out turn off",dev_name(camsys_dev->miscdev.this_device));
+ }
+ spin_unlock(&clk->lock);
+
+ return 0;
+}
+static irqreturn_t camsys_mrv_irq(int irq, void *data)
+{
+ camsys_dev_t *camsys_dev = (camsys_dev_t*)data;
+ camsys_irqstas_t *irqsta;
+ camsys_irqpool_t *irqpool;
+ unsigned int isp_mis,mipi_mis,mi_mis,*mis;
+
+ isp_mis = __raw_readl((void volatile *)(camsys_dev->devmems.registermem->vir_base + MRV_ISP_MIS));
+ mipi_mis = __raw_readl((void volatile *)(camsys_dev->devmems.registermem->vir_base + MRV_MIPI_MIS));
+ mi_mis = __raw_readl((void volatile *)(camsys_dev->devmems.registermem->vir_base + MRV_MI_MIS));
+
+ __raw_writel(isp_mis, (void volatile *)(camsys_dev->devmems.registermem->vir_base + MRV_ISP_ICR));
+ __raw_writel(mipi_mis, (void volatile *)(camsys_dev->devmems.registermem->vir_base + MRV_MIPI_ICR));
+ __raw_writel(mi_mis, (void volatile *)(camsys_dev->devmems.registermem->vir_base + MRV_MI_ICR));
+
+ spin_lock(&camsys_dev->irq.lock);
+ if (!list_empty(&camsys_dev->irq.irq_pool)) {
+ list_for_each_entry(irqpool, &camsys_dev->irq.irq_pool, list) {
+ if (irqpool->pid != 0) {
+ switch(irqpool->mis)
+ {
+ case MRV_ISP_MIS:
+ {
+ mis = &isp_mis;
+ break;
+ }
+
+ case MRV_MIPI_MIS:
+ {
+ mis = &mipi_mis;
+ break;
+ }
+ case MRV_MI_MIS:
+ {
+ mis = &mi_mis;
+ break;
+ }
+
+ default:
+ {
+ camsys_trace(2,"Thread(pid:%d) irqpool mis(%d) is invalidate",irqpool->pid,irqpool->mis);
+ goto end;
+ }
+ }
+
+ if (*mis != 0) {
+ spin_lock(&irqpool->lock);
+ if (!list_empty(&irqpool->deactive)) {
+ irqsta = list_first_entry(&irqpool->deactive, camsys_irqstas_t, list);
+ irqsta->sta.mis = *mis;
+ list_del_init(&irqsta->list);
+ list_add_tail(&irqsta->list,&irqpool->active);
+ wake_up(&irqpool->done);
+ }
+ spin_unlock(&irqpool->lock);
+ }
+ }
+ }
+ }
+end:
+ spin_unlock(&camsys_dev->irq.lock);
+
+ return IRQ_HANDLED;
+}
+static int camsys_mrv_remove_cb(struct platform_device *pdev)
+{
+ camsys_dev_t *camsys_dev = platform_get_drvdata(pdev);
+ camsys_mrv_clk_t *mrv_clk=NULL;
+
+ if (camsys_dev->clk != NULL) {
+
+ mrv_clk = (camsys_mrv_clk_t*)camsys_dev->clk;
+ if (mrv_clk->out_on)
+ camsys_mrv_clkout_cb(mrv_clk,0);
+ if (mrv_clk->in_on)
+ camsys_mrv_clkin_cb(mrv_clk,0);
+
+ if (!IS_ERR_OR_NULL(mrv_clk->pd_isp)) {
+ clk_put(mrv_clk->pd_isp);
+ }
+ if (!IS_ERR_OR_NULL(mrv_clk->aclk_isp)) {
+ clk_put(mrv_clk->aclk_isp);
+ }
+ if (!IS_ERR_OR_NULL(mrv_clk->hclk_isp)) {
+ clk_put(mrv_clk->hclk_isp);
+ }
+ if (!IS_ERR_OR_NULL(mrv_clk->isp)) {
+ clk_put(mrv_clk->isp);
+ }
+ if (!IS_ERR_OR_NULL(mrv_clk->isp_jpe)) {
+ clk_put(mrv_clk->isp_jpe);
+ }
+ if (!IS_ERR_OR_NULL(mrv_clk->pclkin_isp)) {
+ clk_put(mrv_clk->pclkin_isp);
+ }
+ if (!IS_ERR_OR_NULL(mrv_clk->cif_clk_out)) {
+ clk_put(mrv_clk->cif_clk_out);
+ }
+
+ kfree(mrv_clk);
+ mrv_clk = NULL;
+ }
+
+ return 0;
+}
+int camsys_mrv_probe_cb(struct platform_device *pdev, camsys_dev_t *camsys_dev)
+{
+ int err = 0;
+ camsys_mrv_clk_t *mrv_clk=NULL;
+ //struct clk *clk_parent;
+
+ err = request_irq(camsys_dev->irq.irq_id, camsys_mrv_irq, 0, CAMSYS_MARVIN_IRQNAME,camsys_dev);
+ if (err) {
+ camsys_err("request irq for %s failed",CAMSYS_MARVIN_IRQNAME);
+ goto end;
+ }
+
+ //Clk and Iomux init
+ mrv_clk = kzalloc(sizeof(camsys_mrv_clk_t),GFP_KERNEL);
+ if (mrv_clk == NULL) {
+ camsys_err("Allocate camsys_mrv_clk_t failed!");
+ err = -EINVAL;
+ goto clk_failed;
+ }
+
+ // mrv_clk->pd_isp = devm_clk_get(&pdev->dev, "pd_isp");
+ mrv_clk->pd_isp = NULL;
+ mrv_clk->aclk_isp = devm_clk_get(&pdev->dev, "aclk_isp");
+ mrv_clk->hclk_isp = devm_clk_get(&pdev->dev, "hclk_isp");
+ mrv_clk->isp = devm_clk_get(&pdev->dev, "clk_isp");
+ mrv_clk->isp_jpe = devm_clk_get(&pdev->dev, "clk_isp_jpe");
+ mrv_clk->pclkin_isp = devm_clk_get(&pdev->dev, "pclkin_isp");
+ mrv_clk->cif_clk_out = devm_clk_get(&pdev->dev, "clk_vipout");
+ if (/*IS_ERR_OR_NULL(mrv_clk->pd_isp) ||*/ IS_ERR_OR_NULL(mrv_clk->aclk_isp) || IS_ERR_OR_NULL(mrv_clk->hclk_isp) ||
+ IS_ERR_OR_NULL(mrv_clk->isp) || IS_ERR_OR_NULL(mrv_clk->isp_jpe) || IS_ERR_OR_NULL(mrv_clk->pclkin_isp) ||
+ IS_ERR_OR_NULL(mrv_clk->cif_clk_out)) {
+ camsys_err("Get %s clock resouce failed!\n",miscdev_name);
+ err = -EINVAL;
+ goto clk_failed;
+ }
+
+ clk_set_rate(mrv_clk->isp,320000000);
+ clk_set_rate(mrv_clk->isp_jpe,320000000);
+
+ spin_lock_init(&mrv_clk->lock);
+
+ mrv_clk->in_on = false;
+ mrv_clk->out_on = 0;
+
+ camsys_dev->clk = (void*)mrv_clk;
+ camsys_dev->clkin_cb = camsys_mrv_clkin_cb;
+ camsys_dev->clkout_cb = camsys_mrv_clkout_cb;
+ camsys_dev->reset_cb = camsys_mrv_reset_cb;
+ camsys_dev->iomux = camsys_mrv_iomux_cb;
+
+ camsys_dev->miscdev.minor = MISC_DYNAMIC_MINOR;
+ camsys_dev->miscdev.name = miscdev_name;
+ camsys_dev->miscdev.nodename = miscdev_name;
+ camsys_dev->miscdev.fops = &camsys_fops;
+
+ err = misc_register(&camsys_dev->miscdev);
+ if (err < 0) {
+ camsys_err("misc register %s failed!",miscdev_name);
+ goto misc_register_failed;
+ }
+
+ //Variable init
+ camsys_dev->dev_id = CAMSYS_DEVID_MARVIN;
+ camsys_dev->platform_remove = camsys_mrv_remove_cb;
+
+ return 0;
+misc_register_failed:
+ if (!IS_ERR_OR_NULL(camsys_dev->miscdev.this_device)) {
+ misc_deregister(&camsys_dev->miscdev);
+ }
+
+clk_failed:
+ if (mrv_clk != NULL) {
+ if (!IS_ERR_OR_NULL(mrv_clk->pd_isp)) {
+ clk_put(mrv_clk->pd_isp);
+ }
+ if (!IS_ERR_OR_NULL(mrv_clk->aclk_isp)) {
+ clk_put(mrv_clk->aclk_isp);
+ }
+ if (!IS_ERR_OR_NULL(mrv_clk->hclk_isp)) {
+ clk_put(mrv_clk->hclk_isp);
+ }
+ if (!IS_ERR_OR_NULL(mrv_clk->isp)) {
+ clk_put(mrv_clk->isp);
+ }
+ if (!IS_ERR_OR_NULL(mrv_clk->isp_jpe)) {
+ clk_put(mrv_clk->isp_jpe);
+ }
+ if (!IS_ERR_OR_NULL(mrv_clk->pclkin_isp)) {
+ clk_put(mrv_clk->pclkin_isp);
+ }
+ if (!IS_ERR_OR_NULL(mrv_clk->cif_clk_out)) {
+ clk_put(mrv_clk->cif_clk_out);
+ }
+
+ kfree(mrv_clk);
+ mrv_clk = NULL;
+ }
+
+end:
+ return err;
+}
+EXPORT_SYMBOL_GPL(camsys_mrv_probe_cb);
+
--- /dev/null
+#ifndef __CAMSYS_MARVIN_H__
+#define __CAMSYS_MARVIN_H__
+
+#include "camsys_internal.h"
+
+#define CAMSYS_MARVIN_IRQNAME "MarvinIrq"
+
+
+
+#define MRV_ISP_BASE 0x400
+#define MRV_ISP_RIS (MRV_ISP_BASE+0x1c0)
+#define MRV_ISP_MIS (MRV_ISP_BASE+0x1c4)
+#define MRV_ISP_ICR (MRV_ISP_BASE+0x1c8)
+
+#define MRV_MIPI_BASE 0x1C00
+#define MRV_MIPI_MIS (MRV_MIPI_BASE+0x10)
+#define MRV_MIPI_ICR (MRV_MIPI_BASE+0x14)
+
+#define MRV_MI_BASE (0x1400)
+#define MRV_MI_MIS (MRV_MI_BASE+0x100)
+#define MRV_MI_ICR (MRV_MI_BASE+0x104)
+
+
+
+typedef struct camsys_mrv_clk_s {
+ struct clk *pd_isp;
+ struct clk *hclk_isp;
+ struct clk *aclk_isp;
+ struct clk *isp;
+ struct clk *isp_jpe;
+ struct clk *pclkin_isp;
+ bool in_on;
+
+ struct clk *cif_clk_out;
+ unsigned int out_on;
+
+ spinlock_t lock;
+} camsys_mrv_clk_t;
+
+int camsys_mrv_probe_cb(struct platform_device *pdev, camsys_dev_t *camsys_dev);
+
+#endif
+
+
--- /dev/null
+#include "camsys_mipicsi_phy.h"
+
+#if defined(CONFIG_ARCH_ROCKCHIP)
+//GRF_SOC_CON14
+//bit 0 dphy_rx0_testclr
+//bit 1 dphy_rx0_testclk
+//bit 2 dphy_rx0_testen
+//bit 3:10 dphy_rx0_testdin
+#define GRF_SOC_CON14_OFFSET (0x027c)
+#define DPHY_RX0_TESTCLR_MASK (0x1<<16)
+#define DPHY_RX0_TESTCLK_MASK (0x1<<17)
+#define DPHY_RX0_TESTEN_MASK (0x1<<18)
+#define DPHY_RX0_TESTDIN_MASK (0xff<<19)
+
+#define DPHY_RX0_TESTCLR (1<<0)
+#define DPHY_RX0_TESTCLK (1<<1)
+#define DPHY_RX0_TESTEN (1<<2)
+#define DPHY_RX0_TESTDIN_OFFSET (3)
+
+
+//GRF_SOC_CON6
+//bit 0 grf_con_disable_isp
+//bit 1 grf_con_isp_dphy_sel 1'b0 mipi phy rx0
+#define GRF_SOC_CON6_OFFSET (0x025c)
+#define MIPI_PHY_RX0_MASK (0x1<<16)
+#define MIPI_PHY_RX0 (0x1<<0)
+
+#endif
+
+static void phy0_WriteReg(uint8_t addr, uint8_t data)
+{
+
+ //TESTEN =1,TESTDIN=addr
+ write_grf_reg(GRF_SOC_CON14_OFFSET,(( addr << DPHY_RX0_TESTDIN_OFFSET) |DPHY_RX0_TESTDIN_MASK | DPHY_RX0_TESTEN| DPHY_RX0_TESTEN_MASK));
+ //TESTCLK=0
+ write_grf_reg(GRF_SOC_CON14_OFFSET, DPHY_RX0_TESTCLK_MASK);
+ //TESTEN =0,TESTDIN=data
+ write_grf_reg(GRF_SOC_CON14_OFFSET, (( data << DPHY_RX0_TESTDIN_OFFSET)|DPHY_RX0_TESTDIN_MASK |DPHY_RX0_TESTEN));
+ //TESTCLK=1
+ write_grf_reg(GRF_SOC_CON14_OFFSET, DPHY_RX0_TESTCLK_MASK |DPHY_RX0_TESTCLK);
+
+}
+
+static uint8_t phy0_ReadReg(uint8_t addr) //read 0xff968034 bit8~15
+{
+ uint8_t data = 0;
+ //TESTEN =1,TESTDIN=addr
+ write_grf_reg(GRF_SOC_CON14_OFFSET,(( addr << DPHY_RX0_TESTDIN_OFFSET) |DPHY_RX0_TESTDIN_MASK | DPHY_RX0_TESTEN| DPHY_RX0_TESTEN_MASK));
+ //TESTCLK=0
+ write_grf_reg(GRF_SOC_CON14_OFFSET, DPHY_RX0_TESTCLK_MASK);
+
+ data = ((read_grf_reg(GRF_SOC_CON14_OFFSET) >> DPHY_RX0_TESTDIN_OFFSET) & (0xff));
+
+ camsys_err("%s phy addr = 0x%x,value = 0x%x\n",__func__,addr,data);
+ return data ;
+
+
+}
+
+
+static void PHY0_Init(int numLane,int clkfreq)
+{
+
+// select phy rx0
+ write_grf_reg(GRF_SOC_CON6_OFFSET, MIPI_PHY_RX0_MASK | MIPI_PHY_RX0);
+
+//TESTCLK=1
+ write_grf_reg(GRF_SOC_CON14_OFFSET, DPHY_RX0_TESTCLK_MASK |DPHY_RX0_TESTCLK);
+//TESTCLR=1
+ write_grf_reg(GRF_SOC_CON14_OFFSET, DPHY_RX0_TESTCLK_MASK |DPHY_RX0_TESTCLK | DPHY_RX0_TESTCLR_MASK |DPHY_RX0_TESTCLR);
+//TESTCLR=0 zyc
+ write_grf_reg(GRF_SOC_CON14_OFFSET, DPHY_RX0_TESTCLK_MASK |DPHY_RX0_TESTCLK);
+
+//**********************************************************************//
+
+//set clock lane
+ phy0_WriteReg(0x34,0x14);
+
+//set lane 0
+ /********************
+ 500-550M 0x0E
+ 600-650M 0x10
+ 720M 0x12
+ 360M 0x2A
+ *******************/
+ phy0_WriteReg(0x44,0x10);
+
+ //**********************************************************************//
+
+//Normal operation
+ phy0_ReadReg(0x00);
+ //TESTCLK=1
+ write_grf_reg(GRF_SOC_CON14_OFFSET, DPHY_RX0_TESTCLK_MASK |DPHY_RX0_TESTCLK);
+
+ //TESTEN =0
+ write_grf_reg(GRF_SOC_CON14_OFFSET, (DPHY_RX0_TESTEN));
+
+ }
+
+
+static int camsys_mipiphy_ops (void *phy, void *phyinfo, unsigned int on)
+{
+ PHY0_Init(1,0);
+ return 0;
+}
+
+static int camsys_mipiphy_clkin_cb(void *ptr, unsigned int on)
+{
+ return 0;
+}
+
+static int camsys_mipiphy_remove_cb(struct platform_device *pdev)
+{
+ return 0;
+}
+int camsys_mipiphy_probe_cb(struct platform_device *pdev, camsys_dev_t *camsys_dev)
+{
+
+ camsys_dev->mipiphy.clkin_cb = camsys_mipiphy_clkin_cb;
+ camsys_dev->mipiphy.ops = camsys_mipiphy_ops;
+ camsys_dev->mipiphy.remove = camsys_mipiphy_remove_cb;
+
+ return 0;
+
+}
+
--- /dev/null
+#ifndef __CAMSYS_MIPICSI_PHY_H__
+#define __CAMSYS_MIPICSI_PHY_H__
+
+#include "camsys_internal.h"
+
+#if defined(CONFIG_ARCH_ROCKCHIP)
+
+#define write_grf_reg(addr, val) __raw_writel(val, addr+RK_GRF_VIRT)
+#define read_grf_reg(addr) __raw_readl(addr+RK_GRF_VIRT)
+#define mask_grf_reg(addr, msk, val) write_grf_reg(addr,(val)|((~(msk))&read_grf_reg(addr)))
+#else
+#define write_grf_reg(addr, val)
+#define read_grf_reg(addr) 0
+#define mask_grf_reg(addr, msk, val)
+#endif
+
+
+typedef struct camsys_mipiphy_clk_s {
+ struct clk *pd_mipi_csi;
+ struct clk *pclk_mipiphy_csi;
+ bool in_on;
+ spinlock_t lock;
+} camsys_mipiphy_clk_t;
+
+
+int camsys_mipiphy_probe_cb(struct platform_device *pdev, camsys_dev_t *camsys_dev);
+
+#endif
--- /dev/null
+#ifndef __RKCAMSYS_HEAR_H__
+#define __RKCAMSYS_HEAR_H__
+
+#include <linux/ioctl.h>
+
+/*
+* C A M S Y S H E A D F I L E V E R S I O N
+*
+*v0.0.1:
+* 1) test version;
+*v0.0.2:
+* 1) modify camsys_irqcnnt_t;
+*v0.0.3:
+* 1) add support cif phy for marvin;
+*v0.0.4:
+* 1) add clock information in struct camsys_devio_name_s;
+*/
+#define CAMSYS_HEAD_VERSION KERNEL_VERSION(0,0,4)
+
+#define CAMSYS_MARVIN_DEVNAME "camsys_marvin"
+#define CAMSYS_CIF0_DEVNAME "camsys_cif0"
+#define CAMSYS_CIF1_DEVNAME "camsys_cif1"
+
+#define CAMSYS_NAME_LEN 32
+
+#define CAMSYS_DEVID_MARVIN 0x00000001
+#define CAMSYS_DEVID_CIF_0 0x00000002
+#define CAMSYS_DEVID_CIF_1 0x00000004
+#define CAMSYS_DEVID_INTERNAL 0x000000FF
+
+#define CAMSYS_DEVID_SENSOR_1A 0x01000000
+#define CAMSYS_DEVID_SENSOR_1B 0x02000000
+#define CAMSYS_DEVID_SENSOR_2 0x04000000
+#define CAMSYS_DEVID_EXTERNAL 0xFF000000
+#define CAMSYS_DEVID_EXTERNAL_NUM 8
+
+#define CAMSYS_DEVCFG_FLASHLIGHT 0x00000001
+#define CAMSYS_DEVCFG_PREFLASHLIGHT 0x00000002
+#define CAMSYS_DEVCFG_SHUTTER 0x00000004
+
+typedef struct camsys_irqsta_s {
+ unsigned int ris; //Raw interrupt status
+ unsigned int mis; //Masked interrupt status
+} camsys_irqsta_t;
+
+typedef struct camsys_irqcnnt_s {
+ int pid;
+ unsigned int timeout; //us
+
+ unsigned int mis;
+ unsigned int icr;
+} camsys_irqcnnt_t;
+
+typedef enum camsys_mmap_type_e { //this type can be filled in mmap offset argument
+ CamSys_Mmap_RegisterMem,
+ CamSys_Mmap_I2cMem,
+
+ CamSys_Mmap_End
+} camsys_mmap_type_t;
+
+typedef struct camsys_querymem_s {
+ camsys_mmap_type_t mem_type;
+ unsigned long mem_offset;
+
+ unsigned int mem_size;
+} camsys_querymem_t;
+
+typedef struct camsys_i2c_info_s {
+ unsigned char bus_num;
+ unsigned short slave_addr;
+ unsigned int reg_addr; //i2c device register address
+ unsigned int reg_size; //register address size
+ unsigned int val;
+ unsigned int val_size; //register value size
+ unsigned int i2cbuf_directly;
+ unsigned int i2cbuf_bytes;
+ unsigned int speed; //100000 == 100KHz
+} camsys_i2c_info_t;
+
+typedef struct camsys_reginfo_s {
+ unsigned int dev_mask;
+ unsigned int reg_offset;
+ unsigned int val;
+} camsys_reginfo_t;
+
+typedef enum camsys_sysctrl_ops_e {
+ CamSys_Avdd =0,
+ CamSys_Dovdd,
+ CamSys_Dvdd,
+ CamSys_Afvdd,
+
+ CamSys_Vdd_Tag = 10,
+
+ CamSys_PwrDn,
+ CamSys_Rst,
+ CamSys_AfPwr,
+ CamSys_AfPwrDn,
+
+ CamSys_Gpio_Tag = 50,
+
+ CamSys_ClkIn
+} camsys_sysctrl_ops_t;
+
+typedef struct camsys_regulator_info_s {
+ unsigned char name[CAMSYS_NAME_LEN];
+ int min_uv;
+ int max_uv;
+} camsys_regulator_info_t;
+
+typedef struct camsys_gpio_info_s {
+ unsigned char name[CAMSYS_NAME_LEN];
+ unsigned int active;
+} camsys_gpio_info_t;
+
+typedef struct camsys_sysctrl_s {
+ unsigned int dev_mask;
+ camsys_sysctrl_ops_t ops;
+ unsigned int on;
+} camsys_sysctrl_t;
+
+typedef struct camsys_flash_info_s {
+ camsys_gpio_info_t fl;
+} camsys_flash_info_t;
+
+typedef struct camsys_mipiphy_s {
+ unsigned int data_en_bit; //data lane enable bit;
+} camsys_mipiphy_t;
+
+typedef enum camsys_fmt_e {
+ CamSys_Fmt_Yuv420_8b = 0x18,
+ CamSys_Fmt_Yuv420_10b = 0x19,
+ CamSys_Fmt_LegacyYuv420_8b = 0x19,
+
+ CamSys_Fmt_Yuv422_8b = 0x1e,
+ CamSys_Fmt_Yuv422_10b = 0x1f,
+
+ CamSys_Fmt_Raw_6b = 0x28,
+ CamSys_Fmt_Raw_7b = 0x29,
+ CamSys_Fmt_Raw_8b = 0x2a,
+ CamSys_Fmt_Raw_10b = 0x2b,
+ CamSys_Fmt_Raw_12b = 0x2c,
+ CamSys_Fmt_Raw_14b = 0x2d,
+} camsys_fmt_t;
+
+typedef struct camsys_cifphy_s {
+ unsigned int cif_num;
+ camsys_fmt_t fmt;
+} camsys_cifphy_t;
+
+typedef enum camsys_phy_type_e {
+ CamSys_Phy_Mipi,
+ CamSys_Phy_Cif,
+
+ CamSys_Phy_end
+} camsys_phy_type_t;
+
+typedef struct camsys_extdev_phy_s {
+ camsys_phy_type_t type;
+ union {
+ camsys_mipiphy_t mipi;
+ camsys_cifphy_t cif;
+ } info;
+
+} camsys_extdev_phy_t;
+
+typedef struct camsys_extdev_clk_s {
+ unsigned int in_rate;
+} camsys_extdev_clk_t;
+
+typedef struct camsys_devio_name_s {
+ unsigned int dev_id;
+
+ camsys_regulator_info_t avdd; // sensor avdd power regulator name
+ camsys_regulator_info_t dovdd; // sensor dovdd power regulator name
+ camsys_regulator_info_t dvdd; // sensor dvdd power regulator name "NC" describe no regulator
+ camsys_regulator_info_t afvdd;
+
+ camsys_gpio_info_t pwrdn; // standby gpio name
+ camsys_gpio_info_t rst; // hard reset gpio name
+ camsys_gpio_info_t afpwr; // auto focus vcm driver ic power gpio name
+ camsys_gpio_info_t afpwrdn; // auto focus vcm driver ic standby gpio
+
+ camsys_flash_info_t fl;
+
+ camsys_extdev_phy_t phy;
+ camsys_extdev_clk_t clk;
+
+ unsigned int dev_cfg; // function bit mask configuration
+} camsys_devio_name_t;
+
+typedef struct camsys_version_s {
+ unsigned int drv_ver;
+ unsigned int head_ver;
+} camsys_version_t;
+
+/*
+ * I O C T L C O D E S F O R R O C K C H I P S C A M S Y S D E V I C E S
+ *
+ */
+#define CAMSYS_IOC_MAGIC 'M'
+#define CAMSYS_IOC_MAXNR 12
+
+#define CAMSYS_VERCHK _IOR(CAMSYS_IOC_MAGIC, 0, camsys_version_t)
+
+#define CAMSYS_I2CRD _IOWR(CAMSYS_IOC_MAGIC, 1, camsys_i2c_info_t)
+#define CAMSYS_I2CWR _IOW(CAMSYS_IOC_MAGIC, 2, camsys_i2c_info_t)
+
+#define CAMSYS_SYSCTRL _IOW(CAMSYS_IOC_MAGIC, 3, camsys_sysctrl_t)
+#define CAMSYS_REGRD _IOWR(CAMSYS_IOC_MAGIC, 4, camsys_reginfo_t)
+#define CAMSYS_REGWR _IOW(CAMSYS_IOC_MAGIC, 5, camsys_reginfo_t)
+#define CAMSYS_REGISTER_DEVIO _IOW(CAMSYS_IOC_MAGIC, 6, camsys_devio_name_t)
+#define CAMSYS_DEREGISTER_DEVIO _IOW(CAMSYS_IOC_MAGIC, 7, unsigned int)
+#define CAMSYS_IRQCONNECT _IOW(CAMSYS_IOC_MAGIC, 8, camsys_irqcnnt_t)
+#define CAMSYS_IRQWAIT _IOR(CAMSYS_IOC_MAGIC, 9, camsys_irqsta_t)
+#define CAMSYS_IRQDISCONNECT _IOW(CAMSYS_IOC_MAGIC, 10, camsys_irqcnnt_t)
+
+#define CAMSYS_QUREYMEM _IOR(CAMSYS_IOC_MAGIC, 11, camsys_querymem_t)
+#endif