vvcam_isp_driver.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. /****************************************************************************
  2. *
  3. * The MIT License (MIT)
  4. *
  5. * Copyright (c) 2020 VeriSilicon Holdings Co., Ltd.
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a
  8. * copy of this software and associated documentation files (the "Software"),
  9. * to deal in the Software without restriction, including without limitation
  10. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11. * and/or sell copies of the Software, and to permit persons to whom the
  12. * Software is furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in
  15. * all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  23. * DEALINGS IN THE SOFTWARE.
  24. *
  25. *****************************************************************************
  26. *
  27. * The GPL License (GPL)
  28. *
  29. * Copyright (c) 2020 VeriSilicon Holdings Co., Ltd.
  30. *
  31. * This program is free software; you can redistribute it and/or
  32. * modify it under the terms of the GNU General Public License
  33. * as published by the Free Software Foundation; either version 2
  34. * of the License, or (at your option) any later version.
  35. *
  36. * This program is distributed in the hope that it will be useful,
  37. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  38. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  39. * GNU General Public License for more details.
  40. *
  41. * You should have received a copy of the GNU General Public License
  42. * along with this program;
  43. *
  44. *****************************************************************************
  45. *
  46. * Note: This software is released under dual MIT and GPL licenses. A
  47. * recipient may use this file under the terms of either the MIT license or
  48. * GPL License. If you wish to use only one license not the other, you can
  49. * indicate your decision by deleting one of the above license notices in your
  50. * version of this file.
  51. *
  52. *****************************************************************************/
  53. #include <asm/io.h>
  54. #include <linux/cdev.h>
  55. #include <linux/module.h>
  56. #include <linux/platform_device.h>
  57. #include <linux/delay.h>
  58. #include <linux/clk.h>
  59. #include <linux/io.h>
  60. #include <linux/mm.h>
  61. #include <linux/timer.h>
  62. #include <linux/kernel.h>
  63. #include <linux/init.h>
  64. #include <linux/workqueue.h>
  65. #include <linux/slab.h>
  66. #include <linux/proc_fs.h>
  67. #include <linux/debugfs.h>
  68. #include <linux/miscdevice.h>
  69. #include <linux/uaccess.h>
  70. #include <linux/interrupt.h>
  71. #include <linux/of_reserved_mem.h>
  72. #include "isp_ioctl.h"
  73. #include "mrv_all_regs.h"
  74. #include "isp_wdr.h"
  75. extern MrvAllRegister_t *all_regs;
  76. static ulong vvImgBufBase = 0x10000000;
  77. module_param(vvImgBufBase, ulong, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  78. MODULE_PARM_DESC(vvImgBufBase, "Base addrss of memory reserved for ISP");
  79. static ulong vvImgBufSize = 0x10000000;
  80. module_param(vvImgBufSize, ulong, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  81. MODULE_PARM_DESC(vvImgBufSize, "Size of memory reserved for ISP");
  82. #define VIVCAM_ISP_NAME "vivisp"
  83. #define VIVCAM_ISP_MAXCNT 2
  84. #define VIVCAM_ISP_IRQ_NUMBER 16
  85. struct vvcam_isp_driver_dev
  86. {
  87. struct cdev cdev;
  88. dev_t devt;
  89. struct class *class;
  90. struct mutex vvmutex;
  91. unsigned int device_idx;
  92. struct timer_list isp_timer;
  93. struct work_struct vvnative_wq;
  94. wait_queue_head_t irq_wait;
  95. int irq_num;
  96. void *private;
  97. };
  98. static unsigned int vvcam_isp_major = 0;
  99. static unsigned int vvcam_isp_minor = 0;
  100. static struct class *vvcam_isp_class;
  101. static unsigned int devise_register_index = 0;
  102. static bool isp_irq = false;
  103. static unsigned int vvnative_isp_poll(struct file * filp, poll_table *wait)
  104. {
  105. unsigned int mask = 0;
  106. struct vvcam_isp_driver_dev *pdriver_dev = filp->private_data;
  107. poll_wait(filp, &pdriver_dev->irq_wait, wait);
  108. //pr_info("poll isp_irq %d\n", isp_irq);
  109. if (isp_irq) {
  110. mask |= POLLIN |POLLRDNORM;
  111. isp_irq = false;
  112. }
  113. return mask;
  114. }
  115. static void vvnative_isp_work(struct work_struct *work)
  116. {
  117. /*Todo update those module that does not have shandow register*/
  118. struct vvcam_isp_driver_dev *pdriver_dev = container_of(work, struct vvcam_isp_driver_dev, vvnative_wq);
  119. struct isp_ic_dev * pisp_dev = pdriver_dev->private;
  120. pr_info("%s enter \n", __func__);
  121. isp_irq = true;
  122. wake_up_interruptible(&pdriver_dev->irq_wait);
  123. if (pisp_dev->isp_mis & MRV_ISP_MIS_FRAME_MASK) {
  124. if (pisp_dev->wdr.changed) {
  125. pr_info("%s pisp_dev->wdr.changed %d\n", __func__,
  126. pisp_dev->wdr.changed);
  127. isp_s_wdr(pisp_dev);
  128. }
  129. if (pisp_dev->flt.changed) {
  130. pr_info("%s pisp_dev->flt.changed %d\n", __func__,
  131. pisp_dev->flt.changed);
  132. isp_s_flt(pisp_dev);
  133. }
  134. #ifndef ISP_CPROC_SHD_RY
  135. if (pisp_dev->cproc.changed) {
  136. pr_info("%s pisp_dev->cproc.changed %d\n", __func__,
  137. pisp_dev->cproc.changed);
  138. isp_s_cproc(pisp_dev);
  139. }
  140. #endif
  141. if (pisp_dev->gamma_out.changed) {
  142. pr_info("%s pisp_dev->gamma_out.changed %d\n", __func__,
  143. pisp_dev->gamma_out.changed);
  144. isp_s_gamma_out(pisp_dev);
  145. }
  146. }
  147. }
  148. static irqreturn_t vvcam_isp_irq(int irq, void *dev_id)
  149. {
  150. struct vvcam_isp_driver_dev *pdriver_dev ;
  151. struct isp_ic_dev * pisp_dev;
  152. u32 isp_mis, mi_mis, mi_mis_addr, mi_icr_addr;
  153. #ifdef ISP_MIV2_RY
  154. u32 miv2_mis1, miv2_mis3;
  155. #endif
  156. #if defined(ISP_MI_PP_READ_RY) || defined (ISP_3DNR_V3) || defined (ISP_MI_PP_WRITE_RY) || defined (ISP_MI_HDR_RY)
  157. u32 miv2_mis2;
  158. #endif
  159. pdriver_dev = (struct vvcam_isp_driver_dev *)dev_id;
  160. pisp_dev = pdriver_dev->private;
  161. isp_mis = isp_read_reg(pisp_dev, REG_ADDR(isp_mis));
  162. #ifdef ISP_MIV2_RY
  163. mi_icr_addr = REG_ADDR(miv2_icr);
  164. mi_mis_addr = REG_ADDR(miv2_mis);
  165. miv2_mis1 = isp_read_reg(pisp_dev, REG_ADDR(miv2_mis1));
  166. if (miv2_mis1) {
  167. pr_info("%s mi mis1 0x%08x\n", __func__, miv2_mis1);
  168. isp_write_reg(pisp_dev, REG_ADDR(miv2_icr1), miv2_mis1);
  169. }
  170. miv2_mis3 = isp_read_reg(pisp_dev, REG_ADDR(miv2_mis3));
  171. if (miv2_mis3) {
  172. pr_info("%s mi mis3 0x%08x\n", __func__, miv2_mis3);
  173. isp_write_reg(pisp_dev, REG_ADDR(miv2_icr3), miv2_mis3);
  174. }
  175. #elif defined(ISP_MIV1)
  176. mi_icr_addr = REG_ADDR(mi_icr);
  177. mi_mis_addr = REG_ADDR(mi_mis);
  178. #endif
  179. mi_mis = isp_read_reg(pisp_dev, mi_mis_addr);
  180. #if defined(ISP_MI_PP_READ_RY) || defined (ISP_3DNR_V3) || defined (ISP_MI_PP_WRITE_RY) || defined (ISP_MI_HDR_RY)
  181. miv2_mis2 = isp_read_reg(pisp_dev, REG_ADDR(miv2_mis2));
  182. pr_info("%s isp mis 0x%08x, mi mis 0x%08x post mis 0x%08x\n", __func__, \
  183. isp_mis, mi_mis, miv2_mis2);
  184. #else
  185. pr_info("%s isp mis 0x%08x, mi mis 0x%08x\n", __func__, \
  186. isp_mis, mi_mis);
  187. #endif
  188. if (isp_mis) {
  189. isp_mis_t mis_data;
  190. mis_data.irq_src = SRC_ISP_IRQ;
  191. mis_data.val = isp_mis;
  192. pisp_dev->isp_mis = isp_mis;
  193. isp_irq_write_circle_queue(&mis_data, &pisp_dev->circle_list);
  194. isp_write_reg(pisp_dev, REG_ADDR(isp_icr), isp_mis);
  195. if(isp_mis & MRV_ISP_ISR_ISP_OFF_MASK)
  196. isp_write_reg(pisp_dev, REG_ADDR(isp_imsc), isp_mis& (~MRV_ISP_ISR_ISP_OFF_MASK));
  197. }
  198. if (mi_mis) {
  199. isp_mis_t mis_data;
  200. mis_data.irq_src = SRC_MI_IRQ;
  201. mis_data.val = mi_mis;
  202. isp_irq_write_circle_queue(&mis_data, &pisp_dev->circle_list);
  203. isp_write_reg(pisp_dev, mi_icr_addr, mi_mis);
  204. }
  205. #ifdef ISP_MIV2_RY
  206. if (miv2_mis1) {
  207. isp_mis_t mis_data;
  208. mis_data.irq_src = SRC_MI1_IRQ;
  209. mis_data.val = mi_mis;
  210. isp_irq_write_circle_queue(&mis_data, &pisp_dev->circle_list);
  211. isp_write_reg(pisp_dev, mi_icr_addr, mi_mis);
  212. }
  213. #endif
  214. #if defined(ISP_MI_PP_READ_RY) || defined (ISP_3DNR_V3) || defined (ISP_MI_PP_WRITE_RY) || defined (ISP_MI_HDR_RY)
  215. if (miv2_mis2) {
  216. isp_mis_t mis_data;
  217. mis_data.irq_src = SRC_MI2_IRQ;
  218. mis_data.val = miv2_mis2;
  219. isp_irq_write_circle_queue(&mis_data, &pisp_dev->circle_list);
  220. isp_write_reg(pisp_dev, REG_ADDR(miv2_icr2), miv2_mis2);
  221. }
  222. #endif
  223. #if defined(ISP_MI_PP_READ_RY) || defined (ISP_3DNR_V3) || defined (ISP_MI_PP_WRITE_RY) || defined (ISP_MI_HDR_RY)
  224. if (isp_mis != 0 ||mi_mis != 0 || miv2_mis2 != 0) {
  225. #else
  226. if (isp_mis != 0 ||mi_mis != 0 ) {
  227. #endif
  228. schedule_work(&pdriver_dev->vvnative_wq);
  229. } else {
  230. return IRQ_NONE;
  231. }
  232. return IRQ_HANDLED;
  233. }
  234. static int vvcam_isp_open(struct inode * inode, struct file * file)
  235. {
  236. struct vvcam_isp_driver_dev *pdriver_dev;
  237. struct isp_ic_dev * pisp_dev;
  238. pdriver_dev = container_of(inode->i_cdev, struct vvcam_isp_driver_dev, cdev);
  239. file->private_data = pdriver_dev;
  240. pisp_dev = pdriver_dev->private;
  241. /*create circle queue*/
  242. isp_irq_create_circle_queue(&(pisp_dev->circle_list), QUEUE_NODE_COUNT);
  243. return 0;
  244. };
  245. static long vvcam_isp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  246. {
  247. long ret = 0;
  248. struct vvcam_isp_driver_dev *pdriver_dev;
  249. struct isp_ic_dev * pisp_dev;
  250. pr_err("%s:cmd = %d\n", __func__, cmd);
  251. pdriver_dev = file->private_data;
  252. if (pdriver_dev == NULL)
  253. {
  254. pr_err("%s:file private is null point error\n", __func__);
  255. return -ENOMEM;
  256. }
  257. pisp_dev = pdriver_dev->private;
  258. //pr_info("%s:isp[%d] pdriver_dev =0x%px\n", __func__,pdriver_dev->device_idx,pdriver_dev);
  259. //pr_info("%s:pisp_dev =0x%px\n", __func__,pisp_dev);
  260. mutex_lock(&pdriver_dev->vvmutex);
  261. ret = isp_priv_ioctl(pisp_dev, cmd ,(void __user *)arg);
  262. mutex_unlock(&pdriver_dev->vvmutex);
  263. return ret;
  264. };
  265. static int vvcam_isp_release(struct inode * inode, struct file * file)
  266. {
  267. struct vvcam_isp_driver_dev *pdriver_dev;
  268. struct isp_ic_dev *pisp_dev;
  269. pdriver_dev = container_of(inode->i_cdev, struct vvcam_isp_driver_dev, cdev);
  270. file->private_data = pdriver_dev;
  271. pisp_dev = pdriver_dev->private;
  272. pr_info("enter %s\n", __func__);
  273. isp_irq_destroy_circle_queue(&(pisp_dev->circle_list));
  274. return 0;
  275. };
  276. static int vvcam_isp_mmap(struct file *pFile, struct vm_area_struct *vma)
  277. {
  278. int ret = 0;
  279. ulong phy_base_addr = 0;
  280. unsigned long pfn_start = (phy_base_addr >> PAGE_SHIFT) + vma->vm_pgoff;
  281. unsigned long size = vma->vm_end - vma->vm_start;
  282. pr_info("phy: 0x%lx, size: 0x%lx\n", pfn_start << PAGE_SHIFT, size);
  283. vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
  284. if (remap_pfn_range(vma, vma->vm_start,pfn_start,size, vma->vm_page_prot))
  285. {
  286. pr_err("-->%s: remap_pfn_range error!\n", __func__);
  287. return -EIO;
  288. }
  289. return ret;
  290. };
  291. static struct file_operations vvcam_isp_fops = {
  292. .owner = THIS_MODULE,
  293. .open = vvcam_isp_open,
  294. .release = vvcam_isp_release,
  295. .unlocked_ioctl = vvcam_isp_ioctl,
  296. .mmap = vvcam_isp_mmap,
  297. .poll = vvnative_isp_poll,
  298. };
  299. static int vvcam_isp_probe(struct platform_device *pdev)
  300. {
  301. int ret = 0;
  302. struct vvcam_isp_driver_dev *pdriver_dev;
  303. struct isp_ic_dev * pisp_dev;
  304. struct resource *mem;
  305. pr_info("enter %s\n", __func__);
  306. if (pdev->id >= VIVCAM_ISP_MAXCNT)
  307. {
  308. pr_err("%s:pdev id is %d error\n", __func__,pdev->id);
  309. return -EINVAL;
  310. }
  311. pdriver_dev = devm_kzalloc(&pdev->dev,sizeof(struct vvcam_isp_driver_dev), GFP_KERNEL);
  312. if (pdriver_dev == NULL)
  313. {
  314. pr_err("%s:alloc struct vvcam_isp_driver_dev error\n", __func__);
  315. return -ENOMEM;
  316. }
  317. memset(pdriver_dev,0,sizeof(struct vvcam_isp_driver_dev ));
  318. pr_info("%s:isp[%d]: pdriver_dev =0x%px\n", __func__,pdev->id,pdriver_dev);
  319. pisp_dev = devm_kzalloc(&pdev->dev,sizeof(struct isp_ic_dev), GFP_KERNEL);
  320. if (pisp_dev == NULL)
  321. {
  322. pr_err("%s:alloc struct isp_ic_dev error\n", __func__);
  323. return -ENOMEM;
  324. }
  325. memset(pisp_dev,0,sizeof(struct isp_ic_dev ));
  326. pr_info("%s:isp[%d]: psensor_dev =0x%px\n", __func__,pdev->id,pisp_dev);
  327. mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  328. pisp_dev->base = devm_ioremap_resource(&pdev->dev, mem);
  329. pisp_dev->reset = NULL;
  330. pdriver_dev->private = pisp_dev;
  331. pdriver_dev->device_idx = pdev->id;
  332. mutex_init(&pdriver_dev->vvmutex);
  333. platform_set_drvdata(pdev, pdriver_dev);
  334. pdriver_dev->irq_num = platform_get_irq(pdev, 0);
  335. if (devise_register_index == 0)
  336. {
  337. /*init work queue*/
  338. INIT_WORK(&pdriver_dev->vvnative_wq, vvnative_isp_work);
  339. ret = devm_request_irq(&pdev->dev, pdriver_dev->irq_num, vvcam_isp_irq,
  340. IRQF_TRIGGER_RISING|IRQF_SHARED, "ISP_IRQ", (char *)pdriver_dev);
  341. if (ret) {
  342. pr_err("%s[%d]:request irq error!\n", __func__, __LINE__);
  343. return ret;
  344. }
  345. init_waitqueue_head(&pdriver_dev->irq_wait);
  346. if (vvcam_isp_major == 0)
  347. {
  348. ret = alloc_chrdev_region(&pdriver_dev->devt, 0, VIVCAM_ISP_MAXCNT, VIVCAM_ISP_NAME);
  349. if (ret != 0)
  350. {
  351. pr_err("%s:alloc_chrdev_region error\n", __func__);
  352. return ret;
  353. }
  354. vvcam_isp_major = MAJOR(pdriver_dev->devt);
  355. vvcam_isp_minor = MINOR(pdriver_dev->devt);
  356. }
  357. else
  358. {
  359. pdriver_dev->devt = MKDEV(vvcam_isp_major, vvcam_isp_minor);
  360. ret = register_chrdev_region(pdriver_dev->devt, VIVCAM_ISP_MAXCNT, VIVCAM_ISP_NAME);
  361. if (ret)
  362. {
  363. pr_err("%s:register_chrdev_region error\n", __func__);
  364. return ret;
  365. }
  366. }
  367. vvcam_isp_class = class_create(THIS_MODULE, VIVCAM_ISP_NAME);
  368. if (IS_ERR(vvcam_isp_class))
  369. {
  370. pr_err("%s[%d]:class_create error!\n", __func__, __LINE__);
  371. return -EINVAL;
  372. }
  373. }
  374. pdriver_dev->devt = MKDEV(vvcam_isp_major, vvcam_isp_minor + pdev->id);
  375. cdev_init(&pdriver_dev->cdev, &vvcam_isp_fops);
  376. ret = cdev_add(&pdriver_dev->cdev, pdriver_dev->devt, 1);
  377. if ( ret )
  378. {
  379. pr_err("%s[%d]:cdev_add error!\n", __func__, __LINE__);
  380. return ret;
  381. }
  382. pdriver_dev->class = vvcam_isp_class;
  383. device_create(pdriver_dev->class, NULL, pdriver_dev->devt,
  384. pdriver_dev, "%s%d", VIVCAM_ISP_NAME, pdev->id);
  385. devise_register_index++;
  386. pr_info("exit %s\n", __func__);
  387. return ret;
  388. }
  389. static int vvcam_isp_remove(struct platform_device *pdev)
  390. {
  391. struct vvcam_isp_driver_dev *pdriver_dev;
  392. pr_info("enter %s\n", __func__);
  393. devise_register_index--;
  394. pdriver_dev = platform_get_drvdata(pdev);
  395. // free_irq(pdriver_dev->irq_num, pdriver_dev);
  396. cdev_del(&pdriver_dev->cdev);
  397. device_destroy(pdriver_dev->class, pdriver_dev->devt);
  398. unregister_chrdev_region(pdriver_dev->devt, VIVCAM_ISP_MAXCNT);
  399. if (devise_register_index == 0)
  400. {
  401. class_destroy(pdriver_dev->class);
  402. }
  403. return 0;
  404. }
  405. static struct platform_driver vvcam_isp_driver = {
  406. .probe = vvcam_isp_probe,
  407. .remove = vvcam_isp_remove,
  408. .driver = {
  409. .name = VIVCAM_ISP_NAME,
  410. .owner = THIS_MODULE,
  411. }
  412. };
  413. static void vvcam_isp_pdev_release(struct device *dev)
  414. {
  415. pr_info("enter %s\n", __func__);
  416. }
  417. #ifdef WITH_VVCAM
  418. static struct resource vvcam_isp0_resource[] = {
  419. [0] = {
  420. .start = VVISP0_BASE,
  421. .end = VVISP0_BASE + ISP_REG_SIZE - 1,
  422. .flags = IORESOURCE_MEM,
  423. },
  424. [1] = {
  425. .start = VIVCAM_ISP_IRQ_NUMBER,
  426. .end = VIVCAM_ISP_IRQ_NUMBER,
  427. .flags = IORESOURCE_IRQ,
  428. },
  429. };
  430. static struct platform_device vvcam_isp_pdev = {
  431. .name = VIVCAM_ISP_NAME,
  432. .id = 0,
  433. .resource = vvcam_isp0_resource,
  434. .num_resources = ARRAY_SIZE(vvcam_isp0_resource),
  435. .dev.release = vvcam_isp_pdev_release,
  436. };
  437. #endif
  438. #ifdef WITH_VVCAM_DUAL
  439. static struct resource vvcam_isp1_resource[] = {
  440. [0] = {
  441. .start = VVISP1_BASE,
  442. .end = VVISP1_BASE + ISP_REG_SIZE - 1,
  443. .flags = IORESOURCE_MEM,
  444. },
  445. [1] = {
  446. .start = VIVCAM_ISP_IRQ_NUMBER,
  447. .end = VIVCAM_ISP_IRQ_NUMBER,
  448. .flags = IORESOURCE_IRQ,
  449. },
  450. };
  451. static struct platform_device vvcam_isp_dual_pdev = {
  452. .name = VIVCAM_ISP_NAME,
  453. .id = 1,
  454. .resource = vvcam_isp1_resource,
  455. .num_resources = ARRAY_SIZE(vvcam_isp1_resource),
  456. .dev.release = vvcam_isp_pdev_release,
  457. };
  458. #endif
  459. static int __init vvcam_isp_init_module(void)
  460. {
  461. int ret = 0;
  462. pr_info("enter %s\n", __func__);
  463. #ifdef WITH_VVCAM
  464. ret = platform_device_register(&vvcam_isp_pdev);
  465. if (ret)
  466. {
  467. pr_err("register platform device failed.\n");
  468. return ret;
  469. }
  470. #endif
  471. #ifdef WITH_VVCAM_DUAL
  472. ret = platform_device_register(&vvcam_isp_dual_pdev);
  473. if (ret)
  474. {
  475. pr_err("register platform device failed.\n");
  476. return ret;
  477. }
  478. #endif
  479. ret = platform_driver_register(&vvcam_isp_driver);
  480. if (ret)
  481. {
  482. pr_err("register platform driver failed.\n");
  483. return ret;
  484. }
  485. return ret;
  486. }
  487. static void __exit vvcam_isp_exit_module(void)
  488. {
  489. pr_info("enter %s\n", __func__);
  490. platform_driver_unregister(&vvcam_isp_driver);
  491. #ifdef WITH_VVCAM
  492. platform_device_unregister(&vvcam_isp_pdev);
  493. #endif
  494. #ifdef WITH_VVCAM_DUAL
  495. platform_device_unregister(&vvcam_isp_dual_pdev);
  496. #endif
  497. }
  498. module_init(vvcam_isp_init_module);
  499. module_exit(vvcam_isp_exit_module);
  500. MODULE_DESCRIPTION("ISP");
  501. MODULE_LICENSE("GPL");