* v4l2 camera test app
@ 2006-03-16 10:25 Komal Shah
2006-03-20 13:19 ` Ola Helm
0 siblings, 1 reply; 8+ messages in thread
From: Komal Shah @ 2006-03-16 10:25 UTC (permalink / raw)
To: linux-omap-open-source
[-- Attachment #1: Type: text/plain, Size: 591 bytes --]
Hi All,
As I had received 2-3 emails in the past for simple v4l2 camera capture
test application for OMAP, I have attached the one which I have tested
with OMAP2420 TI EVM.
To compile
#arm-linux-gcc -o vcaputre vcam.c
To execute
#./vcaputre -n 20 -m -C cam.dump
Enjoy and fix the bugs you find yourself or send me the patch. There
are quite lot of improvments one can do to this app :)
---Komal Shah
http://komalshah.blogspot.com/
__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 3552432323-vcam.c --]
[-- Type: text/x-csrc; name="vcam.c", Size: 20353 bytes --]
/* Video For Linux 2 based camera capture
* application.
*
* Author: Komal Shah <komal_shah802003@yahoo.com>
*
* Part of code derived from xawtv
* License of xawtv applies.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <getopt.h> /* getopt_long() */
#include <fcntl.h> /* low-level i/o */
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/signal.h>
#include <asm/types.h> /* for videodev2.h */
#include <linux/videodev2.h>
/* TODO:
*
* -- Add direct rendering captured buffers to videoout
* -- Add option for the above.
* -- Add notice if driver supported preview is enabled. Drops the FPS.
* -- Make scripts to simplify execution and corner testing
* -- Add sensor capture format selection strings on command line
* -- Add better parameter checking supplied by user on command line.
*/
#define DEFAULT_WIDTH 320
#define DEFAULT_HEIGHT 240
#define DEFAULT_NFRAMES 10
#define DEFAULT_SIZE (DEFAULT_WIDTH*DEFAULT_HEIGHT*2)
#define WANTED_BUFFERS 32
#define MAX_CTRL 32
#define MAX_FORMAT 32
#define ALIGN 1
#define CAN_READWRITE 0x00000001
#define CAN_STREAM 0x00000002
#define CAN_OVERLAY 0x00000004
#define IO_METHOD_MMAP 0x00000001
#define IO_METHOD_READ 0x00000002
#define IO_METHOD_USERPTR 0x00000004
#define CLEAR(x) memset (&(x), 0, sizeof (x))
struct app_video_format {
unsigned int width;
unsigned int height;
unsigned int pixelformat;
enum v4l2_buf_type type;
unsigned int bytesperline;
unsigned int memory;
};
struct app_video_buf {
struct app_video_format fmt;
size_t size;
unsigned char *data;
};
struct v4l2_handle {
int fd;
char *device;
struct v4l2_capability cap;
struct v4l2_streamparm streamparm;
struct v4l2_queryctrl ctl[MAX_CTRL*2];
struct v4l2_fmtdesc fmtdesc[MAX_FORMAT];
int nfmts;
int flags;
int fps,first;
long long start;
struct v4l2_format fmt;
int capture;
int player;
struct v4l2_requestbuffers req;
/* Internal v4l2_buffers */
struct v4l2_buffer buf_v4l2[WANTED_BUFFERS];
/* mapped buffers in user space*/
struct app_video_buf buf_me[WANTED_BUFFERS];
struct v4l2_framebuffer ov_fb;
struct v4l2_format ov_win;
int ov_error;
int ov_enabled;
int ov_on;
struct app_video_format *app_fmt;
};
static int (*init_userp)(struct v4l2_handle *handle, unsigned int buffer_size);
static int (*init_mmap)(struct v4l2_handle *handle, int bcount);
static int (*init_read)(struct v4l2_handle *handle, unsigned int buffer_size);
static void* (*init_device)(char *device);
struct _buffer
{
void *start;
int length;
};
struct _buffer *buffers = NULL;
unsigned int n_buffers = 0;
unsigned int bcount = 2;
void errno_exit(char *msg);
static int vid_capture(void *h, char *filename);
static int read_frame(struct v4l2_handle *h);
int width = DEFAULT_WIDTH;
int height = DEFAULT_HEIGHT;
char *filename = "dump";
int nframes = 0; /*DEFAULT_NFRAMES;*/
int open_mode = O_RDWR | O_NONBLOCK; /* O_NONBLOCK is must for camera*/
static char *command;
static char *device = "/dev/v4l/video0" ; /* default */
int io = IO_METHOD_READ; /*default */
int capture = 0;
int preview = 0;
int vplayer = 0;
int vcapture = 0;
int fps = 0;
FILE *outfd = NULL;
FILE *infd = NULL;
/* NOTE: Let the few common function between vplay and
* vcapture separate...once I finish the testing with
* all the features, I can merge them based on the
* difference and the amount of code duplication.
* ---Komal Shah
*/
static void
print_bufinfo(struct v4l2_buffer *buf)
{
static char *type[] = {
[V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap",
[V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over",
[V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out",
[V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap",
[V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out",
};
fprintf(stderr,"v4l2: buf %d: %s 0x%x+%d, used %d\n",
buf->index,
buf->type < sizeof(type)/sizeof(char*)
? type[buf->type] : "unknown",
buf->m.offset,buf->length,buf->bytesused);
}
int xioctl(int fd, int request, void *arg)
{
int r;
do r = ioctl(fd, request, arg);
while( -1 == r && EINTR == errno);
return r;
}
void errno_exit(char *msg)
{
printf("Exit : %s\n", msg);
exit(0);
}
static int v4l2_open(void *handle)
{
struct v4l2_handle *h = handle;
printf("device name is %s\n", h->device);
h->fd = open(h->device, open_mode, 0);
if (h->fd == -1)
return -1;
return 0;
}
static int v4l2_close(void *handle)
{
struct v4l2_handle *h = handle;
close(h->fd);
h->fd = -1;
}
static void
get_device_capabilities(struct v4l2_handle *h)
{
if (xioctl(h->fd, VIDIOC_QUERYCAP, &h->cap) == -1) {
close(h->fd);
return -1;
}
}
static void
enum_fmts(struct v4l2_handle *h)
{
for (h->nfmts = 0; h->nfmts < MAX_FORMAT; h->nfmts++) {
h->fmtdesc[h->nfmts].index = h->nfmts;
h->fmtdesc[h->nfmts].type = h->app_fmt->type;
if (-1 == xioctl(h->fd, VIDIOC_ENUM_FMT, &h->fmtdesc[h->nfmts]))
break;
}
h->streamparm.type = h->app_fmt->type;
ioctl(h->fd,VIDIOC_G_PARM,&h->streamparm);
}
static int
v4l2_setformat(void *handle)
{
unsigned int min;
int ret;
struct v4l2_handle *h = handle;
h->fmt.type = h->app_fmt->type;
h->fmt.fmt.pix.width = h->app_fmt->width;
h->fmt.fmt.pix.height= h->app_fmt->height;
h->fmt.fmt.pix.pixelformat = h->app_fmt->pixelformat;
h->fmt.fmt.pix.field = V4L2_FIELD_NONE;
ret = xioctl(h->fd, VIDIOC_S_FMT, &h->fmt);
if (ret < 0)
{
fprintf(stderr, "ioctl VIDIOC_S_FMT failed: %s", strerror(errno));
return -1;
}
if (h->fmt.fmt.pix.pixelformat != h->app_fmt->pixelformat)
return -1;
h->app_fmt->width = h->fmt.fmt.pix.width;
h->app_fmt->height = h->fmt.fmt.pix.height;
h->app_fmt->bytesperline = h->fmt.fmt.pix.bytesperline;
min = h->fmt.fmt.pix.width*2;
if(h->fmt.fmt.pix.bytesperline < min)
h->fmt.fmt.pix.bytesperline = min;
min = h->fmt.fmt.pix.bytesperline*h->fmt.fmt.pix.height;
if(h->fmt.fmt.pix.sizeimage < min)
h->fmt.fmt.pix.sizeimage = min;
fprintf(stderr,"v4l2: new params (%dx%d, %c%c%c%c, %d byte)\n",
h->app_fmt->width,h->app_fmt->height,
h->fmt.fmt.pix.pixelformat & 0xff,
(h->fmt.fmt.pix.pixelformat >> 8) & 0xff,
(h->fmt.fmt.pix.pixelformat >> 16) & 0xff,
(h->fmt.fmt.pix.pixelformat >> 24) & 0xff,
h->fmt.fmt.pix.sizeimage);
return 0;
}
void* vcapture_init_device(char *device)
{
struct v4l2_capability vcap;
struct v4l2_format fmt;
int ret;
struct v4l2_handle *h;
if(device && 0 != strncmp(device, "/dev/", 5))
return NULL;
h = (struct v4l2_handle*) malloc(sizeof(*h));
if ( h == NULL)
return NULL;
memset(h, 0, sizeof(*h));
h->fd = -1;
h->device = strdup(device ? device : "/dev/v4l/video0");
if (v4l2_open(h) != 0)
goto err;
h->app_fmt = (struct app_video_format*) malloc(sizeof(*h->app_fmt));
memset(h->app_fmt, 0, sizeof(*h->app_fmt));
h->app_fmt->width = width;
h->app_fmt->height = height;
h->app_fmt->pixelformat = V4L2_PIX_FMT_UYVY;
/*h->app_fmt->pixelformat = V4L2_PIX_FMT_SBGGR8;*/
get_device_capabilities(h);
fprintf(stderr, "v4l2: init\nv4l2: device info:\n"
" %s %d.%d.%d / %s @ %s\n",
h->cap.driver,
(h->cap.version >> 16) & 0xff,
(h->cap.version >> 8) & 0xff,
h->cap.version & 0xff,
h->cap.card,h->cap.bus_info);
if (h->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
{
h->capture = 1;
}
else if (h->cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)
{
h->player = 1;
}
else {
fprintf(stderr, "Driver doesn't support capture/video"
"output capabilities\n");
goto err;
}
if (h->cap.capabilities & V4L2_CAP_READWRITE)
h->flags |= CAN_READWRITE;
if (h->cap.capabilities && V4L2_CAP_STREAMING)
h->flags |= CAN_STREAM;
if (h->cap.capabilities && V4L2_CAP_VIDEO_OVERLAY)
h->flags |= CAN_OVERLAY;
if (h->capture)
h->app_fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (h->player)
h->app_fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
enum_fmts(h);
v4l2_setformat(h);
return h;
err:
if (h->fd != -1)
close(h->fd);
if (h)
free(h);
return NULL;
}
static void
v4l_reqbufs(struct v4l2_handle *h, int bcount)
{
CLEAR(h->req);
h->req.count= bcount;
h->req.type = h->fmt.type;
h->req.memory = h->app_fmt->memory;
if(-1 == xioctl(h->fd,VIDIOC_REQBUFS,&h->req)){
if(EINVAL == errno){
fprintf(stderr,"%s does not allow to request buffers\n",h->device);
exit(-1);
}else{
errno_exit("VIDIOC_REQBUFS");
}
}
if(h->req.count < 2){
fprintf(stderr,"Insufficient buffer memory on %s\n",h->device);
exit(-1);
}
printf("Driver provided buffers are %d\n", h->req.count);
}
int vcapture_init_userp(struct v4l2_handle *h, unsigned int buffer_size)
{
struct v4l2_requestbuffers req;
h->app_fmt->memory = V4L2_MEMORY_USERPTR;
v4l_reqbufs(h, bcount);
for(n_buffers = 0; n_buffers < h->req.count; ++n_buffers){
struct v4l2_buffer buf;
#ifdef ALIGN
buffer_size = buffer_size + 0x20;
#endif
if(buffer_size & 0xfff)
buffer_size = (buffer_size & 0xffffe000) + 4096;
h->buf_me[n_buffers].size = buffer_size;
h->buf_me[n_buffers].data = malloc(buffer_size);
printf("User Buffers[%d].start = %x length = %d\n",
n_buffers,h->buf_me[n_buffers].data,
h->buf_me[n_buffers].size);
if(!h->buf_me[n_buffers].data){
fprintf(stderr,"Out of memory\n");
exit(-1);
}
h->buf_v4l2[n_buffers].type = h->req.type;
h->buf_v4l2[n_buffers].memory = V4L2_MEMORY_USERPTR;
h->buf_v4l2[n_buffers].index = n_buffers;
#ifdef ALIGN
h->buf_v4l2[n_buffers].m.userptr = ((unsigned
int)h->buf_me[n_buffers].data &
0xffffffe0) + 0x20;
#else
h->buf_v4l2[n_buffers].m.userptr = (unsigned
int)h->buf_me[n_buffers].data;
#endif
if (xioctl(h->fd, VIDIOC_QUERYBUF, &h->buf_v4l2[n_buffers]) == -1) {
errno_exit("VIDIOC_QUERYBUF");
}
}
return 0;
}
int vcapture_init_mmap(struct v4l2_handle *h, int bcount)
{
int i;
h->app_fmt->memory = V4L2_MEMORY_MMAP;
v4l_reqbufs(h, bcount);
for(n_buffers = 0; n_buffers < h->req.count; ++n_buffers)
{
h->buf_v4l2[n_buffers].type = h->fmt.type;
h->buf_v4l2[n_buffers].memory= V4L2_MEMORY_MMAP;
h->buf_v4l2[n_buffers].index = n_buffers;
if(-1 == xioctl(h->fd, VIDIOC_QUERYBUF,
&h->buf_v4l2[n_buffers])){
printf("error is %d\n", strerror(errno));
errno_exit("QUERYBUF");
}
h->buf_me[n_buffers].size = h->buf_v4l2[n_buffers].length;
h->buf_me[n_buffers].data = mmap(NULL,
h->buf_me[n_buffers].size,/* + 64,*/
PROT_READ|PROT_WRITE,
MAP_SHARED,
h->fd,
h->buf_v4l2[n_buffers].m.offset);
if(h->buf_me[n_buffers].data == MAP_FAILED)
errno_exit("MMAP");
}
return 0;
}
int vcapture_init_read(struct v4l2_handle *h, unsigned int buffer_size)
{
h->buf_me[0].data = malloc(buffer_size);
h->buf_me[0].size = buffer_size;
if(!h->buf_me[0].data)
{
fprintf(stderr, "Error allocation memory: malloc\n");
return -1;
}
return 0;
}
int vcapture_set_streamparm(struct v4l2_handle *h, int fps)
{
memset(&h->streamparm, 0, sizeof(h->streamparm));
h->streamparm.type = h->app_fmt->type;
h->streamparm.parm.capture.capturemode = 0;
h->streamparm.parm.capture.timeperframe.numerator = 1;
h->streamparm.parm.capture.timeperframe.denominator = fps;
if(xioctl(h->fd, VIDIOC_S_PARM, &h->streamparm) == -1){
fprintf(stderr, "Unable to set %d fps: \n", fps,
strerror(errno));
return -1;
}
return 0;
}
static int read_frame(struct v4l2_handle *h)
{
struct v4l2_buffer buf;
unsigned int i;
switch (io) {
case IO_METHOD_READ:
if (-1 == read(h->fd, h->buf_me[0].data,
h->buf_me[0].size)) {
switch (errno) {
case EAGAIN:
return 0;
case EIO:
assert(0);
/* Could ignore EIO, see spec. */
/* fall through */
default:
errno_exit("read_frame");
}
}
if(capture) { /*this can slow down a bit over NFS*/
fwrite(h->buf_me[0].data, 1,h->buf_me[0].size, outfd);
}
break;
case IO_METHOD_MMAP:
CLEAR(buf);
buf.type = h->fmt.type;
buf.memory = V4L2_MEMORY_MMAP;
if(-1 == xioctl(h->fd,VIDIOC_DQBUF,&buf)){
switch(errno){
case EAGAIN:
return 0;
case EIO:
/*Could ignore EIO,see spec.*/
/*fall through*/
default:
errno_exit("VIDIOC_DQBUF");
}
}
assert(buf.index < n_buffers);
h->buf_v4l2[buf.index] = buf;
if(capture) {
fwrite(h->buf_me[buf.index].data, 1,
h->buf_me[buf.index].size, outfd);
}
if(-1==xioctl(h->fd,VIDIOC_QBUF,&buf))
errno_exit("VIDIOC_QBUF");
break;
case IO_METHOD_USERPTR:
{
char *src_buf;
CLEAR(buf);
buf.type = h->fmt.type;
buf.memory = V4L2_MEMORY_USERPTR;
if(-1 == xioctl(h->fd,VIDIOC_DQBUF,&buf)){
switch(errno){
case EAGAIN:
return 0;
case EIO:
/*Could ignore EIO,see spec.*/
/*fall through*/
default:
errno_exit("VIDIOC_DQBUF");
}
}
h->buf_v4l2[buf.index] = buf;
#ifdef ALIGN
src_buf = (char*)(((unsigned
int)h->buf_me[buf.index].data &
0xffffffe0) + 0x20);
#endif
if(-1 == xioctl(h->fd,VIDIOC_QBUF,&buf))
errno_exit("VIDIOC_QBUF");
}
break;
}
return 1;
}
static void
start_capturing(struct v4l2_handle *h)
{
unsigned int i;
enum v4l2_buf_type type;
struct v4l2_buffer buf;
switch(io){
case IO_METHOD_READ:
/*Nothing to do.*/
break;
case IO_METHOD_MMAP:
case IO_METHOD_USERPTR:
for( i = 0; i < n_buffers; ++i){
print_bufinfo(&h->buf_v4l2[i]);
if(-1 == xioctl(h->fd,VIDIOC_QBUF,&h->buf_v4l2[i]))
errno_exit("VIDIOC_QBUF");
}
type = h->fmt.type;
if(-1 == xioctl(h->fd,VIDIOC_STREAMON,&type))
errno_exit("VIDIOC_STREAMON");
break;
}
}
static void
stop_capturing(struct v4l2_handle *h)
{
enum v4l2_buf_type type;
switch(io){
case IO_METHOD_READ:
/*Nothing to do.*/
break;
case IO_METHOD_MMAP:
case IO_METHOD_USERPTR:
type = h->fmt.type;
if(-1 == xioctl(h->fd, VIDIOC_STREAMOFF, &type))
errno_exit("VIDIOC_STREAMOFF");
break;
}
}
/* do capture */
int mainloop(struct v4l2_handle *h)
{
int i, type;
unsigned int count;
fd_set rdfds;
struct timeval tv;
int ret;
count = nframes;
printf("capture\n");
while (count-- > 0) {
for (;;) {
FD_ZERO (&rdfds);
FD_SET (h->fd, &rdfds);
/* Timeout. */
tv.tv_sec = 1;
tv.tv_usec = 0;
ret = select (h->fd + 1, &rdfds, NULL, NULL, &tv);
if (ret < 0) {
if (EINTR == errno)
{
fprintf(stderr, "EINTR\n");
continue;
}
errno_exit ("select");
}
if (ret == 0) {
fprintf (stderr, "select timeout\n");
exit(0);
}
fflush(0);
printf(".");
if (read_frame(h))
break;
/* EAGAIN - continue select loop. */
}
}
printf("\n");
return 0;
}
static void
uninit_device(struct v4l2_handle *h)
{
unsigned int i;
switch(io){
case IO_METHOD_READ:
free(h->buf_me[0].data);
break;
case IO_METHOD_MMAP:
for(i = 0;i < n_buffers; ++i){
if(-1 == munmap(h->buf_me[i].data,h->buf_me[i].size))
errno_exit("munmap");
}
break;
case IO_METHOD_USERPTR:
for(i = 0;i < n_buffers; ++i)
free(h->buf_me[i].data);
break;
}
free(h->buf_me);
}
static int
start_overlay(struct v4l2_handle *h)
{
int e = 1;
if(-1 == xioctl(h->fd, VIDIOC_OVERLAY, &e))
{
errno_exit("VIDIOC_OVERLAY");
}
return 0;
}
static void
init_buffers(struct v4l2_handle *h)
{
switch (io) {
case IO_METHOD_MMAP:
init_mmap(h, bcount);
break;
case IO_METHOD_USERPTR:
init_userp(h, h->fmt.fmt.pix.sizeimage);
break;
case IO_METHOD_READ:
init_read(h, h->fmt.fmt.pix.sizeimage);
break;
}
}
static int vid_capture(void *handle, char *filename)
{
struct v4l2_handle *h = handle;
init_buffers(h);
outfd = fopen(filename, "w+");
if (outfd == NULL) {
fprintf(stderr, "Unable to open %s file\n", filename);
return -1;
}
start_capturing(h);
mainloop(h);
stop_capturing(h);
}
/* main */
/* usage: -d <device> -w <width> -h <height> -n <no.of frames>
* -o <output dump to file>
*/
static void usage(char *command){
printf(
" Usage: %s [OPTION]... \n"
"\n"
"-h, --help help\n"
"-d, --device video device(default:/dev/v4l/video0)\n"
"-w, --width width (default: 320 pixels)\n"
"-H, --height height (default: 240 pixels)\n"
"-n, --frames no. of frames (default: 10)\n"
"-m, --mmap mmmap(default: read)\n"
"-r, --read read(default: read)\n"
"-u, --userp userp(default: read)\n"
"-b, --bcount buffer count(default: 2)\n"
"-p, --preview preview on(default: off)\n",
command
);
}
static void signal_handler(int sig)
{
fprintf(stderr, "\nAborted by signal %s...\n", strsignal(sig));
if(vcapture) {
if (outfd > 1)
close(outfd);
outfd = -1;
}
exit(-1);
}
int main(int argc, char *argv[])
{
struct v4l2_handle *hcapture;
struct v4l2_handle *hpreview;
char *short_options="hd:w:H:n:o:v:b:f:mrupC";
char *prev_device = "/dev/v4l/video1";
static struct option long_options[] = {
{"help", 0, 0, 'h'},
{"device",1, 0, 'd'},
{"width", 1, 0, 'w'},
{"height", 1, 0, 'H'},
{"frames", 1, 0, 'n'},
{"file", 1, 0, 'o'},
{"mmap", 0, 0, 'm'},
{"read", 0, 0, 'r'},
{"userptr", 0, 0, 'u'},
{"bcount", 1, 0, 'b'},
{"preview", 0, 0, 'p'},
{"fps", 1, 0, 'f'},
{"capture", 0, 0, 'C'},
{0, 0, 0, 0}
};
int option_index;
int fd, err, c;
command = argv[0];
if (strstr(argv[0], "vplay")){
vplayer = 1;
command = "vplay";
}else if (strstr(argv[0], "vcapture")){
vcapture = 1;
command = "vcapture";
}else {
fprintf(stderr, "command should be named either vcapture or vplay\n");
return 1;
}
while ((c = getopt_long(argc, argv, short_options, long_options,
&option_index)) != -1) {
switch(c){
case 'h':
usage(command);
return 0;
case 'd':
device = optarg;
break;
case 'w':
width = atoi(optarg);
break;
case 'H':
height = atoi(optarg);
break;
case 'n':
nframes = atoi(optarg);
break;
case 'N':
open_mode |= O_NONBLOCK;
break;
case 'm':
io = IO_METHOD_MMAP;
printf("Info: MMAP method selected\n");
break;
case 'r':
io = IO_METHOD_READ;
printf("Info: READ method selected\n");
break;
case 'u':
io = IO_METHOD_USERPTR;
printf("Info: USER Pointer method selected\n");
break;
case 'b':
bcount = atoi(optarg);
break;
case 'p':
preview = 1;
break;
case 'f':
fps = atoi(optarg);
break;
case 'C':
capture = 1;
break;
default:
fprintf(stderr, "Try %s --help for more infromation\n",
command);
return 1;
}
}
if(vcapture){
init_mmap = vcapture_init_mmap;
init_userp = vcapture_init_userp;
init_read = vcapture_init_read;
init_device = vcapture_init_device;
if (!nframes)
nframes = DEFAULT_NFRAMES;
}
/*
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
signal(SIGABRT, signal_handler);
*/
hcapture = init_device(device);
//hpreview = init_device(prev_device);
if ( hcapture == NULL)
fprintf(stderr, "Unable to initialize %s video device\n", device);
/*if ( hpreview == NULL)
fprintf(stderr, "Unable to initialize %s video device\n", prev_device);
*/
if(fps)
vcapture_set_streamparm(hcapture, fps);
/*start preview*/
if(preview)
start_overlay(hcapture);
if(capture){
vid_capture(hcapture, argv[optind]);
/* init preview buffers
* NOTE: same io method will be used
* for video out as video capture
*/
//init_buffers(hpreview, bcount);
}
/*preview only*/
if(preview && (!capture))/*spin continously, until user aborts*/
while(1);
uninit_device(hcapture);
//uninit_device(hpreview);
if (capture)
fclose(outfd);
v4l2_close(hcapture);
//v4l2_close(hpreview);
return 0;
}
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: v4l2 camera test app
2006-03-16 10:25 v4l2 camera test app Komal Shah
@ 2006-03-20 13:19 ` Ola Helm
2006-03-20 14:58 ` omap24xxcam status (Was: v4l2 camera test app) Komal Shah
2006-03-20 15:45 ` [PATCH] Re: v4l2 camera test app David Cohen
0 siblings, 2 replies; 8+ messages in thread
From: Ola Helm @ 2006-03-20 13:19 UTC (permalink / raw)
To: Komal Shah, Linux-omap-open-source
Hi,
Have you got some idea what's the situation of the 24xx camera driver at the
moment? AFAIK the patch David sent in last month is not included to tree,
propably since there were some opposite opinions about the way of
implementation and at least I did not have one file mentioned in patch (I
think you mentioned about the same issue)
/O
On 3/16/06, Komal Shah <komal_shah802003@yahoo.com> wrote:
>
> Hi All,
>
> As I had received 2-3 emails in the past for simple v4l2 camera capture
> test application for OMAP, I have attached the one which I have tested
> with OMAP2420 TI EVM.
>
> To compile
> #arm-linux-gcc -o vcaputre vcam.c
>
> To execute
> #./vcaputre -n 20 -m -C cam.dump
>
> Enjoy and fix the bugs you find yourself or send me the patch. There
> are quite lot of improvments one can do to this app :)
>
> ---Komal Shah
> http://komalshah.blogspot.com/
>
> __________________________________________________
> Do You Yahoo!?
> Tired of spam? Yahoo! Mail has the best spam protection around
> http://mail.yahoo.com
>
> _______________________________________________
> Linux-omap-open-source mailing list
> Linux-omap-open-source@linux.omap.com
> http://linux.omap.com/mailman/listinfo/linux-omap-open-source
>
>
>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: omap24xxcam status (Was: v4l2 camera test app)
2006-03-20 13:19 ` Ola Helm
@ 2006-03-20 14:58 ` Komal Shah
2006-03-20 16:10 ` David Cohen
2006-03-20 15:45 ` [PATCH] Re: v4l2 camera test app David Cohen
1 sibling, 1 reply; 8+ messages in thread
From: Komal Shah @ 2006-03-20 14:58 UTC (permalink / raw)
To: Ola Helm, Linux-omap-open-source
--- Ola Helm <ola.hel@gmail.com> wrote:
> Hi,
>
> Have you got some idea what's the situation of the 24xx camera driver
> at the
> moment? AFAIK the patch David sent in last month is not included to
> tree,
> propably since there were some opposite opinions about the way of
> implementation and at least I did not have one file mentioned in
> patch (I
> think you mentioned about the same issue)
24xx camera driver is now in David's hand. I just review the code now,
as not able to work on camera stuff anymore.
Following strategy can work out meanwhile as I had offline discussion
with David :)
o Separate 24xx CamDMA code from omap24xxcam.c to new file as
exported apis (Suggested by David)
o Keep the old omap24xxcam driver interface(2.6.8 TI kernel days),
having video out code part of the camera driver itself. As new
separated video out code depends upon the common display controller
library, which requires to change fb driver in git tree to adopt
that interface, so that video out, and fb driver can
utilize the same code. But video out patches submitted by me didn't
generated any discussion on the list in that direction.
o So, to have 24xx camera code in git tree, we can use the old camera
driver interface as of now, if everyone agrees.
---Komal Shah
http://komalshah.blogspot.com/
__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH] Re: v4l2 camera test app
2006-03-20 13:19 ` Ola Helm
2006-03-20 14:58 ` omap24xxcam status (Was: v4l2 camera test app) Komal Shah
@ 2006-03-20 15:45 ` David Cohen
2006-03-20 20:16 ` Komal Shah
1 sibling, 1 reply; 8+ messages in thread
From: David Cohen @ 2006-03-20 15:45 UTC (permalink / raw)
To: ext Ola Helm; +Cc: Linux-omap-open-source
[-- Attachment #1: Type: text/plain, Size: 1862 bytes --]
Hi,
I am sending a new version of the camera driver for omap2420. Unlike the
last patch I sent, I am not using those functions from dispc and vout
that were not applied yet.
The sensor module should be configured to BT8. The configurations for
NOBT are in the code, but commented on omap24xxcam_sensor_cc_ctrl
function. It can be changed if necessary.
Regards,
David Cohen
ext Ola Helm wrote:
>Hi,
>
>Have you got some idea what's the situation of the 24xx camera driver at the
>moment? AFAIK the patch David sent in last month is not included to tree,
>propably since there were some opposite opinions about the way of
>implementation and at least I did not have one file mentioned in patch (I
>think you mentioned about the same issue)
>
>/O
>
>On 3/16/06, Komal Shah <komal_shah802003@yahoo.com> wrote:
>
>
>>Hi All,
>>
>>As I had received 2-3 emails in the past for simple v4l2 camera capture
>>test application for OMAP, I have attached the one which I have tested
>>with OMAP2420 TI EVM.
>>
>>To compile
>>#arm-linux-gcc -o vcaputre vcam.c
>>
>>To execute
>>#./vcaputre -n 20 -m -C cam.dump
>>
>>Enjoy and fix the bugs you find yourself or send me the patch. There
>>are quite lot of improvments one can do to this app :)
>>
>>---Komal Shah
>>http://komalshah.blogspot.com/
>>
>>__________________________________________________
>>Do You Yahoo!?
>>Tired of spam? Yahoo! Mail has the best spam protection around
>>http://mail.yahoo.com
>>
>>_______________________________________________
>>Linux-omap-open-source mailing list
>>Linux-omap-open-source@linux.omap.com
>>http://linux.omap.com/mailman/listinfo/linux-omap-open-source
>>
>>
>>
>>
>>
>>
>_______________________________________________
>Linux-omap-open-source mailing list
>Linux-omap-open-source@linux.omap.com
>http://linux.omap.com/mailman/listinfo/linux-omap-open-source
>
>
[-- Attachment #2: diff_omap24xxcam.patch --]
[-- Type: text/plain, Size: 128753 bytes --]
diff --git a/drivers/media/video/omap/Makefile b/drivers/media/video/omap/Makefile
index c4c5a81..3027af6 100644
--- a/drivers/media/video/omap/Makefile
+++ b/drivers/media/video/omap/Makefile
@@ -3,9 +3,8 @@
obj-$(CONFIG_VIDEO_OMAP_CAMERA) += omapcamera.o
obj-$(CONFIG_VIDEO_CAMERA_SENSOR_OV9640) += sensor_ov9640.o
-objs-yy := camera_core.o
-
-objs-y$(CONFIG_ARCH_OMAP16XX) += omap16xxcam.o
+objs-y$(CONFIG_ARCH_OMAP16XX) += camera_core.o omap16xxcam.o
+objs-y$(CONFIG_ARCH_OMAP24XX) += omap24xxcam.o
objs-y$(CONFIG_MACH_OMAP_H3) += h3_sensor_power.o
omapcamera-objs := $(objs-yy)
diff --git a/drivers/media/video/omap/omap24xxcam.c b/drivers/media/video/omap/omap24xxcam.c
new file mode 100644
index 0000000..aa60431
--- /dev/null
+++ b/drivers/media/video/omap/omap24xxcam.c
@@ -0,0 +1,3306 @@
+/*
+ * drivers/media/video/omap/omap24xxcam.c
+ *
+ * Video-for-Linux (Version 2) camera capture driver for
+ * the OMAP24xx camera controller.
+ *
+ * Author: Andy Lowe (source@mvista.com)
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * History:
+ * 2006/mar - David Cohen <david.cohen@indt.org.br>
+ * * Updated the driver for the Linux Device Model
+ * * Updated some obsolete functions of V4L2
+ * * Some others small fixes
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/pci.h> /* needed for videobufs */
+#include <media/video-buf.h>
+#include <linux/dma-mapping.h>
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/version.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <asm/scatterlist.h>
+#include <asm/irq.h>
+#include <asm/semaphore.h>
+#include <asm/processor.h>
+#include <asm/arch/clock.h>
+
+#include "omap24xxcam.h"
+
+#define CAMERA_OV9640
+#ifdef CAMERA_OV9640
+#include "ov9640.h"
+#endif
+#include "sensor_if.h"
+
+/* configuration macros */
+#define CAM_NAME "omap24xxcam"
+
+/* Should be moved from here */
+#define INT_CAM_MPU_IRQ 24
+
+//#define DEBUG_CAM
+
+#ifdef DEBUG_CAM
+#define DBG printk(KERN_INFO CAM_NAME ": %s\n", __FUNCTION__)
+#define DBG_END printk(KERN_INFO CAM_NAME ": %s END!\n", __FUNCTION__)
+#define DBG_MID(x) printk(KERN_INFO CAM_NAME ": %s - %d\n", __FUNCTION__, x)
+#else
+#define DBG
+#define DBG_END
+#define DBG_MID(x)
+#endif
+
+extern struct camera_sensor camera_sensor_if;
+
+void omap24xxcam_cleanup(void);
+
+/* global variables */
+static struct omap24xxcam_device *saved_cam;
+
+/* module parameters */
+static int video_nr = -1; /* video device minor (-1 ==> auto assign) */
+/* Maximum amount of memory to use for capture buffers.
+ * Default is 4800KB, enough to double-buffer SXGA.
+ */
+static int capture_mem = 1280 * 960 * 2 * 2;
+/* Size of video overlay framebuffer. This determines the maximum image size
+ * that can be previewed. Default is 600KB, enough for VGA.
+ */
+static int overlay_mem = 640 * 480 * 2;
+/* Size of video2_mem framebuffer. This determines the maximum image size which
+ * video2_layer can support. Default is 300 KB. Size of LCD or 320*240.
+*/
+static int video2_mem = 320 * 240 * 2;
+
+static struct clk *cam_fck;
+static struct clk *cam_ick;
+
+/* -------------------------------------------------------------------------- */
+
+/* Set the value of the CC_CTRL register in cam->cc_ctrl that is required to
+ * support the currently selected capture format in cam->pix. The CC_CTRL bits
+ * which must be configured are: NOBT_SYNCHRO, BT_CORRECT, PAR_ORDERCAM,
+ * PAR_CLK_POL, NOBT_HS_POL, NOBT_VS_POL, PAR_MODE, and CCP_MODE. The CC_RST,
+ * CC_FRAME_TRIG, and CC_EN bits are actively managed by the driver and should
+ * be set to zero by this routine.
+ */
+static void omap24xxcam_sensor_cc_ctrl(struct omap24xxcam_device *cam)
+{
+ struct v4l2_pix_format *pix = &cam->pix;
+
+ DBG;
+
+ cam->cc_ctrl = /*CC_CTRL_NOBT_SYNCHRO | CC_CTRL_NOBT_VS_POL */
+ CC_CTRL_BT_CORRECT | CC_CTRL_PAR_MODE_BT8;
+
+ switch (pix->pixelformat) {
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_RGB555:
+ default:
+ /* These formats need a 16-bit byte swap */
+ //cam->cc_ctrl |= CC_CTRL_PAR_ORDERCAM;
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_RGB565X:
+ case V4L2_PIX_FMT_RGB555X:
+ /* These formats don't need a 16-bit byte swap */
+ break;
+ }
+}
+
+/*
+ * camera core register I/O routines
+ */
+
+static __inline__ u32
+cc_reg_in(const struct omap24xxcam_device *cam, u32 offset)
+{
+ return readl(cam->cam_mmio_base + CC_REG_OFFSET + offset);
+}
+
+static __inline__ u32
+cc_reg_out(const struct omap24xxcam_device *cam, u32 offset, u32 val)
+{
+ writel(val, cam->cam_mmio_base + CC_REG_OFFSET + offset);
+ return val;
+}
+
+static __inline__ u32
+cc_reg_merge(const struct omap24xxcam_device *cam, u32 offset,
+ u32 val, u32 mask)
+{
+ u32 addr = cam->cam_mmio_base + CC_REG_OFFSET + offset;
+ u32 new_val = (readl(addr) & ~mask) | (val & mask);
+
+ writel(new_val, addr);
+ return new_val;
+}
+
+void cc_init(const struct omap24xxcam_device *cam)
+{
+ DBG;
+ /* Setting the camera core AUTOIDLE bit causes problems with frame
+ * synchronization, so we will clear the AUTOIDLE bit instead.
+ */
+ //cc_reg_out(cam, CC_SYSCONFIG, 0);
+ cc_reg_out(cam, CC_SYSCONFIG, CC_SYSCONFIG_AUTOIDLE);
+}
+
+/*
+ * camera MMU register I/O routines
+ */
+
+static __inline__ u32
+cammmu_reg_in(const struct omap24xxcam_device *cam, u32 offset)
+{
+ return readl(cam->cam_mmio_base + CAMMMU_REG_OFFSET + offset);
+}
+
+static __inline__ u32
+cammmu_reg_out(const struct omap24xxcam_device *cam, u32 offset, u32 val)
+{
+ writel(val, cam->cam_mmio_base + CAMMMU_REG_OFFSET + offset);
+ return val;
+}
+
+static __inline__ u32
+cammmu_reg_merge(const struct omap24xxcam_device *cam, u32 offset,
+ u32 val, u32 mask)
+{
+ u32 addr = cam->cam_mmio_base + CAMMMU_REG_OFFSET + offset;
+ u32 new_val = (readl(addr) & ~mask) | (val & mask);
+
+ writel(new_val, addr);
+ return new_val;
+}
+
+void cammmu_init(const struct omap24xxcam_device *cam)
+{
+ DBG;
+ /* set the camera MMU autoidle bit */
+ cammmu_reg_out(cam, CAMMMU_SYSCONFIG, CAMMMU_SYSCONFIG_AUTOIDLE);
+}
+
+/*
+ * camera DMA register I/O routines
+ */
+
+__inline__ u32
+camdma_reg_in(const struct omap24xxcam_device *cam, u32 offset)
+{
+ return readl(cam->cam_mmio_base + CAMDMA_REG_OFFSET + offset);
+}
+
+__inline__ u32
+camdma_reg_out(const struct omap24xxcam_device *cam, u32 offset, u32 val)
+{
+ writel(val, cam->cam_mmio_base + CAMDMA_REG_OFFSET + offset);
+ return val;
+}
+
+__inline__ u32
+camdma_reg_merge(const struct omap24xxcam_device *cam, u32 offset,
+ u32 val, u32 mask)
+{
+ u32 addr = cam->cam_mmio_base + CAMDMA_REG_OFFSET + offset;
+ u32 new_val = (readl(addr) & ~mask) | (val & mask);
+
+ writel(new_val, addr);
+ return new_val;
+}
+
+void
+camdma_init(const struct omap24xxcam_device *cam)
+{
+ DBG;
+ camdma_reg_out(cam, CAMDMA_OCP_SYSCONFIG,
+ CAMDMA_OCP_SYSCONFIG_MIDLEMODE_NSTANDBY
+ | CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE
+ | CAMDMA_OCP_SYSCONFIG_AUTOIDLE);
+
+ camdma_reg_merge(cam, CAMDMA_GCR, 0x10,
+ CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH);
+}
+
+/*
+ * camera subsystem register I/O routines
+ */
+
+static __inline__ u32
+cam_reg_in(const struct omap24xxcam_device *cam, u32 offset)
+{
+ return readl(cam->cam_mmio_base + offset);
+}
+
+static __inline__ u32
+cam_reg_out(const struct omap24xxcam_device *cam, u32 offset, u32 val)
+{
+ writel(val, cam->cam_mmio_base + offset);
+ return val;
+}
+
+static __inline__ u32
+cam_reg_merge(const struct omap24xxcam_device *cam, u32 offset,
+ u32 val, u32 mask)
+{
+ u32 addr = cam->cam_mmio_base + offset;
+ u32 new_val = (readl(addr) & ~mask) | (val & mask);
+
+ writel(new_val, addr);
+ return new_val;
+}
+
+/* Reset the camera subsystem (camera core, camera DMA, and camera MMU) */
+static void
+cam_reset(const struct omap24xxcam_device *cam, unsigned long timeout_ticks)
+{
+ unsigned long timeout;
+
+ DBG;
+
+ cam_reg_out(cam, CAM_SYSCONFIG, CAM_SYSCONFIG_SOFTRESET);
+ /* wait for reset to complete */
+ timeout = jiffies + timeout_ticks;
+ while (!(cam_reg_in(cam, CAM_SYSSTATUS) & CAM_SYSSTATUS_RESETDONE)
+ && time_before(jiffies, timeout)) {
+ if (!in_atomic()) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1);
+ } else
+ udelay(10);
+ }
+ if (!(cam_reg_in(cam, CAM_SYSSTATUS) & CAM_SYSSTATUS_RESETDONE)) {
+ printk(KERN_WARNING CAM_NAME
+ ": timeout waiting for camera subsystem reset\n");
+ }
+
+ return;
+}
+
+/* Initialize the camera subsystem (camera core, camera DMA, and camera MMU) */
+void cam_init(const struct omap24xxcam_device *cam)
+{
+ DBG;
+ /* reset the camera subsystem with a timeout of 200ms */
+ cam_reset(cam, HZ / 5);
+
+ /* set the camera subsystem autoidle bit */
+ cam_reg_out(cam, CAM_SYSCONFIG, CAM_SYSCONFIG_AUTOIDLE);
+
+ /* initialize the camera MMU */
+ cammmu_init(cam);
+
+ /* initialize the camera DMA controller */
+ camdma_init(cam);
+
+ /* initialize the camera core module */
+ cc_init(cam);
+}
+
+/*
+ * display controller register I/O routines
+ */
+
+static __inline__ u32
+dispc_reg_in(const struct omap24xxcam_device *cam, u32 offset)
+{
+ return readl(cam->dispc_mmio_base + DISPC_REG_OFFSET + offset);
+}
+
+static __inline__ u32
+dispc_reg_out(const struct omap24xxcam_device *cam, u32 offset, u32 val)
+{
+ writel(val, cam->dispc_mmio_base + DISPC_REG_OFFSET + offset);
+ return val;
+}
+
+static __inline__ u32
+dispc_reg_merge(const struct omap24xxcam_device *cam, u32 offset,
+ u32 val, u32 mask)
+{
+ u32 addr = cam->dispc_mmio_base + DISPC_REG_OFFSET + offset;
+ u32 new_val = (readl(addr) & ~mask) | (val & mask);
+
+ writel(new_val, addr);
+ return new_val;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* Turn off the video overlay window. */
+static void omap24xxcam_disable_vlayer(struct omap24xxcam_device *cam, int v)
+{
+ unsigned long vid_attributes;
+
+ DBG;
+
+ vid_attributes = dispc_reg_merge(cam, DISPC_VID_ATTRIBUTES(v), 0,
+ DISPC_VID_ATTRIBUTES_ENABLE);
+ if (vid_attributes & DISPC_VID_ATTRIBUTES_VIDCHANNELOUT) {
+ /* digital output */
+ dispc_reg_merge(cam, DISPC_CONTROL, DISPC_CONTROL_GODIGITAL,
+ DISPC_CONTROL_GODIGITAL);
+ } else {
+ /* LCD */
+ dispc_reg_merge(cam, DISPC_CONTROL, DISPC_CONTROL_GOLCD,
+ DISPC_CONTROL_GOLCD);
+ }
+}
+
+/* Flip the video overlay framebuffer. The video overlay window may initially
+ * be either enabled or disabled. The overlay window will be enabled by this
+ * routine. fb_base_phys is the physical base address of the framebuffer for
+ * the video overlay. The address programmed into the base address register of
+ * the video overlay window is calculated based on the cropped size and the full
+ * size of the overlay framebuffer.
+ */
+static void
+omap24xxcam_flip_overlay(struct omap24xxcam_device *cam,
+ unsigned long fb_base_phys)
+{
+ unsigned long vid_attributes;
+ int v = cam->vid1;
+ unsigned long cropped_base_phys;
+ struct v4l2_rect *crop = &cam->crop;
+ struct v4l2_pix_format *pix = &cam->pix;
+
+ DBG;
+
+ cropped_base_phys = fb_base_phys
+ + pix->bytesperline * crop->top + crop->left * 2;
+ dispc_reg_out(cam, DISPC_VID_BA0(v), cropped_base_phys);
+ dispc_reg_out(cam, DISPC_VID_BA1(v), cropped_base_phys);
+
+ vid_attributes = dispc_reg_merge(cam, DISPC_VID_ATTRIBUTES(v),
+ DISPC_VID_ATTRIBUTES_ENABLE,
+ DISPC_VID_ATTRIBUTES_ENABLE);
+ if (vid_attributes & DISPC_VID_ATTRIBUTES_VIDCHANNELOUT) {
+ /* digital output */
+ dispc_reg_merge(cam, DISPC_CONTROL, DISPC_CONTROL_GODIGITAL,
+ DISPC_CONTROL_GODIGITAL);
+ } else {
+ /* LCD */
+ dispc_reg_merge(cam, DISPC_CONTROL, DISPC_CONTROL_GOLCD,
+ DISPC_CONTROL_GOLCD);
+ }
+}
+
+/* Get the framebuffer parameters by reading the display controller registers
+ * for the graphics window.
+ */
+static void omap24xxcam_g_fbuf(struct omap24xxcam_device *cam)
+{
+ struct v4l2_framebuffer *fbuf = &cam->fbuf;
+ unsigned long gfx_size, gfx_position;
+
+ DBG;
+
+ /* This routine makes some assumptions about the framebuffer driver.
+ * First, the entire contents of the graphics framebuffer must be
+ * displayed, i.e. a configuration in which part of the graphics
+ * framebuffer is offscreen is not supported. The graphics
+ * window must not be resized or repositioned while capture preview is
+ * active. The rotation capabilities of the display controller must
+ * not be used to rotate the graphics window.
+ */
+ fbuf->capability = V4L2_FBUF_CAP_EXTERNOVERLAY
+ | V4L2_FBUF_CAP_CHROMAKEY;
+ gfx_size = dispc_reg_in(cam, DISPC_GFX_SIZE);
+ fbuf->fmt.width = 1 + ((gfx_size & DISPC_GFX_SIZE_GFXSIZEX)
+ >> DISPC_GFX_SIZE_GFXSIZEX_SHIFT);
+ fbuf->fmt.height = 1 + ((gfx_size & DISPC_GFX_SIZE_GFXSIZEY)
+ >> DISPC_GFX_SIZE_GFXSIZEY_SHIFT);
+ gfx_position = dispc_reg_in(cam, DISPC_GFX_POSITION);
+ cam->gfx_position_x = (gfx_position & DISPC_GFX_POSITION_GFXPOSX)
+ >> DISPC_GFX_POSITION_GFXPOSX_SHIFT;
+ cam->gfx_position_y = (gfx_position & DISPC_GFX_POSITION_GFXPOSY)
+ >> DISPC_GFX_POSITION_GFXPOSY_SHIFT;
+ cam->gfx_attributes = dispc_reg_in(cam, DISPC_GFX_ATTRIBUTES);
+}
+
+/* Return the default overlay cropping rectangle in crop given the image capture
+ * size in cam->pix and the video display size in cam->fbuf. The default
+ * cropping rectangle is the largest rectangle no larger than the capture size
+ * that will fit on the display. The default cropping rectangle is centered in
+ * the captured image. All dimensions and offsets are rounded down to even
+ * numbers.
+ */
+static void
+omap24xxcam_default_crop_rect(struct omap24xxcam_device *cam,
+ struct v4l2_rect *crop)
+{
+ struct v4l2_pix_format *pix = &cam->pix;
+ struct v4l2_framebuffer *fbuf = &cam->fbuf;
+
+ DBG;
+
+ crop->width = (pix->width < fbuf->fmt.width) ?
+ pix->width : fbuf->fmt.width;
+ crop->height = (pix->height < fbuf->fmt.height) ?
+ pix->height : fbuf->fmt.height;
+ crop->width &= ~1;
+ crop->height &= ~1;
+ crop->left = ((pix->width - crop->width) >> 1) & ~1;
+ crop->top = ((pix->height - crop->height) >> 1) & ~1;
+}
+
+/* Given a new cropping rectangle in new_crop, adjust the cropping rectangle to
+ * the nearest supported configuration. The image preview window cam->win will
+ * also be adjusted if necessary. The preview window is adjusted such that the
+ * horizontal and vertical rescaling ratios stay constant. If the preview
+ * window would fall outside the display boundaries, the cropping rectangle will
+ * also be adjusted to maintain the rescaling ratios. If successful, cam->crop
+ * and cam->win are updated.
+ * Returns zero if succesful, or -EINVAL if the requested cropping rectangle is
+ * impossible and cannot reasonably be adjusted.
+ */
+static int
+omap24xxcam_new_crop_rect(struct omap24xxcam_device *cam,
+ const struct v4l2_rect *new_crop)
+{
+ struct v4l2_pix_format *pix = &cam->pix;
+ struct v4l2_window *win = &cam->win;
+ struct v4l2_framebuffer *fbuf = &cam->fbuf;
+ struct v4l2_rect *crop = &cam->crop;
+ struct v4l2_rect try_crop;
+ unsigned long vresize, hresize;
+
+ DBG;
+
+ /* make a working copy of the new_crop rectangle */
+ try_crop = *new_crop;
+
+ /* adjust the cropping rectangle so it fits in the image */
+ if (try_crop.left < 0) {
+ try_crop.width += try_crop.left;
+ try_crop.left = 0;
+ }
+ if (try_crop.top < 0) {
+ try_crop.height += try_crop.top;
+ try_crop.top = 0;
+ }
+ try_crop.width = (try_crop.width < pix->width) ?
+ try_crop.width : pix->width;
+ try_crop.height = (try_crop.height < pix->height) ?
+ try_crop.height : pix->height;
+ if (try_crop.left + try_crop.width > pix->width)
+ try_crop.width = pix->width - try_crop.left;
+ if (try_crop.top + try_crop.height > pix->height)
+ try_crop.height = pix->height - try_crop.top;
+ try_crop.width &= ~1;
+ try_crop.height &= ~1;
+ if (try_crop.width <= 0 || try_crop.height <= 0)
+ return -EINVAL;
+
+ if (crop->height != win->w.height) {
+ /* If we're resizing vertically, we can't support a crop width
+ * wider than 768 pixels.
+ */
+ if (try_crop.width > 768)
+ try_crop.width = 768;
+ }
+ /* vertical resizing */
+ vresize = (1024 * crop->height) / win->w.height;
+ if (vresize > 2048)
+ vresize = 2048;
+ else if (vresize == 0)
+ vresize = 1;
+ win->w.height = ((1024 * try_crop.height) / vresize) & ~1;
+ if (win->w.height == 0)
+ win->w.height = 2;
+ if (win->w.height + win->w.top > fbuf->fmt.height) {
+ /* We made the preview window extend below the bottom of the
+ * display, so clip it to the display boundary and resize the
+ * cropping height to maintain the vertical resizing ratio.
+ */
+ win->w.height = (fbuf->fmt.height - win->w.top) & ~1;
+ try_crop.height = ((vresize * win->w.height) / 1024) & ~1;
+ if (try_crop.height == 0)
+ try_crop.height = 2;
+ }
+ /* horizontal resizing */
+ hresize = (1024 * crop->width) / win->w.width;
+ if (hresize > 2048)
+ hresize = 2048;
+ else if (hresize == 0)
+ hresize = 1;
+ win->w.width = ((1024 * try_crop.width) / hresize) & ~1;
+ if (win->w.width == 0)
+ win->w.width = 2;
+ if (win->w.width + win->w.left > fbuf->fmt.width) {
+ /* We made the preview window extend past the right side of the
+ * display, so clip it to the display boundary and resize the
+ * cropping width to maintain the horizontal resizing ratio.
+ */
+ win->w.width = (fbuf->fmt.width - win->w.left) & ~1;
+ try_crop.width = ((hresize * win->w.width) / 1024) & ~1;
+ if (try_crop.width == 0)
+ try_crop.width = 2;
+ }
+ /* update our cropping rectangle and we're done */
+ *crop = try_crop;
+ return 0;
+}
+
+/* Given a new preview window in new_win, adjust the preview window to the
+ * nearest supported configuration. The adjusted preview window parameters are
+ * returned in new_win.
+ * Returns zero if succesful, or -EINVAL if the requested preview window is
+ * impossible and cannot reasonably be adjusted.
+ */
+static int
+omap24xxcam_try_preview_window(struct omap24xxcam_device *cam,
+ struct v4l2_window *new_win)
+{
+ struct v4l2_framebuffer *fbuf = &cam->fbuf;
+ struct v4l2_rect try_win;
+
+ DBG;
+
+ /* make a working copy of the new_win rectangle */
+ try_win = new_win->w;
+
+ /* adjust the preview window so it fits on the display by clipping any
+ * offscreen areas
+ */
+ if (try_win.left < 0) {
+ try_win.width += try_win.left;
+ try_win.left = 0;
+ }
+ if (try_win.top < 0) {
+ try_win.height += try_win.top;
+ try_win.top = 0;
+ }
+ try_win.width = (try_win.width < fbuf->fmt.width) ?
+ try_win.width : fbuf->fmt.width;
+ try_win.height = (try_win.height < fbuf->fmt.height) ?
+ try_win.height : fbuf->fmt.height;
+ if (try_win.left + try_win.width > fbuf->fmt.width)
+ try_win.width = fbuf->fmt.width - try_win.left;
+ if (try_win.top + try_win.height > fbuf->fmt.height)
+ try_win.height = fbuf->fmt.height - try_win.top;
+ try_win.width &= ~1;
+ try_win.height &= ~1;
+ if (try_win.width <= 0 || try_win.height <= 0)
+ return -EINVAL;
+
+ /* We now have a valid preview window, so go with it */
+ new_win->w = try_win;
+ new_win->field = V4L2_FIELD_NONE;
+ return 0;
+}
+
+/* Given a new preview window in new_win, adjust the preview window to the
+ * nearest supported configuration. The image cropping window cam->crop
+ * will also be adjusted if necessary. Preference is given to keeping the
+ * preview window as close to the requested configuration as possible. If
+ * successful, new_win, cam->win, and cam->crop are updated.
+ * Returns zero if succesful, or -EINVAL if the requested preview window is
+ * impossible and cannot reasonably be adjusted.
+ */
+static int
+omap24xxcam_new_preview_window(struct omap24xxcam_device *cam,
+ struct v4l2_window *new_win)
+{
+ struct v4l2_window *win = &cam->win;
+ struct v4l2_rect *crop = &cam->crop;
+ int err;
+
+ DBG;
+
+ err = omap24xxcam_try_preview_window(cam, new_win);
+ if (err)
+ return err;
+
+ /* update our preview window */
+ win->w = new_win->w;
+ win->field = new_win->field;
+ win->chromakey = new_win->chromakey;
+
+ /* adjust the cropping window to allow for resizing limitations */
+ if (crop->height / win->w.height >= 2) {
+ /* The maximum vertical downsizing ratio is 2:1 */
+ crop->height = win->w.height * 2;
+ }
+ if (crop->width / win->w.width >= 2) {
+ /* The maximum horizontal downsizing ratio is 2:1 */
+ crop->width = win->w.width * 2;
+ }
+ if (crop->width > 768) {
+ /* The OMAP2420 vertical resizing line buffer is 768 pixels
+ * wide. If the cropped image is wider than 768 pixels then it
+ * cannot be vertically resized.
+ */
+ if (crop->height != win->w.height)
+ crop->width = 768;
+ }
+ return 0;
+}
+
+/* Given a capture format in cam->pix, the cam->crop, cam->win, and cam->fbuf
+ * structures are initialized to default values. cam->fbuf is initialized by
+ * reading the display controller registers for the graphics window. cam->crop
+ * is initialized to the largest window size that will fit on the display. The
+ * crop window is centered in the captured image. cam->win is initialized to
+ * the same size as cam->crop and is centered on the display.
+ * All sizes and offsets are constrained to be even numbers.
+ */
+static void omap24xxcam_new_capture_format(struct omap24xxcam_device *cam)
+{
+ struct v4l2_rect *crop = &cam->crop;
+ struct v4l2_window *win = &cam->win;
+ struct v4l2_framebuffer *fbuf = &cam->fbuf;
+
+ DBG;
+
+ /* get the framebuffer parameters */
+ omap24xxcam_g_fbuf(cam);
+
+ /* crop defines the preview source window in the image capture
+ * buffer
+ */
+ omap24xxcam_default_crop_rect(cam, crop);
+
+ /* win defines the preview target window on the display */
+ win->w.width = crop->width;
+ win->w.height = crop->height;
+ win->w.left = ((fbuf->fmt.width - win->w.width) >> 1) & ~1;
+ win->w.top = ((fbuf->fmt.height - win->w.height) >> 1) & ~1;
+}
+
+/* Program the camera interface xclk for the frequency cam->xclk based on
+ * the functional clock frequency cam->mclk. If the specifed cam->xclk
+ * frequency is not possible based on the value of cam->mclk, then the
+ * closest xclk frequency lower than the specified xclk will be selected.
+ * The actual xclk frequency is returned in cam->xclk. If cam->xclk is zero,
+ * then xclk is turned off (stable low value).
+ */
+static void omap24xxcam_set_xclk(struct omap24xxcam_device *cam)
+{
+ unsigned long divisor;
+
+ DBG;
+
+ if (cam->mclk == 0)
+ cam->mclk = 96000000; /* supply a default mclk */
+
+ if (cam->xclk == 0) {
+ cc_reg_out(cam, CC_CTRL_XCLK, CC_CTRL_XCLK_DIV_STABLE_LOW);
+ return;
+ }
+
+ if (cam->xclk > cam->mclk)
+ cam->xclk = cam->mclk;
+
+ divisor = cam->mclk / cam->xclk;
+ if (cam->xclk * divisor < cam->mclk)
+ divisor += 1;
+ if (divisor > 30)
+ divisor = 30;
+ cam->xclk = cam->mclk / divisor;
+ if (divisor == 1)
+ cc_reg_out(cam, CC_CTRL_XCLK, CC_CTRL_XCLK_DIV_BYPASS);
+ else
+ cc_reg_out(cam, CC_CTRL_XCLK, divisor);
+}
+
+/* Write the color space conversion coefficients to the display controller
+ * registers. Each coefficient is a signed 11-bit integer in the range
+ * [-1024, 1023]. The matrix coefficients are:
+ * [ RY RCr RCb ]
+ * [ GY GCr GCb ]
+ * [ BY BCr BCb ]
+ */
+static void
+omap24xxcam_set_colorconv(struct omap24xxcam_device *cam,
+ const short int mtx[3][3], int v)
+{
+ unsigned long ccreg;
+
+ DBG;
+
+ ccreg = (mtx[0][0] & 0x7ff) | ((mtx[0][1] & 0x7ff) << 16);
+ dispc_reg_out(cam, DISPC_VID_CONV_COEF0(v), ccreg);
+ ccreg = (mtx[0][2] & 0x7ff) | ((mtx[1][0] & 0x7ff) << 16);
+ dispc_reg_out(cam, DISPC_VID_CONV_COEF1(v), ccreg);
+ ccreg = (mtx[1][1] & 0x7ff) | ((mtx[1][2] & 0x7ff) << 16);
+ dispc_reg_out(cam, DISPC_VID_CONV_COEF2(v), ccreg);
+ ccreg = (mtx[2][0] & 0x7ff) | ((mtx[2][1] & 0x7ff) << 16);
+ dispc_reg_out(cam, DISPC_VID_CONV_COEF3(v), ccreg);
+ ccreg = mtx[2][2] & 0x7ff;
+ dispc_reg_out(cam, DISPC_VID_CONV_COEF4(v), ccreg);
+}
+
+/* Write the horizontal and vertical resizing coefficients to the display
+ * controller registers. Each coefficient is a signed 8-bit integer in the
+ * range [-128, 127] except for the middle coefficient (vc[1][i] and hc[3][i])
+ * which is an unsigned 8-bit integer in the range [0, 255]. The first index of
+ * the matrix is the coefficient number (0 to 2 vertical or 0 to 4 horizontal)
+ * and the second index is the phase (0 to 7).
+ */
+static void
+omap24xxcam_set_resize(struct omap24xxcam_device *cam,
+ const short int vc[3][8], const short int hc[5][8],
+ int v)
+{
+ int i;
+ unsigned long reg;
+
+ DBG;
+
+ for (i = 0; i < 8; i++) {
+ reg = (hc[0][i] & 0xff) | ((hc[1][i] & 0xff) << 8)
+ | ((hc[2][i] & 0xff) << 16) | ((hc[3][i] & 0xff) << 24);
+ dispc_reg_out(cam, DISPC_VID_FIR_COEF_H(v, i), reg);
+ reg = (hc[4][i] & 0xff) | ((vc[0][i] & 0xff) << 8)
+ | ((vc[1][i] & 0xff) << 16) | ((vc[2][i] & 0xff) << 24);
+ dispc_reg_out(cam, DISPC_VID_FIR_COEF_HV(v, i), reg);
+ }
+}
+
+static void
+omap24xxcam_configure_overlay(struct omap24xxcam_device *cam,
+ struct omap24xx_vid2_format *vid2_format)
+{
+ int v;
+ struct v4l2_window *win = &cam->win;
+ struct v4l2_rect *crop = &cam->crop;
+ struct v4l2_pix_format *pix;
+ struct v4l2_framebuffer *fbuf = &cam->fbuf;
+ int vid_position_x, vid_position_y;
+ unsigned long vid_position, vid_size, vid_picture_size;
+ unsigned long vid_attributes;
+ unsigned long firvinc, firhinc;
+ /* color space conversion matrices */
+ const static short int cc_bt601[3][3] = {
+ {298, 409, 0},
+ {298, -208, -100},
+ {298, 0, 517}
+ };
+ const static short int cc_bt709[3][3] = {
+ {298, 459, 0},
+ {298, -137, -55},
+ {298, 0, 541}
+ };
+ const static short int cc_bt601_full[3][3] = {
+ {256, 351, 0},
+ {256, -179, -86},
+ {256, 0, 443}
+ };
+ /* vertical resizing matrix */
+ const static short int vc[3][8] = {
+ {0, 3, 12, 32, 0, 7, 5, 2},
+ {128, 123, 111, 89, 64, 89, 111, 123},
+ {0, 2, 5, 7, 64, 32, 12, 3}
+ };
+ /* horizontal resizing matrix */
+ const static short int hc[5][8] = {
+ {0, -1, -2, -5, 0, -2, -1, 0},
+ {0, 13, 30, 51, -9, -11, -11, -8},
+ {128, 124, 112, 95, 73, 95, 112, 124},
+ {0, -8, -11, -11, 73, 51, 30, 13},
+ {0, 0, -1, -2, -9, -5, -2, -1}
+ };
+
+ DBG;
+
+ if (vid2_format) {
+ pix = &vid2_format->pix;
+ v = cam->vid2;
+ } else {
+ pix = &cam->pix;
+ v = cam->vid1;
+ }
+ /* make sure the video overlay is disabled before we reconfigure it */
+ omap24xxcam_disable_vlayer(cam, v);
+
+ /* configure the video attributes register */
+ vid_attributes = 0;
+ switch (pix->pixelformat) {
+ case V4L2_PIX_FMT_YUYV:
+ vid_attributes |= DISPC_VID_ATTRIBUTES_VIDFORMAT_YUV2;
+ vid_attributes |= DISPC_VID_ATTRIBUTES_VIDCOLORCONVENABLE;
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ vid_attributes |= DISPC_VID_ATTRIBUTES_VIDFORMAT_UYVY;
+ vid_attributes |= DISPC_VID_ATTRIBUTES_VIDCOLORCONVENABLE;
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ default:
+ vid_attributes |= DISPC_VID_ATTRIBUTES_VIDFORMAT_RGB16;
+ vid_attributes |= ((cam->gfx_attributes &
+ DISPC_GFX_ATTRIBUTES_GFXREPLICATIONENABLE)
+ << 5);
+ break;
+ case V4L2_PIX_FMT_RGB565X:
+ vid_attributes |= DISPC_VID_ATTRIBUTES_VIDFORMAT_RGB16;
+ vid_attributes |= DISPC_VID_ATTRIBUTES_VIDENDIANNESS;
+ vid_attributes |= ((cam->gfx_attributes &
+ DISPC_GFX_ATTRIBUTES_GFXREPLICATIONENABLE)
+ << 5);
+ break;
+ }
+ if (cam->gfx_attributes & DISPC_GFX_ATTRIBUTES_GFXCHANNELOUT)
+ vid_attributes |= DISPC_VID_ATTRIBUTES_VIDCHANNELOUT;
+ vid_attributes |= ((cam->gfx_attributes
+ & DISPC_GFX_ATTRIBUTES_GFXBURSTSIZE) << 8);
+ switch (pix->colorspace) {
+ case V4L2_COLORSPACE_SMPTE170M:
+ case V4L2_COLORSPACE_SMPTE240M:
+ case V4L2_COLORSPACE_BT878:
+ case V4L2_COLORSPACE_470_SYSTEM_M:
+ case V4L2_COLORSPACE_470_SYSTEM_BG:
+ /* luma (Y) range lower limit is 16, BT.601 standard */
+ omap24xxcam_set_colorconv(cam, cc_bt601, v);
+ break;
+ case V4L2_COLORSPACE_REC709:
+ /* luma (Y) range lower limit is 16, BT.709 standard */
+ omap24xxcam_set_colorconv(cam, cc_bt709, v);
+ break;
+ case V4L2_COLORSPACE_JPEG:
+ case V4L2_COLORSPACE_SRGB:
+ /* full luma (Y) range, assume BT.601 standard */
+ vid_attributes |= DISPC_VID_ATTRIBUTES_VIDFULLRANGE;
+ omap24xxcam_set_colorconv(cam, cc_bt601_full, v);
+ break;
+ }
+ if (!vid2_format) { /* use win and crop if it is for overlay */
+ if (win->w.width != crop->width) {
+ vid_attributes |=
+ DISPC_VID_ATTRIBUTES_VIDRESIZEENABLE_HRESIZE;
+ if (win->w.width < crop->width)
+ vid_attributes |=
+ DISPC_VID_ATTRIBUTES_VIDHRESIZECONF;
+ }
+ if (win->w.height != crop->height) {
+ vid_attributes |=
+ DISPC_VID_ATTRIBUTES_VIDRESIZEENABLE_VRESIZE;
+ if (win->w.height < crop->height)
+ vid_attributes |=
+ DISPC_VID_ATTRIBUTES_VIDVRESIZECONF;
+ }
+ }
+ dispc_reg_out(cam, DISPC_VID_ATTRIBUTES(v), vid_attributes);
+
+ /* configure transparency color key */
+ if (fbuf->flags & V4L2_FBUF_FLAG_CHROMAKEY) {
+ /* enable chromakey */
+ if (vid_attributes & DISPC_VID_ATTRIBUTES_VIDCHANNELOUT) {
+ /* digital output channel */
+ dispc_reg_out(cam, DISPC_TRANS_COLOR1, win->chromakey);
+ dispc_reg_merge(cam, DISPC_CONFIG,
+ DISPC_CONFIG_TCKDIGENABLE,
+ DISPC_CONFIG_TCKDIGSELECTION
+ | DISPC_CONFIG_TCKDIGENABLE);
+ } else {
+ /* LCD */
+ dispc_reg_out(cam, DISPC_TRANS_COLOR0, win->chromakey);
+ dispc_reg_merge(cam, DISPC_CONFIG,
+ DISPC_CONFIG_TCKLCDENABLE,
+ DISPC_CONFIG_TCKLCDSELECTION
+ | DISPC_CONFIG_TCKLCDENABLE);
+ }
+ } else {
+ /* disable chromakey */
+ if (vid_attributes & DISPC_VID_ATTRIBUTES_VIDCHANNELOUT) {
+ /* digital output channel */
+ dispc_reg_merge(cam, DISPC_CONFIG, 0,
+ DISPC_CONFIG_TCKDIGSELECTION
+ | DISPC_CONFIG_TCKDIGENABLE);
+ } else {
+ /* LCD */
+ dispc_reg_merge(cam, DISPC_CONFIG, 0,
+ DISPC_CONFIG_TCKLCDSELECTION
+ | DISPC_CONFIG_TCKLCDENABLE);
+ }
+ }
+
+ /* initialize the resizing filter */
+ omap24xxcam_set_resize(cam, vc, hc, v);
+
+ if (!vid2_format) { /* use win and crop if it is for overlay */
+ dispc_reg_out(cam, DISPC_VID_ACCU0(v), 0);
+ dispc_reg_out(cam, DISPC_VID_ACCU1(v), 0);
+ firhinc = (1024 * (crop->width - 1)) / (win->w.width - 1);
+ if (firhinc < 1)
+ firhinc = 1;
+ else if (firhinc > 2047)
+ firhinc = 2047;
+ firvinc = (1024 * (crop->height - 1)) / (win->w.height - 1);
+ if (firvinc < 1)
+ firvinc = 1;
+ else if (firvinc > 2047)
+ firvinc = 2047;
+ dispc_reg_out(cam, DISPC_VID_FIR(v), firhinc | (firvinc << 16));
+
+ /* configure the target window on the display */
+ vid_position_x = cam->gfx_position_x + win->w.left;
+ vid_position_y = cam->gfx_position_y + win->w.top;
+ vid_size =
+ (((win->w.width - 1) << DISPC_VID_SIZE_VIDSIZEX_SHIFT)
+ & DISPC_VID_SIZE_VIDSIZEX)
+ | (((win->w.height - 1) << DISPC_VID_SIZE_VIDSIZEY_SHIFT)
+ & DISPC_VID_SIZE_VIDSIZEY);
+
+ /* configure the source window in the framebuffer */
+ vid_picture_size =
+ (((crop->width -
+ 1) << DISPC_VID_PICTURE_SIZE_VIDORGSIZEX_SHIFT)
+ & DISPC_VID_PICTURE_SIZE_VIDORGSIZEX)
+ |
+ (((crop->height -
+ 1) << DISPC_VID_PICTURE_SIZE_VIDORGSIZEY_SHIFT)
+ & DISPC_VID_PICTURE_SIZE_VIDORGSIZEY);
+ dispc_reg_out(cam, DISPC_VID_ROW_INC(v),
+ 1 + pix->bytesperline - crop->width * 2);
+ } else { /* video 2 layer configuration */
+ struct v4l2_framebuffer *fbuf = &cam->fbuf;
+ int row_inc;
+ /* in video2 layer we won't be down or up scaling */
+ dispc_reg_out(cam, DISPC_VID_FIR(v), 0x400 | (0x400 << 16));
+ if (pix->width + vid2_format->left > fbuf->fmt.width) {
+ vid_position_x = fbuf->fmt.width < pix->width ? 0 :
+ cam->gfx_position_x + fbuf->fmt.width - pix->width;
+ } else {
+ vid_position_x = cam->gfx_position_x +
+ vid2_format->left;
+
+ }
+
+ if (pix->height + vid2_format->top > fbuf->fmt.height) {
+ vid_position_y = fbuf->fmt.height < pix->height ? 0 :
+ cam->gfx_position_y +
+ fbuf->fmt.height - pix->height;
+ } else {
+ vid_position_y = cam->gfx_position_y + vid2_format->top;
+ }
+
+ vid_size = ((((pix->width > fbuf->fmt.width ? fbuf->fmt.width
+ : pix->width) - 1)
+ << DISPC_VID_SIZE_VIDSIZEX_SHIFT)
+ & DISPC_VID_SIZE_VIDSIZEX)
+ | ((((pix->height > fbuf->fmt.height ? fbuf->fmt.height
+ : pix->height) - 1) << DISPC_VID_SIZE_VIDSIZEY_SHIFT)
+ & DISPC_VID_SIZE_VIDSIZEY);
+ vid_picture_size = vid_size;
+ row_inc = ((pix->width -
+ ((vid_size >> DISPC_VID_SIZE_VIDSIZEX_SHIFT)
+ & DISPC_VID_SIZE_VIDSIZEX)) * 2)
+ - 1;
+ /* we are subtracting 1 instead of adding because vid_size
+ ** is 1 less than the pix width
+ */
+ dispc_reg_out(cam, DISPC_VID_ROW_INC(v), row_inc);
+ }
+ vid_position = ((vid_position_x << DISPC_VID_POSITION_VIDPOSX_SHIFT)
+ & DISPC_VID_POSITION_VIDPOSX)
+ | ((vid_position_y << DISPC_VID_POSITION_VIDPOSY_SHIFT)
+ & DISPC_VID_POSITION_VIDPOSY);
+ dispc_reg_out(cam, DISPC_VID_POSITION(v), vid_position);
+ dispc_reg_out(cam, DISPC_VID_SIZE(v), vid_size);
+ dispc_reg_out(cam, DISPC_VID_PICTURE_SIZE(v), vid_picture_size);
+ dispc_reg_out(cam, DISPC_VID_PIXEL_INC(v), 1);
+
+ if (vid2_format) {
+ unsigned long vid2_base_phys;
+ vid2_base_phys = cam->video2_base_phys;
+ //+ pix->bytesperline*crop->top + crop->left*2;
+ dispc_reg_out(cam, DISPC_VID_BA0(v), vid2_base_phys);
+ dispc_reg_out(cam, DISPC_VID_BA1(v), vid2_base_phys);
+ vid_attributes = dispc_reg_merge(cam, DISPC_VID_ATTRIBUTES(v),
+ DISPC_VID_ATTRIBUTES_ENABLE,
+ DISPC_VID_ATTRIBUTES_ENABLE);
+ if (vid_attributes & DISPC_VID_ATTRIBUTES_VIDCHANNELOUT) {
+ /* digital output */
+ dispc_reg_merge(cam, DISPC_CONTROL,
+ DISPC_CONTROL_GODIGITAL,
+ DISPC_CONTROL_GODIGITAL);
+ } else {
+ /* LCD */
+ dispc_reg_merge(cam, DISPC_CONTROL, DISPC_CONTROL_GOLCD,
+ DISPC_CONTROL_GOLCD);
+ }
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* Start a DMA transfer from the camera to memory.
+ * Returns zero if the transfer was successfully started, or non-zero if all
+ * DMA channels are already in use or starting is currently inhibited.
+ */
+int
+omap24xxcam_dma_start(struct omap24xxcam_device *cam, dma_addr_t start,
+ unsigned long len, dma_callback_t callback, void *arg)
+{
+ unsigned long irqflags;
+ int dmach;
+ void (*dma_notify)(struct omap24xxcam_device *cam);
+
+ DBG;
+
+ spin_lock_irqsave(&cam->dma_lock, irqflags);
+
+ if (!cam->free_dmach || cam->dma_stop) {
+ spin_unlock_irqrestore(&cam->dma_lock, irqflags);
+ DBG_MID(3);
+ return -EBUSY;
+ }
+
+ dmach = cam->next_dmach;
+
+ cam->camdma[dmach].callback = callback;
+ cam->camdma[dmach].arg = arg;
+
+ camdma_reg_out(cam, CAMDMA_CCR(dmach),
+ CAMDMA_CCR_SEL_SRC_DST_SYNC
+ | CAMDMA_CCR_BS
+ | CAMDMA_CCR_DST_AMODE_POST_INC
+ | CAMDMA_CCR_SRC_AMODE_POST_INC
+ | CAMDMA_CCR_FS
+ | CAMDMA_CCR_WR_ACTIVE
+ | CAMDMA_CCR_RD_ACTIVE
+ | CAMDMA_CCR_SYNCHRO_CAMERA);
+ camdma_reg_out(cam, CAMDMA_CLNK_CTRL(dmach), 0);
+ camdma_reg_out(cam, CAMDMA_CEN(dmach), len);
+ camdma_reg_out(cam, CAMDMA_CFN(dmach), 1);
+ camdma_reg_out(cam, CAMDMA_CSDP(dmach),
+ CAMDMA_CSDP_WRITE_MODE_POSTED
+ | CAMDMA_CSDP_DST_BURST_EN_64
+ | CAMDMA_CSDP_DST_PACKED
+ | CAMDMA_CSDP_SRC_BURST_EN_64
+ | CAMDMA_CSDP_SRC_PACKED
+ | CAMDMA_CSDP_DATA_TYPE_8BITS);
+ camdma_reg_out(cam, CAMDMA_CSSA(dmach), 0);
+ camdma_reg_out(cam, CAMDMA_CDSA(dmach), start);
+ camdma_reg_out(cam, CAMDMA_CSEI(dmach), 0);
+ camdma_reg_out(cam, CAMDMA_CSFI(dmach), DMA_THRESHOLD);
+ camdma_reg_out(cam, CAMDMA_CDEI(dmach), 0);
+ camdma_reg_out(cam, CAMDMA_CDFI(dmach), 0);
+ camdma_reg_out(cam, CAMDMA_CSR(dmach),
+ CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR
+ | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR
+ | CAMDMA_CSR_BLOCK
+ | CAMDMA_CSR_DROP);
+ camdma_reg_out(cam, CAMDMA_CICR(dmach),
+ CAMDMA_CICR_MISALIGNED_ERR_IE
+ | CAMDMA_CICR_SUPERVISOR_ERR_IE
+ | CAMDMA_CICR_SECURE_ERR_IE
+ | CAMDMA_CICR_TRANS_ERR_IE
+ | CAMDMA_CICR_BLOCK_IE
+ | CAMDMA_CICR_DROP_IE);
+
+ /* We're ready to start the DMA transfer. */
+
+ if (cam->free_dmach < NUM_CAMDMA_CHANNELS) {
+ /* A transfer is already in progress, so try to chain to it. */
+ int prev_dmach, ch;
+
+ if (dmach == 0)
+ prev_dmach = NUM_CAMDMA_CHANNELS - 1;
+ else
+ prev_dmach = dmach - 1;
+ camdma_reg_out(cam, CAMDMA_CLNK_CTRL(prev_dmach),
+ CAMDMA_CLNK_CTRL_ENABLE_LNK | dmach);
+ /* Did we chain the DMA transfer before the previous one
+ * finished?
+ */
+ ch = (dmach + cam->free_dmach) % NUM_CAMDMA_CHANNELS;
+ DBG_MID(1);
+ while (!(camdma_reg_in(cam, CAMDMA_CCR(ch))
+ & CAMDMA_CCR_ENABLE))
+ {
+ if (ch == dmach) {
+ /* The previous transfer has ended and this one
+ * hasn't started, so we must not have chained
+ * to the previous one in time. We'll have to
+ * start it now.
+ */
+ camdma_reg_out(cam, CAMDMA_CCR(dmach),
+ CAMDMA_CCR_SEL_SRC_DST_SYNC
+ | CAMDMA_CCR_BS
+ | CAMDMA_CCR_DST_AMODE_POST_INC
+ | CAMDMA_CCR_SRC_AMODE_POST_INC
+ | CAMDMA_CCR_ENABLE
+ | CAMDMA_CCR_FS
+ | CAMDMA_CCR_SYNCHRO_CAMERA);
+ break;
+ } else
+ ch = (ch + 1) % NUM_CAMDMA_CHANNELS;
+ }
+ DBG_MID(2);
+ }
+ else {
+ /* No transfer is in progress, so we'll just start this one
+ * now.
+ */
+ camdma_reg_out(cam, CAMDMA_CCR(dmach),
+ CAMDMA_CCR_SEL_SRC_DST_SYNC
+ | CAMDMA_CCR_BS
+ | CAMDMA_CCR_DST_AMODE_POST_INC
+ | CAMDMA_CCR_SRC_AMODE_POST_INC
+ | CAMDMA_CCR_ENABLE
+ | CAMDMA_CCR_FS
+ | CAMDMA_CCR_SYNCHRO_CAMERA);
+ }
+
+ cam->next_dmach = (cam->next_dmach + 1) % NUM_CAMDMA_CHANNELS;
+ cam->free_dmach--;
+
+ dma_notify = cam->dma_notify;
+ cam->dma_notify = NULL;
+
+ spin_unlock_irqrestore(&cam->dma_lock, irqflags);
+
+ if (dma_notify)
+ (*dma_notify)(cam);
+
+ DBG_END;
+
+ return 0;
+}
+
+/* DMA completion routine for the scatter-gather DMA fragments. */
+static void
+omap24xxcam_sg_dma_callback(struct omap24xxcam_device *cam, unsigned long csr,
+ void *arg)
+{
+ int sgslot = (int)arg;
+ struct sgdma_state *sgdma;
+ const unsigned long csr_error = CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+ DBG;
+
+ spin_lock(&cam->sg_lock);
+
+ sgdma = cam->sgdma + sgslot;
+ if (!sgdma->queued_sglist) {
+ spin_unlock(&cam->sg_lock);
+ printk(KERN_DEBUG CAM_NAME
+ ": sgdma completed when none queued!\n");
+ return;
+ }
+
+ sgdma->csr |= csr;
+ if (!--sgdma->queued_sglist) {
+ /* Queue for this sglist is empty, so check to see if we're
+ * done.
+ */
+ if ((sgdma->next_sglist == sgdma->sglen)
+ || (sgdma->csr & csr_error)) {
+ dma_callback_t callback = sgdma->callback;
+ void *arg = sgdma->arg;
+ unsigned long sg_csr = sgdma->csr;
+ /* All done with this sglist */
+ cam->free_sgdma++;
+ if (callback) {
+ spin_unlock(&cam->sg_lock);
+ (*callback) (cam, sg_csr, arg);
+ return;
+ }
+ }
+ }
+
+ spin_unlock(&cam->sg_lock);
+}
+
+/* Process the scatter-gather DMA queue by starting queued transfers. */
+static void omap24xxcam_sg_dma_process(struct omap24xxcam_device *cam)
+{
+ unsigned long irqflags;
+ int queued_sgdma, sgslot;
+ struct sgdma_state *sgdma;
+ const unsigned long csr_error = CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+ DBG;
+
+ spin_lock_irqsave(&cam->sg_lock, irqflags);
+
+ queued_sgdma = NUM_SG_DMA - cam->free_sgdma;
+ sgslot = (cam->next_sgdma + cam->free_sgdma) % NUM_SG_DMA;
+ while (queued_sgdma > 0) {
+ sgdma = cam->sgdma + sgslot;
+ while ((sgdma->next_sglist < sgdma->sglen) &&
+ !(sgdma->csr & csr_error)) {
+ const struct scatterlist *sglist;
+
+ sglist = sgdma->sglist + sgdma->next_sglist;
+ /* try to start the next DMA transfer */
+ if (omap24xxcam_dma_start(cam, sg_dma_address(sglist),
+ sg_dma_len(sglist),
+ omap24xxcam_sg_dma_callback,
+ (void *)sgslot)) {
+ /* DMA start failed */
+ spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+ return;
+ } else {
+ /* DMA start was successful */
+ sgdma->next_sglist++;
+ sgdma->queued_sglist++;
+ }
+ }
+ queued_sgdma--;
+ sgslot = (sgslot + 1) % NUM_SG_DMA;
+ }
+
+ spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+ DBG_END;
+}
+
+/* Queue a scatter-gather DMA transfer from the camera to memory.
+ * Returns zero if the transfer was successfully queued, or
+ * non-zero if all of the scatter-gather slots are already in use.
+ */
+static int
+omap24xxcam_sg_dma_queue(struct omap24xxcam_device *cam,
+ const struct scatterlist *sglist, int sglen,
+ dma_callback_t callback, void *arg)
+{
+ unsigned long irqflags;
+ struct sgdma_state *sgdma;
+
+ DBG;
+
+ if ((sglen < 0) || ((sglen > 0) & !sglist))
+ return -EINVAL;
+
+ spin_lock_irqsave(&cam->sg_lock, irqflags);
+
+ if (!cam->free_sgdma) {
+ spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+ return -EBUSY;
+ }
+
+ sgdma = cam->sgdma + cam->next_sgdma;
+
+ sgdma->sglist = sglist;
+ sgdma->sglen = sglen;
+ sgdma->next_sglist = 0;
+ sgdma->queued_sglist = 0;
+ sgdma->csr = 0;
+ sgdma->callback = callback;
+ sgdma->arg = arg;
+
+ cam->next_sgdma = (cam->next_sgdma + 1) % NUM_SG_DMA;
+ cam->free_sgdma--;
+
+ spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+
+ omap24xxcam_sg_dma_process(cam);
+
+ return 0;
+}
+
+/* Abort all chained DMA transfers. After all transfers have been aborted and
+ * the DMA controller is idle, the completion routines for any aborted transfers
+ * will be called in sequence. The DMA controller may not be idle after this
+ * routine completes, because the completion routines might start new transfers.
+ */
+static void
+omap24xxcam_dma_abort(struct omap24xxcam_device *cam, unsigned long csr)
+{
+ unsigned long irqflags;
+ int dmach, i, free_dmach;
+ dma_callback_t callback;
+ void *arg;
+
+ DBG;
+
+ spin_lock_irqsave(&cam->dma_lock, irqflags);
+
+ /* stop any DMA transfers in progress */
+ dmach = (cam->next_dmach + cam->free_dmach) % NUM_CAMDMA_CHANNELS;
+ for (i = 0; i < NUM_CAMDMA_CHANNELS; i++) {
+ /* mask all interrupts from this channel */
+ camdma_reg_out(cam, CAMDMA_CICR(dmach), 0);
+ /* unlink this channel */
+ camdma_reg_merge(cam, CAMDMA_CLNK_CTRL(dmach), 0,
+ CAMDMA_CLNK_CTRL_ENABLE_LNK);
+ /* disable this channel */
+ camdma_reg_merge(cam, CAMDMA_CCR(dmach), 0, CAMDMA_CCR_ENABLE);
+ dmach = (dmach + 1) % NUM_CAMDMA_CHANNELS;
+ }
+
+ /* We have to be careful here because the callback routine might start
+ * a new DMA transfer, and we only want to abort transfers that were
+ * started before this routine was called.
+ */
+ free_dmach = cam->free_dmach;
+ while ((cam->free_dmach < NUM_CAMDMA_CHANNELS) &&
+ (free_dmach < NUM_CAMDMA_CHANNELS)) {
+ dmach = (cam->next_dmach + cam->free_dmach)
+ % NUM_CAMDMA_CHANNELS;
+ callback = cam->camdma[dmach].callback;
+ arg = cam->camdma[dmach].arg;
+ cam->free_dmach++;
+ free_dmach++;
+ if (callback) {
+ /* leave interrupts disabled during callback */
+ spin_unlock(&cam->dma_lock);
+ (*callback) (cam, csr, arg);
+ spin_lock(&cam->dma_lock);
+ }
+ }
+
+ spin_unlock_irqrestore(&cam->dma_lock, irqflags);
+}
+
+/* Abort all chained DMA transfers. After all transfers have been aborted and
+ * the DMA controller is idle, the completion routines for any aborted transfers
+ * will be called in sequence. If the completion routines attempt to start a
+ * new DMA transfer it will fail, so the DMA controller will be idle after this
+ * routine completes.
+ */
+static void
+omap24xxcam_dma_stop(struct omap24xxcam_device *cam, unsigned long csr)
+{
+ unsigned long irqflags;
+
+ DBG;
+
+ spin_lock_irqsave(&cam->dma_lock, irqflags);
+ cam->dma_stop++;
+ spin_unlock_irqrestore(&cam->dma_lock, irqflags);
+ omap24xxcam_dma_abort(cam, csr);
+ spin_lock_irqsave(&cam->dma_lock, irqflags);
+ cam->dma_stop--;
+ spin_unlock_irqrestore(&cam->dma_lock, irqflags);
+}
+
+/* Sync scatter-gather DMA by aborting any DMA transfers currently in progress.
+ * Any queued scatter-gather DMA transactions that have not yet been started
+ * will remain queued. The DMA controller will be idle after this routine
+ * completes. When the scatter-gather queue is restarted, the next
+ * scatter-gather DMA transfer will begin at the start of a new transaction.
+ */
+static void
+omap24xxcam_sg_dma_sync(struct omap24xxcam_device *cam, unsigned long csr)
+{
+ unsigned long irqflags;
+ int sgslot;
+ struct sgdma_state *sgdma;
+
+ DBG;
+
+ /* stop any DMA transfers in progress */
+ omap24xxcam_dma_stop(cam, csr);
+
+ spin_lock_irqsave(&cam->sg_lock, irqflags);
+
+ if (cam->free_sgdma < NUM_SG_DMA) {
+ sgslot = (cam->next_sgdma + cam->free_sgdma) % NUM_SG_DMA;
+ sgdma = cam->sgdma + sgslot;
+ if (sgdma->next_sglist != 0) {
+ /* This DMA transfer was in progress, so abort it. */
+ dma_callback_t callback = sgdma->callback;
+ void *arg = sgdma->arg;
+ cam->free_sgdma++;
+ if (callback) {
+ /* leave interrupts masked */
+ spin_unlock(&cam->sg_lock);
+ (*callback) (cam, csr, arg);
+ spin_lock(&cam->sg_lock);
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+}
+
+/* This routine is not needed at the moment, but we'll keep it around just in
+ * case.
+ */
+#if 0
+/* Stop the DMA controller, aborting any DMA transfers in progress. Any queued
+ * scatter-gather DMA transactions are cancelled. The DMA controller will be
+ * idle after this routine completes, and the scatter-gather DMA queue will
+ * be empty. csr is the completion status passed to the completion routines
+ * for any DMA transfers that are aborted. It should have at least one error
+ * bit set.
+ */
+static void
+omap24xxcam_sg_dma_stop(struct omap24xxcam_device *cam, unsigned long csr)
+{
+ unsigned long irqflags;
+ int queued_sgdma, sgslot;
+ struct sgdma_state *sgdma;
+ dma_callback_t callback;
+ void *arg;
+
+ /* stop any DMA transfers in progress */
+ omap24xxcam_dma_stop(cam, csr);
+
+ spin_lock_irqsave(&cam->sg_lock, irqflags);
+
+ queued_sgdma = NUM_SG_DMA - cam->free_sgdma;
+ sgslot = (cam->next_sgdma + cam->free_sgdma) % NUM_SG_DMA;
+ while (queued_sgdma > 0) {
+ sgdma = cam->sgdma + sgslot;
+ callback = sgdma->callback;
+ arg = sgdma->arg;
+ cam->free_sgdma++;
+ sgdma->queued_sglist = 0;
+ if (callback) {
+ /* leave interrupts masked */
+ spin_unlock(&cam->sg_lock);
+ (*callback) (cam, csr, arg);
+ spin_lock(&cam->sg_lock);
+ }
+ queued_sgdma--;
+ sgslot = (sgslot + 1) % NUM_SG_DMA;
+ }
+
+ spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+}
+#endif /* if 0 */
+
+/* Register a routine to be called once immediately after a DMA transfer is
+ * started. The purpose of this is to allow the camera interface to be
+ * started only after a DMA transaction has been queued in order to avoid
+ * DMA overruns. The registered callback routine will only be called one
+ * time and then discarded. Only one callback routine may be registered at a
+ * time.
+ * Returns zero if successful, or a non-zero error code if a different callback
+ * routine has already been registered.
+ */
+static int
+omap24xxcam_dma_notify(struct omap24xxcam_device *cam,
+ void (*callback) (struct omap24xxcam_device * cam))
+{
+ unsigned long irqflags;
+
+ DBG;
+
+ spin_lock_irqsave(&cam->dma_lock, irqflags);
+
+ if (cam->dma_notify && (cam->dma_notify != callback)) {
+ spin_unlock_irqrestore(&cam->dma_lock, irqflags);
+ return -EBUSY;
+ }
+
+ cam->dma_notify = callback;
+
+ spin_unlock_irqrestore(&cam->dma_lock, irqflags);
+
+ return 0;
+}
+
+/* Camera DMA interrupt service routine. */
+static void omap24xxcam_dma_isr(struct omap24xxcam_device *cam)
+{
+ int dmach, i;
+ dma_callback_t callback;
+ void *arg;
+ unsigned long csr;
+ const unsigned long csr_error = CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+ spin_lock(&cam->dma_lock);
+
+ if (cam->free_dmach == NUM_CAMDMA_CHANNELS) {
+ /* A camera DMA interrupt occurred while all channels are idle,
+ * so we'll acknowledge the interrupt in the IRQSTATUS register
+ * and exit.
+ */
+ for (i = 0; i< 4; ++i) {
+ csr = camdma_reg_in(cam, CAMDMA_CSR(i));
+ /* ack interrupt in CSR */
+ camdma_reg_out(cam, CAMDMA_CSR(i), csr);
+ }
+ camdma_reg_out(cam, CAMDMA_IRQSTATUS_L0, 0xffffffff);
+ spin_unlock(&cam->dma_lock);
+ return;
+ }
+
+ while (cam->free_dmach < NUM_CAMDMA_CHANNELS) {
+ dmach = (cam->next_dmach + cam->free_dmach)
+ % NUM_CAMDMA_CHANNELS;
+ if (camdma_reg_in(cam, CAMDMA_CCR(dmach)) & CAMDMA_CCR_ENABLE) {
+ /* This buffer hasn't finished yet, so we're done. */
+ break;
+ }
+ csr = camdma_reg_in(cam, CAMDMA_CSR(dmach));
+ /* ack interrupt in CSR */
+ camdma_reg_out(cam, CAMDMA_CSR(dmach), csr);
+ /* ack interrupt in IRQSTATUS */
+ camdma_reg_out(cam, CAMDMA_IRQSTATUS_L0, (1 << dmach));
+ if (csr & csr_error) {
+ /* A DMA error occurred, so stop all DMA transfers in
+ * progress.
+ */
+ spin_unlock(&cam->dma_lock);
+ omap24xxcam_dma_stop(cam, csr);
+ return;
+ } else {
+ callback = cam->camdma[dmach].callback;
+ arg = cam->camdma[dmach].arg;
+ cam->free_dmach++;
+ if (callback) {
+ spin_unlock(&cam->dma_lock);
+ (*callback) (cam, csr, arg);
+ spin_lock(&cam->dma_lock);
+ }
+ }
+ }
+
+ spin_unlock(&cam->dma_lock);
+
+ omap24xxcam_sg_dma_process(cam);
+}
+
+/* Shutdown the camera DMA driver and controller. */
+static void omap24xxcam_dma_exit(struct omap24xxcam_device *cam)
+{
+ int ch;
+
+ DBG;
+
+ /* Mask all DMA interrupts */
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L0, 0);
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L1, 0);
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L2, 0);
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L3, 0);
+
+ /* disable all DMA channels */
+ for (ch = 0; ch < NUM_CAMDMA_CHANNELS; ch++)
+ camdma_reg_out(cam, CAMDMA_CCR(ch), 0);
+}
+
+/* Initialize the camera DMA driver. */
+static void omap24xxcam_dma_init(struct omap24xxcam_device *cam)
+{
+ int ch, sg;
+
+ DBG;
+
+ /* group all channels on DMA IRQ0 and unmask irq */
+
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L0, 0xffffffff);
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L1, 0);
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L2, 0);
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L3, 0);
+
+ spin_lock_init(&cam->dma_lock);
+ cam->free_dmach = NUM_CAMDMA_CHANNELS;
+ cam->next_dmach = 0;
+ for (ch = 0; ch < NUM_CAMDMA_CHANNELS; ch++) {
+ cam->camdma[ch].callback = NULL;
+ cam->camdma[ch].arg = NULL;
+ }
+
+ spin_lock_init(&cam->sg_lock);
+ cam->free_sgdma = NUM_SG_DMA;
+ cam->next_sgdma = 0;
+ for (sg = 0; sg < NUM_SG_DMA; sg++) {
+ cam->sgdma[sg].sglen = 0;
+ cam->sgdma[sg].next_sglist = 0;
+ cam->sgdma[sg].queued_sglist = 0;
+ cam->sgdma[sg].csr = 0;
+ cam->sgdma[sg].callback = NULL;
+ cam->sgdma[sg].arg = NULL;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* Callback routine for overlay DMA completion. We just start another DMA
+ * transfer unless overlay has been turned off.
+ */
+static void
+omap24xxcam_overlay_callback(struct omap24xxcam_device *cam, unsigned long csr,
+ void *arg)
+{
+ int err;
+ unsigned long irqflags;
+ const unsigned long csr_error = CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+ DBG;
+
+ spin_lock_irqsave(&cam->overlay_lock, irqflags);
+
+ if (cam->overlay_cnt > 0)
+ --cam->overlay_cnt;
+
+ if (!cam->previewing || (csr & csr_error)) {
+ printk(KERN_INFO CAM_NAME
+ ": overlay_callback error. csr = 0x%08x\n", (u16)csr);
+ spin_unlock_irqrestore(&cam->overlay_lock, irqflags);
+ return;
+ }
+
+ sg_dma_address(&cam->overlay_sglist) = cam->overlay_base_phys;
+ sg_dma_len(&cam->overlay_sglist) = cam->pix.sizeimage;
+
+ while (cam->overlay_cnt < 2) {
+ err = omap24xxcam_sg_dma_queue(cam, &cam->overlay_sglist, 1,
+ omap24xxcam_overlay_callback,
+ NULL);
+ if (err)
+ break;
+ ++cam->overlay_cnt;
+ }
+
+ spin_unlock_irqrestore(&cam->overlay_lock, irqflags);
+}
+
+/* Begin DMA'ing into the camera overlay framebuffer. We queue up two DMA
+ * transfers so that all frames will be captured.
+ */
+static void omap24xxcam_start_overlay_dma(struct omap24xxcam_device *cam)
+{
+ int err;
+ unsigned long irqflags;
+
+ DBG;
+
+ if (!cam->previewing)
+ return;
+
+ if (cam->pix.sizeimage > cam->overlay_size)
+ return;
+
+ spin_lock_irqsave(&cam->overlay_lock, irqflags);
+
+ sg_dma_address(&cam->overlay_sglist) = cam->overlay_base_phys;
+ sg_dma_len(&cam->overlay_sglist) = cam->pix.sizeimage;
+
+ while (cam->overlay_cnt < 2) {
+ err = omap24xxcam_sg_dma_queue(cam, &cam->overlay_sglist, 1,
+ omap24xxcam_overlay_callback,
+ NULL);
+ if (err)
+ break;
+ ++cam->overlay_cnt;
+ }
+
+ spin_unlock_irqrestore(&cam->overlay_lock, irqflags);
+}
+
+/* Enable the camera core interface. */
+static void omap24xxcam_cc_enable(struct omap24xxcam_device *cam)
+{
+ DBG;
+ /* Get the CC_CTRL register value for the current capture format. */
+ omap24xxcam_sensor_cc_ctrl(cam);
+
+ /* program the camera interface DMA packet size */
+ cc_reg_out(cam, CC_CTRL_DMA, CC_CTRL_DMA_EN | (DMA_THRESHOLD / 4 - 1));
+
+ /* enable camera core error interrupts */
+ cc_reg_out(cam, CC_IRQENABLE, CC_IRQENABLE_FW_ERR_IRQ
+ | CC_IRQENABLE_FSC_ERR_IRQ | CC_IRQENABLE_SSC_ERR_IRQ
+ | CC_IRQENABLE_FIFO_OF_IRQ /*| CC_IRQENABLE_FIFO_FULL_IRQ */
+ );
+
+ /* enable the camera interface */
+ cc_reg_out(cam, CC_CTRL, cam->cc_ctrl | CC_CTRL_CC_EN);
+}
+
+/* Error recovery for DMA errors and camera interface errors. */
+static void omap24xxcam_error_handler(struct omap24xxcam_device *cam)
+{
+ DBG;
+ /* Get the CC_CTRL register value for the current capture format. */
+ omap24xxcam_sensor_cc_ctrl(cam);
+
+ /* Disable and reset the camera interface. */
+ cc_reg_out(cam, CC_CTRL,
+ cam->cc_ctrl & ~(CC_CTRL_CC_EN | CC_CTRL_CC_FRAME_TRIG));
+ cc_reg_out(cam, CC_CTRL, (cam->cc_ctrl | CC_CTRL_CC_RST)
+ & ~(CC_CTRL_CC_EN | CC_CTRL_CC_FRAME_TRIG));
+
+ /* Stop the DMA controller and frame sync scatter-gather DMA. */
+ omap24xxcam_sg_dma_sync(cam, CAMDMA_CSR_TRANS_ERR);
+
+#if 1
+ /* Reset and re-initialize the entire camera subsystem.
+ * Resetting the camera FIFO via the CC_RST bit in the CC_CTRL
+ * register is supposed to be sufficient to recover from a
+ * camera interface error, but it doesn't seem to be enough. If
+ * we only do that then subsequent image captures are out of sync
+ * by either one or two times DMA_THRESHOLD bytes. Resetting and
+ * re-initializing the entire camera subsystem prevents the problem
+ * with frame synchronization. Calling cam_init() from an ISR is
+ * undesirable since it waits an indeterminate amount of time for the
+ * camera subsystem reset to complete. If we ever figure out exactly
+ * what needs to be reset to recover from a camera interface error,
+ * maybe we can replace this global reset with something less drastic.
+ */
+ cam_init(cam);
+ omap24xxcam_set_xclk(cam);
+ /* group all channels on DMA IRQ0 and unmask irq */
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L0, 0xffffffff);
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L1, 0);
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L2, 0);
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L3, 0);
+#endif
+
+ if (cam->previewing || cam->streaming) {
+ /* Preview or capture is in progress, so we need to register
+ * our routine to restart the camera interface the next time a
+ * DMA transfer is queued.
+ */
+ omap24xxcam_dma_notify(cam, omap24xxcam_cc_enable);
+ }
+
+ /* Restart overlay DMA if preview is enabled. */
+ omap24xxcam_start_overlay_dma(cam);
+
+ /* Restart the scatter-gather DMA queue. */
+ omap24xxcam_sg_dma_process(cam);
+}
+
+/* Interrupt service routine for camera core interrupts. */
+static void omap24xxcam_cc_isr(struct omap24xxcam_device *cam)
+{
+ unsigned long cc_irqstatus;
+ const unsigned long cc_irqstatus_err = CC_IRQSTATUS_FW_ERR_IRQ
+ | CC_IRQSTATUS_FSC_ERR_IRQ | CC_IRQSTATUS_SSC_ERR_IRQ
+ | CC_IRQSTATUS_FIFO_OF_IRQ;
+
+ cc_irqstatus = cc_reg_in(cam, CC_IRQSTATUS);
+ cc_reg_out(cam, CC_IRQSTATUS, cc_irqstatus);
+
+ if (cc_irqstatus & cc_irqstatus_err)
+ omap24xxcam_error_handler(cam);
+}
+
+static irqreturn_t omap24xxcam_isr(int irq, void *arg, struct pt_regs *regs)
+{
+ struct omap24xxcam_device *cam = (struct omap24xxcam_device *)arg;
+ unsigned long irqstatus;
+ unsigned int irqhandled = 0;
+
+ irqstatus = cam_reg_in(cam, CAM_IRQSTATUS);
+ if (irqstatus &
+ (CAM_IRQSTATUS_DMA_IRQ2 | CAM_IRQSTATUS_DMA_IRQ1
+ | CAM_IRQSTATUS_DMA_IRQ0)) {
+ omap24xxcam_dma_isr(cam);
+ irqhandled = 1;
+ }
+ if (irqstatus & CAM_IRQSTATUS_CC_IRQ) {
+ omap24xxcam_cc_isr(cam);
+ irqhandled = 1;
+ }
+ if (irqstatus & CAM_IRQSTATUS_MMU_IRQ)
+ printk(KERN_ERR CAM_NAME ": Unhandled camera MMU interrupt!\n");
+
+ return IRQ_RETVAL(irqhandled);
+}
+
+static void omap24xxcam_adjust_xclk(struct omap24xxcam_device *cam)
+{
+ unsigned long divisor;
+
+ DBG;
+
+ if (cam->xclk > cam->mclk)
+ cam->xclk = cam->mclk;
+ divisor = cam->mclk / cam->xclk;
+ if (cam->xclk * divisor < cam->mclk)
+ divisor += 1;
+ if (divisor > 30)
+ divisor = 30;
+
+ cam->xclk = cam->mclk / divisor;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* This routine is called from interrupt context when a scatter-gather DMA
+ * transfer of a videobuf_buffer completes.
+ */
+static void
+omap24xxcam_vbq_complete(struct omap24xxcam_device *cam, unsigned long csr,
+ void *arg)
+{
+ struct videobuf_buffer *vb = (struct videobuf_buffer *)arg;
+ const unsigned long csr_error = CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+ DBG;
+
+ spin_lock(&cam->vbq_lock);
+
+ do_gettimeofday(&vb->ts);
+ vb->field_count = cam->field_count;
+ cam->field_count += 2;
+ if (csr & csr_error) {
+ vb->state = STATE_ERROR;
+ omap24xxcam_error_handler(cam);
+ } else
+ vb->state = STATE_DONE;
+ wake_up(&vb->done);
+ spin_unlock(&cam->vbq_lock);
+}
+
+static void
+omap24xxcam_vbq_release(struct videobuf_queue *vbq, struct videobuf_buffer *vb)
+{
+ DBG;
+
+ videobuf_waiton(vb, 0, 0);
+ videobuf_dma_pci_unmap(NULL, &vb->dma);
+ videobuf_dma_free(&vb->dma);
+
+ vb->state = STATE_NEEDS_INIT;
+}
+
+/* Limit the number of available kernel image capture buffers based on the
+ * number requested, the currently selected image size, and the maximum
+ * amount of memory permitted for kernel capture buffers.
+ */
+static int
+omap24xxcam_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt,
+ unsigned int *size)
+{
+ struct omap24xxcam_fh *fh = vbq->priv_data;
+ struct omap24xxcam_device *cam = fh->cam;
+
+ DBG;
+
+ if (*cnt <= 0)
+ *cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */
+
+ if (*cnt > VIDEO_MAX_FRAME)
+ *cnt = VIDEO_MAX_FRAME;
+
+ spin_lock(&cam->img_lock);
+
+ *size = cam->pix.sizeimage;
+
+ spin_unlock(&cam->img_lock);
+
+ while (*size * *cnt > capture_mem)
+ (*cnt)--;
+
+ return 0;
+}
+
+static int
+omap24xxcam_vbq_prepare(struct videobuf_queue *vbq, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct omap24xxcam_fh *fh = vbq->priv_data;
+ struct omap24xxcam_device *cam = fh->cam;
+ int err = 0;
+
+ DBG;
+
+ spin_lock(&cam->img_lock);
+
+ if (vb->baddr) {
+ /* This is a userspace buffer. */
+ if (cam->pix.sizeimage > vb->bsize) {
+ /* The buffer isn't big enough. */
+ err = -EINVAL;
+ } else
+ vb->size = cam->pix.sizeimage;
+ } else if (!vb->baddr) {
+ if (vb->state != STATE_NEEDS_INIT) {
+ /* We have a kernel bounce buffer that has already been
+ * allocated.
+ */
+ if (cam->pix.sizeimage > vb->size) {
+ /* The image size has been changed to a larger
+ * size since this buffer was allocated, so we
+ * need to free and reallocate it.
+ */
+ spin_unlock(&cam->img_lock);
+ omap24xxcam_vbq_release(vbq, vb);
+ spin_lock(&cam->img_lock);
+ vb->size = cam->pix.sizeimage;
+ }
+ } else {
+ /* We need to allocate a new kernel bounce buffer. */
+ vb->size = cam->pix.sizeimage;
+ }
+ }
+
+ vb->width = cam->pix.width;
+ vb->height = cam->pix.height;
+ vb->field = field;
+
+ spin_unlock(&cam->img_lock);
+
+ if (err)
+ return err;
+
+ if (vb->state == STATE_NEEDS_INIT)
+ err = videobuf_iolock(NULL, vb, NULL);
+
+ if (!err)
+ vb->state = STATE_PREPARED;
+ else
+ omap24xxcam_vbq_release(vbq, vb);
+
+ return err;
+}
+
+static void
+omap24xxcam_vbq_queue(struct videobuf_queue *vbq, struct videobuf_buffer *vb)
+{
+ struct omap24xxcam_fh *fh = vbq->priv_data;
+ struct omap24xxcam_device *cam = fh->cam;
+ enum videobuf_state state = vb->state;
+ int err;
+
+ DBG;
+
+ vb->state = STATE_QUEUED;
+ err = omap24xxcam_sg_dma_queue(cam, vb->dma.sglist, vb->dma.sglen,
+ omap24xxcam_vbq_complete, vb);
+ if (err) {
+ /* Oops. We're not supposed to get any errors here. The only
+ * way we could get an error is if we ran out of scatter-gather
+ * DMA slots, but we are supposed to have at least as many
+ * scatter-gather DMA slots as video buffers so that can't
+ * happen.
+ */
+ printk(KERN_DEBUG CAM_NAME
+ ": Failed to queue a video buffer for DMA!\n");
+ vb->state = state;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int
+omap24xxcam_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ void *arg)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ struct omap24xxcam_device *cam = fh->cam;
+ int err;
+
+ DBG;
+
+ switch (cmd) {
+ /* for time being below IOCTL cmd is here */
+
+ case VIDIOC_ENUMINPUT:
+ {
+ /* default handler assumes 1 video input (the camera) */
+ struct v4l2_input *input = (struct v4l2_input *)arg;
+ int index = input->index;
+
+ memset(input, 0, sizeof(*input));
+ input->index = index;
+
+ if (index > 0)
+ return -EINVAL;
+
+ strlcpy(input->name, "camera", sizeof(input->name));
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+
+ return 0;
+ }
+
+ case VIDIOC_G_INPUT:
+ {
+ unsigned int *input = arg;
+ *input = 0;
+
+ return 0;
+ }
+
+ case VIDIOC_S_INPUT:
+ {
+ unsigned int *input = arg;
+
+ if (*input > 0)
+ return -EINVAL;
+
+ return 0;
+ }
+
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *cap =
+ (struct v4l2_capability *)arg;
+
+ memset(cap, 0, sizeof(*cap));
+ strlcpy(cap->driver, CAM_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, cam->vfd->name, sizeof(cap->card));
+ cap->bus_info[0] = '\0';
+ cap->version = KERNEL_VERSION(0, 0, 0);
+ cap->capabilities =
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_VIDEO_OVERLAY |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ return 0;
+ }
+
+ case VIDIOC_G_FMT:
+ {
+ struct v4l2_format *f = (struct v4l2_format *)arg;
+
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ {
+ struct v4l2_pix_format *pix =
+ &f->fmt.pix;
+ memset(pix, 0, sizeof(*pix));
+ spin_lock(&cam->img_lock);
+ *pix = cam->pix;
+ spin_unlock(&cam->img_lock);
+ return 0;
+ }
+
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ {
+ struct v4l2_window *win = &f->fmt.win;
+ memset(win, 0, sizeof(*win));
+ /* The API has a bit of a problem here.
+ * We're returning a v4l2_window
+ * structure, but that structure
+ * contains pointers to variable-sized
+ * objects for clipping rectangles and
+ * clipping bitmaps. We will just
+ * return NULLs for those pointers.
+ */
+ spin_lock(&cam->img_lock);
+ win->w = cam->win.w;
+ win->field = cam->win.field;
+ win->chromakey = cam->win.chromakey;
+ spin_unlock(&cam->img_lock);
+ return 0;
+ }
+
+ default:
+ {
+ return -EINVAL;
+ }
+ }
+ }
+
+ case VIDIOC_TRY_FMT:
+ {
+ struct v4l2_format *f = (struct v4l2_format *)arg;
+
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ {
+ struct v4l2_window *win = &f->fmt.win;
+
+ spin_lock(&cam->img_lock);
+ err =
+ omap24xxcam_try_preview_window(cam,
+ win);
+ spin_unlock(&cam->img_lock);
+ return err;
+ }
+
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ {
+ return cam->cam_sensor->try_format(&f->
+ fmt.
+ pix,
+ cam->
+ sensor);
+ }
+
+ default:
+ {
+ return -EINVAL;
+ }
+ }
+ }
+
+ case VIDIOC_S_FMT:
+ {
+ struct v4l2_format *f = (struct v4l2_format *)arg;
+
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ {
+ struct v4l2_window *win = &f->fmt.win;
+
+ spin_lock(&cam->img_lock);
+ if (cam->previewing) {
+ spin_unlock(&cam->img_lock);
+ return -EBUSY;
+ }
+ err =
+ omap24xxcam_new_preview_window(cam,
+ win);
+ spin_unlock(&cam->img_lock);
+ return err;
+ }
+
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ {
+ spin_lock(&cam->img_lock);
+ if (cam->streaming || cam->previewing) {
+ spin_unlock(&cam->img_lock);
+ return -EBUSY;
+ }
+ cam->cam_sensor->try_format(&f->fmt.pix,
+ cam->
+ sensor);
+ /* set the new capture format */
+ cam->pix = f->fmt.pix;
+ /* adjust the capture frame rate */
+ cam->xclk =
+ cam->cam_sensor->calc_xclk(&cam->
+ pix,
+ &cam->
+ nominal_timeperframe,
+ cam->
+ sensor);
+ omap24xxcam_adjust_xclk(cam);
+ cam->cparm.timeperframe =
+ cam->nominal_timeperframe;
+ /* intialize the preview parameters */
+ omap24xxcam_new_capture_format(cam);
+ spin_unlock(&cam->img_lock);
+ /* program xclk */
+ omap24xxcam_set_xclk(cam);
+ /* program the sensor */
+ err =
+ cam->cam_sensor->configure(&cam->
+ pix,
+ cam->
+ xclk,
+ &cam->
+ cparm.
+ timeperframe,
+ cam->
+ sensor);
+ return err;
+ }
+
+ default:
+ {
+ return -EINVAL;
+ }
+ }
+ }
+
+ case VIDIOC_G_FBUF:
+ {
+ struct v4l2_framebuffer *fbuf =
+ (struct v4l2_framebuffer *)arg;
+
+ spin_lock(&cam->img_lock);
+ *fbuf = cam->fbuf;
+ spin_unlock(&cam->img_lock);
+ return 0;
+ }
+
+ case VIDIOC_S_FBUF:
+ {
+ struct v4l2_framebuffer *fbuf =
+ (struct v4l2_framebuffer *)arg;
+ unsigned int flags = fbuf->flags;
+
+ /* The only field the user is allowed to change is
+ * fbuf->flags.
+ */
+ spin_lock(&cam->img_lock);
+ if (cam->previewing) {
+ spin_unlock(&cam->img_lock);
+ return -EBUSY;
+ }
+ if (flags & V4L2_FBUF_FLAG_CHROMAKEY)
+ cam->fbuf.flags |= V4L2_FBUF_FLAG_CHROMAKEY;
+ else
+ cam->fbuf.flags &= ~V4L2_FBUF_FLAG_CHROMAKEY;
+ spin_unlock(&cam->img_lock);
+ return 0;
+ }
+
+ case VIDIOC_CROPCAP:
+ {
+ struct v4l2_cropcap *cropcap =
+ (struct v4l2_cropcap *)arg;
+ enum v4l2_buf_type type = cropcap->type;
+
+ memset(cropcap, 0, sizeof(*cropcap));
+ cropcap->type = type;
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ {
+ struct v4l2_pix_format *pix = &cam->pix;
+
+ spin_lock(&cam->img_lock);
+ cropcap->bounds.width = pix->width & ~1;
+ cropcap->bounds.height =
+ pix->height & ~1;
+ omap24xxcam_default_crop_rect(cam,
+ &cropcap->
+ defrect);
+ spin_unlock(&cam->img_lock);
+ cropcap->pixelaspect.numerator = 1;
+ cropcap->pixelaspect.denominator = 1;
+ return 0;
+ }
+
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ {
+ /* We're required to support the CROPCAP
+ * ioctl even though the G_CROP/S_CROP
+ * ioctls are optional, which seems a
+ * little strange. We don't support
+ * cropping of captured images.
+ */
+ spin_lock(&cam->img_lock);
+ cropcap->bounds.width = cam->pix.width;
+ cropcap->bounds.height =
+ cam->pix.height;
+ spin_unlock(&cam->img_lock);
+ cropcap->defrect.width =
+ cropcap->bounds.width;
+ cropcap->defrect.height =
+ cropcap->bounds.height;
+ cropcap->pixelaspect.numerator = 1;
+ cropcap->pixelaspect.denominator = 1;
+ return 0;
+ }
+
+ default:
+ {
+ return -EINVAL;
+ }
+ }
+ }
+
+ case VIDIOC_G_CROP:
+ {
+ struct v4l2_crop *crop = (struct v4l2_crop *)arg;
+
+ switch (crop->type) {
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ {
+ spin_lock(&cam->img_lock);
+ crop->c = cam->crop;
+ spin_unlock(&cam->img_lock);
+ return 0;
+ }
+
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ {
+ /* We don't support cropping of captured
+ * images.
+ */
+ return -EINVAL;
+ }
+
+ default:
+ {
+ return -EINVAL;
+ }
+ }
+ }
+
+ case VIDIOC_S_CROP:
+ {
+ struct v4l2_crop *crop = (struct v4l2_crop *)arg;
+
+ switch (crop->type) {
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ {
+ spin_lock(&cam->img_lock);
+ if (cam->previewing) {
+ spin_unlock(&cam->img_lock);
+ return -EBUSY;
+ }
+ err = omap24xxcam_new_crop_rect(cam,
+ &crop->
+ c);
+ spin_unlock(&cam->img_lock);
+ return err;
+ }
+
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ {
+ /* We don't support cropping of captured
+ * images.
+ */
+ return -EINVAL;
+ }
+
+ default:
+ {
+ return -EINVAL;
+ }
+ }
+ }
+
+ case VIDIOC_G_PARM:
+ {
+ struct v4l2_streamparm *parm =
+ (struct v4l2_streamparm *)arg;
+ enum v4l2_buf_type type = parm->type;
+
+ memset(parm, 0, sizeof(*parm));
+ parm->type = type;
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ spin_lock(&cam->img_lock);
+ parm->parm.capture = cam->cparm;
+ spin_unlock(&cam->img_lock);
+ return 0;
+ }
+
+ case VIDIOC_S_PARM:
+ {
+ struct v4l2_streamparm *parm =
+ (struct v4l2_streamparm *)arg;
+ struct v4l2_captureparm *cparm = &parm->parm.capture;
+
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ spin_lock(&cam->img_lock);
+ if (cam->streaming || cam->previewing) {
+ spin_unlock(&cam->img_lock);
+ return -EBUSY;
+ }
+ cam->cparm.capturemode = cparm->capturemode;
+ if (cparm->timeperframe.numerator
+ && cparm->timeperframe.denominator) {
+ cam->nominal_timeperframe = cparm->timeperframe;
+ /* adjust the capture frame rate */
+ cam->xclk =
+ cam->cam_sensor->calc_xclk(&cam->pix,
+ &cam->
+ nominal_timeperframe,
+ cam->sensor);
+ omap24xxcam_adjust_xclk(cam);
+ cam->cparm.timeperframe =
+ cam->nominal_timeperframe;
+ spin_unlock(&cam->img_lock);
+ /* program xclk */
+ omap24xxcam_set_xclk(cam);
+ /* program the sensor */
+ err =
+ cam->cam_sensor->configure(&cam->pix,
+ cam->xclk,
+ &cam->cparm.
+ timeperframe,
+ cam->sensor);
+ } else {
+ spin_unlock(&cam->img_lock);
+ }
+ return 0;
+ }
+
+ case VIDIOC_OVERLAY:
+ {
+ int *on = arg;
+
+ spin_lock(&cam->img_lock);
+
+ if (!cam->previewing && *on) {
+ if (cam->pix.sizeimage <= cam->overlay_size) {
+ /* Turn on the overlay window */
+ omap24xxcam_configure_overlay(cam,
+ NULL);
+ omap24xxcam_flip_overlay(cam,
+ cam->
+ overlay_base_phys);
+ cam->previewing = fh;
+ spin_unlock(&cam->img_lock);
+ /* start the camera interface */
+ omap24xxcam_dma_notify(cam,
+ omap24xxcam_cc_enable);
+ omap24xxcam_start_overlay_dma(cam);
+ } else {
+ /* Image size is bigger than overlay
+ * buffer.
+ */
+ omap24xxcam_disable_vlayer(cam,
+ cam->vid1);
+ spin_unlock(&cam->img_lock);
+ return -EINVAL;
+ }
+ } else if (!*on) {
+ /* turn overlay off */
+ omap24xxcam_disable_vlayer(cam, cam->vid1);
+ cam->previewing = NULL;
+ spin_unlock(&cam->img_lock);
+ } else
+ spin_unlock(&cam->img_lock);
+
+ return 0;
+ }
+
+ case VIDIOC_REQBUFS:
+ return videobuf_reqbufs(&fh->vbq, arg);
+
+ case VIDIOC_QUERYBUF:
+ return videobuf_querybuf(&fh->vbq, arg);
+
+ case VIDIOC_QBUF:
+ return videobuf_qbuf(&fh->vbq, arg);
+
+ case VIDIOC_DQBUF:
+ return videobuf_dqbuf(&fh->vbq, arg,
+ file->f_flags & O_NONBLOCK);
+
+ case VIDIOC_STREAMON:
+ {
+ spin_lock(&cam->img_lock);
+ if (cam->streaming) {
+ spin_unlock(&cam->img_lock);
+ return -EBUSY;
+ } else
+ cam->streaming = fh;
+ spin_unlock(&cam->img_lock);
+
+ omap24xxcam_dma_notify(cam, omap24xxcam_cc_enable);
+ return videobuf_streamon(&fh->vbq);
+ }
+
+ case VIDIOC_STREAMOFF:
+ {
+ struct videobuf_queue *q = &fh->vbq;
+ int i;
+
+ /* video-buf lib has trouble to turn off streaming while
+ any buffer is still in QUEUED state. Let's wait until
+ all queued buffers are filled.
+ */
+ for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ if (NULL == q->bufs[i])
+ continue;
+ while (q->bufs[i]->state == STATE_QUEUED) ;
+ }
+
+ err = videobuf_streamoff(q);
+ if (err < 0)
+ return err;
+
+ spin_lock(&cam->img_lock);
+ if (cam->streaming == fh)
+ cam->streaming = NULL;
+ spin_unlock(&cam->img_lock);
+ return 0;
+ }
+
+ case VIDIOC_G_CTRL:
+ case VIDIOC_S_CTRL:
+ case VIDIOC_QUERYCTRL:
+ case VIDIOC_QUERYMENU:
+ {
+ /* no controls have been implemented yet */
+ return -EINVAL;
+ }
+
+ case VIDIOC_ENUMSTD:
+ case VIDIOC_G_STD:
+ case VIDIOC_S_STD:
+ case VIDIOC_QUERYSTD:
+ {
+ /* Digital cameras don't have an analog video standard,
+ * so we don't need to implement these ioctls.
+ */
+ return -EINVAL;
+ }
+
+ case VIDIOC_G_AUDIO:
+ case VIDIOC_S_AUDIO:
+ case VIDIOC_G_AUDOUT:
+ case VIDIOC_S_AUDOUT:
+ {
+ /* we don't have any audio inputs or outputs */
+ return -EINVAL;
+ }
+
+ case VIDIOC_G_JPEGCOMP:
+ case VIDIOC_S_JPEGCOMP:
+ {
+ /* JPEG compression is not supported */
+ return -EINVAL;
+ }
+
+ case VIDIOC_G_TUNER:
+ case VIDIOC_S_TUNER:
+ case VIDIOC_G_MODULATOR:
+ case VIDIOC_S_MODULATOR:
+ case VIDIOC_G_FREQUENCY:
+ case VIDIOC_S_FREQUENCY:
+ {
+ /* we don't have a tuner or modulator */
+ return -EINVAL;
+ }
+
+ case VIDIOC_ENUMOUTPUT:
+ case VIDIOC_G_OUTPUT:
+ case VIDIOC_S_OUTPUT:
+ {
+ /* we don't have any video outputs */
+ return -EINVAL;
+ }
+
+ case VIDIOC_ENUM_FMT:
+ {
+ struct v4l2_fmtdesc *fmt = arg;
+ return cam->cam_sensor->enum_pixformat(fmt,
+ cam->sensor);
+ }
+ case VIDIOC_S_VID2:
+ {
+ /* this api will set the parameters of video layer 2
+ ** of DISPC to display to use video 2 layer pipeline
+ ** to use hardware color conversion block to display
+ ** YUV422 format data on LCD
+ **/
+ struct omap24xx_vid2_format *vid2_format =
+ (struct omap24xx_vid2_format *)arg;
+
+ omap24xxcam_configure_overlay(cam, vid2_format);
+ return 0;
+ }
+
+ case VIDIOC_S_VID2_DISABLE:
+ {
+ omap24xxcam_disable_vlayer(cam, cam->vid2);
+ return 0;
+ }
+
+ default:
+ {
+ /* unrecognized ioctl */
+ return -ENOIOCTLCMD;
+ }
+ }
+
+ return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+ /*
+ * file operations
+ */
+
+static unsigned
+int omap24xxcam_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ struct omap24xxcam_device *cam = fh->cam;
+ struct videobuf_buffer *vb;
+ enum v4l2_field field;
+
+ DBG;
+
+ spin_lock(&cam->img_lock);
+
+ if (cam->streaming == fh) {
+ spin_unlock(&cam->img_lock);
+ /* streaming capture */
+ if (list_empty(&fh->vbq.stream))
+ return POLLERR;
+ vb = list_entry(fh->vbq.stream.next, struct videobuf_buffer,
+ stream);
+ } else if (cam->streaming) {
+ /* streaming I/O is in progress on another file descriptor */
+ spin_unlock(&cam->img_lock);
+ return POLLERR;
+ } else {
+ /* read() capture */
+ spin_unlock(&cam->img_lock);
+ down(&fh->vbq.lock);
+ if (fh->vbq.read_buf == NULL) {
+ /* need to capture a new image */
+ fh->vbq.read_buf = videobuf_alloc(fh->vbq.msize);
+ if (fh->vbq.read_buf == NULL) {
+ up(&fh->vbq.lock);
+ return POLLERR;
+ }
+ fh->vbq.read_buf->memory = V4L2_MEMORY_USERPTR;
+ field = videobuf_next_field(&fh->vbq);
+ if (fh->vbq.ops->buf_prepare(&fh->vbq, fh->vbq.read_buf,
+ field) != 0) {
+ up(&fh->vbq.lock);
+ return POLLERR;
+ }
+ omap24xxcam_dma_notify(cam, omap24xxcam_cc_enable);
+ fh->vbq.ops->buf_queue(&fh->vbq, fh->vbq.read_buf);
+ fh->vbq.read_off = 0;
+ }
+ up(&fh->vbq.lock);
+ vb = (struct videobuf_buffer *)fh->vbq.read_buf;
+ }
+
+ omap24xxcam_dma_notify(cam, omap24xxcam_cc_enable);
+ poll_wait(file, &vb->done, wait);
+ if (vb->state == STATE_DONE || vb->state == STATE_ERROR)
+ return POLLIN | POLLRDNORM;
+
+ return 0;
+}
+
+static ssize_t
+omap24xxcam_read(struct file *file, char *data, size_t count, loff_t * ppos)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ struct omap24xxcam_device *cam = fh->cam;
+ int err;
+
+ DBG;
+
+ spin_lock(&cam->img_lock);
+ if (cam->streaming) {
+ spin_unlock(&cam->img_lock);
+ return -EBUSY;
+ }
+ spin_unlock(&cam->img_lock);
+
+ omap24xxcam_dma_notify(cam, omap24xxcam_cc_enable);
+
+ /* **HACK**for some strange reason, dma'ing directly to user
+ ** buffer gives syncing error, we will use kernel bounce buffer
+ ** to capture the image pretending that we want to read one pixel
+ ** less than the actual image size.
+ */
+ err =
+ videobuf_read_one(&fh->vbq, data, count - 2, ppos,
+ file->f_flags & O_NONBLOCK);
+
+ DBG_END;
+
+ return err;
+}
+static ssize_t
+omap24xxcam_write(struct file *file, const char *data, size_t count,
+ loff_t * ppos)
+{
+ unsigned long vid_attributes;
+ struct omap24xxcam_fh *fh = file->private_data;
+ struct omap24xxcam_device *cam = fh->cam;
+
+ DBG;
+
+ vid_attributes = dispc_reg_merge(cam, DISPC_VID_ATTRIBUTES(1),
+ DISPC_VID_ATTRIBUTES_ENABLE,
+ DISPC_VID_ATTRIBUTES_ENABLE);
+ if (vid_attributes & DISPC_VID_ATTRIBUTES_VIDCHANNELOUT) {
+ /* digital output */
+ dispc_reg_merge(cam, DISPC_CONTROL, DISPC_CONTROL_GODIGITAL,
+ DISPC_CONTROL_GODIGITAL);
+ } else {
+ /* LCD */
+ dispc_reg_merge(cam, DISPC_CONTROL, DISPC_CONTROL_GOLCD,
+ DISPC_CONTROL_GOLCD);
+ }
+ if (copy_from_user((void *)cam->video2_base, data, count)) {
+ printk("error in copying data");
+ }
+ return count;
+}
+
+static int omap24xxcam_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+
+ return videobuf_mmap_mapper(&fh->vbq, vma);
+}
+
+static int
+omap24xxcam_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return video_usercopy(inode, file, cmd, arg, omap24xxcam_do_ioctl);
+}
+
+/*
+ * Do some sanity check, set clock rate, starts it and
+ * turn codec audio on
+ */
+int omap24xxcam_clock_on(void)
+{
+
+ clk_enable(cam_fck);
+ clk_enable(cam_ick);
+
+ printk(KERN_DEBUG
+ "FCLK = %d [%d], usecount = %d\n",
+ (uint) clk_get_rate(cam_fck), CAM_CLOCK,
+ clk_get_usecount(cam_fck));
+
+ return 0;
+}
+
+/*
+ * Do some sanity check, turn clock off and then turn
+ * codec audio off
+ */
+int omap24xxcam_clock_off(void)
+{
+ if (clk_get_usecount(cam_fck) > 0) {
+ if (clk_get_rate(cam_fck) != CAM_CLOCK) {
+ printk(KERN_WARNING
+ "FCLK for camera should be %d Hz. But is %d Hz\n",
+ (uint) clk_get_rate(cam_fck), CAM_CLOCK);
+ }
+
+ clk_disable(cam_fck);
+ clk_disable(cam_ick);
+ }
+
+ return 0;
+}
+
+static int omap24xxcam_release(struct inode *inode, struct file *file)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ struct omap24xxcam_device *cam = fh->cam;
+
+ DBG;
+
+ spin_lock(&cam->img_lock);
+ /* turn off overlay */
+ if (cam->previewing == fh) {
+ cam->previewing = NULL;
+ spin_unlock(&cam->img_lock);
+ omap24xxcam_disable_vlayer(cam, cam->vid1);
+ spin_lock(&cam->img_lock);
+ }
+
+ /* stop streaming capture */
+ if (cam->streaming == fh) {
+ cam->streaming = NULL;
+ spin_unlock(&cam->img_lock);
+ videobuf_streamoff(&fh->vbq);
+ spin_lock(&cam->img_lock);
+ }
+ spin_unlock(&cam->img_lock);
+
+ /* release read_buf videobuf_buffer struct */
+ if (fh->vbq.read_buf) {
+ omap24xxcam_vbq_release(&fh->vbq, fh->vbq.read_buf);
+ kfree(fh->vbq.read_buf);
+ }
+
+ file->private_data = NULL;
+ kfree(fh);
+
+ return 0;
+}
+
+static int omap24xxcam_open(struct inode *inode, struct file *file)
+{
+ int minor = iminor(inode);
+ struct omap24xxcam_device *cam = saved_cam;
+ struct omap24xxcam_fh *fh;
+
+ DBG;
+
+ if (!cam || !cam->vfd || (cam->vfd->minor != minor))
+ return -ENODEV;
+
+ /* allocate per-filehandle data */
+ fh = kmalloc(sizeof(*fh), GFP_KERNEL);
+ if (NULL == fh)
+ return -ENOMEM;
+ file->private_data = fh;
+ fh->cam = cam;
+ fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ videobuf_queue_init(&fh->vbq, &cam->vbq_ops, NULL, &cam->vbq_lock,
+ fh->type, V4L2_FIELD_NONE,
+ sizeof(struct videobuf_buffer), fh);
+
+ return 0;
+}
+
+static struct file_operations omap24xxcam_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .read = omap24xxcam_read,
+ .write = omap24xxcam_write,
+ .poll = omap24xxcam_poll,
+ .ioctl = omap24xxcam_ioctl,
+ .mmap = omap24xxcam_mmap,
+ .open = omap24xxcam_open,
+ .release = omap24xxcam_release,
+};
+
+/* -------------------------------------------------------------------------- */
+static int omap24xxcam_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
+
+ DBG;
+
+ /* disable previewing */
+ spin_lock(&cam->img_lock);
+ if (cam->previewing) {
+ /* turn overlay off */
+ omap24xxcam_disable_vlayer(cam, cam->vid1);
+ cam->previewing = NULL;
+ }
+ spin_unlock(&cam->img_lock);
+
+ /* Get the CC_CTRL register value for the current capture format. */
+ omap24xxcam_sensor_cc_ctrl(cam);
+
+ /* Disable the camera interface. */
+ cc_reg_out(cam, CC_CTRL,
+ cam->cc_ctrl & ~(CC_CTRL_CC_EN | CC_CTRL_CC_FRAME_TRIG));
+
+ /* Stop the DMA controller and frame sync scatter-gather DMA. */
+ omap24xxcam_sg_dma_sync(cam, CAMDMA_CSR_TRANS_ERR);
+
+ /* stop XCLK */
+ cc_reg_out(cam, CC_CTRL_XCLK, CC_CTRL_XCLK_DIV_STABLE_LOW);
+
+ /* power down the sensor */
+ cam->cam_sensor->power_off(cam->sensor);
+
+ return 0;
+}
+static int omap24xxcam_resume(struct platform_device *pdev)
+{
+ struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
+
+ DBG;
+
+ /* power up the sensor */
+ cam->cam_sensor->power_on(cam->sensor);
+
+ /* set XCLK */
+ omap24xxcam_set_xclk(cam);
+
+ if (cam->streaming) {
+ /* capture was in progress, so we need to register
+ * our routine to restart the camera interface the next time a
+ * DMA transfer is queued.
+ */
+ omap24xxcam_dma_notify(cam, omap24xxcam_cc_enable);
+ }
+
+ /* Restart the scatter-gather DMA queue. */
+ omap24xxcam_sg_dma_process(cam);
+
+ /* camera interface will be enabled through dma_notify function
+ ** automatically when new dma starts
+ */
+
+ return 0;
+}
+
+static int omap24xxcam_probe(struct platform_device *pdev)
+{
+ struct omap24xxcam_device *cam;
+ struct video_device *vfd;
+
+ DBG;
+
+ cam = kmalloc(sizeof(struct omap24xxcam_device), GFP_KERNEL);
+ if (!cam) {
+ printk(KERN_ERR CAM_NAME ": could not allocate memory\n");
+ goto init_error;
+ }
+ memset(cam, 0, sizeof(struct omap24xxcam_device));
+ saved_cam = cam;
+
+ /* initialize the video_device struct */
+ vfd = cam->vfd = video_device_alloc();
+ if (!vfd) {
+ printk(KERN_ERR CAM_NAME
+ ": could not allocate video device struct\n");
+ goto init_error;
+ }
+ vfd->release = video_device_release;
+#ifdef FIXME_FIXME
+/* If the dev fields are not initlized (parent and such) sysfs will crash you
+ * when it tries to set you up....most drivers seem to chain in the info their
+ * parent bus gave them. Getting this associated right is likely necessary for power
+ * mangement.
+ */
+ vfd->dev = &cam->dev;
+#endif
+ strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));
+ vfd->type = VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CHROMAKEY;
+ /* need to register for a VID_HARDWARE_* ID in videodev.h */
+ vfd->hardware = 0;
+ vfd->fops = &omap24xxcam_fops;
+ video_set_drvdata(vfd, cam);
+ vfd->minor = -1;
+
+ /* initialize the videobuf queue ops */
+ cam->vbq_ops.buf_setup = omap24xxcam_vbq_setup;
+ cam->vbq_ops.buf_prepare = omap24xxcam_vbq_prepare;
+ cam->vbq_ops.buf_queue = omap24xxcam_vbq_queue;
+ cam->vbq_ops.buf_release = omap24xxcam_vbq_release;
+ spin_lock_init(&cam->vbq_lock);
+
+ /* Impose a lower limit on the amount of memory allocated for capture.
+ * We require at least enough memory to double-buffer QVGA (300KB).
+ */
+ if (capture_mem < 320 * 240 * 2 * 2)
+ capture_mem = 320 * 240 * 2 * 2;
+
+ /* request the mem region for the camera registers */
+ if (!request_mem_region(CAM_REG_BASE, CAM_REG_SIZE, vfd->name)) {
+ printk(KERN_ERR CAM_NAME
+ ": cannot reserve camera register I/O region\n");
+ goto init_error;
+ }
+ cam->cam_mmio_base_phys = CAM_REG_BASE;
+ cam->cam_mmio_size = CAM_REG_SIZE;
+
+ /* map the region */
+ cam->cam_mmio_base = (unsigned long)
+ ioremap(cam->cam_mmio_base_phys, cam->cam_mmio_size);
+ if (!cam->cam_mmio_base) {
+ printk(KERN_ERR CAM_NAME
+ ": cannot map camera register I/O region\n");
+ goto init_error;
+ }
+
+ /* Map the display controller registers.
+ * Note that we do not request the memory region first, because the
+ * framebuffer driver will already have claimed this region and the
+ * request would fail.
+ */
+ cam->dispc_mmio_base_phys = DSS_REG_BASE;
+ cam->dispc_mmio_size = DSS_REG_SIZE;
+ cam->dispc_mmio_base = (unsigned long)
+ ioremap(cam->dispc_mmio_base_phys, cam->dispc_mmio_size);
+ if (!cam->dispc_mmio_base) {
+ printk(KERN_ERR CAM_NAME
+ ": cannot map display controller register I/O region\n");
+ goto init_error;
+ }
+
+ /* allocate coherent memory for the overlay framebuffer */
+ cam->overlay_size = overlay_mem;
+ if (cam->overlay_size > 0) {
+ cam->overlay_base = (unsigned long)dma_alloc_coherent(NULL,
+ cam->
+ overlay_size,
+ (dma_addr_t
+ *) &
+ cam->
+ overlay_base_phys,
+ GFP_KERNEL
+ |
+ GFP_DMA);
+ if (!cam->overlay_base) {
+ printk(KERN_ERR CAM_NAME
+ ": cannot allocate overlay framebuffer\n");
+ goto init_error;
+ }
+ }
+ memset((void *)cam->overlay_base, 0, cam->overlay_size);
+
+ cam->video2_size = video2_mem;
+ if (cam->video2_size > 0) {
+ cam->video2_base = (unsigned long)dma_alloc_coherent(NULL,
+ cam->
+ video2_size,
+ (dma_addr_t
+ *) & cam->
+ video2_base_phys,
+ GFP_KERNEL
+ | GFP_DMA);
+ if (!cam->video2_base) {
+ printk(KERN_ERR CAM_NAME
+ ": cannot allocate video2 layer memory\n");
+ goto init_error;
+
+ }
+ }
+ memset((void *)cam->video2_base, 0, cam->video2_size);
+
+ /* initialize the overlay spinlock */
+ spin_lock_init(&cam->overlay_lock);
+
+ /* initialize the camera interface */
+ cam_init(cam);
+
+ /* initialize the spinlock used to serialize access to the image
+ * parameters
+ */
+ spin_lock_init(&cam->img_lock);
+ cam->cam_sensor = &camera_sensor_if;
+
+ /* initialize the camera interface functional clock frequency */
+ cam->mclk = 96000000; /* 96MHz */
+ cam_fck = clk_get(0, "cam_fck");
+ cam_ick = clk_get(0, "cam_ick");
+ omap24xxcam_clock_on();
+
+ /* initialize the streaming capture parameters */
+ cam->cparm.readbuffers = 1;
+ cam->cparm.capability = V4L2_CAP_TIMEPERFRAME;
+
+ /* Enable the xclk output. The sensor may (and does, in the case of
+ * the OV9640) require an xclk input in order for its initialization
+ * routine to work.
+ */
+ cam->xclk = 12000000; /* choose an arbitrary xclk frequency */
+ omap24xxcam_set_xclk(cam);
+
+ /* get the framebuffer parameters in case the sensor init routine
+ * needs them
+ */
+ omap24xxcam_g_fbuf(cam);
+
+ /* select an arbitrary default capture frame rate of 5fps */
+ cam->nominal_timeperframe.numerator = 1;
+ cam->nominal_timeperframe.denominator = 15;
+
+ /* initialize the sensor and define a default capture format cam->pix */
+ cam->sensor = cam->cam_sensor->init(&cam->pix);
+ if (!cam->sensor) {
+ printk(KERN_ERR CAM_NAME ": cannot initialize sensor\n");
+ goto init_error;
+ }
+ printk(KERN_INFO "Sensor is %s\n", cam->cam_sensor->name);
+
+ /* calculate xclk based on the default capture format and default
+ * frame rate
+ */
+ cam->xclk = cam->cam_sensor->calc_xclk(&cam->pix,
+ &cam->nominal_timeperframe,
+ cam->sensor);
+ omap24xxcam_adjust_xclk(cam);
+ cam->cparm.timeperframe = cam->nominal_timeperframe;
+
+ /* program the camera interface to generate the new xclk frequency */
+ omap24xxcam_set_xclk(cam);
+
+ /* initialize the image preview parameters based on the default capture
+ * format
+ */
+ omap24xxcam_new_capture_format(cam);
+
+ /* program the sensor for the default capture format and rate */
+ cam->cam_sensor->configure(&cam->pix, cam->xclk,
+ &cam->cparm.timeperframe, cam->sensor);
+
+ /* use display controller video window 0 for preview */
+ cam->vid1 = 0;
+ cam->vid2 = 1;
+
+ /* initialize the DMA driver */
+ omap24xxcam_dma_init(cam);
+
+ /* install the interrupt service routine */
+ if (request_irq(INT_CAM_MPU_IRQ, omap24xxcam_isr, 0, CAM_NAME, cam)) {
+ printk(KERN_ERR CAM_NAME
+ ": could not install interrupt service routine\n");
+ goto init_error;
+ }
+ cam->irq = INT_CAM_MPU_IRQ;
+
+ if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) {
+ printk(KERN_ERR CAM_NAME
+ ": could not register Video for Linux device\n");
+ vfd->minor = -1;
+ goto init_error;
+ }
+ /* set driver specific data to use in power management functions */
+ platform_set_drvdata(pdev, cam);
+
+ printk(KERN_INFO CAM_NAME
+ ": registered device video%d [v4l2]\n", vfd->minor);
+
+#undef CAMERA_TEST
+//#define CAMERA_TEST
+#ifdef CAMERA_TEST
+ if (cam->pix.sizeimage <= cam->overlay_size) {
+ printk(KERN_INFO CAM_NAME ": Camera test--enabling overlay\n");
+ /* turn on the video overlay */
+ omap24xxcam_configure_overlay(cam, NULL);
+ omap24xxcam_flip_overlay(cam, cam->overlay_base_phys);
+ cam->previewing = (struct omap24xxcam_fh *)1;
+ /* start the camera interface */
+ omap24xxcam_dma_notify(cam, omap24xxcam_cc_enable);
+ omap24xxcam_start_overlay_dma(cam);
+ } else {
+ printk(KERN_INFO CAM_NAME
+ ": Can't start camera test--overlay buffer too"
+ " small\n");
+ }
+#endif
+
+ return 0;
+
+ init_error:
+ omap24xxcam_cleanup();
+ return -ENODEV;
+}
+
+static int omap24xxcam_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver omap24xxcam_driver = {
+ .probe = omap24xxcam_probe,
+ .remove = omap24xxcam_remove,
+#ifdef CONFIG_PM
+ .suspend = omap24xxcam_suspend,
+ .resume = omap24xxcam_resume,
+#else
+ .suspend = NULL,
+ .resume = NULL,
+#endif
+ .shutdown = NULL,
+ .driver {
+ .name = CAM_NAME,
+ },
+};
+
+static struct platform_device omap24xxcam_dev = {
+ .name = CAM_NAME,
+ .dev = {
+ .release = NULL,
+ },
+ .id = 0,
+};
+
+int __init omap24xxcam_init(void)
+{
+ int ret;
+
+ DBG;
+
+ ret = platform_driver_register(&omap24xxcam_driver);
+ if (ret != 0)
+ return ret;
+ ret = platform_device_register(&omap24xxcam_dev);
+ if (ret != 0) {
+ platform_driver_unregister(&omap24xxcam_driver);
+ return ret;
+ }
+
+ return 0;
+}
+
+void omap24xxcam_cleanup(void)
+{
+ struct omap24xxcam_device *cam = saved_cam;
+ struct video_device *vfd;
+
+ DBG;
+
+ if (!cam)
+ return;
+ vfd = cam->vfd;
+
+ if (vfd) {
+ if (vfd->minor == -1) {
+ /* The device was never registered, so release the
+ * video_device struct directly.
+ */
+ video_device_release(vfd);
+ } else {
+ /* The unregister function will release the video_device
+ * struct as well as unregistering it.
+ */
+ video_unregister_device(vfd);
+ }
+ cam->vfd = NULL;
+ }
+
+ if (cam->irq) {
+ free_irq(cam->irq, cam);
+ cam->irq = 0;
+ }
+
+ omap24xxcam_dma_exit(cam);
+ cam->cam_sensor->cleanup(cam->sensor);
+ /* sensor allocated private data is gone */
+ cam->sensor = NULL;
+
+ if (cam->video2_base) {
+ dma_free_coherent(NULL, cam->video2_size,
+ (void *)cam->video2_base,
+ cam->video2_base_phys);
+ cam->video2_base = 0;
+ }
+ cam->video2_base_phys = 0;
+
+ if (cam->overlay_base) {
+ dma_free_coherent(NULL, cam->overlay_size,
+ (void *)cam->overlay_base,
+ cam->overlay_base_phys);
+ cam->overlay_base = 0;
+ }
+ cam->overlay_base_phys = 0;
+
+ if (cam->dispc_mmio_base) {
+ iounmap((void *)cam->dispc_mmio_base);
+ cam->dispc_mmio_base = 0;
+ }
+ cam->dispc_mmio_base_phys = 0;
+
+ if (cam->cam_mmio_base) {
+ iounmap((void *)cam->cam_mmio_base);
+ cam->cam_mmio_base = 0;
+ }
+ if (cam->cam_mmio_base_phys) {
+ release_mem_region(cam->cam_mmio_base_phys, cam->cam_mmio_size);
+ cam->cam_mmio_base_phys = 0;
+ }
+
+ platform_device_unregister(&omap24xxcam_dev);
+ platform_driver_unregister(&omap24xxcam_driver);
+
+ kfree(cam);
+ saved_cam = NULL;
+}
+
+MODULE_AUTHOR("MontaVista Software, Inc.");
+MODULE_DESCRIPTION("OMAP24xx Video for Linux camera driver");
+MODULE_LICENSE("GPL");
+module_param(video_nr, int, 0);
+MODULE_PARM_DESC(video_nr,
+ "Minor number for video device (-1 ==> auto assign)");
+module_param(capture_mem, int, 0);
+MODULE_PARM_DESC(capture_mem,
+ "Maximum amount of memory for capture buffers (default 4800KB)");
+module_param(overlay_mem, int, 0);
+MODULE_PARM_DESC(overlay_mem,
+ "Preview overlay framebuffer size (default 600KB)");
+
+module_init(omap24xxcam_init);
+module_exit(omap24xxcam_cleanup);
diff --git a/drivers/media/video/omap/omap24xxcam.h b/drivers/media/video/omap/omap24xxcam.h
new file mode 100644
index 0000000..e12c208
--- /dev/null
+++ b/drivers/media/video/omap/omap24xxcam.h
@@ -0,0 +1,865 @@
+/*
+ * drivers/media/video/omap24xxcam.h
+ *
+ * Video-for-Linux (Version 2) camera capture driver for
+ * the OMAP24xx camera controller.
+ *
+ * Author: Andy Lowe (source@mvista.com)
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef OMAP24XXCAM_H
+#define OMAP24XXCAM_H
+
+#define CAM_CLOCK 96000000
+
+/* physical memory map definitions */
+ /* camera subsystem */
+#define CAM_REG_BASE 0x48052000
+#define CAM_REG_SIZE 0x00001000
+ /* camera core */
+#define CC_REG_OFFSET 0x00000400
+ /* camera DMA */
+#define CAMDMA_REG_OFFSET 0x00000800
+ /* camera MMU */
+#define CAMMMU_REG_OFFSET 0x00000C00
+
+/* define camera subsystem register offsets */
+#define CAM_REVISION 0x000
+#define CAM_SYSCONFIG 0x010
+#define CAM_SYSSTATUS 0x014
+#define CAM_IRQSTATUS 0x018
+#define CAM_GPO 0x040
+#define CAM_GPI 0x050
+
+/* define camera core register offsets */
+#define CC_REVISION 0x000
+#define CC_SYSCONFIG 0x010
+#define CC_SYSSTATUS 0x014
+#define CC_IRQSTATUS 0x018
+#define CC_IRQENABLE 0x01C
+#define CC_CTRL 0x040
+#define CC_CTRL_DMA 0x044
+#define CC_CTRL_XCLK 0x048
+#define CC_FIFODATA 0x04C
+#define CC_TEST 0x050
+#define CC_GENPAR 0x054
+#define CC_CCPFSCR 0x058
+#define CC_CCPFECR 0x05C
+#define CC_CCPLSCR 0x060
+#define CC_CCPLECR 0x064
+#define CC_CCPDFR 0x068
+
+/* define camera dma register offsets */
+#define CAMDMA_REVISION 0x000
+#define CAMDMA_IRQSTATUS_L0 0x008
+#define CAMDMA_IRQSTATUS_L1 0x00C
+#define CAMDMA_IRQSTATUS_L2 0x010
+#define CAMDMA_IRQSTATUS_L3 0x014
+#define CAMDMA_IRQENABLE_L0 0x018
+#define CAMDMA_IRQENABLE_L1 0x01C
+#define CAMDMA_IRQENABLE_L2 0x020
+#define CAMDMA_IRQENABLE_L3 0x024
+#define CAMDMA_SYSSTATUS 0x028
+#define CAMDMA_OCP_SYSCONFIG 0x02C
+#define CAMDMA_CAPS_0 0x064
+#define CAMDMA_CAPS_2 0x06C
+#define CAMDMA_CAPS_3 0x070
+#define CAMDMA_CAPS_4 0x074
+#define CAMDMA_GCR 0x078
+#define CAMDMA_CCR(n) (0x080 + (n)*0x60)
+#define CAMDMA_CLNK_CTRL(n) (0x084 + (n)*0x60)
+#define CAMDMA_CICR(n) (0x088 + (n)*0x60)
+#define CAMDMA_CSR(n) (0x08C + (n)*0x60)
+#define CAMDMA_CSDP(n) (0x090 + (n)*0x60)
+#define CAMDMA_CEN(n) (0x094 + (n)*0x60)
+#define CAMDMA_CFN(n) (0x098 + (n)*0x60)
+#define CAMDMA_CSSA(n) (0x09C + (n)*0x60)
+#define CAMDMA_CDSA(n) (0x0A0 + (n)*0x60)
+#define CAMDMA_CSEI(n) (0x0A4 + (n)*0x60)
+#define CAMDMA_CSFI(n) (0x0A8 + (n)*0x60)
+#define CAMDMA_CDEI(n) (0x0AC + (n)*0x60)
+#define CAMDMA_CDFI(n) (0x0B0 + (n)*0x60)
+#define CAMDMA_CSAC(n) (0x0B4 + (n)*0x60)
+#define CAMDMA_CDAC(n) (0x0B8 + (n)*0x60)
+#define CAMDMA_CCEN(n) (0x0BC + (n)*0x60)
+#define CAMDMA_CCFN(n) (0x0C0 + (n)*0x60)
+#define CAMDMA_COLOR(n) (0x0C4 + (n)*0x60)
+
+/* define camera mmu register offsets */
+#define CAMMMU_REVISION 0x000
+#define CAMMMU_SYSCONFIG 0x010
+#define CAMMMU_SYSSTATUS 0x014
+#define CAMMMU_IRQSTATUS 0x018
+#define CAMMMU_IRQENABLE 0x01C
+#define CAMMMU_WALKING_ST 0x040
+#define CAMMMU_CNTL 0x044
+#define CAMMMU_FAULT_AD 0x048
+#define CAMMMU_TTB 0x04C
+#define CAMMMU_LOCK 0x050
+#define CAMMMU_LD_TLB 0x054
+#define CAMMMU_CAM 0x058
+#define CAMMMU_RAM 0x05C
+#define CAMMMU_GFLUSH 0x060
+#define CAMMMU_FLUSH_ENTRY 0x064
+#define CAMMMU_READ_CAM 0x068
+#define CAMMMU_READ_RAM 0x06C
+#define CAMMMU_EMU_FAULT_AD 0x070
+
+/* Define bit fields within selected registers */
+#define CAM_REVISION_MAJOR (15 << 4)
+#define CAM_REVISION_MAJOR_SHIFT 4
+#define CAM_REVISION_MINOR (15 << 0)
+#define CAM_REVISION_MINOR_SHIFT 0
+
+#define CAM_SYSCONFIG_SOFTRESET (1 << 1)
+#define CAM_SYSCONFIG_AUTOIDLE (1 << 0)
+
+#define CAM_SYSSTATUS_RESETDONE (1 << 0)
+
+#define CAM_IRQSTATUS_CC_IRQ (1 << 4)
+#define CAM_IRQSTATUS_MMU_IRQ (1 << 3)
+#define CAM_IRQSTATUS_DMA_IRQ2 (1 << 2)
+#define CAM_IRQSTATUS_DMA_IRQ1 (1 << 1)
+#define CAM_IRQSTATUS_DMA_IRQ0 (1 << 0)
+
+#define CAM_GPO_CAM_S_P_EN (1 << 1)
+#define CAM_GPO_CAM_CCP_MODE (1 << 0)
+
+#define CAM_GPI_CC_DMA_REQ1 (1 << 24)
+#define CAP_GPI_CC_DMA_REQ0 (1 << 23)
+#define CAP_GPI_CAM_MSTANDBY (1 << 21)
+#define CAP_GPI_CAM_WAIT (1 << 20)
+#define CAP_GPI_CAM_S_DATA (1 << 17)
+#define CAP_GPI_CAM_S_CLK (1 << 16)
+#define CAP_GPI_CAM_P_DATA (0xFFF << 3)
+#define CAP_GPI_CAM_P_DATA_SHIFT 3
+#define CAP_GPI_CAM_P_VS (1 << 2)
+#define CAP_GPI_CAM_P_HS (1 << 1)
+#define CAP_GPI_CAM_P_CLK (1 << 0)
+
+#define CC_REVISION_MAJOR (15 << 4)
+#define CC_REVISION_MAJOR_SHIFT 4
+#define CC_REVISION_MINOR (15 << 0)
+#define CC_REVISION_MINOR_SHIFT 0
+
+#define CC_SYSCONFIG_SIDLEMODE (3 << 3)
+#define CC_SYSCONFIG_SIDLEMODE_FIDLE (0 << 3)
+#define CC_SYSCONFIG_SIDLEMODE_NIDLE (1 << 3)
+#define CC_SYSCONFIG_SOFTRESET (1 << 1)
+#define CC_SYSCONFIG_AUTOIDLE (1 << 0)
+
+#define CC_SYSSTATUS_RESETDONE (1 << 0)
+
+#define CC_IRQSTATUS_FS_IRQ (1 << 19)
+#define CC_IRQSTATUS_LE_IRQ (1 << 18)
+#define CC_IRQSTATUS_LS_IRQ (1 << 17)
+#define CC_IRQSTATUS_FE_IRQ (1 << 16)
+#define CC_IRQSTATUS_FW_ERR_IRQ (1 << 10)
+#define CC_IRQSTATUS_FSC_ERR_IRQ (1 << 9)
+#define CC_IRQSTATUS_SSC_ERR_IRQ (1 << 8)
+#define CC_IRQSTATUS_FIFO_NOEMPTY_IRQ (1 << 4)
+#define CC_IRQSTATUS_FIFO_FULL_IRQ (1 << 3)
+#define CC_IRQSTATUS_FIFO_THR_IRQ (1 << 2)
+#define CC_IRQSTATUS_FIFO_OF_IRQ (1 << 1)
+#define CC_IRQSTATUS_FIFO_UF_IRQ (1 << 0)
+
+#define CC_IRQENABLE_FS_IRQ (1 << 19)
+#define CC_IRQENABLE_LE_IRQ (1 << 18)
+#define CC_IRQENABLE_LS_IRQ (1 << 17)
+#define CC_IRQENABLE_FE_IRQ (1 << 16)
+#define CC_IRQENABLE_FW_ERR_IRQ (1 << 10)
+#define CC_IRQENABLE_FSC_ERR_IRQ (1 << 9)
+#define CC_IRQENABLE_SSC_ERR_IRQ (1 << 8)
+#define CC_IRQENABLE_FIFO_NOEMPTY_IRQ (1 << 4)
+#define CC_IRQENABLE_FIFO_FULL_IRQ (1 << 3)
+#define CC_IRQENABLE_FIFO_THR_IRQ (1 << 2)
+#define CC_IRQENABLE_FIFO_OF_IRQ (1 << 1)
+#define CC_IRQENABLE_FIFO_UF_IRQ (1 << 0)
+
+#define CC_CTRL_CC_ONE_SHOT (1 << 20)
+#define CC_CTRL_CC_IF_SYNCHRO (1 << 19)
+#define CC_CTRL_CC_RST (1 << 18)
+#define CC_CTRL_CC_FRAME_TRIG (1 << 17)
+#define CC_CTRL_CC_EN (1 << 16)
+#define CC_CTRL_NOBT_SYNCHRO (1 << 13)
+#define CC_CTRL_BT_CORRECT (1 << 12)
+#define CC_CTRL_PAR_ORDERCAM (1 << 11)
+#define CC_CTRL_PAR_CLK_POL (1 << 10)
+#define CC_CTRL_NOBT_HS_POL (1 << 9)
+#define CC_CTRL_NOBT_VS_POL (1 << 8)
+#define CC_CTRL_PAR_MODE (7 << 1)
+#define CC_CTRL_PAR_MODE_SHIFT 1
+#define CC_CTRL_PAR_MODE_NOBT8 (0 << 1)
+#define CC_CTRL_PAR_MODE_NOBT10 (1 << 1)
+#define CC_CTRL_PAR_MODE_NOBT12 (2 << 1)
+#define CC_CTRL_PAR_MODE_BT8 (4 << 1)
+#define CC_CTRL_PAR_MODE_BT10 (5 << 1)
+#define CC_CTRL_PAR_MODE_FIFOTEST (7 << 1)
+#define CC_CTRL_CCP_MODE (1 << 0)
+
+#define CC_CTRL_DMA_EN (1 << 8)
+#define CC_CTRL_DMA_FIFO_THRESHOLD (0x7F << 0)
+#define CC_CTRL_DMA_FIFO_THRESHOLD_SHIFT 0
+
+#define CC_CTRL_XCLK_DIV (0x1F << 0)
+#define CC_CTRL_XCLK_DIV_SHIFT 0
+#define CC_CTRL_XCLK_DIV_STABLE_LOW (0 << 0)
+#define CC_CTRL_XCLK_DIV_STABLE_HIGH (1 << 0)
+#define CC_CTRL_XCLK_DIV_BYPASS (31 << 0)
+
+#define CC_TEST_FIFO_RD_POINTER (0xFF << 24)
+#define CC_TEST_FIFO_RD_POINTER_SHIFT 24
+#define CC_TEST_FIFO_WR_POINTER (0xFF << 16)
+#define CC_TEST_FIFO_WR_POINTER_SHIFT 16
+#define CC_TEST_FIFO_LEVEL (0xFF << 8)
+#define CC_TEST_FIFO_LEVEL_SHIFT 8
+#define CC_TEST_FIFO_LEVEL_PEAK (0xFF << 0)
+#define CC_TEST_FIFO_LEVEL_PEAK_SHIFT 0
+
+#define CC_GENPAR_FIFO_DEPTH (7 << 0)
+#define CC_GENPAR_FIFO_DEPTH_SHIFT 0
+
+#define CC_CCPDFR_ALPHA (0xFF << 8)
+#define CC_CCPDFR_ALPHA_SHIFT 8
+#define CC_CCPDFR_DATAFORMAT (15 << 0)
+#define CC_CCPDFR_DATAFORMAT_SHIFT 0
+#define CC_CCPDFR_DATAFORMAT_YUV422BE ( 0 << 0)
+#define CC_CCPDFR_DATAFORMAT_YUV422 ( 1 << 0)
+#define CC_CCPDFR_DATAFORMAT_YUV420 ( 2 << 0)
+#define CC_CCPDFR_DATAFORMAT_RGB444 ( 4 << 0)
+#define CC_CCPDFR_DATAFORMAT_RGB565 ( 5 << 0)
+#define CC_CCPDFR_DATAFORMAT_RGB888NDE ( 6 << 0)
+#define CC_CCPDFR_DATAFORMAT_RGB888 ( 7 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW8NDE ( 8 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW8 ( 9 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW10NDE (10 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW10 (11 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW12NDE (12 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW12 (13 << 0)
+#define CC_CCPDFR_DATAFORMAT_JPEG8 (15 << 0)
+
+#define CAMDMA_REVISION_MAJOR (15 << 4)
+#define CAMDMA_REVISION_MAJOR_SHIFT 4
+#define CAMDMA_REVISION_MINOR (15 << 0)
+#define CAMDMA_REVISION_MINOR_SHIFT 0
+
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE (3 << 12)
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY (0 << 12)
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_NSTANDBY (1 << 12)
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_SSTANDBY (2 << 12)
+#define CAMDMA_OCP_SYSCONFIG_FUNC_CLOCK (1 << 9)
+#define CAMDMA_OCP_SYSCONFIG_OCP_CLOCK (1 << 8)
+#define CAMDMA_OCP_SYSCONFIG_EMUFREE (1 << 5)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE (3 << 3)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE (0 << 3)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_NIDLE (1 << 3)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_SIDLE (2 << 3)
+#define CAMDMA_OCP_SYSCONFIG_SOFTRESET (1 << 1)
+#define CAMDMA_OCP_SYSCONFIG_AUTOIDLE (1 << 0)
+
+#define CAMDMA_SYSSTATUS_RESETDONE (1 << 0)
+
+#define CAMDMA_GCR_ARBITRATION_RATE (0xFF << 16)
+#define CAMDMA_GCR_ARBITRATION_RATE_SHIFT 16
+#define CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH (0xFF << 0)
+#define CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH_SHIFT 0
+
+#define CAMDMA_CCR_SEL_SRC_DST_SYNC (1 << 24)
+#define CAMDMA_CCR_PREFETCH (1 << 23)
+#define CAMDMA_CCR_SUPERVISOR (1 << 22)
+#define CAMDMA_CCR_SECURE (1 << 21)
+#define CAMDMA_CCR_BS (1 << 18)
+#define CAMDMA_CCR_TRANSPARENT_COPY_ENABLE (1 << 17)
+#define CAMDMA_CCR_CONSTANT_FILL_ENABLE (1 << 16)
+#define CAMDMA_CCR_DST_AMODE (3 << 14)
+#define CAMDMA_CCR_DST_AMODE_CONST_ADDR (0 << 14)
+#define CAMDMA_CCR_DST_AMODE_POST_INC (1 << 14)
+#define CAMDMA_CCR_DST_AMODE_SGL_IDX (2 << 14)
+#define CAMDMA_CCR_DST_AMODE_DBL_IDX (3 << 14)
+#define CAMDMA_CCR_SRC_AMODE (3 << 12)
+#define CAMDMA_CCR_SRC_AMODE_CONST_ADDR (0 << 12)
+#define CAMDMA_CCR_SRC_AMODE_POST_INC (1 << 12)
+#define CAMDMA_CCR_SRC_AMODE_SGL_IDX (2 << 12)
+#define CAMDMA_CCR_SRC_AMODE_DBL_IDX (3 << 12)
+#define CAMDMA_CCR_WR_ACTIVE (1 << 10)
+#define CAMDMA_CCR_RD_ACTIVE (1 << 9)
+#define CAMDMA_CCR_SUSPEND_SENSITIVE (1 << 8)
+#define CAMDMA_CCR_ENABLE (1 << 7)
+#define CAMDMA_CCR_PRIO (1 << 6)
+#define CAMDMA_CCR_FS (1 << 5)
+#define CAMDMA_CCR_SYNCHRO ((3 << 19) | (31 << 0))
+#define CAMDMA_CCR_SYNCHRO_CAMERA 0x01
+
+#define CAMDMA_CLNK_CTRL_ENABLE_LNK (1 << 15)
+#define CAMDMA_CLNK_CTRL_NEXTLCH_ID (0x1F << 0)
+#define CAMDMA_CLNK_CTRL_NEXTLCH_ID_SHIFT 0
+
+#define CAMDMA_CICR_MISALIGNED_ERR_IE (1 << 11)
+#define CAMDMA_CICR_SUPERVISOR_ERR_IE (1 << 10)
+#define CAMDMA_CICR_SECURE_ERR_IE (1 << 9)
+#define CAMDMA_CICR_TRANS_ERR_IE (1 << 8)
+#define CAMDMA_CICR_PACKET_IE (1 << 7)
+#define CAMDMA_CICR_BLOCK_IE (1 << 5)
+#define CAMDMA_CICR_LAST_IE (1 << 4)
+#define CAMDMA_CICR_FRAME_IE (1 << 3)
+#define CAMDMA_CICR_HALF_IE (1 << 2)
+#define CAMDMA_CICR_DROP_IE (1 << 1)
+
+#define CAMDMA_CSR_MISALIGNED_ERR (1 << 11)
+#define CAMDMA_CSR_SUPERVISOR_ERR (1 << 10)
+#define CAMDMA_CSR_SECURE_ERR (1 << 9)
+#define CAMDMA_CSR_TRANS_ERR (1 << 8)
+#define CAMDMA_CSR_PACKET (1 << 7)
+#define CAMDMA_CSR_SYNC (1 << 6)
+#define CAMDMA_CSR_BLOCK (1 << 5)
+#define CAMDMA_CSR_LAST (1 << 4)
+#define CAMDMA_CSR_FRAME (1 << 3)
+#define CAMDMA_CSR_HALF (1 << 2)
+#define CAMDMA_CSR_DROP (1 << 1)
+
+#define CAMDMA_CSDP_SRC_ENDIANNESS (1 << 21)
+#define CAMDMA_CSDP_SRC_ENDIANNESS_LOCK (1 << 20)
+#define CAMDMA_CSDP_DST_ENDIANNESS (1 << 19)
+#define CAMDMA_CSDP_DST_ENDIANNESS_LOCK (1 << 18)
+#define CAMDMA_CSDP_WRITE_MODE (3 << 16)
+#define CAMDMA_CSDP_WRITE_MODE_WRNP (0 << 16)
+#define CAMDMA_CSDP_WRITE_MODE_POSTED (1 << 16)
+#define CAMDMA_CSDP_WRITE_MODE_POSTED_LAST_WRNP (2 << 16)
+#define CAMDMA_CSDP_DST_BURST_EN (3 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_1 (0 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_16 (1 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_32 (2 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_64 (3 << 14)
+#define CAMDMA_CSDP_DST_PACKED (1 << 13)
+#define CAMDMA_CSDP_WR_ADD_TRSLT (15 << 9)
+#define CAMDMA_CSDP_WR_ADD_TRSLT_ENABLE_MREQADD (3 << 9)
+#define CAMDMA_CSDP_SRC_BURST_EN (3 << 7)
+#define CAMDMA_CSDP_SRC_BURST_EN_1 (0 << 7)
+#define CAMDMA_CSDP_SRC_BURST_EN_16 (1 << 7)
+#define CAMDMA_CSDP_SRC_BURST_EN_32 (2 << 7)
+#define CAMDMA_CSDP_SRC_BURST_EN_64 (3 << 7)
+#define CAMDMA_CSDP_SRC_PACKED (1 << 6)
+#define CAMDMA_CSDP_RD_ADD_TRSLT (15 << 2)
+#define CAMDMA_CSDP_RD_ADD_TRSLT_ENABLE_MREQADD (3 << 2)
+#define CAMDMA_CSDP_DATA_TYPE (3 << 0)
+#define CAMDMA_CSDP_DATA_TYPE_8BITS (0 << 0)
+#define CAMDMA_CSDP_DATA_TYPE_16BITS (1 << 0)
+#define CAMDMA_CSDP_DATA_TYPE_32BITS (2 << 0)
+
+#define CAMMMU_SYSCONFIG_AUTOIDLE (1 << 0)
+
+struct omap24xx_cc_regs {
+ u32 revision; /* 0x000 */
+ u32 res1[3];
+ u32 sysconfig; /* 0x010 */
+ u32 sysstatus; /* 0x014 */
+ u32 irqstatus; /* 0x018 */
+ u32 irqenable; /* 0x01C */
+ u32 res2[8];
+ u32 ctrl; /* 0x040 */
+ u32 ctrl_dma; /* 0x044 */
+ u32 ctrl_xclk; /* 0x048 */
+ u32 fifodata; /* 0x04C */
+ u32 test; /* 0x050 */
+ u32 genpar; /* 0x054 */
+ u32 ccpfscr; /* 0x058 */
+ u32 ccpfecr; /* 0x05C */
+ u32 ccplscr; /* 0x060 */
+ u32 ccplecr; /* 0x064 */
+ u32 ccpdfr; /* 0x068 */
+};
+struct omap24xx_vid2_format {
+ struct v4l2_pix_format pix;
+ __s32 left; /* following two members are defined to */
+ __s32 top; /* position the video2 layer on the lcd */
+
+};
+
+/* forward declarations */
+struct omap24xxcam_fh;
+struct omap24xxcam_device;
+
+/* camera DMA definitions */
+#define DMA_THRESHOLD 32 /* number of bytes transferred per DMA request */
+/* NUM_CAMDMA_CHANNELS is the number of logical channels provided by the camera
+ * DMA controller.
+ */
+#define NUM_CAMDMA_CHANNELS 4
+/* NUM_SG_DMA is the number of scatter-gather DMA transfers that can be queued.
+ * We need it to be 2 greater than the maximum number of video frames so that
+ * we can use 2 slots for overlay while still having VIDEO_MAX_FRAME slots left
+ * for streaming.
+ */
+#define NUM_SG_DMA (VIDEO_MAX_FRAME+2)
+
+typedef void (*dma_callback_t) (struct omap24xxcam_device * cam,
+ unsigned long status, void *arg);
+
+struct camdma_state {
+ dma_callback_t callback;
+ void *arg;
+};
+struct sgdma_state {
+ const struct scatterlist *sglist;
+ int sglen; /* number of sglist entries */
+ int next_sglist; /* index of next sglist entry to process */
+ int queued_sglist; /* number of sglist entries queued for DMA */
+ unsigned long csr; /* DMA return code */
+ dma_callback_t callback;
+ void *arg;
+};
+
+/* per-device data structure */
+struct omap24xxcam_device {
+ unsigned int irq;
+
+ unsigned long cam_mmio_base;
+ unsigned long cam_mmio_base_phys;
+ unsigned long cam_mmio_size;
+
+ unsigned long dispc_mmio_base;
+ unsigned long dispc_mmio_base_phys;
+ unsigned long dispc_mmio_size;
+
+ unsigned long overlay_base;
+ unsigned long overlay_base_phys;
+ unsigned long overlay_size;
+
+ /* camera DMA management */
+ spinlock_t dma_lock;
+ /* While dma_stop!=0, an attempt to start a new DMA transfer will
+ * fail.
+ */
+ int dma_stop;
+ int free_dmach; /* number of dma channels free */
+ int next_dmach; /* index of next dma channel to use */
+ struct camdma_state camdma[NUM_CAMDMA_CHANNELS];
+ /* dma_notify is a pointer to a callback routine for notification when
+ * a DMA transfer has been started.
+ */
+ void (*dma_notify) (struct omap24xxcam_device * cam);
+
+ /* frequncy (in Hz) of camera interface functional clock (MCLK) */
+ unsigned long mclk;
+
+ struct device dev;
+ struct video_device *vfd;
+
+ spinlock_t overlay_lock; /* spinlock for overlay DMA counter */
+ int overlay_cnt; /* count of queued overlay DMA xfers */
+ struct scatterlist overlay_sglist;
+
+ spinlock_t vbq_lock; /* spinlock for videobuf queues */
+ struct videobuf_queue_ops vbq_ops; /* videobuf queue operations */
+ unsigned long field_count; /* field counter for videobuf_buffer */
+
+ /* scatter-gather DMA management */
+ spinlock_t sg_lock;
+ int free_sgdma; /* number of free sg dma slots */
+ int next_sgdma; /* index of next sg dma slot to use */
+ struct sgdma_state sgdma[NUM_SG_DMA];
+
+ /* The img_lock is used to serialize access to the image parameters for
+ * overlay and capture.
+ */
+ spinlock_t img_lock;
+
+ /* Access to everything below here is locked by img_lock */
+
+ /* We allow streaming from at most one filehandle at a time.
+ * non-NULL means streaming is in progress.
+ */
+ struct omap24xxcam_fh *streaming;
+ /* We allow previewing from at most one filehandle at a time.
+ * non-NULL means previewing is in progress.
+ */
+ struct omap24xxcam_fh *previewing;
+
+ /* capture parameters (frame rate, number of buffers) */
+ struct v4l2_captureparm cparm;
+
+ /* This is the frame period actually requested by the user. */
+ struct v4l2_fract nominal_timeperframe;
+
+ /* frequency (in Hz) of camera interface xclk output */
+ unsigned long xclk;
+
+ /* pointer to camera sensor interface interface */
+ struct camera_sensor *cam_sensor;
+ /* blind pointer to private data structure for sensor */
+ void *sensor;
+
+ /* pix defines the size and pixel format of the image captured by the
+ * sensor. This also defines the size of the framebuffers. The
+ * same pool of framebuffers is used for video capture and video
+ * overlay. These parameters are set/queried by the
+ * VIDIOC_S_FMT/VIDIOC_G_FMT ioctls with a CAPTURE buffer type.
+ */
+ struct v4l2_pix_format pix;
+
+ /* crop defines the size and offset of the video overlay source window
+ * within the framebuffer. These parameters are set/queried by the
+ * VIDIOC_S_CROP/VIDIOC_G_CROP ioctls with an OVERLAY buffer type.
+ * The cropping rectangle allows a subset of the captured image to be
+ * previewed. It only affects the portion of the image previewed, not
+ * captured; the entire camera image is always captured.
+ */
+ struct v4l2_rect crop;
+
+ /* win defines the size and offset of the video overlay target window
+ * within the video display. These parameters are set/queried by the
+ * VIDIOC_S_FMT/VIDIOC_G_FMT ioctls with an OVERLAY buffer type.
+ */
+ struct v4l2_window win;
+
+ /* fbuf reflects the size of the video display. It is queried with the
+ * VIDIOC_G_FBUF ioctl. The size of the video display cannot be
+ * changed with the VIDIOC_S_FBUF ioctl.
+ */
+ struct v4l2_framebuffer fbuf;
+
+ /* value of CC_CTRL register required to support current capture
+ * format
+ */
+ unsigned long cc_ctrl;
+
+ /* display controller video window (0 or 1) to use for capture
+ * preview
+ */
+ int vid1;
+
+ /* gfx_position x and y are the offset of the display controller
+ * graphics window with respect to the display
+ */
+ int gfx_position_x;
+ int gfx_position_y;
+ /* value of GFX_ATTRIBUTES register from display controller */
+ unsigned long gfx_attributes;
+
+ /* video 2 layer of the display controller is also configured through
+ ** it */
+ int vid2;
+ unsigned long video2_base;
+ unsigned long video2_base_phys;
+ unsigned long video2_size;
+};
+
+/* per-filehandle data structure */
+struct omap24xxcam_fh {
+ struct omap24xxcam_device *cam;
+ enum v4l2_buf_type type;
+ struct videobuf_queue vbq;
+};
+
+/* Selected register definitions from the framebuffer driver for the
+ * OMAP2420 display controller are repeated here.
+ */
+#ifndef OMAP24XXFB_H
+
+/* physical memory map definitions */
+ /* display subsystem */
+#define DSS_REG_BASE 0x48050000
+#define DSS_REG_SIZE 0x00001000
+ /* display controller */
+#define DISPC_REG_OFFSET 0x00000400
+
+/* define display controller register offsets */
+#define DISPC_REVISION 0x000
+#define DISPC_SYSCONFIG 0x010
+#define DISPC_SYSSTATUS 0x014
+#define DISPC_IRQSTATUS 0x018
+#define DISPC_IRQENABLE 0x01C
+#define DISPC_CONTROL 0x040
+#define DISPC_CONFIG 0x044
+#define DISPC_CAPABLE 0x048
+#define DISPC_DEFAULT_COLOR0 0x04C
+#define DISPC_DEFAULT_COLOR1 0x050
+#define DISPC_TRANS_COLOR0 0x054
+#define DISPC_TRANS_COLOR1 0x058
+#define DISPC_LINE_STATUS 0x05C
+#define DISPC_LINE_NUMBER 0x060
+#define DISPC_TIMING_H 0x064
+#define DISPC_TIMING_V 0x068
+#define DISPC_POL_FREQ 0x06C
+#define DISPC_DIVISOR 0x070
+#define DISPC_SIZE_DIG 0x078
+#define DISPC_SIZE_LCD 0x07C
+#define DISPC_GFX_BA0 0x080
+#define DISPC_GFX_BA1 0x084
+#define DISPC_GFX_POSITION 0x088
+#define DISPC_GFX_SIZE 0x08C
+#define DISPC_GFX_ATTRIBUTES 0x0A0
+#define DISPC_GFX_FIFO_THRESHOLD 0x0A4
+#define DISPC_GFX_FIFO_SIZE 0x0A8
+#define DISPC_GFX_ROW_INC 0x0AC
+#define DISPC_GFX_PIXEL_INC 0x0B0
+#define DISPC_GFX_WINDOW_SKIP 0x0B4
+#define DISPC_GFX_TABLE_BA 0x0B8
+
+/* The registers for the video pipelines are parameterized by the video pipeline
+ * index: n=0 for VID1 and n=1 for VID2.
+ */
+#define DISPC_VID_BA0(n) (0x0BC + (n)*0x90)
+#define DISPC_VID_BA1(n) (0x0C0 + (n)*0x90)
+#define DISPC_VID_POSITION(n) (0x0C4 + (n)*0x90)
+#define DISPC_VID_SIZE(n) (0x0C8 + (n)*0x90)
+#define DISPC_VID_ATTRIBUTES(n) (0x0CC + (n)*0x90)
+#define DISPC_VID_FIFO_THRESHOLD(n) (0x0D0 + (n)*0x90)
+#define DISPC_VID_FIFO_SIZE(n) (0x0D4 + (n)*0x90)
+#define DISPC_VID_ROW_INC(n) (0x0D8 + (n)*0x90)
+#define DISPC_VID_PIXEL_INC(n) (0x0DC + (n)*0x90)
+#define DISPC_VID_FIR(n) (0x0E0 + (n)*0x90)
+#define DISPC_VID_PICTURE_SIZE(n) (0x0E4 + (n)*0x90)
+#define DISPC_VID_ACCU0(n) (0x0E8 + (n)*0x90)
+#define DISPC_VID_ACCU1(n) (0x0EC + (n)*0x90)
+/* The FIR coefficients are parameterized by the video pipeline index n = {0, 1}
+ * and the coefficient index i = {0, 1, 2, 3, 4, 5, 6, 7}.
+ */
+#define DISPC_VID_FIR_COEF_H(n, i) (0x0F0 + (i)*0x8 + (n)*0x90)
+#define DISPC_VID_FIR_COEF_HV(n, i) (0x0F4 + (i)*0x8 + (n)*0x90)
+#define DISPC_VID_CONV_COEF0(n) (0x130 + (n)*0x90)
+#define DISPC_VID_CONV_COEF1(n) (0x134 + (n)*0x90)
+#define DISPC_VID_CONV_COEF2(n) (0x138 + (n)*0x90)
+#define DISPC_VID_CONV_COEF3(n) (0x13C + (n)*0x90)
+#define DISPC_VID_CONV_COEF4(n) (0x140 + (n)*0x90)
+
+/* Define bit fields within selected registers */
+#define DISPC_REVISION_MAJOR (15 << 4)
+#define DISPC_REVISION_MAJOR_SHIFT 4
+#define DISPC_REVISION_MINOR (15 << 0)
+#define DISPC_REVISION_MINOR_SHIFT 0
+
+#define DISPC_SYSCONFIG_MIDLEMODE (3 << 12)
+#define DISPC_SYSCONFIG_MIDLEMODE_FSTANDBY (0 << 12)
+#define DISPC_SYSCONFIG_MIDLEMODE_NSTANDBY (1 << 12)
+#define DISPC_SYSCONFIG_MIDLEMODE_SSTANDBY (2 << 12)
+#define DISPC_SYSCONFIG_SIDLEMODE (3 << 3)
+#define DISPC_SYSCONFIG_SIDLEMODE_FIDLE (0 << 3)
+#define DISPC_SYSCONFIG_SIDLEMODE_NIDLE (1 << 3)
+#define DISPC_SYSCONFIG_SIDLEMODE_SIDLE (2 << 3)
+#define DISPC_SYSCONFIG_SOFTRESET (1 << 1)
+#define DISPC_SYSCONFIG_AUTOIDLE (1 << 0)
+
+#define DISPC_SYSSTATUS_RESETDONE (1 << 0)
+
+#define DISPC_IRQSTATUS_SYNCLOST (1 << 14)
+#define DISPC_IRQSTATUS_VID2ENDWINDOW (1 << 13)
+#define DISPC_IRQSTATUS_VID2FIFOUNDERFLOW (1 << 12)
+#define DISPC_IRQSTATUS_VID1ENDWINDOW (1 << 11)
+#define DISPC_IRQSTATUS_VID1FIFOUNDERFLOW (1 << 10)
+#define DISPC_IRQSTATUS_OCPERROR (1 << 9)
+#define DISPC_IRQSTATUS_PALETTEGAMMALOADING (1 << 8)
+#define DISPC_IRQSTATUS_GFXENDWINDOW (1 << 7)
+#define DISPC_IRQSTATUS_GFXFIFOUNDERFLOW (1 << 6)
+#define DISPC_IRQSTATUS_PROGRAMMEDLINENUMBER (1 << 5)
+#define DISPC_IRQSTATUS_ACBIASCOUNTSTATUS (1 << 4)
+#define DISPC_IRQSTATUS_EVSYNC_ODD (1 << 3)
+#define DISPC_IRQSTATUS_EVSYNC_EVEN (1 << 2)
+#define DISPC_IRQSTATUS_VSYNC (1 << 1)
+#define DISPC_IRQSTATUS_FRAMEDONE (1 << 0)
+
+#define DISPC_IRQENABLE_SYNCLOST (1 << 14)
+#define DISPC_IRQENABLE_VID2ENDWINDOW (1 << 13)
+#define DISPC_IRQENABLE_VID2FIFOUNDERFLOW (1 << 12)
+#define DISPC_IRQENABLE_VID1ENDWINDOW (1 << 11)
+#define DISPC_IRQENABLE_VID1FIFOUNDERFLOW (1 << 10)
+#define DISPC_IRQENABLE_OCPERROR (1 << 9)
+#define DISPC_IRQENABLE_PALETTEGAMMALOADING (1 << 8)
+#define DISPC_IRQENABLE_GFXENDWINDOW (1 << 7)
+#define DISPC_IRQENABLE_GFXFIFOUNDERFLOW (1 << 6)
+#define DISPC_IRQENABLE_PROGRAMMEDLINENUMBER (1 << 5)
+#define DISPC_IRQENABLE_ACBIASCOUNTSTATUS (1 << 4)
+#define DISPC_IRQENABLE_EVSYNC_ODD (1 << 3)
+#define DISPC_IRQENABLE_EVSYNC_EVEN (1 << 2)
+#define DISPC_IRQENABLE_VSYNC (1 << 1)
+#define DISPC_IRQENABLE_FRAMEDONE (1 << 0)
+
+#define DISPC_CONTROL_TDMUNUSEDBITS (3 << 25)
+#define DISPC_CONTROL_TDMUNUSEDBITS_LOWLEVEL (0 << 25)
+#define DISPC_CONTROL_TDMUNUSEDBITS_HIGHLEVEL (1 << 25)
+#define DISPC_CONTROL_TDMUNUSEDBITS_UNCHANGED (2 << 25)
+#define DISPC_CONTROL_TDMCYCLEFORMAT (3 << 23)
+#define DISPC_CONTROL_TDMCYCLEFORMAT_1CYCPERPIX (0 << 23)
+#define DISPC_CONTROL_TDMCYCLEFORMAT_2CYCPERPIX (1 << 23)
+#define DISPC_CONTROL_TDMCYCLEFORMAT_3CYCPERPIX (2 << 23)
+#define DISPC_CONTROL_TDMCYCLEFORMAT_3CYCPER2PIX (3 << 23)
+#define DISPC_CONTROL_TDMPARALLELMODE (3 << 21)
+#define DISPC_CONTROL_TDMPARALLELMODE_8BPARAINT (0 << 21)
+#define DISPC_CONTROL_TDMPARALLELMODE_9BPARAINT (1 << 21)
+#define DISPC_CONTROL_TDMPARALLELMODE_12BPARAINT (2 << 21)
+#define DISPC_CONTROL_TDMPARALLELMODE_16BPARAINT (3 << 21)
+#define DISPC_CONTROL_TDMENABLE (1 << 20)
+#define DISPC_CONTROL_HT (7 << 17)
+#define DISPC_CONTROL_HT_SHIFT 17
+#define DISPC_CONTROL_GPOUT1 (1 << 16)
+#define DISPC_CONTROL_GPOUT0 (1 << 15)
+#define DISPC_CONTROL_GPIN1 (1 << 14)
+#define DISPC_CONTROL_GPIN0 (1 << 13)
+#define DISPC_CONTROL_OVERLAYOPTIMIZATION (1 << 12)
+#define DISPC_CONTROL_RFBIMODE (1 << 11)
+#define DISPC_CONTROL_SECURE (1 << 10)
+#define DISPC_CONTROL_TFTDATALINES (3 << 8)
+#define DISPC_CONTROL_TFTDATALINES_OALSB12B (0 << 8)
+#define DISPC_CONTROL_TFTDATALINES_OALSB16B (1 << 8)
+#define DISPC_CONTROL_TFTDATALINES_OALSB18B (2 << 8)
+#define DISPC_CONTROL_TFTDATALINES_OALSB24B (3 << 8)
+#define DISPC_CONTROL_TFTDITHERENABLE (1 << 7)
+#define DISPC_CONTROL_GODIGITAL (1 << 6)
+#define DISPC_CONTROL_GOLCD (1 << 5)
+#define DISPC_CONTROL_M8B (1 << 4)
+#define DISPC_CONTROL_STNTFT (1 << 3)
+#define DISPC_CONTROL_MONOCOLOR (1 << 2)
+#define DISPC_CONTROL_DIGITALENABLE (1 << 1)
+#define DISPC_CONTROL_LCDENABLE (1 << 0)
+
+#define DISPC_CONFIG_TCKDIGSELECTION (1 << 13)
+#define DISPC_CONFIG_TCKDIGENABLE (1 << 12)
+#define DISPC_CONFIG_TCKLCDSELECTION (1 << 11)
+#define DISPC_CONFIG_TCKLCDENABLE (1 << 10)
+#define DISPC_CONFIG_FUNCGATED (1 << 9)
+#define DISPC_CONFIG_ACBIASGATED (1 << 8)
+#define DISPC_CONFIG_VSYNCGATED (1 << 7)
+#define DISPC_CONFIG_HSYNCGATED (1 << 6)
+#define DISPC_CONFIG_PIXELCLOCKGATED (1 << 5)
+#define DISPC_CONFIG_PIXELDATAGATED (1 << 4)
+#define DISPC_CONFIG_PALETTEGAMMATABLE (1 << 3)
+#define DISPC_CONFIG_LOADMODE_FRDATLEFR (1 << 2)
+#define DISPC_CONFIG_LOADMODE_PGTABUSETB (1 << 1)
+#define DISPC_CONFIG_PIXELGATED (1 << 0)
+
+#define DISPC_CAPABLE_GFXGAMMATABLECAPABLE (1 << 9)
+#define DISPC_CAPABLE_GFXLAYERCAPABLE (1 << 8)
+#define DISPC_CAPABLE_GFXTRANSDSTCAPABLE (1 << 7)
+#define DISPC_CAPABLE_STNDITHERINGCAPABLE (1 << 6)
+#define DISPC_CAPABLE_TFTDITHERINGCAPABLE (1 << 5)
+#define DISPC_CAPABLE_VIDTRANSSRCCAPABLE (1 << 4)
+#define DISPC_CAPABLE_VIDLAYERCAPABLE (1 << 3)
+#define DISPC_CAPABLE_VIDVERTFIRCAPABLE (1 << 2)
+#define DISPC_CAPABLE_VIDHORFIRCAPABLE (1 << 1)
+#define DISPC_CAPABLE_VIDCAPABLE (1 << 0)
+
+#define DISPC_POL_FREQ_ONOFF (1 << 17)
+#define DISPC_POL_FREQ_RF (1 << 16)
+#define DISPC_POL_FREQ_IEO (1 << 15)
+#define DISPC_POL_FREQ_IPC (1 << 14)
+#define DISPC_POL_FREQ_IHS (1 << 13)
+#define DISPC_POL_FREQ_IVS (1 << 12)
+#define DISPC_POL_FREQ_ACBI (15 << 8)
+#define DISPC_POL_FREQ_ACBI_SHIFT 8
+#define DISPC_POL_FREQ_ACB 0xFF
+#define DISPC_POL_FREQ_ACB_SHIFT 0
+
+#define DISPC_TIMING_H_HBP (0xFF << 20)
+#define DISPC_TIMING_H_HBP_SHIFT 20
+#define DISPC_TIMING_H_HFP (0xFF << 8)
+#define DISPC_TIMING_H_HFP_SHIFT 8
+#define DISPC_TIMING_H_HSW (0x3F << 0)
+#define DISPC_TIMING_H_HSW_SHIFT 0
+
+#define DISPC_TIMING_V_VBP (0xFF << 20)
+#define DISPC_TIMING_V_VBP_SHIFT 20
+#define DISPC_TIMING_V_VFP (0xFF << 8)
+#define DISPC_TIMING_V_VFP_SHIFT 8
+#define DISPC_TIMING_V_VSW (0x3F << 0)
+#define DISPC_TIMING_V_VSW_SHIFT 0
+
+#define DISPC_DIVISOR_LCD (0xFF << 16)
+#define DISPC_DIVISOR_LCD_SHIFT 16
+#define DISPC_DIVISOR_PCD 0xFF
+#define DISPC_DIVISOR_PCD_SHIFT 0
+
+#define DISPC_SIZE_LCD_LPP (0x7FF << 16)
+#define DISPC_SIZE_LCD_LPP_SHIFT 16
+#define DISPC_SIZE_LCD_PPL 0x7FF
+#define DISPC_SIZE_LCD_PPL_SHIFT 0
+
+#define DISPC_SIZE_DIG_LPP (0x7FF << 16)
+#define DISPC_SIZE_DIG_LPP_SHIFT 16
+#define DISPC_SIZE_DIG_PPL 0x7FF
+#define DISPC_SIZE_DIG_PPL_SHIFT 0
+
+#define DISPC_GFX_POSITION_GFXPOSY (0x7FF << 16)
+#define DISPC_GFX_POSITION_GFXPOSY_SHIFT 16
+#define DISPC_GFX_POSITION_GFXPOSX 0x7FF
+#define DISPC_GFX_POSITION_GFXPOSX_SHIFT 0
+
+#define DISPC_GFX_SIZE_GFXSIZEY (0x7FF << 16)
+#define DISPC_GFX_SIZE_GFXSIZEY_SHIFT 16
+#define DISPC_GFX_SIZE_GFXSIZEX 0x7FF
+#define DISPC_GFX_SIZE_GFXSIZEX_SHIFT 0
+
+#define DISPC_GFX_ATTRIBUTES_GFXENDIANNESS (1 << 10)
+#define DISPC_GFX_ATTRIBUTES_GFXNIBBLEMODE (1 << 9)
+#define DISPC_GFX_ATTRIBUTES_GFXCHANNELOUT (1 << 8)
+#define DISPC_GFX_ATTRIBUTES_GFXBURSTSIZE (3 << 6)
+#define DISPC_GFX_ATTRIBUTES_GFXBURSTSIZE_BURST4X32 (0 << 6)
+#define DISPC_GFX_ATTRIBUTES_GFXBURSTSIZE_BURST8X32 (1 << 6)
+#define DISPC_GFX_ATTRIBUTES_GFXBURSTSIZE_BURST16X32 (2 << 6)
+#define DISPC_GFX_ATTRIBUTES_GFXREPLICATIONENABLE (1 << 5)
+#define DISPC_GFX_ATTRIBUTES_GFXFORMAT (15 << 1)
+#define DISPC_GFX_ATTRIBUTES_GFXFORMAT_BITMAP1 (0 << 1)
+#define DISPC_GFX_ATTRIBUTES_GFXFORMAT_BITMAP2 (1 << 1)
+#define DISPC_GFX_ATTRIBUTES_GFXFORMAT_BITMAP4 (2 << 1)
+#define DISPC_GFX_ATTRIBUTES_GFXFORMAT_BITMAP8 (3 << 1)
+#define DISPC_GFX_ATTRIBUTES_GFXFORMAT_RGB12 (4 << 1)
+#define DISPC_GFX_ATTRIBUTES_GFXFORMAT_RGB16 (6 << 1)
+#define DISPC_GFX_ATTRIBUTES_GFXFORMAT_RGB24 (8 << 1)
+#define DISPC_GFX_ATTRIBUTES_ENABLE (1 << 0)
+
+#define DISPC_GFX_FIFO_THRESHOLD_HIGH (0x1FF << 16)
+#define DISPC_GFX_FIFO_THRESHOLD_HIGH_SHIFT 16
+#define DISPC_GFX_FIFO_THRESHOLD_LOW 0x1FF
+#define DISPC_GFX_FIFO_THRESHOLD_LOW_SHIFT 0
+
+#define DISPC_VID_POSITION_VIDPOSY (0x7FF << 16)
+#define DISPC_VID_POSITION_VIDPOSY_SHIFT 16
+#define DISPC_VID_POSITION_VIDPOSX 0x7FF
+#define DISPC_VID_POSITION_VIDPOSX_SHIFT 0
+
+#define DISPC_VID_SIZE_VIDSIZEY (0x7FF << 16)
+#define DISPC_VID_SIZE_VIDSIZEY_SHIFT 16
+#define DISPC_VID_SIZE_VIDSIZEX 0x7FF
+#define DISPC_VID_SIZE_VIDSIZEX_SHIFT 0
+
+#define DISPC_VID_ATTRIBUTES_VIDROWREPEATENABLE (1 << 18)
+#define DISPC_VID_ATTRIBUTES_VIDENDIANNESS (1 << 17)
+#define DISPC_VID_ATTRIBUTES_VIDCHANNELOUT (1 << 16)
+#define DISPC_VID_ATTRIBUTES_VIDBURSTSIZE (3 << 14)
+#define DISPC_VID_ATTRIBUTES_VIDBURSTSIZE_BURST4X32 (0 << 14)
+#define DISPC_VID_ATTRIBUTES_VIDBURSTSIZE_BURST8X32 (1 << 14)
+#define DISPC_VID_ATTRIBUTES_VIDBURSTSIZE_BURST16X32 (2 << 14)
+#define DISPC_VID_ATTRIBUTES_VIDROTATION (3 << 12)
+#define DISPC_VID_ATTRIBUTES_VIDROTATION_NOROT (0 << 12)
+#define DISPC_VID_ATTRIBUTES_VIDROTATION_ROT90 (1 << 12)
+#define DISPC_VID_ATTRIBUTES_VIDROTATION_ROT180 (2 << 12)
+#define DISPC_VID_ATTRIBUTES_VIDROTATION_ROT270 (3 << 12)
+#define DISPC_VID_ATTRIBUTES_VIDFULLRANGE (1 << 11)
+#define DISPC_VID_ATTRIBUTES_VIDREPLICATIONENABLE (1 << 10)
+#define DISPC_VID_ATTRIBUTES_VIDCOLORCONVENABLE (1 << 9)
+#define DISPC_VID_ATTRIBUTES_VIDVRESIZECONF (1 << 8)
+#define DISPC_VID_ATTRIBUTES_VIDHRESIZECONF (1 << 7)
+#define DISPC_VID_ATTRIBUTES_VIDRESIZEENABLE_VRESIZE (1 << 6)
+#define DISPC_VID_ATTRIBUTES_VIDRESIZEENABLE_HRESIZE (1 << 5)
+#define DISPC_VID_ATTRIBUTES_VIDFORMAT (15 << 1)
+#define DISPC_VID_ATTRIBUTES_VIDFORMAT_RGB16 (6 << 1)
+#define DISPC_VID_ATTRIBUTES_VIDFORMAT_YUV2 (10 << 1)
+#define DISPC_VID_ATTRIBUTES_VIDFORMAT_UYVY (11 << 1)
+#define DISPC_VID_ATTRIBUTES_ENABLE (1 << 0)
+
+#define DISPC_VID_PICTURE_SIZE_VIDORGSIZEY (0x7FF << 16)
+#define DISPC_VID_PICTURE_SIZE_VIDORGSIZEY_SHIFT 16
+#define DISPC_VID_PICTURE_SIZE_VIDORGSIZEX 0x7FF
+#define DISPC_VID_PICTURE_SIZE_VIDORGSIZEX_SHIFT 0
+#define VIDIOC_S_VID2 _IOWR ('V', 90, struct omap24xx_vid2_format)
+#define VIDIOC_S_VID2_DISABLE _IOWR ('V', 91, int)
+
+#endif /* ifndef OMAP24XXFB_H */
+
+#endif /* ifndef OMAP24XXCAM_H */
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: omap24xxcam status (Was: v4l2 camera test app)
2006-03-20 14:58 ` omap24xxcam status (Was: v4l2 camera test app) Komal Shah
@ 2006-03-20 16:10 ` David Cohen
0 siblings, 0 replies; 8+ messages in thread
From: David Cohen @ 2006-03-20 16:10 UTC (permalink / raw)
To: ext Komal Shah; +Cc: Linux-omap-open-source
Hi,
I just sent a code that should be compilable and working. I guess the
mainly target is to apply this patch to the public tree. After that, as
Komal said, could be interesting to update the dma code to the omap api
to be easier future reviews.
Regards,
David Cohen
ext Komal Shah wrote:
>--- Ola Helm <ola.hel@gmail.com> wrote:
>
>
>
>>Hi,
>>
>>Have you got some idea what's the situation of the 24xx camera driver
>>at the
>>moment? AFAIK the patch David sent in last month is not included to
>>tree,
>>propably since there were some opposite opinions about the way of
>>implementation and at least I did not have one file mentioned in
>>patch (I
>>think you mentioned about the same issue)
>>
>>
>
>24xx camera driver is now in David's hand. I just review the code now,
>as not able to work on camera stuff anymore.
>
>Following strategy can work out meanwhile as I had offline discussion
>with David :)
>
>o Separate 24xx CamDMA code from omap24xxcam.c to new file as
> exported apis (Suggested by David)
>
>o Keep the old omap24xxcam driver interface(2.6.8 TI kernel days),
> having video out code part of the camera driver itself. As new
> separated video out code depends upon the common display controller
> library, which requires to change fb driver in git tree to adopt
> that interface, so that video out, and fb driver can
> utilize the same code. But video out patches submitted by me didn't
> generated any discussion on the list in that direction.
>
>o So, to have 24xx camera code in git tree, we can use the old camera
> driver interface as of now, if everyone agrees.
>
>---Komal Shah
>http://komalshah.blogspot.com/
>
>__________________________________________________
>Do You Yahoo!?
>Tired of spam? Yahoo! Mail has the best spam protection around
>http://mail.yahoo.com
>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* RE: omap24xxcam status (Was: v4l2 camera test app)
@ 2006-03-20 16:27 Zhang, Jian
2006-03-20 17:36 ` David Cohen
0 siblings, 1 reply; 8+ messages in thread
From: Zhang, Jian @ 2006-03-20 16:27 UTC (permalink / raw)
To: David Cohen, ext Komal Shah; +Cc: Linux-omap-open-source
David,
I don't see the new sensor interface incorporated in your patch. It is
likely that Micron 2MP camera MT9D111 will be used by more people. The
new sensor interface supports double-context which is an advanced
feature of micron camera.
Regards,
Jian
-----Original Message-----
From: David Cohen [mailto:david.cohen@indt.org.br]
Sent: Monday, March 20, 2006 10:10 AM
To: ext Komal Shah
Cc: Ola Helm; Linux-omap-open-source@linux.omap.com; Zhang, Jian
Subject: Re: omap24xxcam status (Was: v4l2 camera test app)
Hi,
I just sent a code that should be compilable and working. I guess the
mainly target is to apply this patch to the public tree. After that, as
Komal said, could be interesting to update the dma code to the omap api
to be easier future reviews.
Regards,
David Cohen
ext Komal Shah wrote:
>--- Ola Helm <ola.hel@gmail.com> wrote:
>
>
>
>>Hi,
>>
>>Have you got some idea what's the situation of the 24xx camera driver
>>at the
>>moment? AFAIK the patch David sent in last month is not included to
>>tree,
>>propably since there were some opposite opinions about the way of
>>implementation and at least I did not have one file mentioned in
>>patch (I
>>think you mentioned about the same issue)
>>
>>
>
>24xx camera driver is now in David's hand. I just review the code now,
>as not able to work on camera stuff anymore.
>
>Following strategy can work out meanwhile as I had offline discussion
>with David :)
>
>o Separate 24xx CamDMA code from omap24xxcam.c to new file as
> exported apis (Suggested by David)
>
>o Keep the old omap24xxcam driver interface(2.6.8 TI kernel days),
> having video out code part of the camera driver itself. As new
> separated video out code depends upon the common display controller
> library, which requires to change fb driver in git tree to adopt
> that interface, so that video out, and fb driver can
> utilize the same code. But video out patches submitted by me didn't
> generated any discussion on the list in that direction.
>
>o So, to have 24xx camera code in git tree, we can use the old camera
> driver interface as of now, if everyone agrees.
>
>---Komal Shah
>http://komalshah.blogspot.com/
>
>__________________________________________________
>Do You Yahoo!?
>Tired of spam? Yahoo! Mail has the best spam protection around
>http://mail.yahoo.com
>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: omap24xxcam status (Was: v4l2 camera test app)
2006-03-20 16:27 omap24xxcam status (Was: v4l2 camera test app) Zhang, Jian
@ 2006-03-20 17:36 ` David Cohen
0 siblings, 0 replies; 8+ messages in thread
From: David Cohen @ 2006-03-20 17:36 UTC (permalink / raw)
To: ext Zhang, Jian; +Cc: Linux-omap-open-source
Yes... good point. I will genereted another patch with support to this
new interface.
But it would be great if anyone could test this patch on H4.
Regards,
David Cohen
ext Zhang, Jian wrote:
>David,
>
>I don't see the new sensor interface incorporated in your patch. It is
>likely that Micron 2MP camera MT9D111 will be used by more people. The
>new sensor interface supports double-context which is an advanced
>feature of micron camera.
>
>Regards,
>Jian
>
>-----Original Message-----
>From: David Cohen [mailto:david.cohen@indt.org.br]
>Sent: Monday, March 20, 2006 10:10 AM
>To: ext Komal Shah
>Cc: Ola Helm; Linux-omap-open-source@linux.omap.com; Zhang, Jian
>Subject: Re: omap24xxcam status (Was: v4l2 camera test app)
>
>Hi,
>
>I just sent a code that should be compilable and working. I guess the
>mainly target is to apply this patch to the public tree. After that, as
>Komal said, could be interesting to update the dma code to the omap api
>to be easier future reviews.
>
>Regards,
>
>David Cohen
>
>ext Komal Shah wrote:
>
>
>
>>--- Ola Helm <ola.hel@gmail.com> wrote:
>>
>>
>>
>>
>>
>>>Hi,
>>>
>>>Have you got some idea what's the situation of the 24xx camera driver
>>>at the
>>>moment? AFAIK the patch David sent in last month is not included to
>>>tree,
>>>propably since there were some opposite opinions about the way of
>>>implementation and at least I did not have one file mentioned in
>>>patch (I
>>>think you mentioned about the same issue)
>>>
>>>
>>>
>>>
>>24xx camera driver is now in David's hand. I just review the code now,
>>as not able to work on camera stuff anymore.
>>
>>Following strategy can work out meanwhile as I had offline discussion
>>with David :)
>>
>>o Separate 24xx CamDMA code from omap24xxcam.c to new file as
>> exported apis (Suggested by David)
>>
>>o Keep the old omap24xxcam driver interface(2.6.8 TI kernel days),
>> having video out code part of the camera driver itself. As new
>> separated video out code depends upon the common display controller
>> library, which requires to change fb driver in git tree to adopt
>> that interface, so that video out, and fb driver can
>> utilize the same code. But video out patches submitted by me didn't
>> generated any discussion on the list in that direction.
>>
>>o So, to have 24xx camera code in git tree, we can use the old camera
>> driver interface as of now, if everyone agrees.
>>
>>---Komal Shah
>>http://komalshah.blogspot.com/
>>
>>__________________________________________________
>>Do You Yahoo!?
>>Tired of spam? Yahoo! Mail has the best spam protection around
>>http://mail.yahoo.com
>>
>>
>>
>>
>
>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] Re: v4l2 camera test app
2006-03-20 15:45 ` [PATCH] Re: v4l2 camera test app David Cohen
@ 2006-03-20 20:16 ` Komal Shah
0 siblings, 0 replies; 8+ messages in thread
From: Komal Shah @ 2006-03-20 20:16 UTC (permalink / raw)
To: David Cohen, ext Ola Helm; +Cc: linux-omap-open-source
--- David Cohen <david.cohen@indt.org.br> wrote:
> Hi,
>
> I am sending a new version of the camera driver for omap2420. Unlike
> the
> last patch I sent, I am not using those functions from dispc and vout
> that were not applied yet.
> The sensor module should be configured to BT8. The configurations for
> NOBT are in the code, but commented on omap24xxcam_sensor_cc_ctrl
> function. It can be changed if necessary.
>
> +
> +#include "omap24xxcam.h"
> +
> +#define CAMERA_OV9640
> +#ifdef CAMERA_OV9640
> +#include "ov9640.h"
> +#endif
You may not need to include this.
> +static void omap24xxcam_sensor_cc_ctrl(struct omap24xxcam_device
> *cam)
> +{
> + struct v4l2_pix_format *pix = &cam->pix;
> +
> + DBG;
> +
> + cam->cc_ctrl = /*CC_CTRL_NOBT_SYNCHRO | CC_CTRL_NOBT_VS_POL */
> + CC_CTRL_BT_CORRECT | CC_CTRL_PAR_MODE_BT8;
As I believe this should come from sensor, I think Jian added this in
the new sensor interface.
> + if (!in_atomic()) {
> + set_current_state(TASK_INTERRUPTIBLE);
> + schedule_timeout(1);
We can use the new api available which combines this two functions.
> + CAMDMA_CSDP_WRITE_MODE_POSTED
> + | CAMDMA_CSDP_DST_BURST_EN_64
> + | CAMDMA_CSDP_DST_PACKED
> + | CAMDMA_CSDP_SRC_BURST_EN_64
Why changing from 16 to 64? vga?
> +
> + cam = kmalloc(sizeof(struct omap24xxcam_device), GFP_KERNEL);
> + if (!cam) {
> + printk(KERN_ERR CAM_NAME ": could not allocate memory\n");
> + goto init_error;
> + }
> + memset(cam, 0, sizeof(struct omap24xxcam_device));
I like kzalloc.
---Komal Shah
http://komalshah.blogspot.com/
__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2006-03-20 20:16 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-03-16 10:25 v4l2 camera test app Komal Shah
2006-03-20 13:19 ` Ola Helm
2006-03-20 14:58 ` omap24xxcam status (Was: v4l2 camera test app) Komal Shah
2006-03-20 16:10 ` David Cohen
2006-03-20 15:45 ` [PATCH] Re: v4l2 camera test app David Cohen
2006-03-20 20:16 ` Komal Shah
-- strict thread matches above, loose matches on Subject: below --
2006-03-20 16:27 omap24xxcam status (Was: v4l2 camera test app) Zhang, Jian
2006-03-20 17:36 ` David Cohen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox