isif.c 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165
  1. /*
  2. * Copyright (C) 2008-2009 Texas Instruments Inc
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. *
  18. * Image Sensor Interface (ISIF) driver
  19. *
  20. * This driver is for configuring the ISIF IP available on DM365 or any other
  21. * TI SoCs. This is used for capturing yuv or bayer video or image data
  22. * from a decoder or sensor. This IP is similar to the CCDC IP on DM355
  23. * and DM6446, but with enhanced or additional ip blocks. The driver
  24. * configures the ISIF upon commands from the vpfe bridge driver through
  25. * ccdc_hw_device interface.
  26. *
  27. * TODO: 1) Raw bayer parameter settings and bayer capture
  28. * 2) Add support for control ioctl
  29. */
  30. #include <linux/delay.h>
  31. #include <linux/platform_device.h>
  32. #include <linux/uaccess.h>
  33. #include <linux/io.h>
  34. #include <linux/videodev2.h>
  35. #include <linux/clk.h>
  36. #include <linux/err.h>
  37. #include <linux/module.h>
  38. #include <mach/mux.h>
  39. #include <media/davinci/isif.h>
  40. #include <media/davinci/vpss.h>
  41. #include "isif_regs.h"
  42. #include "ccdc_hw_device.h"
  43. /* Defaults for module configuration parameters */
  44. static struct isif_config_params_raw isif_config_defaults = {
  45. .linearize = {
  46. .en = 0,
  47. .corr_shft = ISIF_NO_SHIFT,
  48. .scale_fact = {1, 0},
  49. },
  50. .df_csc = {
  51. .df_or_csc = 0,
  52. .csc = {
  53. .en = 0,
  54. },
  55. },
  56. .dfc = {
  57. .en = 0,
  58. },
  59. .bclamp = {
  60. .en = 0,
  61. },
  62. .gain_offset = {
  63. .gain = {
  64. .r_ye = {1, 0},
  65. .gr_cy = {1, 0},
  66. .gb_g = {1, 0},
  67. .b_mg = {1, 0},
  68. },
  69. },
  70. .culling = {
  71. .hcpat_odd = 0xff,
  72. .hcpat_even = 0xff,
  73. .vcpat = 0xff,
  74. },
  75. .compress = {
  76. .alg = ISIF_ALAW,
  77. },
  78. };
  79. /* ISIF operation configuration */
  80. static struct isif_oper_config {
  81. struct device *dev;
  82. enum vpfe_hw_if_type if_type;
  83. struct isif_ycbcr_config ycbcr;
  84. struct isif_params_raw bayer;
  85. enum isif_data_pack data_pack;
  86. /* Master clock */
  87. struct clk *mclk;
  88. /* ISIF base address */
  89. void __iomem *base_addr;
  90. /* ISIF Linear Table 0 */
  91. void __iomem *linear_tbl0_addr;
  92. /* ISIF Linear Table 1 */
  93. void __iomem *linear_tbl1_addr;
  94. } isif_cfg = {
  95. .ycbcr = {
  96. .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
  97. .frm_fmt = CCDC_FRMFMT_INTERLACED,
  98. .win = ISIF_WIN_NTSC,
  99. .fid_pol = VPFE_PINPOL_POSITIVE,
  100. .vd_pol = VPFE_PINPOL_POSITIVE,
  101. .hd_pol = VPFE_PINPOL_POSITIVE,
  102. .pix_order = CCDC_PIXORDER_CBYCRY,
  103. .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED,
  104. },
  105. .bayer = {
  106. .pix_fmt = CCDC_PIXFMT_RAW,
  107. .frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
  108. .win = ISIF_WIN_VGA,
  109. .fid_pol = VPFE_PINPOL_POSITIVE,
  110. .vd_pol = VPFE_PINPOL_POSITIVE,
  111. .hd_pol = VPFE_PINPOL_POSITIVE,
  112. .gain = {
  113. .r_ye = {1, 0},
  114. .gr_cy = {1, 0},
  115. .gb_g = {1, 0},
  116. .b_mg = {1, 0},
  117. },
  118. .cfa_pat = ISIF_CFA_PAT_MOSAIC,
  119. .data_msb = ISIF_BIT_MSB_11,
  120. .config_params = {
  121. .data_shift = ISIF_NO_SHIFT,
  122. .col_pat_field0 = {
  123. .olop = ISIF_GREEN_BLUE,
  124. .olep = ISIF_BLUE,
  125. .elop = ISIF_RED,
  126. .elep = ISIF_GREEN_RED,
  127. },
  128. .col_pat_field1 = {
  129. .olop = ISIF_GREEN_BLUE,
  130. .olep = ISIF_BLUE,
  131. .elop = ISIF_RED,
  132. .elep = ISIF_GREEN_RED,
  133. },
  134. .test_pat_gen = 0,
  135. },
  136. },
  137. .data_pack = ISIF_DATA_PACK8,
  138. };
  139. /* Raw Bayer formats */
  140. static const u32 isif_raw_bayer_pix_formats[] = {
  141. V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
  142. /* Raw YUV formats */
  143. static const u32 isif_raw_yuv_pix_formats[] = {
  144. V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
  145. /* register access routines */
  146. static inline u32 regr(u32 offset)
  147. {
  148. return __raw_readl(isif_cfg.base_addr + offset);
  149. }
  150. static inline void regw(u32 val, u32 offset)
  151. {
  152. __raw_writel(val, isif_cfg.base_addr + offset);
  153. }
  154. /* reg_modify() - read, modify and write register */
  155. static inline u32 reg_modify(u32 mask, u32 val, u32 offset)
  156. {
  157. u32 new_val = (regr(offset) & ~mask) | (val & mask);
  158. regw(new_val, offset);
  159. return new_val;
  160. }
  161. static inline void regw_lin_tbl(u32 val, u32 offset, int i)
  162. {
  163. if (!i)
  164. __raw_writel(val, isif_cfg.linear_tbl0_addr + offset);
  165. else
  166. __raw_writel(val, isif_cfg.linear_tbl1_addr + offset);
  167. }
  168. static void isif_disable_all_modules(void)
  169. {
  170. /* disable BC */
  171. regw(0, CLAMPCFG);
  172. /* disable vdfc */
  173. regw(0, DFCCTL);
  174. /* disable CSC */
  175. regw(0, CSCCTL);
  176. /* disable linearization */
  177. regw(0, LINCFG0);
  178. /* disable other modules here as they are supported */
  179. }
  180. static void isif_enable(int en)
  181. {
  182. if (!en) {
  183. /* Before disable isif, disable all ISIF modules */
  184. isif_disable_all_modules();
  185. /*
  186. * wait for next VD. Assume lowest scan rate is 12 Hz. So
  187. * 100 msec delay is good enough
  188. */
  189. msleep(100);
  190. }
  191. reg_modify(ISIF_SYNCEN_VDHDEN_MASK, en, SYNCEN);
  192. }
  193. static void isif_enable_output_to_sdram(int en)
  194. {
  195. reg_modify(ISIF_SYNCEN_WEN_MASK, en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN);
  196. }
  197. static void isif_config_culling(struct isif_cul *cul)
  198. {
  199. u32 val;
  200. /* Horizontal pattern */
  201. val = (cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT) | cul->hcpat_odd;
  202. regw(val, CULH);
  203. /* vertical pattern */
  204. regw(cul->vcpat, CULV);
  205. /* LPF */
  206. reg_modify(ISIF_LPF_MASK << ISIF_LPF_SHIFT,
  207. cul->en_lpf << ISIF_LPF_SHIFT, MODESET);
  208. }
  209. static void isif_config_gain_offset(void)
  210. {
  211. struct isif_gain_offsets_adj *gain_off_p =
  212. &isif_cfg.bayer.config_params.gain_offset;
  213. u32 val;
  214. val = (!!gain_off_p->gain_sdram_en << GAIN_SDRAM_EN_SHIFT) |
  215. (!!gain_off_p->gain_ipipe_en << GAIN_IPIPE_EN_SHIFT) |
  216. (!!gain_off_p->gain_h3a_en << GAIN_H3A_EN_SHIFT) |
  217. (!!gain_off_p->offset_sdram_en << OFST_SDRAM_EN_SHIFT) |
  218. (!!gain_off_p->offset_ipipe_en << OFST_IPIPE_EN_SHIFT) |
  219. (!!gain_off_p->offset_h3a_en << OFST_H3A_EN_SHIFT);
  220. reg_modify(GAIN_OFFSET_EN_MASK, val, CGAMMAWD);
  221. val = (gain_off_p->gain.r_ye.integer << GAIN_INTEGER_SHIFT) |
  222. gain_off_p->gain.r_ye.decimal;
  223. regw(val, CRGAIN);
  224. val = (gain_off_p->gain.gr_cy.integer << GAIN_INTEGER_SHIFT) |
  225. gain_off_p->gain.gr_cy.decimal;
  226. regw(val, CGRGAIN);
  227. val = (gain_off_p->gain.gb_g.integer << GAIN_INTEGER_SHIFT) |
  228. gain_off_p->gain.gb_g.decimal;
  229. regw(val, CGBGAIN);
  230. val = (gain_off_p->gain.b_mg.integer << GAIN_INTEGER_SHIFT) |
  231. gain_off_p->gain.b_mg.decimal;
  232. regw(val, CBGAIN);
  233. regw(gain_off_p->offset, COFSTA);
  234. }
  235. static void isif_restore_defaults(void)
  236. {
  237. enum vpss_ccdc_source_sel source = VPSS_CCDCIN;
  238. dev_dbg(isif_cfg.dev, "\nstarting isif_restore_defaults...");
  239. isif_cfg.bayer.config_params = isif_config_defaults;
  240. /* Enable clock to ISIF, IPIPEIF and BL */
  241. vpss_enable_clock(VPSS_CCDC_CLOCK, 1);
  242. vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1);
  243. vpss_enable_clock(VPSS_BL_CLOCK, 1);
  244. /* Set default offset and gain */
  245. isif_config_gain_offset();
  246. vpss_select_ccdc_source(source);
  247. dev_dbg(isif_cfg.dev, "\nEnd of isif_restore_defaults...");
  248. }
  249. static int isif_open(struct device *device)
  250. {
  251. isif_restore_defaults();
  252. return 0;
  253. }
  254. /* This function will configure the window size to be capture in ISIF reg */
  255. static void isif_setwin(struct v4l2_rect *image_win,
  256. enum ccdc_frmfmt frm_fmt, int ppc)
  257. {
  258. int horz_start, horz_nr_pixels;
  259. int vert_start, vert_nr_lines;
  260. int mid_img = 0;
  261. dev_dbg(isif_cfg.dev, "\nStarting isif_setwin...");
  262. /*
  263. * ppc - per pixel count. indicates how many pixels per cell
  264. * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
  265. * raw capture this is 1
  266. */
  267. horz_start = image_win->left << (ppc - 1);
  268. horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1;
  269. /* Writing the horizontal info into the registers */
  270. regw(horz_start & START_PX_HOR_MASK, SPH);
  271. regw(horz_nr_pixels & NUM_PX_HOR_MASK, LNH);
  272. vert_start = image_win->top;
  273. if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
  274. vert_nr_lines = (image_win->height >> 1) - 1;
  275. vert_start >>= 1;
  276. /* To account for VD since line 0 doesn't have any data */
  277. vert_start += 1;
  278. } else {
  279. /* To account for VD since line 0 doesn't have any data */
  280. vert_start += 1;
  281. vert_nr_lines = image_win->height - 1;
  282. /* configure VDINT0 and VDINT1 */
  283. mid_img = vert_start + (image_win->height / 2);
  284. regw(mid_img, VDINT1);
  285. }
  286. regw(0, VDINT0);
  287. regw(vert_start & START_VER_ONE_MASK, SLV0);
  288. regw(vert_start & START_VER_TWO_MASK, SLV1);
  289. regw(vert_nr_lines & NUM_LINES_VER, LNV);
  290. }
  291. static void isif_config_bclamp(struct isif_black_clamp *bc)
  292. {
  293. u32 val;
  294. /*
  295. * DC Offset is always added to image data irrespective of bc enable
  296. * status
  297. */
  298. regw(bc->dc_offset, CLDCOFST);
  299. if (bc->en) {
  300. val = bc->bc_mode_color << ISIF_BC_MODE_COLOR_SHIFT;
  301. /* Enable BC and horizontal clamp caculation paramaters */
  302. val = val | 1 | (bc->horz.mode << ISIF_HORZ_BC_MODE_SHIFT);
  303. regw(val, CLAMPCFG);
  304. if (bc->horz.mode != ISIF_HORZ_BC_DISABLE) {
  305. /*
  306. * Window count for calculation
  307. * Base window selection
  308. * pixel limit
  309. * Horizontal size of window
  310. * vertical size of the window
  311. * Horizontal start position of the window
  312. * Vertical start position of the window
  313. */
  314. val = bc->horz.win_count_calc |
  315. ((!!bc->horz.base_win_sel_calc) <<
  316. ISIF_HORZ_BC_WIN_SEL_SHIFT) |
  317. ((!!bc->horz.clamp_pix_limit) <<
  318. ISIF_HORZ_BC_PIX_LIMIT_SHIFT) |
  319. (bc->horz.win_h_sz_calc <<
  320. ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) |
  321. (bc->horz.win_v_sz_calc <<
  322. ISIF_HORZ_BC_WIN_V_SIZE_SHIFT);
  323. regw(val, CLHWIN0);
  324. regw(bc->horz.win_start_h_calc, CLHWIN1);
  325. regw(bc->horz.win_start_v_calc, CLHWIN2);
  326. }
  327. /* vertical clamp caculation paramaters */
  328. /* Reset clamp value sel for previous line */
  329. val |=
  330. (bc->vert.reset_val_sel << ISIF_VERT_BC_RST_VAL_SEL_SHIFT) |
  331. (bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT);
  332. regw(val, CLVWIN0);
  333. /* Optical Black horizontal start position */
  334. regw(bc->vert.ob_start_h, CLVWIN1);
  335. /* Optical Black vertical start position */
  336. regw(bc->vert.ob_start_v, CLVWIN2);
  337. /* Optical Black vertical size for calculation */
  338. regw(bc->vert.ob_v_sz_calc, CLVWIN3);
  339. /* Vertical start position for BC subtraction */
  340. regw(bc->vert_start_sub, CLSV);
  341. }
  342. }
  343. static void isif_config_linearization(struct isif_linearize *linearize)
  344. {
  345. u32 val, i;
  346. if (!linearize->en) {
  347. regw(0, LINCFG0);
  348. return;
  349. }
  350. /* shift value for correction & enable linearization (set lsb) */
  351. val = (linearize->corr_shft << ISIF_LIN_CORRSFT_SHIFT) | 1;
  352. regw(val, LINCFG0);
  353. /* Scale factor */
  354. val = ((!!linearize->scale_fact.integer) <<
  355. ISIF_LIN_SCALE_FACT_INTEG_SHIFT) |
  356. linearize->scale_fact.decimal;
  357. regw(val, LINCFG1);
  358. for (i = 0; i < ISIF_LINEAR_TAB_SIZE; i++) {
  359. if (i % 2)
  360. regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 1);
  361. else
  362. regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 0);
  363. }
  364. }
  365. static int isif_config_dfc(struct isif_dfc *vdfc)
  366. {
  367. /* initialize retries to loop for max ~ 250 usec */
  368. u32 val, count, retries = loops_per_jiffy / (4000/HZ);
  369. int i;
  370. if (!vdfc->en)
  371. return 0;
  372. /* Correction mode */
  373. val = (vdfc->corr_mode << ISIF_VDFC_CORR_MOD_SHIFT);
  374. /* Correct whole line or partial */
  375. if (vdfc->corr_whole_line)
  376. val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT;
  377. /* level shift value */
  378. val |= vdfc->def_level_shift << ISIF_VDFC_LEVEL_SHFT_SHIFT;
  379. regw(val, DFCCTL);
  380. /* Defect saturation level */
  381. regw(vdfc->def_sat_level, VDFSATLV);
  382. regw(vdfc->table[0].pos_vert, DFCMEM0);
  383. regw(vdfc->table[0].pos_horz, DFCMEM1);
  384. if (vdfc->corr_mode == ISIF_VDFC_NORMAL ||
  385. vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
  386. regw(vdfc->table[0].level_at_pos, DFCMEM2);
  387. regw(vdfc->table[0].level_up_pixels, DFCMEM3);
  388. regw(vdfc->table[0].level_low_pixels, DFCMEM4);
  389. }
  390. /* set DFCMARST and set DFCMWR */
  391. val = regr(DFCMEMCTL) | (1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT) | 1;
  392. regw(val, DFCMEMCTL);
  393. count = retries;
  394. while (count && (regr(DFCMEMCTL) & 0x1))
  395. count--;
  396. if (!count) {
  397. dev_dbg(isif_cfg.dev, "defect table write timeout !!!\n");
  398. return -1;
  399. }
  400. for (i = 1; i < vdfc->num_vdefects; i++) {
  401. regw(vdfc->table[i].pos_vert, DFCMEM0);
  402. regw(vdfc->table[i].pos_horz, DFCMEM1);
  403. if (vdfc->corr_mode == ISIF_VDFC_NORMAL ||
  404. vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
  405. regw(vdfc->table[i].level_at_pos, DFCMEM2);
  406. regw(vdfc->table[i].level_up_pixels, DFCMEM3);
  407. regw(vdfc->table[i].level_low_pixels, DFCMEM4);
  408. }
  409. val = regr(DFCMEMCTL);
  410. /* clear DFCMARST and set DFCMWR */
  411. val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT);
  412. val |= 1;
  413. regw(val, DFCMEMCTL);
  414. count = retries;
  415. while (count && (regr(DFCMEMCTL) & 0x1))
  416. count--;
  417. if (!count) {
  418. dev_err(isif_cfg.dev,
  419. "defect table write timeout !!!\n");
  420. return -1;
  421. }
  422. }
  423. if (vdfc->num_vdefects < ISIF_VDFC_TABLE_SIZE) {
  424. /* Extra cycle needed */
  425. regw(0, DFCMEM0);
  426. regw(0x1FFF, DFCMEM1);
  427. regw(1, DFCMEMCTL);
  428. }
  429. /* enable VDFC */
  430. reg_modify((1 << ISIF_VDFC_EN_SHIFT), (1 << ISIF_VDFC_EN_SHIFT),
  431. DFCCTL);
  432. return 0;
  433. }
  434. static void isif_config_csc(struct isif_df_csc *df_csc)
  435. {
  436. u32 val1 = 0, val2 = 0, i;
  437. if (!df_csc->csc.en) {
  438. regw(0, CSCCTL);
  439. return;
  440. }
  441. for (i = 0; i < ISIF_CSC_NUM_COEFF; i++) {
  442. if ((i % 2) == 0) {
  443. /* CSCM - LSB */
  444. val1 = (df_csc->csc.coeff[i].integer <<
  445. ISIF_CSC_COEF_INTEG_SHIFT) |
  446. df_csc->csc.coeff[i].decimal;
  447. } else {
  448. /* CSCM - MSB */
  449. val2 = (df_csc->csc.coeff[i].integer <<
  450. ISIF_CSC_COEF_INTEG_SHIFT) |
  451. df_csc->csc.coeff[i].decimal;
  452. val2 <<= ISIF_CSCM_MSB_SHIFT;
  453. val2 |= val1;
  454. regw(val2, (CSCM0 + ((i - 1) << 1)));
  455. }
  456. }
  457. /* program the active area */
  458. regw(df_csc->start_pix, FMTSPH);
  459. /*
  460. * one extra pixel as required for CSC. Actually number of
  461. * pixel - 1 should be configured in this register. So we
  462. * need to subtract 1 before writing to FMTSPH, but we will
  463. * not do this since csc requires one extra pixel
  464. */
  465. regw(df_csc->num_pixels, FMTLNH);
  466. regw(df_csc->start_line, FMTSLV);
  467. /*
  468. * one extra line as required for CSC. See reason documented for
  469. * num_pixels
  470. */
  471. regw(df_csc->num_lines, FMTLNV);
  472. /* Enable CSC */
  473. regw(1, CSCCTL);
  474. }
  475. static int isif_config_raw(void)
  476. {
  477. struct isif_params_raw *params = &isif_cfg.bayer;
  478. struct isif_config_params_raw *module_params =
  479. &isif_cfg.bayer.config_params;
  480. struct vpss_pg_frame_size frame_size;
  481. struct vpss_sync_pol sync;
  482. u32 val;
  483. dev_dbg(isif_cfg.dev, "\nStarting isif_config_raw..\n");
  484. /*
  485. * Configure CCDCFG register:-
  486. * Set CCD Not to swap input since input is RAW data
  487. * Set FID detection function to Latch at V-Sync
  488. * Set WENLOG - isif valid area
  489. * Set TRGSEL
  490. * Set EXTRG
  491. * Packed to 8 or 16 bits
  492. */
  493. val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC |
  494. ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN |
  495. ISIF_CCDCFG_EXTRG_DISABLE | isif_cfg.data_pack;
  496. dev_dbg(isif_cfg.dev, "Writing 0x%x to ...CCDCFG \n", val);
  497. regw(val, CCDCFG);
  498. /*
  499. * Configure the vertical sync polarity(MODESET.VDPOL)
  500. * Configure the horizontal sync polarity (MODESET.HDPOL)
  501. * Configure frame id polarity (MODESET.FLDPOL)
  502. * Configure data polarity
  503. * Configure External WEN Selection
  504. * Configure frame format(progressive or interlace)
  505. * Configure pixel format (Input mode)
  506. * Configure the data shift
  507. */
  508. val = ISIF_VDHDOUT_INPUT | (params->vd_pol << ISIF_VD_POL_SHIFT) |
  509. (params->hd_pol << ISIF_HD_POL_SHIFT) |
  510. (params->fid_pol << ISIF_FID_POL_SHIFT) |
  511. (ISIF_DATAPOL_NORMAL << ISIF_DATAPOL_SHIFT) |
  512. (ISIF_EXWEN_DISABLE << ISIF_EXWEN_SHIFT) |
  513. (params->frm_fmt << ISIF_FRM_FMT_SHIFT) |
  514. (params->pix_fmt << ISIF_INPUT_SHIFT) |
  515. (params->config_params.data_shift << ISIF_DATASFT_SHIFT);
  516. regw(val, MODESET);
  517. dev_dbg(isif_cfg.dev, "Writing 0x%x to MODESET...\n", val);
  518. /*
  519. * Configure GAMMAWD register
  520. * CFA pattern setting
  521. */
  522. val = params->cfa_pat << ISIF_GAMMAWD_CFA_SHIFT;
  523. /* Gamma msb */
  524. if (module_params->compress.alg == ISIF_ALAW)
  525. val |= ISIF_ALAW_ENABLE;
  526. val |= (params->data_msb << ISIF_ALAW_GAMA_WD_SHIFT);
  527. regw(val, CGAMMAWD);
  528. /* Configure DPCM compression settings */
  529. if (module_params->compress.alg == ISIF_DPCM) {
  530. val = BIT(ISIF_DPCM_EN_SHIFT) |
  531. (module_params->compress.pred <<
  532. ISIF_DPCM_PREDICTOR_SHIFT);
  533. }
  534. regw(val, MISC);
  535. /* Configure Gain & Offset */
  536. isif_config_gain_offset();
  537. /* Configure Color pattern */
  538. val = (params->config_params.col_pat_field0.olop) |
  539. (params->config_params.col_pat_field0.olep << 2) |
  540. (params->config_params.col_pat_field0.elop << 4) |
  541. (params->config_params.col_pat_field0.elep << 6) |
  542. (params->config_params.col_pat_field1.olop << 8) |
  543. (params->config_params.col_pat_field1.olep << 10) |
  544. (params->config_params.col_pat_field1.elop << 12) |
  545. (params->config_params.col_pat_field1.elep << 14);
  546. regw(val, CCOLP);
  547. dev_dbg(isif_cfg.dev, "Writing %x to CCOLP ...\n", val);
  548. /* Configure HSIZE register */
  549. val = (!!params->horz_flip_en) << ISIF_HSIZE_FLIP_SHIFT;
  550. /* calculate line offset in 32 bytes based on pack value */
  551. if (isif_cfg.data_pack == ISIF_PACK_8BIT)
  552. val |= ((params->win.width + 31) >> 5);
  553. else if (isif_cfg.data_pack == ISIF_PACK_12BIT)
  554. val |= (((params->win.width +
  555. (params->win.width >> 2)) + 31) >> 5);
  556. else
  557. val |= (((params->win.width * 2) + 31) >> 5);
  558. regw(val, HSIZE);
  559. /* Configure SDOFST register */
  560. if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
  561. if (params->image_invert_en) {
  562. /* For interlace inverse mode */
  563. regw(0x4B6D, SDOFST);
  564. dev_dbg(isif_cfg.dev, "Writing 0x4B6D to SDOFST...\n");
  565. } else {
  566. /* For interlace non inverse mode */
  567. regw(0x0B6D, SDOFST);
  568. dev_dbg(isif_cfg.dev, "Writing 0x0B6D to SDOFST...\n");
  569. }
  570. } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
  571. if (params->image_invert_en) {
  572. /* For progressive inverse mode */
  573. regw(0x4000, SDOFST);
  574. dev_dbg(isif_cfg.dev, "Writing 0x4000 to SDOFST...\n");
  575. } else {
  576. /* For progressive non inverse mode */
  577. regw(0x0000, SDOFST);
  578. dev_dbg(isif_cfg.dev, "Writing 0x0000 to SDOFST...\n");
  579. }
  580. }
  581. /* Configure video window */
  582. isif_setwin(&params->win, params->frm_fmt, 1);
  583. /* Configure Black Clamp */
  584. isif_config_bclamp(&module_params->bclamp);
  585. /* Configure Vertical Defection Pixel Correction */
  586. if (isif_config_dfc(&module_params->dfc) < 0)
  587. return -EFAULT;
  588. if (!module_params->df_csc.df_or_csc)
  589. /* Configure Color Space Conversion */
  590. isif_config_csc(&module_params->df_csc);
  591. isif_config_linearization(&module_params->linearize);
  592. /* Configure Culling */
  593. isif_config_culling(&module_params->culling);
  594. /* Configure horizontal and vertical offsets(DFC,LSC,Gain) */
  595. regw(module_params->horz_offset, DATAHOFST);
  596. regw(module_params->vert_offset, DATAVOFST);
  597. /* Setup test pattern if enabled */
  598. if (params->config_params.test_pat_gen) {
  599. /* Use the HD/VD pol settings from user */
  600. sync.ccdpg_hdpol = params->hd_pol;
  601. sync.ccdpg_vdpol = params->vd_pol;
  602. dm365_vpss_set_sync_pol(sync);
  603. frame_size.hlpfr = isif_cfg.bayer.win.width;
  604. frame_size.pplen = isif_cfg.bayer.win.height;
  605. dm365_vpss_set_pg_frame_size(frame_size);
  606. vpss_select_ccdc_source(VPSS_PGLPBK);
  607. }
  608. dev_dbg(isif_cfg.dev, "\nEnd of isif_config_ycbcr...\n");
  609. return 0;
  610. }
  611. static int isif_set_buftype(enum ccdc_buftype buf_type)
  612. {
  613. if (isif_cfg.if_type == VPFE_RAW_BAYER)
  614. isif_cfg.bayer.buf_type = buf_type;
  615. else
  616. isif_cfg.ycbcr.buf_type = buf_type;
  617. return 0;
  618. }
  619. static enum ccdc_buftype isif_get_buftype(void)
  620. {
  621. if (isif_cfg.if_type == VPFE_RAW_BAYER)
  622. return isif_cfg.bayer.buf_type;
  623. return isif_cfg.ycbcr.buf_type;
  624. }
  625. static int isif_enum_pix(u32 *pix, int i)
  626. {
  627. int ret = -EINVAL;
  628. if (isif_cfg.if_type == VPFE_RAW_BAYER) {
  629. if (i < ARRAY_SIZE(isif_raw_bayer_pix_formats)) {
  630. *pix = isif_raw_bayer_pix_formats[i];
  631. ret = 0;
  632. }
  633. } else {
  634. if (i < ARRAY_SIZE(isif_raw_yuv_pix_formats)) {
  635. *pix = isif_raw_yuv_pix_formats[i];
  636. ret = 0;
  637. }
  638. }
  639. return ret;
  640. }
  641. static int isif_set_pixel_format(unsigned int pixfmt)
  642. {
  643. if (isif_cfg.if_type == VPFE_RAW_BAYER) {
  644. if (pixfmt == V4L2_PIX_FMT_SBGGR8) {
  645. if ((isif_cfg.bayer.config_params.compress.alg !=
  646. ISIF_ALAW) &&
  647. (isif_cfg.bayer.config_params.compress.alg !=
  648. ISIF_DPCM)) {
  649. dev_dbg(isif_cfg.dev,
  650. "Either configure A-Law or DPCM\n");
  651. return -EINVAL;
  652. }
  653. isif_cfg.data_pack = ISIF_PACK_8BIT;
  654. } else if (pixfmt == V4L2_PIX_FMT_SBGGR16) {
  655. isif_cfg.bayer.config_params.compress.alg =
  656. ISIF_NO_COMPRESSION;
  657. isif_cfg.data_pack = ISIF_PACK_16BIT;
  658. } else
  659. return -EINVAL;
  660. isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
  661. } else {
  662. if (pixfmt == V4L2_PIX_FMT_YUYV)
  663. isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
  664. else if (pixfmt == V4L2_PIX_FMT_UYVY)
  665. isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
  666. else
  667. return -EINVAL;
  668. isif_cfg.data_pack = ISIF_PACK_8BIT;
  669. }
  670. return 0;
  671. }
  672. static u32 isif_get_pixel_format(void)
  673. {
  674. u32 pixfmt;
  675. if (isif_cfg.if_type == VPFE_RAW_BAYER)
  676. if (isif_cfg.bayer.config_params.compress.alg == ISIF_ALAW ||
  677. isif_cfg.bayer.config_params.compress.alg == ISIF_DPCM)
  678. pixfmt = V4L2_PIX_FMT_SBGGR8;
  679. else
  680. pixfmt = V4L2_PIX_FMT_SBGGR16;
  681. else {
  682. if (isif_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
  683. pixfmt = V4L2_PIX_FMT_YUYV;
  684. else
  685. pixfmt = V4L2_PIX_FMT_UYVY;
  686. }
  687. return pixfmt;
  688. }
  689. static int isif_set_image_window(struct v4l2_rect *win)
  690. {
  691. if (isif_cfg.if_type == VPFE_RAW_BAYER) {
  692. isif_cfg.bayer.win.top = win->top;
  693. isif_cfg.bayer.win.left = win->left;
  694. isif_cfg.bayer.win.width = win->width;
  695. isif_cfg.bayer.win.height = win->height;
  696. } else {
  697. isif_cfg.ycbcr.win.top = win->top;
  698. isif_cfg.ycbcr.win.left = win->left;
  699. isif_cfg.ycbcr.win.width = win->width;
  700. isif_cfg.ycbcr.win.height = win->height;
  701. }
  702. return 0;
  703. }
  704. static void isif_get_image_window(struct v4l2_rect *win)
  705. {
  706. if (isif_cfg.if_type == VPFE_RAW_BAYER)
  707. *win = isif_cfg.bayer.win;
  708. else
  709. *win = isif_cfg.ycbcr.win;
  710. }
  711. static unsigned int isif_get_line_length(void)
  712. {
  713. unsigned int len;
  714. if (isif_cfg.if_type == VPFE_RAW_BAYER) {
  715. if (isif_cfg.data_pack == ISIF_PACK_8BIT)
  716. len = ((isif_cfg.bayer.win.width));
  717. else if (isif_cfg.data_pack == ISIF_PACK_12BIT)
  718. len = (((isif_cfg.bayer.win.width * 2) +
  719. (isif_cfg.bayer.win.width >> 2)));
  720. else
  721. len = (((isif_cfg.bayer.win.width * 2)));
  722. } else
  723. len = (((isif_cfg.ycbcr.win.width * 2)));
  724. return ALIGN(len, 32);
  725. }
  726. static int isif_set_frame_format(enum ccdc_frmfmt frm_fmt)
  727. {
  728. if (isif_cfg.if_type == VPFE_RAW_BAYER)
  729. isif_cfg.bayer.frm_fmt = frm_fmt;
  730. else
  731. isif_cfg.ycbcr.frm_fmt = frm_fmt;
  732. return 0;
  733. }
  734. static enum ccdc_frmfmt isif_get_frame_format(void)
  735. {
  736. if (isif_cfg.if_type == VPFE_RAW_BAYER)
  737. return isif_cfg.bayer.frm_fmt;
  738. return isif_cfg.ycbcr.frm_fmt;
  739. }
  740. static int isif_getfid(void)
  741. {
  742. return (regr(MODESET) >> 15) & 0x1;
  743. }
  744. /* misc operations */
  745. static void isif_setfbaddr(unsigned long addr)
  746. {
  747. regw((addr >> 21) & 0x07ff, CADU);
  748. regw((addr >> 5) & 0x0ffff, CADL);
  749. }
  750. static int isif_set_hw_if_params(struct vpfe_hw_if_param *params)
  751. {
  752. isif_cfg.if_type = params->if_type;
  753. switch (params->if_type) {
  754. case VPFE_BT656:
  755. case VPFE_BT656_10BIT:
  756. case VPFE_YCBCR_SYNC_8:
  757. isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT;
  758. isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
  759. break;
  760. case VPFE_BT1120:
  761. case VPFE_YCBCR_SYNC_16:
  762. isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_16BIT;
  763. isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
  764. break;
  765. case VPFE_RAW_BAYER:
  766. isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
  767. break;
  768. default:
  769. dev_dbg(isif_cfg.dev, "Invalid interface type\n");
  770. return -EINVAL;
  771. }
  772. return 0;
  773. }
  774. /* This function will configure ISIF for YCbCr parameters. */
  775. static int isif_config_ycbcr(void)
  776. {
  777. struct isif_ycbcr_config *params = &isif_cfg.ycbcr;
  778. struct vpss_pg_frame_size frame_size;
  779. u32 modeset = 0, ccdcfg = 0;
  780. struct vpss_sync_pol sync;
  781. dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr...");
  782. /* configure pixel format or input mode */
  783. modeset = modeset | (params->pix_fmt << ISIF_INPUT_SHIFT) |
  784. (params->frm_fmt << ISIF_FRM_FMT_SHIFT) |
  785. (params->fid_pol << ISIF_FID_POL_SHIFT) |
  786. (params->hd_pol << ISIF_HD_POL_SHIFT) |
  787. (params->vd_pol << ISIF_VD_POL_SHIFT);
  788. /* pack the data to 8-bit ISIFCFG */
  789. switch (isif_cfg.if_type) {
  790. case VPFE_BT656:
  791. if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
  792. dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
  793. return -EINVAL;
  794. }
  795. modeset |= (VPFE_PINPOL_NEGATIVE << ISIF_VD_POL_SHIFT);
  796. regw(3, REC656IF);
  797. ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR;
  798. break;
  799. case VPFE_BT656_10BIT:
  800. if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
  801. dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
  802. return -EINVAL;
  803. }
  804. /* setup BT.656, embedded sync */
  805. regw(3, REC656IF);
  806. /* enable 10 bit mode in ccdcfg */
  807. ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR |
  808. ISIF_BW656_ENABLE;
  809. break;
  810. case VPFE_BT1120:
  811. if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) {
  812. dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
  813. return -EINVAL;
  814. }
  815. regw(3, REC656IF);
  816. break;
  817. case VPFE_YCBCR_SYNC_8:
  818. ccdcfg |= ISIF_DATA_PACK8;
  819. ccdcfg |= ISIF_YCINSWP_YCBCR;
  820. if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
  821. dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
  822. return -EINVAL;
  823. }
  824. break;
  825. case VPFE_YCBCR_SYNC_16:
  826. if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) {
  827. dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
  828. return -EINVAL;
  829. }
  830. break;
  831. default:
  832. /* should never come here */
  833. dev_dbg(isif_cfg.dev, "Invalid interface type\n");
  834. return -EINVAL;
  835. }
  836. regw(modeset, MODESET);
  837. /* Set up pix order */
  838. ccdcfg |= params->pix_order << ISIF_PIX_ORDER_SHIFT;
  839. regw(ccdcfg, CCDCFG);
  840. /* configure video window */
  841. if ((isif_cfg.if_type == VPFE_BT1120) ||
  842. (isif_cfg.if_type == VPFE_YCBCR_SYNC_16))
  843. isif_setwin(&params->win, params->frm_fmt, 1);
  844. else
  845. isif_setwin(&params->win, params->frm_fmt, 2);
  846. /*
  847. * configure the horizontal line offset
  848. * this is done by rounding up width to a multiple of 16 pixels
  849. * and multiply by two to account for y:cb:cr 4:2:2 data
  850. */
  851. regw(((((params->win.width * 2) + 31) & 0xffffffe0) >> 5), HSIZE);
  852. /* configure the memory line offset */
  853. if ((params->frm_fmt == CCDC_FRMFMT_INTERLACED) &&
  854. (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED))
  855. /* two fields are interleaved in memory */
  856. regw(0x00000249, SDOFST);
  857. /* Setup test pattern if enabled */
  858. if (isif_cfg.bayer.config_params.test_pat_gen) {
  859. sync.ccdpg_hdpol = params->hd_pol;
  860. sync.ccdpg_vdpol = params->vd_pol;
  861. dm365_vpss_set_sync_pol(sync);
  862. dm365_vpss_set_pg_frame_size(frame_size);
  863. }
  864. return 0;
  865. }
  866. static int isif_configure(void)
  867. {
  868. if (isif_cfg.if_type == VPFE_RAW_BAYER)
  869. return isif_config_raw();
  870. return isif_config_ycbcr();
  871. }
  872. static int isif_close(struct device *device)
  873. {
  874. /* copy defaults to module params */
  875. isif_cfg.bayer.config_params = isif_config_defaults;
  876. return 0;
  877. }
  878. static struct ccdc_hw_device isif_hw_dev = {
  879. .name = "ISIF",
  880. .owner = THIS_MODULE,
  881. .hw_ops = {
  882. .open = isif_open,
  883. .close = isif_close,
  884. .enable = isif_enable,
  885. .enable_out_to_sdram = isif_enable_output_to_sdram,
  886. .set_hw_if_params = isif_set_hw_if_params,
  887. .configure = isif_configure,
  888. .set_buftype = isif_set_buftype,
  889. .get_buftype = isif_get_buftype,
  890. .enum_pix = isif_enum_pix,
  891. .set_pixel_format = isif_set_pixel_format,
  892. .get_pixel_format = isif_get_pixel_format,
  893. .set_frame_format = isif_set_frame_format,
  894. .get_frame_format = isif_get_frame_format,
  895. .set_image_window = isif_set_image_window,
  896. .get_image_window = isif_get_image_window,
  897. .get_line_length = isif_get_line_length,
  898. .setfbaddr = isif_setfbaddr,
  899. .getfid = isif_getfid,
  900. },
  901. };
  902. static int isif_probe(struct platform_device *pdev)
  903. {
  904. void (*setup_pinmux)(void);
  905. struct resource *res;
  906. void *__iomem addr;
  907. int status = 0, i;
  908. /*
  909. * first try to register with vpfe. If not correct platform, then we
  910. * don't have to iomap
  911. */
  912. status = vpfe_register_ccdc_device(&isif_hw_dev);
  913. if (status < 0)
  914. return status;
  915. /* Get and enable Master clock */
  916. isif_cfg.mclk = clk_get(&pdev->dev, "master");
  917. if (IS_ERR(isif_cfg.mclk)) {
  918. status = PTR_ERR(isif_cfg.mclk);
  919. goto fail_mclk;
  920. }
  921. if (clk_prepare_enable(isif_cfg.mclk)) {
  922. status = -ENODEV;
  923. goto fail_mclk;
  924. }
  925. /* Platform data holds setup_pinmux function ptr */
  926. if (NULL == pdev->dev.platform_data) {
  927. status = -ENODEV;
  928. goto fail_mclk;
  929. }
  930. setup_pinmux = pdev->dev.platform_data;
  931. /*
  932. * setup Mux configuration for ccdc which may be different for
  933. * different SoCs using this CCDC
  934. */
  935. setup_pinmux();
  936. i = 0;
  937. /* Get the ISIF base address, linearization table0 and table1 addr. */
  938. while (i < 3) {
  939. res = platform_get_resource(pdev, IORESOURCE_MEM, i);
  940. if (!res) {
  941. status = -ENODEV;
  942. goto fail_nobase_res;
  943. }
  944. res = request_mem_region(res->start, resource_size(res),
  945. res->name);
  946. if (!res) {
  947. status = -EBUSY;
  948. goto fail_nobase_res;
  949. }
  950. addr = ioremap_nocache(res->start, resource_size(res));
  951. if (!addr) {
  952. status = -ENOMEM;
  953. goto fail_base_iomap;
  954. }
  955. switch (i) {
  956. case 0:
  957. /* ISIF base address */
  958. isif_cfg.base_addr = addr;
  959. break;
  960. case 1:
  961. /* ISIF linear tbl0 address */
  962. isif_cfg.linear_tbl0_addr = addr;
  963. break;
  964. default:
  965. /* ISIF linear tbl0 address */
  966. isif_cfg.linear_tbl1_addr = addr;
  967. break;
  968. }
  969. i++;
  970. }
  971. isif_cfg.dev = &pdev->dev;
  972. printk(KERN_NOTICE "%s is registered with vpfe.\n",
  973. isif_hw_dev.name);
  974. return 0;
  975. fail_base_iomap:
  976. release_mem_region(res->start, resource_size(res));
  977. i--;
  978. fail_nobase_res:
  979. if (isif_cfg.base_addr)
  980. iounmap(isif_cfg.base_addr);
  981. if (isif_cfg.linear_tbl0_addr)
  982. iounmap(isif_cfg.linear_tbl0_addr);
  983. while (i >= 0) {
  984. res = platform_get_resource(pdev, IORESOURCE_MEM, i);
  985. release_mem_region(res->start, resource_size(res));
  986. i--;
  987. }
  988. fail_mclk:
  989. clk_disable_unprepare(isif_cfg.mclk);
  990. clk_put(isif_cfg.mclk);
  991. vpfe_unregister_ccdc_device(&isif_hw_dev);
  992. return status;
  993. }
  994. static int isif_remove(struct platform_device *pdev)
  995. {
  996. struct resource *res;
  997. int i = 0;
  998. iounmap(isif_cfg.base_addr);
  999. iounmap(isif_cfg.linear_tbl0_addr);
  1000. iounmap(isif_cfg.linear_tbl1_addr);
  1001. while (i < 3) {
  1002. res = platform_get_resource(pdev, IORESOURCE_MEM, i);
  1003. if (res)
  1004. release_mem_region(res->start, resource_size(res));
  1005. i++;
  1006. }
  1007. vpfe_unregister_ccdc_device(&isif_hw_dev);
  1008. clk_disable_unprepare(isif_cfg.mclk);
  1009. clk_put(isif_cfg.mclk);
  1010. return 0;
  1011. }
  1012. static struct platform_driver isif_driver = {
  1013. .driver = {
  1014. .name = "isif",
  1015. .owner = THIS_MODULE,
  1016. },
  1017. .remove = isif_remove,
  1018. .probe = isif_probe,
  1019. };
  1020. module_platform_driver(isif_driver);
  1021. MODULE_LICENSE("GPL");