diff options
Diffstat (limited to 'v4l_experimental')
-rw-r--r-- | v4l_experimental/dpl3518.c | 413 | ||||
-rw-r--r-- | v4l_experimental/dpl3518.h | 44 | ||||
-rw-r--r-- | v4l_experimental/plx9054.h | 177 | ||||
-rw-r--r-- | v4l_experimental/rds-saa6588.c | 134 |
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); +} |