Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci-2.6.23
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci-2.6.23
Commits
8403b938
Commit
8403b938
authored
May 09, 2005
by
Tony Lindgren
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add OMAP camera driver
Adds OMAP camera driver. Signed-off-by:
Tony Lindgren
<
tony@atomide.com
>
parent
4ed2ff0a
Changes
12
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
3588 additions
and
0 deletions
+3588
-0
drivers/media/video/Kconfig
drivers/media/video/Kconfig
+6
-0
drivers/media/video/Makefile
drivers/media/video/Makefile
+1
-0
drivers/media/video/omap/Makefile
drivers/media/video/omap/Makefile
+7
-0
drivers/media/video/omap/camera_core.c
drivers/media/video/omap/camera_core.c
+1197
-0
drivers/media/video/omap/camera_core.h
drivers/media/video/omap/camera_core.h
+155
-0
drivers/media/video/omap/camera_hw_if.h
drivers/media/video/omap/camera_hw_if.h
+48
-0
drivers/media/video/omap/omap16xxcam.c
drivers/media/video/omap/omap16xxcam.c
+584
-0
drivers/media/video/omap/omap16xxcam.h
drivers/media/video/omap/omap16xxcam.h
+106
-0
drivers/media/video/omap/ov9640.h
drivers/media/video/omap/ov9640.h
+179
-0
drivers/media/video/omap/sensor_if.h
drivers/media/video/omap/sensor_if.h
+49
-0
drivers/media/video/omap/sensor_ov9640.c
drivers/media/video/omap/sensor_ov9640.c
+1181
-0
include/asm-arm/arch-omap/camera.h
include/asm-arm/arch-omap/camera.h
+75
-0
No files found.
drivers/media/video/Kconfig
View file @
8403b938
...
...
@@ -358,4 +358,10 @@ config VIDEO_M32R_AR_M64278
Say Y here to use the Renesas M64278E-800 camera module,
which supports VGA(640x480 pixcels) size of images.
config VIDEO_OMAP_CAMERA
tristate "OMAP Video for Linux camera driver"
depends on VIDEO_DEV && ARCH_OMAP16XX
select VIDEO_BUF
endmenu
drivers/media/video/Makefile
View file @
8403b938
...
...
@@ -52,5 +52,6 @@ obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o
obj-$(CONFIG_VIDEO_TVEEPROM)
+=
tveeprom.o
obj-$(CONFIG_VIDEO_M32R_AR_M64278)
+=
arv.o
obj-$(CONFIG_VIDEO_OMAP_CAMERA)
+=
omap/
EXTRA_CFLAGS
+=
-I
$(srctree)
/drivers/media/dvb/dvb-core
drivers/media/video/omap/Makefile
0 → 100644
View file @
8403b938
# Makefile for camera driver for H2/H3
omapCamera-objs
:=
camera_core.o omap16xxcam.o sensor_ov9640.o
obj-y
+=
omapCamera.o
EXTRA_CFLAGS
=
-I
$(src)
/..
drivers/media/video/omap/camera_core.c
0 → 100644
View file @
8403b938
/*
* drivers/media/video/omap/camera_core.c
*
* Copyright (C) 2004 Texas Instruments, Inc.
*
* Video-for-Linux (Version 2) camera capture driver for
* the OMAP H2 and H3 camera controller.
*
* Adapted from omap24xx driver written by Andy Lowe (source@mvista.com)
* Copyright (C) 2003-2004 MontaVista Software, Inc.
*
* This package is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* History:
* 27/03/05 Vladimir Barinov - Added support for power management
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/ctype.h>
#include <linux/pagemap.h>
#include <linux/mm.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/videodev.h>
#include <linux/pci.h>
#include <asm/semaphore.h>
#include <asm/processor.h>
#include <linux/dma-mapping.h>
#include <linux/fb.h>
#include <asm/io.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
#include "sensor_if.h"
#include "camera_hw_if.h"
#include "camera_core.h"
struct
camera_device
*
camera_dev
;
extern
struct
camera_sensor
camera_sensor_if
;
extern
struct
camera_hardware
camera_hardware_if
;
static
void
camera_core_sgdma_process
(
struct
camera_device
*
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 sxga.
*/
static
int
overlay_mem
=
640
*
480
*
2
;
/* DMA completion routine for the scatter-gather DMA fragments. */
/* This function is called when a scatter DMA fragment is completed */
static
void
camera_core_callback_sgdma
(
void
*
arg1
,
void
*
arg2
)
{
struct
camera_device
*
cam
=
(
struct
camera_device
*
)
arg1
;
int
sgslot
=
(
int
)
arg2
;
struct
sgdma_state
*
sgdma
;
spin_lock
(
&
cam
->
sg_lock
);
sgdma
=
cam
->
sgdma
+
sgslot
;
if
(
!
sgdma
->
queued_sglist
)
{
spin_unlock
(
&
cam
->
sg_lock
);
printk
(
KERN_ERR
CAM_NAME
": SGDMA completed when none queued
\n
"
);
return
;
}
if
(
!--
sgdma
->
queued_sglist
)
{
/* queue for this sglist is empty so check whether transfer
** of the frame has been completed */
if
(
sgdma
->
next_sglist
==
sgdma
->
sglen
)
{
dma_callback_t
callback
=
sgdma
->
callback
;
void
*
arg
=
sgdma
->
arg
;
/* all done with this sglist */
cam
->
free_sgdma
++
;
if
(
callback
)
{
spin_unlock
(
&
cam
->
sg_lock
);
(
*
callback
)(
cam
,
arg
);
camera_core_sgdma_process
(
cam
);
return
;
}
}
}
spin_unlock
(
&
cam
->
sg_lock
);
camera_core_sgdma_process
(
cam
);
return
;
}
static
void
camera_core_sgdma_init
(
struct
camera_device
*
cam
)
{
int
sg
;
/* Initialize the underlying camera DMA */
cam
->
cam_hardware
->
init_dma
(
cam
->
hardware_data
);
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
;
}
}
/*
* Process the scatter-gather DMA queue by starting queued transfers
* This function is called to program the dma to start the transfer of an image.
*/
static
void
camera_core_sgdma_process
(
struct
camera_device
*
cam
)
{
unsigned
long
irqflags
;
int
queued_sgdma
,
sgslot
;
struct
sgdma_state
*
sgdma
;
const
struct
scatterlist
*
sglist
;
spin_lock_irqsave
(
&
cam
->
sg_lock
,
irqflags
);
if
(
1
==
cam
->
in_use
)
{
spin_unlock_irqrestore
(
&
cam
->
sg_lock
,
irqflags
);
return
;
}
cam
->
in_use
=
1
;
spin_unlock_irqrestore
(
&
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
)
{
sglist
=
sgdma
->
sglist
+
sgdma
->
next_sglist
;
if
(
cam
->
cam_hardware
->
start_dma
(
sgdma
,
camera_core_callback_sgdma
,
(
void
*
)
cam
,
(
void
*
)
sgslot
,
cam
->
hardware_data
))
{
/* dma start failed */
cam
->
in_use
=
0
;
return
;
}
else
{
/* dma start successful */
sgdma
->
next_sglist
++
;
sgdma
->
queued_sglist
++
;
}
}
queued_sgdma
--
;
sgslot
=
(
sgslot
+
1
)
%
(
NUM_SG_DMA
);
}
cam
->
in_use
=
0
;
}
/* 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
camera_core_sgdma_queue
(
struct
camera_device
*
cam
,
const
struct
scatterlist
*
sglist
,
int
sglen
,
dma_callback_t
callback
,
void
*
arg
)
{
unsigned
long
irqflags
;
struct
sgdma_state
*
sgdma
;
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
);
camera_core_sgdma_process
(
cam
);
return
0
;
}
/* -------------------overlay routines ------------------------------*/
/* callback routine for overlay DMA completion. We just start another DMA
* transfer unless overlay has been turned off
*/
static
void
camera_core_overlay_callback
(
void
*
arg1
,
void
*
arg
)
{
struct
camera_device
*
cam
=
(
struct
camera_device
*
)
arg1
;
int
err
;
unsigned
long
irqflags
;
int
i
,
j
;
int
count
,
index
;
unsigned
char
*
fb_buf
=
phys_to_virt
((
unsigned
long
)
camera_dev
->
fbuf
.
base
);
spin_lock_irqsave
(
&
cam
->
overlay_lock
,
irqflags
);
if
(
!
cam
->
previewing
||
cam
->
overlay_cnt
==
0
)
{
spin_unlock_irqrestore
(
&
cam
->
overlay_lock
,
irqflags
);
return
;
}
--
cam
->
overlay_cnt
;
sg_dma_address
(
&
cam
->
overlay_sglist
)
=
cam
->
overlay_base_phys
;
sg_dma_len
(
&
cam
->
overlay_sglist
)
=
cam
->
pix
.
sizeimage
;
count
=
0
;
j
=
((
cam
->
pix
.
width
-
1
)
*
cam
->
fbuf
.
fmt
.
bytesperline
);
for
(
i
=
0
;
i
<
cam
->
pix
.
sizeimage
;
i
+=
cam
->
pix
.
bytesperline
)
{
for
(
index
=
0
;
index
<
cam
->
pix
.
bytesperline
;
index
++
)
{
fb_buf
[
j
]
=
*
(((
unsigned
char
*
)
cam
->
overlay_base
)
+
i
+
index
);
index
++
;
fb_buf
[
j
+
1
]
=
*
(((
unsigned
char
*
)
cam
->
overlay_base
)
+
i
+
index
);
j
=
j
-
cam
->
fbuf
.
fmt
.
bytesperline
;
}
count
+=
2
;
j
=
((
cam
->
pix
.
width
-
1
)
*
cam
->
fbuf
.
fmt
.
bytesperline
)
+
count
;
}
while
(
cam
->
overlay_cnt
<
2
)
{
err
=
camera_core_sgdma_queue
(
cam
,
&
cam
->
overlay_sglist
,
1
,
camera_core_overlay_callback
,
NULL
);
if
(
err
)
break
;
++
cam
->
overlay_cnt
;
}
spin_unlock_irqrestore
(
&
cam
->
overlay_lock
,
irqflags
);
}
static
void
camera_core_start_overlay
(
struct
camera_device
*
cam
)
{
int
err
;
unsigned
long
irqflags
;
if
(
!
cam
->
previewing
)
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
=
camera_core_sgdma_queue
(
cam
,
&
cam
->
overlay_sglist
,
1
,
camera_core_overlay_callback
,
NULL
);
if
(
err
)
break
;
++
cam
->
overlay_cnt
;
}
spin_unlock_irqrestore
(
&
cam
->
overlay_lock
,
irqflags
);
}
/* ------------------ videobuf_queue_ops ---------------------------------------- */
/* This routine is called from interrupt context when a scatter-gather DMA
* transfer of a videobuf_buffer completes.
*/
static
void
camera_core_vbq_complete
(
void
*
arg1
,
void
*
arg
)
{
struct
camera_device
*
cam
=
(
struct
camera_device
*
)
arg1
;
struct
videobuf_buffer
*
vb
=
(
struct
videobuf_buffer
*
)
arg
;
spin_lock
(
&
cam
->
vbq_lock
);
do_gettimeofday
(
&
vb
->
ts
);
vb
->
field_count
=
cam
->
field_count
;
cam
->
field_count
+=
2
;
vb
->
state
=
STATE_DONE
;
wake_up
(
&
vb
->
done
);
spin_unlock
(
&
cam
->
vbq_lock
);
}
static
void
camera_core_vbq_release
(
struct
videobuf_queue
*
q
,
struct
videobuf_buffer
*
vb
)
{
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
camera_core_vbq_setup
(
struct
videobuf_queue
*
q
,
unsigned
int
*
cnt
,
unsigned
int
*
size
)
{
struct
camera_device
*
cam
=
q
->
priv_data
;
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
camera_core_vbq_prepare
(
struct
videobuf_queue
*
q
,
struct
videobuf_buffer
*
vb
,
enum
v4l2_field
field
)
{
struct
camera_device
*
cam
=
q
->
priv_data
;
int
err
=
0
;
spin_lock
(
&
cam
->
img_lock
);
if
(
cam
->
pix
.
sizeimage
>
vb
->
bsize
)
{
spin_unlock
(
&
cam
->
img_lock
);
return
-
EINVAL
;
}
vb
->
size
=
cam
->
pix
.
sizeimage
;
vb
->
width
=
cam
->
pix
.
width
;
vb
->
height
=
cam
->
pix
.
height
;
vb
->
field
=
field
;
spin_unlock
(
&
cam
->
img_lock
);
if
(
vb
->
state
==
STATE_NEEDS_INIT
)
err
=
videobuf_iolock
(
NULL
,
vb
,
NULL
);
if
(
!
err
)
vb
->
state
=
STATE_PREPARED
;
else
camera_core_vbq_release
(
q
,
vb
);
return
err
;
}
static
void
camera_core_vbq_queue
(
struct
videobuf_queue
*
q
,
struct
videobuf_buffer
*
vb
)
{
struct
camera_device
*
cam
=
q
->
priv_data
;
enum
videobuf_state
state
=
vb
->
state
;
int
err
;
vb
->
state
=
STATE_QUEUED
;
err
=
camera_core_sgdma_queue
(
cam
,
vb
->
dma
.
sglist
,
vb
->
dma
.
sglen
,
camera_core_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 SGDMA
\n
"
);
vb
->
state
=
state
;
}
}
/* ------------------ videobuf_queue_ops ---------------------------------------- */
static
int
camera_core_do_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
void
*
arg
)
{
struct
camera_fh
*
fh
=
file
->
private_data
;
struct
camera_device
*
cam
=
fh
->
cam
;
int
err
;
switch
(
cmd
)
{
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_ENUM_FMT
:
{
struct
v4l2_fmtdesc
*
fmt
=
arg
;
return
cam
->
cam_sensor
->
enum_pixformat
(
fmt
,
cam
->
sensor_data
);
}
case
VIDIOC_TRY_FMT
:
{
struct
v4l2_format
*
fmt
=
arg
;
return
cam
->
cam_sensor
->
try_format
(
&
fmt
->
fmt
.
pix
,
cam
->
sensor_data
);
}
case
VIDIOC_G_FMT
:
{
struct
v4l2_format
*
fmt
=
arg
;
/* get the current format */
memset
(
&
fmt
->
fmt
.
pix
,
0
,
sizeof
(
fmt
->
fmt
.
pix
));
fmt
->
fmt
.
pix
=
cam
->
pix
;
return
0
;
}
case
VIDIOC_S_FMT
:
{
struct
v4l2_format
*
fmt
=
arg
;
unsigned
int
temp_sizeimage
=
0
;
temp_sizeimage
=
cam
->
pix
.
sizeimage
;
cam
->
cam_sensor
->
try_format
(
&
fmt
->
fmt
.
pix
,
cam
->
sensor_data
);
cam
->
pix
=
fmt
->
fmt
.
pix
;
cam
->
xclk
=
cam
->
cam_sensor
->
calc_xclk
(
&
cam
->
pix
,
&
cam
->
nominal_timeperframe
,
cam
->
sensor_data
);
cam
->
cparm
.
timeperframe
=
cam
->
nominal_timeperframe
;
cam
->
xclk
=
cam
->
cam_hardware
->
set_xclk
(
cam
->
xclk
,
cam
->
hardware_data
);
return
cam
->
cam_sensor
->
configure
(
&
cam
->
pix
,
cam
->
xclk
,
&
cam
->
cparm
.
timeperframe
,
cam
->
sensor_data
);
}
case
VIDIOC_QUERYCTRL
:
{
struct
v4l2_queryctrl
*
qc
=
arg
;
return
cam
->
cam_sensor
->
query_control
(
qc
,
cam
->
sensor_data
);
}
case
VIDIOC_G_CTRL
:
{
struct
v4l2_control
*
vc
=
arg
;
return
cam
->
cam_sensor
->
get_control
(
vc
,
cam
->
sensor_data
);
}
case
VIDIOC_S_CTRL
:
{
struct
v4l2_control
*
vc
=
arg
;
return
cam
->
cam_sensor
->
set_control
(
vc
,
cam
->
sensor_data
);
}
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_FBUF
:
/* Get the frame buffer parameters */
{
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
:
/* set the frame buffer parameters */
{
struct
v4l2_framebuffer
*
fbuf
=
(
struct
v4l2_framebuffer
*
)
arg
;
spin_lock
(
&
cam
->
img_lock
);
if
(
cam
->
previewing
)
{
spin_unlock
(
&
cam
->
img_lock
);
return
-
EBUSY
;
}
cam
->
fbuf
.
base
=
fbuf
->
base
;
cam
->
fbuf
.
fmt
=
fbuf
->
fmt
;
spin_unlock
(
&
cam
->
img_lock
);
return
0
;
}
case
VIDIOC_OVERLAY
:
{
int
enable
=
*
((
int
*
)
arg
);
/*
* check whether the capture format and
** the display format matches
* return failure if they are different
*/
if
(
cam
->
pix
.
pixelformat
!=
cam
->
fbuf
.
fmt
.
pixelformat
)
{
return
-
EINVAL
;
}
/* If the camera image size is greater
** than LCD size return failure */
if
((
cam
->
pix
.
width
>
cam
->
fbuf
.
fmt
.
height
)
||
(
cam
->
pix
.
height
>
cam
->
fbuf
.
fmt
.
width
))
{
return
-
EINVAL
;
}
if
(
!
cam
->
previewing
&&
enable
)
{
cam
->
previewing
=
fh
;
cam
->
overlay_cnt
=
0
;
camera_core_start_overlay
(
cam
);
}
else
if
(
!
enable
)
{
cam
->
previewing
=
NULL
;
}
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
||
cam
->
reading
)
{
spin_unlock
(
&
cam
->
img_lock
);
return
-
EBUSY
;
}
else
{
cam
->
streaming
=
fh
;
/* FIXME: start camera interface */
}
spin_unlock
(
&
cam
->
img_lock
);
return
videobuf_streamon
(
&
fh
->
vbq
);
}
case
VIDIOC_STREAMOFF
:
{
err
=
videobuf_streamoff
(
&
fh
->
vbq
);
if
(
err
<
0
)
return
err
;
spin_lock
(
&
cam
->
img_lock
);
if
(
cam
->
streaming
==
fh
)
{
cam
->
streaming
=
NULL
;
/* FIXME: stop camera interface */
}
spin_unlock
(
&
cam
->
img_lock
);
return
0
;
}
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
;
}
default:
{
/* unrecognized ioctl */
return
-
ENOIOCTLCMD
;
}
}
return
0
;
}
/*
* file operations
*/
static
unsigned
int
camera_core_poll
(
struct
file
*
file
,
struct
poll_table_struct
*
wait
)
{
return
-
EINVAL
;
}
/* ------------------------------------------------------------ */
/* callback routine for read DMA completion. We just start another DMA
* transfer unless overlay has been turned off
*/
static
void
camera_core_capture_callback
(
void
*
arg1
,
void
*
arg
)
{
struct
camera_device
*
cam
=
(
struct
camera_device
*
)
arg1
;
int
err
;
unsigned
long
irqflags
;
static
int
done
=
0
;
spin_lock_irqsave
(
&
cam
->
capture_lock
,
irqflags
);
if
(
!
cam
->
reading
)
{
done
=
0
;
cam
->
capture_started
=
0
;
spin_unlock_irqrestore
(
&
cam
->
capture_lock
,
irqflags
);
return
;
}
if
(
done
<
14
)
{
++
done
;
sg_dma_address
(
&
cam
->
capture_sglist
)
=
cam
->
capture_base_phys
;
sg_dma_len
(
&
cam
->
capture_sglist
)
=
cam
->
pix
.
sizeimage
;
err
=
camera_core_sgdma_queue
(
cam
,
&
cam
->
capture_sglist
,
1
,
camera_core_capture_callback
,
NULL
);
}
else
{
cam
->
capture_completed
=
1
;
if
(
cam
->
reading
)
{
/* Wake up any process which are waiting for the
** DMA to complete */
wake_up_interruptible
(
&
camera_dev
->
new_video_frame
);
sg_dma_address
(
&
cam
->
capture_sglist
)
=
cam
->
capture_base_phys
;
sg_dma_len
(
&
cam
->
capture_sglist
)
=
cam
->
pix
.
sizeimage
;
err
=
camera_core_sgdma_queue
(
cam
,
&
cam
->
capture_sglist
,
1
,
camera_core_capture_callback
,
NULL
);
}
}
spin_unlock_irqrestore
(
&
cam
->
capture_lock
,
irqflags
);
}
static
ssize_t
camera_core_read
(
struct
file
*
file
,
char
*
data
,
size_t
count
,
loff_t
*
ppos
)
{
struct
camera_fh
*
fh
=
file
->
private_data
;
struct
camera_device
*
cam
=
fh
->
cam
;
int
err
;
unsigned
long
irqflags
;
long
timeout
;
#if 0 /* use video_buf to do capture */
int i;
for (i = 0; i < 14; i++)
videobuf_read_one(file, &fh->vbq, data, count, ppos);
i = videobuf_read_one(file, &fh->vbq, data, count, ppos);
return i;
#endif
if
(
!
cam
->
capture_base
)
{
cam
->
capture_base
=
(
unsigned
long
)
dma_alloc_coherent
(
NULL
,
cam
->
pix
.
sizeimage
,
(
dma_addr_t
*
)
&
cam
->
capture_base_phys
,
GFP_KERNEL
|
GFP_DMA
);
}
if
(
!
cam
->
capture_base
)
{
printk
(
KERN_ERR
CAM_NAME
": cannot allocate capture buffer
\n
"
);
return
0
;
}
spin_lock_irqsave
(
&
cam
->
capture_lock
,
irqflags
);
cam
->
reading
=
fh
;
cam
->
capture_started
=
1
;
sg_dma_address
(
&
cam
->
capture_sglist
)
=
cam
->
capture_base_phys
;
sg_dma_len
(
&
cam
->
capture_sglist
)
=
cam
->
pix
.
sizeimage
;
spin_unlock_irqrestore
(
&
cam
->
capture_lock
,
irqflags
);
err
=
camera_core_sgdma_queue
(
cam
,
&
cam
->
capture_sglist
,
1
,
camera_core_capture_callback
,
NULL
);
/* Wait till DMA is completed */
timeout
=
HZ
*
10
;
cam
->
capture_completed
=
0
;
while
(
cam
->
capture_completed
==
0
)
{
timeout
=
interruptible_sleep_on_timeout
(
&
cam
->
new_video_frame
,
timeout
);
if
(
timeout
==
0
)
{
printk
(
KERN_ERR
CAM_NAME
": timeout waiting video frame
\n
"
);
return
-
EIO
;
/* time out */
}
}
/* copy the data to the user buffer */
err
=
copy_to_user
(
data
,
(
void
*
)
cam
->
capture_base
,
cam
->
pix
.
sizeimage
);
return
(
cam
->
pix
.
sizeimage
-
err
);
}
static
int
camera_core_mmap
(
struct
file
*
file
,
struct
vm_area_struct
*
vma
)
{
struct
camera_fh
*
fh
=
file
->
private_data
;
return
videobuf_mmap_mapper
(
&
fh
->
vbq
,
vma
);
}
static
int
camera_core_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
return
video_usercopy
(
inode
,
file
,
cmd
,
arg
,
camera_core_do_ioctl
);
}
static
int
camera_core_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
struct
camera_fh
*
fh
=
file
->
private_data
;
struct
camera_device
*
cam
=
fh
->
cam
;
file
->
private_data
=
NULL
;
kfree
(
fh
);
spin_lock
(
&
cam
->
img_lock
);
if
(
cam
->
previewing
==
fh
)
{
cam
->
previewing
=
NULL
;
}
if
(
cam
->
streaming
==
fh
)
{
cam
->
streaming
=
NULL
;
}
if
(
cam
->
reading
==
fh
)
{
cam
->
reading
=
NULL
;
}
spin_unlock
(
&
cam
->
img_lock
);
camera_dev
->
cam_hardware
->
finish_dma
(
cam
->
hardware_data
);
if
(
cam
->
capture_base
)
{
dma_free_coherent
(
NULL
,
cam
->
pix
.
sizeimage
,
(
void
*
)
cam
->
capture_base
,
cam
->
capture_base_phys
);
cam
->
capture_base
=
0
;
cam
->
capture_base_phys
=
0
;
}
if
(
fh
->
vbq
.
read_buf
)
{
camera_core_vbq_release
(
&
fh
->
vbq
,
fh
->
vbq
.
read_buf
);
kfree
(
fh
->
vbq
.
read_buf
);
}
cam
->
cam_hardware
->
close
(
cam
->
hardware_data
);
cam
->
active
=
0
;
return
0
;
}
static
int
camera_core_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
int
minor
=
iminor
(
inode
);
struct
camera_device
*
cam
=
camera_dev
;
struct
camera_fh
*
fh
;
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
;
spin_lock
(
&
cam
->
img_lock
);
if
(
cam
->
active
==
1
)
{
printk
(
KERN_ERR
CAM_NAME
": Camera device Active
\n
"
);
spin_unlock
(
&
cam
->
img_lock
);
return
-
EPERM
;
}
cam
->
active
=
1
;
spin_unlock
(
&
cam
->
img_lock
);
videobuf_queue_init
(
&
fh
->
vbq
,
&
cam
->
vbq_ops
,
NULL
,
&
cam
->
vbq_lock
,
fh
->
type
,
V4L2_FIELD_NONE
,
sizeof
(
struct
videobuf_buffer
),
fh
);
cam
->
capture_completed
=
0
;
cam
->
capture_started
=
0
;
if
(
cam
->
cam_hardware
->
open
(
cam
->
hardware_data
))
{
printk
(
KERN_ERR
CAM_NAME
": Camera IF configuration failed
\n
"
);
cam
->
active
=
0
;
return
-
ENODEV
;
}
cam
->
xclk
=
cam
->
cam_hardware
->
set_xclk
(
cam
->
xclk
,
cam
->
hardware_data
);
/* program the sensor for the capture format and rate */
if
(
cam
->
cam_sensor
->
configure
(
&
cam
->
pix
,
cam
->
xclk
,
&
cam
->
cparm
.
timeperframe
,
cam
->
sensor_data
))
{
printk
(
KERN_ERR
CAM_NAME
": Camera sensor configuration failed
\n
"
);
cam
->
cam_hardware
->
close
(
cam
->
hardware_data
);
cam
->
active
=
0
;
return
-
ENODEV
;
}
return
0
;
}
#ifdef CONFIG_PM
static
int
camera_core_suspend
(
struct
device
*
dev
,
u32
state
,
u32
level
)
{
struct
camera_device
*
cam
=
dev_get_drvdata
(
dev
);
int
ret
=
0
;
spin_lock
(
&
cam
->
img_lock
);
switch
(
level
)
{
case
SUSPEND_POWER_DOWN
:
if
(
cam
->
active
)
{
cam
->
cam_hardware
->
close
(
cam
->
hardware_data
);
}
cam
->
cam_sensor
->
power_off
(
cam
->
sensor_data
);
break
;
}
spin_unlock
(
&
cam
->
img_lock
);
return
ret
;
}
static
int
camera_core_resume
(
struct
device
*
dev
,
u32
level
)
{
struct
camera_device
*
cam
=
dev_get_drvdata
(
dev
);
int
ret
=
0
;
spin_lock
(
&
cam
->
img_lock
);
switch
(
level
)
{
case
RESUME_POWER_ON
:
cam
->
cam_sensor
->
power_on
(
cam
->
sensor_data
);
if
(
cam
->
active
)
{
cam
->
capture_completed
=
1
;
cam
->
cam_hardware
->
open
(
cam
->
hardware_data
);
cam
->
cam_hardware
->
set_xclk
(
cam
->
xclk
,
cam
->
hardware_data
);
cam
->
cam_sensor
->
configure
(
&
cam
->
pix
,
cam
->
xclk
,
&
cam
->
cparm
.
timeperframe
,
cam
->
sensor_data
);
camera_core_sgdma_process
(
cam
);
}
break
;
}
spin_unlock
(
&
cam
->
img_lock
);
return
ret
;
}
#endif
/* CONFIG_PM */
static
struct
file_operations
camera_core_fops
=
{
.
owner
=
THIS_MODULE
,
.
llseek
=
no_llseek
,
.
read
=
camera_core_read
,
.
poll
=
camera_core_poll
,
.
ioctl
=
camera_core_ioctl
,
.
mmap
=
camera_core_mmap
,
.
open
=
camera_core_open
,
.
release
=
camera_core_release
,
};
static
struct
device_driver
camera_core_driver
=
{
.
name
=
CAM_NAME
,
.
bus
=
&
platform_bus_type
,
.
probe
=
NULL
,
.
remove
=
NULL
,
#ifdef CONFIG_PM
.
suspend
=
camera_core_suspend
,
.
resume
=
camera_core_resume
,
#endif
.
shutdown
=
NULL
,
};
static
struct
platform_device
camera_core_device
=
{
.
name
=
CAM_NAME
,
.
dev
=
{
.
release
=
NULL
,
},
.
id
=
0
,
};
void
camera_core_cleanup
(
void
)
{
struct
camera_device
*
cam
=
camera_dev
;
struct
video_device
*
vfd
;
if
(
!
cam
)
return
;
vfd
=
cam
->
vfd
;
if
(
vfd
)
{
if
(
vfd
->
minor
==
-
1
)
{
/* The device never got 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
);
driver_unregister
(
&
camera_core_driver
);
platform_device_unregister
(
&
camera_core_device
);
}
cam
->
vfd
=
NULL
;
}
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
;
cam
->
cam_sensor
->
cleanup
(
cam
->
sensor_data
);
cam
->
cam_hardware
->
cleanup
(
cam
->
hardware_data
);
kfree
(
cam
);
camera_dev
=
NULL
;
return
;
}
int
__init
camera_core_init
(
void
)
{
struct
camera_device
*
cam
;
struct
video_device
*
vfd
;
cam
=
kmalloc
(
sizeof
(
struct
camera_device
),
GFP_KERNEL
);
if
(
!
cam
)
{
printk
(
KERN_ERR
CAM_NAME
": could not allocate memory
\n
"
);
goto
init_error
;
}
memset
(
cam
,
0
,
sizeof
(
struct
camera_device
));
/* Save the pointer to camera device in a global variable */
camera_dev
=
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
;
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
=
&
camera_core_fops
;
video_set_drvdata
(
vfd
,
cam
);
vfd
->
minor
=
-
1
;
/* initialize the videobuf queue ops */
cam
->
vbq_ops
.
buf_setup
=
camera_core_vbq_setup
;
cam
->
vbq_ops
.
buf_prepare
=
camera_core_vbq_prepare
;
cam
->
vbq_ops
.
buf_queue
=
camera_core_vbq_queue
;
cam
->
vbq_ops
.
buf_release
=
camera_core_vbq_release
;
/* initilize the overlay interface */
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
);
spin_lock_init
(
&
cam
->
overlay_lock
);
spin_lock_init
(
&
cam
->
capture_lock
);
/*Initialise the pointer to the sensor interface and camera interface */
cam
->
cam_sensor
=
&
camera_sensor_if
;
cam
->
cam_hardware
=
&
camera_hardware_if
;
/* initialize the camera interface */
cam
->
hardware_data
=
cam
->
cam_hardware
->
init
();
if
(
!
cam
->
hardware_data
)
{
printk
(
KERN_ERR
CAM_NAME
": cannot initialize interface hardware
\n
"
);
goto
init_error
;
}
/* initialize the spinlock used to serialize access to the image
* parameters
*/
spin_lock_init
(
&
cam
->
img_lock
);
/* initialize the streaming capture parameters */
cam
->
cparm
.
capability
=
V4L2_CAP_TIMEPERFRAME
;
cam
->
cparm
.
readbuffers
=
1
;
/* 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
=
21000000
;
/* choose an arbitrary xclk frequency */
cam
->
xclk
=
cam
->
cam_hardware
->
set_xclk
(
cam
->
xclk
,
cam
->
hardware_data
);
/* initialize the sensor and define a default capture format cam->pix */
cam
->
sensor_data
=
cam
->
cam_sensor
->
init
(
&
cam
->
pix
);
if
(
!
cam
->
sensor_data
)
{
cam
->
cam_hardware
->
disable
(
cam
->
hardware_data
);
printk
(
KERN_ERR
CAM_NAME
": cannot initialize sensor
\n
"
);
goto
init_error
;
}
printk
(
KERN_INFO
CAM_NAME
": %s interface with %s sensor
\n
"
,
cam
->
cam_hardware
->
name
,
cam
->
cam_sensor
->
name
);
/* select an arbitrary default capture frame rate of 15fps */
cam
->
nominal_timeperframe
.
numerator
=
1
;
cam
->
nominal_timeperframe
.
denominator
=
15
;
/* 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_data
);
cam
->
cparm
.
timeperframe
=
cam
->
nominal_timeperframe
;
/* initialise the wait queue */
init_waitqueue_head
(
&
cam
->
new_video_frame
);
/* Initialise the DMA structures */
camera_core_sgdma_init
(
cam
);
/* Disable the Camera after detection */
cam
->
cam_hardware
->
disable
(
cam
->
hardware_data
);
dev_set_drvdata
(
&
camera_core_device
.
dev
,
(
void
*
)
cam
);
if
(
platform_device_register
(
&
camera_core_device
)
<
0
)
{
printk
(
KERN_ERR
CAM_NAME
": could not register platform_device
\n
"
);
goto
init_error
;
}
if
(
driver_register
(
&
camera_core_driver
)
<
0
)
{
printk
(
KERN_ERR
CAM_NAME
": could not register driver
\n
"
);
platform_device_unregister
(
&
camera_core_device
);
goto
init_error
;
}
if
(
video_register_device
(
vfd
,
VFL_TYPE_GRABBER
,
video_nr
)
<
0
)
{
printk
(
KERN_ERR
CAM_NAME
": could not register Video for Linux device
\n
"
);
platform_device_unregister
(
&
camera_core_device
);
driver_unregister
(
&
camera_core_driver
);
goto
init_error
;
}
printk
(
KERN_INFO
CAM_NAME
": registered device video%d [v4l2]
\n
"
,
vfd
->
minor
);
return
0
;
init_error:
camera_core_cleanup
();
return
-
ENODEV
;
}
MODULE_AUTHOR
(
"Texas Instruments."
);
MODULE_DESCRIPTION
(
"OMAP 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_init
(
camera_core_init
);
module_exit
(
camera_core_cleanup
);
drivers/media/video/omap/camera_core.h
0 → 100644
View file @
8403b938
/*
* drivers/media/video/omap/camera_core.h
*
* Copyright (C) 2004 Texas Instruments, Inc.
*
* This package is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef CAMERA_CORE__H
#define CAMERA_CORE__H
struct
camera_fh
;
#include <media/video-buf.h>
#include <asm/scatterlist.h>
struct
camera_device
;
typedef
void
(
*
dma_callback_t
)(
void
*
arg1
,
void
*
arg2
);
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
;
};
/* NUM_SG_DMA is the number of scatter-gather DMA transfers that can be queued.
*/
#define NUM_SG_DMA VIDEO_MAX_FRAME+2
/* per-device data structure */
struct
camera_device
{
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
;
unsigned
long
overlay_base_phys
;
unsigned
long
overlay_base
;
unsigned
long
overlay_size
;
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
];
char
in_use
;
/* The img_lock is used to serialize access to the image parameters for
* overlay and capture. Need to use spin_lock_irq when writing to the
* reading, streaming, and previewing parameters. A regular spin_lock
* will suffice for all other cases.
*/
spinlock_t
img_lock
;
/* We allow reading from at most one filehandle at a time.
* non-NULL means reading is in progress.
*/
struct
camera_fh
*
reading
;
/* We allow streaming from at most one filehandle at a time.
* non-NULL means streaming is in progress.
*/
struct
camera_fh
*
streaming
;
/* We allow previewing from at most one filehandle at a time.
* non-NULL means previewing is in progress.
*/
struct
camera_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 the sensor interface ops */
struct
camera_sensor
*
cam_sensor
;
void
*
sensor_data
;
/* Pointer to the camera interface hardware ops */
struct
camera_hardware
*
cam_hardware
;
void
*
hardware_data
;
/* 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
;
/* end of generic stuff, the above should be common to all omaps */
/* note, 2420 uses videobuf to do caprure, it is more memory efficient
we need 1710 and 2420 do capture in the same way */
/* Variables to store the capture state */
/* Wait till DMA is completed */
wait_queue_head_t
new_video_frame
;
char
capture_completed
;
char
capture_started
;
spinlock_t
capture_lock
;
struct
scatterlist
capture_sglist
;
unsigned
long
capture_base
;
unsigned
long
capture_base_phys
;
char
active
;
};
/* per-filehandle data structure */
struct
camera_fh
{
struct
camera_device
*
cam
;
enum
v4l2_buf_type
type
;
struct
videobuf_queue
vbq
;
};
#define CAM_NAME "omap-camera"
#endif
/* CAMERA_CORE__H */
drivers/media/video/omap/camera_hw_if.h
0 → 100644
View file @
8403b938
/*
* drivers/media/video/omap/camera_hw_if.h
*
* Copyright (C) 2004 Texas Instruments, Inc.
*
* Camera interface to OMAP camera capture drivers
* Camera interface hardware driver should implement this interface
*
* This package is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef OMAP_CAMERA_HW_IF_H
#define OMAP_CAMERA_HW_IF_H
#define LEN_HW_IF_NAME 31
struct
sgdma_state
;
struct
camera_hardware
{
unsigned
int
version
;
//version of camera driver module
char
name
[
LEN_HW_IF_NAME
+
1
];
void
*
(
*
init
)(
void
);
int
(
*
cleanup
)(
void
*
);
int
(
*
open
)(
void
*
);
/* acquire h/w resources (irq,DMA), etc. */
int
(
*
close
)(
void
*
);
/* free h/w resources, stop i/f */
int
(
*
enable
)(
void
*
);
int
(
*
disable
)(
void
*
);
int
(
*
abort
)(
void
*
);
int
(
*
set_xclk
)(
int
,
void
*
);
int
(
*
init_dma
)(
void
*
);
int
(
*
start_dma
)(
struct
sgdma_state
*
,
void
(
*
)(
void
*
arg1
,
void
*
arg2
),
void
*
,
void
*
,
void
*
);
int
(
*
finish_dma
)(
void
*
);
};
#endif
/* OMAP_CAMERA_HW_IF_H */
drivers/media/video/omap/omap16xxcam.c
0 → 100644
View file @
8403b938
/*
* drivers/media/video/omap/omap16xxcam.c
*
* Copyright (C) 2004 Texas Instruments, Inc.
*
* Video-for-Linux (Version 2) camera capture driver for
* the OMAP H2 and H3 camera controller.
*
* leverage some code from CEE distribution
* Copyright (C) 2003-2004 MontaVista Software, Inc.
*
* This package is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#include <linux/config.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <asm/arch/irqs.h>
#include <asm/arch/dma.h>
#include <asm/arch/hardware.h>
#include <asm/io.h>
#include <asm/scatterlist.h>
#include <asm/mach-types.h>
#include <asm/hardware/clock.h>
#include "omap16xxcam.h"
#include "camera_hw_if.h"
#include "camera_core.h"
#define CONF_CAMERAIF_RESET_R 5
#define EN_PER 0
/* NUM_CAMDMA_CHANNELS is the number of logical channels used for
* DMA data transfer.
*/
#define NUM_CAMDMA_CHANNELS 2
typedef
struct
{
unsigned
int
ctrlclock
;
/* 00 */
unsigned
int
it_status
;
/* 04 */
unsigned
int
mode
;
/* 08 */
unsigned
int
status
;
/* 0C */
unsigned
int
camdata
;
/* 10 */
unsigned
int
gpio
;
/* 14 */
unsigned
int
peak_counter
;
/* 18 */
}
camera_regs_t
;
struct
camdma_state
{
dma_callback_t
callback
;
void
*
arg1
;
void
*
arg2
;
};
struct
omap16xxcam
{
camera_regs_t
*
camera_regs
;
unsigned
long
iobase_phys
;
/* frequncy (in Hz) of camera interface functional clock (ocp_clk) */
unsigned
long
ocp_clk
;
/* dma related stuff */
spinlock_t
dma_lock
;
int
free_dmach
;
int
next_dmach
;
struct
camdma_state
camdma
[
NUM_CAMDMA_CHANNELS
];
int
dma_channel_number1
;
int
dma_channel_number2
;
wait_queue_head_t
vsync_wait
;
int
new
;
};
static
struct
omap16xxcam
hardware_data
;
static
int
omap16xxcam_set_xclk
(
int
,
void
*
);
static
void
omap16xx_cam_dma_link_callback
(
int
,
unsigned
short
,
void
*
);
/* Clears the camera data FIFO by setting RAZ_FIFO bit in MODE configuration
register. */
static
void
omap16xx_cam_clear_fifo
(
struct
omap16xxcam
*
data
)
{
data
->
camera_regs
->
mode
|=
RAZ_FIFO
;
udelay
(
10
);
data
->
camera_regs
->
mode
&=
~
RAZ_FIFO
;
}
static
void
omap16xx_cam_reset
(
struct
omap16xxcam
*
data
,
int
yes
)
{
if
(
machine_is_omap_h3
())
data
->
camera_regs
->
gpio
=
yes
?
0
:
1
;
else
data
->
camera_regs
->
gpio
=
yes
?
1
:
0
;
}
static
void
omap16xx_cam_init
(
void
)
{
/*
* FIXME - Use mux API's instead of directly writing in to MUX registers
*/
omap_writel
(
omap_readl
(
FUNC_MUX_CTRL_4
)
&
~
(
0x1ff
<<
21
),
FUNC_MUX_CTRL_4
);
omap_writel
(
0
,
FUNC_MUX_CTRL_5
);
omap_writel
(
omap_readl
(
PULL_DWN_CTRL_0
)
&
~
(
0x1FFF
<<
17
),
PULL_DWN_CTRL_0
);
omap_writel
(
omap_readl
(
PU_PD_SEL_0
)
&
~
(
0x1FFF
<<
17
),
PU_PD_SEL_0
);
omap_writel
(
0xeaef
,
COMP_MODE_CTRL_0
);
omap_writel
(
omap_readl
(
OMAP1610_RESET_CONTROL
)
&
~
(
1
<<
CONF_CAMERAIF_RESET_R
),
OMAP1610_RESET_CONTROL
);
omap_writel
(
omap_readl
(
OMAP1610_RESET_CONTROL
)
|
(
1
<<
CONF_CAMERAIF_RESET_R
),
OMAP1610_RESET_CONTROL
);
/* Enable peripheral reset */
omap_writew
(
omap_readw
(
ARM_RSTCT2
)
|
(
1
<<
EN_PER
),
ARM_RSTCT2
);
/* enable peripheral clock */
if
(
machine_is_omap_h3
())
clk_enable
(
clk_get
(
0
,
"tc2_ck"
));
else
{
clk_enable
(
clk_get
(
0
,
"armper_ck"
));
clk_enable
(
clk_get
(
0
,
"armxor_ck"
));
}
}
static
void
omap16xx_cam_waitfor_syncedge
(
struct
omap16xxcam
*
data
,
u32
edge_mask
)
{
data
->
camera_regs
->
mode
=
(
FIFO_TRIGGER_LVL
<<
THRESHOLD_BIT
)
|
edge_mask
;
do
{
interruptible_sleep_on
(
&
data
->
vsync_wait
);
}
while
(
signal_pending
(
current
));
}
static
void
omap16xx_cam_configure_dma
(
struct
omap16xxcam
*
data
)
{
data
->
camera_regs
->
mode
=
(
FIFO_TRIGGER_LVL
<<
THRESHOLD_BIT
)
|
EN_DMA
|
EN_FIFO_FULL
;
data
->
camera_regs
->
ctrlclock
|=
LCLK_EN
;
}
/* acquire h/w resources DMA */
static
int
omap16xx_cam_link_open
(
struct
omap16xxcam
*
data
)
{
int
ret
;
/* Acquire first dma channel */
if
((
ret
=
omap_request_dma
(
OMAP_DMA_CAMERA_IF_RX
,
"camera dma 1"
,
omap16xx_cam_dma_link_callback
,
(
void
*
)
data
,
&
data
->
dma_channel_number1
)))
{
return
ret
;
}
/* Acquire second dma channel */
if
((
ret
=
omap_request_dma
(
OMAP_DMA_CAMERA_IF_RX
,
"camera dma 2"
,
omap16xx_cam_dma_link_callback
,
(
void
*
)
data
,
&
data
->
dma_channel_number2
)))
{
printk
(
"No DMA available for camera
\n
"
);
return
ret
;
}
data
->
next_dmach
=
data
->
dma_channel_number1
;
omap_writew
(
data
->
dma_channel_number2
,
OMAP_DMA_CLNK_CTRL
(
data
->
dma_channel_number1
));
omap_writew
(
data
->
dma_channel_number1
,
OMAP_DMA_CLNK_CTRL
(
data
->
dma_channel_number2
));
return
0
;
}
/* free h/w resources, stop i/f */
static
int
omap16xx_cam_link_close
(
struct
omap16xxcam
*
data
)
{
/* free dma channels */
omap_stop_dma
(
data
->
dma_channel_number1
);
omap_stop_dma
(
data
->
dma_channel_number2
);
omap_free_dma
(
data
->
dma_channel_number1
);
omap_free_dma
(
data
->
dma_channel_number2
);
return
0
;
}
/* dma callback routine. */
static
void
omap16xx_cam_dma_link_callback
(
int
lch
,
unsigned
short
ch_status
,
void
*
data
)
{
int
count
;
void
*
arg1
,
*
arg2
;
struct
sgdma_state
*
sgdma
=
sgdma
;
struct
omap16xxcam
*
cam
=
(
struct
omap16xxcam
*
)
data
;
dma_callback_t
callback
;
spin_lock
(
&
cam
->
dma_lock
);
if
(
cam
->
free_dmach
==
2
)
{
printk
(
"callback all CHANNELS WERE IDLE
\n
"
);
spin_unlock
(
&
cam
->
dma_lock
);
return
;
}
if
(
cam
->
free_dmach
==
0
)
{
lch
=
cam
->
next_dmach
;
}
else
{
lch
=
cam
->
next_dmach
==
cam
->
dma_channel_number1
?
cam
->
dma_channel_number2
:
cam
->
dma_channel_number1
;
}
while
(
cam
->
free_dmach
<
2
)
{
if
((
omap_readw
(
OMAP_DMA_CCR
(
lch
))
&
(
1
<<
7
)
))
break
;
count
=
(
lch
==
cam
->
dma_channel_number2
)
?
1
:
0
;
callback
=
cam
->
camdma
[
count
].
callback
;
arg1
=
cam
->
camdma
[
count
].
arg1
;
arg2
=
cam
->
camdma
[
count
].
arg2
;
cam
->
free_dmach
++
;
spin_unlock
(
&
cam
->
dma_lock
);
callback
(
arg1
,
arg2
);
spin_lock
(
&
cam
->
dma_lock
);
lch
=
(
lch
==
cam
->
dma_channel_number2
)
?
cam
->
dma_channel_number1
:
cam
->
dma_channel_number2
;
}
spin_unlock
(
&
cam
->
dma_lock
);
}
static
irqreturn_t
omap16xx_cam_isr
(
int
irq
,
void
*
client_data
,
struct
pt_regs
*
regs
)
{
struct
omap16xxcam
*
data
=
(
struct
omap16xxcam
*
)
client_data
;
unsigned
int
itstat
=
data
->
camera_regs
->
it_status
;
/* VSYNC UP interrupt, start filling FIFO and enabling DMA */
if
(
itstat
&
V_UP
)
{
data
->
camera_regs
->
mode
&=
~
EN_V_UP
;
omap16xx_cam_clear_fifo
(
data
);
omap16xx_cam_configure_dma
(
data
);
omap_start_dma
(
data
->
next_dmach
);
wake_up_interruptible
(
&
data
->
vsync_wait
);
}
if
(
itstat
&
V_DOWN
)
{
data
->
camera_regs
->
mode
&=
~
EN_V_DOWN
;
wake_up_interruptible
(
&
data
->
vsync_wait
);
}
if
(
itstat
&
H_UP
)
printk
(
"H_UP
\n
"
);
if
(
itstat
&
H_DOWN
)
printk
(
"H_DOWN
\n
"
);
if
(
itstat
&
FIFO_FULL
)
{
omap16xx_cam_clear_fifo
(
data
);
printk
(
"FIFO_FULL
\n
"
);
}
if
(
itstat
&
DATA_XFER
)
printk
(
"DATA_TRANS
\n
"
);
return
IRQ_HANDLED
;
}
/* ------------- below are interface functions ----------------- */
/* ------------- these functions are named omap16xxcam_<name> -- */
static
int
omap16xxcam_init_dma
(
void
*
priv
)
{
int
ch
;
struct
omap16xxcam
*
data
=
(
struct
omap16xxcam
*
)
priv
;
data
->
free_dmach
=
2
;
for
(
ch
=
0
;
ch
<
2
;
++
ch
)
{
data
->
camdma
[
ch
].
callback
=
NULL
;
data
->
camdma
[
ch
].
arg1
=
NULL
;
data
->
camdma
[
ch
].
arg2
=
NULL
;
}
return
0
;
}
/* start the dma of chains */
static
int
omap16xxcam_start_dma
(
struct
sgdma_state
*
sgdma
,
dma_callback_t
callback
,
void
*
arg1
,
void
*
arg2
,
void
*
priv
)
{
struct
omap16xxcam
*
data
=
(
struct
omap16xxcam
*
)
priv
;
struct
scatterlist
*
sglist
;
unsigned
long
irqflags
;
int
dmach
;
int
prev_dmach
;
int
count
;
spin_lock_irqsave
(
&
data
->
dma_lock
,
irqflags
);
sglist
=
(
struct
scatterlist
*
)(
sgdma
->
sglist
+
sgdma
->
next_sglist
);
if
(
!
data
->
free_dmach
)
{
spin_unlock_irqrestore
(
&
data
->
dma_lock
,
irqflags
);
return
-
EBUSY
;
}
dmach
=
data
->
next_dmach
;
count
=
(
dmach
==
data
->
dma_channel_number2
)
?
1
:
0
;
data
->
camdma
[
count
].
callback
=
callback
;
data
->
camdma
[
count
].
arg1
=
arg1
;
data
->
camdma
[
count
].
arg2
=
arg2
;
if
(
machine_is_omap_h3
())
omap_set_dma_src_params
(
dmach
,
OMAP_DMA_PORT_OCP_T1
,
OMAP_DMA_AMODE_CONSTANT
,
CAM_CAMDATA_REG
);
else
omap_set_dma_src_params
(
dmach
,
OMAP_DMA_PORT_TIPB
,
OMAP_DMA_AMODE_CONSTANT
,
CAM_CAMDATA_REG
);
omap_set_dma_dest_params
(
dmach
,
OMAP_DMA_PORT_EMIFF
,
OMAP_DMA_AMODE_POST_INC
,
sg_dma_address
(
sglist
));
omap_set_dma_transfer_params
(
dmach
,
OMAP_DMA_DATA_TYPE_S32
,
FIFO_TRIGGER_LVL
,
sg_dma_len
(
sglist
)
/
(
4
*
FIFO_TRIGGER_LVL
),
OMAP_DMA_SYNC_FRAME
);
omap_writew
(
omap_readw
(
OMAP_DMA_CLNK_CTRL
(
dmach
))
&
~
(
1
<<
15
),
OMAP_DMA_CLNK_CTRL
(
dmach
));
prev_dmach
=
(
dmach
==
data
->
dma_channel_number2
)
?
data
->
dma_channel_number1
:
data
->
dma_channel_number2
;
if
(
data
->
new
)
{
data
->
new
=
0
;
omap16xx_cam_waitfor_syncedge
(
data
,
EN_V_UP
);
}
else
{
if
(
omap_readw
(
OMAP_DMA_CCR
(
prev_dmach
))
&
(
1
<<
7
))
{
omap_writew
((
omap_readw
(
OMAP_DMA_CLNK_CTRL
(
prev_dmach
))
|
(
1
<<
15
)),
OMAP_DMA_CLNK_CTRL
(
prev_dmach
));
}
else
{
/* no transfer is in progress */
omap_start_dma
(
dmach
);
}
}
data
->
next_dmach
=
prev_dmach
;
data
->
free_dmach
--
;
spin_unlock_irqrestore
(
&
data
->
dma_lock
,
irqflags
);
return
0
;
}
int
static
omap16xxcam_finish_dma
(
void
*
priv
)
{
struct
omap16xxcam
*
data
=
(
struct
omap16xxcam
*
)
priv
;
while
(
data
->
free_dmach
<
2
)
mdelay
(
1
);
return
0
;
}
/* Enables the camera. Takes camera out of reset. Enables the clocks. */
static
int
omap16xxcam_enable
(
void
*
priv
)
{
struct
omap16xxcam
*
data
=
(
struct
omap16xxcam
*
)
priv
;
omap16xx_cam_reset
(
data
,
1
);
/* give clock to camera_module */
data
->
camera_regs
->
mode
=
(
FIFO_TRIGGER_LVL
<<
THRESHOLD_BIT
);
data
->
camera_regs
->
ctrlclock
=
MCLK_EN
|
CAMEXCLK_EN
;
omap16xx_cam_clear_fifo
(
data
);
/* wait for camera to settle down */
mdelay
(
5
);
return
0
;
}
/* Disables all the camera clocks. Put the camera interface in reset. */
static
int
omap16xxcam_disable
(
void
*
priv
)
{
struct
omap16xxcam
*
data
=
(
struct
omap16xxcam
*
)
priv
;
omap16xx_cam_clear_fifo
(
data
);
data
->
camera_regs
->
ctrlclock
=
0x00000000
;
data
->
camera_regs
->
mode
=
0x00000000
;
omap16xx_cam_reset
(
data
,
0
);
return
0
;
}
/* Abort the data transfer */
static
int
omap16xxcam_abort
(
void
*
priv
)
{
return
omap16xxcam_disable
(
priv
);
}
static
int
omap16xxcam_set_xclk
(
int
xclk
,
void
*
priv
)
{
struct
omap16xxcam
*
data
=
(
struct
omap16xxcam
*
)
priv
;
int
xclk_val
;
int
divisor
=
1
;
divisor
=
data
->
ocp_clk
/
xclk
;
if
(
divisor
*
xclk
<
data
->
ocp_clk
)
++
divisor
;
switch
(
divisor
)
{
case
1
:
case
2
:
xclk_val
=
FOSCMOD_TC2_CK2
;
break
;
case
3
:
xclk_val
=
FOSCMOD_TC2_CK3
;
break
;
case
4
:
case
5
:
case
6
:
case
7
:
xclk_val
=
FOSCMOD_TC2_CK4
;
break
;
case
8
:
case
9
:
xclk_val
=
FOSCMOD_TC2_CK8
;
break
;
case
10
:
case
11
:
xclk_val
=
FOSCMOD_TC2_CK10
;
break
;
case
12
:
case
13
:
case
14
:
case
15
:
xclk_val
=
FOSCMOD_TC2_CK12
;
break
;
case
16
:
xclk_val
=
FOSCMOD_TC2_CK16
;
break
;
default:
xclk_val
=
FOSCMOD_TC2_CK16
;
}
/* follow the protocol to change the XCLK clock */
data
->
camera_regs
->
ctrlclock
&=
~
CAMEXCLK_EN
;
data
->
camera_regs
->
ctrlclock
|=
xclk_val
;
data
->
camera_regs
->
ctrlclock
|=
CAMEXCLK_EN
;
return
(
data
->
ocp_clk
/
divisor
);
}
static
int
omap16xxcam_open
(
void
*
priv
)
{
struct
omap16xxcam
*
data
=
(
struct
omap16xxcam
*
)
priv
;
int
ret
;
if
((
ret
=
request_irq
(
INT_CAMERA
,
omap16xx_cam_isr
,
SA_INTERRUPT
,
"camera"
,
data
)))
{
printk
(
"FAILED to aquire irq
\n
"
);
return
ret
;
}
data
->
new
=
1
;
omap16xxcam_enable
(
data
);
omap16xxcam_init_dma
(
data
);
return
omap16xx_cam_link_open
(
data
);
}
static
int
omap16xxcam_close
(
void
*
priv
)
{
struct
omap16xxcam
*
data
=
(
struct
omap16xxcam
*
)
priv
;
omap16xxcam_disable
(
priv
);
free_irq
(
INT_CAMERA
,
data
);
return
omap16xx_cam_link_close
(
data
);
}
static
int
omap16xxcam_cleanup
(
void
*
priv
)
{
struct
omap16xxcam
*
data
=
(
struct
omap16xxcam
*
)
priv
;
omap16xxcam_disable
(
data
);
if
(
machine_is_omap_h3
())
{
if
(
data
->
camera_regs
)
{
iounmap
((
void
*
)
data
->
camera_regs
);
data
->
camera_regs
=
NULL
;
}
}
if
(
data
->
iobase_phys
)
{
release_mem_region
(
data
->
iobase_phys
,
CAMERA_IOSIZE
);
data
->
iobase_phys
=
0
;
}
return
0
;
}
/* Initialise the OMAP camera interface */
static
void
*
omap16xxcam_init
(
void
)
{
unsigned
long
cam_iobase
;
if
(
!
request_region
(
CAMERA_BASE
,
CAMERA_IOSIZE
,
"OAMP16xx Camera"
))
{
printk
(
"OMAP16XX Parallel Camera Interface is already in use
\n
"
);
return
NULL
;
}
if
(
machine_is_omap_h3
())
{
cam_iobase
=
(
unsigned
long
)
ioremap
(
CAMERA_BASE
,
CAMERA_IOSIZE
);
if
(
!
cam_iobase
)
{
printk
(
"CANNOT MAP CAMERA REGISTER
\n
"
);
return
NULL
;
}
}
else
cam_iobase
=
io_p2v
(
CAMERA_BASE
);
/* Set the base address of the camera registers */
hardware_data
.
camera_regs
=
(
camera_regs_t
*
)
cam_iobase
;
hardware_data
.
iobase_phys
=
(
unsigned
long
)
CAMERA_BASE
;
/* get the input clock value to camera interface and store it */
if
(
machine_is_omap_h3
())
hardware_data
.
ocp_clk
=
clk_get_rate
(
clk_get
(
0
,
"tc_ck"
));
else
hardware_data
.
ocp_clk
=
clk_get_rate
(
clk_get
(
0
,
"mpuper_ck"
));
/* Init the camera IF */
omap16xx_cam_init
();
/* enable it. This is needed for sensor detection */
omap16xxcam_enable
((
void
*
)
&
hardware_data
);
/* Init dma data */
spin_lock_init
(
&
hardware_data
.
dma_lock
);
init_waitqueue_head
(
&
hardware_data
.
vsync_wait
);
return
(
void
*
)
&
hardware_data
;
}
struct
camera_hardware
camera_hardware_if
=
{
version
:
0x01
,
name
:
"OMAP16xx Camera Parallel"
,
init
:
omap16xxcam_init
,
cleanup
:
omap16xxcam_cleanup
,
open
:
omap16xxcam_open
,
close
:
omap16xxcam_close
,
enable
:
omap16xxcam_enable
,
disable
:
omap16xxcam_disable
,
abort
:
omap16xxcam_abort
,
set_xclk
:
omap16xxcam_set_xclk
,
init_dma
:
omap16xxcam_init_dma
,
start_dma
:
omap16xxcam_start_dma
,
finish_dma
:
omap16xxcam_finish_dma
,
};
drivers/media/video/omap/omap16xxcam.h
0 → 100644
View file @
8403b938
/*
* drivers/media/video/omap/omap16xxcam.h
*
* Copyright (C) 2004 Texas Instruments, Inc.
*
* This package is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef OMAP_16XX_CAM_H
#define OMAP_16XX_CAM_H
#define DMA_ELEM_SIZE 4
#define FIFO_TRIGGER_LVL (32)
/*
* ---------------------------------------------------------------------------
* OMAP1610 Camera Interface
* ---------------------------------------------------------------------------
*/
#ifdef CONFIG_MACH_OMAP_H3
#define CAMERA_BASE (0x2007d800)
#else
#define CAMERA_BASE (IO_PHYS + 0x6800)
#endif
#define CAM_CTRLCLOCK_REG (CAMERA_BASE + 0x00)
#define CAM_IT_STATUS_REG (CAMERA_BASE + 0x04)
#define CAM_MODE_REG (CAMERA_BASE + 0x08)
#define CAM_STATUS_REG (CAMERA_BASE + 0x0C)
#define CAM_CAMDATA_REG (CAMERA_BASE + 0x10)
#define CAM_GPIO_REG (CAMERA_BASE + 0x14)
#define CAM_PEAK_CTR_REG (CAMERA_BASE + 0x18)
#define CAMERA_IOSIZE 0x1C
/* CTRLCLOCK bit shifts */
#define FOSCMOD_BIT 0
#define FOSCMOD_MASK (0x7 << FOSCMOD_BIT)
#define FOSCMOD_12MHz 0x0
#define FOSCMOD_6MHz 0x2
#define FOSCMOD_9_6MHz 0x4
#define FOSCMOD_24MHz 0x5
#define FOSCMOD_8MHz 0x6
#define FOSCMOD_TC2_CK2 0x3
#define FOSCMOD_TC2_CK3 0x1
#define FOSCMOD_TC2_CK4 0x5
#define FOSCMOD_TC2_CK8 0x0
#define FOSCMOD_TC2_CK10 0x4
#define FOSCMOD_TC2_CK12 0x6
#define FOSCMOD_TC2_CK16 0x2
#define POLCLK (1<<3)
#define CAMEXCLK_EN (1<<4)
#define MCLK_EN (1<<5)
#define DPLL_EN (1<<6)
#define LCLK_EN (1<<7)
/* IT_STATUS bit shifts */
#define V_UP (1<<0)
#define V_DOWN (1<<1)
#define H_UP (1<<2)
#define H_DOWN (1<<3)
#define FIFO_FULL (1<<4)
#define DATA_XFER (1<<5)
/* MODE bit shifts */
#define CAMOSC (1<<0)
#define IMGSIZE_BIT 1
#define IMGSIZE_MASK (0x3 << IMGSIZE_BIT)
#define IMGSIZE_CIF (0x0 << IMGSIZE_BIT)
/* 352x288 */
#define IMGSIZE_QCIF (0x1 << IMGSIZE_BIT)
/* 176x144 */
#define IMGSIZE_VGA (0x2 << IMGSIZE_BIT)
/* 640x480 */
#define IMGSIZE_QVGA (0x3 << IMGSIZE_BIT)
/* 320x240 */
#define ORDERCAMD (1<<3)
#define EN_V_UP (1<<4)
#define EN_V_DOWN (1<<5)
#define EN_H_UP (1<<6)
#define EN_H_DOWN (1<<7)
#define EN_DMA (1<<8)
#define THRESHOLD (1<<9)
#define THRESHOLD_BIT 9
#define THRESHOLD_MASK (0x7f<<9)
#define EN_NIRQ (1<<16)
#define EN_FIFO_FULL (1<<17)
#define RAZ_FIFO (1<<18)
/* STATUS bit shifts */
#define VSTATUS (1<<0)
#define HSTATUS (1<<1)
/* GPIO bit shifts */
#define CAM_RST (1<<0)
#define XCLK_6MHZ 6000000
#define XCLK_8MHZ 8000000
#define XCLK_9_6MHZ 9000000
#define XCLK_12MHZ 12000000
#define XCLK_24MHZ 24000000
#endif
/* OMAP_16XX_CAM_H */
drivers/media/video/omap/ov9640.h
0 → 100644
View file @
8403b938
/*
* drivers/media/video/omap/ov9640.h
*
* Register definitions for the OmniVision OV9640 CameraChip.
*
* 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 OV9640_H
#define OV9640_H
/* The OV9640 I2C sensor chip has a fixed slave address of 0x30. */
#ifdef CONFIG_OMAP24XX_VIRTIO
#define OV9640_I2C_ADDR 0x60
#else
#define OV9640_I2C_ADDR 0x30
#endif
/* define register offsets for the OV9640 sensor chip */
#define OV9640_GAIN 0x00
#define OV9640_BLUE 0x01
#define OV9640_RED 0x02
#define OV9640_VREF 0x03
#define OV9640_COM1 0x04
#define OV9640_BAVE 0x05
#define OV9640_GEAVE 0x06
#define OV9640_RAVE 0x08
#define OV9640_COM2 0x09
#define OV9640_PID 0x0A
#define OV9640_VER 0x0B
#define OV9640_COM3 0x0C
#define OV9640_COM4 0x0D
#define OV9640_COM5 0x0E
#define OV9640_COM6 0x0F
#define OV9640_AECH 0x10
#define OV9640_CLKRC 0x11
#define OV9640_COM7 0x12
#define OV9640_COM8 0x13
#define OV9640_COM9 0x14
#define OV9640_COM10 0x15
#define OV9640_HSTRT 0x17
#define OV9640_HSTOP 0x18
#define OV9640_VSTRT 0x19
#define OV9640_VSTOP 0x1A
#define OV9640_PSHFT 0x1B
#define OV9640_MIDH 0x1C
#define OV9640_MIDL 0x1D
#define OV9640_MVFP 0x1E
#define OV9640_LAEC 0x1F
#define OV9640_BOS 0x20
#define OV9640_GBOS 0x21
#define OV9640_GROS 0x22
#define OV9640_ROS 0x23
#define OV9640_AEW 0x24
#define OV9640_AEB 0x25
#define OV9640_VPT 0x26
#define OV9640_BBIAS 0x27
#define OV9640_GBBIAS 0x28
#define OV9640_EXHCH 0x2A
#define OV9640_EXHCL 0x2B
#define OV9640_RBIAS 0x2C
#define OV9640_ADVFL 0x2D
#define OV9640_ADVFH 0x2E
#define OV9640_YAVE 0x2F
#define OV9640_HSYST 0x30
#define OV9640_HSYEN 0x31
#define OV9640_HREF 0x32
#define OV9640_CHLF 0x33
#define OV9640_ARBLM 0x34
#define OV9640_ADC 0x37
#define OV9640_ACOM 0x38
#define OV9640_OFON 0x39
#define OV9640_TSLB 0x3A
#define OV9640_COM11 0x3B
#define OV9640_COM12 0x3C
#define OV9640_COM13 0x3D
#define OV9640_COM14 0x3E
#define OV9640_EDGE 0x3F
#define OV9640_COM15 0x40
#define OV9640_COM16 0x41
#define OV9640_COM17 0x42
#define OV9640_MTX1 0x4F
#define OV9640_MTX2 0x50
#define OV9640_MTX3 0x51
#define OV9640_MTX4 0x52
#define OV9640_MTX5 0x53
#define OV9640_MTX6 0x54
#define OV9640_MTX7 0x55
#define OV9640_MTX8 0x56
#define OV9640_MTX9 0x57
#define OV9640_MTXS 0x58
#define OV9640_LCC1 0x62
#define OV9640_LCC2 0x63
#define OV9640_LCC3 0x64
#define OV9640_LCC4 0x65
#define OV9640_LCC5 0x66
#define OV9640_MANU 0x67
#define OV9640_MANV 0x68
#define OV9640_HV 0x69
#define OV9640_MBD 0x6A
#define OV9640_DBLV 0x6B
#define OV9640_GSP1 0x6C
#define OV9640_GSP2 0x6D
#define OV9640_GSP3 0x6E
#define OV9640_GSP4 0x6F
#define OV9640_GSP5 0x70
#define OV9640_GSP6 0x71
#define OV9640_GSP7 0x72
#define OV9640_GSP8 0x73
#define OV9640_GSP9 0x74
#define OV9640_GSP10 0x75
#define OV9640_GSP11 0x76
#define OV9640_GSP12 0x77
#define OV9640_GSP13 0x78
#define OV9640_GSP14 0x79
#define OV9640_GSP15 0x7A
#define OV9640_GSP16 0x7B
#define OV9640_GST1 0x7C
#define OV9640_GST2 0x7D
#define OV9640_GST3 0x7E
#define OV9640_GST4 0x7F
#define OV9640_GST5 0x80
#define OV9640_GST6 0x81
#define OV9640_GST7 0x82
#define OV9640_GST8 0x83
#define OV9640_GST9 0x84
#define OV9640_GST10 0x85
#define OV9640_GST11 0x86
#define OV9640_GST12 0x87
#define OV9640_GST13 0x88
#define OV9640_GST14 0x89
#define OV9640_GST15 0x8A
#define OV9640_NUM_REGS (OV9640_GST15 + 1)
#define OV9640_PID_MAGIC 0x96
/* high byte of product ID number */
#define OV9640_VER_REV2 0x48
/* low byte of product ID number */
#define OV9640_VER_REV3 0x49
/* low byte of product ID number */
#define OV9640_MIDH_MAGIC 0x7F
/* high byte of mfg ID */
#define OV9640_MIDL_MAGIC 0xA2
/* low byte of mfg ID */
/* define a structure for ov9640 register initialization values */
struct
ov9640_reg
{
unsigned
char
reg
;
unsigned
char
val
;
};
enum
image_size
{
QQCIF
,
QQVGA
,
QCIF
,
QVGA
,
CIF
,
VGA
,
SXGA
};
enum
pixel_format
{
YUV
,
RGB565
,
RGB555
};
#define NUM_IMAGE_SIZES 7
#define NUM_PIXEL_FORMATS 3
struct
capture_size
{
unsigned
long
width
;
unsigned
long
height
;
};
/* Array of image sizes supported by OV9640. These must be ordered from
* smallest image size to largest.
*/
const
static
struct
capture_size
ov9640_sizes
[]
=
{
{
88
,
72
},
/* QQCIF */
{
160
,
120
},
/* QQVGA */
{
176
,
144
},
/* QCIF */
{
320
,
240
},
/* QVGA */
{
352
,
288
},
/* CIF */
{
640
,
480
},
/* VGA */
{
1280
,
960
},
/* SXGA */
};
#endif
/* ifndef OV9640_H */
drivers/media/video/omap/sensor_if.h
0 → 100644
View file @
8403b938
/*
* drivers/media/video/omap/sensor_if.h
*
* Copyright (C) 2004 Texas Instruments, Inc.
*
* Sensor interface to OMAP camera capture drivers
* Sensor driver should implement this interface
*
* This package is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef OMAP_SENSOR_IF_H
#define OMAP_SENSOR_IF_H
#define LEN_SENSOR_NAME 31
struct
camera_sensor
{
unsigned
int
version
;
char
name
[
LEN_SENSOR_NAME
+
1
];
void
*
(
*
init
)(
struct
v4l2_pix_format
*
);
int
(
*
cleanup
)(
void
*
);
int
(
*
power_on
)(
void
*
);
int
(
*
power_off
)(
void
*
);
int
(
*
enum_pixformat
)(
struct
v4l2_fmtdesc
*
,
void
*
);
int
(
*
try_format
)
(
struct
v4l2_pix_format
*
,
void
*
);
unsigned
long
(
*
calc_xclk
)
(
struct
v4l2_pix_format
*
,
struct
v4l2_fract
*
,
void
*
);
int
(
*
configure
)
(
struct
v4l2_pix_format
*
,
unsigned
long
,
struct
v4l2_fract
*
,
void
*
);
int
(
*
query_control
)
(
struct
v4l2_queryctrl
*
,
void
*
);
int
(
*
get_control
)
(
struct
v4l2_control
*
,
void
*
);
int
(
*
set_control
)
(
struct
v4l2_control
*
,
void
*
);
};
#endif
drivers/media/video/omap/sensor_ov9640.c
0 → 100644
View file @
8403b938
/*
* drivers/media/video/omap/sensor_ov9640.c
*
* Ov9640 Sensor driver for OMAP camera sensor interface
*
* 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.
*/
#include <linux/errno.h>
#include <linux/i2c.h>
#include <linux/videodev.h>
#include <media/video-buf.h>
#include <linux/delay.h>
#include <asm/mach-types.h>
#include <asm/arch/gpioexpander.h>
#include "sensor_if.h"
#include "ov9640.h"
#define CAMERA_OV9640
#ifdef CAMERA_OV9640
struct
ov9640_sensor
{
/* I2C parameters */
struct
i2c_client
client
;
struct
i2c_driver
driver
;
int
ver
;
/* OV9640 version */
};
static
struct
ov9640_sensor
ov9640
;
/* list of image formats supported by OV9640 sensor */
const
static
struct
v4l2_fmtdesc
ov9640_formats
[]
=
{
{
/* Note: V4L2 defines RGB565 as:
*
* Byte 0 Byte 1
* g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3
*
* We interpret RGB565 as:
*
* Byte 0 Byte 1
* g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3
*/
.
description
=
"RGB565, le"
,
.
pixelformat
=
V4L2_PIX_FMT_RGB565
,
},{
/* Note: V4L2 defines RGB565X as:
*
* Byte 0 Byte 1
* b4 b3 b2 b1 b0 g5 g4 g3 g2 g1 g0 r4 r3 r2 r1 r0
*
* We interpret RGB565X as:
*
* Byte 0 Byte 1
* r4 r3 r2 r1 r0 g5 g4 g3 g2 g1 g0 b4 b3 b2 b1 b0
*/
.
description
=
"RGB565, be"
,
.
pixelformat
=
V4L2_PIX_FMT_RGB565X
,
},
{
.
description
=
"YUYV (YUV 4:2:2), packed"
,
.
pixelformat
=
V4L2_PIX_FMT_YUYV
,
},{
.
description
=
"UYVY, packed"
,
.
pixelformat
=
V4L2_PIX_FMT_UYVY
,
},
{
/* Note: V4L2 defines RGB555 as:
*
* Byte 0 Byte 1
* g2 g1 g0 r4 r3 r2 r1 r0 x b4 b3 b2 b1 b0 g4 g3
*
* We interpret RGB555 as:
*
* Byte 0 Byte 1
* g2 g1 g0 b4 b3 b2 b1 b0 x r4 r3 r2 r1 r0 g4 g3
*/
.
description
=
"RGB555, le"
,
.
pixelformat
=
V4L2_PIX_FMT_RGB555
,
},{
/* Note: V4L2 defines RGB555X as:
*
* Byte 0 Byte 1
* x b4 b3 b2 b1 b0 g4 g3 g2 g1 g0 r4 r3 r2 r1 r0
*
* We interpret RGB555X as:
*
* Byte 0 Byte 1
* x r4 r3 r2 r1 r0 g4 g3 g2 g1 g0 b4 b3 b2 b1 b0
*/
.
description
=
"RGB555, be"
,
.
pixelformat
=
V4L2_PIX_FMT_RGB555X
,
}
};
#define NUM_CAPTURE_FORMATS (sizeof(ov9640_formats)/sizeof(ov9640_formats[0]))
#define NUM_OVERLAY_FORMATS 2
/* register initialization tables for OV9640 */
#define OV9640_REG_TERM 0xFF
/* terminating list entry for reg */
#define OV9640_VAL_TERM 0xFF
/* terminating list entry for val */
/* common OV9640 register initialization for all image sizes, pixel formats,
* and frame rates
*/
const
static
struct
ov9640_reg
ov9640_common
[]
=
{
{
0x12
,
0x80
},
{
0x11
,
0x80
},
{
0x13
,
0x88
},
/* COM7, CLKRC, COM8 */
{
0x01
,
0x58
},
{
0x02
,
0x24
},
{
0x04
,
0x00
},
/* BLUE, RED, COM1 */
{
0x0E
,
0x81
},
{
0x0F
,
0x4F
},
{
0x14
,
0xcA
},
/* COM5, COM6, COM9 */
{
0x16
,
0x02
},
{
0x1B
,
0x01
},
{
0x24
,
0x70
},
/* ?, PSHFT, AEW */
{
0x25
,
0x68
},
{
0x26
,
0xD3
},
{
0x27
,
0x90
},
/* AEB, VPT, BBIAS */
{
0x2A
,
0x00
},
{
0x2B
,
0x00
},
{
0x32
,
0x24
},
/* EXHCH, EXHCL, HREF */
{
0x33
,
0x02
},
{
0x37
,
0x02
},
{
0x38
,
0x13
},
/* CHLF, ADC, ACOM */
{
0x39
,
0xF0
},
{
0x3A
,
0x00
},
{
0x3B
,
0x01
},
/* OFON, TSLB, COM11 */
{
0x3D
,
0x90
},
{
0x3E
,
0x02
},
{
0x3F
,
0xF2
},
/* COM13, COM14, EDGE */
{
0x41
,
0x02
},
{
0x42
,
0xC8
},
/* COM16, COM17 */
{
0x43
,
0xF0
},
{
0x44
,
0x10
},
{
0x45
,
0x6C
},
/* ?, ?, ? */
{
0x46
,
0x6C
},
{
0x47
,
0x44
},
{
0x48
,
0x44
},
/* ?, ?, ? */
{
0x49
,
0x03
},
{
0x59
,
0x49
},
{
0x5A
,
0x94
},
/* ?, ?, ? */
{
0x5B
,
0x46
},
{
0x5C
,
0x84
},
{
0x5D
,
0x5C
},
/* ?, ?, ? */
{
0x5E
,
0x08
},
{
0x5F
,
0x00
},
{
0x60
,
0x14
},
/* ?, ?, ? */
{
0x61
,
0xCE
},
/* ? */
{
0x62
,
0x70
},
{
0x63
,
0x00
},
{
0x64
,
0x04
},
/* LCC1, LCC2, LCC3 */
{
0x65
,
0x00
},
{
0x66
,
0x00
},
/* LCC4, LCC5 */
{
0x69
,
0x00
},
{
0x6A
,
0x3E
},
{
0x6B
,
0x3F
},
/* HV, MBD, DBLV */
{
0x6C
,
0x40
},
{
0x6D
,
0x30
},
{
0x6E
,
0x4B
},
/* GSP1, GSP2, GSP3 */
{
0x6F
,
0x60
},
{
0x70
,
0x70
},
{
0x71
,
0x70
},
/* GSP4, GSP5, GSP6 */
{
0x72
,
0x70
},
{
0x73
,
0x70
},
{
0x74
,
0x60
},
/* GSP7, GSP8, GSP9 */
{
0x75
,
0x60
},
{
0x76
,
0x50
},
{
0x77
,
0x48
},
/* GSP10,GSP11,GSP12 */
{
0x78
,
0x3A
},
{
0x79
,
0x2E
},
{
0x7A
,
0x28
},
/* GSP13,GSP14,GSP15 */
{
0x7B
,
0x22
},
{
0x7C
,
0x04
},
{
0x7D
,
0x07
},
/* GSP16,GST1, GST2 */
{
0x7E
,
0x10
},
{
0x7F
,
0x28
},
{
0x80
,
0x36
},
/* GST3, GST4, GST5 */
{
0x81
,
0x44
},
{
0x82
,
0x52
},
{
0x83
,
0x60
},
/* GST6, GST7, GST8 */
{
0x84
,
0x6C
},
{
0x85
,
0x78
},
{
0x86
,
0x8C
},
/* GST9, GST10,GST11 */
{
0x87
,
0x9E
},
{
0x88
,
0xBB
},
{
0x89
,
0xD2
},
/* GST12,GST13,GST14 */
{
0x8A
,
0xE6
},
{
0x13
,
0xaF
},
{
0x15
,
0x02
},
/* GST15, COM8 */
{
0x22
,
0x8a
},
/* GROS */
{
OV9640_REG_TERM
,
OV9640_VAL_TERM
}
};
/* OV9640 register configuration for all combinations of pixel format and
* image size
*/
/* YUV (YCbCr) QQCIF */
const
static
struct
ov9640_reg
qqcif_yuv
[]
=
{
{
0x12
,
0x08
},
{
0x3C
,
0x46
},
{
0x40
,
0xC0
},
/* COM7, COM12, COM15 */
{
0x04
,
0x24
},
{
0x0C
,
0x00
},
{
0x0D
,
0x40
},
/* COM1, COM3, COM4 */
{
0x4F
,
0x50
},
{
0x50
,
0x43
},
{
0x51
,
0x0D
},
/* MTX1, MTX2, MTX3 */
{
0x52
,
0x19
},
{
0x53
,
0x4C
},
{
0x54
,
0x65
},
/* MTX4, MTX5, MTX6 */
{
0x55
,
0x40
},
{
0x56
,
0x40
},
{
0x57
,
0x40
},
/* MTX7, MTX8, MTX9 */
{
0x58
,
0x0F
},
/* MTXS */
{
OV9640_REG_TERM
,
OV9640_VAL_TERM
}
};
/* YUV (YCbCr) QQVGA */
const
static
struct
ov9640_reg
qqvga_yuv
[]
=
{
{
0x12
,
0x10
},
{
0x3C
,
0x46
},
{
0x40
,
0xC0
},
/* COM7, COM12, COM15 */
{
0x04
,
0x24
},
{
0x0C
,
0x04
},
{
0x0D
,
0xC0
},
/* COM1, COM3, COM4 */
{
0x4F
,
0x50
},
{
0x50
,
0x43
},
{
0x51
,
0x0D
},
/* MTX1, MTX2, MTX3 */
{
0x52
,
0x19
},
{
0x53
,
0x4C
},
{
0x54
,
0x65
},
/* MTX4, MTX5, MTX6 */
{
0x55
,
0x40
},
{
0x56
,
0x40
},
{
0x57
,
0x40
},
/* MTX7, MTX8, MTX9 */
{
0x58
,
0x0F
},
/* MTXS */
{
OV9640_REG_TERM
,
OV9640_VAL_TERM
}
};
/* YUV (YCbCr) QCIF */
const
static
struct
ov9640_reg
qcif_yuv
[]
=
{
{
0x12
,
0x08
},
{
0x3C
,
0x46
},
{
0x40
,
0xC0
},
/* COM7, COM12, COM15 */
{
0x04
,
0x00
},
{
0x0C
,
0x04
},
{
0x0D
,
0xC0
},
/* COM1, COM3, COM4 */
{
0x4F
,
0x50
},
{
0x50
,
0x43
},
{
0x51
,
0x0D
},
/* MTX1, MTX2, MTX3 */
{
0x52
,
0x19
},
{
0x53
,
0x4C
},
{
0x54
,
0x65
},
/* MTX4, MTX5, MTX6 */
{
0x55
,
0x40
},
{
0x56
,
0x40
},
{
0x57
,
0x40
},
/* MTX7, MTX8, MTX9 */
{
0x58
,
0x0F
},
/* MTXS */
{
OV9640_REG_TERM
,
OV9640_VAL_TERM
}
};
/* YUV (YCbCr) QVGA */
const
static
struct
ov9640_reg
qvga_yuv
[]
=
{
{
0x12
,
0x10
},
{
0x3C
,
0x46
},
{
0x40
,
0xC0
},
/* COM7, COM12, COM15 */
{
0x04
,
0x00
},
{
0x0C
,
0x04
},
{
0x0D
,
0xC0
},
/* COM1, COM3, COM4 */
{
0x4F
,
0x50
},
{
0x50
,
0x43
},
{
0x51
,
0x0D
},
/* MTX1, MTX2, MTX3 */
{
0x52
,
0x19
},
{
0x53
,
0x4C
},
{
0x54
,
0x65
},
/* MTX4, MTX5, MTX6 */
{
0x55
,
0x40
},
{
0x56
,
0x40
},
{
0x57
,
0x40
},
/* MTX7, MTX8, MTX9 */
{
0x58
,
0x0F
},
/* MTXS */
{
OV9640_REG_TERM
,
OV9640_VAL_TERM
}
};
/* YUV (YCbCr) CIF */
const
static
struct
ov9640_reg
cif_yuv
[]
=
{
{
0x12
,
0x20
},
{
0x3C
,
0x46
},
{
0x40
,
0xC0
},
/* COM7, COM12, COM15 */
{
0x04
,
0x00
},
{
0x0C
,
0x04
},
{
0x0D
,
0xC0
},
/* COM1, COM3, COM4 */
{
0x4F
,
0x50
},
{
0x50
,
0x43
},
{
0x51
,
0x0D
},
/* MTX1, MTX2, MTX3 */
{
0x52
,
0x19
},
{
0x53
,
0x4C
},
{
0x54
,
0x65
},
/* MTX4, MTX5, MTX6 */
{
0x55
,
0x40
},
{
0x56
,
0x40
},
{
0x57
,
0x40
},
/* MTX7, MTX8, MTX9 */
{
0x58
,
0x0F
},
/* MTXS */
{
OV9640_REG_TERM
,
OV9640_VAL_TERM
}
};
/* YUV (YCbCr) VGA */
const
static
struct
ov9640_reg
vga_yuv
[]
=
{
{
0x12
,
0x40
},
{
0x3C
,
0x46
},
{
0x40
,
0xC0
},
/* COM7, COM12, COM15 */
{
0x04
,
0x00
},
{
0x0C
,
0x04
},
{
0x0D
,
0xC0
},
/* COM1, COM3, COM4 */
{
0x4F
,
0x50
},
{
0x50
,
0x43
},
{
0x51
,
0x0D
},
/* MTX1, MTX2, MTX3 */
{
0x52
,
0x19
},
{
0x53
,
0x4C
},
{
0x54
,
0x65
},
/* MTX4, MTX5, MTX6 */
{
0x55
,
0x40
},
{
0x56
,
0x40
},
{
0x57
,
0x40
},
/* MTX7, MTX8, MTX9 */
{
0x58
,
0x0F
},
/* MTXS */
{
OV9640_REG_TERM
,
OV9640_VAL_TERM
}
};
/* YUV (YCbCr) SXGA */
const
static
struct
ov9640_reg
sxga_yuv
[]
=
{
{
0x12
,
0x00
},
{
0x3C
,
0x46
},
{
0x40
,
0xC0
},
/* COM7, COM12, COM15 */
{
0x04
,
0x00
},
{
0x0C
,
0x00
},
{
0x0D
,
0x40
},
/* COM1, COM3, COM4 */
{
0x4F
,
0x50
},
{
0x50
,
0x43
},
{
0x51
,
0x0D
},
/* MTX1, MTX2, MTX3 */
{
0x52
,
0x19
},
{
0x53
,
0x4C
},
{
0x54
,
0x65
},
/* MTX4, MTX5, MTX6 */
{
0x55
,
0x40
},
{
0x56
,
0x40
},
{
0x57
,
0x40
},
/* MTX7, MTX8, MTX9 */
{
0x58
,
0x0F
},
/* MTXS */
{
OV9640_REG_TERM
,
OV9640_VAL_TERM
}
};
/* RGB565 QQCIF */
const
static
struct
ov9640_reg
qqcif_565
[]
=
{
{
0x12
,
0x0C
},
{
0x3C
,
0x40
},
{
0x40
,
0x10
},
/* COM7, COM12, COM15 */
{
0x04
,
0x24
},
{
0x0C
,
0x00
},
{
0x0D
,
0x40
},
/* COM1, COM3, COM4 */
{
0x4F
,
0x71
},
{
0x50
,
0x3E
},
{
0x51
,
0x0C
},
/* MTX1, MTX2, MTX3 */
{
0x52
,
0x33
},
{
0x53
,
0x72
},
{
0x54
,
0x00
},
/* MTX4, MTX5, MTX6 */
{
0x55
,
0x2B
},
{
0x56
,
0x66
},
{
0x57
,
0xD2
},
/* MTX7, MTX8, MTX9 */
{
0x58
,
0x65
},
/* MTXS */
{
OV9640_REG_TERM
,
OV9640_VAL_TERM
}
};
/* RGB565 QQVGA */
const
static
struct
ov9640_reg
qqvga_565
[]
=
{
{
0x12
,
0x14
},
{
0x3C
,
0x40
},
{
0x40
,
0x10
},
/* COM7, COM12, COM15 */
{
0x04
,
0x24
},
{
0x0C
,
0x04
},
{
0x0D
,
0xC0
},
/* COM1, COM3, COM4 */
{
0x4F
,
0x71
},
{
0x50
,
0x3E
},
{
0x51
,
0x0C
},
/* MTX1, MTX2, MTX3 */
{
0x52
,
0x33
},
{
0x53
,
0x72
},
{
0x54
,
0x00
},
/* MTX4, MTX5, MTX6 */
{
0x55
,
0x2B
},
{
0x56
,
0x66
},
{
0x57
,
0xD2
},
/* MTX7, MTX8, MTX9 */
{
0x58
,
0x65
},
/* MTXS */
{
OV9640_REG_TERM
,
OV9640_VAL_TERM
}
};
/* RGB565 QCIF */
const
static
struct
ov9640_reg
qcif_565
[]
=
{
{
0x12
,
0x0C
},
{
0x3C
,
0x40
},
{
0x40
,
0x10
},
/* COM7, COM12, COM15 */
{
0x04
,
0x00
},
{
0x0C
,
0x04
},
{
0x0D
,
0xC0
},
/* COM1, COM3, COM4 */
{
0x4F
,
0x71
},
{
0x50
,
0x3E
},
{
0x51
,
0x0C
},
/* MTX1, MTX2, MTX3 */
{
0x52
,
0x33
},
{
0x53
,
0x72
},
{
0x54
,
0x00
},
/* MTX4, MTX5, MTX6 */
{
0x55
,
0x2B
},
{
0x56
,
0x66
},
{
0x57
,
0xD2
},
/* MTX7, MTX8, MTX9 */
{
0x58
,
0x65
},
/* MTXS */
{
OV9640_REG_TERM
,
OV9640_VAL_TERM
}
};
/* RGB565 QVGA */
const
static
struct
ov9640_reg
qvga_565
[]
=
{
{
0x12
,
0x14
},
{
0x3C
,
0x40
},
{
0x40
,
0x10
},
/* COM7, COM12, COM15 */
{
0x04
,
0x00
},
{
0x0C
,
0x04
},
{
0x0D
,
0xC0
},
/* COM1, COM3, COM4 */
{
0x4F
,
0x71
},
{
0x50
,
0x3E
},
{
0x51
,
0x0C
},
/* MTX1, MTX2, MTX3 */
{
0x52
,
0x33
},
{
0x53
,
0x72
},
{
0x54
,
0x00
},
/* MTX4, MTX5, MTX6 */
{
0x55
,
0x2B
},
{
0x56
,
0x66
},
{
0x57
,
0xD2
},
/* MTX7, MTX8, MTX9 */
{
0x58
,
0x65
},
/* MTXS */
{
OV9640_REG_TERM
,
OV9640_VAL_TERM
}
};
/* RGB565 CIF */
const
static
struct
ov9640_reg
cif_565
[]
=
{
{
0x12
,
0x24
},
{
0x3C
,
0x40
},
{
0x40
,
0x10
},
/* COM7, COM12, COM15 */
{
0x04
,
0x00
},
{
0x0C
,
0x04
},
{
0x0D
,
0xC0
},
/* COM1, COM3, COM4 */
{
0x4F
,
0x71
},
{
0x50
,
0x3E
},
{
0x51
,
0x0C
},
/* MTX1, MTX2, MTX3 */
{
0x52
,
0x33
},
{
0x53
,
0x72
},
{
0x54
,
0x00
},
/* MTX4, MTX5, MTX6 */
{
0x55
,
0x2B
},
{
0x56
,
0x66
},
{
0x57
,
0xD2
},
/* MTX7, MTX8, MTX9 */
{
0x58
,
0x65
},
/* MTXS */
{
OV9640_REG_TERM
,
OV9640_VAL_TERM
}
};
/* RGB565 VGA */
const
static
struct
ov9640_reg
vga_565
[]
=
{
{
0x12
,
0x44
},
{
0x3C
,
0x40
},
{
0x40
,
0x10
},
/* COM7, COM12, COM15 */
{
0x04
,
0x00
},
{
0x0C
,
0x04
},
{
0x0D
,
0xC0
},
/* COM1, COM3, COM4 */
{
0x4F
,
0x71
},
{
0x50
,
0x3E
},
{
0x51
,
0x0C
},
/* MTX1, MTX2, MTX3 */
{
0x52
,
0x33
},
{
0x53
,
0x72
},
{
0x54
,
0x00
},
/* MTX4, MTX5, MTX6 */
{
0x55
,
0x2B
},
{
0x56
,
0x66
},
{
0x57
,
0xD2
},
/* MTX7, MTX8, MTX9 */
{
0x58
,
0x65
},
/* MTXS */
{
OV9640_REG_TERM
,
OV9640_VAL_TERM
}
};
/* RGB565 SXGA */
const
static
struct
ov9640_reg
sxga_565
[]
=
{
{
0x12
,
0x04
},
{
0x3C
,
0x40
},
{
0x40
,
0x10
},
/* COM7, COM12, COM15 */
{
0x04
,
0x00
},
{
0x0C
,
0x00
},
{
0x0D
,
0x40
},
/* COM1, COM3, COM4 */
{
0x4F
,
0x71
},
{
0x50
,
0x3E
},
{
0x51
,
0x0C
},
/* MTX1, MTX2, MTX3 */
{
0x52
,
0x33
},
{
0x53
,
0x72
},
{
0x54
,
0x00
},
/* MTX4, MTX5, MTX6 */
{
0x55
,
0x2B
},
{
0x56
,
0x66
},
{
0x57
,
0xD2
},
/* MTX7, MTX8, MTX9 */
{
0x58
,
0x65
},
/* MTXS */
{
OV9640_REG_TERM
,
OV9640_VAL_TERM
}
};
/* RGB555 QQCIF */
const
static
struct
ov9640_reg
qqcif_555
[]
=
{
{
0x12
,
0x0C
},
{
0x3C
,
0x40
},
{
0x40
,
0x30
},
/* COM7, COM12, COM15 */
{
0x04
,
0x24
},
{
0x0C
,
0x00
},
{
0x0D
,
0x40
},
/* COM1, COM3, COM4 */
{
0x4F
,
0x71
},
{
0x50
,
0x3E
},
{
0x51
,
0x0C
},
/* MTX1, MTX2, MTX3 */
{
0x52
,
0x33
},
{
0x53
,
0x72
},
{
0x54
,
0x00
},
/* MTX4, MTX5, MTX6 */
{
0x55
,
0x2B
},
{
0x56
,
0x66
},
{
0x57
,
0xD2
},
/* MTX7, MTX8, MTX9 */
{
0x58
,
0x65
},
/* MTXS */
{
OV9640_REG_TERM
,
OV9640_VAL_TERM
}
};
/* RGB555 QQVGA */
const
static
struct
ov9640_reg
qqvga_555
[]
=
{
{
0x12
,
0x14
},
{
0x3C
,
0x40
},
{
0x40
,
0x30
},
/* COM7, COM12, COM15 */
{
0x04
,
0x24
},
{
0x0C
,
0x04
},
{
0x0D
,
0xC0
},
/* COM1, COM3, COM4 */
{
0x4F
,
0x71
},
{
0x50
,
0x3E
},
{
0x51
,
0x0C
},
/* MTX1, MTX2, MTX3 */
{
0x52
,
0x33
},
{
0x53
,
0x72
},
{
0x54
,
0x00
},
/* MTX4, MTX5, MTX6 */
{
0x55
,
0x2B
},
{
0x56
,
0x66
},
{
0x57
,
0xD2
},
/* MTX7, MTX8, MTX9 */
{
0x58
,
0x65
},
/* MTXS */
{
OV9640_REG_TERM
,
OV9640_VAL_TERM
}
};
/* RGB555 QCIF */
const
static
struct
ov9640_reg
qcif_555
[]
=
{
{
0x12
,
0x0C
},
{
0x3C
,
0x40
},
{
0x40
,
0x30
},
/* COM7, COM12, COM15 */
{
0x04
,
0x00
},
{
0x0C
,
0x04
},
{
0x0D
,
0xC0
},
/* COM1, COM3, COM4 */
{
0x4F
,
0x71
},
{
0x50
,
0x3E
},
{
0x51
,
0x0C
},
/* MTX1, MTX2, MTX3 */
{
0x52
,
0x33
},
{
0x53
,
0x72
},
{
0x54
,
0x00
},
/* MTX4, MTX5, MTX6 */
{
0x55
,
0x2B
},
{
0x56
,
0x66
},
{
0x57
,
0xD2
},
/* MTX7, MTX8, MTX9 */
{
0x58
,
0x65
},
/* MTXS */
{
OV9640_REG_TERM
,
OV9640_VAL_TERM
}
};
/* RGB555 QVGA */
const
static
struct
ov9640_reg
qvga_555
[]
=
{
{
0x12
,
0x14
},
{
0x3C
,
0x40
},
{
0x40
,
0x30
},
/* COM7, COM12, COM15 */
{
0x04
,
0x00
},
{
0x0C
,
0x04
},
{
0x0D
,
0xC0
},
/* COM1, COM3, COM4 */
{
0x4F
,
0x71
},
{
0x50
,
0x3E
},
{
0x51
,
0x0C
},
/* MTX1, MTX2, MTX3 */
{
0x52
,
0x33
},
{
0x53
,
0x72
},
{
0x54
,
0x00
},
/* MTX4, MTX5, MTX6 */
{
0x55
,
0x2B
},
{
0x56
,
0x66
},
{
0x57
,
0xD2
},
/* MTX7, MTX8, MTX9 */
{
0x58
,
0x65
},
/* MTXS */
{
OV9640_REG_TERM
,
OV9640_VAL_TERM
}
};
/* RGB555 CIF */
const
static
struct
ov9640_reg
cif_555
[]
=
{
{
0x12
,
0x24
},
{
0x3C
,
0x40
},
{
0x40
,
0x30
},
/* COM7, COM12, COM15 */
{
0x04
,
0x00
},
{
0x0C
,
0x04
},
{
0x0D
,
0xC0
},
/* COM1, COM3, COM4 */
{
0x4F
,
0x71
},
{
0x50
,
0x3E
},
{
0x51
,
0x0C
},
/* MTX1, MTX2, MTX3 */
{
0x52
,
0x33
},
{
0x53
,
0x72
},
{
0x54
,
0x00
},
/* MTX4, MTX5, MTX6 */
{
0x55
,
0x2B
},
{
0x56
,
0x66
},
{
0x57
,
0xD2
},
/* MTX7, MTX8, MTX9 */
{
0x58
,
0x65
},
/* MTXS */
{
OV9640_REG_TERM
,
OV9640_VAL_TERM
}
};
/* RGB555 VGA */
const
static
struct
ov9640_reg
vga_555
[]
=
{
{
0x12
,
0x44
},
{
0x3C
,
0x40
},
{
0x40
,
0x30
},
/* COM7, COM12, COM15 */
{
0x04
,
0x00
},
{
0x0C
,
0x04
},
{
0x0D
,
0xC0
},
/* COM1, COM3, COM4 */
{
0x4F
,
0x71
},
{
0x50
,
0x3E
},
{
0x51
,
0x0C
},
/* MTX1, MTX2, MTX3 */
{
0x52
,
0x33
},
{
0x53
,
0x72
},
{
0x54
,
0x00
},
/* MTX4, MTX5, MTX6 */
{
0x55
,
0x2B
},
{
0x56
,
0x66
},
{
0x57
,
0xD2
},
/* MTX7, MTX8, MTX9 */
{
0x58
,
0x65
},
/* MTXS */
{
OV9640_REG_TERM
,
OV9640_VAL_TERM
}
};
/* RGB555 SXGA */
const
static
struct
ov9640_reg
sxga_555
[]
=
{
{
0x12
,
0x04
},
{
0x3C
,
0x40
},
{
0x40
,
0x30
},
/* COM7, COM12, COM15 */
{
0x04
,
0x00
},
{
0x0C
,
0x00
},
{
0x0D
,
0x40
},
/* COM1, COM3, COM4 */
{
0x4F
,
0x71
},
{
0x50
,
0x3E
},
{
0x51
,
0x0C
},
/* MTX1, MTX2, MTX3 */
{
0x52
,
0x33
},
{
0x53
,
0x72
},
{
0x54
,
0x00
},
/* MTX4, MTX5, MTX6 */
{
0x55
,
0x2B
},
{
0x56
,
0x66
},
{
0x57
,
0xD2
},
/* MTX7, MTX8, MTX9 */
{
0x58
,
0x65
},
/* MTXS */
{
OV9640_REG_TERM
,
OV9640_VAL_TERM
}
};
#define DEF_GAIN 31
#define DEF_AUTOGAIN 1
#define DEF_EXPOSURE 154
#define DEF_AEC 1
#define DEF_FREEZE_AGCAEC 0
#define DEF_BLUE 153
#define DEF_RED (255 - DEF_BLUE)
#define DEF_AWB 1
#define DEF_HFLIP 0
#define DEF_VFLIP 0
/* Our own specific controls */
#define V4L2_CID_FREEZE_AGCAEC V4L2_CID_PRIVATE_BASE+0
#define V4L2_CID_AUTOEXPOSURE V4L2_CID_PRIVATE_BASE+1
#define V4L2_CID_LAST_PRIV V4L2_CID_AUTOEXPOSURE
/* Video controls */
static
struct
vcontrol
{
struct
v4l2_queryctrl
qc
;
int
current_value
;
u8
reg
;
u8
mask
;
u8
start_bit
;
}
control
[]
=
{
{
{
V4L2_CID_GAIN
,
V4L2_CTRL_TYPE_INTEGER
,
"Gain"
,
0
,
63
,
1
,
DEF_GAIN
},
0
,
OV9640_GAIN
,
0x3f
,
0
},
{
{
V4L2_CID_AUTOGAIN
,
V4L2_CTRL_TYPE_BOOLEAN
,
"Auto Gain"
,
0
,
1
,
0
,
DEF_AUTOGAIN
},
0
,
OV9640_COM8
,
0x04
,
2
},
{
{
V4L2_CID_EXPOSURE
,
V4L2_CTRL_TYPE_INTEGER
,
"Exposure"
,
0
,
255
,
1
,
DEF_EXPOSURE
},
0
,
OV9640_AECH
,
0xff
,
0
},
{
{
V4L2_CID_AUTOEXPOSURE
,
V4L2_CTRL_TYPE_BOOLEAN
,
"Auto Exposure"
,
0
,
1
,
0
,
DEF_AEC
},
0
,
OV9640_COM8
,
0x01
,
0
},
{
{
V4L2_CID_FREEZE_AGCAEC
,
V4L2_CTRL_TYPE_BOOLEAN
,
"Freeze AGC/AEC"
,
0
,
1
,
0
,
DEF_FREEZE_AGCAEC
},
0
,
OV9640_COM9
,
0x01
,
0
},
{
{
V4L2_CID_RED_BALANCE
,
V4L2_CTRL_TYPE_INTEGER
,
"Red Balance"
,
0
,
255
,
1
,
DEF_RED
},
0
,
OV9640_RED
,
0xff
,
0
},
{
{
V4L2_CID_BLUE_BALANCE
,
V4L2_CTRL_TYPE_INTEGER
,
"Blue Balance"
,
0
,
255
,
1
,
DEF_BLUE
},
0
,
OV9640_BLUE
,
0xff
,
0
},
{
{
V4L2_CID_AUTO_WHITE_BALANCE
,
V4L2_CTRL_TYPE_BOOLEAN
,
"Auto White Balance"
,
0
,
1
,
0
,
DEF_AWB
},
0
,
OV9640_COM8
,
0x02
,
1
},
{
{
V4L2_CID_HFLIP
,
V4L2_CTRL_TYPE_BOOLEAN
,
"Mirror Image"
,
0
,
1
,
0
,
DEF_HFLIP
},
0
,
OV9640_MVFP
,
0x20
,
5
},
{
{
V4L2_CID_VFLIP
,
V4L2_CTRL_TYPE_BOOLEAN
,
"Vertical Flip"
,
0
,
1
,
0
,
DEF_VFLIP
},
0
,
OV9640_MVFP
,
0x10
,
4
},
};
#define NUM_CONTROLS (sizeof(control)/sizeof(control[0]))
const
static
struct
ov9640_reg
*
ov9640_reg_init
[
NUM_PIXEL_FORMATS
][
NUM_IMAGE_SIZES
]
=
{
{
qqcif_yuv
,
qqvga_yuv
,
qcif_yuv
,
qvga_yuv
,
cif_yuv
,
vga_yuv
,
sxga_yuv
},
{
qqcif_565
,
qqvga_565
,
qcif_565
,
qvga_565
,
cif_565
,
vga_565
,
sxga_565
},
{
qqcif_555
,
qqvga_555
,
qcif_555
,
qvga_555
,
cif_555
,
vga_555
,
sxga_555
},
};
/*
* Read a value from a register in an OV9640 sensor device. The value is
* returned in 'val'.
* Returns zero if successful, or non-zero otherwise.
*/
static
int
ov9640_read_reg
(
struct
i2c_client
*
client
,
u8
reg
,
u8
*
val
)
{
int
err
;
struct
i2c_msg
msg
[
1
];
unsigned
char
data
[
1
];
if
(
!
client
->
adapter
)
return
-
ENODEV
;
msg
->
addr
=
client
->
addr
;
msg
->
flags
=
0
;
msg
->
len
=
1
;
msg
->
buf
=
data
;
*
data
=
reg
;
err
=
i2c_transfer
(
client
->
adapter
,
msg
,
1
);
if
(
err
>=
0
)
{
msg
->
flags
=
I2C_M_RD
;
err
=
i2c_transfer
(
client
->
adapter
,
msg
,
1
);
}
if
(
err
>=
0
)
{
*
val
=
*
data
;
return
0
;
}
return
err
;
}
/* Write a value to a register in an OV9640 sensor device.
* Returns zero if successful, or non-zero otherwise.
*/
static
int
ov9640_write_reg
(
struct
i2c_client
*
client
,
u8
reg
,
u8
val
)
{
int
err
;
struct
i2c_msg
msg
[
1
];
unsigned
char
data
[
2
];
if
(
!
client
->
adapter
)
return
-
ENODEV
;
msg
->
addr
=
client
->
addr
;
msg
->
flags
=
0
;
msg
->
len
=
2
;
msg
->
buf
=
data
;
data
[
0
]
=
reg
;
data
[
1
]
=
val
;
err
=
i2c_transfer
(
client
->
adapter
,
msg
,
1
);
if
(
err
>=
0
)
return
0
;
return
err
;
}
static
int
ov9640_write_reg_mask
(
struct
i2c_client
*
client
,
u8
reg
,
u8
*
val
,
u8
mask
)
{
u8
oldval
,
newval
;
int
rc
;
if
(
mask
==
0xff
)
{
newval
=
*
val
;
}
else
{
/* need to do read - modify - write */
if
((
rc
=
ov9640_read_reg
(
client
,
reg
,
&
oldval
)))
return
rc
;
oldval
&=
(
~
mask
);
/* Clear the masked bits */
*
val
&=
mask
;
/* Enforce mask on value */
newval
=
oldval
|
*
val
;
/* Set the desired bits */
}
/* write the new value to the register */
if
((
rc
=
ov9640_write_reg
(
client
,
reg
,
newval
)))
return
rc
;
if
((
rc
=
ov9640_read_reg
(
client
,
reg
,
&
newval
)))
return
rc
;
*
val
=
newval
&
mask
;
return
0
;
}
static
int
ov9640_read_reg_mask
(
struct
i2c_client
*
client
,
u8
reg
,
u8
*
val
,
u8
mask
)
{
int
rc
;
if
((
rc
=
ov9640_read_reg
(
client
,
reg
,
val
)))
return
rc
;
(
*
val
)
&=
mask
;
return
0
;
}
/* Initialize a list of OV9640 registers.
* The list of registers is terminated by the pair of values
* { OV9640_REG_TERM, OV9640_VAL_TERM }.
* Returns zero if successful, or non-zero otherwise.
*/
static
int
ov9640_write_regs
(
struct
i2c_client
*
client
,
const
struct
ov9640_reg
reglist
[])
{
int
err
;
const
struct
ov9640_reg
*
next
=
reglist
;
while
(
!
((
next
->
reg
==
OV9640_REG_TERM
)
&&
(
next
->
val
==
OV9640_VAL_TERM
)))
{
err
=
ov9640_write_reg
(
client
,
next
->
reg
,
next
->
val
);
udelay
(
100
);
if
(
err
)
return
err
;
next
++
;
}
return
0
;
}
/* Returns the index of the requested ID from the control structure array */
static
int
find_vctrl
(
int
id
)
{
int
i
;
if
(
id
<
V4L2_CID_BASE
)
return
-
EDOM
;
for
(
i
=
NUM_CONTROLS
-
1
;
i
>=
0
;
i
--
)
if
(
control
[
i
].
qc
.
id
==
id
)
break
;
if
(
i
<
0
)
i
=
-
EINVAL
;
return
i
;
}
/* Calculate the internal clock divisor (value of the CLKRC register) of the
* OV9640 given the image size, the frequency (in Hz) of its XCLK input and a
* desired frame period (in seconds). The frame period 'fper' is expressed as
* a fraction. The frame period is an input/output parameter.
* Returns the value of the OV9640 CLKRC register that will yield the frame
* period returned in 'fper' at the specified xclk frequency. The
* returned period will be as close to the requested period as possible.
*/
static
unsigned
char
ov9640_clkrc
(
enum
image_size
isize
,
unsigned
long
xclk
,
struct
v4l2_fract
*
fper
)
{
unsigned
long
fpm
,
fpm_max
;
/* frames per minute */
unsigned
long
divisor
;
const
unsigned
long
divisor_max
=
64
;
const
static
unsigned
long
clks_per_frame
[]
=
{
200000
,
200000
,
200000
,
200000
,
400000
,
800000
,
3200000
};
if
(
fper
->
numerator
>
0
)
fpm
=
(
fper
->
denominator
*
60
)
/
fper
->
numerator
;
else
fpm
=
0xffffffff
;
fpm_max
=
(
xclk
*
60
)
/
clks_per_frame
[
isize
];
if
(
fpm_max
==
0
)
fpm_max
=
1
;
if
(
fpm
>
fpm_max
)
fpm
=
fpm_max
;
if
(
fpm
==
0
)
fpm
=
1
;
divisor
=
fpm_max
/
fpm
;
if
(
divisor
>
divisor_max
)
divisor
=
divisor_max
;
fper
->
numerator
=
divisor
*
60
;
fper
->
denominator
=
fpm_max
;
/* try to reduce the fraction */
while
(
!
(
fper
->
denominator
%
5
)
&&
!
(
fper
->
numerator
%
5
))
{
fper
->
numerator
/=
5
;
fper
->
denominator
/=
5
;
}
while
(
!
(
fper
->
denominator
%
3
)
&&
!
(
fper
->
numerator
%
3
))
{
fper
->
numerator
/=
3
;
fper
->
denominator
/=
3
;
}
while
(
!
(
fper
->
denominator
%
2
)
&&
!
(
fper
->
numerator
%
2
))
{
fper
->
numerator
/=
2
;
fper
->
denominator
/=
2
;
}
if
(
fper
->
numerator
<
fper
->
denominator
)
{
if
(
!
(
fper
->
denominator
%
fper
->
numerator
))
{
fper
->
denominator
/=
fper
->
numerator
;
fper
->
numerator
=
1
;
}
}
else
{
if
(
!
(
fper
->
numerator
%
fper
->
denominator
))
{
fper
->
numerator
/=
fper
->
denominator
;
fper
->
denominator
=
1
;
}
}
/* we set bit 7 in CLKRC to enable the digital PLL */
return
(
0x80
|
(
divisor
-
1
));
}
/* Configure the OV9640 for a specified image size, pixel format, and frame
* period. xclk is the frequency (in Hz) of the xclk input to the OV9640.
* fper is the frame period (in seconds) expressed as a fraction.
* Returns zero if successful, or non-zero otherwise.
* The actual frame period is returned in fper.
*/
static
int
ov9640_configure
(
struct
i2c_client
*
client
,
enum
image_size
isize
,
enum
pixel_format
pfmt
,
unsigned
long
xclk
,
struct
v4l2_fract
*
fper
)
{
int
err
;
unsigned
char
clkrc
;
/* common register initialization */
err
=
ov9640_write_regs
(
client
,
ov9640_common
);
if
(
err
)
return
err
;
/* configure image size and pixel format */
err
=
ov9640_write_regs
(
client
,
ov9640_reg_init
[
pfmt
][
isize
]);
if
(
err
)
return
err
;
/* configure frame rate */
clkrc
=
ov9640_clkrc
(
isize
,
xclk
,
fper
);
err
=
ov9640_write_reg
(
client
,
OV9640_CLKRC
,
clkrc
);
if
(
err
)
return
err
;
return
0
;
}
static
int
ov9640_powerup
(
void
)
{
unsigned
char
expa
;
int
err
;
if
(
machine_is_omap_h2
())
return
0
;
/* read the current state of GPIO EXPA output */
if
((
err
=
read_gpio_expa
(
&
expa
,
0x27
))){
printk
(
KERN_ERR
"Error reading GPIO EXPA
\n
"
);
return
err
;
}
/* set GPIO EXPA P7 CAMERA_MOD_EN to power-up sensor */
if
((
err
=
write_gpio_expa
(
expa
|
0x80
,
0x27
)))
{
printk
(
KERN_ERR
"Error writing to GPIO EXPA
\n
"
);
return
err
;
}
return
0
;
}
static
int
ov9640_powerdown
(
void
)
{
unsigned
char
expa
;
int
err
;
if
(
machine_is_omap_h2
())
return
0
;
/* read the current state of GPIO EXPA output */
if
((
err
=
read_gpio_expa
(
&
expa
,
0x27
))){
printk
(
KERN_ERR
"Error reading GPIO EXPA
\n
"
);
return
err
;
}
/* clear GPIO EXPA P7 CAMERA_MOD_EN to power-up sensor */
if
((
err
=
write_gpio_expa
(
expa
&
~
0x80
,
0x27
)))
{
printk
(
KERN_ERR
"Error writing to GPIO EXPA
\n
"
);
return
err
;
}
return
0
;
}
static
int
ov9640sensor_power_on
(
void
*
priv
)
{
return
ov9640_powerup
();
}
static
int
ov9640sensor_power_off
(
void
*
priv
)
{
return
ov9640_powerdown
();
}
/* Detect if an OV9640 is present, and if so which revision.
* A device is considered to be detected if the manufacturer ID (MIDH and MIDL)
* and the product ID (PID) registers match the expected values.
* Any value of the version ID (VER) register is accepted.
* Here are the version numbers we know about:
* 0x48 --> OV9640 Revision 1 or OV9640 Revision 2
* 0x49 --> OV9640 Revision 3
* Returns a negative error number if no device is detected, or the
* non-negative value of the version ID register if a device is detected.
*/
static
int
ov9640_detect
(
struct
i2c_client
*
client
)
{
u8
midh
,
midl
,
pid
,
ver
;
if
(
!
client
)
return
-
ENODEV
;
if
(
ov9640_read_reg
(
client
,
OV9640_MIDH
,
&
midh
))
return
-
ENODEV
;
if
(
ov9640_read_reg
(
client
,
OV9640_MIDL
,
&
midl
))
return
-
ENODEV
;
if
(
ov9640_read_reg
(
client
,
OV9640_PID
,
&
pid
))
return
-
ENODEV
;
if
(
ov9640_read_reg
(
client
,
OV9640_VER
,
&
ver
))
return
-
ENODEV
;
if
((
midh
!=
OV9640_MIDH_MAGIC
)
||
(
midl
!=
OV9640_MIDL_MAGIC
)
||
(
pid
!=
OV9640_PID_MAGIC
))
{
/* We didn't read the values we expected, so
* this must not be an OV9640.
*/
return
-
ENODEV
;
}
return
ver
;
}
/* This function registers an I2C client via i2c_attach_client() for an OV9640
* sensor device. If 'probe' is non-zero, then the I2C client is only
* registered if the device can be detected. If 'probe' is zero, then no
* device detection is attempted and the I2C client is always registered.
* Returns zero if an I2C client is successfully registered, or non-zero
* otherwise.
*/
static
int
ov9640_i2c_attach_client
(
struct
i2c_adapter
*
adap
,
int
addr
,
int
probe
)
{
struct
ov9640_sensor
*
sensor
=
&
ov9640
;
struct
i2c_client
*
client
=
&
sensor
->
client
;
int
err
;
if
(
client
->
adapter
)
return
-
EBUSY
;
/* our client is already attached */
client
->
addr
=
addr
;
client
->
flags
=
I2C_CLIENT_ALLOW_USE
;
client
->
driver
=
&
sensor
->
driver
;
client
->
adapter
=
adap
;
err
=
i2c_attach_client
(
client
);
if
(
err
)
{
client
->
adapter
=
NULL
;
return
err
;
}
if
(
probe
)
{
err
=
ov9640_detect
(
client
);
if
(
err
<
0
)
{
i2c_detach_client
(
client
);
client
->
adapter
=
NULL
;
return
err
;
}
sensor
->
ver
=
err
;
}
return
0
;
}
/* This function is called by i2c_del_adapter() and i2c_del_driver()
* if the adapter or driver with which this I2C client is associated is
* removed. This function unregisters the client via i2c_detach_client().
* Returns zero if the client is successfully detached, or non-zero
* otherwise.
*/
static
int
ov9640_i2c_detach_client
(
struct
i2c_client
*
client
)
{
int
err
;
if
(
!
client
->
adapter
)
return
-
ENODEV
;
/* our client isn't attached */
err
=
i2c_detach_client
(
client
);
client
->
adapter
=
NULL
;
return
err
;
}
/* This function will be called for each registered I2C bus adapter when our
* I2C driver is registered via i2c_add_driver(). It will also be called
* whenever a new I2C adapter is registered after our I2C driver is registered.
* This function probes the specified I2C bus adapter to determine if an
* OV9640 sensor device is present. If a device is detected, an I2C client
* is registered for it via ov9640_i2c_attach_client(). Note that we can't use
* the standard i2c_probe() function to look for the sensor because the OMAP
* I2C controller doesn't support probing.
* Returns zero if an OV9640 device is detected and an I2C client successfully
* registered for it, or non-zero otherwise.
*/
static
int
ov9640_i2c_probe_adapter
(
struct
i2c_adapter
*
adap
)
{
return
ov9640_i2c_attach_client
(
adap
,
OV9640_I2C_ADDR
,
1
);
}
/* Find the best match for a requested image capture size. The best match
* is chosen as the nearest match that has the same number or fewer pixels
* as the requested size, or the smallest image size if the requested size
* has fewer pixels than the smallest image.
*/
static
enum
image_size
ov9640_find_size
(
unsigned
int
width
,
unsigned
int
height
)
{
enum
image_size
isize
;
unsigned
long
pixels
=
width
*
height
;
for
(
isize
=
QQCIF
;
isize
<
SXGA
;
isize
++
)
{
if
(
ov9640_sizes
[
isize
+
1
].
height
*
ov9640_sizes
[
isize
+
1
].
width
>
pixels
)
{
return
isize
;
}
}
return
SXGA
;
}
/* following are sensor interface functions implemented by
* OV9640 sensor driver.
*/
static
int
ov9640sensor_query_control
(
struct
v4l2_queryctrl
*
qc
,
void
*
priv
)
{
int
i
;
i
=
find_vctrl
(
qc
->
id
);
if
(
i
==
-
EINVAL
)
{
qc
->
flags
=
V4L2_CTRL_FLAG_DISABLED
;
return
0
;
}
if
(
i
<
0
)
return
-
EINVAL
;
*
qc
=
control
[
i
].
qc
;
return
0
;
}
static
int
ov9640sensor_get_control
(
struct
v4l2_control
*
vc
,
void
*
priv
)
{
struct
ov9640_sensor
*
sensor
=
(
struct
ov9640_sensor
*
)
priv
;
struct
i2c_client
*
client
=
&
sensor
->
client
;
int
i
,
val
;
struct
vcontrol
*
lvc
;
i
=
find_vctrl
(
vc
->
id
);
if
(
i
<
0
)
return
-
EINVAL
;
lvc
=
&
control
[
i
];
if
(
ov9640_read_reg_mask
(
client
,
lvc
->
reg
,
(
u8
*
)
&
val
,
lvc
->
mask
))
return
-
EIO
;
val
=
val
>>
lvc
->
start_bit
;
if
(
val
>=
0
)
{
vc
->
value
=
lvc
->
current_value
=
val
;
return
0
;
}
else
return
val
;
}
static
int
ov9640sensor_set_control
(
struct
v4l2_control
*
vc
,
void
*
priv
)
{
struct
ov9640_sensor
*
sensor
=
(
struct
ov9640_sensor
*
)
priv
;
struct
i2c_client
*
client
=
&
sensor
->
client
;
struct
vcontrol
*
lvc
;
int
val
=
vc
->
value
;
int
i
;
i
=
find_vctrl
(
vc
->
id
);
if
(
i
<
0
)
return
-
EINVAL
;
lvc
=
&
control
[
i
];
val
=
val
<<
lvc
->
start_bit
;
if
(
ov9640_write_reg_mask
(
client
,
lvc
->
reg
,
(
u8
*
)
&
val
,
(
u8
)
lvc
->
mask
))
return
-
EIO
;
val
=
val
>>
lvc
->
start_bit
;
if
(
val
>=
0
)
{
lvc
->
current_value
=
val
;
return
0
;
}
else
return
val
;
}
/* Implement the VIDIOC_ENUM_FMT ioctl for the CAPTURE buffer type.
*/
static
int
ov9640sensor_enum_pixformat
(
struct
v4l2_fmtdesc
*
fmt
,
void
*
priv
)
{
int
index
=
fmt
->
index
;
enum
v4l2_buf_type
type
=
fmt
->
type
;
memset
(
fmt
,
0
,
sizeof
(
*
fmt
));
fmt
->
index
=
index
;
fmt
->
type
=
type
;
switch
(
fmt
->
type
)
{
case
V4L2_BUF_TYPE_VIDEO_CAPTURE
:
if
(
index
>=
NUM_CAPTURE_FORMATS
)
return
-
EINVAL
;
break
;
case
V4L2_BUF_TYPE_VIDEO_OVERLAY
:
if
(
index
>=
NUM_OVERLAY_FORMATS
)
return
-
EINVAL
;
break
;
default:
return
-
EINVAL
;
}
fmt
->
flags
=
ov9640_formats
[
index
].
flags
;
strlcpy
(
fmt
->
description
,
ov9640_formats
[
index
].
description
,
sizeof
(
fmt
->
description
));
fmt
->
pixelformat
=
ov9640_formats
[
index
].
pixelformat
;
return
0
;
}
/* Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. This
* ioctl is used to negotiate the image capture size and pixel format
* without actually making it take effect.
*/
static
int
ov9640sensor_try_format
(
struct
v4l2_pix_format
*
pix
,
void
*
priv
)
{
enum
image_size
isize
;
int
ifmt
;
isize
=
ov9640_find_size
(
pix
->
width
,
pix
->
height
);
pix
->
width
=
ov9640_sizes
[
isize
].
width
;
pix
->
height
=
ov9640_sizes
[
isize
].
height
;
for
(
ifmt
=
0
;
ifmt
<
NUM_CAPTURE_FORMATS
;
ifmt
++
)
{
if
(
pix
->
pixelformat
==
ov9640_formats
[
ifmt
].
pixelformat
)
break
;
}
if
(
ifmt
==
NUM_CAPTURE_FORMATS
)
ifmt
=
0
;
pix
->
pixelformat
=
ov9640_formats
[
ifmt
].
pixelformat
;
pix
->
field
=
V4L2_FIELD_NONE
;
pix
->
bytesperline
=
pix
->
width
*
2
;
pix
->
sizeimage
=
pix
->
bytesperline
*
pix
->
height
;
pix
->
priv
=
0
;
switch
(
pix
->
pixelformat
)
{
case
V4L2_PIX_FMT_YUYV
:
case
V4L2_PIX_FMT_UYVY
:
default:
pix
->
colorspace
=
V4L2_COLORSPACE_JPEG
;
break
;
case
V4L2_PIX_FMT_RGB565
:
case
V4L2_PIX_FMT_RGB565X
:
case
V4L2_PIX_FMT_RGB555
:
case
V4L2_PIX_FMT_RGB555X
:
pix
->
colorspace
=
V4L2_COLORSPACE_SRGB
;
break
;
}
return
0
;
}
/* Given the image capture format in pix, the nominal frame period in
* timeperframe, calculate the required xclk frequency
* The nominal xclk input frequency of the OV9640 is 24MHz, maximum
* frequency is 48MHz, and minimum frequency is 10MHz.
*/
static
unsigned
long
ov9640sensor_calc_xclk
(
struct
v4l2_pix_format
*
pix
,
struct
v4l2_fract
*
timeperframe
,
void
*
priv
)
{
unsigned
long
tgt_xclk
;
/* target xclk */
unsigned
long
tgt_fpm
;
/* target frames per minute */
enum
image_size
isize
;
/* We use arbitrary rules to select the xclk frequency. If the
* capture size is VGA and the frame rate is greater than 900
* frames per minute, or if the capture size is SXGA and the
* frame rate is greater than 450 frames per minutes, then the
* xclk frequency will be set to 48MHz. Otherwise, the xclk
* frequency will be set to 24MHz. If the mclk frequency is such that
* the target xclk frequency is not achievable, then xclk will be set
* as close as to the target as possible.
*/
if
((
timeperframe
->
numerator
==
0
)
||
(
timeperframe
->
denominator
==
0
))
{
/* supply a default nominal_timeperframe of 15 fps */
timeperframe
->
numerator
=
1
;
timeperframe
->
denominator
=
15
;
}
tgt_fpm
=
(
timeperframe
->
denominator
*
60
)
/
timeperframe
->
numerator
;
tgt_xclk
=
24000000
;
isize
=
ov9640_find_size
(
pix
->
width
,
pix
->
height
);
switch
(
isize
)
{
case
SXGA
:
if
(
tgt_fpm
>
450
)
tgt_xclk
=
48000000
;
break
;
case
VGA
:
if
(
tgt_fpm
>
900
)
tgt_xclk
=
48000000
;
break
;
default:
break
;
}
return
tgt_xclk
;
}
/* Given a capture format in pix, the frame period in timeperframe, and
* the xclk frequency, set the capture format of the OV9640 sensor.
* The actual frame period will be returned in timeperframe.
*/
static
int
ov9640sensor_configure
(
struct
v4l2_pix_format
*
pix
,
unsigned
long
xclk
,
struct
v4l2_fract
*
timeperframe
,
void
*
priv
)
{
struct
ov9640_sensor
*
sensor
=
(
struct
ov9640_sensor
*
)
priv
;
enum
pixel_format
pfmt
=
YUV
;
switch
(
pix
->
pixelformat
)
{
case
V4L2_PIX_FMT_RGB565
:
case
V4L2_PIX_FMT_RGB565X
:
pfmt
=
RGB565
;
break
;
case
V4L2_PIX_FMT_RGB555
:
case
V4L2_PIX_FMT_RGB555X
:
pfmt
=
RGB555
;
break
;
case
V4L2_PIX_FMT_YUYV
:
case
V4L2_PIX_FMT_UYVY
:
default:
pfmt
=
YUV
;
}
return
ov9640_configure
(
&
sensor
->
client
,
ov9640_find_size
(
pix
->
width
,
pix
->
height
),
pfmt
,
xclk
,
timeperframe
);
}
/* Prepare for the driver to exit.
* Balances ov9640sensor_init().
* This function must de-initialize the sensor and its associated data
* structures.
*/
static
int
ov9640sensor_cleanup
(
void
*
priv
)
{
struct
ov9640_sensor
*
sensor
=
(
struct
ov9640_sensor
*
)
priv
;
if
(
sensor
)
{
i2c_del_driver
(
&
sensor
->
driver
);
ov9640_powerdown
();
}
return
0
;
}
/* Initialize the OV9640 sensor.
* This routine allocates and initializes the data structure for the sensor,
* powers up the sensor, registers the I2C driver, and sets a default image
* capture format in pix. The capture format is not actually programmed
* into the OV9640 sensor by this routine.
* This function must return a non-NULL value to indicate that
* initialization is successful.
*/
static
void
*
ov9640sensor_init
(
struct
v4l2_pix_format
*
pix
)
{
struct
ov9640_sensor
*
sensor
=
&
ov9640
;
struct
i2c_driver
*
driver
=
&
sensor
->
driver
;
int
err
;
memset
(
sensor
,
0
,
sizeof
(
*
sensor
));
/* power-up the sensor */
if
(
ov9640_powerup
())
return
NULL
;
driver
->
owner
=
THIS_MODULE
;
strlcpy
(
driver
->
name
,
"OV9640 I2C driver"
,
sizeof
(
driver
->
name
));
driver
->
id
=
I2C_DRIVERID_EXP0
;
driver
->
flags
=
I2C_DF_NOTIFY
;
driver
->
attach_adapter
=
ov9640_i2c_probe_adapter
;
driver
->
detach_client
=
ov9640_i2c_detach_client
;
err
=
i2c_add_driver
(
driver
);
if
(
err
)
{
printk
(
KERN_ERR
"Failed to register OV9640 I2C client.
\n
"
);
return
NULL
;
}
if
(
!
sensor
->
client
.
adapter
)
{
printk
(
KERN_WARNING
"Failed to detect OV9640 sensor chip.
\n
"
);
return
NULL
;
}
else
{
printk
(
KERN_INFO
"OV9640 sensor chip version 0x%02x detected
\n
"
,
sensor
->
ver
);
}
/* Make the default capture format QCIF RGB565 */
pix
->
width
=
ov9640_sizes
[
QCIF
].
width
;
pix
->
height
=
ov9640_sizes
[
QCIF
].
height
;
pix
->
pixelformat
=
V4L2_PIX_FMT_RGB565
;
ov9640sensor_try_format
(
pix
,
NULL
);
return
(
void
*
)
sensor
;
}
struct
camera_sensor
camera_sensor_if
=
{
version:
0x01
,
name:
"OV9640"
,
init:
ov9640sensor_init
,
cleanup:
ov9640sensor_cleanup
,
enum_pixformat:
ov9640sensor_enum_pixformat
,
try_format:
ov9640sensor_try_format
,
calc_xclk:
ov9640sensor_calc_xclk
,
configure:
ov9640sensor_configure
,
query_control:
ov9640sensor_query_control
,
get_control:
ov9640sensor_get_control
,
set_control:
ov9640sensor_set_control
,
power_on:
ov9640sensor_power_on
,
power_off:
ov9640sensor_power_off
,
};
void
print_ov9640_regs
(
void
*
priv
)
{
struct
ov9640_sensor
*
sensor
=
(
struct
ov9640_sensor
*
)
priv
;
u8
reg
,
val
;
for
(
reg
=
0x00
;
reg
<=
0x8A
;
reg
++
)
if
(
ov9640_read_reg
(
&
sensor
->
client
,
reg
,
&
val
))
printk
(
"error reading %x
\n
"
,
reg
);
else
printk
(
"reg %x = %x
\n
"
,
reg
,
val
);
}
#endif
/* ifdef CAMERA_OV9640 */
include/asm-arm/arch-omap/camera.h
0 → 100644
View file @
8403b938
/*
* OMAP-1510 camera interface
*
* FIXME: This will go to same directory with the camera driver
*/
#define CAMERA_BASE 0xfffb6800
#define CAM_CTRLCLOCK_REG (CAMERA_BASE + 0x00)
#define CAM_IT_STATUS_REG (CAMERA_BASE + 0x04)
#define CAM_MODE_REG (CAMERA_BASE + 0x08)
#define CAM_STATUS_REG (CAMERA_BASE + 0x0C)
#define CAM_CAMDATA_REG (CAMERA_BASE + 0x10)
#define CAM_GPIO_REG (CAMERA_BASE + 0x14)
#define CAM_PEAK_CTR_REG (CAMERA_BASE + 0x18)
#ifndef __ASSEMBLY__
typedef
struct
{
__u32
ctrlclock
;
/* 00 */
__u32
it_status
;
/* 04 */
__u32
mode
;
/* 08 */
__u32
status
;
/* 0C */
__u32
camdata
;
/* 10 */
__u32
gpio
;
/* 14 */
__u32
peak_counter
;
/* 18 */
}
camera_regs_t
;
#endif
/* CTRLCLOCK bit shifts */
#define FOSCMOD_BIT 0
#define FOSCMOD_MASK (0x7 << FOSCMOD_BIT)
#define FOSCMOD_12MHz 0x0
#define FOSCMOD_6MHz 0x2
#define FOSCMOD_9_6MHz 0x4
#define FOSCMOD_24MHz 0x5
#define FOSCMOD_8MHz 0x6
#define POLCLK (1<<3)
#define CAMEXCLK_EN (1<<4)
#define MCLK_EN (1<<5)
#define DPLL_EN (1<<6)
#define LCLK_EN (1<<7)
/* IT_STATUS bit shifts */
#define V_UP (1<<0)
#define V_DOWN (1<<1)
#define H_UP (1<<2)
#define H_DOWN (1<<3)
#define FIFO_FULL (1<<4)
#define DATA_XFER (1<<5)
/* MODE bit shifts */
#define CAMOSC (1<<0)
#define IMGSIZE_BIT 1
#define IMGSIZE_MASK (0x3 << IMGSIZE_BIT)
#define IMGSIZE_CIF (0x0 << IMGSIZE_BIT)
/* 352x288 */
#define IMGSIZE_QCIF (0x1 << IMGSIZE_BIT)
/* 176x144 */
#define IMGSIZE_VGA (0x2 << IMGSIZE_BIT)
/* 640x480 */
#define IMGSIZE_QVGA (0x3 << IMGSIZE_BIT)
/* 320x240 */
#define ORDERCAMD (1<<3)
#define EN_V_UP (1<<4)
#define EN_V_DOWN (1<<5)
#define EN_H_UP (1<<6)
#define EN_H_DOWN (1<<7)
#define EN_DMA (1<<8)
#define THRESHOLD (1<<9)
#define THRESHOLD_BIT 9
#define THRESHOLD_MASK (0x7f<<9)
#define EN_NIRQ (1<<16)
#define EN_FIFO_FULL (1<<17)
#define RAZ_FIFO (1<<18)
/* STATUS bit shifts */
#define VSTATUS (1<<0)
#define HSTATUS (1<<1)
/* GPIO bit shifts */
#define CAM_RST (1<<0)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment