/*
    stv0056af.c		A kernel 2.6 driver for SGS-Thompson STV0056AF
			Satellite Sound and Video Processor 

    Version: $Id: stv0056af.c,v 1.7 2004/11/07 12:09:51 ttittmann Exp $
			
    Copyright (C) 2003,2004 Torsten Tittmann <Torsten.Tittmann@gmx.de>

    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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/*
    Derived from
   
    stv0056af.c		SGS-Thomson STV0056AF I2C driver
 
    Copyright (C) 2000,2001 Rolf Siebrecht <rolf.siebrecht@t-online.de>
*/

#include <asm/delay.h>
#include <asm/ioctl.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>

#include "stv0056af.h"

static int debug;		// module load parameter
static int video_gain;
static int decoder_output;
module_param(debug, int, 0444);
MODULE_PARM_DESC(debug, "debug level (default: 0)");
module_param(video_gain, int, 0444);
MODULE_PARM_DESC(video_gain, "gain = n * 0.202 dB (default: 0)");
module_param(decoder_output, int, 0444);
MODULE_PARM_DESC(decoder_output, "output mode of Mini DIN jack (default: 0)");

#define dprintk(level,args...) \
	do { if ((debug & level)) { printk("%s: %s(): ",__stringify(KBUILD_MODNAME), __FUNCTION__); printk(args); } } while (0)

/* I2C addresses to scan */
static unsigned short int normal_i2c[] =
    { I2C_STV0056AF_1, I2C_STV0056AF_2, I2C_CLIENT_END };
static unsigned short int normal_i2c_range[] = { I2C_CLIENT_END };

/* magic definition of all other variables and things */
I2C_CLIENT_INSMOD;

/* unique ID allocation */
static int stv0056af_id = 0;

static struct i2c_driver stv_driver;

/* The STV0056AF doesn't feature a single register read via I2C. Only	*/
/* a block read of its read-able registers 6..10 is possible. But this	*/
/* is NOT an SMBUS block read because the "command" byte (number of	*/
/* first register) is omitted. To make things worse the STV0056AF	*/
/* transmits registers 6..10 in a 8-9-10-7-6 sequence.			*/
/* So, every time we need a certain register we use 'i2c_master_recv'	*/
/* to read the whole block into the array 'stv_readregs'. The macro	*/
/* GET_STV_REG gets that very register from the array. Only numbers in	*/
/* the range 6..10 are allowed as GET_STV_REG argument.			*/
unsigned char stv_readregs[5];
#define GET_STV_REG( reg )	stv_readregs[(reg>7) ? (reg-8) : (10-reg)]

/* STV0056AF registers and bit masks */
#define STV_REG0_VOLUME	0x1f
#define STV_REG1_GAIN	0x3f
#define STV_REG2_B7	0x80
#define STV_REG2_B6	0x40
#define STV_REG234_OSEL	0x07	/* output source select */
#define STV_REG6_SW1	0x20
#define STV_REG6_SW2	0x08
#define	STV_REG6_SW3	0x10
#define STV_REG6_SW4	0x04
#define STV_REG6_IODIR	0x02	/* direction of IO pin; 1 = output */
#define	STV_REG6_IO	0x01	/* state of IO pin */
#define STV_REG6_B7B6	0xc0
#define STV_REG8_LSUB	0x01
#define	STV_REG8_RSUB	0x10

#define STV_SCART1	0
#define STV_SCART2	1
#define STV_DECODER	2

static int stv0056af_set_volume(struct i2c_client *client, unsigned char volume)
{				/* select volume */
	struct stv0056af *decoder = i2c_get_clientdata(client);
	unsigned char stv_register_0;
	int ret;

	dprintk(2, "vol=0x%02x.\n", volume);

	stv_register_0 = decoder->writeregs[0] & !STV_REG0_VOLUME;	/* read and erase old volume */
	stv_register_0 |= volume & STV_REG0_VOLUME;	/* set new volume */

	if (0 !=
	    (ret = i2c_smbus_write_byte_data(client, 0x00, stv_register_0))) {
		dprintk(1, "i2c_smbus_write_byte_data() failed.\n");
		return -EIO;
	}

	decoder->writeregs[0] = stv_register_0;

	return 0;
}

