2009年6月30日 星期二

S3C2440 Camera interface V4L2 driver for linux-2.6.29

/*s3c2440_ov9650.c*/

#include <linux/module.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/semaphore.h>
#include <mach/regs-gpio.h>

#include "sccb.h"
#include "s3c2440camif.h"

#define OV9650_SCCB_ADDR    0x60
#define OV9650_MANUFACT_ID    0x7FA2
#define OV9650_PRODUCT_ID    0x9650

/*
09032004
OV9650
VGA YUV
15fps when 24MHz input clock
Device Address(Hex)/Register(Hex)/Value(Hex)
*/
static struct ov9650_reg
{
  u8 subaddr;
  u8 value;
}regs[] = {
{0x12, 0x80},
{0x11, 0x81},
{0x6b, 0x0a},
{0x6a, 0x3e},
{0x3b, 0x09},
{0x13, 0xe0},
{0x01, 0x80},
{0x02, 0x80},
{0x00, 0x00},
{0x10, 0x00},
{0x13, 0xe5},

/*{0x39, 0x50},*/ /*30 fps*/
{0x39, 0x43}, /*15fps*/
/*{0x38, 0x92},*/ /*30fps*/
{0x38, 0x12}, /*15fps*/
{0x37, 0x00},
/*{0x35, 0x81},*/ /*30 fps*/
{0x35, 0x91}, /*15 fps*/
{0x0e, 0x20},
{0x1e, 0x04},

{0xa8, 0x80},
{0x12, 0x40},
{0x04, 0x00},
{0x0c, 0x04},
{0x0d, 0x80},
{0x18, 0xc6},
{0x17, 0x26},
{0x32, 0xad},
{0x03, 0x00},
{0x1a, 0x3d},
{0x19, 0x01},
{0x3f, 0xa6},
{0x14, 0x2e},
{0x15, 0x02},
{0x41, 0x02},
{0x42, 0x08},

{0x1b, 0x00},
{0x16, 0x06},
{0x33, 0xe2}, /*c0 for internal regulator*/
{0x34, 0xbf},
{0x96, 0x04},
{0x3a, 0x00},
{0x8e, 0x00},

{0x3c, 0x77},
{0x8B, 0x06},
{0x94, 0x88},
{0x95, 0x88},
{0x40, 0xc1},
{0x29, 0x3f}, /*2f for internal regulator*/
{0x0f, 0x42},

{0x3d, 0x92},
{0x69, 0x40},
{0x5c, 0xb9},
{0x5d, 0x96},
{0x5e, 0x10},
{0x59, 0xc0},
{0x5a, 0xaf},
{0x5b, 0x55},
{0x43, 0xf0},
{0x44, 0x10},
{0x45, 0x68},
{0x46, 0x96},
{0x47, 0x60},
{0x48, 0x80},
{0x5f, 0xe0},
{0x60, 0x8c}, /*0c for advanced AWB (related to lens)*/
{0x61, 0x20},
{0xa5, 0xd9},
{0xa4, 0x74},
{0x8d, 0x02},
{0x13, 0xe7},

{0x4f, 0x3a},
{0x50, 0x3d},
{0x51, 0x03},
{0x52, 0x12},
{0x53, 0x26},
{0x54, 0x38},
{0x55, 0x40},
{0x56, 0x40},
{0x57, 0x40},
{0x58, 0x0d},

{0x8C, 0x23},
{0x3e, 0x02},
{0xa9, 0xb8},
{0xaa, 0x92},
{0xab, 0x0a},

{0x8f, 0xdf},
{0x90, 0x00},
{0x91, 0x00},
{0x9f, 0x00},
{0xa0, 0x00},
{0x3a, 0x0d}, /*UYVY, Digital BLC enable*/

{0x24, 0x70},
{0x25, 0x64},
{0x26, 0xc3},

{0x2a, 0x00}, /*10 for 50Hz*/
{0x2b, 0x00}, /*40 for 50Hz*/

{0x6c, 0x40},
{0x6d, 0x30},
{0x6e, 0x4b},
{0x6f, 0x60},
{0x70, 0x70},
{0x71, 0x70},
{0x72, 0x70},
{0x73, 0x70},
{0x74, 0x60},
{0x75, 0x60},
{0x76, 0x50},
{0x77, 0x48},
{0x78, 0x3a},
{0x79, 0x2e},
{0x7a, 0x28},
{0x7b, 0x22},
{0x7c, 0x04},
{0x7d, 0x07},
{0x7e, 0x10},
{0x7f, 0x28},
{0x80, 0x36},
{0x81, 0x44},
{0x82, 0x52},
{0x83, 0x60},
{0x84, 0x6c},
{0x85, 0x78},
{0x86, 0x8c},
{0x87, 0x9e},
{0x88, 0xbb},
{0x89, 0xd2},
{0x8a, 0xe6}
};
#if 0
static struct ov9650_reg
{
    u8 subaddr;
    u8 value;
}regs[] = {
    /* OV9650 intialization parameter table for SXGA application */       
    {0x12, 0x80}, {0x39, 0x43}, {0x38, 0x12}, {0x37, 0x00}, {0x0e, 0x20},
    {0x1e, 0x0c}, {0x01, 0x80}, {0x02, 0x80}, {0x00, 0x00}, {0x10, 0xf0},
    {0x04, 0x00}, {0x0c, 0x00}, {0x0d, 0x00}, {0x11, 0x80}, {0x12, 0x40},
    {0x14, 0x2e}, {0x15, 0x00}, {0x18, 0xbd}, {0x17, 0x1d}, {0x32, 0xbf},
    {0x03, 0x12}, {0x1a, 0x81}, {0x19, 0x01}, {0x3f, 0xa6}, {0x41, 0x02},
    {0x42, 0x08}, {0x1b, 0x00}, {0x16, 0x06}, {0x33, 0xc0}, {0x34, 0xbf},
    {0xa8, 0x80}, {0x96, 0x04}, {0x3a, 0x00}, {0x8e, 0x00}, {0x3c, 0x77},
    {0x8b, 0x06}, {0x35, 0x91}, {0x94, 0x88}, {0x95, 0x88}, {0x40, 0xc1},
    {0x29, 0x3f}, {0x0f, 0x42}, {0x13, 0xe5}, {0x3d, 0x92}, {0x69, 0x80},
    {0x5c, 0x96}, {0x5d, 0x96}, {0x5e, 0x10}, {0x59, 0xeb}, {0x5a, 0x9c},
    {0x5b, 0x55}, {0x43, 0xf0}, {0x44, 0x10}, {0x45, 0x55}, {0x46, 0x86},
    {0x47, 0x64}, {0x48, 0x86}, {0x5f, 0xe0}, {0x60, 0x8c}, {0x61, 0x20},
    {0xa5, 0xd9}, {0xa4, 0x74}, {0x8d, 0x02}, {0x13, 0xe7}, {0x4f, 0x3a},
    {0x50, 0x3d}, {0x51, 0x03}, {0x52, 0x12}, {0x53, 0x26}, {0x54, 0x38},
    {0x55, 0x40}, {0x56, 0x40}, {0x57, 0x40}, {0x58, 0x0d}, {0x8c, 0x23},
    {0x3e, 0x02}, {0xa9, 0xb8}, {0xaa, 0x92}, {0xab, 0x0a}, {0x8f, 0xdf},
    {0x90, 0x00}, {0x91, 0x00}, {0x9f, 0x00}, {0x3a, 0x0c}, {0x24, 0x70},
    {0x25, 0x64}, {0x26, 0xc3}, {0x2a, 0x12}, {0x2b, 0x46}, {0x3b, 0x19},
    {0x6c, 0x40}, {0x6d, 0x30}, {0x6e, 0x4b}, {0x6f, 0x60}, 
    {0x70, 0x70}, {0x71, 0x70}, {0x72, 0x70}, {0x73, 0x70},
    {0x74, 0x60}, {0x75, 0x60}, {0x76, 0x50}, {0x77, 0x48},
    {0x78, 0x3a}, {0x79, 0x2e}, {0x7a, 0x28}, {0x7b, 0x22},
    {0x7c, 0x04}, {0x7d, 0x07}, {0x7e, 0x10}, {0x7f, 0x28},
    {0x80, 0x36}, {0x81, 0x44}, {0x82, 0x52}, {0x83, 0x60},
    {0x84, 0x6c}, {0x85, 0x78}, {0x86, 0x8c}, {0x87, 0x9e},
    {0x88, 0xbb}, {0x89, 0xd2}, {0x8a, 0xe6},
    {0x6a, 0x41}, {0x66, 0x00},
    {0x3e, 0x00}, {0x3f, 0xa4}
};
#endif
DECLARE_MUTEX(regs_mutex);

static void __inline__ ov9650_poweron(void)
{
    s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_OUTP);
    s3c2410_gpio_setpin(S3C2410_GPG12, 0);
    mdelay(20);
}

static void __inline__ ov9650_poweroff(void)
{
    s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_OUTP);
    s3c2410_gpio_setpin(S3C2410_GPG12, 1);
    mdelay(20);
}

static int __inline__ ov9650_check(void)
{
    u32 mid;

    mid = sccb_read(OV9650_SCCB_ADDR, 0x1c)<<8;
    mid |= sccb_read(OV9650_SCCB_ADDR, 0x1d);
    printk("SCCB address 0x%02X, manufacture ID 0x%04X, expect 0x%04X\n", OV9650_SCCB_ADDR, mid, OV9650_MANUFACT_ID);

    return (mid==OV9650_MANUFACT_ID)?1:0;
}

static u32 __inline__ show_ov9650_product_id(void)
{
    u32 pid;

    pid = sccb_read(OV9650_SCCB_ADDR, 0x0a)<<8;
    pid |= sccb_read(OV9650_SCCB_ADDR, 0x0b);
    printk("SCCB address 0x%02X, product ID 0x%04X, expect 0x%04X\n", OV9650_SCCB_ADDR, pid, OV9650_PRODUCT_ID);
    return pid;
}

static void ov9650_init_regs(void)
{
    int i;
   
    down(&regs_mutex);
    for (i=0; i<ARRAY_SIZE(regs); i++)
    {
        if (regs[i].subaddr == 0xff)
        {
            mdelay(regs[i].value);
            continue;
        }
        sccb_write(OV9650_SCCB_ADDR, regs[i].subaddr, regs[i].value);
    }
    up(&regs_mutex);
}

