isif.c 30 KB

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