static int stv0056af_set_gain(struct i2c_client *client, unsigned char gain)
{				/* select video gain */
	struct stv0056af *decoder = i2c_get_clientdata(client);
	unsigned char stv_register_1;
	int ret;

	dprintk(2, "gain=0x%02x.\n", gain);

	stv_register_1 = decoder->writeregs[1] & !STV_REG1_GAIN;	/* read and erase old gain */
	stv_register_1 |= gain & STV_REG1_GAIN;	/* set new gain */

	if (0 !=
	    (ret = i2c_smbus_write_byte_data(client, 0x01, stv_register_1))) {
		dprintk(1, "i2c_smbus_write_byte_data() failed.\n");
		return -EIO;
	}

	decoder->writeregs[1] = stv_register_1;

	return 0;
}

static int stv0056af_select_output(struct i2c_client *client, int output,
				   int source)
{
	struct stv0056af *decoder = i2c_get_clientdata(client);
	unsigned char reg_nr, stv_register;
	int ret;

	dprintk(2, "out=%d; src=%d\n", output, source);

	switch (output) {
	case STV_SCART1:
		reg_nr = 0x02;
		break;
	case STV_SCART2:
		reg_nr = 0x03;
		break;
	case STV_DECODER:
		reg_nr = 0x04;
		break;
	default:
		dprintk(1, "Wrong output channel.\n");
		return -EINVAL;
	}
	stv_register = decoder->writeregs[reg_nr] & !STV_REG234_OSEL;
	stv_register |= source & STV_REG234_OSEL;

	if (0 !=
	    (ret = i2c_smbus_write_byte_data(client, reg_nr, stv_register))) {
		dprintk(1, "i2c_smbus_write_byte_data() failed.\n");
		return -EIO;
	}

	decoder->writeregs[reg_nr] = stv_register;

	return 0;
}

/* !! Untested !! */
/* Not used & not needed by MediaFocusII */
static int stv0056af_set_carrier(struct i2c_client *client, unsigned int freq1,
				 unsigned int freq2)
{				/* select frequencies */
	struct stv0056af *decoder = i2c_get_clientdata(client);
	int ret = 0, watchdog1, watchdog2, leftsub = 0, maxcount;
	unsigned char org_vol, stv_register_2, stv_register_6;

	dprintk(2, "f1=%d; f2=%d.\n", freq1, freq2);

	org_vol = decoder->writeregs[0] & STV_REG0_VOLUME;	/* original volume */
	ret |= stv0056af_set_volume(client, 0);	/* mute audio */

	ret |=
	    (i2c_master_recv(client, stv_readregs, sizeof(stv_readregs)) !=
	     sizeof(stv_readregs));
	stv_register_6 = GET_STV_REG(6) & !(STV_REG6_SW1 | STV_REG6_SW2 | STV_REG6_SW3 | STV_REG6_SW4);	/* clear old bits */
	stv_register_6 |= STV_REG6_SW4;	/* SW3(L) to Bias, SW4(L) closed */
	ret |= i2c_smbus_write_byte_data(client, 0x06, stv_register_6);	/* SW1(R) to Bias, SW2(R) open */
	stv_register_6 &= !STV_REG6_B7B6;	/* clear old bits */
	stv_register_6 |= ((freq1 << 6) & STV_REG6_B7B6);	/* set new freq1bits */
	ret |= i2c_smbus_write_byte_data(client, 0x07, freq1 >> 2);	/* set synth to left chan subcarrier */
	ret |= i2c_smbus_write_byte_data(client, 0x06, stv_register_6);
	maxcount = 200;
	do {
		udelay(10000);	/* okay ??? */
		ret |=
		    (i2c_master_recv(client, stv_readregs, sizeof(stv_readregs))
		     != sizeof(stv_readregs));
		watchdog1 =
		    ((int)GET_STV_REG(9) << 2) | ((GET_STV_REG(8) >> 2) & 0x03);
		maxcount--;
	} while ((abs(watchdog1 - freq1) > 1) && (maxcount != 0));	/* loop until |watchdog1 - freq1| <= 10 kHz */
	if (maxcount == 0) {
		dprintk(1, "tracking of left audio channel synth failed!\n");
		return -1;
	}
	stv_register_6 &= !STV_REG6_SW4;
	stv_register_6 |= STV_REG6_SW3;
	ret |= i2c_smbus_write_byte_data(client, 0x06, stv_register_6);	/* SW3(L) to FM sig, SW4(L) opened */
	/* FIXME!! Delay needed ??? */
	ret |=
	    (i2c_master_recv(client, stv_readregs, sizeof(stv_readregs)) !=
	     sizeof(stv_readregs));
	if (GET_STV_REG(8) & STV_REG8_LSUB) {	/* Left Subcarrier present? */
		leftsub = 1;	/* yes: Unmute Audio to Left Mono */
		stv_register_2 =
		    decoder->writeregs[2] & !(STV_REG2_B7 | STV_REG2_B6);
		ret |= i2c_smbus_write_byte_data(client, 0x02, stv_register_2);
		decoder->writeregs[2] = stv_register_2;
		ret |= stv0056af_set_volume(client, org_vol);
	}

	stv_register_6 |= STV_REG6_SW2;
	ret |= i2c_smbus_write_byte_data(client, 0x06, stv_register_6);	/* SW2(R) closed */
	stv_register_6 &= !STV_REG6_B7B6;
	stv_register_6 |= (freq2 << 6) & STV_REG6_B7B6;
	ret |= i2c_smbus_write_byte_data(client, 0x07, freq2 >> 2);	/* set synth to right chan subcarrier */
	ret |= i2c_smbus_write_byte_data(client, 0x06, stv_register_6);
	maxcount = 200;
	do {
		udelay(10000);
		ret |=
		    (i2c_master_recv(client, stv_readregs, sizeof(stv_readregs))
		     != sizeof(stv_readregs));
		watchdog2 =
		    (GET_STV_REG(10) << 2) | ((GET_STV_REG(8) >> 6) & 0x03);
		maxcount--;
	} while ((abs(watchdog2 - freq2) > 1) && (maxcount != 0));	/* loop until |watchdog2 - freq2| <= 10 kHz */
	if (maxcount == 0) {
		dprintk(1, "tracking of right audio channel synth failed!\n");
		return -1;
	}
	stv_register_6 &= !STV_REG6_SW2;
	stv_register_6 |= STV_REG6_SW1;
	ret |= i2c_smbus_write_byte_data(client, 0x06, stv_register_6);	/* SW1(R) to FM sig, SW2(R) opened */

	ret |=
	    (i2c_master_recv(client, stv_readregs, sizeof(stv_readregs)) !=
	     sizeof(stv_readregs));
	if (GET_STV_REG(8) & STV_REG8_RSUB) {	/* Right Subcarrier present? */
		if (leftsub) {	/* Was Left Subcarrier present? */
			stv_register_2 = decoder->writeregs[2] | (STV_REG2_B7 | STV_REG2_B6);	/* Unmute Audio to Stereo */
			ret |=
			    i2c_smbus_write_byte_data(client, 0x02,
						      stv_register_2);
			decoder->writeregs[2] = stv_register_2;	/* original volume already set */
		} else {
			stv_register_2 = decoder->writeregs[2] & !STV_REG2_B6;
			stv_register_2 |= STV_REG2_B7;	/* Unmute Audio to Right Mono */
			ret |=
			    i2c_smbus_write_byte_data(client, 0x02,
						      stv_register_2);
			decoder->writeregs[2] = stv_register_2;
			ret |= stv0056af_set_volume(client, org_vol);
		}
	}

	if (ret != 0) {
		dprintk(1, "client failed.\n");
		return -EIO;
	}

	return 0;
}