int s3c2440_ov9650_init(void)
{
    printk(KERN_ALERT"Loading OV9650 driver.........\n");
    /* power on. */
    ov9650_poweron();
    mdelay(100);

    /* check device. */
    if (ov9650_check() == 0 && ov9650_check() == 0)
    {
        printk(KERN_ERR"No OV9650 found!!!\n");
        return -ENODEV;
    }

    show_ov9650_product_id();
    ov9650_init_regs();
    printk("ov9650 init done!\n");
    return 0;
}
#if 0
module_init(ov9650_init);
module_exit(ov9650_cleanup);
MODULE_LICENSE("GPL");
#endif





/*s3c2440camif.h*/

#ifndef __S3C2440CAMIF_H__
#define __S3C2440CAMIF_H__

#define MIN_C_WIDTH   32
#define MAX_C_WIDTH   320
#define MIN_C_HEIGHT  48
#define MAX_C_HEIGHT  240

#define MIN_P_WIDTH   32
#define MAX_P_WIDTH   640
#define MIN_P_HEIGHT  48
#define MAX_P_HEIGHT  480

enum
{
    CAMIF_BUFF_INVALID = 0,
    CAMIF_BUFF_RGB565 = 1,
    CAMIF_BUFF_RGB24 = 2,
    CAMIF_BUFF_YCbCr420 = 3,
    CAMIF_BUFF_YCbCr422 = 4
};

/* image buffer for s3c2440 camif. */
struct s3c2440camif_buffer
{
    int state;
    ssize_t img_size;

  struct device *dev;
    unsigned int order;
    unsigned long virt_base;
    unsigned long phy_base;
  unsigned long offset;
};

/* for s3c2440camif_dev->state field. */
enum
{
    CAMIF_STATE_FREE = 0,        // not openned
    CAMIF_STATE_READY = 1,        // openned, but standby
    CAMIF_STATE_PREVIEWING = 2,    // in previewing
    CAMIF_STATE_CODECING = 3    // in capturing
};

/* for s3c2440camif_dev->cmdcode field. */
enum
{
    CAMIF_CMD_NONE    = 0,
    CAMIF_CMD_SFMT    = 1<<0,        // source image format changed.
    CAMIF_CMD_WND    = 1<<1,        // window offset changed.
    CAMIF_CMD_ZOOM    = 1<<2,        // zoom picture in/out
    CAMIF_CMD_TFMT    = 1<<3,        // target image format changed.
    CAMIF_CMD_P2C    = 1<<4,        // need camif switches from p-path to c-path
    CAMIF_CMD_C2P    = 1<<5,        // neet camif switches from c-path to p-path
  CAMIF_CMD_REGS = 1<<6,  // Update regs

  CAMIF_CMD_START  = 1<<15,   // stop capture
    CAMIF_CMD_STOP    = 1<<16        // stop capture
};

enum
{
  CAMIF_PATH_NONE = 0,
  CAMIF_PATH_PREVIEW = 1<<0,
  CAMIF_PATH_CODEC = 1<<1
};

/* main s3c2440 camif structure. */
struct s3c2440camif_dev
{
    /* hardware clock. */
    struct clk * clk;

    /* source(input) image size. */
    int srcHsize;
    int srcVsize;

    /* windowed image size. */
    int wndHsize;
    int wndVsize;

    /* codec-path target(output) image size. */
    int coTargetHsize;
    int coTargetVsize;

    /* preview-path target(preview) image size. */
    int preTargetHsize;
    int preTargetVsize;

    /* the camera interface state. */
    int state;    // CMAIF_STATE_FREE, CAMIF_STATE_PREVIEWING, CAMIF_STATE_CAPTURING.

    /* for executing camif commands. */
    int cmdcode;                // command code, CAMIF_CMD_START, CAMIF_CMD_CFG, etc.
    wait_queue_head_t wait;    // wait queue for waiting untile command completed (if in preview or in capturing).

  /* For V4L2 data */
  __u32 pixelformat;
  int path; /*output path*/

  spinlock_t      lock;
  int open_count;
  int frame;  /*frame index*/
  int rdy;
};
#if 0
/* opened file handle.*/
struct s3c2440camif_fh
{
    /* the camif */
    struct s3c2440camif_dev    * dev;

    /* master flag, only master openner could execute 'set' ioctls. */
    int master;
};
#endif

struct s3c2440camif_res
{
  int width;
  int height;
};

#define S3C244X_CAMIFREG(x) ((x) + camif_base_addr)

