patch-2.3.50 linux/drivers/char/tda985x.c
Next file: linux/drivers/char/tty_io.c
Previous file: linux/drivers/char/tda9855.c
Back to the patch index
Back to the overall index
- Lines: 533
- Date:
Mon Mar 6 15:32:30 2000
- Orig file:
v2.3.49/linux/drivers/char/tda985x.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.3.49/linux/drivers/char/tda985x.c linux/drivers/char/tda985x.c
@@ -0,0 +1,532 @@
+/*
+ * For the TDA9850 and TDA9855 chips
+ * (The TDA9855 is used on the Diamond DTV2000 and the TDA9850 is used
+ * on STB cards. Other cards probably use these chips as well.)
+ * This driver will not complain if used with any
+ * other i2c device with the same address.
+ *
+ * Copyright (c) 1999 Gerd Knorr
+ * TDA9850 code and TDA9855.c merger by Eric Sandeen (eric_sandeen@bigfoot.com)
+ * This code is placed under the terms of the GNU General Public License
+ * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu)
+ * Which was based on tda8425.c by Greg Alexander (c) 1998
+ *
+ * OPTIONS:
+ * debug - set to 1 if you'd like to see debug messages
+ * chip - set to 9850 or 9855 to select your chip (default 9855)
+ *
+ * TODO:
+ * Fix channel change bug - sound goes out when changeing channels, mute
+ * and unmote to fix. - Is this still here?
+ * Fine tune sound
+ * Get rest of capabilities into video_audio struct...
+ *
+ * Revision: 0.4 - check for correct chip= insmod value
+ * also cleaned up comments a bit
+ * Revision: 0.3 - took out extraneous tda985x_write in tda985x_command
+ * Revision: 0.2 - added insmod option chip=
+ * Revision: 0.1 - original version
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/videodev.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#include "bttv.h"
+#include "audiochip.h"
+
+MODULE_PARM(debug,"i");
+MODULE_PARM(chip,"i");
+MODULE_PARM_DESC(chip, "Type of chip to handle: 9850 or 9855");
+
+static int debug = 0; /* insmod parameter */
+static int chip = 9855; /* insmod parameter */
+
+/* Addresses to scan */
+#define I2C_TDA985x_L 0xb4
+#define I2C_TDA985x_H 0xb6
+static unsigned short normal_i2c[] = {I2C_CLIENT_END};
+static unsigned short normal_i2c_range[] = {
+ I2C_TDA985x_L >> 1,
+ I2C_TDA985x_H >> 1,
+ I2C_CLIENT_END};
+static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static struct i2c_client_address_data addr_data = {
+ normal_i2c, normal_i2c_range,
+ probe, probe_range,
+ ignore, ignore_range,
+ force
+};
+
+/* This is a superset of the TDA9850 and TDA9855 members */
+
+struct tda985x {
+ int addr;
+ int rvol, lvol;
+ int bass, treble, sub;
+ int c4, c5, c6, c7;
+ int a1, a2, a3;
+};
+
+static struct i2c_driver driver;
+static struct i2c_client client_template;
+
+#define dprintk if (debug) printk
+
+/* The TDA9850 and TDA9855 are both made by Philips Semiconductor
+ * http://www.semiconductors.philips.com
+ * TDA9850: I2C-bus controlled BTSC stereo/SAP decoder
+ * TDA9855: I2C-bus controlled BTSC stereo/SAP decoder and audio processor
+ *
+ * The TDA9850 has more or less a subset of the functions that the TDA9855
+ * has. As a result, we can re-use many of these defines. Anything with
+ * TDA9855 is specific to that chip, anything with TDA9850 is specific
+ * to that chip, and anything with TDA985x is valid for either.
+ *
+ * To complicate things further, the TDA9850 uses labels C1 through C4
+ * for subaddresses 0x04 through 0x07, while the TDA9855 uses
+ * C1 through C3 for subadresses 0x05 through 0x07 - quite confusing.
+ * To help keep things straight, I have renamed the various C[1,4] labels
+ * to C[4,7] so that the numerical label matches the hex value of the
+ * subaddress for both chips. At least the A[1,3] labels line up. :)
+ */
+
+ /* subaddresses for TDA9855 */
+#define TDA9855_VR 0x00 /* Volume, right */
+#define TDA9855_VL 0x01 /* Volume, left */
+#define TDA9855_BA 0x02 /* Bass */
+#define TDA9855_TR 0x03 /* Treble */
+#define TDA9855_SW 0x04 /* Subwoofer - not connected on DTV2000 */
+
+ /* subaddresses for TDA9850 */
+#define TDA9850_C4 0x04 /* Control 1 for TDA9850 */
+
+ /* subaddesses for both chips */
+#define TDA985x_C5 0x05 /* Control 2 for TDA9850, Control 1 for TDA9855 */
+#define TDA985x_C6 0x06 /* Control 3 for TDA9850, Control 2 for TDA9855 */
+#define TDA985x_C7 0x07 /* Control 4 for TDA9850, Control 3 for TDA9855 */
+#define TDA985x_A1 0x08 /* Alignment 1 for both chips */
+#define TDA985x_A2 0x09 /* Alignment 2 for both chips */
+#define TDA985x_A3 0x0a /* Alignment 3 for both chips */
+
+ /* Masks for bits in TDA9855 subaddresses */
+/* 0x00 - VR in TDA9855 */
+/* 0x01 - VL in TDA9855 */
+/* lower 7 bits control gain from -71dB (0x28) to 16dB (0x7f)
+ * in 1dB steps - mute is 0x27 */
+
+
+/* 0x02 - BA in TDA9855 */
+/* lower 5 bits control bass gain from -12dB (0x06) to 16.5dB (0x19)
+ * in .5dB steps - 0 is 0x0E */
+
+
+/* 0x03 - TR in TDA9855 */
+/* 4 bits << 1 control treble gain from -12dB (0x3) to 12dB (0xb)
+ * in 3dB steps - 0 is 0x7 */
+
+ /* Masks for bits in both chips' subaddresses */
+/* 0x04 - SW in TDA9855, C4/Control 1 in TDA9850 */
+/* Unique to TDA9855: */
+/* 4 bits << 2 control subwoofer/surround gain from -14db (0x1) to 14db (0xf)
+ * in 3dB steps - mute is 0x0 */
+
+/* Unique to TDA9850: */
+/* lower 4 bits control stereo noise threshold, over which stereo turns off
+ * set to values of 0x00 through 0x0f for Ster1 through Ster16 */
+
+
+/* 0x05 - C5 - Control 1 in TDA9855 , Control 2 in TDA9850*/
+/* Unique to TDA9855: */
+#define TDA9855_MUTE 1<<7 /* GMU, Mute at outputs */
+#define TDA9855_AVL 1<<6 /* AVL, Automatic Volume Level */
+#define TDA9855_LOUD 1<<5 /* Loudness, 1==off */
+#define TDA9855_SUR 1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */
+ /* Bits 0 to 3 select various combinations
+ * of line in and line out, only the
+ * interesting ones are defined */
+#define TDA9855_EXT 1<<2 /* Selects inputs LIR and LIL. Pins 41 & 12 */
+#define TDA9855_INT 0 /* Selects inputs LOR and LOL. (internal) */
+
+/* Unique to TDA9850: */
+/* lower 4 bits contol SAP noise threshold, over which SAP turns off
+ * set to values of 0x00 through 0x0f for SAP1 through SAP16 */
+
+
+/* 0x06 - C6 - Control 2 in TDA9855, Control 3 in TDA9850 */
+/* Common to TDA9855 and TDA9850: */
+#define TDA985x_SAP 3<<6 /* Selects SAP output, mute if not received */
+#define TDA985x_STEREO 1<<6 /* Selects Stereo ouput, mono if not received */
+#define TDA985x_MONO 0 /* Forces Mono output */
+#define TDA985x_LMU 1<<3 /* Mute (LOR/LOL for 9855, OUTL/OUTR for 9850) */
+
+/* Unique to TDA9855: */
+#define TDA9855_TZCM 1<<5 /* If set, don't mute till zero crossing */
+#define TDA9855_VZCM 1<<4 /* If set, don't change volume till zero crossing*/
+#define TDA9855_LINEAR 0 /* Linear Stereo */
+#define TDA9855_PSEUDO 1 /* Pseudo Stereo */
+#define TDA9855_SPAT_30 2 /* Spatial Stereo, 30% anti-phase crosstalk */
+#define TDA9855_SPAT_50 3 /* Spatial Stereo, 52% anti-phase crosstalk */
+#define TDA9855_E_MONO 7 /* Forced mono - mono select elseware, so useless*/
+
+
+/* 0x07 - C7 - Control 3 in TDA9855, Control 4 in TDA9850 */
+/* Common to both TDA9855 and TDA9850: */
+/* lower 4 bits control input gain from -3.5dB (0x0) to 4dB (0xF)
+ * in .5dB steps - 0dB is 0x7 */
+
+
+/* 0x08, 0x09 - A1 and A2 (read/write) */
+/* Common to both TDA9855 and TDA9850: */
+/* lower 5 bites are wideband and spectral expander alignment
+ * from 0x00 to 0x1f - nominal at 0x0f and 0x10 (read/write) */
+#define TDA985x_STP 1<<5 /* Stereo Pilot/detect (read-only) */
+#define TDA985x_SAPP 1<<6 /* SAP Pilot/detect (read-only) */
+#define TDA985x_STS 1<<7 /* Stereo trigger 1= <35mV 0= <30mV (write-only)*/
+
+
+/* 0x0a - A3 */
+/* Common to both TDA9855 and TDA9850: */
+/* lower 3 bits control timing current for alignment: -30% (0x0), -20% (0x1),
+ * -10% (0x2), nominal (0x3), +10% (0x6), +20% (0x5), +30% (0x4) */
+#define TDA985x_ADJ 1<<7 /* Stereo adjust on/off (wideband and spectral */
+
+/* Unique to TDA9855: */
+/* 2 bits << 5 control AVL attack time: 420ohm (0x0), 730ohm (0x2),
+ * 1200ohm (0x1), 2100ohm (0x3) */
+
+
+/* Begin code */
+
+static int tda985x_write(struct i2c_client *client, int subaddr, int val)
+{
+ unsigned char buffer[2];
+ dprintk("In tda985x_write\n");
+ dprintk("Writing %d 0x%x\n", subaddr, val);
+ buffer[0] = subaddr;
+ buffer[1] = val;
+ if (2 != i2c_master_send(client,buffer,2)) {
+ printk(KERN_WARNING "tda985x: I/O error, trying (write %d 0x%x)\n",
+ subaddr, val);
+ return -1;
+ }
+ return 0;
+}
+
+static int tda985x_read(struct i2c_client *client)
+{
+ unsigned char buffer;
+ dprintk("In tda985x_read\n");
+ if (1 != i2c_master_recv(client,&buffer,1)) {
+ printk(KERN_WARNING "tda985x: I/O error, trying (read)\n");
+ return -1;
+ }
+ dprintk("Read 0x%02x\n", buffer);
+ return buffer;
+}
+
+static int tda985x_set(struct i2c_client *client)
+{
+ struct tda985x *t = client->data;
+ unsigned char buf[16];
+ dprintk("In tda985x_set\n");
+
+ if (chip == 9855)
+ {
+ dprintk(KERN_INFO
+ "tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
+ t->rvol,t->lvol,t->bass,t->treble,t->sub,
+ t->c5,t->c6,t->c7,t->a1,t->a2,t->a3);
+ buf[0] = TDA9855_VR;
+ buf[1] = t->rvol;
+ buf[2] = t->lvol;
+ buf[3] = t->bass;
+ buf[4] = t->treble;
+ buf[5] = t->sub;
+ buf[6] = t->c5;
+ buf[7] = t->c6;
+ buf[8] = t->c7;
+ buf[9] = t->a1;
+ buf[10] = t->a2;
+ buf[11] = t->a3;
+ if (12 != i2c_master_send(client,buf,12)) {
+ printk(KERN_WARNING "tda9855: I/O error, trying tda985x_set\n");
+ return -1;
+ }
+ }
+
+ else if (chip == 9850)
+ {
+ dprintk(KERN_INFO
+ "tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
+ t->c4,t->c5,t->c6,t->c7,t->a1,t->a2,t->a3);
+ buf[0] = TDA9850_C4;
+ buf[1] = t->c4;
+ buf[2] = t->c5;
+ buf[3] = t->c6;
+ buf[4] = t->c7;
+ buf[5] = t->a1;
+ buf[6] = t->a2;
+ buf[7] = t->a3;
+ if (8 != i2c_master_send(client,buf,8)) {
+ printk(KERN_WARNING "tda9850: I/O error, trying tda985x_set\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static void do_tda985x_init(struct i2c_client *client)
+{
+ struct tda985x *t = client->data;
+ dprintk("In tda985x_init\n");
+
+ if (chip == 9855)
+ {
+ printk("Using tda9855 options\n");
+ t->rvol = 0x6f; /* 0dB */
+ t->lvol = 0x6f; /* 0dB */
+ t->bass = 0x0e; /* 0dB */
+ t->treble = (0x07 << 1); /* 0dB */
+ t->sub = 0x8 << 2; /* 0dB */
+ t->c5 = TDA9855_MUTE | TDA9855_AVL |
+ TDA9855_LOUD | TDA9855_INT;
+ /* Set Mute, AVL, Loudness off, Internal sound */
+ t->c6 = TDA985x_STEREO | TDA9855_LINEAR |
+ TDA9855_TZCM | TDA9855_VZCM;
+ /* Stereo linear mode, also wait til zero crossings */
+ t->c7 = 0x07; /* 0dB input gain */
+ }
+
+ else if (chip == 9850)
+ {
+ printk("Using tda9850 options\n");
+ t->c4 = 0x08; /* Set stereo noise thresh to nominal */
+ t->c5 = 0x08; /* Set SAP noise threshold to nominal */
+ t->c6 = TDA985x_STEREO; /* Select Stereo mode for decoder */
+ t->c7 = 0x07; /* 0dB input gain */
+ }
+
+ /* The following is valid for both chip types */
+ t->a1 = 0x10; /* Select nominal wideband expander */
+ t->a2 = 0x10; /* Select nominal spectral expander and 30mV trigger */
+ t->a3 = 0x3; /* Set: nominal timing current, 420ohm AVL attack */
+
+ tda985x_set(client);
+}
+
+/* *********************** *
+ * i2c interface functions *
+ * *********************** */
+
+static int tda985x_attach(struct i2c_adapter *adap, int addr,
+ unsigned short flags, int kind)
+{
+ struct tda985x *t;
+ struct i2c_client *client;
+ dprintk("In tda985x_attach\n");
+ client = kmalloc(sizeof *client,GFP_KERNEL);
+ if (!client)
+ return -ENOMEM;
+ memcpy(client,&client_template,sizeof(struct i2c_client));
+ client->adapter = adap;
+ client->addr = addr;
+
+ client->data = t = kmalloc(sizeof *t,GFP_KERNEL);
+ if (!t)
+ return -ENOMEM;
+ memset(t,0,sizeof *t);
+ do_tda985x_init(client);
+ MOD_INC_USE_COUNT;
+ strcpy(client->name,"TDA985x");
+ printk(KERN_INFO "tda985x: init\n");
+
+ i2c_attach_client(client);
+ return 0;
+}
+
+static int tda985x_probe(struct i2c_adapter *adap)
+{
+ if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+ return i2c_probe(adap, &addr_data, tda985x_attach);
+ return 0;
+}
+
+static int tda985x_detach(struct i2c_client *client)
+{
+ struct tda985x *t = client->data;
+
+ do_tda985x_init(client);
+ i2c_detach_client(client);
+
+ kfree(t);
+ kfree(client);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static int tda985x_command(struct i2c_client *client,
+ unsigned int cmd, void *arg)
+{
+ struct tda985x *t = client->data;
+ dprintk("In tda985x_command...\n");
+#if 0
+ __u16 *sarg = arg;
+#endif
+
+ switch (cmd) {
+ /* --- v4l ioctls --- */
+ /* take care: bttv does userspace copying, we'll get a
+ kernel pointer here... */
+ case VIDIOCGAUDIO:
+ {
+ struct video_audio *va = arg;
+ dprintk("VIDIOCGAUDIO\n");
+ if (chip == 9855)
+ {
+ int left,right;
+
+ va->flags |= VIDEO_AUDIO_VOLUME |
+ VIDEO_AUDIO_BASS |
+ VIDEO_AUDIO_TREBLE;
+
+ /* min is 0x27 max is 0x7f, vstep is 2e8 */
+ left = (t->lvol-0x27)*0x2e8;
+ right = (t->rvol-0x27)*0x2e8;
+ va->volume=MAX(left,right);
+ va->balance=(32768*MIN(left,right))/
+ (va->volume ? va->volume : 1);
+ va->balance=(left<right)?
+ (65535-va->balance) : va->balance;
+ va->bass = (t->bass-0x6)*0xccc; /* min 0x6 max 0x19 */
+ va->treble = ((t->treble>>1)-0x3)*0x1c71;
+ }
+
+ /* Valid for both chips: */
+ {
+ va->mode = ((TDA985x_STP | TDA985x_SAPP) &
+ tda985x_read(client)) >> 4;
+ /* Add mono mode regardless of SAP and stereo */
+ /* Allows forced mono */
+ va->mode |= VIDEO_SOUND_MONO;
+ }
+
+ break; /* VIDIOCGAUDIO case */
+ }
+
+ case VIDIOCSAUDIO:
+ {
+ struct video_audio *va = arg;
+ dprintk("VIDEOCSAUDIO...\n");
+ if (chip == 9855)
+ {
+ int left,right;
+
+ left = (MIN(65536 - va->balance,32768) *
+ va->volume) / 32768;
+ right = (MIN(va->balance,32768) *
+ va->volume) / 32768;
+ t->lvol = left/0x2e8+0x27;
+ t->rvol = right/0x2e8+0x27;
+ t->bass = va->bass/0xccc+0x6;
+ t->treble = (va->treble/0x1c71+0x3)<<1;
+ tda985x_write(client,TDA9855_VL,t->lvol);
+ tda985x_write(client,TDA9855_VR,t->rvol);
+ tda985x_write(client,TDA9855_BA, t->bass);
+ tda985x_write(client,TDA9855_TR,t->treble);
+ }
+
+ /* The following is valid for both chips */
+
+ switch (va->mode) {
+ case VIDEO_SOUND_MONO:
+ dprintk("VIDEO_SOUND_MONO\n");
+ t->c6= TDA985x_MONO | (t->c6 & 0x3f);
+ tda985x_write(client,TDA985x_C6,t->c6);
+ break;
+ case VIDEO_SOUND_STEREO:
+ dprintk("VIDEO_SOUND_STEREO\n");
+ t->c6= TDA985x_STEREO | (t->c6 & 0x3f);
+ tda985x_write(client,TDA985x_C6,t->c6);
+ break;
+ case VIDEO_SOUND_LANG1:
+ dprintk("VIDEO_SOUND_LANG1\n");
+ t->c6= TDA985x_SAP | (t->c6 & 0x3f);
+ tda985x_write(client,TDA985x_C6,t->c6);
+ break;
+ } /* End of (va->mode) switch */
+
+ break;
+
+ } /* end of VIDEOCSAUDIO case */
+
+ default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */
+
+ /* nothing */
+ dprintk("Default\n");
+
+ } /* end of (cmd) switch */
+
+ return 0;
+}
+
+
+static struct i2c_driver driver = {
+ "i2c tda985x driver",
+ I2C_DRIVERID_TDA9855, /* Get new one for TDA985x? */
+ I2C_DF_NOTIFY,
+ tda985x_probe,
+ tda985x_detach,
+ tda985x_command,
+};
+
+static struct i2c_client client_template =
+{
+ "(unset)", /* name */
+ -1,
+ 0,
+ 0,
+ NULL,
+ &driver
+};
+
+#ifdef MODULE
+int init_module(void)
+#else
+int tda985x_init(void)
+#endif
+{
+ if ( (chip != 9850) && (chip != 9855) )
+ {
+ printk(KERN_ERR "tda985x: chip parameter must be 9850 or 9855\n");
+ return -EINVAL;
+ }
+ i2c_add_driver(&driver);
+ return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ i2c_del_driver(&driver);
+}
+#endif
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)