#include <linux/module.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/clk.h>
#include <linux/random.h>
#include <linux/version.h>
#include <linux/videodev2.h>
#include <linux/dma-mapping.h>
#ifdef CONFIG_VIDEO_V4L1_COMPAT
#include <linux/videodev.h>
#endif
#include <linux/interrupt.h>
#include <media/v4l2-common.h>
#include <linux/highmem.h>
#include <linux/miscdevice.h>
#include <asm/io.h>
#include <asm/memory.h>
#include <mach/regs-gpio.h>
#include <mach/regs-gpioj.h>
#include <mach/regs-clock.h>
#include <mach/map.h>
#include "ov9650.h"
/* debug print macro. */
/* hardware & driver name, version etc. */
#define CARD_NAME "camera"
static unsigned has_ov9650;
unsigned long camif_base_addr;
/* camera device(s) */
static struct tq2440_camif_dev camera;
/* image buffer for previewing. */
struct tq2440_camif_buffer img_buff[] =
{
{
.state = CAMIF_BUFF_INVALID,
.img_size = 0,
.order = 0,
.virt_base = (unsigned long)NULL,
.phy_base = (unsigned long)NULL
},
{
.state = CAMIF_BUFF_INVALID,
.img_size = 0,
.order = 0,
.virt_base = (unsigned long)NULL,
.phy_base = (unsigned long)NULL
},
{
.state = CAMIF_BUFF_INVALID,
.img_size = 0,
.order = 0,
.virt_base = (unsigned long)NULL,
.phy_base = (unsigned long)NULL
},
{
.state = CAMIF_BUFF_INVALID,
.img_size = 0,
.order = 0,
.virt_base = (unsigned long)NULL,
.phy_base = (unsigned long)NULL
}
};
/* software reset camera interface. */
static void __inline__ soft_reset_camif(void)
{
u32 cigctrl;
cigctrl = (1<<31)|(1<<29);
iowrite32(cigctrl, S3C244X_CIGCTRL);
mdelay(10);
cigctrl = (1<<29);
iowrite32(cigctrl, S3C244X_CIGCTRL);
mdelay(10);
}
/* software reset camera interface. */
static void __inline__ hw_reset_camif(void)
{
u32 cigctrl;
cigctrl = (1<<30)|(1<<29);
iowrite32(cigctrl, S3C244X_CIGCTRL);
mdelay(10);
cigctrl = (1<<29);
iowrite32(cigctrl, S3C244X_CIGCTRL);
mdelay(10);
}
/* switch camif from codec path to preview path. */
static void __inline__ camif_c2p(struct tq2440_camif_dev * pdev)
{
/* 1. stop codec. */
{
u32 cicoscctrl;
cicoscctrl = ioread32(S3C244X_CICOSCCTRL);
cicoscctrl &= ~(1<<15); // stop preview scaler.
iowrite32(cicoscctrl, S3C244X_CICOSCCTRL);
}
/* 2. soft-reset camif. */
soft_reset_camif();
/* 3. clear all overflow. */
{
u32 ciwdofst;
ciwdofst = ioread32(S3C244X_CIWDOFST);
ciwdofst |= (1<<30)|(1<<15)|(1<<14)|(1<<13)|(1<<12);
iowrite32(ciwdofst, S3C244X_CIWDOFST);
ciwdofst &= ~((1<<30)|(1<<15)|(1<<14)|(1<<13)|(1<<12));
iowrite32(ciwdofst, S3C244X_CIWDOFST);
}
}
/* calculate main burst size and remained burst size. */
static void __inline__ calc_burst_size(u32 pixperword,u32 hSize, u32 *mainBurstSize, u32 *remainedBurstSize)
{
u32 tmp;
tmp = (hSize/pixperword)%16;
switch(tmp)
{
case 0:
*mainBurstSize = 16;
*remainedBurstSize = 16;
break;
case 4:
*mainBurstSize = 16;
*remainedBurstSize = 4;
break;
case 8:
*mainBurstSize=16;
*remainedBurstSize = 8;
break;
default:
tmp=(hSize/pixperword)%8;
switch(tmp)
{
case 0:
*mainBurstSize = 8;
*remainedBurstSize = 8;
break;
case 4:
*mainBurstSize = 8;
*remainedBurstSize = 4;
default:
*mainBurstSize = 4;
tmp = (hSize/pixperword)%4;
*remainedBurstSize = (tmp)?tmp:4;
break;
}
break;
}
}
/* calculate prescaler ratio and shift. */
static void __inline__ calc_prescaler_ratio_shift(u32 SrcSize, u32 DstSize, u32 *ratio, u32 *shift)
{
if(SrcSize>=32*DstSize)
{
*ratio=32;
*shift=5;
}
else if(SrcSize>=16*DstSize)
{
*ratio=16;
*shift=4;
}
else if(SrcSize>=8*DstSize)
{
*ratio=8;
*shift=3;
}
else if(SrcSize>=4*DstSize)
{
*ratio=4;
*shift=2;
}
else if(SrcSize>=2*DstSize)
{
*ratio=2;
*shift=1;
}
else
{
*ratio=1;
*shift=0;
}
}
/* update CISRCFMT only. */
static void __inline__ update_source_fmt_regs(struct tq2440_camif_dev * pdev)
{
u32 cisrcfmt;
cisrcfmt = (1<<31) // ITU-R BT.601 YCbCr 8-bit mode
|(0<<30) // CB,Cr value offset cntrol for YCbCr
|(pdev->srcHsize<<16) // source image width
|(2<<14) // input order is CbYCrY
|(pdev->srcVsize<<0); // source image height
iowrite32(cisrcfmt, S3C244X_CISRCFMT);
}
/* update registers:
* PREVIEW path:
* CIPRCLRSA1 ~ CIPRCLRSA4
* CIPRTRGFMT
* CIPRCTRL
* CIPRSCCTRL
* CIPRTAREA
* CODEC path:
* CICOYSA1 ~ CICOYSA4
* CICOCBSA1 ~ CICOCBSA4
* CICOCRSA1 ~ CICOCRSA4
* CICOTRGFMT
* CICOCTRL
* CICOTAREA
*/
static void __inline__ update_target_fmt_regs(struct tq2440_camif_dev * pdev)
{
u32 ciprtrgfmt;
u32 ciprctrl;
u32 ciprscctrl;
u32 mainBurstSize, remainedBurstSize;
/* CIPRCLRSA1 ~ CIPRCLRSA4. */
iowrite32(img_buff[0].phy_base, S3C244X_CIPRCLRSA1);
iowrite32(img_buff[1].phy_base, S3C244X_CIPRCLRSA2);
iowrite32(img_buff[2].phy_base, S3C244X_CIPRCLRSA3);
iowrite32(img_buff[3].phy_base, S3C244X_CIPRCLRSA4);
/* CIPRTRGFMT. */
ciprtrgfmt = (pdev->preTargetHsize<<16) // horizontal pixel number of target image
|(0<<14) // don't mirror or rotation.
|(pdev->preTargetVsize<<0); // vertical pixel number of target image
iowrite32(ciprtrgfmt, S3C244X_CIPRTRGFMT);
/* CIPRCTRL. */
calc_burst_size(2, pdev->preTargetHsize, &mainBurstSize, &remainedBurstSize);
ciprctrl = (mainBurstSize<<19)|(remainedBurstSize<<14);
iowrite32(ciprctrl, S3C244X_CIPRCTRL);
/* CIPRSCCTRL. */
ciprscctrl = ioread32(S3C244X_CIPRSCCTRL);
ciprscctrl &= 1<<15; // clear all other info except 'preview scaler start'.
ciprscctrl |= 0<<30; // 16-bits RGB
iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL); // 16-bit RGB
/* CIPRTAREA. */
iowrite32(pdev->preTargetHsize * pdev->preTargetVsize, S3C244X_CIPRTAREA);
}
/* update CIWDOFST only. */
static void __inline__ update_target_wnd_regs(struct tq2440_camif_dev * pdev)
{
u32 ciwdofst;
u32 winHorOfst, winVerOfst;
winHorOfst = (pdev->srcHsize - pdev->wndHsize)>>1;
winVerOfst = (pdev->srcVsize - pdev->wndVsize)>>1;
winHorOfst &= 0xFFFFFFF8;
winVerOfst &= 0xFFFFFFF8;
if ((winHorOfst == 0)&&(winVerOfst == 0))
{
ciwdofst = 0; // disable windows offset.
}
else
{
ciwdofst = (1<<31) // window offset enable
|(1<<30) // clear the overflow ind flag of input CODEC FIFO Y
|(winHorOfst<<16) // windows horizontal offset
|(1<<15) // clear the overflow ind flag of input CODEC FIFO Cb
|(1<<14) // clear the overflow ind flag of input CODEC FIFO Cr
|(1<<13) // clear the overflow ind flag of input PREVIEW FIFO Cb
|(1<<12) // clear the overflow ind flag of input PREVIEW FIFO Cr
|(winVerOfst<<0); // window vertical offset
}
iowrite32(ciwdofst, S3C244X_CIWDOFST);
}
/* update registers:
* PREVIEW path:
* CIPRSCPRERATIO
* CIPRSCPREDST
* CIPRSCCTRL
* CODEC path:
* CICOSCPRERATIO
* CICOSCPREDST
* CICOSCCTRL
*/
static void __inline__ update_target_zoom_regs(struct tq2440_camif_dev * pdev)
{
u32 preHratio, preVratio;
u32 Hshift, Vshift;
u32 shfactor;
u32 preDstWidth, preDstHeight;
u32 Hscale, Vscale;
u32 mainHratio, mainVratio;
u32 ciprscpreratio;
u32 ciprscpredst;
u32 ciprscctrl;
/* CIPRSCPRERATIO. */
calc_prescaler_ratio_shift(pdev->wndHsize, pdev->preTargetHsize, &preHratio, &Hshift);
calc_prescaler_ratio_shift(pdev->wndVsize, pdev->preTargetVsize, &preVratio, &Vshift);
shfactor = 10 - (Hshift + Vshift);
ciprscpreratio = (shfactor<<28) // shift factor for preview pre-scaler
|(preHratio<<16) // horizontal ratio of preview pre-scaler
|(preVratio<<0); // vertical ratio of preview pre-scaler
iowrite32(ciprscpreratio, S3C244X_CIPRSCPRERATIO);
/* CIPRSCPREDST. */
preDstWidth = pdev->wndHsize / preHratio;
preDstHeight = pdev->wndVsize / preVratio;
ciprscpredst = (preDstWidth<<16) // destination width for preview pre-scaler
|(preDstHeight<<0); // destination height for preview pre-s
评论0