/* CAMIF control registers */
#define S3C244X_CISRCFMT        S3C244X_CAMIFREG(0x00)
#define S3C244X_CIWDOFST        S3C244X_CAMIFREG(0x04)
#define S3C244X_CIGCTRL            S3C244X_CAMIFREG(0x08)
#define S3C244X_CICOYSA1        S3C244X_CAMIFREG(0x18)
#define S3C244X_CICOYSA2        S3C244X_CAMIFREG(0x1C)
#define S3C244X_CICOYSA3        S3C244X_CAMIFREG(0x20)
#define S3C244X_CICOYSA4        S3C244X_CAMIFREG(0x24)
#define S3C244X_CICOCBSA1        S3C244X_CAMIFREG(0x28)
#define S3C244X_CICOCBSA2        S3C244X_CAMIFREG(0x2C)
#define S3C244X_CICOCBSA3        S3C244X_CAMIFREG(0x30)
#define S3C244X_CICOCBSA4        S3C244X_CAMIFREG(0x34)
#define S3C244X_CICOCRSA1        S3C244X_CAMIFREG(0x38)
#define S3C244X_CICOCRSA2        S3C244X_CAMIFREG(0x3C)
#define S3C244X_CICOCRSA3        S3C244X_CAMIFREG(0x40)
#define S3C244X_CICOCRSA4        S3C244X_CAMIFREG(0x44)
#define S3C244X_CICOTRGFMT        S3C244X_CAMIFREG(0x48)
#define S3C244X_CICOCTRL        S3C244X_CAMIFREG(0x4C)
#define S3C244X_CICOSCPRERATIO    S3C244X_CAMIFREG(0x50)
#define S3C244X_CICOSCPREDST    S3C244X_CAMIFREG(0x54)
#define S3C244X_CICOSCCTRL        S3C244X_CAMIFREG(0x58)
#define S3C244X_CICOTAREA        S3C244X_CAMIFREG(0x5C)
#define S3C244X_CICOSTATUS        S3C244X_CAMIFREG(0x64)
#define S3C244X_CIPRCLRSA1        S3C244X_CAMIFREG(0x6C)
#define S3C244X_CIPRCLRSA2        S3C244X_CAMIFREG(0x70)
#define S3C244X_CIPRCLRSA3        S3C244X_CAMIFREG(0x74)
#define S3C244X_CIPRCLRSA4        S3C244X_CAMIFREG(0x78)
#define S3C244X_CIPRTRGFMT        S3C244X_CAMIFREG(0x7C)
#define S3C244X_CIPRCTRL        S3C244X_CAMIFREG(0x80)
#define S3C244X_CIPRSCPRERATIO    S3C244X_CAMIFREG(0x84)
#define S3C244X_CIPRSCPREDST    S3C244X_CAMIFREG(0x88)
#define S3C244X_CIPRSCCTRL        S3C244X_CAMIFREG(0x8C)
#define S3C244X_CIPRTAREA        S3C244X_CAMIFREG(0x90)
#define S3C244X_CIPRSTATUS        S3C244X_CAMIFREG(0x98)
#define S3C244X_CIIMGCPT        S3C244X_CAMIFREG(0xA0)

#define S3C244X_CICOSTAY(i)     S3C244X_CAMIFREG((0x18+(i)*4))
#define S3C244X_CICOSTACb(i)    S3C244X_CAMIFREG((0x28+(i)*4))
#define S3C244X_CICOSTACr(i)    S3C244X_CAMIFREG((0x38+(i)*4))
#define S3C244X_CIPRSTARGB(i)   S3C244X_CAMIFREG((0x6C+(i)*4))

#endif




/*s3c2440camif.c*/

/*
 * Video for Linux 2 - Camera interface on S3C2440
 *
 * Copyright (C) 2009
 *
 * 2009/06/19 :
 *  ported by Steve Chang
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
*/  

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef CONFIG_VIDEO_V4L1_COMPAT
#include
#endif
#include
#include
#include
#include

#include
#include
#include
#include
#include
#include

#include "s3c2440camif.h"

/* debug print macro. */

/* hardware & driver name, version etc. */
#define CARD_NAME        "camera"

static unsigned has_ov9650;
unsigned long camif_base_addr;

#if 1
int __init sccb_init(void);
void __exit sccb_cleanup(void);
int __init s3c2440_ov9650_init(void);
void __exit s3c2440_ov9650_cleanup(void);
#endif

/* camera device(s) */
static struct s3c2440camif_dev camera;


/* image buffer for previewing. */
struct s3c2440camif_buffer img_buff[] =
{
    {
        .state = CAMIF_BUFF_INVALID,
        .img_size = 0,
        .order = 0,
        .virt_base = (unsigned long)NULL,
        .phy_base = (unsigned long)NULL,
    .offset = 0
    },
    {
        .state = CAMIF_BUFF_INVALID,
        .img_size = 0,
        .order = 0,
        .virt_base = (unsigned long)NULL,
        .phy_base = (unsigned long)NULL,
    .offset = 0
    },
    {
        .state = CAMIF_BUFF_INVALID,
        .img_size = 0,
        .order = 0,
        .virt_base = (unsigned long)NULL,
        .phy_base = (unsigned long)NULL,
    .offset = 0
    },
    {
        .state = CAMIF_BUFF_INVALID,
        .img_size = 0,
        .order = 0,
        .virt_base = (unsigned long)NULL,
        .phy_base = (unsigned long)NULL,
    .offset = 0
    }
};

/* software reset camera interface. */
static void __inline__ soft_reset_camif(void)
{
    u32 cigctrl;
  u32 cisrcfmt;

  cisrcfmt = ioread32(S3C244X_CISRCFMT);
  cisrcfmt |= (1<<31);          // ITU-R BT.601 YCbCr 8-bit mode
  iowrite32(cisrcfmt, S3C244X_CISRCFMT);  /*Recommand by datasheet p.532*/

    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 s3c2440camif_dev * pdev)
{
    /* 1. stop codec. */
    {
        u32 cicoscctrl;
        cicoscctrl = ioread32(S3C244X_CICOSCCTRL);
        cicoscctrl &= ~(1<<15);    // stop codec 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);
    }

  pdev->path = CAMIF_PATH_PREVIEW;
}

/* switch camif from codec path to preview path. */
static void __inline__ camif_p2c(struct s3c2440camif_dev * pdev)
{
  /* 1. stop preview. */
  {
    u32 ciprscctrl;
    ciprscctrl = ioread32(S3C244X_CIPRSCCTRL);
    ciprscctrl &= ~(1<<15); // stop preview scaler.
    iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL);
  }

  /* 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);
  }

  pdev->path = CAMIF_PATH_CODEC;
}

/* 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 s3c2440camif_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
//                |(0<<14)                // input order is YCbYCr
//                |(1<<14)                // input order is YCrYCb
                |(2<<14)                // input order is CbYCrY
//                |(3<<14)                // input order is CrYCbY
                |(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 s3c2440camif_dev * pdev)
{
    u32 ciprtrgfmt, cicotrgfmt = 0;
    u32 ciprctrl, cicoctrl;
    u32 ciprscctrl, cicoscctrl;

    u32 mainBurstSize, remainedBurstSize;

  switch(pdev->path)  {
    case CAMIF_PATH_PREVIEW:

          /* 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);
      break;
    case CAMIF_PATH_CODEC:

      /* CICOYSA1 ~ CICOYSA4. */
      iowrite32(img_buff[0].phy_base, S3C244X_CICOYSA1);
      iowrite32(img_buff[1].phy_base, S3C244X_CICOYSA2);
      iowrite32(img_buff[2].phy_base, S3C244X_CICOYSA3);
      iowrite32(img_buff[3].phy_base, S3C244X_CICOYSA4);

      /* CICOCBSA1 ~ CICOCBSA4. */
      iowrite32(img_buff[0].phy_base + (pdev->coTargetHsize * pdev->coTargetVsize), S3C244X_CICOCBSA1);
      iowrite32(img_buff[1].phy_base + (pdev->coTargetHsize * pdev->coTargetVsize), S3C244X_CICOCBSA2);
      iowrite32(img_buff[2].phy_base + (pdev->coTargetHsize * pdev->coTargetVsize), S3C244X_CICOCBSA3);
      iowrite32(img_buff[3].phy_base + (pdev->coTargetHsize * pdev->coTargetVsize), S3C244X_CICOCBSA4);
    
      switch(pdev->pixelformat)  {
        case V4L2_PIX_FMT_YUYV:
        case V4L2_PIX_FMT_YUV422P:
          /* CICOCRSA1 ~ CICOCRSA4. */
          iowrite32(img_buff[0].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 3 / 2), S3C244X_CICOCRSA1);
          iowrite32(img_buff[1].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 3 / 2), S3C244X_CICOCRSA2);
          iowrite32(img_buff[2].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 3 / 2), S3C244X_CICOCRSA3);
          iowrite32(img_buff[3].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 3 / 2), S3C244X_CICOCRSA4);

          cicotrgfmt = (1<<31)|(1<<30);  /**/
          break;
        case V4L2_PIX_FMT_YUV420:
          /* CICOCRSA1 ~ CICOCRSA4. */
          iowrite32(img_buff[0].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 5 / 4), S3C244X_CICOCRSA1);
          iowrite32(img_buff[1].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 5 / 4), S3C244X_CICOCRSA2);
          iowrite32(img_buff[2].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 5 / 4), S3C244X_CICOCRSA3);
          iowrite32(img_buff[3].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 5 / 4), S3C244X_CICOCRSA4);

          cicotrgfmt = (1<<31); /**/
          break;
      }

      /* CICOTRGFMT. */
      cicotrgfmt |= (pdev->coTargetHsize<<16)   // horizontal pixel number of target image
            |(0<<14)            // don't mirror or rotation.
            |(pdev->coTargetVsize<<0); // vertical pixel number of target image
      iowrite32(cicotrgfmt, S3C244X_CICOTRGFMT);

      /* CICOCTRL. */
      calc_burst_size(1, pdev->coTargetHsize, &mainBurstSize, &remainedBurstSize);  /*y frame*/
      cicoctrl = (mainBurstSize<<19)|(remainedBurstSize<<14);
      calc_burst_size(1, (pdev->coTargetHsize / 2), &mainBurstSize, &remainedBurstSize);  /*CbCr frame*/
      cicoctrl |= (mainBurstSize<<9)|(remainedBurstSize<<4);
      iowrite32(cicoctrl, S3C244X_CICOCTRL);

      /* CICOSCCTRL. */
      cicoscctrl = ioread32(S3C244X_CICOSCCTRL);
      cicoscctrl &= 1<<15;  // clear all other info except 'codec scaler start'.
      iowrite32(cicoscctrl, S3C244X_CICOSCCTRL);

      /* CICOTAREA. */
      iowrite32(pdev->coTargetHsize * pdev->coTargetVsize, S3C244X_CICOTAREA);
      break;
  }

}

/* update CIWDOFST only. */
static void __inline__ update_target_wnd_regs(struct s3c2440camif_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 s3c2440camif_dev *pdev)
{
    u32 preHratio, preVratio;
  u32 coHratio, coVratio;
    u32 Hshift, Vshift;
    u32 shfactor;
    u32 preDstWidth, preDstHeight;
    u32 Hscale, Vscale;
    u32 mainHratio, mainVratio;

    u32 ciprscpreratio, cicoscpreratio;
    u32 ciprscpredst, cicoscpredst;
    u32 ciprscctrl, cicoscctrl;

  switch(pdev->path)  {
    case CAMIF_PATH_PREVIEW:

      /* CIPRSCPRERATIO. */
      calc_prescaler_ratio_shift(pdev->srcHsize, pdev->preTargetHsize,
                        &preHratio, &Hshift);
      calc_prescaler_ratio_shift(pdev->srcVsize, 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->srcHsize / preHratio;
          preDstHeight = pdev->srcVsize / preVratio;
          ciprscpredst = (preDstWidth<<16)    // destination width for preview pre-scaler
                        |(preDstHeight<<0);    // destination height for preview pre-scaler
          iowrite32(ciprscpredst, S3C244X_CIPRSCPREDST);
 
          /* CIPRSCCTRL. */
          Hscale = (pdev->srcHsize >= pdev->preTargetHsize)?0:1;
          Vscale = (pdev->srcVsize >= pdev->preTargetVsize)?0:1;
          mainHratio = (pdev->srcHsize<<8)/(pdev->preTargetHsize<
          mainVratio = (pdev->srcVsize<<8)/(pdev->preTargetVsize<
          ciprscctrl = ioread32(S3C244X_CIPRSCCTRL);
      ciprscctrl &= ~(1<<30); //keep preview image format RGB565
//          ciprscctrl &= (1<<15);    //preview scaler start.
          ciprscctrl |= (1<<31)    // this bit should be always 1.
                        |(Hscale<<29)        // ???, horizontal scale up/down.
                        |(Vscale<<28)        // ???, vertical scale up/down.
                        |(mainHratio<<16)    // horizontal scale ratio for preview main-scaler
                        |(mainVratio<<0);    // vertical scale ratio for preview main-scaler
          iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL);

      break;
    case CAMIF_PATH_CODEC:

      /* CICOSCPRERATIO. */
      calc_prescaler_ratio_shift(pdev->srcHsize, pdev->coTargetHsize,
                        &coHratio, &Hshift);
      calc_prescaler_ratio_shift(pdev->srcVsize, pdev->coTargetVsize,
                        &coVratio, &Vshift);
      
      shfactor = 10 - (Hshift + Vshift);

      cicoscpreratio = (shfactor<<28)   // shift factor for preview pre-scaler
              |(coHratio<<16)  // horizontal ratio of preview pre-scaler
              |(coVratio<<0);  // vertical ratio of preview pre-scaler
      iowrite32(cicoscpreratio, S3C244X_CICOSCPRERATIO);
 
      /* CICOSCPREDST. */
      preDstWidth = pdev->srcHsize / coHratio;
      preDstHeight = pdev->srcVsize / coVratio;
      cicoscpredst = (preDstWidth<<16)  // destination width for preview pre-scaler
              |(preDstHeight<<0); // destination height for preview pre-scaler
      iowrite32(cicoscpredst, S3C244X_CICOSCPREDST);

      /* CICOSCCTRL. */
      Hscale = (pdev->srcHsize >= pdev->coTargetHsize)?0:1;
      Vscale = (pdev->srcVsize >= pdev->coTargetVsize)?0:1;
      mainHratio = (pdev->srcHsize<<8)/(pdev->coTargetHsize<
      mainVratio = (pdev->srcVsize<<8)/(pdev->coTargetVsize<
      cicoscctrl = ioread32(S3C244X_CICOSCCTRL);
//      cicoscctrl &= (1<<15);  //codec scaler start.
      cicoscctrl |=
              (Hscale<<30)   // ???, horizontal scale up/down.
              |(Vscale<<29)   // ???, vertical scale up/down.
              |(mainHratio<<16) // horizontal scale ratio for preview main-scaler
              |(mainVratio<<0); // vertical scale ratio for preview main-scaler
      iowrite32(cicoscctrl, S3C244X_CICOSCCTRL);

      break;
  }
}

/* update camif registers, called only when camif ready, or ISR. */
static void __inline__ update_camif_regs(struct s3c2440camif_dev * pdev)
{
    if (!in_irq())
    {
        while(1)    // wait until VSYNC is 'L'
        {
            barrier();
            if ((ioread32(S3C244X_CICOSTATUS)&(1<<28)) == 0)
                break;
        }
    }

    /* WARNING: don't change the statement sort below!!! */
    update_source_fmt_regs(pdev);
    update_target_wnd_regs(pdev);
    update_target_fmt_regs(pdev);
    update_target_zoom_regs(pdev);
}

/* start image capture.
 *
 * param 'stream' means capture pictures streamly or capture only one picture.
 */
static int start_capture(struct s3c2440camif_dev * pdev)
{
    int ret;

    u32 ciwdofst;
    u32 ciprscctrl, cicoscctrl;
    u32 ciimgcpt;

  if(pdev->path == CAMIF_PATH_NONE)
    return 0;

    ciwdofst = ioread32(S3C244X_CIWDOFST);
    ciwdofst |= (1<<30)        // Clear the overflow indication flag of input CODEC FIFO Y
                |(1<<15)    // Clear the overflow indication flag of input CODEC FIFO Cb
                |(1<<14)    // Clear the overflow indication flag of input CODEC FIFO Cr
                |(1<<13)    // Clear the overflow indication flag of input PREVIEW FIFO Cb
                |(1<<12);    // Clear the overflow indication flag of input PREVIEW FIFO Cr
    iowrite32(ciwdofst, S3C244X_CIWDOFST);

  switch(pdev->path)  {
    case CAMIF_PATH_PREVIEW:
//printk("Preview Start...\n");
      ciprscctrl = ioread32(S3C244X_CIPRSCCTRL);
      ciprscctrl |= 1<<15;  // preview scaler start
      iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL);
 
      ciimgcpt = (1<<31)    // camera interface global capture enable
              |(1<<29);  // capture enable for preview scaler.
      
      iowrite32(ciimgcpt, S3C244X_CIIMGCPT);

      pdev->state = CAMIF_STATE_PREVIEWING;

      break;
    case CAMIF_PATH_CODEC:
//printk("Codec Start...\n");
      cicoscctrl = ioread32(S3C244X_CICOSCCTRL);
      cicoscctrl |= (1<<15);  // codec scaler start
      iowrite32(cicoscctrl, S3C244X_CICOSCCTRL);
 
      ciimgcpt = (1<<31)    // camera interface global capture enable
              |(1<<30);  // capture enable for codec scaler.
      
      iowrite32(ciimgcpt, S3C244X_CIIMGCPT);

      pdev->state = CAMIF_STATE_CODECING;

      break;
  }


    ret = 0;

#if 0
    if (stream == 0)
    {
        pdev->cmdcode = CAMIF_CMD_STOP;

        ret = wait_event_interruptible(pdev->wait, pdev->cmdcode == CAMIF_CMD_NONE);
    }
#endif
    return ret;
}

/* stop image capture, always called in ISR.
 *    P-path regs:
 *        CIPRSCCTRL
 *        CIPRCTRL
 *    C-path regs:
 *        CICOSCCTRL.
 *        CICOCTRL
 *    Global regs:
 *        CIIMGCPT
 */
static void stop_capture(struct s3c2440camif_dev * pdev)
{
    u32 ciprscctrl, cicoscctrl;
    u32 ciprctrl, cicoctrl;

    switch(pdev->state)
    {
      case CAMIF_STATE_PREVIEWING:
          /* CIPRCTRL. */
          ciprctrl = ioread32(S3C244X_CIPRCTRL);
          ciprctrl |= 1<<2;        // enable last IRQ at the end of frame capture.
          iowrite32(ciprctrl, S3C244X_CIPRCTRL);
 
          /* CIPRSCCTRL. */
          ciprscctrl = ioread32(S3C244X_CIPRSCCTRL);
          ciprscctrl &= ~(1<<15);        // clear preview scaler start bit.
          iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL);
 
          break;
 
      case CAMIF_STATE_CODECING:
          /* CICOCTRL. */
          cicoctrl = ioread32(S3C244X_CICOCTRL);
          cicoctrl |= 1<<2;        // enable last IRQ at the end of frame capture.
          iowrite32(cicoctrl, S3C244X_CICOCTRL);
 
          /* CICOSCCTRL. */
          cicoscctrl = ioread32(S3C244X_CICOSCCTRL);
          cicoscctrl &= ~(1<<15);        // clear codec scaler start bit.
          iowrite32(cicoscctrl, S3C244X_CICOSCCTRL);
 
          break;
 
    }

  /* CIIMGCPT. */
  iowrite32(0, S3C244X_CIIMGCPT);
  pdev->state = CAMIF_STATE_READY;
 
}

/* update camera interface with the new config. */
static void update_camif_config (struct s3c2440camif_dev *pdev, u32 cmdcode)
{
    switch(pdev->state)
    {
    case CAMIF_STATE_READY:

    if(cmdcode == CAMIF_CMD_REGS)
    {
          update_camif_regs(pdev);        // config the regs directly.
      break;
    }
#if 0
    /* source image format. */
    if (cmdcode & CAMIF_CMD_SFMT)
    {
      // ignore it, nothing to do now.
    }

    /* target image format. */
    if (cmdcode & CAMIF_CMD_TFMT)
    {
        /* change target image format only. */
    }

    /* target image window offset. */
    if (cmdcode & CAMIF_CMD_WND)
    {
    }

    /* target image zoomi & zoomout. */
    if (cmdcode & CAMIF_CMD_ZOOM)
    {
    }
#endif
    if (cmdcode == CAMIF_CMD_P2C)
    {
      camif_p2c(pdev);
      break;
    }

    if (cmdcode == CAMIF_CMD_C2P)
    {
      camif_c2p(pdev);
      break;
    }

    if (cmdcode == CAMIF_CMD_START)
    {
      start_capture(pdev);
    }

    break;

    case CAMIF_STATE_PREVIEWING:

    /* camif is previewing image. */
    disable_irq(IRQ_S3C2440_CAM_P);   // disable cam-preview irq.
    /* stop previewing. */
    if (cmdcode & CAMIF_CMD_STOP)
    {
      pdev->cmdcode |= CAMIF_CMD_STOP;
    }
    enable_irq(IRQ_S3C2440_CAM_P);  // enable cam-preview irq.
    wait_event(pdev->wait, (pdev->cmdcode==CAMIF_CMD_NONE));  // wait until the ISR completes command.
        break;

    case CAMIF_STATE_CODECING:

        /* camif is previewing image. */
        disable_irq(IRQ_S3C2440_CAM_C);        // disable cam-codec irq.
        /* stop previewing. */
        if (cmdcode & CAMIF_CMD_STOP)
        {
            pdev->cmdcode |= CAMIF_CMD_STOP;
        }
        enable_irq(IRQ_S3C2440_CAM_C);    // enable cam-codec irq.
        wait_event(pdev->wait, (pdev->cmdcode==CAMIF_CMD_NONE));    // wait until the ISR completes command.
        break;

    default:
        break;
    }
}

static void __inline__ invalid_image_buffer(void)
{
    img_buff[0].state = CAMIF_BUFF_INVALID;
    img_buff[1].state = CAMIF_BUFF_INVALID;
    img_buff[2].state = CAMIF_BUFF_INVALID;
    img_buff[3].state = CAMIF_BUFF_INVALID;
}

/* init image buffer (only when the camif is first open). */
static int __inline__ init_image_buffer(struct s3c2440camif_dev *pdev)
{
    int size1, size2;

    unsigned long size = 0;
    unsigned int order = 0;

    /* size1 is the max image size of codec path. */
    size1 = MAX_C_WIDTH * MAX_C_HEIGHT * 2;
    /* size2 is the max image size of preview path. */
    size2 = MAX_P_WIDTH * MAX_P_HEIGHT * 2;

    size = (size1 > size2) ? size1 : size2;

printk("dma_alloc_coherent <0> size : 0x%08x\n", size);
    order = get_order(size);
    img_buff[0].order = order;
    img_buff[0].virt_base = __get_free_pages(GFP_KERNEL|GFP_DMA, img_buff[0].order);
    if (img_buff[0].virt_base == (unsigned long)NULL)
    {
        goto error0;
    }
  img_buff[0].img_size = size;
    img_buff[0].phy_base = img_buff[0].virt_base - PAGE_OFFSET + PHYS_OFFSET;    // the DMA address.
  img_buff[0].offset = 0;

printk("dma_alloc_coherent <1> size : 0x%08x\n", size);
    img_buff[1].order = order;
    img_buff[1].virt_base = __get_free_pages(GFP_KERNEL|GFP_DMA, img_buff[1].order);
    if (img_buff[1].virt_base == (unsigned long)NULL)
    {
        goto error1;
    }
  img_buff[1].img_size = size;
    img_buff[1].phy_base = img_buff[1].virt_base - PAGE_OFFSET + PHYS_OFFSET;    // the DMA address.
  img_buff[1].offset = PAGE_SIZE << order;

printk("dma_alloc_coherent <2> size : 0x%08x\n", size);
    img_buff[2].order = order;
    img_buff[2].virt_base = __get_free_pages(GFP_KERNEL|GFP_DMA, img_buff[2].order);
    if (img_buff[2].virt_base == (unsigned long)NULL)
    {
        goto error2;
    }
  img_buff[2].img_size = size;
    img_buff[2].phy_base = img_buff[2].virt_base - PAGE_OFFSET + PHYS_OFFSET;    // the DMA address.
  img_buff[2].offset = (PAGE_SIZE << order) * 2;

printk("dma_alloc_coherent <3> size : 0x%08x\n", size);
    img_buff[3].order = order;
    img_buff[3].virt_base = __get_free_pages(GFP_KERNEL|GFP_DMA, img_buff[3].order);
    if (img_buff[3].virt_base == (unsigned long)NULL)
    {
        goto error3;
    }
  img_buff[3].img_size = size;
    img_buff[3].phy_base = img_buff[3].virt_base - PAGE_OFFSET + PHYS_OFFSET;    // the DMA address.
  img_buff[3].offset = (PAGE_SIZE << order) * 3;

    invalid_image_buffer();

    return 0;
error3:
  free_pages(img_buff[2].virt_base, order);
    img_buff[2].phy_base = (unsigned long)NULL;
error2:
  free_pages(img_buff[1].virt_base, order);
    img_buff[1].phy_base = (unsigned long)NULL;
error1:
    free_pages(img_buff[0].virt_base, order);
    img_buff[0].phy_base = (unsigned long)NULL;
error0:
    return -ENOMEM;
}

/* free image buffers (only when the camif is latest close). */
static void __inline__ free_image_buffer(struct s3c2440camif_dev *pdev)
{

    free_pages(img_buff[0].virt_base, img_buff[0].order);
    free_pages(img_buff[1].virt_base, img_buff[1].order);
    free_pages(img_buff[2].virt_base, img_buff[2].order);
    free_pages(img_buff[3].virt_base, img_buff[3].order);

    img_buff[0].order = 0;
    img_buff[0].virt_base = (unsigned long)NULL;
    img_buff[0].phy_base = (unsigned long)NULL;
  img_buff[0].offset = 0;

    img_buff[1].order = 0;
    img_buff[1].virt_base = (unsigned long)NULL;
    img_buff[1].phy_base = (unsigned long)NULL;
  img_buff[1].offset = 0;

    img_buff[2].order = 0;
    img_buff[2].virt_base = (unsigned long)NULL;
    img_buff[2].phy_base = (unsigned long)NULL;
  img_buff[2].offset = 0;

    img_buff[3].order = 0;
    img_buff[3].virt_base = (unsigned long)NULL;
    img_buff[3].phy_base = (unsigned long)NULL;
  img_buff[3].offset = 0;
}

static void __inline__ update_image_buffer(struct s3c2440camif_dev *pdev)
{
  unsigned long size = 0;
  switch(pdev->pixelformat) {
    case V4L2_PIX_FMT_RGB565:
      size = pdev->preTargetHsize * pdev->preTargetVsize * 2;

2 則留言:

  1. good day
    can You send this driver to me (Nikolay.Zhgulev@gmail.com)
    thanks

    [版主回覆11/20/2009 14:14:00]No problem.

    回覆刪除
  2. hi,these days i need to write a v4l2 driver on s3c2440, after reading this blog, i found it's good!
    can you send this driver to me (chaozheng0710@yahoo.cn)
    thanks

    回覆刪除