PageRenderTime 67ms CodeModel.GetById 22ms app.highlight 38ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/media/video/davinci/isif.c

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