Commit 3434eb7e authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

V4L/DVB (5306): Add support for VIDIOC_G_CHIP_IDENT

VIDIOC_G_CHIP_IDENT improves debugging of card problems: it can be
used to detect which chips are on the board and based on that information
selected register dumps can be made, making it easy to debug complicated
media chips containing tens or hundreds of registers.
This ioctl replaces the internal VIDIOC_INT_G_CHIP_IDENT ioctl.
Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent ced80c67
......@@ -22,6 +22,7 @@
#include <linux/spinlock.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/list.h>
......@@ -164,7 +165,7 @@ struct cafe_camera
struct tasklet_struct s_tasklet;
/* Current operating parameters */
enum v4l2_chip_ident sensor_type; /* Currently ov7670 only */
u32 sensor_type; /* Currently ov7670 only */
struct v4l2_pix_format pix_format;
/* Locks */
......@@ -818,6 +819,7 @@ static int __cafe_cam_reset(struct cafe_camera *cam)
*/
static int cafe_cam_init(struct cafe_camera *cam)
{
struct v4l2_chip_ident chip = { V4L2_CHIP_MATCH_I2C_ADDR, 0, 0, 0 };
int ret;
mutex_lock(&cam->s_mutex);
......@@ -827,9 +829,11 @@ static int cafe_cam_init(struct cafe_camera *cam)
ret = __cafe_cam_reset(cam);
if (ret)
goto out;
ret = __cafe_cam_cmd(cam, VIDIOC_INT_G_CHIP_IDENT, &cam->sensor_type);
chip.match_chip = cam->sensor->addr;
ret = __cafe_cam_cmd(cam, VIDIOC_G_CHIP_IDENT, &chip);
if (ret)
goto out;
cam->sensor_type = chip.ident;
// if (cam->sensor->addr != OV7xx0_SID) {
if (cam->sensor_type != V4L2_IDENT_OV7670) {
cam_err(cam, "Unsupported sensor type %d", cam->sensor->addr);
......
......@@ -35,6 +35,7 @@
#include <linux/videodev2.h>
#include <linux/i2c.h>
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
#include <media/cx25840.h>
#include "cx25840-core.h"
......@@ -827,9 +828,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
cx25840_initialize(client, 0);
break;
case VIDIOC_INT_G_CHIP_IDENT:
*(enum v4l2_chip_ident *)arg = state->id;
break;
case VIDIOC_G_CHIP_IDENT:
return v4l2_chip_ident_i2c_client(client, arg, state->id, state->rev);
default:
return -EINVAL;
......@@ -847,7 +847,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
{
struct i2c_client *client;
struct cx25840_state *state;
enum v4l2_chip_ident id;
u32 id;
u16 device_id;
/* Check if the adapter supports the needed features
......@@ -902,6 +902,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
state->audmode = V4L2_TUNER_MODE_LANG1;
state->vbi_line_offset = 8;
state->id = id;
state->rev = device_id;
i2c_attach_client(client);
......
......@@ -43,7 +43,8 @@ struct cx25840_state {
u32 audclk_freq;
int audmode;
int vbi_line_offset;
enum v4l2_chip_ident id;
u32 id;
u32 rev;
int is_cx25836;
};
......
......@@ -15,6 +15,7 @@
#include <linux/delay.h>
#include <linux/videodev.h>
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
#include <linux/i2c.h>
......@@ -1270,9 +1271,8 @@ static int ov7670_command(struct i2c_client *client, unsigned int cmd,
void *arg)
{
switch (cmd) {
case VIDIOC_INT_G_CHIP_IDENT:
* (enum v4l2_chip_ident *) arg = V4L2_IDENT_OV7670;
return 0;
case VIDIOC_G_CHIP_IDENT:
return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_OV7670, 0);
case VIDIOC_INT_RESET:
ov7670_reset(client);
......
......@@ -45,6 +45,7 @@
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
#include <media/saa7115.h>
#include <asm/div64.h>
......@@ -80,7 +81,7 @@ struct saa711x_state {
int sat;
int width;
int height;
enum v4l2_chip_ident ident;
u32 ident;
u32 audclk_freq;
u32 crystal_freq;
u8 ucgc;
......@@ -1232,7 +1233,6 @@ static void saa711x_decode_vbi_line(struct i2c_client *client,
static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct saa711x_state *state = i2c_get_clientdata(client);
int *iarg = arg;
/* ioctls to allow direct access to the saa7115 registers for testing */
switch (cmd) {
......@@ -1437,9 +1437,8 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
}
#endif
case VIDIOC_INT_G_CHIP_IDENT:
*iarg = state->ident;
break;
case VIDIOC_G_CHIP_IDENT:
return v4l2_chip_ident_i2c_client(client, arg, state->ident, 0);
default:
return -EINVAL;
......
......@@ -54,6 +54,7 @@
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
#include <media/saa7127.h>
static int debug = 0;
......@@ -234,7 +235,7 @@ static struct i2c_reg_value saa7127_init_config_50hz[] = {
struct saa7127_state {
v4l2_std_id std;
enum v4l2_chip_ident ident;
u32 ident;
enum saa7127_input_type input_type;
enum saa7127_output_type output_type;
int video_enable;
......@@ -650,9 +651,8 @@ static int saa7127_command(struct i2c_client *client,
break;
}
case VIDIOC_INT_G_CHIP_IDENT:
*(enum v4l2_chip_ident *)arg = state->ident;
break;
case VIDIOC_G_CHIP_IDENT:
return v4l2_chip_ident_i2c_client(client, arg, state->ident, 0);
default:
return -EINVAL;
......
......@@ -60,6 +60,7 @@
#include <linux/video_decoder.h>
#define __OLD_VIDIOC_ /* To allow fixing old calls*/
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
......@@ -383,6 +384,8 @@ static const char *v4l2_ioctls[] = {
[_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER",
[_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER",
[_IOC_NR(VIDIOC_G_CHIP_IDENT)] = "VIDIOC_G_CHIP_IDENT",
#endif
};
#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
......@@ -413,7 +416,6 @@ static const char *v4l2_int_ioctls[] = {
[_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)] = "VIDIOC_INT_DECODE_VBI_LINE",
[_IOC_NR(VIDIOC_INT_S_VBI_DATA)] = "VIDIOC_INT_S_VBI_DATA",
[_IOC_NR(VIDIOC_INT_G_VBI_DATA)] = "VIDIOC_INT_G_VBI_DATA",
[_IOC_NR(VIDIOC_INT_G_CHIP_IDENT)] = "VIDIOC_INT_G_CHIP_IDENT",
[_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)] = "VIDIOC_INT_I2S_CLOCK_FREQ",
[_IOC_NR(VIDIOC_INT_S_STANDBY)] = "VIDIOC_INT_S_STANDBY",
[_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)] = "VIDIOC_INT_S_AUDIO_ROUTING",
......@@ -981,6 +983,22 @@ int v4l2_chip_match_i2c_client(struct i2c_client *c, u32 match_type, u32 match_c
}
}
int v4l2_chip_ident_i2c_client(struct i2c_client *c, struct v4l2_chip_ident *chip,
u32 ident, u32 revision)
{
if (!v4l2_chip_match_i2c_client(c, chip->match_type, chip->match_chip))
return 0;
if (chip->ident == V4L2_IDENT_NONE) {
chip->ident = ident;
chip->revision = revision;
}
else {
chip->ident = V4L2_IDENT_AMBIGUOUS;
chip->revision = 0;
}
return 0;
}
int v4l2_chip_match_host(u32 match_type, u32 match_chip)
{
switch (match_type) {
......@@ -1015,6 +1033,7 @@ EXPORT_SYMBOL(v4l2_ctrl_query_fill);
EXPORT_SYMBOL(v4l2_ctrl_query_fill_std);
EXPORT_SYMBOL(v4l2_chip_match_i2c_client);
EXPORT_SYMBOL(v4l2_chip_ident_i2c_client);
EXPORT_SYMBOL(v4l2_chip_match_host);
/*
......
......@@ -1532,6 +1532,16 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
break;
}
#endif
case VIDIOC_G_CHIP_IDENT:
{
struct v4l2_chip_ident *p=arg;
if (!vfd->vidioc_g_chip_ident)
break;
ret=vfd->vidioc_g_chip_ident(file, fh, p);
if (!ret)
dbgarg (cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision);
break;
}
} /* switch */
if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
......
......@@ -1398,6 +1398,14 @@ struct v4l2_register {
__u64 val;
};
/* VIDIOC_G_CHIP_IDENT */
struct v4l2_chip_ident {
__u32 match_type; /* Match type */
__u32 match_chip; /* Match this chip, meaning determined by match_type */
__u32 ident; /* chip identifier as specified in <media/v4l2-chip-ident.h> */
__u32 revision; /* chip revision, chip specific */
};
/*
* I O C T L C O D E S F O R V I D E O D E V I C E S
*
......@@ -1471,6 +1479,8 @@ struct v4l2_register {
/* Experimental, only implemented if CONFIG_VIDEO_ADV_DEBUG is defined */
#define VIDIOC_DBG_S_REGISTER _IOW ('V', 79, struct v4l2_register)
#define VIDIOC_DBG_G_REGISTER _IOWR ('V', 80, struct v4l2_register)
#define VIDIOC_G_CHIP_IDENT _IOWR ('V', 81, struct v4l2_chip_ident)
#endif
#ifdef __OLD_VIDIOC_
......
/*
v4l2 chip identifiers header
This header provides a list of chip identifiers that can be returned
through the VIDIOC_G_CHIP_IDENT ioctl.
Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef V4L2_CHIP_IDENT_H_
#define V4L2_CHIP_IDENT_H_
/* VIDIOC_G_CHIP_IDENT: identifies the actual chip installed on the board */
enum {
/* general idents: reserved range 0-49 */
V4L2_IDENT_NONE = 0, /* No chip matched */
V4L2_IDENT_AMBIGUOUS = 1, /* Match too general, multiple chips matched */
V4L2_IDENT_UNKNOWN = 2, /* Chip found, but cannot identify */
/* module saa7110: just ident= 100 */
V4L2_IDENT_SAA7110 = 100,
/* module saa7111: just ident= 101 */
V4L2_IDENT_SAA7111 = 101,
/* module saa7115: reserved range 102-149 */
V4L2_IDENT_SAA7113 = 103,
V4L2_IDENT_SAA7114 = 104,
V4L2_IDENT_SAA7115 = 105,
V4L2_IDENT_SAA7118 = 108,
/* module saa7127: reserved range 150-199 */
V4L2_IDENT_SAA7127 = 157,
V4L2_IDENT_SAA7129 = 159,
/* module cx25840: reserved range 200-249 */
V4L2_IDENT_CX25836 = 236,
V4L2_IDENT_CX25837 = 237,
V4L2_IDENT_CX25840 = 240,
V4L2_IDENT_CX25841 = 241,
V4L2_IDENT_CX25842 = 242,
V4L2_IDENT_CX25843 = 243,
/* OmniVision sensors - range 250-299 */
V4L2_IDENT_OV7670 = 250,
};
#endif
......@@ -98,6 +98,8 @@ u32 v4l2_ctrl_next(const u32 * const *ctrl_classes, u32 id);
struct i2c_client; /* forward reference */
int v4l2_chip_match_i2c_client(struct i2c_client *c, u32 id_type, u32 chip_id);
int v4l2_chip_ident_i2c_client(struct i2c_client *c, struct v4l2_chip_ident *chip,
u32 ident, u32 revision);
int v4l2_chip_match_host(u32 id_type, u32 chip_id);
/* ------------------------------------------------------------------------- */
......@@ -114,39 +116,6 @@ struct v4l2_decode_vbi_line {
u32 type; /* VBI service type (V4L2_SLICED_*). 0 if no service found */
};
/* VIDIOC_INT_G_CHIP_IDENT: identifies the actual chip installed on the board */
enum v4l2_chip_ident {
/* general idents: reserved range 0-49 */
V4L2_IDENT_UNKNOWN = 0,
/* module saa7110: just ident= 100 */
V4L2_IDENT_SAA7110 = 100,
/* module saa7111: just ident= 101 */
V4L2_IDENT_SAA7111 = 101,
/* module saa7115: reserved range 102-149 */
V4L2_IDENT_SAA7113 = 103,
V4L2_IDENT_SAA7114 = 104,
V4L2_IDENT_SAA7115 = 105,
V4L2_IDENT_SAA7118 = 108,
/* module saa7127: reserved range 150-199 */
V4L2_IDENT_SAA7127 = 157,
V4L2_IDENT_SAA7129 = 159,
/* module cx25840: reserved range 200-249 */
V4L2_IDENT_CX25836 = 236,
V4L2_IDENT_CX25837 = 237,
V4L2_IDENT_CX25840 = 240,
V4L2_IDENT_CX25841 = 241,
V4L2_IDENT_CX25842 = 242,
V4L2_IDENT_CX25843 = 243,
/* OmniVision sensors - range 250-299 */
V4L2_IDENT_OV7670 = 250,
};
/* audio ioctls */
/* v4l device was opened in Radio mode, to be replaced by VIDIOC_INT_S_TUNER_MODE */
......@@ -208,10 +177,6 @@ enum v4l2_chip_ident {
whether CC data from the first or second field should be obtained). */
#define VIDIOC_INT_G_VBI_DATA _IOWR('d', 106, struct v4l2_sliced_vbi_data)
/* Returns the chip identifier or V4L2_IDENT_UNKNOWN if no identification can
be made. */
#define VIDIOC_INT_G_CHIP_IDENT _IOR ('d', 107, enum v4l2_chip_ident)
/* Sets I2S speed in bps. This is used to provide a standard way to select I2S
clock used by driving digital audio streams at some board designs.
Usual values for the frequency are 1024000 and 2048000.
......
......@@ -317,6 +317,8 @@ struct video_device
int (*vidioc_s_register) (struct file *file, void *fh,
struct v4l2_register *reg);
#endif
int (*vidioc_g_chip_ident) (struct file *file, void *fh,
struct v4l2_chip_ident *chip);
#ifdef OBSOLETE_OWNER /* to be removed soon */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment