summaryrefslogtreecommitdiff
path: root/v4l_experimental
diff options
context:
space:
mode:
Diffstat (limited to 'v4l_experimental')
-rw-r--r--v4l_experimental/dpl3518.c413
-rw-r--r--v4l_experimental/dpl3518.h44
-rw-r--r--v4l_experimental/plx9054.h177
-rw-r--r--v4l_experimental/rds-saa6588.c134
4 files changed, 768 insertions, 0 deletions
diff --git a/v4l_experimental/dpl3518.c b/v4l_experimental/dpl3518.c
new file mode 100644
index 000000000..5a730b7bd
--- /dev/null
+++ b/v4l_experimental/dpl3518.c
@@ -0,0 +1,413 @@
+/*
+ * programming the dpl3518a Dolby Pro Logic Processor
+ *
+ * WARNING: THIS DRIVER WILL LOAD WITHOUT COMPLAINTS EVEN IF A DIFFERENT
+ * CHIP IS AT ADDRESS 0x84 (it relies on i2c to make sure that there is a
+ * device acknowledging that address)
+ *
+ * Copyright (C) 1999 Roland Jansen <roland@lut.rwth-aachen.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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * ---
+ * DOLBY and PRO LOGIC are trademarks of
+ * Dolby Laboratories Licensing Corporation.
+ */
+
+/* FIXME */
+#define DPL_MAJOR 127
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.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/slab.h>
+#include <linux/i2c.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#include "id.h"
+#include "i2c-compat.h"
+#else
+#include <media/id.h>
+#endif
+#include "dpl3518.h"
+
+
+/* Addresses to scan */
+#define I2C_DPL3518 0x84
+static unsigned short normal_i2c[] = {
+ I2C_DPL3518 >> 1,
+ I2C_CLIENT_END};
+static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
+I2C_CLIENT_INSMOD;
+
+struct dpl3518 {
+ struct i2c_client *client;
+ int mode; /* dolby mode */
+};
+
+static struct dpl3518 *dpl_device;
+static struct i2c_driver driver;
+static struct i2c_client client_template;
+
+/* ---------------------------------------------------------------------- */
+
+/* insmod parameters */
+static int debug = 0; /* debug output */
+MODULE_PARM(debug, "i");
+
+MODULE_DESCRIPTION("device driver for dpl3518a Dolby Pro Logic Processor");
+MODULE_AUTHOR("Roland Jansen");
+MODULE_LICENSE("GPL");
+
+#define dprintk if (debug) printk
+
+/* ---------------------------------------------------------------------- */
+
+#define I2C_DPL3518_MR 0x10 /* write address MODE_REG */
+#define I2C_DPL3518_DFP 0x12 /* write address DFP */
+
+/* ----------------------------------------------------------------------- */
+/* functions for talking to the dpl3518 Sound processor */
+
+static int dpl3518_reset(struct i2c_client *client)
+{
+ static char reset_off[3] = { 0x00, 0x80, 0x00 };
+ static char reset_on[3] = { 0x00, 0x00, 0x00 };
+
+ i2c_master_send(client,reset_off,3); /* ignore errors here */
+ if (3 != i2c_master_send(client,reset_on, 3)) {
+ printk(KERN_ERR "dpl3518: chip reset failed, penguin on i2c bus?\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int dpl3518_write(struct i2c_client *client, int dev, int addr, int val)
+{
+ int err;
+ unsigned char buffer[5];
+
+ buffer[0] = dev;
+ buffer[1] = addr >> 8;
+ buffer[2] = addr & 0xff;
+ buffer[3] = val >> 8;
+ buffer[4] = val & 0xff;
+
+ for (err = 0; err < 3;) {
+ if (5 == i2c_master_send(client, buffer, 5))
+ break;
+ err++;
+ printk(KERN_WARNING "dpl3518: I/O error #%d (write 0x%02x/0x%02x)\n",
+ err, dev, addr);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ/10);
+ }
+ if (3 == err) {
+ printk(KERN_WARNING "dpl3518: giving up, reseting chip. Sound will go off, sorry folks :-|\n");
+ dpl3518_reset(client);
+ return -1;
+ }
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* in: 0..100 out: 0x00..0x7f */
+static int p100_to_7f(int i)
+{
+ int r;
+
+ r = ((i & 0x7f) * 127 + 1) / 100;
+ if (r > 127)
+ r = 127;
+ if (r < 0)
+ r = 0;
+ return r;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void dpl3518_ioc_init(struct i2c_client *client)
+{
+ dprintk("dpl3518 init\n");
+ dpl3518_write(client, I2C_DPL3518_MR, 0x0083, 0x0008); /* mode_reg */
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x000b, 0x0320); /*I2S1 src: RL */
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x0012, 0x0000); /*prescale2: off */
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x0016, 0x1000); /*prescale: 0 dB */
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x0038, 0x0420); /*I2S2 src: CS */
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x0040, 0x0000); /*adaptive,surround */
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x0041, 0x0520); /*i2s1, stereo */
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x0042, 0x1400); /*delay: 20ms */
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x0043, 0x0000); /*inp. Bal. auto */
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x0044, 0x4000); /*spatial 50% */
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x0045, 0x0000); /*panorama off */
+ //dpl3518_write(client,I2C_DPL3518_DFP,0x0045,0x5400); /*panorama 66%*/
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x0046, 0x0000); /*reverb off */
+}
+
+static void dpl3518_prologic_init(struct i2c_client *client)
+{
+ dprintk("dpl3518 prologic_init\n");
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x000b, 0x0320); /*I2S1 src: RL */
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x0038, 0x0420); /*I2S2 src: CS */
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x0041, 0x0520); /*i2s1, stereo */
+}
+
+static void dpl3518_noise_init(struct i2c_client *client)
+{
+ dprintk("dpl3518 noise_init\n");
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x000b, 0x0320); /*I2S1 src: RL */
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x0038, 0x0420); /*I2S2 src: CS */
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x0041, 0x0100); /*NOISE */
+}
+
+static void dpl3518_through_init(struct i2c_client *client)
+{
+ dprintk("dpl3518 through_init\n");
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x000b, 0x0520); /*I2S1 src: S1 */
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x0038, 0x0220); /*I2S2 src: scart*/
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x0041, 0x0520); /*i2s1, stereo */
+}
+
+static void dpl3518_setmode(struct i2c_client *client, int mode)
+{
+ dprintk("dpl3518 setmode: %i\n", mode);
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x0040, mode << 4);
+ dpl_device->mode = mode;
+}
+
+static void dpl3518_setnoisemode(struct i2c_client *client, int mode)
+{
+ static int noise_modes[5] = { 0x0000, 0x01a0, 0x01b0, 0x01c0, 0x01d0 };
+ dprintk("dpl3518 setnoisemode: %i\n", mode);
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x0041, noise_modes[mode]);
+}
+
+
+static void dpl3518_delay(struct i2c_client *client, int delay)
+{
+ dprintk("dpl3518 setdelay: %i\n", delay);
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x0042, delay << 8);
+}
+
+static void dpl3518_reverb(struct i2c_client *client, int rev)
+{
+ dprintk("dpl3518 setreverb: %i\n", rev);
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x0046, p100_to_7f(rev) << 8);
+}
+
+static void dpl3518_panorama(struct i2c_client *client, int pan)
+{
+ dprintk("dpl3518 panorama: %i\n", pan);
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x0045, p100_to_7f(pan) << 8);
+}
+
+static void dpl3518_spatial(struct i2c_client *client, int spatial)
+{
+ dprintk("dpl3518 setspatial: %i\n", spatial);
+ dpl3518_write(client, I2C_DPL3518_DFP, 0x0045, p100_to_7f(spatial) << 8);
+}
+
+/* ----------------------------------------------------------------------- */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+static int dpl3518_attach(struct i2c_adapter *adap, int addr, int kind)
+#else
+static int dpl3518_attach(struct i2c_adapter *adap, int addr,
+ unsigned short flags, int kind)
+#endif
+{
+ struct dpl3518 *dpl;
+ struct i2c_client *client;
+
+ client = kmalloc(sizeof *client,GFP_KERNEL);
+ if (!client)
+ return -ENOMEM;
+ memcpy(client,&client_template,sizeof(struct i2c_client));
+ client->adapter = adap;
+ client->addr = addr;
+
+ dpl = kmalloc(sizeof *dpl, GFP_KERNEL);
+ if (NULL == dpl)
+ return -ENOMEM;
+ i2c_set_clientdata(client, dpl);
+ memset(dpl, 0, sizeof(struct dpl3518));
+ dpl->mode = 0; /* DOLBY_MODE_NONE */
+ dpl->client = client;
+
+ if (-1 == dpl3518_reset(client)) {
+ kfree(dpl);
+ kfree(client);
+ dprintk("dpl3518: no chip found\n");
+ return -1;
+ }
+
+ printk(KERN_INFO "dpl3518: init\n");
+ dpl_device = dpl;
+ dpl3518_ioc_init(client);
+
+ /* done */
+ i2c_attach_client(client);
+ return 0;
+}
+
+static int dpl3518_probe(struct i2c_adapter *adap)
+{
+ return i2c_probe(adap, &addr_data, dpl3518_attach);
+}
+
+static int dpl3518_detach(struct i2c_client *client)
+{
+ struct dpl3518 *dpl = i2c_get_clientdata(client);
+
+ dpl3518_reset(client);
+ i2c_detach_client(client);
+
+ dpl_device = NULL;
+ kfree(dpl);
+ kfree(client);
+ return 0;
+}
+
+static int dpl3518_dev_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+// unsigned int minor = MINOR(inode->i_rdev);
+ int ret = 0;
+ struct i2c_client *client = dpl_device->client;
+
+ switch (cmd) {
+ case DPL_IOC_RESET:
+ dpl3518_reset(client);
+ break;
+ case DPL_IOC_VERSION:
+ if (put_user(DPL_VERSION_CODE, (int *) arg))
+ ret = -EFAULT;
+ break;
+ case DPL_IOC_INIT:
+ dpl3518_ioc_init(client);
+ break;
+ case DPL_IOC_PROLOGIC_INIT:
+ dpl3518_prologic_init(client);
+ break;
+ case DPL_IOC_NOISE_INIT:
+ dpl3518_noise_init(client);
+ break;
+ case DPL_IOC_THROUGH_INIT:
+ dpl3518_through_init(client);
+ break;
+ case DPL_IOC_MODE:
+ dpl3518_setmode(client, (int) arg);
+ break;
+ case DPL_IOC_GET_MODE:
+ if (put_user(dpl_device->mode, (int *) arg))
+ ret = -EFAULT;
+ break;
+ case DPL_IOC_NOISE_MODE:
+ dpl3518_setnoisemode(client, (int) arg);
+ break;
+ case DPL_IOC_DELAY:
+ dpl3518_delay(client, (int) arg);
+ break;
+ case DPL_IOC_REVERB:
+ dpl3518_reverb(client, (int) arg);
+ break;
+ case DPL_IOC_PANORAMA:
+ dpl3518_panorama(client, (int) arg);
+ break;
+ case DPL_IOC_SPATIAL:
+ dpl3518_spatial(client, (int) arg);
+ break;
+ default:
+ dprintk("dpl3518_ioctl: default %i\n", (int) arg);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static int dpl3518_dev_open(struct inode *inode, struct file *file)
+{
+ dprintk("dpl3518_dev_open\n");
+ return 0;
+}
+
+static int dpl3518_dev_release(struct inode *inode, struct file *file)
+{
+ dprintk("dpl3518_dev_release\n");
+ return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static struct i2c_driver driver = {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,54)
+ .owner = THIS_MODULE,
+#endif
+ .name = "i2c dpl3518 driver",
+ .id = I2C_DRIVERID_DPL3518,
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = dpl3518_probe,
+ .detach_client = dpl3518_detach,
+};
+
+static struct i2c_client client_template =
+{
+ I2C_DEVNAME("dpl3518"),
+ .id = -1,
+ .driver = &driver
+};
+
+static struct file_operations dpl3518_fops =
+{
+ .owner = THIS_MODULE,
+ .ioctl = dpl3518_dev_ioctl,
+ .open = dpl3518_dev_open,
+ .release = dpl3518_dev_release,
+};
+
+
+static int dpl3518_init(void)
+{
+ if (register_chrdev(DPL_MAJOR, "dpl3518", &dpl3518_fops)) {
+ printk("dpl3518: unable to get major %d\n", DPL_MAJOR);
+ return -EBUSY;
+ }
+ i2c_add_driver(&driver);
+ return 0;
+}
+
+static void dpl3518_fini(void)
+{
+ i2c_del_driver(&driver);
+ unregister_chrdev(DPL_MAJOR, "dpl3518");
+}
+
+module_init(dpl3518_init);
+module_exit(dpl3518_fini);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/v4l_experimental/dpl3518.h b/v4l_experimental/dpl3518.h
new file mode 100644
index 000000000..d67a25648
--- /dev/null
+++ b/v4l_experimental/dpl3518.h
@@ -0,0 +1,44 @@
+#ifndef DPL3518_H
+#define DPL3518_H
+
+#include <linux/ioctl.h>
+
+#define DPL_VERSION_CODE 0x0002 /* Version 0.2 */
+
+
+/* IOCTL numbers */
+
+/* Reset function (just in case...) */
+#define DPL_IOC_RESET _IO('d',1)
+
+/* Get driver version */
+#define DPL_IOC_VERSION _IOR('d',2,int)
+
+/* Dolby Pro Logic modes */
+#define DPL_IOC_INIT _IO('d',3) /* Must be done first */
+
+#define DPL_IOC_PROLOGIC_INIT _IO('d',4)
+#define DPL_IOC_NOISE_INIT _IO('d',5)
+#define DPL_IOC_THROUGH_INIT _IO('d',6)
+
+#define DPL_IOC_MODE _IOW('d',7,int) /* 0 = Normal */
+ /* 1 = Phantom */
+ /* 2 = Wide */
+ /* 3 = Dolby 3 Stereo */
+ /* 4 = Center Off */
+ /* 5 = Panorama */
+ /* 6 = 3D-Panorama (virtual dolby) */
+#define DPL_IOC_GET_MODE _IOR('d',7,int)
+
+#define DPL_IOC_NOISE_MODE _IOW('d',8,int)
+#define DPL_IOC_GET_NOISE_MODE _IOR('d',8,int)
+
+#define DPL_IOC_DELAY _IOW('d',9,int) /* 0 .. 15 */
+#define DPL_IOC_REVERB _IOW('d',10,int) /* 0 .. 100 % */
+#define DPL_IOC_PANORAMA _IOW('d',11,int) /* 0 .. 100 % */
+#define DPL_IOC_SPATIAL _IOW('d',12,int) /* 0 .. 100 % */
+
+
+/* ---------------------------------------------------------------------- */
+
+#endif /* DPL3518_H */
diff --git a/v4l_experimental/plx9054.h b/v4l_experimental/plx9054.h
new file mode 100644
index 000000000..9a1c8783f
--- /dev/null
+++ b/v4l_experimental/plx9054.h
@@ -0,0 +1,177 @@
+#ifndef _PLX9054_H_
+#define _PLX9054_H_
+
+// Definitions for the PLX Configuration space registers.
+// All bits numbers are starting from 0.
+#define PLX9054_STS_CMD_OFFSET 0x4
+
+#define PLX9054_SUBSYSTEM_ID_OFFSET 0x2C
+#define SUBSYSTEM_ID_SHIFT 16
+
+#define PLX9054_CONF_HOT_SWAP_OFFSET 0x48
+#define HOT_SWAP_LED 0x00080000
+
+#define PLX9054_CONF_VPD_OFFSET 0x4C
+#define VPD_ADDRESS_SHIFT 16
+#define VPD_ADDRESS 0x7FFF0000
+#define VPD_FLAG 0x80000000
+
+#define PLX9054_CONF_VPD_DATA 0x50
+
+// Definitions for the PLX internal registers.
+#define PLX9054_LAS0RR_OFFSET 0x00
+
+#define PLX9054_LB0_BASE_ADR 0x04
+#define SPACE0_ENABLED 0x00000001
+#define LB_SPACE0_ADDRESS_MASK 0xFFFFFFF0
+
+#define PLX9054_MARBR_OFFSET 0x08
+#define DIRECT_SLAVE_LOCK_ENABLE (1 << 22) // 22 bit
+#define PRIOPITY_MASK 0x00180000
+#define PRIORITY_DMA_0 0x00100000
+
+//
+#define PLX9054_BIGEND_LMISC_PROTAREA 0x0C
+#define PROT_AREA_SHIFT 16
+#define PROT_AREA_MASK 0x007F0000
+#define BIGEND_DIRECT_MASTER 0x00000002
+#define BIGEND_SPACE_1 (1 << 5) // 5 bit
+#define BIGEND_DMA0 (1 << 7)
+
+#define PLX9054_LBRD0_OFFSET 0x18
+#define SPACE0_BUSWIDTH8 0x00000000
+#define SPACE0_BUSWIDTH16 0x00000001
+#define SPACE0_BUSWIDTH32 0x00000003
+#define SPACE0_READY_INPUT_ENABLE 0x00000040
+#define SPACE0_BTERM_INPUT_ENABLE 0x00000080
+#define SPACE0_PREFETCH_DISABLE 0x00000100
+#define SPACE0_BURST_ENABLE 0x01000000
+#define SPACE0_PREFETCH_COUNT_ENABLE 0x00000400
+#define PCI_TARGET_RETRY_DELAY_MAX 0xF0000000 /* 15 * 4 PCI clocks */
+
+
+#define EROM_BUSWIDTH8 0x00000000
+#define EROM_BUSWIDTH16 0x00010000
+#define EROM_BUSWIDTH32 0x00030000
+#define EROM_READY_INPUT_ENABLE 0x00400000
+#define EROM_BTERM_INPUT_ENABLE 0x00800000
+#define EROM_PREFETCH_DISABLE 0x00000200
+#define EROM_BURST_ENABLE 0x04000000
+#define EROM_PREFETCH_COUNT_ENABLE 0x00000400
+
+#define PLX9054_LB_PCI_RANGE 0x1C
+#define PLX9054_DMRR_OFFSET PLX9054_LB_PCI_RANGE
+#define LB_PCI_RANGE_MASK 0xFFFF0000
+
+#define PLX9054_LB_BASE_ADR 0x20
+#define PLX9054_DMLBAM_OFFSET PLX9054_LB_BASE_ADR
+#define LB_BASE_ADR_MASK 0xFFFF0000
+
+#define PLX9054_DMLBA1_OFFSET 0x24
+
+#define PLX9054_PCI_BASE_ADR 0x28
+#define PLX9054_DMPBAM_OFFSET PLX9054_PCI_BASE_ADR
+#define LB_PCI_MEM_ENABLE 0x00000001
+#define LB_PCI_IO_ENABLE 0x00000002
+#define PCI_PREFETCH_SIZE_INF 0x00001008
+#define PCI_KEEP_BUS 0x00000010
+#define USE_PCI_BASE_ADR 0x00002000
+#define PCI_BASE_ADR_MASK 0xFFFF0000
+
+// INTCSR0 register
+#define PLX9054_INT_CNTRL_STS 0x68
+#define LSERR_ENABLE 0x00000003 // 1 and 2 bit.
+#define PCI_INT_ENABLE 0x00000100 // 8 bit
+#define PCI_DOORBELL_ENABLE 0x00000200 // 9 bit
+#define PCI_ABORT_INT_ENABLE (1<<10) // 10 bit
+#define LOCAL_INT_INPUT_ENABLE 0x00000800 // 11 bit
+#define RETRY_ABORT_ENABLE (1<<12) // 12 bit.
+#define LOCAL_INT_ACTIVE 0x00008000 // 15 bit
+#define LOCAL_INT_OUTPUT_ENABLE 0x00010000 // 16 bit
+#define LOCAL_DOORBELL_ENABLE 0x00020000 // 17 bit
+#define DMA0_INT_ENABLE 0x00040000 // 18 bit
+#define DMA1_INT_ENABLE 0x00080000 // 19 bit
+#define DMA0_INT_ACTIVE 0x00200000 // 21 bit
+#define DMA1_INT_ACTIVE 0x00400000
+
+
+#define PLX9054_CNTRL_OFFSET 0x6C
+#define SERIAL_EEPROM_CLK 0x01000000
+#define SERIAL_EEPROM_DATA 0x04000000
+#define SERIAL_EEPROM_CS 0x02000000
+#define GP_OUTPUT 0x00010000 // 16 bit
+#define GP_INPUT (1 << 17) // 17 bit
+#define GP_OUTPUT_ENABLE 0x00040000
+//#define SERIAL_EEPROM_PESENT
+
+
+// DMAMODE0 register.
+#define PLX9054_DMA0_MODE 0x80
+#define DMA0_LB_WIDTH_16 0x1
+#define DMA0_LB_WIDTH_32 0x2
+#define DMA0_LB_WIDTH_MASK 0x3
+#define DMA0_BTERM_ENABLE (1 << 7) // 7 bit
+#define DMA0_LOCAL_BURST_ENABLE (1 << 8) // 8 bit
+#define DMA0_DONE_ENABLE (1 << 10) // 10 bit
+#define DMA0_HOLD_LOCAL_ADRESS (1 << 11) // 11 bit
+#define DMA0_DEMAND_MODE (1 << 12) // 12 bit
+#define DMA0_FAST_TERMINATION (1 << 15) // 15 bit
+#define DMA0_INT_TO_PCI (1 << 17) // 17 bit
+
+
+// DMAPADR0 register
+#define PLX9054_DMA0_PCI_ADDRESS 0x84
+
+
+// DMALADR0 register
+#define PLX9054_DMA0_LB_ADDRESS 0x88
+
+
+// DMASIZ0 register
+#define PLX9054_DMA0_SIZE 0x8C
+
+
+// DMADPR0 register
+#define PLX9054_DMA0_DESCR_PTR 0x90
+#define DMA0_DESCRIPTOR_INT_ENABLE (1 << 2) // 2 bit
+#define DMA0_LOCAL_TO_PCI_TRANSFER (1 << 3) // 3 bit
+
+
+#define PLX9054_DMA1_MODE 0x94
+#define DMA1_DONE_ENABLE 0x00000400 // 10 bit
+#define DMA1_INT_TO_PCI 0x00020000 // 18 bit
+
+
+#define PLX9054_DMA1_DESCR_PTR 0xA4
+#define DMA1_INT_TERM_CNT_ENABLE 0x00000004
+
+// DMACSR0 register
+#define PLX9054_DMA_CMD_STS 0xA8
+#define DMA0_ENABLE 1 // 0 bit
+#define DMA0_START (1 << 1) // 1 bit
+#define DMA0_ABORT (1 << 2) // 2 bit
+#define DMA0_CLEAR_INT (1 << 3) // 3 bit
+#define DMA0_TRANSFER_DONE (1 << 4) // 4 bit
+
+#define DMA1_CLEAR_INT 0x00000800
+#define DMA1_TRANSFER_DONE 0x00001000
+
+#define PLX9054_LAS1RR_OFFSET 0xF0
+
+#define PLX9054_LB1_BASE_ADR 0xF4
+#define PLX9054_LAS1BA_OFFSET PLX9054_LB1_BASE_ADR
+#define SPACE1_ENABLED 0x00000001
+#define LB_SPACE1_ADDRESS_MASK 0xFFFFFFF0
+
+#define PLX9054_LBRD1_OFFSET 0xF8
+#define SPACE1_BUSWIDTH8 0x00000000
+#define SPACE1_BUSWIDTH16 0x00000001
+#define SPACE1_BUSWIDTH32 0x00000003
+#define SPACE1_READY_INPUT_ENABLE 0x00000040
+#define SPACE1_BTERM_INPUT_ENABLE 0x00000080
+#define SPACE1_PREFETCH_DISABLE 0x00000200
+#define SPACE1_BURST_ENABLE 0x00000100
+#define SPACE1_PREFETCH_COUNT_ENABLE 0x00000400
+
+
+#endif
diff --git a/v4l_experimental/rds-saa6588.c b/v4l_experimental/rds-saa6588.c
new file mode 100644
index 000000000..de4464a08
--- /dev/null
+++ b/v4l_experimental/rds-saa6588.c
@@ -0,0 +1,134 @@
+/*
+ * poll i2c RDS receiver [Philips saa6588]
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+
+int debug;
+
+/* ----------------------------------------------------------------- */
+
+char rds_psn[9];
+char rds_txt[65];
+
+void rds_decode(int blkno,int b1, int b2)
+{
+ static int group,spare,c1,c2;
+
+ switch (blkno) {
+ case 0:
+ if (debug)
+ fprintf(stderr,"block A - id=%d\n",
+ (b1 << 8) | b2);
+ break;
+ case 1:
+ if (debug)
+ fprintf(stderr,"block B - group=%d%c tp=%d pty=%d spare=%d\n",
+ (b1 >> 4) & 0x0f,
+ ((b1 >> 3) & 0x01) + 'A',
+ (b1 >> 2) & 0x01,
+ ((b1 << 3) & 0x18) | ((b2 >> 5) & 0x07),
+ b2 & 0x1f);
+ group = (b1 >> 3) & 0x1f;
+ spare = b2 & 0x1f;
+ break;
+ case 2:
+ if (debug)
+ fprintf(stderr,"block C - 0x%02x 0x%02x\n",b1,b2);
+ c1 = b1;
+ c2 = b2;
+ break;
+ case 3:
+ if (debug)
+ fprintf(stderr,"block D - 0x%02x 0x%02x\n",b1,b2);
+ switch (group) {
+ case 0:
+ rds_psn[2*(spare & 0x03)+0] = b1;
+ rds_psn[2*(spare & 0x03)+1] = b2;
+ if ((spare & 0x03) == 0x03)
+ fprintf(stderr,"PSN #>%s<#\n",rds_psn);
+ break;
+ case 4:
+ rds_txt[4*(spare & 0x0f)+0] = c1;
+ rds_txt[4*(spare & 0x0f)+1] = c2;
+ rds_txt[4*(spare & 0x0f)+2] = b1;
+ rds_txt[4*(spare & 0x0f)+3] = b2;
+ if ((spare & 0x0f) == 0x0f)
+ fprintf(stderr,"TXT #>%s<#\n",rds_txt);
+ break;
+ }
+ break;
+ default:
+ fprintf(stderr,"unknown block [%d]\n",blkno);
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ int c,f,rc, no, lastno = -1;
+ unsigned char b[40];
+ char *device = "/dev/i2c-0";
+
+ /* parse options */
+ while (-1 != (c=getopt(argc,argv,"hvd:"))) {
+ switch (c){
+ case 'd':
+ if (optarg)
+ device = optarg;
+ break;
+ case 'v':
+ debug = 1;
+ break;
+ case 'h':
+ default:
+ printf("poll i2c RDS receiver [saa6588] via chardev\n");
+ printf("usage: %s [ -d i2c-device ]\n",argv[0]);
+ exit(1);
+ }
+ }
+
+ if (-1 == (f = open(device,O_RDWR))) {
+ fprintf(stderr,"open %s: %s\n",device,strerror(errno));
+ exit(1);
+ }
+ ioctl(f,I2C_SLAVE,0x20 >> 1);
+ for (;;) {
+ memset(b,0,sizeof(b));
+ rc = read(f,b,6);
+ if (6 != rc) {
+ fprintf(stderr,"oops: read: rc=%d, expected 6 [%s]\n",
+ rc,strerror(errno));
+ break;
+ }
+ if (0 == (b[0] & 0x10)) {
+ fprintf(stderr,"no signal\r");
+ continue;
+ }
+ if (1 == (b[0] & 0x08)) {
+ fprintf(stderr,"overflow detected\n");
+ }
+ if (1 == (b[0] & 0x04)) {
+ fprintf(stderr,"reset detected\n");
+ }
+ if (debug)
+ fprintf(stderr,"raw: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
+ b[0],b[1],b[2],b[3],b[4],b[5]);
+ no = b[0] >> 5;
+ if (lastno != no) {
+ rds_decode(no, b[1], b[2]);
+ lastno = no;
+ }
+ usleep(10*1000);
+ }
+ close(f);
+ exit(0);
+}