vvnative.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  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 <linux/module.h> /* Module support */
  54. #include <linux/version.h> /* Kernel version */
  55. #include <linux/cdev.h> /* Charactor device support */
  56. #include <linux/vermagic.h>
  57. #include <linux/slab.h>
  58. #include <linux/fs.h>
  59. #include <linux/device.h>
  60. #include <linux/ioctl.h>
  61. #include <linux/mm.h>
  62. #include "vvnative.h"
  63. #include "vvnative_cfg.h"
  64. #include "vvnative_combo.h"
  65. #ifdef SENSOR_USE_GPIO_I2C
  66. #include "soc_i2c.h"
  67. #endif
  68. #ifndef MODULE_LICENSE
  69. # define MODULE_LICENSE(x)
  70. #endif /* MODULE_LICENSE */
  71. #ifndef MODULE_VERSION
  72. # define MODULE_VERSION(x)
  73. #endif /* MODULE_VERSION */
  74. #define DRIVER_AUTHOR "VeriSilicon IPD"
  75. #define DRIVER_DESC "Verisilicon ISP driver"
  76. #define DRIVER_LICENSE "GPL"
  77. #define DRIVER_VERSION "1.0"
  78. #ifdef MODULE
  79. MODULE_AUTHOR( DRIVER_AUTHOR );
  80. MODULE_DESCRIPTION( DRIVER_DESC );
  81. MODULE_LICENSE( DRIVER_LICENSE );
  82. MODULE_INFO( vermagic, VERMAGIC_STRING);
  83. #endif /* MODULE */
  84. /* vvcam_isp_dev_major: device major number */
  85. unsigned int vvcam_isp_dev_major = 0;
  86. module_param(vvcam_isp_dev_major, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  87. MODULE_PARM_DESC(vvcam_isp_dev_major, "vvcam ISP device major number");
  88. /* vvcam_isp_dev_minor: device base(start) minor number */
  89. unsigned int vvcam_isp_dev_minor = 0;
  90. module_param(vvcam_isp_dev_minor, uint, S_IRUGO | S_IWUSR);
  91. MODULE_PARM_DESC(vvcam_isp_dev_minor, "vvcam ISP device base minor number");
  92. /* vvcam_isp_dev_count: counts */
  93. unsigned int vvcam_isp_dev_count = VVCAM_ISP_DEVICES;
  94. module_param(vvcam_isp_dev_count, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  95. MODULE_PARM_DESC(vvcam_isp_dev_count, "vvcam ISP device counts");
  96. struct vvcam_isp_dev *vvcam_isp_drv;
  97. struct vvcam_common *vvcam_drv_common;
  98. static int vvcam_isp_dev_open(struct inode *inode, struct file *file);
  99. static int vvcam_isp_dev_release(struct inode *inode, struct file *file);
  100. static long vvcam_isp_dev_ioctl(struct file * pFile, unsigned int cmd, unsigned long arg);
  101. static int vvcam_isp_dev_mmap(struct file *pFile, struct vm_area_struct *vma);
  102. static int vvcam_isp_devio_remap(int dev_no);
  103. static int vvcam_isp_devio_unmap(int dev_no);
  104. long (*vvnative_ioctl[])(struct vvcam_isp_dev *vvcam_isp_drv,unsigned int cmd, void *args)=
  105. {
  106. vvcam_combo_isp_ioctl, /*devid0*/
  107. vvcam_combo_isp_ioctl, /*devid1*/
  108. vvcam_combo_csi_ioctl, /*devid2*/
  109. vvcam_combo_csi_ioctl, /*devid3*/
  110. vvcam_combo_sensor_ioctl, /*devid4*/
  111. vvcam_combo_sensor_ioctl, /*devid5*/
  112. vvcam_combo_dwe_ioctl, /*devid6*/
  113. vvcam_combo_vse_ioctl, /*devid7*/
  114. vvcam_combo_soc_ioctl, /*devid8*/
  115. };
  116. int (*vvnative_init[])(struct vvcam_isp_dev *vvcam_isp_drv)=
  117. {
  118. vvcam_combo_isp_init, /*devid0*/
  119. vvcam_combo_isp_init, /*devid1*/
  120. vvcam_combo_csi_init, /*devid2*/
  121. vvcam_combo_csi_init, /*devid3*/
  122. vvcam_combo_sensor_init, /*devid4*/
  123. vvcam_combo_sensor_init, /*devid5*/
  124. vvcam_combo_dwe_init, /*devid6*/
  125. vvcam_combo_vse_init, /*devid7*/
  126. vvcam_combo_soc_init, /*devid8*/
  127. };
  128. int (*vvnative_deinit[])(struct vvcam_isp_dev *vvcam_isp_drv)=
  129. {
  130. vvcam_combo_isp_deinit, /*devid0*/
  131. vvcam_combo_isp_deinit, /*devid1*/
  132. vvcam_combo_csi_deinit, /*devid2*/
  133. vvcam_combo_csi_deinit, /*devid3*/
  134. vvcam_combo_sensor_deinit, /*devid4*/
  135. vvcam_combo_sensor_deinit, /*devid5*/
  136. vvcam_combo_dwe_deinit, /*devid6*/
  137. vvcam_combo_vse_deinit, /*devid7*/
  138. vvcam_combo_soc_deinit, /*devid8*/
  139. };
  140. /*TODO:expand dual camera devs*/
  141. struct file_operations vvcam_isp_fops = {
  142. .owner = THIS_MODULE,
  143. .open = vvcam_isp_dev_open,
  144. .release = vvcam_isp_dev_release,
  145. .unlocked_ioctl = vvcam_isp_dev_ioctl,
  146. .mmap = vvcam_isp_dev_mmap,
  147. };
  148. /*On-the-fly debug opitions*/
  149. char * on_the_fly_str="VIV ISP local debug buffer";
  150. static void vivdev_dump_buf(unsigned char *out_buf, unsigned char* dump_data, int len, unsigned char * phy_address)
  151. {
  152. int m;
  153. int n;
  154. char *buf;
  155. buf = out_buf;
  156. int llength = 0x10;
  157. unsigned int udata;
  158. sprintf (buf, "Phy Addr: 0x%lx, Va Addr:0x%lx, len:%d\n", (unsigned long)phy_address, dump_data, len);
  159. buf += strlen(buf);
  160. for (m=0; m<len; m++)
  161. {
  162. if(m%llength == 0)
  163. {
  164. sprintf(buf, "%04x| ", m);
  165. buf += strlen(buf);
  166. }
  167. if((m%2) == 0){
  168. sprintf (buf, " ");
  169. buf += strlen(buf);
  170. }
  171. udata = (unsigned int)(*(dump_data+m));
  172. sprintf (buf, "%02x", udata&0xff);
  173. buf += strlen(buf);
  174. if(m%llength == (llength-1))
  175. {
  176. sprintf (buf, " | ");
  177. buf += strlen(buf);
  178. for (n=llength;n>0;n--)
  179. {
  180. if ((*(dump_data+m+1-n)>31) && (*(dump_data+m+1-n)<127))
  181. {
  182. sprintf (buf, "%c", *(dump_data+m+1-n));
  183. buf += strlen(buf);
  184. }
  185. else
  186. {
  187. sprintf (buf, ".");
  188. buf += strlen(buf);
  189. }
  190. }
  191. sprintf (buf, "\n");
  192. buf += strlen(buf);
  193. }
  194. }
  195. sprintf (buf, "\n");
  196. buf += strlen(buf);
  197. }
  198. static ssize_t get_vivdev(struct device *dev,
  199. struct device_attribute *attr, char *buf)
  200. {
  201. const char * name;
  202. char dev_name_perfix[8];
  203. int dev_index;
  204. int ret;
  205. if(NULL == vvcam_drv_common)
  206. {
  207. pr_info("-->%s Error, null pointer of vvcam_drv_common\n", __func__);
  208. return 0;
  209. }
  210. mutex_lock(&vvcam_drv_common->vvmutex);
  211. name = dev_name(dev);
  212. pr_info("-->%s dev_name name:%s\n", __func__, name);
  213. ret = sscanf(name, "%6s%d", dev_name_perfix, &dev_index);
  214. pr_info("-->%s sscanf ret:%d, name:%s, id:%d\n", __func__, ret, dev_name_perfix, dev_index);
  215. ret = sprintf(buf, "%s\n", vvcam_drv_common->viv_buf);
  216. mutex_unlock(&vvcam_drv_common->vvmutex);
  217. return ret;
  218. }
  219. static ssize_t set_vivdev(struct device *dev,
  220. struct device_attribute *attr,
  221. const char *buf, size_t len)
  222. {
  223. const char * name;
  224. char dev_name_perfix[8];
  225. int dev_index;
  226. unsigned int data;
  227. unsigned int addr;
  228. unsigned int read_cnt;
  229. unsigned char mode;
  230. int ret;
  231. if(NULL == vvcam_drv_common)
  232. {
  233. pr_info("-->%s Error, null pointer of vvcam_drv_common\n", __func__);
  234. return 0;
  235. }
  236. mutex_lock(&vvcam_drv_common->vvmutex);
  237. name = dev_name(dev);
  238. pr_info("-->%s dev_name name:%s\n", __func__, name);
  239. ret = sscanf(name, "%6s%d", dev_name_perfix, &dev_index);
  240. pr_info("-->%s sscanf ret:%d, name:%s, id:%d\n", __func__, ret, dev_name_perfix, dev_index);
  241. ret = sscanf(buf, "%c, 0x%x, 0x%x, 0x%d", &mode, &addr, &data, &read_cnt);
  242. if(ret < 3)
  243. {
  244. sprintf(vvcam_drv_common->viv_buf, "Error input string %s The parameters number:%d, expect format: 'r/w, 0xAddress, 0xData, 0xReadCnt'",
  245. buf, ret);
  246. pr_info("Error input string %s The parameters number:%d, expect format: 'r/w, 0xAddress, 0xData, 0xReadNumber'",buf, ret);
  247. mutex_unlock(&vvcam_drv_common->vvmutex);
  248. return len;
  249. }
  250. sprintf(vvcam_drv_common->viv_buf, "init: %s, scanf ret:%d, mode:%c, addr:0x%x, data:0x%x, readcnt:0x%x", buf, ret, mode, addr, data, read_cnt);
  251. pr_info("-->%s init: %s, scanf ret:%d, mode:%c, addr:0x%x, data:0x%x, readcnt:0x%x", __func__, buf, ret, mode, addr, data, read_cnt);
  252. vivdev_dump_buf((unsigned char*)vvcam_drv_common->viv_buf, on_the_fly_str, strlen(on_the_fly_str), 0xaaaa);
  253. mutex_unlock(&vvcam_drv_common->vvmutex);
  254. return len;
  255. }
  256. static DEVICE_ATTR(vivdevio, S_IWUSR|S_IRUSR|S_IRGRP|S_IWGRP|S_IROTH, get_vivdev, set_vivdev);
  257. static int vvcam_isp_dev_open(struct inode *inode, struct file *file)
  258. {
  259. int minor = iminor(inode);
  260. pr_info("-->%s: ISPdev%d opened\n", __func__, minor);
  261. mutex_lock(&(vvcam_isp_drv + minor)->vvmutex);
  262. if((vvcam_isp_drv + minor)->open_cnt >= VVISP_OPEN_LIMITATION)
  263. {
  264. pr_info("-->%s: ISPdev%d cannot open device\n", __func__, minor);
  265. mutex_unlock(&(vvcam_isp_drv + minor)->vvmutex);
  266. return -EBUSY;
  267. }
  268. if((vvcam_isp_drv + minor)->initialized == 0)
  269. {
  270. pr_info("-->%s: ISPdev%d device not initialized\n", __func__, minor);
  271. mutex_unlock(&(vvcam_isp_drv + minor)->vvmutex);
  272. return -EBUSY;
  273. }
  274. (vvcam_isp_drv + minor)->open_cnt++;
  275. pr_info("-->%s: ISPdev%d update open_cnt to %d\n", __func__, minor, (vvcam_isp_drv + minor)->open_cnt);
  276. try_module_get(THIS_MODULE);
  277. mutex_unlock(&(vvcam_isp_drv + minor)->vvmutex);
  278. return 0;
  279. }
  280. /* Called when a process closes the device file */
  281. static int vvcam_isp_dev_release(struct inode *inode, struct file *file)
  282. {
  283. int minor = iminor(inode);
  284. pr_info("-->%s: ISPdev%d releaseing...\n", __func__, minor);
  285. mutex_lock(&(vvcam_isp_drv + minor)->vvmutex);
  286. if((vvcam_isp_drv + minor)->open_cnt <= 0)
  287. {
  288. pr_info("-->%s: ISPdev%d internal error\n", __func__, minor);
  289. mutex_unlock(&(vvcam_isp_drv + minor)->vvmutex);
  290. return -EBUSY;
  291. }
  292. (vvcam_isp_drv + minor)->open_cnt--;
  293. module_put(THIS_MODULE);
  294. mutex_unlock(&(vvcam_isp_drv + minor)->vvmutex);
  295. return 0;
  296. }
  297. static long vvcam_isp_dev_ioctl(struct file * pFile, unsigned int cmd, unsigned long arg)
  298. {
  299. long ret;
  300. struct inode *inode =pFile->f_mapping->host;
  301. int minor = iminor(inode);
  302. pr_info("-->%s: ISPdev%d Ioctl runs, cmd:%d, args:%ld...\n", __func__, minor, cmd, arg);
  303. ret = (*(vvnative_ioctl+minor))(vvcam_isp_drv + minor, cmd, arg);
  304. return ret;
  305. };
  306. static int vvcam_isp_dev_mmap(struct file *pFile, struct vm_area_struct *vma)
  307. {
  308. struct inode *inode =pFile->f_mapping->host;
  309. int minor = iminor(inode);
  310. ulong img_buf_base = vvnative_get_img_buf_base();
  311. ulong img_buf_size = vvnative_get_img_buf_size();
  312. unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
  313. unsigned long pfn_start = (img_buf_base >> PAGE_SHIFT) + vma->vm_pgoff;
  314. unsigned long size = vma->vm_end - vma->vm_start;
  315. int ret = 0;
  316. if(size > img_buf_size)
  317. {
  318. size = img_buf_size;
  319. }
  320. pr_info("-->%s: ISPdev%d mmap runs...\n", __func__, minor);
  321. pr_info("-->%s: mmap parameters: phy start:0x%lx, ph size:0x%lx, vm start: 0x%lx, size: 0x%lx, offset, page start: 0x%lx\n",
  322. __func__, img_buf_base, img_buf_size, vma->vm_start, size, offset, pfn_start);
  323. /* Map reserved image buffer memory. */
  324. if (remap_pfn_range(vma, vma->vm_start,
  325. (img_buf_base >> PAGE_SHIFT),
  326. size, vma->vm_page_prot))
  327. {
  328. pr_err("-->%s: remap_pfn_range error!\n", __func__);
  329. pr_info("-->%s: mmap parameters: phy start:0x%lx, ph size:0x%lx, vm start: 0x%lx, size: 0x%lx, offset\n",
  330. __func__, img_buf_base, img_buf_size, vma->vm_start, size, offset);
  331. return -EIO;
  332. }
  333. return ret;
  334. };
  335. static int vvcam_isp_devio_remap(int dev_no)
  336. {
  337. void __iomem *addr;
  338. ulong reg_base = vvnative_get_reg_base_by_idx(dev_no);
  339. ulong reg_size = vvnative_get_reg_size_by_idx(dev_no);
  340. if(NULL == vvcam_isp_drv)
  341. {
  342. pr_err("-->%s: NULL pointer!\n", __func__);
  343. return -1;
  344. }
  345. (vvcam_isp_drv + dev_no)->phy_address = reg_base;
  346. (vvcam_isp_drv + dev_no)->size = reg_size;
  347. pr_info("ioremap of dev: %d, phy address:0x%lx, size:0x%lx\n", dev_no, reg_base, reg_size);
  348. if((0 == reg_base) ||(0 == reg_size))
  349. {
  350. (vvcam_isp_drv + dev_no)->base_address = NULL;
  351. pr_info("ioremap of dev: %d, phy address is 0\n", dev_no);
  352. }else{
  353. addr = ioremap(reg_base, reg_size);
  354. pr_info("ioremap of dev: %d, address:0x%lx\n", dev_no, (unsigned long)addr);
  355. (vvcam_isp_drv + dev_no)->base_address = addr;
  356. }
  357. return 0;
  358. }
  359. static int vvcam_isp_devio_unmap(int dev_no)
  360. {
  361. if((NULL == vvcam_isp_drv))
  362. {
  363. pr_err("-->%s: NULL pointer!\n", __func__);
  364. return -1;
  365. }
  366. if(NULL != (vvcam_isp_drv + dev_no)->base_address)
  367. {
  368. iounmap((vvcam_isp_drv + dev_no)->base_address);
  369. }
  370. return 0;
  371. }
  372. /*!
  373. *******************************************************************************
  374. ** First function called by the OS. This function registers the device and
  375. ** vendor id that this driver handles.
  376. */
  377. int __init vvcam_isp_dev_initialize( void )
  378. {
  379. int result = 0;
  380. struct device *dev;
  381. dev_t devt;
  382. int retval;
  383. int dev_idx = 0;
  384. struct class *vvisp_class;
  385. pr_info("-->%s enter\n", __func__);
  386. pr_info("-->%s : %d, registerMemBase = 0x%lx, dev number:%d\n", __func__, __LINE__, VVISP0_BASE, VVCAM_ISP_DEVICES);
  387. /**********************************************************************
  388. * register/alloc the device major number and range, if
  389. * major = 0, alloc from kernel to get an available device major number
  390. * major != 0, use the specific value as major number, this value may be invalid
  391. **********************************************************************/
  392. vvcam_isp_drv = kzalloc(sizeof(struct vvcam_isp_dev) * VVCAM_ISP_DEVICES, GFP_KERNEL);
  393. if (!vvcam_isp_drv)
  394. {
  395. return -ENOMEM;
  396. }
  397. vvcam_drv_common = kzalloc(sizeof(struct vvcam_common), GFP_KERNEL);
  398. if (!vvcam_drv_common)
  399. {
  400. return -ENOMEM;
  401. }
  402. if (0 == vvcam_isp_dev_major)
  403. {
  404. result = alloc_chrdev_region(&devt, 0, VVCAM_ISP_DEVICES, DRIVER_NAME);
  405. if (result)
  406. {
  407. goto fail_check;
  408. }
  409. vvcam_isp_dev_major = MAJOR(devt);
  410. vvcam_isp_dev_minor = MINOR(devt);
  411. }
  412. else
  413. {
  414. devt = MKDEV(vvcam_isp_dev_major, vvcam_isp_dev_minor);
  415. result = register_chrdev_region(devt, VVCAM_ISP_DEVICES, DRIVER_NAME);
  416. if (result)
  417. {
  418. result = -EBUSY;
  419. goto fail_check;
  420. }
  421. }
  422. pr_info("--> vvcam ISP init, major id: %d, minor id: %d\n", MAJOR(devt), MINOR(devt));
  423. vvisp_class = class_create(THIS_MODULE, DRIVER_NAME);
  424. if (IS_ERR(vvisp_class))
  425. {
  426. pr_info("-->%s : %d, class_create error!\n", __func__, __LINE__);
  427. goto fail_check;
  428. }
  429. dev_idx = 0;
  430. for(dev_idx = 0; dev_idx < VVCAM_ISP_DEVICES; dev_idx++)
  431. {
  432. if(strcmp(vvnative_get_dev_name_by_idx(dev_idx), VVNATIVE_NA) == 0)
  433. {
  434. pr_info("--> subisp%d is absent, id number:%s, skip..\n", dev_idx, vvnative_get_dev_name_by_idx(dev_idx) );
  435. (vvcam_isp_drv + dev_idx)->initialized = 0;
  436. continue;
  437. }
  438. (vvcam_isp_drv + dev_idx)->devt = MKDEV(vvcam_isp_dev_major, vvcam_isp_dev_minor + dev_idx);
  439. pr_info("--> subisp%d reg, major id: %d, minor id: %d, dev_name:%s\n", dev_idx,
  440. MAJOR((vvcam_isp_drv + dev_idx)->devt), MINOR((vvcam_isp_drv + dev_idx)->devt),
  441. vvnative_get_dev_name_by_idx(dev_idx));
  442. cdev_init(&(vvcam_isp_drv + dev_idx)->cdev, &vvcam_isp_fops);
  443. (vvcam_isp_drv + dev_idx)->cdev.owner = THIS_MODULE;
  444. retval = cdev_add(&(vvcam_isp_drv + dev_idx)->cdev, (vvcam_isp_drv + dev_idx)->devt, 1);
  445. if (retval)
  446. {
  447. pr_info("-->%s : %d, cdev_add error!\n", __func__, __LINE__);
  448. goto fail_check;
  449. }
  450. (vvcam_isp_drv + dev_idx)->class = vvisp_class;
  451. dev = device_create((vvcam_isp_drv + dev_idx)->class, NULL, (vvcam_isp_drv + dev_idx)->devt,
  452. (vvcam_isp_drv + dev_idx), "%s%d", vvnative_get_dev_name_by_idx(dev_idx), vvnative_get_dev_idx(dev_idx));
  453. if (IS_ERR(dev))
  454. {
  455. pr_info("-->%s : %d, device_create error!\n", __func__, __LINE__);
  456. class_destroy(vvcam_isp_drv->class);
  457. goto fail_check;
  458. }
  459. pr_info("-->dev create for subisp %s %d done\n", DRIVER_NAME, dev_idx);
  460. (vvcam_isp_drv + dev_idx)->dev = dev;
  461. if(sysfs_create_file(&(dev->kobj), &dev_attr_vivdevio.attr)) {
  462. pr_info("-->%s : %d, sysfs_create_file error!\n", __func__, __LINE__);
  463. goto fail_check;
  464. }
  465. /* init */
  466. mutex_init(&(vvcam_isp_drv + dev_idx)->vvmutex);
  467. (vvcam_isp_drv + dev_idx)->open_cnt = 0;
  468. (vvcam_isp_drv + dev_idx)->initialized = 1;
  469. (vvcam_isp_drv + dev_idx)->dev_idx = vvnative_get_dev_idx(dev_idx);
  470. result = vvcam_isp_devio_remap(dev_idx);
  471. if(result)
  472. {
  473. pr_err("-->%s: vvcam_isp_devio_remap error!\n", __func__);
  474. goto fail_check;
  475. }
  476. /* submodule initialization */
  477. result = (*(vvnative_init+dev_idx))(vvcam_isp_drv + dev_idx);
  478. if(result)
  479. {
  480. pr_err("-->%s: vvnative_init error with subdev:%d!\n", __func__, dev_idx);
  481. goto fail_check;
  482. }
  483. }
  484. /* on-the-fly debug init */
  485. mutex_init(&vvcam_drv_common->vvmutex);
  486. sprintf(vvcam_drv_common->viv_buf, "vivisp_buf");
  487. return result;
  488. fail_check:
  489. /* Unregister char driver */
  490. pr_info("-->vvcam_isp_dev_initialize error\n");
  491. unregister_chrdev_region(devt, VVCAM_ISP_DEVICES);
  492. return result;
  493. }
  494. /*!
  495. *******************************************************************************
  496. ** Unload the driver module
  497. */
  498. void __exit vvcam_isp_dev_cleanup( void )
  499. {
  500. int result = 0;
  501. int dev_idx = 0;
  502. pr_info("-->%s enter\n", __func__);
  503. if(NULL == vvcam_isp_drv)
  504. {
  505. pr_info("-->%s Internal error, NULL pointer\n", __func__);
  506. return;
  507. }
  508. for(dev_idx = 0; dev_idx < VVCAM_ISP_DEVICES; dev_idx++)
  509. {
  510. if(0 == (vvcam_isp_drv + dev_idx)->initialized)
  511. {
  512. continue;
  513. }
  514. /* submodule un-initialization */
  515. result = (*(vvnative_deinit+dev_idx))(vvcam_isp_drv + dev_idx);
  516. if(result)
  517. {
  518. pr_err("-->%s: vvnative_deinit error with subdev:%d!\n", __func__, dev_idx);
  519. }
  520. result = vvcam_isp_devio_unmap(dev_idx);
  521. if(result)
  522. {
  523. pr_err("-->%s: vvcam_isp_devio_unmap error!\n", __func__);
  524. }
  525. device_destroy((vvcam_isp_drv + dev_idx)->class, (vvcam_isp_drv + dev_idx)->devt);
  526. cdev_del(&(vvcam_isp_drv + dev_idx)->cdev);
  527. /* remove the char device structure (has been added) */
  528. unregister_chrdev_region((vvcam_isp_drv + dev_idx)->devt, VVCAM_ISP_DEVICES);
  529. (vvcam_isp_drv + dev_idx)->dev = NULL;
  530. (vvcam_isp_drv + dev_idx)->open_cnt = 0;
  531. }
  532. class_destroy(vvcam_isp_drv->class);
  533. vvcam_isp_drv->class = NULL;
  534. kfree(vvcam_isp_drv);
  535. vvcam_isp_drv = NULL;
  536. kfree(vvcam_drv_common);
  537. vvcam_drv_common = NULL;
  538. return;
  539. }
  540. module_init(vvcam_isp_dev_initialize);
  541. module_exit(vvcam_isp_dev_cleanup);
  542. MODULE_LICENSE ("GPL");