static int stv0056af_chip_init(struct i2c_client *client)
{				/* initialize the stv0056af */
	struct stv0056af *decoder = i2c_get_clientdata(client);
	int i, ret = 0;
	const unsigned char init[][2] = {
		/* addr value */
		{0x00, 0x80},	/* 5 register read cycle, no ANRS, audio i/p from PLL, muted audio      */
		{0x01, 0x00},	/* video deemp = VIDEEM1, video non-inverted, video gain = 0dB */
		{0x02, 0xcf},	/* vol o/p = stereo, vol i/p = audio deemp, 4MHz clk, scart1 video = high Z */
		{0x03, 0xf7},	/* audio deemp = 75us, scart2 audio = high Z, pin 9 = VIDEEM2, scart2 video = high Z */
		{0x04, 0x8a},	/* black level = 0, scart3 audio = PLL, low power, scart3 = normal video */
		{0x05, 0x36},	/* pin29 = i/o, 22kHz off, 49.1 kHz FM deviation */
		{0x06, 0x42},	/* SW1=Bias,SW3=Bias,SW2 opened,SW4 opened, i/o = output, i/o = L */
		{0x07, 0xa6},	/* synth freq = 6.65 MHz */
	};

	dprintk(4, ".\n");

	for (i = 0; i < (sizeof(init) / (sizeof(init[0]))); i++) {
		ret |=
		    i2c_smbus_write_byte_data(client, init[i][0], init[i][1]);
		if (i <= 5)
			decoder->writeregs[i] = init[i][1];

		udelay(50);
	}

	memset(decoder, 0, sizeof(struct stv0056af));

	decoder->adapter = client->adapter;
	if ((video_gain > -1) && (video_gain <= 0x3f)) {	/* valid insmod arg? */
		decoder->video_gain = video_gain;
		stv0056af_set_gain(client, video_gain);
		dprintk(1, "set by insmod option: video gain = +%d.%d dB\n",
			(202 * video_gain) / 1000, (202 * video_gain) % 1000);
	} else
		decoder->video_gain = 0;
	decoder->source_scart1 = STV_HIGHZ;
	decoder->source_scart2 = STV_HIGHZ;
	if ((decoder_output > -1) && (decoder_output <= 2)) {	/* valid insmod arg? */
		decoder->source_decoder = decoder_output;
		stv0056af_select_output(client, STV_DECODER, decoder_output);
		switch (decoder_output) {
		case 0:
			dprintk(1,
				"set by insmod option: decoder output mode = baseband unclamped\n");
			break;
		case 1:
			dprintk(1,
				"set by insmod option: decoder output mode = deemphasized unclamped\n");
			break;
		case 2:
			dprintk(1,
				"set by insmod option: decoder output mode = deemphasized clamped\n");
			break;
		default:
			dprintk(1,
				"set by insmod option: decoder output mode = ?\n");
		}
	} else {
		decoder->source_decoder = STV_NORMAL_VIDEO;
	}

	decoder->volume = 0;
	decoder->sig22khz = STV_22KHZ_OFF;

	/* FIXME!! stv0056af_set_carrier could be called at this place to set initial audio carriers */

	if (ret != 0) {
		dprintk(1, "client failed.\n");
		return -EIO;
	}

	return 0;
}

static int stv0056af_detect(struct i2c_adapter *adapter, int addr, int kind)
{
	struct i2c_client *client;
	struct stv0056af *decoder;
	int ret;

	dprintk(4, "addr=0x%02x.\n", addr);

	/* let's see whether this adapter can support what we need */
	if (i2c_check_functionality
	    (adapter, I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA) == 0) {
		return 0;
	}

	/* allocate memory for client structure */
	if (NULL == (client = kmalloc((sizeof(struct i2c_client)), GFP_KERNEL)))
		return -ENOMEM;
	memset(client, 0, sizeof(struct i2c_client));

	/* allocate memory for stv structure */
	if (NULL == (decoder = kmalloc((sizeof(struct stv0056af)), GFP_KERNEL))) {
		kfree(client);
		return -ENOMEM;
	}
	memset(decoder, 0, sizeof(struct stv0056af));

	/* fill client structure */
	sprintf(client->name, "SGS-Thomson STV0056AF");
	client->id = stv0056af_id++;
	client->flags = 0;
	client->addr = addr;
	client->adapter = adapter;
	client->driver = &stv_driver;
	i2c_set_clientdata(client, decoder);

	if (stv0056af_id == 0) {
		dprintk(1, "No hardware detected.\n");
	} else {
		dprintk(1, "client detected @ i2c address 0x%02x.\n",
			client->addr);
	}

	/* tell the i2c layer a new client has arrived */
	if ((ret = i2c_attach_client(client)) != 0) {
		dprintk(1,
			"i2c_attach_client failed, client @ 0x%02x not attached.\n",
			client->addr);
		kfree(decoder);
		kfree(client);
		return ret;
	}

	dprintk(1, "client @ 0x%02x attached to adapter '%s'.\n", client->addr,
		client->adapter->name);

	/* STV0056AF chip init */
	if ((ret = stv0056af_chip_init(client)) != 0) {
		dprintk(1,
			"Init of client @ 0x%02x failed, continuing anyway.\n",
			client->addr);
		return ret;
	}

	return 0;
}

static int stv0056af_attach(struct i2c_adapter *adapter)
{
	dprintk(4, ".\n");

	return i2c_probe(adapter, &addr_data, &stv0056af_detect);
}

