Commit 1b8dac15 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

V4L/DVB (10499): saa7146: convert saa7146 and mxb in particular to v4l2_subdev.

Modified mxb to load the i2c modules through v4l2_subdev. So no more probing.
Modified tea6415c and tea6420 to use the standard routing ops to do the
routing, rather than using private commands. Dropped the private commands
from tda9840 (they were never used except during initialization of the
module).

Added saa7146 support for VIDIOC_DBG_G_CHIP_IDENT.

Converted saa5246a and saa5249 to v4l2_subdev.
Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent d30e21dd
#include <media/saa7146_vv.h>
#include <media/v4l2-chip-ident.h>
static int max_memory = 32;
......@@ -209,6 +210,7 @@ static struct v4l2_queryctrl controls[] = {
.step = 1,
.default_value = 128,
.type = V4L2_CTRL_TYPE_INTEGER,
.flags = V4L2_CTRL_FLAG_SLIDER,
},{
.id = V4L2_CID_CONTRAST,
.name = "Contrast",
......@@ -217,6 +219,7 @@ static struct v4l2_queryctrl controls[] = {
.step = 1,
.default_value = 64,
.type = V4L2_CTRL_TYPE_INTEGER,
.flags = V4L2_CTRL_FLAG_SLIDER,
},{
.id = V4L2_CID_SATURATION,
.name = "Saturation",
......@@ -225,15 +228,16 @@ static struct v4l2_queryctrl controls[] = {
.step = 1,
.default_value = 64,
.type = V4L2_CTRL_TYPE_INTEGER,
.flags = V4L2_CTRL_FLAG_SLIDER,
},{
.id = V4L2_CID_VFLIP,
.name = "Vertical flip",
.name = "Vertical Flip",
.minimum = 0,
.maximum = 1,
.type = V4L2_CTRL_TYPE_BOOLEAN,
},{
.id = V4L2_CID_HFLIP,
.name = "Horizontal flip",
.name = "Horizontal Flip",
.minimum = 0,
.maximum = 1,
.type = V4L2_CTRL_TYPE_BOOLEAN,
......@@ -1112,6 +1116,22 @@ static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type ty
return err;
}
static int vidioc_g_chip_ident(struct file *file, void *__fh,
struct v4l2_dbg_chip_ident *chip)
{
struct saa7146_fh *fh = __fh;
struct saa7146_dev *dev = fh->dev;
chip->ident = V4L2_IDENT_NONE;
chip->revision = 0;
if (v4l2_chip_match_host(&chip->match)) {
chip->ident = V4L2_IDENT_SAA7146;
return 0;
}
return v4l2_device_call_until_err(&dev->v4l2_dev, 0,
core, g_chip_ident, chip);
}
#ifdef CONFIG_VIDEO_V4L1_COMPAT
static int vidiocgmbuf(struct file *file, void *__fh, struct video_mbuf *mbuf)
{
......@@ -1152,6 +1172,7 @@ const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
.vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay,
.vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay,
.vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_g_chip_ident = vidioc_g_chip_ident,
.vidioc_overlay = vidioc_overlay,
.vidioc_g_fbuf = vidioc_g_fbuf,
......
This diff is collapsed.
......@@ -46,10 +46,11 @@
#include <linux/smp_lock.h>
#include <linux/mutex.h>
#include <linux/videotext.h>
#include <linux/videodev.h>
#include <media/v4l2-common.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-i2c-drv-legacy.h>
#include <media/v4l2-i2c-drv.h>
MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
MODULE_DESCRIPTION("Philips SAA5246A, SAA5281 Teletext decoder driver");
......@@ -388,13 +389,19 @@ MODULE_LICENSE("GPL");
struct saa5246a_device
{
struct v4l2_subdev sd;
struct video_device *vdev;
u8 pgbuf[NUM_DAUS][VTX_VIRTUALSIZE];
int is_searching[NUM_DAUS];
struct i2c_client *client;
unsigned long in_use;
struct mutex lock;
};
static inline struct saa5246a_device *to_dev(struct v4l2_subdev *sd)
{
return container_of(sd, struct saa5246a_device, sd);
}
static struct video_device saa_template; /* Declared near bottom */
/*
......@@ -403,12 +410,13 @@ static struct video_device saa_template; /* Declared near bottom */
static int i2c_sendbuf(struct saa5246a_device *t, int reg, int count, u8 *data)
{
struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
char buf[64];
buf[0] = reg;
memcpy(buf+1, data, count);
if(i2c_master_send(t->client, buf, count+1)==count+1)
if (i2c_master_send(client, buf, count + 1) == count + 1)
return 0;
return -1;
}
......@@ -436,7 +444,9 @@ static int i2c_senddata(struct saa5246a_device *t, ...)
*/
static int i2c_getdata(struct saa5246a_device *t, int count, u8 *buf)
{
if(i2c_master_recv(t->client, buf, count)!=count)
struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
if (i2c_master_recv(client, buf, count) != count)
return -1;
return 0;
}
......@@ -961,9 +971,6 @@ static int saa5246a_open(struct file *file)
{
struct saa5246a_device *t = video_drvdata(file);
if (t->client == NULL)
return -ENODEV;
if (test_and_set_bit(0, &t->in_use))
return -EBUSY;
......@@ -1033,18 +1040,29 @@ static struct video_device saa_template =
.minor = -1,
};
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
static int saa5246a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA5246A, 0);
}
static const struct v4l2_subdev_core_ops saa5246a_core_ops = {
.g_chip_ident = saa5246a_g_chip_ident,
};
static const struct v4l2_subdev_ops saa5246a_ops = {
.core = &saa5246a_core_ops,
};
I2C_CLIENT_INSMOD;
static int saa5246a_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int pgbuf;
int err;
struct video_device *vd;
struct saa5246a_device *t;
struct v4l2_subdev *sd;
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
......@@ -1053,40 +1071,43 @@ static int saa5246a_probe(struct i2c_client *client,
t = kzalloc(sizeof(*t), GFP_KERNEL);
if (t == NULL)
return -ENOMEM;
sd = &t->sd;
v4l2_i2c_subdev_init(sd, client, &saa5246a_ops);
mutex_init(&t->lock);
/* Now create a video4linux device */
vd = video_device_alloc();
if (vd == NULL) {
t->vdev = video_device_alloc();
if (t->vdev == NULL) {
kfree(t);
return -ENOMEM;
}
i2c_set_clientdata(client, vd);
memcpy(vd, &saa_template, sizeof(*vd));
memcpy(t->vdev, &saa_template, sizeof(*t->vdev));
for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
memset(t->pgbuf[pgbuf], ' ', sizeof(t->pgbuf[0]));
t->is_searching[pgbuf] = false;
}
video_set_drvdata(vd, t);
video_set_drvdata(t->vdev, t);
/* Register it */
err = video_register_device(vd, VFL_TYPE_VTX, -1);
err = video_register_device(t->vdev, VFL_TYPE_VTX, -1);
if (err < 0) {
kfree(t);
video_device_release(vd);
video_device_release(t->vdev);
t->vdev = NULL;
return err;
}
t->client = client;
return 0;
}
static int saa5246a_remove(struct i2c_client *client)
{
struct video_device *vd = i2c_get_clientdata(client);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct saa5246a_device *t = to_dev(sd);
video_unregister_device(vd);
kfree(video_get_drvdata(vd));
video_unregister_device(t->vdev);
v4l2_device_unregister_subdev(sd);
kfree(t);
return 0;
}
......
......@@ -50,15 +50,17 @@
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/videotext.h>
#include <linux/videodev.h>
#include <media/v4l2-common.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-i2c-drv-legacy.h>
#include <media/v4l2-i2c-drv.h>
MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
MODULE_DESCRIPTION("Philips SAA5249 Teletext decoder driver");
MODULE_LICENSE("GPL");
#define VTX_VER_MAJ 1
#define VTX_VER_MIN 8
......@@ -95,17 +97,23 @@ typedef struct {
struct saa5249_device
{
struct v4l2_subdev sd;
struct video_device *vdev;
vdau_t vdau[NUM_DAUS]; /* Data for virtual DAUs (the 5249 only has one */
/* real DAU, so we have to simulate some more) */
int vtx_use_count;
int is_searching[NUM_DAUS];
int disp_mode;
int virtual_mode;
struct i2c_client *client;
unsigned long in_use;
struct mutex lock;
};
static inline struct saa5249_device *to_dev(struct v4l2_subdev *sd)
{
return container_of(sd, struct saa5249_device, sd);
}
#define CCTWR 34 /* IC write/read-address of vtx-chip */
#define CCTRD 35
......@@ -147,12 +155,13 @@ static void jdelay(unsigned long delay)
static int i2c_sendbuf(struct saa5249_device *t, int reg, int count, u8 *data)
{
struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
char buf[64];
buf[0] = reg;
memcpy(buf+1, data, count);
if (i2c_master_send(t->client, buf, count + 1) == count + 1)
if (i2c_master_send(client, buf, count + 1) == count + 1)
return 0;
return -1;
}
......@@ -180,7 +189,9 @@ static int i2c_senddata(struct saa5249_device *t, ...)
static int i2c_getdata(struct saa5249_device *t, int count, u8 *buf)
{
if(i2c_master_recv(t->client, buf, count)!=count)
struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
if (i2c_master_recv(client, buf, count) != count)
return -1;
return 0;
}
......@@ -497,9 +508,6 @@ static int saa5249_open(struct file *file)
struct saa5249_device *t = video_drvdata(file);
int pgbuf;
if (t->client == NULL)
return -ENODEV;
if (test_and_set_bit(0, &t->in_use))
return -EBUSY;
......@@ -553,18 +561,28 @@ static struct video_device saa_template =
.release = video_device_release,
};
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
static int saa5249_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
I2C_CLIENT_INSMOD;
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA5249, 0);
}
static const struct v4l2_subdev_core_ops saa5249_core_ops = {
.g_chip_ident = saa5249_g_chip_ident,
};
static const struct v4l2_subdev_ops saa5249_ops = {
.core = &saa5249_core_ops,
};
static int saa5249_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int pgbuf;
int err;
struct video_device *vd;
struct saa5249_device *t;
struct v4l2_subdev *sd;
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
......@@ -573,16 +591,17 @@ static int saa5249_probe(struct i2c_client *client,
t = kzalloc(sizeof(*t), GFP_KERNEL);
if (t == NULL)
return -ENOMEM;
sd = &t->sd;
v4l2_i2c_subdev_init(sd, client, &saa5249_ops);
mutex_init(&t->lock);
/* Now create a video4linux device */
vd = kmalloc(sizeof(struct video_device), GFP_KERNEL);
if (vd == NULL) {
t->vdev = video_device_alloc();
if (t->vdev == NULL) {
kfree(client);
return -ENOMEM;
}
i2c_set_clientdata(client, vd);
memcpy(vd, &saa_template, sizeof(*vd));
memcpy(t->vdev, &saa_template, sizeof(*t->vdev));
for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
......@@ -593,26 +612,27 @@ static int saa5249_probe(struct i2c_client *client,
t->vdau[pgbuf].stopped = true;
t->is_searching[pgbuf] = false;
}
video_set_drvdata(vd, t);
video_set_drvdata(t->vdev, t);
/* Register it */
err = video_register_device(vd, VFL_TYPE_VTX, -1);
err = video_register_device(t->vdev, VFL_TYPE_VTX, -1);
if (err < 0) {
kfree(t);
kfree(vd);
video_device_release(t->vdev);
t->vdev = NULL;
return err;
}
t->client = client;
return 0;
}
static int saa5249_remove(struct i2c_client *client)
{
struct video_device *vd = i2c_get_clientdata(client);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct saa5249_device *t = to_dev(sd);
video_unregister_device(vd);
kfree(video_get_drvdata(vd));
kfree(vd);
video_unregister_device(t->vdev);
v4l2_device_unregister_subdev(sd);
kfree(t);
return 0;
}
......
......@@ -30,8 +30,8 @@
#include <linux/ioctl.h>
#include <linux/i2c.h>
#include <media/v4l2-device.h>
#include <media/v4l2-i2c-drv-legacy.h>
#include "tda9840.h"
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-i2c-drv.h>
MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
MODULE_DESCRIPTION("tda9840 driver");
......@@ -56,11 +56,6 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
#define TDA9840_SET_BOTH_R 0x16
#define TDA9840_SET_EXTERNAL 0x7a
/* addresses to scan, found only at 0x42 (7-Bit) */
static unsigned short normal_i2c[] = { I2C_ADDR_TDA9840, I2C_CLIENT_END };
/* magic definition of all other variables and things */
I2C_CLIENT_INSMOD;
static void tda9840_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
......@@ -137,60 +132,17 @@ static int tda9840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t)
return 0;
}
static long tda9840_ioctl(struct v4l2_subdev *sd, unsigned cmd, void *arg)
static int tda9840_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
{
int byte;
switch (cmd) {
case TDA9840_LEVEL_ADJUST:
byte = *(int *)arg;
v4l2_dbg(1, debug, sd, "TDA9840_LEVEL_ADJUST: %d\n", byte);
/* check for correct range */
if (byte > 25 || byte < -20)
return -EINVAL;
/* calculate actual value to set, see specs, page 18 */
byte /= 5;
if (0 < byte)
byte += 0x8;
else
byte = -byte;
tda9840_write(sd, LEVEL_ADJUST, byte);
break;
case TDA9840_STEREO_ADJUST:
byte = *(int *)arg;
v4l2_dbg(1, debug, sd, "TDA9840_STEREO_ADJUST: %d\n", byte);
/* check for correct range */
if (byte > 25 || byte < -24)
return -EINVAL;
/* calculate actual value to set */
byte /= 5;
if (0 < byte)
byte += 0x20;
else
byte = -byte;
tda9840_write(sd, STEREO_ADJUST, byte);
break;
default:
return -ENOIOCTLCMD;
}
return 0;
}
struct i2c_client *client = v4l2_get_subdevdata(sd);
static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg)
{
return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TDA9840, 0);
}
/* ----------------------------------------------------------------------- */
static const struct v4l2_subdev_core_ops tda9840_core_ops = {
.ioctl = tda9840_ioctl,
.g_chip_ident = tda9840_g_chip_ident,
};
static const struct v4l2_subdev_tuner_ops tda9840_tuner_ops = {
......@@ -209,8 +161,6 @@ static int tda9840_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct v4l2_subdev *sd;
int result;
int byte;
/* let's see whether this adapter can support what we need */
if (!i2c_check_functionality(client->adapter,
......@@ -227,15 +177,9 @@ static int tda9840_probe(struct i2c_client *client,
v4l2_i2c_subdev_init(sd, client, &tda9840_ops);
/* set initial values for level & stereo - adjustment, mode */
byte = 0;
result = tda9840_ioctl(sd, TDA9840_LEVEL_ADJUST, &byte);
result |= tda9840_ioctl(sd, TDA9840_STEREO_ADJUST, &byte);
tda9840_write(sd, LEVEL_ADJUST, 0);
tda9840_write(sd, STEREO_ADJUST, 0);
tda9840_write(sd, SWITCH, TDA9840_SET_STEREO);
if (result) {
v4l2_dbg(1, debug, sd, "could not initialize tda9840\n");
kfree(sd);
return -ENODEV;
}
return 0;
}
......@@ -248,12 +192,7 @@ static int tda9840_remove(struct i2c_client *client)
return 0;
}
static int tda9840_legacy_probe(struct i2c_adapter *adapter)
{
/* Let's see whether this is a known adapter we can attach to.
Prevents conflicts with tvaudio.c. */
return adapter->id == I2C_HW_SAA7146;
}
static const struct i2c_device_id tda9840_id[] = {
{ "tda9840", 0 },
{ }
......@@ -262,9 +201,7 @@ MODULE_DEVICE_TABLE(i2c, tda9840_id);
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "tda9840",
.command = tda9840_command,
.probe = tda9840_probe,
.remove = tda9840_remove,
.legacy_probe = tda9840_legacy_probe,
.id_table = tda9840_id,
};
#ifndef __INCLUDED_TDA9840__
#define __INCLUDED_TDA9840__
#define I2C_ADDR_TDA9840 0x42
/* values may range between +2.5 and -2.0;
the value has to be multiplied with 10 */
#define TDA9840_LEVEL_ADJUST _IOW('v',3,int)
/* values may range between +2.5 and -2.4;
the value has to be multiplied with 10 */
#define TDA9840_STEREO_ADJUST _IOW('v',4,int)
#endif
......@@ -32,7 +32,8 @@
#include <linux/ioctl.h>
#include <linux/i2c.h>
#include <media/v4l2-device.h>
#include <media/v4l2-i2c-drv-legacy.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-i2c-drv.h>
#include "tea6415c.h"
MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
......@@ -44,25 +45,22 @@ module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
/* addresses to scan, found only at 0x03 and/or 0x43 (7-bit) */
static unsigned short normal_i2c[] = { I2C_TEA6415C_1, I2C_TEA6415C_2, I2C_CLIENT_END };
/* magic definition of all other variables and things */
I2C_CLIENT_INSMOD;
/* makes a connection between the input-pin 'i' and the output-pin 'o'
for the tea6415c-client 'client' */
static int switch_matrix(struct i2c_client *client, int i, int o)
/* makes a connection between the input-pin 'i' and the output-pin 'o' */
static int tea6415c_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
u8 byte = 0;
u32 i = route->input;
u32 o = route->output;
int ret;
v4l_dbg(1, debug, client, "i=%d, o=%d\n", i, o);
v4l2_dbg(1, debug, sd, "i=%d, o=%d\n", i, o);
/* check if the pins are valid */
if (0 == ((1 == i || 3 == i || 5 == i || 6 == i || 8 == i || 10 == i || 20 == i || 11 == i)
&& (18 == o || 17 == o || 16 == o || 15 == o || 14 == o || 13 == o)))
return -1;
return -EINVAL;
/* to understand this, have a look at the tea6415c-specs (p.5) */
switch (o) {
......@@ -115,37 +113,33 @@ static int switch_matrix(struct i2c_client *client, int i, int o)
ret = i2c_smbus_write_byte(client, byte);
if (ret) {
v4l_dbg(1, debug, client,
v4l2_dbg(1, debug, sd,
"i2c_smbus_write_byte() failed, ret:%d\n", ret);
return -EIO;
}
return ret;
}
static long tea6415c_ioctl(struct v4l2_subdev *sd, unsigned cmd, void *arg)
static int tea6415c_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
{
if (cmd == TEA6415C_SWITCH) {
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct tea6415c_multiplex *v = (struct tea6415c_multiplex *)arg;
return switch_matrix(client, v->in, v->out);
}
return -ENOIOCTLCMD;
}
static int tea6415c_command(struct i2c_client *client, unsigned cmd, void *arg)
{
return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TEA6415C, 0);
}
/* ----------------------------------------------------------------------- */
static const struct v4l2_subdev_core_ops tea6415c_core_ops = {
.ioctl = tea6415c_ioctl,
.g_chip_ident = tea6415c_g_chip_ident,
};
static const struct v4l2_subdev_video_ops tea6415c_video_ops = {
.s_routing = tea6415c_s_routing,
};
static const struct v4l2_subdev_ops tea6415c_ops = {
.core = &tea6415c_core_ops,
.video = &tea6415c_video_ops,
};
/* this function is called by i2c_probe */
......@@ -176,12 +170,6 @@ static int tea6415c_remove(struct i2c_client *client)
return 0;
}
static int tea6415c_legacy_probe(struct i2c_adapter *adapter)
{
/* Let's see whether this is a known adapter we can attach to.
Prevents conflicts with tvaudio.c. */
return adapter->id == I2C_HW_SAA7146;
}
static const struct i2c_device_id tea6415c_id[] = {
{ "tea6415c", 0 },
......@@ -191,9 +179,7 @@ MODULE_DEVICE_TABLE(i2c, tea6415c_id);
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "tea6415c",
.command = tea6415c_command,
.probe = tea6415c_probe,
.remove = tea6415c_remove,
.legacy_probe = tea6415c_legacy_probe,
.id_table = tea6415c_id,
};
#ifndef __INCLUDED_TEA6415C__
#define __INCLUDED_TEA6415C__
/* possible i2c-addresses */
#define I2C_TEA6415C_1 0x03
#define I2C_TEA6415C_2 0x43
/* the tea6415c's design is quite brain-dead. although there are
8 inputs and 6 outputs, these aren't enumerated in any way. because
I don't want to say "connect input pin 20 to output pin 17", I define
......@@ -28,12 +24,4 @@
#define TEA6415C_INPUT7 1
#define TEA6415C_INPUT8 11
struct tea6415c_multiplex
{
int in; /* input-pin */
int out; /* output-pin */
};
#define TEA6415C_SWITCH _IOW('v',1,struct tea6415c_multiplex)
#endif
......@@ -32,7 +32,8 @@
#include <linux/ioctl.h>
#include <linux/i2c.h>
#include <media/v4l2-device.h>
#include <media/v4l2-i2c-drv-legacy.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-i2c-drv.h>
#include "tea6420.h"
MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
......@@ -44,24 +45,23 @@ module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
/* addresses to scan, found only at 0x4c and/or 0x4d (7-Bit) */
static unsigned short normal_i2c[] = { I2C_ADDR_TEA6420_1, I2C_ADDR_TEA6420_2, I2C_CLIENT_END };
/* magic definition of all other variables and things */
I2C_CLIENT_INSMOD;
/* make a connection between the input 'i' and the output 'o'
with gain 'g' for the tea6420-client 'client' (note: i = 6 means 'mute') */
static int tea6420_switch(struct i2c_client *client, int i, int o, int g)
with gain 'g' (note: i = 6 means 'mute') */
static int tea6420_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
int i = route->input;
int o = route->output & 0xf;
int g = (route->output >> 4) & 0xf;
u8 byte;
int ret;
v4l_dbg(1, debug, client, "i=%d, o=%d, g=%d\n", i, o, g);
v4l2_dbg(1, debug, sd, "i=%d, o=%d, g=%d\n", i, o, g);
/* check if the parameters are valid */
if (i < 1 || i > 6 || o < 1 || o > 4 || g < 0 || g > 6 || g % 2 != 0)
return -1;
return -EINVAL;
byte = ((o - 1) << 5);
byte |= (i - 1);
......@@ -83,37 +83,33 @@ static int tea6420_switch(struct i2c_client *client, int i, int o, int g)
ret = i2c_smbus_write_byte(client, byte);
if (ret) {
v4l_dbg(1, debug, client,
v4l2_dbg(1, debug, sd,
"i2c_smbus_write_byte() failed, ret:%d\n", ret);
return -EIO;
}
return 0;
}
static long tea6420_ioctl(struct v4l2_subdev *sd, unsigned cmd, void *arg)
static int tea6420_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
{
if (cmd == TEA6420_SWITCH) {
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct tea6420_multiplex *a = (struct tea6420_multiplex *)arg;
return tea6420_switch(client, a->in, a->out, a->gain);
}
return -ENOIOCTLCMD;
}
static int tea6420_command(struct i2c_client *client, unsigned cmd, void *arg)
{
return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TEA6420, 0);
}
/* ----------------------------------------------------------------------- */
static const struct v4l2_subdev_core_ops tea6420_core_ops = {
.ioctl = tea6420_ioctl,
.g_chip_ident = tea6420_g_chip_ident,
};
static const struct v4l2_subdev_audio_ops tea6420_audio_ops = {
.s_routing = tea6420_s_routing,
};
static const struct v4l2_subdev_ops tea6420_ops = {
.core = &tea6420_core_ops,
.audio = &tea6420_audio_ops,
};
/* this function is called by i2c_probe */
......@@ -130,20 +126,24 @@ static int tea6420_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
if (sd == NULL)
return -ENOMEM;
v4l2_i2c_subdev_init(sd, client, &tea6420_ops);
/* set initial values: set "mute"-input to all outputs at gain 0 */
err = 0;
for (i = 1; i < 5; i++) {
err += tea6420_switch(client, 6, i, 0);
struct v4l2_routing route;
route.input = 6;
route.output = i;
err += tea6420_s_routing(sd, &route);
}
if (err) {
v4l_dbg(1, debug, client, "could not initialize tea6420\n");
return -ENODEV;
}
sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
if (sd == NULL)
return -ENOMEM;
v4l2_i2c_subdev_init(sd, client, &tea6420_ops);
return 0;
}
......@@ -156,12 +156,6 @@ static int tea6420_remove(struct i2c_client *client)
return 0;
}
static int tea6420_legacy_probe(struct i2c_adapter *adapter)
{
/* Let's see whether this is a known adapter we can attach to.
Prevents conflicts with tvaudio.c. */
return adapter->id == I2C_HW_SAA7146;
}
static const struct i2c_device_id tea6420_id[] = {
{ "tea6420", 0 },
......@@ -171,9 +165,7 @@ MODULE_DEVICE_TABLE(i2c, tea6420_id);
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "tea6420",
.command = tea6420_command,
.probe = tea6420_probe,
.remove = tea6420_remove,
.legacy_probe = tea6420_legacy_probe,
.id_table = tea6420_id,
};
#ifndef __INCLUDED_TEA6420__
#define __INCLUDED_TEA6420__
/* possible addresses */
#define I2C_ADDR_TEA6420_1 0x4c
#define I2C_ADDR_TEA6420_2 0x4d
/* input pins */
#define TEA6420_OUTPUT1 1
#define TEA6420_OUTPUT2 2
#define TEA6420_OUTPUT3 3
#define TEA6420_OUTPUT4 4
struct tea6420_multiplex
{
int in; /* input of audio switch */
int out; /* output of audio switch */
int gain; /* gain of connection */
};
/* output pins */
#define TEA6420_INPUT1 1
#define TEA6420_INPUT2 2
#define TEA6420_INPUT3 3
#define TEA6420_INPUT4 4
#define TEA6420_INPUT5 5
#define TEA6420_INPUT6 6
#define TEA6420_SWITCH _IOW('v',1,struct tea6420_multiplex)
/* gain on the output pins, ORed with the output pin */
#define TEA6420_GAIN0 0x00
#define TEA6420_GAIN2 0x20
#define TEA6420_GAIN4 0x40
#define TEA6420_GAIN6 0x60
#endif
......@@ -63,6 +63,9 @@ enum {
V4L2_IDENT_OV7720 = 251,
V4L2_IDENT_OV7725 = 252,
/* module saa7146: reserved range 300-309 */
V4L2_IDENT_SAA7146 = 300,
/* Conexant MPEG encoder/decoders: reserved range 410-420 */
V4L2_IDENT_CX23415 = 415,
V4L2_IDENT_CX23416 = 416,
......@@ -74,9 +77,21 @@ enum {
/* module tvp5150 */
V4L2_IDENT_TVP5150 = 5150,
/* module saa5246a: just ident 5246 */
V4L2_IDENT_SAA5246A = 5246,
/* module saa5249: just ident 5249 */
V4L2_IDENT_SAA5249 = 5249,
/* module cs5345: just ident 5345 */
V4L2_IDENT_CS5345 = 5345,
/* module tea6415c: just ident 6415 */
V4L2_IDENT_TEA6415C = 6415,
/* module tea6420: just ident 6420 */
V4L2_IDENT_TEA6420 = 6420,
/* module saa6752hs: reserved range 6750-6759 */
V4L2_IDENT_SAA6752HS = 6752,
V4L2_IDENT_SAA6752HS_AC3 = 6753,
......@@ -87,6 +102,9 @@ enum {
/* module wm8775: just ident 8775 */
V4L2_IDENT_WM8775 = 8775,
/* module tda9840: just ident 9840 */
V4L2_IDENT_TDA9840 = 9840,
/* module tw9910: just ident 9910 */
V4L2_IDENT_TW9910 = 9910,
......
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