diff options
Diffstat (limited to 'drivers/media/sprd_isp/isp1.0')
| -rw-r--r-- | drivers/media/sprd_isp/isp1.0/Shark_reg_isp.h | 70 | ||||
| -rw-r--r-- | drivers/media/sprd_isp/isp1.0/Tiger_reg_isp.h | 91 | ||||
| -rw-r--r-- | drivers/media/sprd_isp/isp1.0/compat_isp_drv_kernel.c | 327 | ||||
| -rw-r--r-- | drivers/media/sprd_isp/isp1.0/compat_isp_drv_kernel.h | 26 | ||||
| -rw-r--r-- | drivers/media/sprd_isp/isp1.0/isp_drv_kernel.c | 1494 | ||||
| -rw-r--r-- | drivers/media/sprd_isp/isp1.0/isp_drv_null.c | 305 |
6 files changed, 2313 insertions, 0 deletions
diff --git a/drivers/media/sprd_isp/isp1.0/Shark_reg_isp.h b/drivers/media/sprd_isp/isp1.0/Shark_reg_isp.h new file mode 100644 index 00000000..6b99f9ea --- /dev/null +++ b/drivers/media/sprd_isp/isp1.0/Shark_reg_isp.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2012 Spreadtrum Communications Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef _TIGER_REG_ISP_H_ +#define _TIGER_REG_ISP_H_ +#ifndef CONFIG_64BIT +#include <soc/sprd/globalregs.h> +#else +#include <soc/sprd/irqs.h> +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + +#define ISP_DCAM_BASE DCAM_BASE +#define ISP_DCAM_INT_STS (ISP_DCAM_BASE + 0x003CUL) +#define ISP_DCAM_INT_CLR (ISP_DCAM_BASE + 0x0044UL) + +#define ISP_BASE_ADDR ISP_BASE +#define ISP_LNC_STATUS (ISP_BASE_ADDR+0x0200UL) +#define ISP_LNC_LOAD (ISP_BASE_ADDR+0x0220UL) +#define ISP_AXI_MASTER (ISP_BASE_ADDR+0x2000UL) +#define ISP_INT_RAW (ISP_BASE_ADDR+0x2080UL) +#define ISP_INT_STATUS (ISP_BASE_ADDR+0x2084UL) +#define ISP_INT_EN (ISP_BASE_ADDR+0x2078UL) +#define ISP_INT_CLEAR (ISP_BASE_ADDR+0x207cUL) +#define ISP_REG_MAX_SIZE SPRD_ISP_SIZE +#define ISP_AXI_MASTER_STOP (ISP_BASE_ADDR + 0X2054UL) + +#define ISP_AHB_BASE SPRD_MMAHB_BASE +#define ISP_MODULE_EB (ISP_AHB_BASE + 0x0000UL) +#define ISP_MODULE_RESET (ISP_AHB_BASE + 0x0004UL) +#define ISP_CORE_CLK_EB (ISP_AHB_BASE + 0x0008UL) + +#define ISP_CLOCK_BASE SPRD_MMCKG_BASE +#define ISP_CLOCK (ISP_CLOCK_BASE + 0X34) + + +/*irq line number in system*/ +#define ISP_IRQ IRQ_ISP_INT + +#define ISP_EB_BIT BIT_2 +#define ISP_RST_LOG_BIT BIT_2 +#define ISP_RST_CFG_BIT BIT_3 +#define ISP_CORE_CLK_EB_BIT BIT_4 +#define ISP_AXI_MASTER_STOP_BIT BIT_0 + +#define ISP_IRQ_HW_MASK_V0001 (0x1fffffff) +#define ISP_IRQ_NUM_V0001 (29) +#define ISP_TMP_BUF_SIZE_MAX_V0001 (32 * 1024) + +#ifdef __cplusplus +} +#endif + +#endif //_TIGER_REG_ISP_H_ diff --git a/drivers/media/sprd_isp/isp1.0/Tiger_reg_isp.h b/drivers/media/sprd_isp/isp1.0/Tiger_reg_isp.h new file mode 100644 index 00000000..d68a8ff9 --- /dev/null +++ b/drivers/media/sprd_isp/isp1.0/Tiger_reg_isp.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2012 Spreadtrum Communications Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef _TIGER_REG_ISP_H_ +#define _TIGER_REG_ISP_H_ +#include <mach/globalregs.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define BIT_0 0x01 +#define BIT_1 0x02 +#define BIT_2 0x04 +#define BIT_3 0x08 +#define BIT_4 0x10 +#define BIT_5 0x20 +#define BIT_6 0x40 +#define BIT_7 0x80 +#define BIT_8 0x0100 +#define BIT_9 0x0200 +#define BIT_10 0x0400 +#define BIT_11 0x0800 +#define BIT_12 0x1000 +#define BIT_13 0x2000 +#define BIT_14 0x4000 +#define BIT_15 0x8000 +#define BIT_16 0x010000 +#define BIT_17 0x020000 +#define BIT_18 0x040000 +#define BIT_19 0x080000 +#define BIT_20 0x100000 +#define BIT_21 0x200000 +#define BIT_22 0x400000 +#define BIT_23 0x800000 +#define BIT_24 0x01000000 +#define BIT_25 0x02000000 +#define BIT_26 0x04000000 +#define BIT_27 0x08000000 +#define BIT_28 0x10000000 +#define BIT_29 0x20000000 +#define BIT_30 0x40000000 +#define BIT_31 0x80000000 + + +#define ISP_DCAM_BASE DCAM_BASE +#define ISP_DCAM_INT_STS (ISP_DCAM_BASE + 0x0030UL) +#define ISP_DCAM_INT_CLR (ISP_DCAM_BASE + 0x0038UL) + +#define ISP_BASE_ADDR ISP_BASE +#define ISP_LNC_LOAD (ISP_BASE_ADDR+0x0220UL) +#define ISP_AXI_MASTER (ISP_BASE_ADDR+0x2000UL) +#define ISP_INT_RAW (ISP_BASE_ADDR+0x2080UL) +#define ISP_INT_STATUS (ISP_BASE_ADDR+0x2084UL) +#define ISP_INT_EN (ISP_BASE_ADDR+0x2078UL) +#define ISP_INT_CLEAR (ISP_BASE_ADDR+0x207cUL) +#define ISP_REG_MAX_SIZE SPRD_ISP_SIZE + +#define ISP_AHB_BASE SPRD_AHB_BASE +#define ISP_AHB_CTL0 (ISP_AHB_BASE + 0x0200UL) +#define ISP_MODULE_EB (ISP_AHB_CTL0 + 0x0000UL) +#define ISP_MODULE_RESET (ISP_AHB_CTL0 + 0x0010UL) + +#define ISP_CORE_CLK_EB (ISP_AHB_BASE + 0x0208UL) + +/*irq line number in system*/ +#define ISP_IRQ IRQ_ISP_INT +#define DCAM_IRQ IRQ_DCAM_INT + +#define ISP_EB_BIT BIT_12 +#define ISP_RST_BIT BIT_8 +#define ISP_CORE_CLK_EB_BIT BIT_7 +#define ISP_IRQ_HW_MASK_V0000 (0xfff) +#define ISP_IRQ_NUM_V0000 (12) +#define ISP_TMP_BUF_SIZE_MAX_V0000 (36 * 1024) + +#ifdef __cplusplus +} +#endif + +#endif //_TIGER_REG_ISP_H_
\ No newline at end of file diff --git a/drivers/media/sprd_isp/isp1.0/compat_isp_drv_kernel.c b/drivers/media/sprd_isp/isp1.0/compat_isp_drv_kernel.c new file mode 100644 index 00000000..ae0ad4f0 --- /dev/null +++ b/drivers/media/sprd_isp/isp1.0/compat_isp_drv_kernel.c @@ -0,0 +1,327 @@ +#include <linux/compat.h> +#include <linux/fs.h> +#include <linux/uaccess.h> +#include <video/isp_drv_kernel.h> +#include "compat_isp_drv_kernel.h" + +struct compat_isp_irq_param { + compat_uint_t isp_irq_val; + compat_uint_t dcam_irq_val; + compat_uint_t irq_val; + compat_int_t ret_val; +}; + +struct compat_isp_reg_bits { + compat_ulong_t reg_addr; + compat_ulong_t reg_value; +} ; + +struct compat_isp_reg_param { + compat_ulong_t reg_param; + uint32_t counts; +} ; + + +#define COMPAT_ISP_IO_READ _IOR(ISP_IO_MAGIC, 1, struct compat_isp_reg_param) +#define COMPAT_ISP_IO_WRITE _IOW(ISP_IO_MAGIC, 2, struct compat_isp_reg_param) +#define COMPAT_ISP_IO_LNC_PARAM _IOW(ISP_IO_MAGIC, 8, struct compat_isp_reg_param) +#define COMPAT_ISP_IO_LNC _IOW(ISP_IO_MAGIC, 9, struct compat_isp_reg_param) +#define COMPAT_ISP_IO_ALLOC _IOW(ISP_IO_MAGIC, 10, struct compat_isp_reg_param) + + +static int compat_get_rw_param( + struct compat_isp_reg_param __user *data32, + struct isp_reg_param __user *data) +{ + int err = 0; + compat_ulong_t addr; + uint32_t cnt; + + err = get_user(addr, &data32->reg_param); + err |= put_user(addr, &data->reg_param); + err |= get_user(cnt, &data32->counts); + err |= put_user(cnt, &data->counts); + + //printk("compat_get_rw_param, addr: 0x%x data32->reg_param: 0x%x data->reg_param: 0x%lx cnt: %d\n", + // addr, data32->reg_param, data->reg_param, cnt); + + return err; +} + +static int compat_get_rw_param_detail(struct isp_reg_param __user *data) +{ + struct compat_isp_reg_bits __user *data32; + struct isp_reg_bits __user *reg_data; + int err = 0; + int i = 0; + int cnt = data->counts; + compat_ulong_t addr; + compat_ulong_t val; + struct isp_reg_bits __user *data_tmp; + + data32 = compat_ptr(data->reg_param); +// printk("compat_get_rw_param_detail param: %p cnt %d\n", data32, cnt); + reg_data = (struct isp_reg_bits __user*)((unsigned long)data + sizeof(struct isp_reg_param)); + data->reg_param = reg_data; + if (reg_data == NULL) { + printk("compat_isp_k failed to compat_alloc_user_space \n"); + return -EFAULT; + } +// printk("compat_get_rw_param_detail param: data %p \n", reg_data); + data_tmp = reg_data; + for (i=0 ; i< cnt; i++) { + err = get_user(addr, &data32->reg_addr); + err |= put_user(addr, &data_tmp->reg_addr); + err |= get_user(val, &data32->reg_value); + err |= put_user(val, &data_tmp->reg_value); + if (err) { + printk("compat_isp_k, read_param_detail failed cnt %d ret %d\n", cnt, err); + break; + } + data32++; + data_tmp++; + } + return err; +} + +static int compat_put_read_param( + struct compat_isp_reg_param __user *data32, + struct isp_reg_param __user *data) + +{ + int err = 0; + compat_ulong_t val; + uint32_t cnt; + int i = 0; + struct compat_isp_reg_bits __user *reg_data32; + struct isp_reg_bits __user *reg_data; + + cnt = data->counts; + reg_data32 = (struct compat_isp_reg_bits __user *)data32->reg_param; + reg_data = (struct isp_reg_bits __user *)data->reg_param; + for (i=0 ; i<cnt; i++) { + err = get_user(val, ®_data->reg_value); + err |= put_user(val, ®_data32->reg_value); + if (err) { + printk("compat_isp_k, compat_put_read_param ret %d\n", err); + break; + } + reg_data32++; + reg_data++; + } + + return err; +} + +static int compat_get_alloc_param( + struct compat_isp_reg_param __user *data32, + struct isp_reg_param __user *data) +{ + int err = 0; + compat_ulong_t addr; + uint32_t cnt; + struct compat_isp_reg_bits __user *reg_data32; + struct isp_reg_bits __user *reg_data; + + err = get_user(addr, &data32->reg_param); + err |= put_user(addr, &data->reg_param); + err |= get_user(cnt, &data32->counts); + err |= put_user(cnt, &data->counts); + + return err; +} + +static int compat_put_alloc( + struct compat_isp_reg_param __user *data32, + struct isp_reg_param __user *data) + +{ + int err = 0; + compat_ulong_t addr; + uint32_t cnt; + struct compat_isp_reg_bits __user *reg_data32; + struct isp_reg_bits __user *reg_data; + + err = get_user(addr, &data->reg_param); + err |= put_user(addr, &data32->reg_param); + err |= get_user(cnt, &data->counts); + err |= put_user(cnt, &data32->counts); + + return err; +} + + + + +long compat_isp_kernel_ioctl( struct file *fl, unsigned int cmd, unsigned long param) +{ + long ret; + int err = 0; + void __user *up = compat_ptr(param); + + if(ISP_IO_IRQ == cmd) { + ret = fl->f_op->unlocked_ioctl(fl, cmd, (unsigned long)up); + } else { + switch (cmd) { + case COMPAT_ISP_IO_READ: + { + struct compat_isp_reg_param __user *data32; + struct isp_reg_param __user *data; + uint32_t cnt; + + + data32 = compat_ptr(param); + err = get_user(cnt, &data32->counts); + +// printk("COMPAT_ISP_IO_WRITE param: %p \n", data32); + data = compat_alloc_user_space(sizeof(struct isp_reg_param)+cnt*sizeof(struct isp_reg_bits)); + if (data == NULL) { + printk("compat_isp_k failed to compat_alloc_user_space \n"); + return -EFAULT; + } +// printk("@@1 %p", data); + err = compat_get_rw_param(data32, data); + if (err) { + return err; + } + err = compat_get_rw_param_detail(data); + if (err) { + printk("compat_isp_k error %d\n", err); + return err; + } + err = fl->f_op->unlocked_ioctl(fl, ISP_IO_READ, (unsigned long)data); + err = compat_put_read_param(data32, data); + ret = ret ? ret : err; + break; + } + case COMPAT_ISP_IO_WRITE: + { + struct compat_isp_reg_param __user *data32; + struct isp_reg_param __user *data; + uint32_t cnt; + + + data32 = compat_ptr(param); + err = get_user(cnt, &data32->counts); + +// printk("COMPAT_ISP_IO_WRITE param: %p \n", data32); + data = compat_alloc_user_space(sizeof(struct isp_reg_param)+cnt*sizeof(struct isp_reg_bits)); + if (data == NULL) { + printk("compat_isp_k failed to compat_alloc_user_space \n"); + return -EFAULT; + } +// printk("@@1 %p", data); + err = compat_get_rw_param(data32, data); + if (err) { + return err; + } + err = compat_get_rw_param_detail(data); + if (err) { + printk("compat_isp_k error %d\n", err); + return err; + } + err = fl->f_op->unlocked_ioctl(fl, ISP_IO_WRITE, (unsigned long)data); + break; + } + case COMPAT_ISP_IO_LNC_PARAM: + { + struct compat_isp_reg_param __user *data32; + struct isp_reg_param __user *data; + char __user *lnc_data; + + + data32 = compat_ptr(param); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) { + printk("compat_isp_k failed to compat_alloc_user_space \n"); + return -EFAULT; + } + err = compat_get_rw_param(data32, data); + if (err) { + printk("compat_isp_k COMPAT_ISP_IO_LNC_PARAM error\n"); + return err; + } + /*lnc_data = compat_alloc_user_space(sizeof(*lnc_data)*data->counts); + data->reg_param = (unsigned long)lnc_data; + ret = copy_from_user((void*)data->reg_param, (void*)data32->reg_param, data->counts); + if (ret) { + return ret; + }*/ +// printk("test 123\n"); + ret = fl->f_op->unlocked_ioctl(fl, ISP_IO_LNC_PARAM, (unsigned long)data); +// printk("test 123 end\n"); + break; + } + case COMPAT_ISP_IO_LNC: + { + struct compat_isp_reg_param __user *data32; + struct isp_reg_param __user *data; + uint32_t cnt; + + + data32 = compat_ptr(param); + err = get_user(cnt, &data32->counts); + +// printk("COMPAT_ISP_IO_WRITE param: %p \n", data32); + data = compat_alloc_user_space(sizeof(struct isp_reg_param)+cnt*sizeof(struct isp_reg_bits)); + if (data == NULL) { + printk("compat_isp_k failed to compat_alloc_user_space \n"); + return -EFAULT; + } +// printk("@@1 %p", data); + err = compat_get_rw_param(data32, data); + if (err) { + return err; + } + err = compat_get_rw_param_detail(data); + if (err) { + printk("compat_isp_k error %d\n", err); + return err; + } + // printk("test ISP_IO_LNC\n"); + err = fl->f_op->unlocked_ioctl(fl, ISP_IO_LNC, (unsigned long)data); + // printk("test ISP_IO_LNC end\n"); + break; + } + case COMPAT_ISP_IO_ALLOC: + { + struct compat_isp_reg_param __user *data32; + struct isp_reg_param __user *data; + + data32 = compat_ptr(param); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) { + printk("compat_isp_k failed to compat_alloc_user_space \n"); + return -EFAULT; + } + err = compat_get_alloc_param(data32, data); + if (err) { + return err; + } + ret = fl->f_op->unlocked_ioctl(fl, ISP_IO_ALLOC, (unsigned long)data); + if (ret) { + printk("compat_isp_k,failed to ISP_IO_ALLOC %ld", ret); + goto exit; + } + err = compat_put_alloc(data32, data); + ret = err; + break; + } + + case ISP_IO_RST: + case ISP_IO_SETCLK: + case ISP_IO_STOP: + case ISP_IO_INT: + case ISP_IO_DCAM_INT: + { + ret = fl->f_op->unlocked_ioctl(fl, cmd, (unsigned long)up); + break; + } + default: + printk("compat_isp_k, don't support cmd 0x%x", cmd); + break; + } + } +exit: + return ret; +} diff --git a/drivers/media/sprd_isp/isp1.0/compat_isp_drv_kernel.h b/drivers/media/sprd_isp/isp1.0/compat_isp_drv_kernel.h new file mode 100644 index 00000000..a24cce52 --- /dev/null +++ b/drivers/media/sprd_isp/isp1.0/compat_isp_drv_kernel.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2012 Spreadtrum Communications Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef _COMPAT_ISP_DRV_KERNEL_H_ +#define _COMPAT_ISP_DRV_KERNEL_H_ + +#if IS_ENABLED(CONFIG_COMPAT) + +long compat_isp_kernel_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); + +#else + +#define compat_isp_kernel_ioctl NULL + +#endif /* CONFIG_COMPAT */ + +#endif diff --git a/drivers/media/sprd_isp/isp1.0/isp_drv_kernel.c b/drivers/media/sprd_isp/isp1.0/isp_drv_kernel.c new file mode 100644 index 00000000..9a6acbef --- /dev/null +++ b/drivers/media/sprd_isp/isp1.0/isp_drv_kernel.c @@ -0,0 +1,1494 @@ +/* + * Copyright (C) 2012 Spreadtrum Communications Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + #include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/poll.h> +#include <linux/fs.h> +#include <linux/irq.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/miscdevice.h> +#include <asm/io.h> +#include <linux/file.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/types.h> +#include <linux/string.h> +#include <linux/sched.h> +#include <linux/spinlock_types.h> +#include <linux/semaphore.h> +#include <linux/delay.h> +#include <linux/proc_fs.h> +#include <video/isp_drv_kernel.h> +#include <soc/sprd/sci.h> +#include <linux/clk.h> +#include <asm/cacheflush.h> +#ifndef CONFIG_64BIT +#include <soc/sprd/hardware.h> +#endif +#include "compat_isp_drv_kernel.h" +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/vmalloc.h> +#include <linux/kthread.h> + +#include "Shark_reg_isp.h" +#include "parse_hwinfo.h" + + +#define DEBUG_ISP_DRV +#ifdef DEBUG_ISP_DRV +#define ISP_PRINT printk +#else +#define ISP_PRINT(...) +#endif + +#define ISP_QUEUE_LENGTH 16 +#define SA_SHIRQ IRQF_SHARED +static uint32_t g_isp_irq = 0x12345678;/*for share irq handler function*/ +//static uint32_t g_dcam_irq = 0x12345678;/*for share irq handler function*/ + +#define ISP_MINOR MISC_DYNAMIC_MINOR/*isp minor number*/ +#define init_MUTEX(sem) sema_init(sem, 1) +#define init_MUTEX_LOCKED(sem) sema_init(sem, 0) +#define IO_PTR volatile void __iomem * +#define ISP_READL(a) __raw_readl((IO_PTR)a) +#define ISP_WRITEL(a,v) __raw_writel(v,(IO_PTR)a) +#define ISP_OWR(a,v) __raw_writel((__raw_readl((IO_PTR)a) | v), (IO_PTR)a) +#define ISP_AWR(a,v) __raw_writel((__raw_readl((IO_PTR)a) & v), (IO_PTR)a) +#define ISP_NAWR(a,v) __raw_writel((__raw_readl((IO_PTR)a) & ~v), (IO_PTR)a) +#define ISP_REG_RD(a) ISP_READL(((IO_PTR)a)) +#define DEBUG_STR "Error L %d, %s \n" +#define DEBUG_ARGS __LINE__,__FUNCTION__ +#define ISP_LOWEST_ADDR 0x800 +#define ISP_ADDR_INVALID(addr) ((unsigned long)(addr) < (unsigned long)ISP_LOWEST_ADDR) +#define ISP_CHECK_ZERO(a) \ + do { \ + if (ISP_ADDR_INVALID(a)) { \ + printk("isp_k, zero pointer \n"); \ + printk(DEBUG_STR, DEBUG_ARGS); \ + return -EFAULT; \ + } \ + } while(0) + +#define ISP_CHECK_ZERO_VOID(a) \ + do { \ + if (ISP_ADDR_INVALID(a)) { \ + printk("isp_k, zero pointer \n"); \ + printk(DEBUG_STR, DEBUG_ARGS); \ + return; \ + } \ + } while(0) + +#define ISP_DCAM_IRQ_MASK 0x03 +#define ISP_DCAM_IRQ_NUM 0x02 +#define ISP_BUF_MAX_SIZE ISP_TMP_BUF_SIZE_MAX_V0001 +#define ISP_IRQ_NUM ISP_IRQ_NUM_V0001 +#define ISP_IRQ_HW_MASK ISP_IRQ_HW_MASK_V0001 +#define ISP_TIME_OUT_MAX (500) + +struct isp_node { + uint32_t isp_irq_val; + uint32_t dcam_irq_val; + uint64_t system_time; +}; + +struct isp_queue { + struct isp_node node[ISP_QUEUE_LENGTH]; + struct isp_node *write; + struct isp_node *read; +}; + +struct isp_lnc_load { + uint8_t load_lnc_flag; + uint8_t cap_eof_flag; + uint32_t param_counts; + unsigned long load_buf; + struct semaphore load_done_sem; +}; +struct isp_device_t +{ + unsigned long reg_base_addr;/*the pointer of isp register context*/ + uint32_t size;/* struct size*/ + unsigned long buf_addr; + uint32_t buf_len; + struct isp_queue queue; + struct semaphore sem_isr;/*for interrupts*/ + struct semaphore sem_isp;/*for the isp device, protect the isp hardware; protect only one caller use the oi*/ + /*controll/read/write functions*/ + struct clk* s_isp_clk_mm_i; + struct clk *s_isp_clk; + struct semaphore kernel_sem; + struct task_struct* kernel_thread; + struct isp_lnc_load lnc_load; + uint32_t is_kernel_thread_stop; +}; +enum dcam_irq_id { + DCAM_SN_SOF = 0, + DCAM_SN_EOF, + DCAM_CAP_SOF, + DCAM_CAP_EOF, + DCAM_PATH0_DONE, + DCAM_PATH0_OV, + DCAM_PATH1_DONE, + DCAM_PATH1_OV, + DCAM_PATH2_DONE, + DCAM_PATH2_OV, + DCAM_SN_LINE_ERR, + DCAM_SN_FRAME_ERR, + DCAM_JPEG_BUF_OV, + DCAM_ISP_OV, + DCAM_MIPI_OV, + DCAM_ROT_DONE, + DCAM_PATH1_SLICE_DONE, + DCAM_PATH2_SLICE_DONE, + DCAM_RAW_SLICE_DONE, + DCAM_PATH1_SOF, + DCAM_PATH2_SOF, + DCAM_IRQ_NUMBER +}; +struct dcam_frame { + uint32_t type; + uint32_t lock; + uint32_t flags; + uint32_t fid; + uint32_t width; + uint32_t height; + uint32_t yaddr; + uint32_t uaddr; + uint32_t vaddr; + struct dcam_frame *prev; + struct dcam_frame *next; +}; +typedef int (*dcam_isr_func)(struct dcam_frame* frame, void* u_data); +extern int32_t dcam_reg_isr(enum dcam_irq_id id, dcam_isr_func user_func, void* user_data); + +static atomic_t s_isp_users = ATOMIC_INIT(0); +static struct mutex s_isp_lock; /*for the isp driver, protect the isp module; protect only one user open this module*/ +static struct proc_dir_entry* isp_proc_file; +static struct isp_device_t *g_isp_dev_ptr = NULL; + +uint32_t s_dcam_int_eb = 0x00; +unsigned long s_isp_alloc_addr = 0x00; +uint32_t s_isp_alloc_order = 0x00; +uint32_t s_isp_alloc_len = 0x00; + +static DEFINE_SPINLOCK(isp_spin_lock); +static int32_t _isp_set_clk(enum isp_clk_sel clk_sel); +static int32_t _isp_module_eb(void); +static int32_t _isp_module_dis(void); +static int _isp_registerirq(void); +static void _isp_unregisterirq(void); +static irqreturn_t _isp_irq_root(int irq, void *dev_id); +void _dcam_isp_root(void); +static int _isp_queue_init(struct isp_queue *queue); +static int _isp_queue_write(struct isp_queue *queue, struct isp_node *node); +static int _isp_queue_read(struct isp_queue *queue, struct isp_node *node); +static inline void _isp_regread(char *dst, char *src, size_t n); +static inline void _isp_regwrite(char *dst, char *src, size_t n); +static void _read_reg(struct isp_reg_bits *reg_bits_ptr, uint32_t counts); +static void _write_reg(struct isp_reg_bits *reg_bits_ptr, uint32_t counts); + +/**file operation functions declare**/ +static int32_t _isp_kernel_open(struct inode *node, struct file *filp); +static int32_t _isp_kernel_release(struct inode *node, struct file *filp); +static long _isp_kernel_ioctl( struct file *fl, unsigned int cmd, unsigned long param); +/**driver' functions declare**/ +static int32_t _isp_probe(struct platform_device *pdev); +static int32_t _isp_remove(struct platform_device *dev); +/**module' functions declare**/ +static int32_t __init isp_kernel_init(void); +static void isp_kernel_exit(void); +static int32_t _isp_lnc_param_load_ex(struct isp_reg_bits *reg_bits_ptr, uint32_t counts); +static int _isp_stop_kernel_thread(void* param); + +static struct file_operations isp_fops = { + .owner = THIS_MODULE, + .open = _isp_kernel_open, + .unlocked_ioctl = _isp_kernel_ioctl, + .compat_ioctl = compat_isp_kernel_ioctl, + .release = _isp_kernel_release, +}; + +static struct miscdevice isp_dev = { + .minor = ISP_MINOR, + .name = "sprd_isp", + .fops = &isp_fops, +}; + +static const struct of_device_id of_match_table_isp[] = { + { .compatible = "sprd,sprd_isp", }, + { }, +}; + +static struct platform_driver isp_driver = { + .probe = _isp_probe, + .remove = _isp_remove, + .driver = { + .owner = THIS_MODULE, + .name = "sprd_isp", + .of_match_table = of_match_ptr(of_match_table_isp), + }, +}; + +static int32_t _isp_get_systemtime(struct timeval *tv) +{ + struct timespec ts; + + ktime_get_ts(&ts); + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; + return 0; +} + +static int32_t _isp_module_eb(void) +{ + int32_t ret = 0; + + if (0x01 == atomic_inc_return(&s_isp_users)) { + + ret = clk_mm_i_eb(isp_dev.this_device->of_node,1); + ret = _isp_set_clk(ISP_CLK_312M); + if (unlikely(0 != ret)) { + ISP_PRINT("isp_k: set clock error\n"); + ret = -EIO; + } + } + + ISP_PRINT("_isp_module_eb: end\n"); + + return ret; +} + +static int32_t _isp_module_dis(void) +{ + int32_t ret = 0; + + if (0x00 == atomic_dec_return(&s_isp_users)) { + + ret = _isp_set_clk(ISP_CLK_NONE); + if (unlikely(0 != ret)) { + ISP_PRINT("isp_k: close clock error\n"); + ret = -EFAULT; + return ret; + } + ret = clk_mm_i_eb(isp_dev.this_device->of_node,0); + } + return ret; +} + +static int32_t _isp_module_rst(void) +{ + int32_t ret = 0; + uint32_t reg_value=0x00; + int32_t time_out_cnt = 0; + + if (0x00 != atomic_read(&s_isp_users)) { + + ISP_OWR(ISP_AXI_MASTER_STOP, BIT_0); + + reg_value=ISP_READL(ISP_AXI_MASTER); + while((0x00==(reg_value&0x08)) && (time_out_cnt < (ISP_TIME_OUT_MAX * 2))) + { + time_out_cnt++; + udelay(50); + reg_value=ISP_READL(ISP_AXI_MASTER); + } + if (time_out_cnt >= ISP_TIME_OUT_MAX) { + ret = -1; + ISP_PRINT("_isp_module_rst: time out\n"); + } + + ISP_WRITEL(ISP_INT_CLEAR, ISP_IRQ_HW_MASK); + + sci_glb_set(ISP_MODULE_RESET, ISP_RST_LOG_BIT); + sci_glb_set(ISP_MODULE_RESET, ISP_RST_CFG_BIT); + sci_glb_set(ISP_MODULE_RESET, ISP_RST_LOG_BIT); + sci_glb_set(ISP_MODULE_RESET, ISP_RST_CFG_BIT); + sci_glb_set(ISP_MODULE_RESET, ISP_RST_LOG_BIT); + sci_glb_set(ISP_MODULE_RESET, ISP_RST_CFG_BIT); + + sci_glb_clr(ISP_MODULE_RESET, ISP_RST_CFG_BIT); + sci_glb_clr(ISP_MODULE_RESET, ISP_RST_LOG_BIT); + } + + ISP_PRINT("_isp_module_rst: exit\n"); + + return 0; +} + +void* _isp_cap_eof(struct dcam_frame* frame, void* u_data) +{ + struct isp_device_t * p_isp = (struct isp_device_t *)u_data; + if (p_isp) { + p_isp->lnc_load.cap_eof_flag = 1; + if (p_isp->lnc_load.load_lnc_flag) { + up(&p_isp->kernel_sem); + p_isp->lnc_load.load_lnc_flag = 0; + } else { + } + } +} +int _isp_kernel_proc(void *arg) +{ + struct isp_device_t *dev = (struct isp_device_t*)arg; + int32_t time_out_cnt = 0; + uint32_t reg_value=0x00; + int ret = 0; + struct isp_reg_bits *reg_bits_ptr; + uint32_t counts; + while(1) { + if (0 == down_interruptible(&dev->kernel_sem)) { + if (dev->is_kernel_thread_stop) { + printk("isp_k: _isp_kernel_proc stop \n"); + break; + } + reg_bits_ptr = (struct isp_reg_bits*) g_isp_dev_ptr->lnc_load.load_buf; + counts = g_isp_dev_ptr->lnc_load.param_counts; + ret = _isp_lnc_param_load_ex(reg_bits_ptr, counts); + memset((void *)g_isp_dev_ptr->lnc_load.load_buf, 0x00, ISP_BUF_MAX_SIZE); + } + } + dev->is_kernel_thread_stop = 0; + return 0; +} +int _isp_kernel_thread(void* param) +{ + struct isp_device_t *dev = (struct isp_device_t*)param; + if (dev == NULL) { + printk("isp_k: _isp_kernel_thread, dev is NULL \n"); + return -1; + } + dev->lnc_load.load_lnc_flag = 0; + dev->lnc_load.cap_eof_flag = 0; + dev->is_kernel_thread_stop = 0; + sema_init(&dev->kernel_sem, 0); + sema_init(&dev->lnc_load.load_done_sem, 0); + dev->kernel_thread = kthread_run(_isp_kernel_proc, param, "isp_kernel_proc_thread"); + if (IS_ERR(dev->kernel_thread)) { + printk("isp_k: _isp_kernel_thread error!\n"); + return -1; + } + return 0; +} +static int _isp_stop_kernel_thread(void* param) +{ + struct isp_device_t *dev = (struct isp_device_t*)param; + int cnt = 0; + if (dev == NULL) { + printk("SPRD_IMG: sprd_img_opt_flash, dev is NULL \n"); + return -1; + } + if (dev->kernel_thread) { + dev->is_kernel_thread_stop = 1; + up(&dev->kernel_sem); + if (0 != dev->is_kernel_thread_stop) { + while (cnt < 500) { + cnt++; + if (0 == dev->is_kernel_thread_stop) + break; + msleep(1); + } + } + dev->kernel_thread = NULL; + } + return 0; +} +static int32_t _isp_lnc_param_load_ex(struct isp_reg_bits *reg_bits_ptr, uint32_t counts) +{ + int32_t ret = 0; + int32_t time_out_cnt = 0; + volatile uint32_t reg_value=0x00; + + if((0x00!=s_isp_alloc_addr) + &&(0x00!=s_isp_alloc_len)) { + + void *ptr = (void*)s_isp_alloc_addr; + uint32_t len=s_isp_alloc_len; + + #ifndef CONFIG_64BIT + dmac_flush_range(ptr, ptr + len); + outer_flush_range(__pa(ptr), __pa(ptr) + len); + #endif + + reg_bits_ptr->reg_value=(uint32_t)__pa(reg_bits_ptr->reg_value); +//#if defined(CONFIG_MACH_CORE3) + + + reg_value=ISP_READL(ISP_LNC_STATUS); + while((0x00==(reg_value&ISP_LNC_STATUS_OK)) && (time_out_cnt < (ISP_TIME_OUT_MAX*1000))) { + udelay(1); + reg_value=ISP_READL(ISP_LNC_STATUS); + time_out_cnt++; + } + if (time_out_cnt >= (ISP_TIME_OUT_MAX*1000)) { + ret = -1; + ISP_PRINT("isp_k: isp lnc status time out\n"); + } + ISP_OWR(ISP_INT_EN, ISP_INT_LENS_LOAD); + _write_reg(reg_bits_ptr, counts); + }else { + ISP_PRINT("isp_k: isp load lnc param error\n"); + } + return ret; +} +static int32_t _isp_lnc_param_load(struct isp_reg_bits *reg_bits_ptr, uint32_t counts) +{ + int32_t ret = 0; + int32_t time_out_cnt = 0; + uint32_t reg_value=0x00; + printk("isp_k: _isp_lnc_param_load \n"); + if((0x00!=s_isp_alloc_addr) + &&(0x00!=s_isp_alloc_len)) { + void *ptr = (void*)s_isp_alloc_addr; + uint32_t len=s_isp_alloc_len; + #ifndef CONFIG_64BIT + dmac_flush_range(ptr, ptr + len); + outer_flush_range(__pa(ptr), __pa(ptr) + len); + #endif + reg_bits_ptr->reg_value=(uint32_t)__pa(reg_bits_ptr->reg_value); + { + unsigned long flags; + reg_value=ISP_READL(ISP_LNC_STATUS); + while((0x00==(reg_value&ISP_LNC_STATUS_OK)) && (time_out_cnt < (ISP_TIME_OUT_MAX*1000))) { + udelay(1); + reg_value=ISP_READL(ISP_LNC_STATUS); + time_out_cnt++; + } + if (time_out_cnt >= (ISP_TIME_OUT_MAX*1000)) { + ret = -1; + ISP_PRINT("isp_k: isp lnc status time out\n"); + } + _write_reg(reg_bits_ptr, counts); + printk("isp_k: load, 0x%x: 0x%x, 0x%x, counts %d \n", reg_bits_ptr, reg_bits_ptr->reg_addr, reg_bits_ptr->reg_value, counts); + } + + time_out_cnt = 0; + reg_value=ISP_READL(ISP_INT_RAW); + + while ((0x00 == (reg_value&ISP_INT_LENS_LOAD)) && (time_out_cnt < ISP_TIME_OUT_MAX)) { + udelay(1); + reg_value=ISP_READL(ISP_INT_RAW); + time_out_cnt++; + } + if (time_out_cnt >= ISP_TIME_OUT_MAX) { + ret = -1; + ISP_PRINT("isp_k: isp load lnc param time out\n"); + } + ISP_OWR(ISP_INT_CLEAR, ISP_INT_LENS_LOAD); + }else { + ISP_PRINT("isp_k: isp load lnc param error\n"); + } + + return ret; +} + +static int32_t _isp_lnc_param_set(uint32_t* addr, uint32_t len) +{ + int32_t ret = 0; + + if((0x00!=s_isp_alloc_addr) + &&(0x00!=addr)) { + memcpy((void*)s_isp_alloc_addr, (void*)addr, len); + } + + return ret; +} + +static int32_t _isp_free(void) +{ + int32_t ret = 0; + + if((0x00!=s_isp_alloc_addr) + &&(0x00!=s_isp_alloc_order)) { + free_pages(s_isp_alloc_addr, s_isp_alloc_order); + s_isp_alloc_order = 0x00; + s_isp_alloc_addr = 0x00; + s_isp_alloc_len=0x00; + } + + return ret; +} + +static int32_t _isp_alloc(unsigned long* addr, uint32_t len) +{ + int32_t ret = 0x00; + unsigned long buf=0x00; + void *ptr = 0x00; + + if((0x00!=s_isp_alloc_addr) + &&(len<=s_isp_alloc_len)) { + *addr = s_isp_alloc_addr; + } else { + _isp_free(); + } + + if(0x00==s_isp_alloc_addr) { + s_isp_alloc_len=len; + s_isp_alloc_order = get_order(len); + s_isp_alloc_addr = __get_free_pages(GFP_KERNEL | __GFP_COMP, s_isp_alloc_order); + if (NULL == (void*)s_isp_alloc_addr) { + ISP_PRINT("ISP_RAW:_isp_alloc order:0x%x, addr:0x%lx, len:0x%x error\n", s_isp_alloc_order, s_isp_alloc_addr, s_isp_alloc_len); + return 1; + } + ptr = (void*)s_isp_alloc_addr; + *addr = s_isp_alloc_addr; + buf = virt_to_phys((volatile void *)s_isp_alloc_addr); + + #ifndef CONFIG_64BIT + dmac_flush_range(ptr, ptr + len); + outer_flush_range(__pa(ptr), __pa(ptr) + len); + #endif + } + + return ret; +} + +static int32_t _isp_set_clk(enum isp_clk_sel clk_sel) +{ + struct clk *clk_parent; + char *parent = "clk_256m"; + int32_t rtn = 0; + + ISP_CHECK_ZERO(g_isp_dev_ptr); + +#ifdef CONFIG_SC_FPGA + return 0; +#endif + + switch (clk_sel) { + case ISP_CLK_312M: + parent = "clk_312m"; + break; + case ISP_CLK_256M: + parent = "clk_256m"; + break; + case ISP_CLK_128M: + parent = "clk_128m"; + break; + case ISP_CLK_48M: + parent = "clk_48m"; + break; + case ISP_CLK_76M8: + parent = "clk_76p8m"; + break; + + case ISP_CLK_NONE: + ISP_PRINT("isp_k: ISP close CLK %d \n", (int)clk_get_rate(g_isp_dev_ptr->s_isp_clk)); + if (g_isp_dev_ptr->s_isp_clk) { + clk_disable(g_isp_dev_ptr->s_isp_clk); + clk_put(g_isp_dev_ptr->s_isp_clk); + g_isp_dev_ptr->s_isp_clk = NULL; + } + return 0; + default: + parent = "clk_128m"; + break; + } + + if (NULL == g_isp_dev_ptr->s_isp_clk) { + g_isp_dev_ptr->s_isp_clk = parse_clk(isp_dev.this_device->of_node, "clk_isp"); + if (IS_ERR(g_isp_dev_ptr->s_isp_clk)) { + ISP_PRINT("isp_k: parse_clk fail, %p \n", (int)g_isp_dev_ptr->s_isp_clk); + return -1; + } else { + ISP_PRINT("isp_k: get clk_parent ok \n"); + } + } else { + clk_disable(g_isp_dev_ptr->s_isp_clk); + } + + clk_parent = clk_get(NULL, parent); + if (IS_ERR(clk_parent)) { + ISP_PRINT("isp_k: dcam_set_clk fail, %p \n", clk_parent); + return -1; + } else { + ISP_PRINT("isp_k: get clk_parent ok \n"); + } + + rtn = clk_set_parent(g_isp_dev_ptr->s_isp_clk, clk_parent); + if(rtn){ + ISP_PRINT("isp_k: clk_set_parent fail, %d \n", rtn); + } + + rtn = clk_enable(g_isp_dev_ptr->s_isp_clk); + if (rtn) { + ISP_PRINT("isp_k: enable isp clk error.\n"); + return -1; + } + + return rtn; +} + +static int _isp_queue_init(struct isp_queue *queue) +{ + if (NULL == queue) + return -EINVAL; + + memset(queue, 0x00, sizeof(*queue)); + queue->write = &queue->node[0]; + queue->read = &queue->node[0]; + + return 0; +} + +static int _isp_queue_write(struct isp_queue *queue, struct isp_node *node) +{ + struct isp_node *ori_node; + + if (NULL == queue || NULL == node) + return -EINVAL; + + ori_node = queue->write; + + //ISP_PRINT("_isp_queue_write called!\n"); + *queue->write++ = *node; + if (queue->write > &queue->node[ISP_QUEUE_LENGTH-1]) { + queue->write = &queue->node[0]; + } + + if (queue->write == queue->read) { + queue->write = ori_node; + } + + //ISP_PRINT("_isp_queue_write finished!\n"); + return 0; +} + +static int _isp_queue_read(struct isp_queue *queue, struct isp_node *node) +{ + int ret = 0; + + if (NULL == queue || NULL == node) + return -EINVAL; + //ISP_PRINT("_isp_queue_read called!\n"); + if (queue->read != queue->write) { + *node = *queue->read++; + if (queue->read > &queue->node[ISP_QUEUE_LENGTH-1]) { + queue->read = &queue->node[0]; + } + } + //ISP_PRINT("_isp_queue_read finished!\n"); + return ret; +} + +static inline void _isp_regread(char *dst, char *src, size_t n) +{ + char tmp = 0; + uint32_t tmp2 = 0; + char *char_src = 0,*d = 0; + uint32_t *d2 = (uint32_t*) dst; + uint32_t *int_src = (uint32_t*) src; + uint32_t counts = (n>>2)<<2; + uint32_t res_counts = n -counts; + counts = counts>>2; + + while (counts--) { + tmp2 = ISP_READL(int_src); + *d2++ = tmp2; + int_src++; + } + + if(res_counts) { + d = (char*) d2; + char_src = (char*) int_src; + while(res_counts--) { + tmp = __raw_readb(char_src); + *d = tmp; + char_src++; + } + } +} + +static inline void _isp_regwrite(char *dst, char *src, size_t n) +{ + uint32_t tmp2 = 0; + char *char_src = 0, *d = 0; + uint32_t *int_src = 0, *d2 = 0; + uint32_t counts = 0, res_counts = 0; + + int_src = (uint32_t*) src; + d2 = (uint32_t*) dst; + counts = (n>>2)<<2; + res_counts = n - counts; + counts = counts>>2; + + while (counts--) { + tmp2 = *int_src++; + ISP_WRITEL(d2, tmp2); + d2++; + } + + if(res_counts) { + d = (char*) d2; + char_src = (char*) int_src; + + while(res_counts--) { + tmp2 = *char_src++; + __raw_writeb(tmp2, d); + d++; + } + } + +} +static int32_t _isp_get_ctlr(void *param) +{ + struct isp_device_t *dev_ptr = (struct isp_device_t *) param; + + down(&dev_ptr->sem_isp); + + return 0; +} +static int32_t _isp_put_ctlr(void *param) +{ + struct isp_device_t *dev_ptr = (struct isp_device_t *) param; + + up(&dev_ptr->sem_isp); + + return 0; +} + +static int _isp_en_irq(unsigned long int_num) +{ + uint32_t ret = 0; + + ISP_WRITEL(ISP_INT_CLEAR, ISP_IRQ_HW_MASK); + ISP_WRITEL(ISP_INT_EN, int_num); + + return ret; +} + +static int _isp_registerirq(void) +{ + uint32_t ret = 0; + + ret = request_irq(ISP_IRQ, _isp_irq_root, IRQF_SHARED, "ISP", &g_isp_irq); + + return ret; +} +static void _isp_unregisterirq(void) +{ + free_irq (ISP_IRQ, &g_isp_irq); +} + +static int _isp_cfg_dcam_int(uint32_t param) +{ + uint32_t ret = 0; + + s_dcam_int_eb = param; + + return ret; +} + +static void _read_reg(struct isp_reg_bits *reg_bits_ptr, uint32_t counts) +{ + uint32_t i = 0; + unsigned long reg_val = 0; + unsigned long reg_addr = 0; + + for (i = 0; i<counts; ++i) { + //reg_addr = reg_bits_ptr[i].reg_addr; + reg_addr = ISP_BASE_ADDR + reg_bits_ptr[i].reg_addr; + reg_val = ISP_READL(reg_addr); + reg_bits_ptr[i].reg_value = reg_val; + } + +} + +static void _write_reg(struct isp_reg_bits *reg_bits_ptr, uint32_t counts) +{ + uint32_t i = 0; + unsigned long reg_val = 0; + unsigned long reg_addr = 0; + + for (i = 0; i<counts; ++i) { + reg_addr = reg_bits_ptr[i].reg_addr+ISP_BASE_ADDR; + reg_val = reg_bits_ptr[i].reg_value; + ISP_WRITEL(reg_addr, reg_val); + } +} + +/********************************************************** +*open the device +* +***********************************************************/ +static int32_t _isp_kernel_open (struct inode *node, struct file *pf) +{ + int32_t ret = 0; + ISP_PRINT ("isp_k: open start \n"); + + ISP_CHECK_ZERO(g_isp_dev_ptr); + + ret = _isp_get_ctlr(g_isp_dev_ptr); + if (unlikely(ret)) { + ISP_PRINT ("isp_k: get control error \n"); + ret = -EFAULT; + return ret; + } + + g_isp_dev_ptr->reg_base_addr = (unsigned long)ISP_BASE_ADDR; + g_isp_dev_ptr->size = ISP_REG_MAX_SIZE; + + ret = _isp_queue_init(&(g_isp_dev_ptr->queue)); + if (unlikely(0 != ret)) { + ISP_PRINT("isp_k: queue init error\n"); + ret = -EIO; + goto ISP_K_OPEN_ERROR_EXIT; + } + + ret = _isp_module_eb(); + if (unlikely(0 != ret)) { + ISP_PRINT("isp_k: enable isp module error\n"); + ret = -EIO; + goto ISP_K_OPEN_ERROR_EXIT; + } + + ret = _isp_module_rst(); + if (unlikely(0 != ret)) { + ISP_PRINT("isp_k: reset isp module error \n"); + ret = -EIO; + _isp_module_dis(); + goto ISP_K_OPEN_ERROR_EXIT; + } + + dcam_reg_isr(DCAM_CAP_EOF, _isp_cap_eof, g_isp_dev_ptr); + ret = _isp_kernel_thread(g_isp_dev_ptr); + if (unlikely(0 != ret)) { + ISP_PRINT("isp_k: create isp_kernel_thread fail \n"); + ret = -EIO; + _isp_module_dis(); + goto ISP_K_OPEN_ERROR_EXIT; + } + + ret = _isp_registerirq(); + if (unlikely(0 != ret)) { + ISP_PRINT("isp_k: reg irq fail \n"); + ret = -EIO; + _isp_stop_kernel_thread(g_isp_dev_ptr); + _isp_module_dis(); + goto ISP_K_OPEN_ERROR_EXIT; + } + + ISP_PRINT ("isp_k: open end \n"); + return ret; + +ISP_K_OPEN_ERROR_EXIT: + ret = _isp_put_ctlr(g_isp_dev_ptr); + if (unlikely(ret)) { + ISP_PRINT ("isp_k: get control error \n"); + ret = -EFAULT; + } + ISP_PRINT ("isp_k: open error \n"); + return -EIO; +} + +static irqreturn_t _isp_irq_root(int irq, void *dev_id) +{ + int32_t ret = 0; + uint32_t status = 0; + uint32_t irq_line = 0; + uint32_t irq_status = 0; + unsigned long flag = 0; + int32_t i = 0; + struct isp_node node = { 0 }; + struct timeval system_time; + + status = ISP_REG_RD(ISP_INT_STATUS); + irq_line = status&ISP_IRQ_HW_MASK; + //ISP_PRINT("ISP_RAW:isp_k: isp irq: 0x%x\n", irq_line); + if ( 0 == irq_line ) { + return IRQ_NONE; + } + + spin_lock_irqsave(&isp_spin_lock,flag); + if ((ISP_INT_LENS_LOAD & irq_line) == ISP_INT_LENS_LOAD) { + irq_line &= ~ISP_INT_LENS_LOAD; + ISP_OWR(ISP_INT_CLEAR, ISP_INT_LENS_LOAD); + up(&g_isp_dev_ptr->lnc_load.load_done_sem); + if (!irq_line) { + spin_unlock_irqrestore(&isp_spin_lock, flag); + return IRQ_HANDLED; + } + } + for (i = ISP_IRQ_NUM- 1; i >= 0; i--) { + if (irq_line & (1 << (uint32_t)i)) { + irq_status |= 1 << (uint32_t)i; + } + irq_line &= ~(uint32_t)(1 << (uint32_t)i); //clear the interrupt flag + if(!irq_line) //no interrupt source left + break; + } + + ISP_WRITEL(ISP_INT_CLEAR, irq_status); + node.isp_irq_val = irq_status; + _isp_get_systemtime(&system_time); + system_time.tv_sec = system_time.tv_sec * 1000000; + node.system_time = (uint64_t)(system_time.tv_sec+system_time.tv_usec); + ret = _isp_queue_write((struct isp_queue *)&g_isp_dev_ptr->queue, (struct isp_node*)&node); + spin_unlock_irqrestore(&isp_spin_lock, flag); + up(&g_isp_dev_ptr->sem_isr); + + return IRQ_HANDLED; +} +//static irqreturn_t _dcam_irq_root(int irq, void *dev_id) +void _dcam_isp_root(void) +{ + int32_t ret = 0; + unsigned long flag = 0; + struct isp_node node = { 0 }; + struct timeval system_time; + + //ISP_PRINT ("ISP_RAW: isp_k: _dcam_isp_root %d \n", s_dcam_int_eb); + + if(0x00 !=s_dcam_int_eb) + { + spin_lock_irqsave(&isp_spin_lock,flag); + #if defined(CONFIG_MACH_CORE3) + node.dcam_irq_val = ISP_INT_FETCH_EOF; + #else + node.dcam_irq_val = ISP_INT_FETCH_SOF; + #endif + + //ISP_PRINT("isp_k: dcam sof irq :0x%x\n", node.dcam_irq_val); + _isp_get_systemtime(&system_time); + system_time.tv_sec = system_time.tv_sec * 1000000; + node.system_time = (uint64_t)(system_time.tv_sec+system_time.tv_usec); + ret = _isp_queue_write((struct isp_queue *)&g_isp_dev_ptr->queue, (struct isp_node*)&node); + spin_unlock_irqrestore(&isp_spin_lock, flag); + up(&g_isp_dev_ptr->sem_isr); + } + + //return IRQ_HANDLED; +} + +/********************************************************** +*release the device +* +***********************************************************/ +static int32_t _isp_kernel_release (struct inode *node, struct file *pf) +{ + int ret = 0; + ISP_PRINT ("isp_k: release start \n"); + + mutex_lock(&s_isp_lock); + + _isp_unregisterirq(); + ret = _isp_module_dis(); + + mutex_unlock(&s_isp_lock); + + _isp_stop_kernel_thread(g_isp_dev_ptr); + ISP_CHECK_ZERO(g_isp_dev_ptr); + ret = _isp_put_ctlr(g_isp_dev_ptr); + if (unlikely (ret) ) { + ISP_PRINT ("isp_k: release control error \n"); + return -EFAULT; + } + ISP_PRINT ("isp_k: release end \n"); + return ret; +} +/********************************************************** +*read info from file +*size_t size: +*loff_t p: +***********************************************************/ +#if 0 +static int32_t _isp_kernel_proc_read (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int len = 0; + uint32_t reg_buf_len = 200; + uint32_t print_len = 0, print_cnt = 0; + uint32_t *reg_ptr = 0; + + ISP_PRINT ("isp_k: _isp_kernel_proc_read 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x \n", (uint32_t)page, (uint32_t)start, (uint32_t)off, (uint32_t)count, (uint32_t)eof, (uint32_t)data); + + (void)start; (void)off; (void)count; (void)eof; + + if(0x00==g_isp_device.reg_base_addr) + { + return 0x00; + } + + reg_ptr = (uint32_t*)g_isp_device.reg_base_addr; + len += sprintf(page + len, "Context for ISP device \n"); + len += sprintf(page + len, "********************************************* \n"); + while (print_len < reg_buf_len) { + len += sprintf(page + len, "offset 0x%x : 0x%x, 0x%x, 0x%x, 0x%x \n", + print_len, + reg_ptr[print_cnt], + reg_ptr[print_cnt+1], + reg_ptr[print_cnt+2], + reg_ptr[print_cnt+3]); + print_cnt += 4; + print_len += 16; + } + len += sprintf(page + len, "********************************************* \n"); + len += sprintf(page + len, "The end of ISP device \n"); + return len; +} +#endif +/********************************************************** +*the io controller of isp +*unsigned int cmd: +*unsigned long param: +***********************************************************/ +static long _isp_kernel_ioctl( struct file *fl, unsigned int cmd, unsigned long param) +{ + long ret = 0; + uint32_t isp_irq, dcam_irq; + struct isp_irq_param irq_param = { 0 }; + struct isp_node isp_node = { 0 }; + struct isp_reg_param reg_param = { 0 }; + struct isp_reg_bits *reg_bits_ptr = 0; + + //ISP_PRINT("isp_k:_ioctl called, cmd: %x\n", cmd); + + if (!fl) { + return -EINVAL; + } + + ISP_CHECK_ZERO(g_isp_dev_ptr); + + if(ISP_IO_IRQ==cmd) + { + ret = down_interruptible(&g_isp_dev_ptr->sem_isr); + if (ret) { + ISP_PRINT("isp_k: ioctl irq: down failed ret = %ld",ret); + memset(&irq_param, 0, sizeof(irq_param)); + irq_param.ret_val = ret; + ret = copy_to_user ((void*) param, (void*)&irq_param, sizeof(irq_param)); + if ( 0 != ret) { + ISP_PRINT("isp_k: ioctl irq: copy_to_user failed ret = %ld", ret); + } + ret = -ERESTARTSYS; + goto ISP_IOCTL_EXIT; + } + ret=_isp_queue_read(&g_isp_dev_ptr->queue, &isp_node); + if ( 0 != ret) { + + ISP_PRINT("isp_k: ioctl irq: _isp_queue_read error, ret = 0x%x", (uint32_t)ret); + ret = -EFAULT; + goto ISP_IOCTL_EXIT; + } + + irq_param.dcam_irq_val = isp_node.dcam_irq_val; + irq_param.isp_irq_val = isp_node.isp_irq_val; + isp_irq = isp_node.isp_irq_val; + dcam_irq = isp_node.dcam_irq_val; + irq_param.irq_val = dcam_irq|isp_irq; + irq_param.system_time = isp_node.system_time; + ret = copy_to_user ((void*) param, (void*)&irq_param, sizeof(struct isp_irq_param)); + if ( 0 != ret) { + + ISP_PRINT("isp_k: ioctl irq: copy_to_user error, ret = 0x%x", (uint32_t)ret); + ret = -EFAULT; + } + + } else { + + mutex_lock(&s_isp_lock); + + switch (cmd) + { + case ISP_IO_READ: { + uint32_t buf_size = 0; + //ISP_PRINT(" isp_k:_ioctl read called \n"); + ret = copy_from_user((void*)®_param, (void*)param, sizeof(struct isp_reg_param)); + if ( 0 != ret) { + + ISP_PRINT("isp_k: ioctl read: copy_to_user error, ret = 0x%x", (uint32_t)ret); + ret = -EFAULT; + goto IO_READ_EXIT; + } + buf_size = reg_param.counts*sizeof(struct isp_reg_bits); + if (buf_size > g_isp_dev_ptr->buf_len) { + ret =-EFAULT; + goto IO_READ_EXIT; + } + reg_bits_ptr = (struct isp_reg_bits*) g_isp_dev_ptr->buf_addr; + ret = copy_from_user((void*)reg_bits_ptr, (void*)reg_param.reg_param, buf_size); + if ( 0 != ret) { + + ISP_PRINT("isp_k: ioctl read: copy_to_user error, ret = 0x%x", (uint32_t)ret); + ret =-EFAULT; + goto IO_READ_EXIT; + } + _read_reg(reg_bits_ptr, reg_param.counts); + + ret = copy_to_user((void*)reg_param.reg_param, (void*)reg_bits_ptr, buf_size); + if ( 0 != ret) { + + ISP_PRINT("isp_k: ioctl read: copy_to_user error, ret = 0x%x", (uint32_t)ret); + ret = -EFAULT; + goto IO_READ_EXIT; + } + IO_READ_EXIT: + if(reg_bits_ptr) { + memset((void *)g_isp_dev_ptr->buf_addr, 0x00, buf_size); + reg_bits_ptr = NULL; + } + } + break; + + case ISP_IO_WRITE: { + uint32_t buf_size = 0; + //ISP_PRINT(" isp_k:_ioctl write called \n"); + ret = copy_from_user((void*)®_param, (void*)param, sizeof(struct isp_reg_param)); + if ( 0 != ret) { + + ISP_PRINT("isp_k: ioctl write: copy_to_user error, ret = 0x%x", (uint32_t)ret); + ret = -EFAULT; + goto IO_WRITE_EXIT; + } + buf_size = reg_param.counts*sizeof(struct isp_reg_bits); + if(buf_size > g_isp_dev_ptr->buf_len) + { + ret = -EFAULT; + goto IO_WRITE_EXIT; + } + reg_bits_ptr = (struct isp_reg_bits*) g_isp_dev_ptr->buf_addr; + + ret = copy_from_user((void*)reg_bits_ptr, (void*)reg_param.reg_param, buf_size); + if ( 0 != ret) { + + ISP_PRINT("isp_k: ioctl write: copy_to_user error, ret = 0x%x", (uint32_t)ret); + ret = -EFAULT; + goto IO_WRITE_EXIT; + } + _write_reg(reg_bits_ptr, reg_param.counts); + + IO_WRITE_EXIT: + if(reg_bits_ptr) { + memset((void *)g_isp_dev_ptr->buf_addr, 0x00, buf_size); + reg_bits_ptr = NULL; + } + + } + break; + + case ISP_IO_RST: { + ISP_PRINT(" isp_k:ioctl restet start \n"); + g_isp_dev_ptr->lnc_load.cap_eof_flag = 0; + ret = _isp_module_rst(); + if (ret) { + + ISP_PRINT("isp_k: ioctl restet error!\n"); + ret = -EFAULT; + } + } + break; + + case ISP_IO_SETCLK: { + ISP_PRINT(" isp_k:ioctl set clock start \n"); + } + break; + + case ISP_IO_STOP: { + unsigned long flag = 0; + struct isp_node node = { 0 }; + ret = _isp_en_irq(0);//dis-enable the interrupt + ISP_PRINT("isp_k: ioctl stop start !\n"); + spin_lock_irqsave(&isp_spin_lock,flag); + node.dcam_irq_val = ISP_INT_STOP; + ret = _isp_queue_write((struct isp_queue *)&g_isp_dev_ptr->queue, (struct isp_node*)&node); + spin_unlock_irqrestore(&isp_spin_lock, flag); + up(&g_isp_dev_ptr->sem_isr); + } + break; + + case ISP_IO_INT: { + unsigned long int_num; + ret = copy_from_user((void*)&int_num, (void*)param, 0x04); + if (ret) { + ISP_PRINT ("isp_k:io int copy param error, ret = %d \n", (uint32_t)ret); + ret = -EFAULT; + goto ISP_IOCTL_LOCKED_CMD_EXIT; + } + ret = _isp_en_irq(int_num); + //ret = _isp_registerirq(); + if (unlikely(ret)) { + ISP_PRINT ("isp_k:enable interrupt error \n"); + ret = -EFAULT; + } + } + break; + + case ISP_IO_DCAM_INT: { + unsigned long int_param; + ret = copy_from_user((void*)&int_param, (void*)param, 0x04); + if (ret) { + ISP_PRINT ("isp_k:dcam int copy params error, ret = %d \n", (uint32_t)ret); + ret = -EFAULT; + goto ISP_IOCTL_LOCKED_CMD_EXIT; + } + ret = _isp_cfg_dcam_int(int_param); + if (unlikely(ret)) { + ISP_PRINT ("isp_k:cfg dcam interrupt error \n"); + ret = -EFAULT; + } + } + break; + + case ISP_IO_LNC_PARAM: { + uint32_t buf_size = 0; + uint32_t* addr = 0; + ret = copy_from_user((void*)®_param, (void*)param, sizeof(struct isp_reg_param)); + if ( 0 != ret) { + + ISP_PRINT("isp_k: ioctl lnc param: copy_to_user error, ret = 0x%x", (uint32_t)ret); + ret = -EFAULT; + goto IO_LNC_PARAM_EXIT; + } + buf_size = reg_param.counts; + if(buf_size > g_isp_dev_ptr->buf_len){ + + ret = -EFAULT; + goto IO_LNC_PARAM_EXIT; + } + addr = (uint32_t*) g_isp_dev_ptr->buf_addr; + ret = copy_from_user((void*)addr, (void*)reg_param.reg_param, buf_size); + if ( 0 != ret) { + + ISP_PRINT("isp_k: ioctl lnc param: copy_to_user error, ret = 0x%x", (uint32_t)ret); + ret = -EFAULT; + goto IO_LNC_PARAM_EXIT; + } + ret = _isp_lnc_param_set(addr, buf_size); + if ( 0 != ret) { + ISP_PRINT("isp_k: ioctl lnc param error, ret = 0x%x", (uint32_t)ret); + ret = -EFAULT; + goto IO_LNC_PARAM_EXIT; + } + + IO_LNC_PARAM_EXIT: + if(addr) { + memset((void *)g_isp_dev_ptr->buf_addr, 0x00, buf_size); + addr = NULL; + } + } + break; + + case ISP_IO_LNC: { + uint32_t buf_size = 0; + ret = copy_from_user((void*)®_param, (void*)param, sizeof(struct isp_reg_param)); + if ( 0 != ret) { + ISP_PRINT("isp_k: ioctl lnc: copy_to_user error, ret = 0x%x", (uint32_t)ret); + ret = -EFAULT; + goto IO_LNC_EXIT; + } + buf_size = reg_param.counts*sizeof(struct isp_reg_bits); + if(buf_size > g_isp_dev_ptr->buf_len) + { + ret = -EFAULT; + ISP_PRINT("isp_k: isp_io_lnc: buf len failed\n"); + goto IO_LNC_EXIT; + } + reg_bits_ptr = (struct isp_reg_bits*) g_isp_dev_ptr->buf_addr; + ret = copy_from_user((void*)reg_bits_ptr, (void*)reg_param.reg_param, buf_size); + if ( 0 != ret) { + ISP_PRINT("isp_k: ioctl lnc: copy_to_user error, ret = 0x%x", (uint32_t)ret); + ret = -EFAULT; + goto IO_LNC_EXIT; + } + + if (g_isp_dev_ptr->lnc_load.cap_eof_flag == 0) { + ret = _isp_lnc_param_load(reg_bits_ptr, reg_param.counts); + } else { + memcpy((void *)g_isp_dev_ptr->lnc_load.load_buf, (void *)reg_bits_ptr, buf_size); + g_isp_dev_ptr->lnc_load.param_counts = reg_param.counts; + g_isp_dev_ptr->lnc_load.load_lnc_flag = 1; + ret = down_timeout(&g_isp_dev_ptr->lnc_load.load_done_sem, msecs_to_jiffies(500)); + } + if (unlikely(ret)) { + ISP_PRINT ("isp_k:load lnc error \n"); + ret = -EFAULT; + } + IO_LNC_EXIT: + if(reg_bits_ptr) { + memset((void *)g_isp_dev_ptr->buf_addr, 0x00, buf_size); + reg_bits_ptr = NULL; + } + } + break; + + case ISP_IO_ALLOC: { + + ret = copy_from_user((void*)®_param, (void*)param, sizeof(struct isp_reg_param)); + if ( 0 != ret) { + ISP_PRINT("isp_k: ioctl write: copy_to_user error, ret = 0x%x", (uint32_t)ret); + ret = -EFAULT; + break; + } + ret = _isp_alloc(®_param.reg_param, reg_param.counts); + if ( 0 == ret) { + ret = copy_to_user((void*)param, (void*)®_param, sizeof(struct isp_reg_param)); + } else { + ISP_PRINT("isp_k: ioctl alloc error, ret = 0x%x", (uint32_t)ret); + ret = -EFAULT; + } + } + break; + + default: + mutex_unlock(&s_isp_lock); + ISP_PRINT("isp_k:_ioctl cmd is unsupported, cmd = %x\n", (int32_t)cmd); + return -EFAULT; + } + + ISP_IOCTL_LOCKED_CMD_EXIT: + mutex_unlock(&s_isp_lock); + } + + //ISP_PRINT("isp_k:_ioctl finished\n"); + ISP_IOCTL_EXIT: + return ret; +} + +static int _isp_probe(struct platform_device *pdev) +{ + int ret = 0; + ISP_PRINT ("isp_k:probe start\n"); + + ret = misc_register(&isp_dev); + if (ret) { + ISP_PRINT ( "isp_k:probe cannot register miscdev on minor=%d (%d)\n",(int32_t)ISP_MINOR, (int32_t)ret); + return ret; + } + mutex_init(&s_isp_lock); +/* + isp_proc_file = create_proc_read_entry("driver/sprd_isp" , + 0444, + NULL, + _isp_kernel_proc_read, + NULL); + if (unlikely(NULL == isp_proc_file)) { + ISP_PRINT("isp_k:probe Can't create an entry for isp in /proc \n"); + ret = ENOMEM; + return ret; + } +*/ + isp_dev.this_device->of_node = pdev->dev.of_node; + parse_baseaddress(pdev->dev.of_node); + ISP_PRINT (" isp_k:probe end\n"); + return 0; +} + +static int _isp_remove(struct platform_device * dev) +{ + ISP_PRINT ("isp_k: remove start \n"); + + misc_deregister(&isp_dev); + + if (isp_proc_file) { + remove_proc_entry("driver/sprd_isp", NULL); + } + + ISP_PRINT ("isp_k: remove end !\n"); + + return 0; +} + +static int32_t __init isp_kernel_init(void) +{ + int32_t ret = 0; + unsigned long addr = 0; + ISP_PRINT ("isp_k: init start \n"); + if (platform_driver_register(&isp_driver) != 0) { + ISP_PRINT ("isp_kernel_init: platform device register error \n"); + return -1; + } + + g_isp_dev_ptr = (struct isp_device_t*)vzalloc(sizeof(struct isp_device_t)); + ISP_CHECK_ZERO(g_isp_dev_ptr); + init_MUTEX(&g_isp_dev_ptr->sem_isp); + init_MUTEX_LOCKED(&g_isp_dev_ptr->sem_isr); /*for interrupt */ + g_isp_dev_ptr->s_isp_clk = NULL; + g_isp_dev_ptr->s_isp_clk_mm_i = NULL; + g_isp_dev_ptr->buf_addr = 0; + g_isp_dev_ptr->buf_len = 0; + + g_isp_dev_ptr->buf_addr = (unsigned long)vzalloc(ISP_BUF_MAX_SIZE); + if (0 == g_isp_dev_ptr->buf_addr) { + ret = -1; + ISP_PRINT ("isp_kernel_init 1: alloc error \n"); + goto ISP_K_INIT_EXIT; + } + g_isp_dev_ptr->buf_len = ISP_BUF_MAX_SIZE; + + g_isp_dev_ptr->lnc_load.load_buf = (unsigned long)vzalloc(ISP_BUF_MAX_SIZE); + if (0 == g_isp_dev_ptr->lnc_load.load_buf) { + ret = -1; + ISP_PRINT ("isp_kernel_init 3: alloc error \n"); + goto ISP_K_INIT_EXIT; + } + ret = _isp_alloc(&addr, ISP_BUF_MAX_SIZE); + if (ret) { + ret = -1; + ISP_PRINT ("isp_kernel_init 2: alloc error \n"); + goto ISP_K_INIT_EXIT; + } + + ISP_PRINT ("isp_k: init end\n"); + + return ret; + +ISP_K_INIT_EXIT: + _isp_free(); + if (g_isp_dev_ptr->buf_addr) { + vfree((void *)g_isp_dev_ptr->buf_addr); + g_isp_dev_ptr->buf_addr = 0; + g_isp_dev_ptr->buf_len = 0; + } + if (g_isp_dev_ptr->lnc_load.load_buf) { + vfree((void *)g_isp_dev_ptr->lnc_load.load_buf); + g_isp_dev_ptr->lnc_load.load_buf = 0; + } + if (g_isp_dev_ptr) { + vfree(g_isp_dev_ptr); + g_isp_dev_ptr = 0; + } + + return ret; +} + +static void isp_kernel_exit(void) +{ + ISP_PRINT ("isp_k: exit start \n"); + + platform_driver_unregister(&isp_driver); + mutex_destroy(&s_isp_lock); + _isp_free(); + ISP_CHECK_ZERO_VOID(g_isp_dev_ptr); + if (g_isp_dev_ptr->buf_addr) { + vfree((void *)g_isp_dev_ptr->buf_addr); + g_isp_dev_ptr->buf_addr = 0; + g_isp_dev_ptr->buf_len = 0; + } + if(g_isp_dev_ptr->lnc_load.load_buf) { + vfree((void *)g_isp_dev_ptr->lnc_load.load_buf); + g_isp_dev_ptr->lnc_load.load_buf = 0; + } + vfree(g_isp_dev_ptr); + g_isp_dev_ptr = NULL; + + ISP_PRINT ("isp_k: exit end \n"); +} + +module_init(isp_kernel_init); +module_exit(isp_kernel_exit); + +MODULE_DESCRIPTION("Isp Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/sprd_isp/isp1.0/isp_drv_null.c b/drivers/media/sprd_isp/isp1.0/isp_drv_null.c new file mode 100644 index 00000000..4e8b84e0 --- /dev/null +++ b/drivers/media/sprd_isp/isp1.0/isp_drv_null.c @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2012 Spreadtrum Communications Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + #include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/poll.h> +#include <linux/fs.h> +#include <linux/irq.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/miscdevice.h> +#include <asm/io.h> +#include <linux/file.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/types.h> +#include <linux/string.h> +#include <linux/sched.h> +#include <linux/spinlock_types.h> +#include <linux/semaphore.h> +#include <linux/delay.h> +#include <linux/proc_fs.h> +#include <video/isp_drv_kernel.h> + +#include <linux/clk.h> +#include <asm/cacheflush.h> + +#include <linux/of.h> +#include <linux/of_device.h> + +#include "Shark_reg_isp.h" + + +#define DEBUG_ISP_DRV +#ifdef DEBUG_ISP_DRV +#define ISP_PRINT printk +#else +#define ISP_PRINT(...) +#endif +#define ISP_MINOR MISC_DYNAMIC_MINOR/*isp minor number*/ +static struct proc_dir_entry* isp_proc_file; + +/**file operation functions declare**/ +static int32_t _isp_kernel_open(struct inode *node, struct file *filp); +static int32_t _isp_kernel_release(struct inode *node, struct file *filp); +static long _isp_kernel_ioctl( struct file *fl, unsigned int cmd, unsigned long param); +/**driver' functions declare**/ +static int32_t _isp_probe(struct platform_device *pdev); +static int32_t _isp_remove(struct platform_device *dev); +/**module' functions declare**/ +static int32_t __init isp_kernel_init(void); +static void isp_kernel_exit(void); + +static struct file_operations isp_fops = { + .owner = THIS_MODULE, + .open = _isp_kernel_open, + .unlocked_ioctl = _isp_kernel_ioctl, + .release = _isp_kernel_release, +}; + +static struct miscdevice isp_dev = { + .minor = ISP_MINOR, + .name = "sprd_isp", + .fops = &isp_fops, +}; + +static const struct of_device_id of_match_table_isp[] = { + { .compatible = "sprd,sprd_isp", }, + { }, +}; + +static struct platform_driver isp_driver = { + .probe = _isp_probe, + .remove = _isp_remove, + .driver = { + .owner = THIS_MODULE, + .name = "sprd_isp", + .of_match_table = of_match_ptr(of_match_table_isp), + }, +}; + +/********************************************************** +*open the device +* +***********************************************************/ +static int32_t _isp_kernel_open (struct inode *node, struct file *pf) +{ + int32_t ret = 0; + ISP_PRINT ("isp_k: open start \n"); + + return ret; +} + +//static irqreturn_t _dcam_irq_root(int irq, void *dev_id) +void _dcam_isp_root(void) +{ + int32_t ret = 0; + + return IRQ_HANDLED; +} + +/********************************************************** +*release the device +* +***********************************************************/ +static int32_t _isp_kernel_release (struct inode *node, struct file *pf) +{ + int ret = 0; + ISP_PRINT ("isp_k: release start \n"); + + ISP_PRINT ("isp_k: release end \n"); + return ret; +} +/********************************************************** +*read info from file +*size_t size: +*loff_t p: +***********************************************************/ +static int32_t _isp_kernel_proc_read (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int len = 0; +#if 0 + uint32_t reg_buf_len = 200; + uint32_t print_len = 0, print_cnt = 0; + uint32_t *reg_ptr = 0; + + ISP_PRINT ("isp_k: _isp_kernel_proc_read 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x \n", (uint32_t)page, (uint32_t)start, (uint32_t)off, (uint32_t)count, (uint32_t)eof, (uint32_t)data); + + (void)start; (void)off; (void)count; (void)eof; + + if(0x00==g_isp_device.reg_base_addr) + { + return 0x00; + } + + reg_ptr = (uint32_t*)g_isp_device.reg_base_addr; + len += sprintf(page + len, "Context for ISP device \n"); + len += sprintf(page + len, "********************************************* \n"); + while (print_len < reg_buf_len) { + len += sprintf(page + len, "offset 0x%x : 0x%x, 0x%x, 0x%x, 0x%x \n", + print_len, + reg_ptr[print_cnt], + reg_ptr[print_cnt+1], + reg_ptr[print_cnt+2], + reg_ptr[print_cnt+3]); + print_cnt += 4; + print_len += 16; + } + len += sprintf(page + len, "********************************************* \n"); + len += sprintf(page + len, "The end of ISP device \n"); +#endif + return len; +} + +/********************************************************** +*the io controller of isp +*unsigned int cmd: +*unsigned long param: +***********************************************************/ +static long _isp_kernel_ioctl( struct file *fl, unsigned int cmd, unsigned long param) +{ + long ret = 0; + + if(ISP_IO_IRQ==cmd) + { + } else { + + switch (cmd) + { + case ISP_IO_READ: { + } + break; + + case ISP_IO_WRITE: { + } + break; + + case ISP_IO_RST: { + ISP_PRINT(" isp_k:ioctl restet start \n"); + } + break; + + case ISP_IO_SETCLK: + ISP_PRINT(" isp_k:ioctl set clock start \n"); + break; + + case ISP_IO_STOP: { + } + break; + + case ISP_IO_INT: { + } + break; + + case ISP_IO_DCAM_INT: { + } + break; + + case ISP_IO_LNC_PARAM: { + } + break; + + case ISP_IO_LNC: { + } + break; + + case ISP_IO_ALLOC: { + } + break; + + default: + ISP_PRINT("isp_k:_ioctl cmd is unsupported, cmd = %x\n", (int32_t)cmd); + return -EFAULT; + } + + } + + //ISP_PRINT("isp_k:_ioctl finished\n"); + ISP_IOCTL_EXIT: + return ret; +} + +static int _isp_probe(struct platform_device *pdev) +{ + int ret = 0; + ISP_PRINT ("isp_k:probe start\n"); + + ret = misc_register(&isp_dev); + if (ret) { + ISP_PRINT ( "isp_k:probe cannot register miscdev on minor=%d (%d)\n",(int32_t)ISP_MINOR, (int32_t)ret); + return ret; + } +/* + isp_proc_file = create_proc_read_entry("driver/sprd_isp" , + 0444, + NULL, + _isp_kernel_proc_read, + NULL); + if (unlikely(NULL == isp_proc_file)) { + ISP_PRINT("isp_k:probe Can't create an entry for isp in /proc \n"); + ret = ENOMEM; + return ret; + } +*/ + isp_dev.this_device->of_node = pdev->dev.of_node; + ISP_PRINT (" isp_k:probe end\n"); + return 0; +} + +static int _isp_remove(struct platform_device * dev) +{ + ISP_PRINT ("isp_k: remove start \n"); + + misc_deregister(&isp_dev); + + if (isp_proc_file) { + remove_proc_entry("driver/sprd_isp", NULL); + } + + ISP_PRINT ("isp_k: remove end !\n"); + + return 0; +} + +static int32_t __init isp_kernel_init(void) +{ + int32_t ret = 0; + uint32_t addr = 0; + ISP_PRINT ("isp_k: init start \n"); + if (platform_driver_register(&isp_driver) != 0) { + ISP_PRINT ("isp_kernel_init: platform device register error \n"); + return -1; + } + + ISP_PRINT ("isp_k: init end\n"); + + return ret; +} + +static void isp_kernel_exit(void) +{ + ISP_PRINT ("isp_k: exit start \n"); + + platform_driver_unregister(&isp_driver); + + ISP_PRINT ("isp_k: exit end \n"); +} + +module_init(isp_kernel_init); +module_exit(isp_kernel_exit); + +MODULE_DESCRIPTION("Isp Driver"); +MODULE_LICENSE("GPL"); |