static int stv0056af_detach(struct i2c_client *client)
{
	struct stv0056af *decoder = i2c_get_clientdata(client);
	int ret = 0;

	dprintk(4, "addr=0x%02x; adapter='%s'.\n", client->addr,
		client->adapter->name);

	/* Not used & not needed by MediaFocusII */
	/* ret |= stv0056af_set_volume (client, 0); */

	/* FIXME!! switch off audio before unload the module */
	/* ret |= stv0056af_write (stv, 0x06, 0x02); */
	if (ret != 0) {
		dprintk(1,
			"Audio mute before detaching client @ 0x%02x failed.\n",
			client->addr);
	}

	if ((ret = i2c_detach_client(client)) != 0) {
		dprintk(1,
			"i2c_detach_client failed, client @ 0x%02x not detached.\n",
			client->addr);
		return ret;
	}

	dprintk(1, "client @ 0x%02x detached from adapter '%s'.\n",
		client->addr, client->adapter->name);

	kfree(decoder);
	kfree(client);

	return 0;
}

static int stv0056af_command(struct i2c_client *client, unsigned int cmd,
			     void *arg)
{
	struct stv0056af *decoder = i2c_get_clientdata(client);
	unsigned long f = *(unsigned long *)arg;
	unsigned int *sarg = arg;
	int ret = 0;
	unsigned char stv_register_6;

	switch (cmd) {
	case STV_GET_GAIN:{
			*sarg = decoder->video_gain;

			dprintk(4, "STV_GET_GAIN (gain=0x%x)\n", *sarg);

			return ret;
		}

		/* set gain of video path */
	case STV_SET_GAIN:{
			decoder->video_gain = *sarg;

			dprintk(4, "STV_SET_GAIN (gain=0x%x)\n", *sarg);

			return stv0056af_set_gain(client,
						  decoder->video_gain >> 10);
		}

	case STV_GET_SCART1:{
			*sarg = decoder->source_scart1;

			dprintk(4, "STV_GET_SCART1 (src=%d)\n", *sarg);

			return ret;
		}

		/* select source for SCART1 output of STV0056AF */
		/* mediafocusII: normal video path which is shown on-screen */
	case STV_SET_SCART1:{
			decoder->source_scart1 = *sarg;

			dprintk(4, "STV_SET_SCART1 (src=%d)\n", *sarg);

			return stv0056af_select_output(client, STV_SCART1,
						       decoder->source_scart1);
		}

	case STV_GET_SCART2:{
			*sarg = decoder->source_scart2;

			dprintk(4, "STV_GET_SCART2 (src=%d)\n", *sarg);

			return ret;
		}

		/* select source for SCART2 output of STV0056AF */
		/* Not used & not needed by MediaFocusII */
	case STV_SET_SCART2:{
			decoder->source_scart2 = *sarg;

			dprintk(4, "STV_SET_SCART2 (src=%d)\n", *sarg);

			return stv0056af_select_output(client, STV_SCART2,
						       decoder->source_scart2);
		}

	case STV_GET_DECODER:{
			*sarg = decoder->source_decoder;

			dprintk(4, "STV_GET_DECODER (src=%d)\n", *sarg);

			return ret;
		}

		/* select source for SCART3 (= "Decoder") output of STV0056AF */
		/* mediafocusII: video output path to Mini-DIN jack */
	case STV_SET_DECODER:{
			decoder->source_decoder = *sarg;

			dprintk(4, "STV_SET_DECODER (src=%d)\n", *sarg);

			return stv0056af_select_output(client, STV_DECODER,
						       decoder->source_decoder);
		}

		/* Not used & not needed by MediaFocusII */
	case STV_GET_STEREO:{
			*sarg = decoder->audio_mode;

			dprintk(4, "STV_GET_STEREO (mode=0x%x)\n", *sarg);

			return ret;
		}

		/* Not used & not needed by MediaFocusII */
	case STV_SET_STEREO:{
			decoder->audio_mode = *sarg;

			dprintk(4, "STV_SET_STEREO (mode=0x%x)\n", *sarg);

			switch (decoder->audio_mode) {
			case V4L2_TUNER_MODE_MONO:
				return stv0056af_set_carrier(client, 0x0199, 0x0199);	/* 6.60 MHz Mono */
			case V4L2_TUNER_MODE_STEREO:
				return stv0056af_set_carrier(client, 0x0205, 0x0233);	/* 7.02/7.20 MHz Stereo */
			case V4L2_TUNER_MODE_LANG1:
				return stv0056af_set_carrier(client, 0x01A6, 0x01A6);	/* 6.65 MHz Mono */
			case V4L2_TUNER_MODE_LANG2:
				return stv0056af_set_carrier(client, 0x0180, 0x0180);	/* 6.50 MHz Mono */
			default:
				return -EINVAL;
			}
		}

		/* Not used & not needed by MediaFocusII */
	case STV_SWITCH_MUTE:{
			decoder->volume = 0;

			dprintk(4, "STV_SWITCH_MUTE\n");

			return stv0056af_set_volume(client, 0x00);
		}

		/* Not used & not needed by MediaFocusII */
	case STV_GET_VOLUME:{
			*sarg = decoder->volume;

			dprintk(4, "STV_GET_VOLUME (vol=%d)\n", *sarg);

			return ret;
		}

		/* Not used & not needed by MediaFocusII */
	case STV_SET_VOLUME:{

			dprintk(4, "STV_SET_VOLUME (vol=%d; stv_vol=0x%x)\n",
				(uint) f, (unsigned char)(f >> 11));

			ret =
			    stv0056af_set_volume(client,
						 (unsigned char)(f >> 11));
			decoder->volume = (uint) (f);

			return ret;
		}

		/* select generation of 22 kHz tone */
		/* MediaFocusII: pin "IO" is used as pure digital output */
		/*  to control 22 kHz generation in LNB voltage chip     */
	case STV_SET_22KHZ:{

			dprintk(4, "STV_SET_22KHZ (state=0x%x)\n", *sarg);

			switch (*sarg) {
			case STV_22KHZ_ON:
				if (decoder->sig22khz == STV_22KHZ_OFF) {
					ret =
					    (i2c_master_recv
					     (client, stv_readregs,
					      sizeof(stv_readregs)) !=
					     sizeof(stv_readregs));
					stv_register_6 =
					    GET_STV_REG(6) | STV_REG6_IO;
					stv_register_6 |= STV_REG6_IODIR;	/* FIX */
					ret |=
					    i2c_smbus_write_byte_data(client,
								      0x06,
								      stv_register_6);
					decoder->sig22khz = STV_22KHZ_ON;

					if (ret != 0) {
						dprintk(1,
							"STV_22KHZ_ON failed.\n");
						return -EIO;
					}

					dprintk(4,
						"SET_22KHZ: 22kHz was off, now switched on\n");

				}
				break;

			case STV_22KHZ_OFF:
				if (decoder->sig22khz == STV_22KHZ_ON) {
					ret =
					    (i2c_master_recv
					     (client, stv_readregs,
					      sizeof(stv_readregs)) !=
					     sizeof(stv_readregs));
					stv_register_6 =
					    GET_STV_REG(6) & !STV_REG6_IO;
					stv_register_6 |= STV_REG6_IODIR;	/* FIX */
					ret |=
					    i2c_smbus_write_byte_data(client,
								      0x06,
								      stv_register_6);
					decoder->sig22khz = STV_22KHZ_OFF;

					if (ret != 0) {
						dprintk(1,
							"STV_22KHZ_OFF failed.\n");
						return -EIO;
					}

					dprintk(4,
						"SET_22KHZ: 22kHz was on, now switched off\n");

				}
				break;

			default:
				return -EINVAL;
			}
			return ret;
		}

	default:

		dprintk(4, "Unknown ioctl cmd (0x%x).\n", cmd);

		return -ENOIOCTLCMD;
	}
}

static struct i2c_driver stv_driver = {
	.owner = THIS_MODULE,
	.name = "stv0056af.o",
	.id = I2C_DRIVERID_STV0056,
	.flags = I2C_DF_NOTIFY,
	.attach_adapter = stv0056af_attach,
	.detach_client = stv0056af_detach,
	.command = stv0056af_command,
};

static int __init stv0056af_init(void)
{
	int ret;

	if (0 != (ret = i2c_add_driver(&stv_driver))) {
		dprintk(1, "i2c_add_driver() failed, module not inserted.\n");
		return ret;
	}

	return 0;
}

static void __exit stv0056af_exit(void)
{
	if (0 != i2c_del_driver(&stv_driver))
		dprintk(1, "i2c_del_driver() failed.\n");
}

MODULE_AUTHOR("Torsten Tittmann <Torsten.Tittmann@gmx.de>");
MODULE_DESCRIPTION("SGS-Thomson STV0056AF I2C driver");
MODULE_LICENSE("GPL");

module_init(stv0056af_init);
module_exit(stv0056af_exit);
