Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 973909e8 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (9965): tda9840: convert to v4l2_subdev.

parent d531305a
Loading
Loading
Loading
Loading
+116 −72
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/i2c.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
#include <media/v4l2-i2c-drv-legacy.h>
#include "tda9840.h"

@@ -62,20 +62,17 @@ 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 i2c_client *client, u8 reg, u8 val)
static void tda9840_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);

	if (i2c_smbus_write_byte_data(client, reg, val))
		v4l_dbg(1, debug, client, "error writing %02x to %02x\n",
		v4l2_dbg(1, debug, sd, "error writing %02x to %02x\n",
				val, reg);
}

static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg)
static int tda9840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t)
{
	int byte = *(int *)arg;

	switch (cmd) {
	case VIDIOC_S_TUNER: {
		struct v4l2_tuner *t = arg;
	int byte;

	if (t->index)
@@ -98,29 +95,30 @@ static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg)
		byte = TDA9840_SET_MONO;
		break;
	}
		v4l_dbg(1, debug, client, "TDA9840_SWITCH: 0x%02x\n", byte);
		tda9840_write(client, SWITCH, byte);
		break;
	v4l2_dbg(1, debug, sd, "TDA9840_SWITCH: 0x%02x\n", byte);
	tda9840_write(sd, SWITCH, byte);
	return 0;
}

	case VIDIOC_G_TUNER: {
		struct v4l2_tuner *t = arg;
static int tda9840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	u8 byte;

	t->rxsubchans = V4L2_TUNER_SUB_MONO;
	if (1 != i2c_master_recv(client, &byte, 1)) {
			v4l_dbg(1, debug, client,
		v4l2_dbg(1, debug, sd,
			"i2c_master_recv() failed\n");
		return -EIO;
	}

	if (byte & 0x80) {
			v4l_dbg(1, debug, client,
		v4l2_dbg(1, debug, sd,
			"TDA9840_DETECT: register contents invalid\n");
		return -EINVAL;
	}

		v4l_dbg(1, debug, client, "TDA9840_DETECT: byte: 0x%02x\n", byte);
	v4l2_dbg(1, debug, sd, "TDA9840_DETECT: byte: 0x%02x\n", byte);

	switch (byte & 0x60) {
	case 0x00:
@@ -136,11 +134,17 @@ static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg)
		t->rxsubchans = V4L2_TUNER_MODE_MONO;
		break;
	}
		break;
	return 0;
}

static int tda9840_ioctl(struct v4l2_subdev *sd, unsigned cmd, void *arg)
{
	int byte;

	switch (cmd) {
	case TDA9840_LEVEL_ADJUST:
		v4l_dbg(1, debug, client, "TDA9840_LEVEL_ADJUST: %d\n", byte);
		byte = *(int *)arg;
		v4l2_dbg(1, debug, sd, "TDA9840_LEVEL_ADJUST: %d\n", byte);

		/* check for correct range */
		if (byte > 25 || byte < -20)
@@ -152,11 +156,12 @@ static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg)
			byte += 0x8;
		else
			byte = -byte;
		tda9840_write(client, LEVEL_ADJUST, byte);
		tda9840_write(sd, LEVEL_ADJUST, byte);
		break;

	case TDA9840_STEREO_ADJUST:
		v4l_dbg(1, debug, client, "TDA9840_STEREO_ADJUST: %d\n", byte);
		byte = *(int *)arg;
		v4l2_dbg(1, debug, sd, "TDA9840_STEREO_ADJUST: %d\n", byte);

		/* check for correct range */
		if (byte > 25 || byte < -24)
@@ -169,18 +174,41 @@ static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg)
		else
			byte = -byte;

		tda9840_write(client, STEREO_ADJUST, byte);
		tda9840_write(sd, STEREO_ADJUST, byte);
		break;
	default:
		return -ENOIOCTLCMD;
	}

	return 0;
}

static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg)
{
	return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
}

/* ----------------------------------------------------------------------- */

static const struct v4l2_subdev_core_ops tda9840_core_ops = {
	.ioctl = tda9840_ioctl,
};

static const struct v4l2_subdev_tuner_ops tda9840_tuner_ops = {
	.s_tuner = tda9840_s_tuner,
	.g_tuner = tda9840_g_tuner,
};

static const struct v4l2_subdev_ops tda9840_ops = {
	.core = &tda9840_core_ops,
	.tuner = &tda9840_tuner_ops,
};

/* ----------------------------------------------------------------------- */

static int tda9840_probe(struct i2c_client *client,
			  const struct i2c_device_id *id)
{
	struct v4l2_subdev *sd;
	int result;
	int byte;

@@ -188,23 +216,38 @@ static int tda9840_probe(struct i2c_client *client,
	if (!i2c_check_functionality(client->adapter,
			I2C_FUNC_SMBUS_READ_BYTE_DATA |
			I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
		return 0;
		return -EIO;

	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, &tda9840_ops);

	/* set initial values for level & stereo - adjustment, mode */
	byte = 0;
	result = tda9840_command(client, TDA9840_LEVEL_ADJUST, &byte);
	result += tda9840_command(client, TDA9840_STEREO_ADJUST, &byte);
	tda9840_write(client, SWITCH, TDA9840_SET_STEREO);
	result = tda9840_ioctl(sd, TDA9840_LEVEL_ADJUST, &byte);
	result |= tda9840_ioctl(sd, TDA9840_STEREO_ADJUST, &byte);
	tda9840_write(sd, SWITCH, TDA9840_SET_STEREO);
	if (result) {
		v4l_dbg(1, debug, client, "could not initialize tda9840\n");
		v4l2_dbg(1, debug, sd, "could not initialize tda9840\n");
		kfree(sd);
		return -ENODEV;
	}
	return 0;
}

static int tda9840_remove(struct i2c_client *client)
{
	struct v4l2_subdev *sd = i2c_get_clientdata(client);

	v4l2_device_unregister_subdev(sd);
	kfree(sd);
	return 0;
}

static int tda9840_legacy_probe(struct i2c_adapter *adapter)
{
	/* Let's see whether this is a known adapter we can attach to.
@@ -222,6 +265,7 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
	.driverid = I2C_DRIVERID_TDA9840,
	.command = tda9840_command,
	.probe = tda9840_probe,
	.remove = tda9840_remove,
	.legacy_probe = tda9840_legacy_probe,
	.id_table = tda9840_id,
};