diff options
Diffstat (limited to 'linux/drivers/media/dvb')
-rw-r--r-- | linux/drivers/media/dvb/Kconfig | 13 | ||||
-rw-r--r-- | linux/drivers/media/dvb/dm1105/dm1105.c | 7 | ||||
-rw-r--r-- | linux/drivers/media/dvb/dvb-core/dvbdev.c | 79 | ||||
-rw-r--r-- | linux/drivers/media/dvb/dvb-core/dvbdev.h | 1 | ||||
-rw-r--r-- | linux/drivers/media/dvb/dvb-usb/Kconfig | 2 | ||||
-rw-r--r-- | linux/drivers/media/dvb/dvb-usb/dw2102.c | 1 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/Kconfig | 19 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/Makefile | 5 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/lgdt3304.c | 398 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/lgdt3304.h | 45 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/s921_core.c | 587 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/s921_core.h | 114 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/s921_module.c | 254 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/s921_module.h | 49 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/zl10353.c | 3 | ||||
-rw-r--r-- | linux/drivers/media/dvb/ttpci/av7110.c | 2 |
16 files changed, 1547 insertions, 32 deletions
diff --git a/linux/drivers/media/dvb/Kconfig b/linux/drivers/media/dvb/Kconfig index 0bcd85257..40ebde53b 100644 --- a/linux/drivers/media/dvb/Kconfig +++ b/linux/drivers/media/dvb/Kconfig @@ -2,6 +2,19 @@ # DVB device configuration # +config DVB_DYNAMIC_MINORS + bool "Dynamic DVB minor allocation" + depends on DVB_CORE + default n + help + If you say Y here, the DVB subsystem will use dynamic minor + allocation for any device that uses the DVB major number. + This means that you can have more than 4 of a single type + of device (like demuxes and frontends) per adapter, but udev + will be required to manage the device nodes. + + If you are unsure about this, say N here. + menuconfig DVB_CAPTURE_DRIVERS bool "DVB/ATSC adapters" depends on DVB_CORE diff --git a/linux/drivers/media/dvb/dm1105/dm1105.c b/linux/drivers/media/dvb/dm1105/dm1105.c index d9d1e0a12..f578cbdb6 100644 --- a/linux/drivers/media/dvb/dm1105/dm1105.c +++ b/linux/drivers/media/dvb/dm1105/dm1105.c @@ -19,7 +19,6 @@ * */ -#include <linux/version.h> #include <linux/i2c.h> #include <linux/init.h> #include <linux/kernel.h> @@ -368,11 +367,7 @@ static int __devinit dm1105dvb_dma_map(struct dm1105dvb *dm1105dvb) { dm1105dvb->ts_buf = pci_alloc_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, &dm1105dvb->dma_addr); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) - return pci_dma_mapping_error(dm1105dvb->dma_addr); -#else - return pci_dma_mapping_error(dm1105dvb->pdev, dm1105dvb->dma_addr); -#endif + return !dm1105dvb->ts_buf; } static void dm1105dvb_dma_unmap(struct dm1105dvb *dm1105dvb) diff --git a/linux/drivers/media/dvb/dvb-core/dvbdev.c b/linux/drivers/media/dvb/dvb-core/dvbdev.c index c2e824710..59a65a8c3 100644 --- a/linux/drivers/media/dvb/dvb-core/dvbdev.c +++ b/linux/drivers/media/dvb/dvb-core/dvbdev.c @@ -51,33 +51,27 @@ static const char * const dnames[] = { "net", "osd" }; +#ifdef CONFIG_DVB_DYNAMIC_MINORS +#define MAX_DVB_MINORS 256 +#define DVB_MAX_IDS MAX_DVB_MINORS +#else #define DVB_MAX_IDS 4 #define nums2minor(num,type,id) ((num << 6) | (id << 4) | type) #define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64) +#endif static struct class *dvb_class; -static struct dvb_device* dvbdev_find_device (int minor) -{ - struct dvb_adapter *adap; - - list_for_each_entry(adap, &dvb_adapter_list, list_head) { - struct dvb_device *dev; - list_for_each_entry(dev, &adap->device_list, list_head) - if (nums2minor(adap->num, dev->type, dev->id) == minor) - return dev; - } - - return NULL; -} - +static struct dvb_device *dvb_minors[MAX_DVB_MINORS]; +static DECLARE_RWSEM(minor_rwsem); static int dvb_device_open(struct inode *inode, struct file *file) { struct dvb_device *dvbdev; lock_kernel(); - dvbdev = dvbdev_find_device (iminor(inode)); + down_read(&minor_rwsem); + dvbdev = dvb_minors[iminor(inode)]; if (dvbdev && dvbdev->fops) { int err = 0; @@ -97,9 +91,11 @@ static int dvb_device_open(struct inode *inode, struct file *file) file->f_op = fops_get(old_fops); } fops_put(old_fops); + up_read(&minor_rwsem); unlock_kernel(); return err; } + up_read(&minor_rwsem); unlock_kernel(); return -ENODEV; } @@ -201,6 +197,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, #else struct class_device *clsdev; #endif + int minor; int id; mutex_lock(&dvbdev_register_lock); @@ -240,19 +237,39 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, list_add_tail (&dvbdev->list_head, &adap->device_list); + down_write(&minor_rwsem); +#ifdef CONFIG_DVB_DYNAMIC_MINORS + for (minor = 0; minor < MAX_DVB_MINORS; minor++) + if (dvb_minors[minor] == NULL) + break; + + if (minor == MAX_DVB_MINORS) { + kfree(dvbdevfops); + kfree(dvbdev); + mutex_unlock(&dvbdev_register_lock); + return -EINVAL; + } +#else + minor = nums2minor(adap->num, type, id); +#endif + + dvbdev->minor = minor; + dvb_minors[minor] = dvbdev; + up_write(&minor_rwsem); + mutex_unlock(&dvbdev_register_lock); #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27) clsdev = device_create(dvb_class, adap->device, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), - NULL, "dvb%d.%s%d", adap->num, dnames[type], id); + dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id); #elif LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 27) clsdev = device_create_drvdata(dvb_class, adap->device, - MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), - NULL, "dvb%d.%s%d", adap->num, dnames[type], id); + MKDEV(DVB_MAJOR, minor), + dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id); #else clsdev = device_create(dvb_class, adap->device, - MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), + MKDEV(DVB_MAJOR, minor), "dvb%d.%s%d", adap->num, dnames[type], id); #endif if (IS_ERR(clsdev)) { @@ -262,8 +279,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, } dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", - adap->num, dnames[type], id, nums2minor(adap->num, type, id), - nums2minor(adap->num, type, id)); + adap->num, dnames[type], id, minor, minor); return 0; } @@ -275,8 +291,11 @@ void dvb_unregister_device(struct dvb_device *dvbdev) if (!dvbdev) return; - device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num, - dvbdev->type, dvbdev->id))); + down_write(&minor_rwsem); + dvb_minors[dvbdev->minor] = NULL; + up_write(&minor_rwsem); + + device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor)); list_del (&dvbdev->list_head); kfree (dvbdev->fops); @@ -432,6 +451,17 @@ out: return err; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) +static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct dvb_device *dvbdev = dev_get_drvdata(dev); + + add_uevent_var(env, "DVB_DEVICE_NUM=%d", dvbdev->id); + add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num); + return 0; +} +#endif + static int __init init_dvbdev(void) { int retval; @@ -458,6 +488,9 @@ static int __init init_dvbdev(void) retval = PTR_ERR(dvb_class); goto error; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) + dvb_class->dev_uevent = dvb_uevent; +#endif return 0; error: diff --git a/linux/drivers/media/dvb/dvb-core/dvbdev.h b/linux/drivers/media/dvb/dvb-core/dvbdev.h index 574e336ba..dca49cf96 100644 --- a/linux/drivers/media/dvb/dvb-core/dvbdev.h +++ b/linux/drivers/media/dvb/dvb-core/dvbdev.h @@ -74,6 +74,7 @@ struct dvb_device { struct file_operations *fops; struct dvb_adapter *adapter; int type; + int minor; u32 id; /* in theory, 'users' can vanish now, diff --git a/linux/drivers/media/dvb/dvb-usb/Kconfig b/linux/drivers/media/dvb/dvb-usb/Kconfig index 47488a97a..62b68c291 100644 --- a/linux/drivers/media/dvb/dvb-usb/Kconfig +++ b/linux/drivers/media/dvb/dvb-usb/Kconfig @@ -261,7 +261,7 @@ config DVB_USB_DW2102 Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers and the TeVii S650. -config DVB_USB_CINERGY_T2 +config DVB_USB_CINERGY_T2 tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver" depends on DVB_USB help diff --git a/linux/drivers/media/dvb/dvb-usb/dw2102.c b/linux/drivers/media/dvb/dvb-usb/dw2102.c index 6286fbbe7..c9431713d 100644 --- a/linux/drivers/media/dvb/dvb-usb/dw2102.c +++ b/linux/drivers/media/dvb/dvb-usb/dw2102.c @@ -9,7 +9,6 @@ * * see Documentation/dvb/README.dvb-usb for more information */ -#include <linux/version.h> #include "dw2102.h" #include "si21xx.h" #include "stv0299.h" diff --git a/linux/drivers/media/dvb/frontends/Kconfig b/linux/drivers/media/dvb/frontends/Kconfig index 5387fad2e..2470d88e9 100644 --- a/linux/drivers/media/dvb/frontends/Kconfig +++ b/linux/drivers/media/dvb/frontends/Kconfig @@ -371,6 +371,14 @@ config DVB_LGDT330X An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. +config DVB_LGDT3304 + tristate "LG Electronics LGDT3304" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want + to support this frontend. + config DVB_S5H1409 tristate "Samsung S5H1409 based" depends on DVB_CORE && I2C @@ -395,6 +403,17 @@ config DVB_S5H1411 An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. +comment "ISDB-T (terrestrial) frontends" + depends on DVB_CORE + +config DVB_S921 + tristate "Sharp S921 tuner" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + AN ISDB-T DQPSK, QPSK, 16QAM and 64QAM 1seg tuner module. + Say Y when you want to support this frontend. + comment "Digital terrestrial only tuners/PLL" depends on DVB_CORE diff --git a/linux/drivers/media/dvb/frontends/Makefile b/linux/drivers/media/dvb/frontends/Makefile index 2afcd81f3..fd24de4ae 100644 --- a/linux/drivers/media/dvb/frontends/Makefile +++ b/linux/drivers/media/dvb/frontends/Makefile @@ -5,6 +5,8 @@ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ EXTRA_CFLAGS += -Idrivers/media/common/tuners/ +s921-objs := s921_module.o s921_core.o + stb0899-objs = stb0899_drv.o stb0899_algo.o obj-$(CONFIG_DVB_PLL) += dvb-pll.o @@ -39,6 +41,7 @@ obj-$(CONFIG_DVB_OR51132) += or51132.o obj-$(CONFIG_DVB_BCM3510) += bcm3510.o obj-$(CONFIG_DVB_S5H1420) += s5h1420.o obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o +obj-$(CONFIG_DVB_LGDT3304) += lgdt3304.o obj-$(CONFIG_DVB_CX24123) += cx24123.o obj-$(CONFIG_DVB_LNBP21) += lnbp21.o obj-$(CONFIG_DVB_ISL6405) += isl6405.o @@ -60,3 +63,5 @@ obj-$(CONFIG_DVB_CX24116) += cx24116.o obj-$(CONFIG_DVB_SI21XX) += si21xx.o obj-$(CONFIG_DVB_STV0288) += stv0288.o obj-$(CONFIG_DVB_STB6000) += stb6000.o +obj-$(CONFIG_DVB_S921) += s921.o + diff --git a/linux/drivers/media/dvb/frontends/lgdt3304.c b/linux/drivers/media/dvb/frontends/lgdt3304.c new file mode 100644 index 000000000..724811744 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/lgdt3304.c @@ -0,0 +1,398 @@ +/* + * Driver for LG ATSC lgdt3304 driver + * + * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de> + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/delay.h> +#include "dvb_frontend.h" +#include "lgdt3304.h" + +static unsigned int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug,"lgdt3304 debugging (default off)"); + +#define dprintk(fmt, args...) if (debug) do {\ + printk("lgdt3304 debug: " fmt, ##args); } while (0) + +struct lgdt3304_state +{ + struct dvb_frontend frontend; + fe_modulation_t current_modulation; + __u32 snr; + __u32 current_frequency; + __u8 addr; + struct i2c_adapter *i2c; +}; + +static int i2c_write_demod_bytes (struct dvb_frontend *fe, __u8 *buf, int len) +{ + struct lgdt3304_state *state = fe->demodulator_priv; + struct i2c_msg i2cmsgs = { + .addr = state->addr, + .flags = 0, + .len = 3, + .buf = buf + }; + int i; + int err; + + for (i=0; i<len-1; i+=3){ + if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) { + printk("%s i2c_transfer error %d\n", __FUNCTION__, err); + if (err < 0) + return err; + else + return -EREMOTEIO; + } + i2cmsgs.buf += 3; + } + return 0; +} + +static int lgdt3304_i2c_read_reg(struct dvb_frontend *fe, unsigned int reg) +{ + struct lgdt3304_state *state = fe->demodulator_priv; + struct i2c_msg i2cmsgs[2]; + int ret; + __u8 buf; + + __u8 regbuf[2] = { reg>>8, reg&0xff }; + + i2cmsgs[0].addr = state->addr; + i2cmsgs[0].flags = 0; + i2cmsgs[0].len = 2; + i2cmsgs[0].buf = regbuf; + + i2cmsgs[1].addr = state->addr; + i2cmsgs[1].flags = I2C_M_RD; + i2cmsgs[1].len = 1; + i2cmsgs[1].buf = &buf; + + if((ret = i2c_transfer(state->i2c, i2cmsgs, 2))<0) { + printk("%s i2c_transfer error %d\n", __FUNCTION__, ret); + return ret; + } + + return buf; +} + +static int lgdt3304_i2c_write_reg(struct dvb_frontend *fe, int reg, int val) +{ + struct lgdt3304_state *state = fe->demodulator_priv; + char buffer[3] = { reg>>8, reg&0xff, val }; + int ret; + + struct i2c_msg i2cmsgs = { + .addr = state->addr, + .flags = 0, + .len = 3, + .buf=buffer + }; + ret = i2c_transfer(state->i2c, &i2cmsgs, 1); + if (ret != 1) { + printk("%s i2c_transfer error %d\n", __FUNCTION__, ret); + return ret; + } + + return 0; +} + + +static int lgdt3304_soft_Reset(struct dvb_frontend *fe) +{ + lgdt3304_i2c_write_reg(fe, 0x0002, 0x9a); + lgdt3304_i2c_write_reg(fe, 0x0002, 0x9b); + mdelay(200); + return 0; +} + +static int lgdt3304_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) { + int err = 0; + + static __u8 lgdt3304_vsb8_data[] = { + /* 16bit , 8bit */ + /* regs , val */ + 0x00, 0x00, 0x02, + 0x00, 0x00, 0x13, + 0x00, 0x0d, 0x02, + 0x00, 0x0e, 0x02, + 0x00, 0x12, 0x32, + 0x00, 0x13, 0xc4, + 0x01, 0x12, 0x17, + 0x01, 0x13, 0x15, + 0x01, 0x14, 0x18, + 0x01, 0x15, 0xff, + 0x01, 0x16, 0x2c, + 0x02, 0x14, 0x67, + 0x02, 0x24, 0x8d, + 0x04, 0x27, 0x12, + 0x04, 0x28, 0x4f, + 0x03, 0x08, 0x80, + 0x03, 0x09, 0x00, + 0x03, 0x0d, 0x00, + 0x03, 0x0e, 0x1c, + 0x03, 0x14, 0xe1, + 0x05, 0x0e, 0x5b, + }; + + /* not yet tested .. */ + static __u8 lgdt3304_qam64_data[] = { + /* 16bit , 8bit */ + /* regs , val */ + 0x00, 0x00, 0x18, + 0x00, 0x0d, 0x02, + //0x00, 0x0e, 0x02, + 0x00, 0x12, 0x2a, + 0x00, 0x13, 0x00, + 0x03, 0x14, 0xe3, + 0x03, 0x0e, 0x1c, + 0x03, 0x08, 0x66, + 0x03, 0x09, 0x66, + 0x03, 0x0a, 0x08, + 0x03, 0x0b, 0x9b, + 0x05, 0x0e, 0x5b, + }; + +#if 0 + /* not yet tested */ + static __u8 lgdt3304_qam256_data[] = { + /* 16bit , 8bit */ + /* regs , val */ + 0x00, 0x00, 0x19, + 0x00, 0x12, 0x2a, + 0x00, 0x13, 0x80, + 0x00, 0x0d, 0x02, + 0x03, 0x14, 0xe3, + + 0x03, 0x0e, 0x1c, + 0x03, 0x08, 0x66, + 0x03, 0x09, 0x66, + 0x03, 0x0a, 0x08, + 0x03, 0x0b, 0x9b, + 0x03, 0x0d, 0x14, + 0x05, 0x0e, 0x5b, + }; +#endif + + /* tested with KWorld a340 */ + static __u8 lgdt3304_qam256_data[] = { + /* 16bit , 8bit */ + /* regs , val */ + 0x00, 0x00, 0x01, //0x19, + 0x00, 0x12, 0x2a, + 0x00, 0x13, 0x80, + 0x00, 0x0d, 0x02, + 0x03, 0x14, 0xe3, + + 0x03, 0x0e, 0x1c, + 0x03, 0x08, 0x66, + 0x03, 0x09, 0x66, + 0x03, 0x0a, 0x08, + 0x03, 0x0b, 0x9b, + + 0x03, 0x0d, 0x14, + //0x05, 0x0e, 0x5b, + 0x01, 0x06, 0x4a, + 0x01, 0x07, 0x3d, + 0x01, 0x08, 0x70, + 0x01, 0x09, 0xa3, + + 0x05, 0x04, 0xfd, + + 0x00, 0x0d, 0x82, + + 0x05, 0x0e, 0x5b, + + 0x05, 0x0e, 0x5b, + + 0x00, 0x02, 0x9a, + + 0x00, 0x02, 0x9b, + + 0x00, 0x00, 0x01, + 0x00, 0x12, 0x2a, + 0x00, 0x13, 0x80, + 0x00, 0x0d, 0x02, + 0x03, 0x14, 0xe3, + + 0x03, 0x0e, 0x1c, + 0x03, 0x08, 0x66, + 0x03, 0x09, 0x66, + 0x03, 0x0a, 0x08, + 0x03, 0x0b, 0x9b, + + 0x03, 0x0d, 0x14, + 0x01, 0x06, 0x4a, + 0x01, 0x07, 0x3d, + 0x01, 0x08, 0x70, + 0x01, 0x09, 0xa3, + + 0x05, 0x04, 0xfd, + + 0x00, 0x0d, 0x82, + + 0x05, 0x0e, 0x5b, + }; + + struct lgdt3304_state *state = fe->demodulator_priv; + if (state->current_modulation != param->u.vsb.modulation) { + switch(param->u.vsb.modulation) { + case VSB_8: + err = i2c_write_demod_bytes(fe, lgdt3304_vsb8_data, + sizeof(lgdt3304_vsb8_data)); + break; + case QAM_64: + err = i2c_write_demod_bytes(fe, lgdt3304_qam64_data, + sizeof(lgdt3304_qam64_data)); + break; + case QAM_256: + err = i2c_write_demod_bytes(fe, lgdt3304_qam256_data, + sizeof(lgdt3304_qam256_data)); + break; + default: + break; + } + + if (err) { + printk("%s error setting modulation\n", __FUNCTION__); + } else { + state->current_modulation = param->u.vsb.modulation; + } + } + state->current_frequency = param->frequency; + + lgdt3304_soft_Reset(fe); + + + if (fe->ops.tuner_ops.set_params) + fe->ops.tuner_ops.set_params(fe, param); + + return 0; +} + +static int lgdt3304_init(struct dvb_frontend *fe) { + return 0; +} + +static int lgdt3304_sleep(struct dvb_frontend *fe) { + return 0; +} + + +static int lgdt3304_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct lgdt3304_state *state = fe->demodulator_priv; + int r011d; + int qam_lck; + + *status = 0; + dprintk("lgdt read status\n"); + + r011d = lgdt3304_i2c_read_reg(fe, 0x011d); + + dprintk("%02x\n", r011d); + + switch(state->current_modulation) { + case VSB_8: + if (r011d & 0x80) { + dprintk("VSB Locked\n"); + *status |= FE_HAS_CARRIER; + *status |= FE_HAS_LOCK; + *status |= FE_HAS_SYNC; + *status |= FE_HAS_SIGNAL; + } + break; + case QAM_64: + case QAM_256: + qam_lck = r011d & 0x7; + switch(qam_lck) { + case 0x0: dprintk("Unlock\n"); + break; + case 0x4: dprintk("1st Lock in acquisition state\n"); + break; + case 0x6: dprintk("2nd Lock in acquisition state\n"); + break; + case 0x7: dprintk("Final Lock in good reception state\n"); + *status |= FE_HAS_CARRIER; + *status |= FE_HAS_LOCK; + *status |= FE_HAS_SYNC; + *status |= FE_HAS_SIGNAL; + break; + } + break; + default: + printk("%s unhandled modulation\n", __FUNCTION__); + } + + + return 0; +} + +static int lgdt3304_read_ber(struct dvb_frontend *fe, __u32 *ber) +{ + dprintk("read ber\n"); + return 0; +} + +static int lgdt3304_read_snr(struct dvb_frontend *fe, __u16 *snr) +{ + dprintk("read snr\n"); + return 0; +} + +static int lgdt3304_read_ucblocks(struct dvb_frontend *fe, __u32 *ucblocks) +{ + dprintk("read ucblocks\n"); + return 0; +} + +static void lgdt3304_release(struct dvb_frontend *fe) +{ + struct lgdt3304_state *state = (struct lgdt3304_state *)fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops demod_lgdt3304={ + .info = { + .name = "LG 3304", + .type = FE_ATSC, + .frequency_min = 54000000, + .frequency_max = 858000000, + .frequency_stepsize = 62500, + .symbol_rate_min = 5056941, + .symbol_rate_max = 10762000, + .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + }, + .init = lgdt3304_init, + .sleep = lgdt3304_sleep, + .set_frontend = lgdt3304_set_parameters, + .read_snr = lgdt3304_read_snr, + .read_ber = lgdt3304_read_ber, + .read_status = lgdt3304_read_status, + .read_ucblocks = lgdt3304_read_ucblocks, + .release = lgdt3304_release, +}; + +struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config, + struct i2c_adapter *i2c) +{ + + struct lgdt3304_state *state; + state = kzalloc(sizeof(struct lgdt3304_state), GFP_KERNEL); + memset(state, 0x0, sizeof(struct lgdt3304_state)); + state->addr = config->i2c_address; + state->i2c = i2c; + + memcpy(&state->frontend.ops, &demod_lgdt3304, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; +} + +EXPORT_SYMBOL_GPL(lgdt3304_attach); +MODULE_AUTHOR("Markus Rechberger <mrechberger@empiatech.com>"); +MODULE_DESCRIPTION("LGE LGDT3304 DVB-T demodulator driver"); +MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/dvb/frontends/lgdt3304.h b/linux/drivers/media/dvb/frontends/lgdt3304.h new file mode 100644 index 000000000..fc409fe59 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/lgdt3304.h @@ -0,0 +1,45 @@ +/* + * Driver for DVB-T lgdt3304 demodulator + * + * Copyright (C) 2008 Markus Rechberger <mrechberger@gmail.com> + * + * 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.= + */ + +#ifndef LGDT3304_H +#define LGDT3304_H + +#include <linux/dvb/frontend.h> + +struct lgdt3304_config +{ + /* demodulator's I2C address */ + u8 i2c_address; +}; + +#if defined(CONFIG_DVB_LGDT3304) || (defined(CONFIG_DVB_LGDT3304_MODULE) && defined(MODULE)) +extern struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_LGDT */ + +#endif /* LGDT3304_H */ diff --git a/linux/drivers/media/dvb/frontends/s921_core.c b/linux/drivers/media/dvb/frontends/s921_core.c new file mode 100644 index 000000000..5b9e6040e --- /dev/null +++ b/linux/drivers/media/dvb/frontends/s921_core.c @@ -0,0 +1,587 @@ +/* + * Driver for Sharp s921 driver + * + * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de> + * + */ + + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/delay.h> +#include "s921_core.h" + +static int s921_isdb_init(struct s921_isdb_t *dev); +static int s921_isdb_set_parameters(struct s921_isdb_t *dev, struct s921_isdb_t_transmission_mode_params *params); +static int s921_isdb_tune(struct s921_isdb_t *dev, struct s921_isdb_t_tune_params *params); +static int s921_isdb_get_status(struct s921_isdb_t *dev, void *data); + +static u8 init_table[]={ 0x01, 0x40, 0x02, 0x00, 0x03, 0x40, 0x04, 0x01, + 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, + 0x09, 0x00, 0x0a, 0x00, 0x0b, 0x5a, 0x0c, 0x00, + 0x0d, 0x00, 0x0f, 0x00, 0x13, 0x1b, 0x14, 0x80, + 0x15, 0x40, 0x17, 0x70, 0x18, 0x01, 0x19, 0x12, + 0x1a, 0x01, 0x1b, 0x12, 0x1c, 0xa0, 0x1d, 0x00, + 0x1e, 0x0a, 0x1f, 0x08, 0x20, 0x40, 0x21, 0xff, + 0x22, 0x4c, 0x23, 0x4e, 0x24, 0x4c, 0x25, 0x00, + 0x26, 0x00, 0x27, 0xf4, 0x28, 0x60, 0x29, 0x88, + 0x2a, 0x40, 0x2b, 0x40, 0x2c, 0xff, 0x2d, 0x00, + 0x2e, 0xff, 0x2f, 0x00, 0x30, 0x20, 0x31, 0x06, + 0x32, 0x0c, 0x34, 0x0f, 0x37, 0xfe, 0x38, 0x00, + 0x39, 0x63, 0x3a, 0x10, 0x3b, 0x10, 0x47, 0x00, + 0x49, 0xe5, 0x4b, 0x00, 0x50, 0xc0, 0x52, 0x20, + 0x54, 0x5a, 0x55, 0x5b, 0x56, 0x40, 0x57, 0x70, + 0x5c, 0x50, 0x5d, 0x00, 0x62, 0x17, 0x63, 0x2f, + 0x64, 0x6f, 0x68, 0x00, 0x69, 0x89, 0x6a, 0x00, + 0x6b, 0x00, 0x6c, 0x00, 0x6d, 0x00, 0x6e, 0x00, + 0x70, 0x00, 0x71, 0x00, 0x75, 0x00, 0x76, 0x30, + 0x77, 0x01, 0xaf, 0x00, 0xb0, 0xa0, 0xb2, 0x3d, + 0xb3, 0x25, 0xb4, 0x8b, 0xb5, 0x4b, 0xb6, 0x3f, + 0xb7, 0xff, 0xb8, 0xff, 0xb9, 0xfc, 0xba, 0x00, + 0xbb, 0x00, 0xbc, 0x00, 0xd0, 0x30, 0xe4, 0x84, + 0xf0, 0x48, 0xf1, 0x19, 0xf2, 0x5a, 0xf3, 0x8e, + 0xf4, 0x2d, 0xf5, 0x07, 0xf6, 0x5a, 0xf7, 0xba, + 0xf8, 0xd7 }; + +static u8 c_table[]={ 0x58, 0x8a, 0x7b, 0x59, 0x8c, 0x7b, 0x5a, 0x8e, 0x5b, + 0x5b, 0x90, 0x5b, 0x5c, 0x92, 0x5b, 0x5d, 0x94, 0x5b, + 0x5e, 0x96, 0x5b, 0x5f, 0x98, 0x3b, 0x60, 0x9a, 0x3b, + 0x61, 0x9c, 0x3b, 0x62, 0x9e, 0x3b, 0x63, 0xa0, 0x3b, + 0x64, 0xa2, 0x1b, 0x65, 0xa4, 0x1b, 0x66, 0xa6, 0x1b, + 0x67, 0xa8, 0x1b, 0x68, 0xaa, 0x1b, 0x69, 0xac, 0x1b, + 0x6a, 0xae, 0x1b, 0x6b, 0xb0, 0x1b, 0x6c, 0xb2, 0x1b, + 0x6d, 0xb4, 0xfb, 0x6e, 0xb6, 0xfb, 0x6f, 0xb8, 0xfb, + 0x70, 0xba, 0xfb, 0x71, 0xbc, 0xdb, 0x72, 0xbe, 0xdb, + 0x73, 0xc0, 0xdb, 0x74, 0xc2, 0xdb, 0x75, 0xc4, 0xdb, + 0x76, 0xc6, 0xdb, 0x77, 0xc8, 0xbb, 0x78, 0xca, 0xbb, + 0x79, 0xcc, 0xbb, 0x7a, 0xce, 0xbb, 0x7b, 0xd0, 0xbb, + 0x7c, 0xd2, 0xbb, 0x7d, 0xd4, 0xbb, 0x7e, 0xd6, 0xbb, + 0x7f, 0xd8, 0xbb, 0x80, 0xda, 0x9b, 0x81, 0xdc, 0x9b, + 0x82, 0xde, 0x9b, 0x83, 0xe0, 0x9b, 0x84, 0xe2, 0x9b, + 0x85, 0xe4, 0x9b, 0x86, 0xe6, 0x9b, 0x87, 0xe8, 0x9b, + 0x88, 0xea, 0x9b, 0x89, 0xec, 0x9b }; + +int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data) { + switch(cmd) { + case ISDB_T_CMD_INIT: + s921_isdb_init(dev); + break; + case ISDB_T_CMD_SET_PARAM: + s921_isdb_set_parameters(dev, data); + break; + case ISDB_T_CMD_TUNE: + s921_isdb_tune(dev, data); + break; + case ISDB_T_CMD_GET_STATUS: + s921_isdb_get_status(dev, data); + break; + default: + printk("unhandled command\n"); + return -EINVAL; + } + return 0; +} + +static int s921_isdb_init(struct s921_isdb_t *dev) { + unsigned int i; + unsigned int ret; + printk("isdb_init\n"); + for (i = 0; i < sizeof(init_table); i+=2) { + ret = dev->i2c_write(dev->priv_dev, init_table[i], init_table[i+1]); + if (ret != 0) { + printk("i2c write failed\n"); + return ret; + } + } + return 0; +} + +static int s921_isdb_set_parameters(struct s921_isdb_t *dev, struct s921_isdb_t_transmission_mode_params *params) { + + int ret; + /* auto is sufficient for now, lateron this should be reflected in an extra interface */ + +#if 0 + u8 mod_b2 = 0; + u8 mod_b3 = 0; + u8 mod_b4 = 0; + u8 mod_b5 = 0; + u8 mod_b6 = 0; + u8 mod_b7 = 0; + u8 mod_b8 = 0; + /* LAYER A Setup */ + + switch (params->layer_a_carrier_modulation) { + case ISDB_T_LA_CM_DQPSK: + mod_b3 |= 0<<5; + break; + case ISDB_T_LA_CM_QPSK: + mod_b3 |= 1<<5; + break; + case ISDB_T_LA_CM_16QAM: + mod_b3 |= 2<<5; + break; + case ISDB_T_LA_CM_64QAM: + mod_b3 |= 3<<5; + break; + case ISDB_T_LA_CM_NOLAYER: + mod_b3 |= 7<<5; + break; + default: + printk("invalid carrier modulation\n"); + return -EINVAL; + } + + switch(params->layer_a_code_rate) { + case ISDB_T_LA_CR_1_2: + mod_b3 |= 0<<2; + break; + case ISDB_T_LA_CR_2_3: + mod_b3 |= 1<<2; + break; + case ISDB_T_LA_CR_3_4: + mod_b3 |= 2<<2; + break; + case ISDB_T_LA_CR_5_6: + mod_b3 |= 3<<2; + break; + case ISDB_T_LA_CR_7_8: + mod_b3 |= 4<<2; + break; + default: + printk("invalid coderate\n"); + return -EINVAL; + } + + switch (params->layer_a_mode) { + case ISDB_T_LA_MODE_1: + switch(params->layer_a_time_interleave) { + case ISDB_T_LA_TI_0: + mod_b3 |= 0; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_4: + mod_b3 |= 1; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_8: + mod_b3 |= 2; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_16: + mod_b3 |= 3; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_32: + mod_b3 |= 0; + mod_b4 |= 1<<7; + break; + default: + printk("invalid layer a time interleave\n"); + return -EINVAL; + } + break; + case ISDB_T_LA_MODE_2: + switch(params->layer_a_time_interleave) { + case ISDB_T_LA_TI_0: + mod_b3 |= 0; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_2: + mod_b3 |= 1; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_4: + mod_b3 |= 2; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_8: + mod_b3 |= 3; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_16: + mod_b3 |= 0; + mod_b4 |= 1<<7; + break; + default: + + printk("invalid layer a time interleave\n"); + return -EINVAL; + } + break; + case ISDB_T_LA_MODE_3: + switch(params->layer_a_time_interleave) { + case ISDB_T_LA_TI_0: + mod_b3 |= 0; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_1: + mod_b3 |= 1; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_2: + mod_b3 |= 2; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_4: + mod_b3 |= 3; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_8: + mod_b3 |= 0; + mod_b4 |= 1<<7; + break; + default: + printk("invalid layer a time interleave\n"); + return -EINVAL; + } + break; + default: + printk("invalid layer mode\n"); + return -EINVAL; + } + + + /* LAYER B Setup */ + switch (params->layer_b_carrier_modulation) { + case ISDB_T_LB_CM_DQPSK: + mod_b4 |= 0; + break; + case ISDB_T_LB_CM_QPSK: + mod_b4 |= 1; + break; + case ISDB_T_LB_CM_16QAM: + mod_b4 |= 2; + break; + case ISDB_T_LB_CM_64QAM: + mod_b4 |= 3; + break; + case ISDB_T_LB_CM_NOLAYER: + mod_b4 |= 7; + break; + default: + return -EINVAL; + } + + switch(params->layer_b_code_rate) { + case ISDB_T_LB_CR_1_2: + mod_b5 |= 0<<5; + break; + case ISDB_T_LB_CR_2_3: + mod_b5 |= 1<<5; + break; + case ISDB_T_LB_CR_3_4: + mod_b5 |= 2<<5; + break; + case ISDB_T_LB_CR_5_6: + mod_b5 |= 3<<5; + break; + case ISDB_T_LB_CR_7_8: + mod_b5 |= 4<<5; + break; + case ISDB_T_LB_CR_NOLAYER: + mod_b5 |= 7<<5; + break; + default: + return -EINVAL; + } + + switch (params->layer_b_mode) { + case ISDB_T_LB_MODE_1: + switch(params->layer_b_time_interleave) { + case ISDB_T_LB_TI_0: + mod_b5 |= 0; + break; + case ISDB_T_LB_TI_4: + mod_b5 |= 1<<2; + break; + case ISDB_T_LB_TI_8: + mod_b5 |= 2<<2; + break; + case ISDB_T_LB_TI_16: + mod_b5 |= 3<<2; + break; + case ISDB_T_LB_TI_32: + mod_b5 |= 4<<2; + break; + default: + return -EINVAL; + } + break; + case ISDB_T_LB_MODE_2: + switch(params->layer_b_time_interleave) { + case ISDB_T_LB_TI_0: + mod_b5 |= 0; + break; + case ISDB_T_LB_TI_2: + mod_b5 |= 1<<2; + break; + case ISDB_T_LB_TI_4: + mod_b5 |= 2<<2; + break; + case ISDB_T_LB_TI_8: + mod_b5 |= 3<<2; + break; + case ISDB_T_LB_TI_16: + mod_b5 |= 4<<2; + break; + default: + return -EINVAL; + } + break; + case ISDB_T_LB_MODE_3: + switch(params->layer_b_time_interleave) { + case ISDB_T_LB_TI_0: + mod_b5 |= 0; + break; + case ISDB_T_LB_TI_1: + mod_b5 |= 1<<2; + break; + case ISDB_T_LB_TI_2: + mod_b5 |= 2<<2; + break; + case ISDB_T_LB_TI_4: + mod_b5 |= 3<<2; + break; + case ISDB_T_LB_TI_8: + mod_b5 |= 4<<2; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + /* LAYER C Setup */ + switch (params->layer_c_carrier_modulation) { + case ISDB_T_LC_CM_DQPSK: + mod_b5 |= 0<<3; + break; + case ISDB_T_LC_CM_QPSK: + mod_b5 |= 1<<3; + break; + case ISDB_T_LC_CM_16QAM: + mod_b5 |= 2<<3; + break; + case ISDB_T_LC_CM_64QAM: + mod_b5 |= 3<<3; + break; + case ISDB_T_LC_CM_NOLAYER: + mod_b5 |= 7<<3; + break; + default: + return -EINVAL; + } + + switch(params->layer_c_code_rate) { + case ISDB_T_LC_CR_1_2: + mod_b5 |= 0<<0; + break; + case ISDB_T_LC_CR_2_3: + mod_b5 |= 1<<0; + break; + case ISDB_T_LC_CR_3_4: + mod_b5 |= 2<<0; + break; + case ISDB_T_LC_CR_5_6: + mod_b5 |= 3<<0; + break; + case ISDB_T_LC_CR_7_8: + mod_b5 |= 4<<0; + break; + default: + return -EINVAL; + } + + switch (params->layer_c_mode) { + case ISDB_T_LC_MODE_1: + switch(params->layer_c_time_interleave) { + case ISDB_T_LC_TI_0: + mod_b7 |= 0<<5; + break; + case ISDB_T_LC_TI_4: + mod_b7 |= 1<<5; + break; + case ISDB_T_LC_TI_8: + mod_b7 |= 2<<5; + break; + case ISDB_T_LC_TI_16: + mod_b7 |= 3<<5; + break; + case ISDB_T_LC_TI_32: + mod_b7 |= 4<<5; + break; + default: + return -EINVAL; + } + break; + case ISDB_T_LC_MODE_2: + switch(params->layer_c_time_interleave) { + case ISDB_T_LC_TI_0: + mod_b7 |= 0<<5; + break; + case ISDB_T_LC_TI_2: + mod_b7 |= 1<<5; + break; + case ISDB_T_LC_TI_4: + mod_b7 |= 2<<5; + break; + case ISDB_T_LC_TI_8: + mod_b7 |= 3<<5; + break; + case ISDB_T_LC_TI_16: + mod_b7 |= 4<<5; + break; + default: + return -EINVAL; + } + break; + case ISDB_T_LC_MODE_3: + switch(params->layer_c_time_interleave) { + case ISDB_T_LC_TI_0: + mod_b7 |= 0<<5; + break; + case ISDB_T_LC_TI_1: + mod_b7 |= 1<<5; + break; + case ISDB_T_LC_TI_2: + mod_b7 |= 2<<5; + break; + case ISDB_T_LC_TI_4: + mod_b7 |= 3<<5; + break; + case ISDB_T_LC_TI_8: + mod_b7 |= 4<<5; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } +#endif + + + ret = dev->i2c_write(dev->priv_dev, 0xb0, 0xa0); //mod_b2); + ret = dev->i2c_write(dev->priv_dev, 0xb2, 0x3d); //mod_b2); + + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xb3, 0x25); //mod_b3); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xb4, 0x8b); //mod_b4); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xb5, 0x4b); //mod_b5); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xb6, 0x3f); //mod_b6); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xb7, 0x3f); //mod_b7); + if (ret < 0) + return -EINVAL; + + return E_OK; +} + +static int s921_isdb_tune(struct s921_isdb_t *dev, struct s921_isdb_t_tune_params *params) { + + int ret; + int index; + + index = (params->frequency - 473143000)/6000000; + + if (index > 48) { + return -EINVAL; + } + + dev->i2c_write(dev->priv_dev, 0x47, 0x60); + + ret = dev->i2c_write(dev->priv_dev, 0x68, 0x00); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0x69, 0x89); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf0, 0x48); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf1, 0x19); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf2, c_table[index*3]); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf3, c_table[index*3+1]); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf4, c_table[index*3+2]); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf5, 0xae); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf6, 0xb7); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf7, 0xba); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf8, 0xd7); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0x68, 0x0a); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0x69, 0x09); + if (ret < 0) + return -EINVAL; + + dev->i2c_write(dev->priv_dev, 0x01, 0x40); + return 0; +} + +static int s921_isdb_get_status(struct s921_isdb_t *dev, void *data) { + unsigned int *ret = (unsigned int*)data; + u8 ifagc_dt; + u8 rfagc_dt; + + mdelay(10); + ifagc_dt = dev->i2c_read(dev->priv_dev, 0x81); + rfagc_dt = dev->i2c_read(dev->priv_dev, 0x82); +#if 0 + *ret = dev->i2c_read(dev->priv_dev, 0x82); + printk("status 83: %02x\n", *ret); + *ret = dev->i2c_read(dev->priv_dev, 0x80); + mdelay(10); + *ret = dev->i2c_read(dev->priv_dev, 0x80); + mdelay(10); + *ret = dev->i2c_read(dev->priv_dev, 0x80); +#endif + if (rfagc_dt == 0x40) { + *ret = 1; + } + return 0; +} diff --git a/linux/drivers/media/dvb/frontends/s921_core.h b/linux/drivers/media/dvb/frontends/s921_core.h new file mode 100644 index 000000000..de2f10a44 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/s921_core.h @@ -0,0 +1,114 @@ +#ifndef _S921_CORE_H +#define _S921_CORE_H +//#define u8 unsigned int +//#define u32 unsigned int + + + +//#define EINVAL -1 +#define E_OK 0 + +struct s921_isdb_t { + void *priv_dev; + int (*i2c_write)(void *dev, u8 reg, u8 val); + int (*i2c_read)(void *dev, u8 reg); +}; + +#define ISDB_T_CMD_INIT 0 +#define ISDB_T_CMD_SET_PARAM 1 +#define ISDB_T_CMD_TUNE 2 +#define ISDB_T_CMD_GET_STATUS 3 + +struct s921_isdb_t_tune_params { + u32 frequency; +}; + +struct s921_isdb_t_status { +}; + +struct s921_isdb_t_transmission_mode_params { + u8 mode; + u8 layer_a_mode; +#define ISDB_T_LA_MODE_1 0 +#define ISDB_T_LA_MODE_2 1 +#define ISDB_T_LA_MODE_3 2 + u8 layer_a_carrier_modulation; +#define ISDB_T_LA_CM_DQPSK 0 +#define ISDB_T_LA_CM_QPSK 1 +#define ISDB_T_LA_CM_16QAM 2 +#define ISDB_T_LA_CM_64QAM 3 +#define ISDB_T_LA_CM_NOLAYER 4 + u8 layer_a_code_rate; +#define ISDB_T_LA_CR_1_2 0 +#define ISDB_T_LA_CR_2_3 1 +#define ISDB_T_LA_CR_3_4 2 +#define ISDB_T_LA_CR_5_6 4 +#define ISDB_T_LA_CR_7_8 8 +#define ISDB_T_LA_CR_NOLAYER 16 + u8 layer_a_time_interleave; +#define ISDB_T_LA_TI_0 0 +#define ISDB_T_LA_TI_1 1 +#define ISDB_T_LA_TI_2 2 +#define ISDB_T_LA_TI_4 4 +#define ISDB_T_LA_TI_8 8 +#define ISDB_T_LA_TI_16 16 +#define ISDB_T_LA_TI_32 32 + u8 layer_a_nseg; + + u8 layer_b_mode; +#define ISDB_T_LB_MODE_1 0 +#define ISDB_T_LB_MODE_2 1 +#define ISDB_T_LB_MODE_3 2 + u8 layer_b_carrier_modulation; +#define ISDB_T_LB_CM_DQPSK 0 +#define ISDB_T_LB_CM_QPSK 1 +#define ISDB_T_LB_CM_16QAM 2 +#define ISDB_T_LB_CM_64QAM 3 +#define ISDB_T_LB_CM_NOLAYER 4 + u8 layer_b_code_rate; +#define ISDB_T_LB_CR_1_2 0 +#define ISDB_T_LB_CR_2_3 1 +#define ISDB_T_LB_CR_3_4 2 +#define ISDB_T_LB_CR_5_6 4 +#define ISDB_T_LB_CR_7_8 8 +#define ISDB_T_LB_CR_NOLAYER 16 + u8 layer_b_time_interleave; +#define ISDB_T_LB_TI_0 0 +#define ISDB_T_LB_TI_1 1 +#define ISDB_T_LB_TI_2 2 +#define ISDB_T_LB_TI_4 4 +#define ISDB_T_LB_TI_8 8 +#define ISDB_T_LB_TI_16 16 +#define ISDB_T_LB_TI_32 32 + u8 layer_b_nseg; + + u8 layer_c_mode; +#define ISDB_T_LC_MODE_1 0 +#define ISDB_T_LC_MODE_2 1 +#define ISDB_T_LC_MODE_3 2 + u8 layer_c_carrier_modulation; +#define ISDB_T_LC_CM_DQPSK 0 +#define ISDB_T_LC_CM_QPSK 1 +#define ISDB_T_LC_CM_16QAM 2 +#define ISDB_T_LC_CM_64QAM 3 +#define ISDB_T_LC_CM_NOLAYER 4 + u8 layer_c_code_rate; +#define ISDB_T_LC_CR_1_2 0 +#define ISDB_T_LC_CR_2_3 1 +#define ISDB_T_LC_CR_3_4 2 +#define ISDB_T_LC_CR_5_6 4 +#define ISDB_T_LC_CR_7_8 8 +#define ISDB_T_LC_CR_NOLAYER 16 + u8 layer_c_time_interleave; +#define ISDB_T_LC_TI_0 0 +#define ISDB_T_LC_TI_1 1 +#define ISDB_T_LC_TI_2 2 +#define ISDB_T_LC_TI_4 4 +#define ISDB_T_LC_TI_8 8 +#define ISDB_T_LC_TI_16 16 +#define ISDB_T_LC_TI_32 32 + u8 layer_c_nseg; +}; + +int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data); +#endif diff --git a/linux/drivers/media/dvb/frontends/s921_module.c b/linux/drivers/media/dvb/frontends/s921_module.c new file mode 100644 index 000000000..6018ec505 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/s921_module.c @@ -0,0 +1,254 @@ +/* + * Driver for Sharp s921 driver + * + * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de> + * + * All rights reserved. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/delay.h> +#include "dvb_frontend.h" +#include "s921_module.h" +#include "s921_core.h" + +static unsigned int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug,"s921 debugging (default off)"); + +#define dprintk(fmt, args...) if (debug) do {\ + printk("s921 debug: " fmt, ##args); } while (0) + +struct s921_state +{ + struct dvb_frontend frontend; + fe_modulation_t current_modulation; + __u32 snr; + __u32 current_frequency; + __u8 addr; + struct s921_isdb_t dev; + struct i2c_adapter *i2c; +}; + +static int s921_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) { + struct s921_state *state = (struct s921_state *)fe->demodulator_priv; + struct s921_isdb_t_transmission_mode_params params; + struct s921_isdb_t_tune_params tune_params; + + tune_params.frequency = param->frequency; +#if 0 + struct dvb_ofdm_parameters *op = ¶m->u.ofdm; + + switch (op->bandwidth) { + case BANDWIDTH_6_MHZ: + case BANDWIDTH_7_MHZ: + case BANDWIDTH_8_MHZ: + default: + break; + } + + switch (op->code_rate_HP) { + case FEC_2_3: + case FEC_3_4: + case FEC_5_6: + case FEC_7_8: + case FEC_1_2: + case FEC_AUTO: + break; + default: + break; + } + + switch(op->code_rate_LP) { + case FEC_2_3: + case FEC_3_4: + case FEC_5_6: + case FEC_7_8: + case FEC_1_2: + case FEC_AUTO: + case FEC_NONE: + default: + break; + } + + switch (op->constellation) { + case QPSK: + case QAM_AUTO: + case QAM_16: + default: + break; + } + + switch (op->guard_interval) { + case GUARD_INTERVAL_1_32: + case GUARD_INTERVAL_AUTO: + case GUARD_INTERVAL_1_16: + case GUARD_INTERVAL_1_8: + case GUARD_INTERVAL_1_4: + default: + break; + } + + switch (op->hierarchy_information) { + case HIERARCHY_AUTO: + case HIERARCHY_NONE: + case HIERARCHY_1: + case HIERARCHY_2: + case HIERARCHY_4: + default: + break; + } + +#endif + s921_isdb_cmd(&state->dev, ISDB_T_CMD_SET_PARAM, ¶ms); + s921_isdb_cmd(&state->dev, ISDB_T_CMD_TUNE, &tune_params); + mdelay(100); + return 0; +} + +static int s921_init(struct dvb_frontend *fe) { + printk("s921 init\n"); + return 0; +} + +static int s921_sleep(struct dvb_frontend *fe) { + printk("s921 sleep\n"); + return 0; +} + +static int s921_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct s921_state *state = (struct s921_state *)fe->demodulator_priv; + unsigned int ret; + mdelay(5); + s921_isdb_cmd(&state->dev, ISDB_T_CMD_GET_STATUS, &ret); + *status = 0; + + printk("status: %02x\n", ret); + if (ret == 1) { + *status |= FE_HAS_CARRIER; + *status |= FE_HAS_VITERBI; + *status |= FE_HAS_LOCK; + *status |= FE_HAS_SYNC; + *status |= FE_HAS_SIGNAL; + } + + return 0; +} + +static int s921_read_ber(struct dvb_frontend *fe, __u32 *ber) +{ + dprintk("read ber\n"); + return 0; +} + +static int s921_read_snr(struct dvb_frontend *fe, __u16 *snr) +{ + dprintk("read snr\n"); + return 0; +} + +static int s921_read_ucblocks(struct dvb_frontend *fe, __u32 *ucblocks) +{ + dprintk("read ucblocks\n"); + return 0; +} + +static void s921_release(struct dvb_frontend *fe) +{ + struct s921_state *state = (struct s921_state *)fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops demod_s921={ + .info = { + .name = "SHARP S921", + .type = FE_OFDM, + .frequency_min = 473143000, + .frequency_max = 767143000, + .frequency_stepsize = 6000000, + .frequency_tolerance = 0, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | + FE_CAN_MUTE_TS + }, + .init = s921_init, + .sleep = s921_sleep, + .set_frontend = s921_set_parameters, + .read_snr = s921_read_snr, + .read_ber = s921_read_ber, + .read_status = s921_read_status, + .read_ucblocks = s921_read_ucblocks, + .release = s921_release, +}; + +static int s921_write(void *dev, u8 reg, u8 val) { + struct s921_state *state = dev; + char buf[2]={reg,val}; + int err; + struct i2c_msg i2cmsgs = { + .addr = state->addr, + .flags = 0, + .len = 2, + .buf = buf + }; + + if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) { + printk("%s i2c_transfer error %d\n", __FUNCTION__, err); + if (err < 0) + return err; + else + return -EREMOTEIO; + } + + return 0; +} + +static int s921_read(void *dev, u8 reg) { + struct s921_state *state = dev; + u8 b1; + int ret; + struct i2c_msg msg[2] = { { .addr = state->addr, + .flags = 0, + .buf = ®, .len = 1 }, + { .addr = state->addr, + .flags = I2C_M_RD, + .buf = &b1, .len = 1 } }; + + ret = i2c_transfer(state->i2c, msg, 2); + if (ret != 2) + return ret; + return b1; +} + +struct dvb_frontend* s921_attach(const struct s921_config *config, + struct i2c_adapter *i2c) +{ + + struct s921_state *state; + state = kzalloc(sizeof(struct s921_state), GFP_KERNEL); + memset(state, 0x0, sizeof(struct s921_state)); + + state->addr = config->i2c_address; + state->i2c = i2c; + state->dev.i2c_write = &s921_write; + state->dev.i2c_read = &s921_read; + state->dev.priv_dev = state; + + s921_isdb_cmd(&state->dev, ISDB_T_CMD_INIT, NULL); + + memcpy(&state->frontend.ops, &demod_s921, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; +} + +EXPORT_SYMBOL_GPL(s921_attach); +MODULE_AUTHOR("Markus Rechberger <mrechberger@empiatech.com>"); +MODULE_DESCRIPTION("Sharp S921 ISDB-T 1Seg"); +MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/dvb/frontends/s921_module.h b/linux/drivers/media/dvb/frontends/s921_module.h new file mode 100644 index 000000000..78660424b --- /dev/null +++ b/linux/drivers/media/dvb/frontends/s921_module.h @@ -0,0 +1,49 @@ +/* + * Driver for DVB-T s921 demodulator + * + * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.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.= + */ + +#ifndef S921_MODULE_H +#define S921_MODULE_H + +#include <linux/dvb/frontend.h> +#include "s921_core.h" + +int s921_isdb_init(struct s921_isdb_t *dev); +int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data); + +struct s921_config +{ + /* demodulator's I2C address */ + u8 i2c_address; +}; + +#if defined(CONFIG_DVB_S921) || (defined(CONFIG_DVB_S921_MODULE) && defined(MODULE)) +extern struct dvb_frontend* s921_attach(const struct s921_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend* s921_attach(const struct s921_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_S921 */ + +#endif /* S921_H */ diff --git a/linux/drivers/media/dvb/frontends/zl10353.c b/linux/drivers/media/dvb/frontends/zl10353.c index 11160a3ee..2e449a457 100644 --- a/linux/drivers/media/dvb/frontends/zl10353.c +++ b/linux/drivers/media/dvb/frontends/zl10353.c @@ -225,15 +225,18 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, /* These are extrapolated from the 7 and 8MHz values */ zl10353_single_write(fe, MCLK_RATIO, 0x97); zl10353_single_write(fe, 0x64, 0x34); + zl10353_single_write(fe, 0xcc, 0xdd); break; case BANDWIDTH_7_MHZ: zl10353_single_write(fe, MCLK_RATIO, 0x86); zl10353_single_write(fe, 0x64, 0x35); + zl10353_single_write(fe, 0xcc, 0x73); break; case BANDWIDTH_8_MHZ: default: zl10353_single_write(fe, MCLK_RATIO, 0x75); zl10353_single_write(fe, 0x64, 0x36); + zl10353_single_write(fe, 0xcc, 0x73); } zl10353_calc_nominal_rate(fe, op->bandwidth, &nominal_rate); diff --git a/linux/drivers/media/dvb/ttpci/av7110.c b/linux/drivers/media/dvb/ttpci/av7110.c index 2ef9f030f..b99057a68 100644 --- a/linux/drivers/media/dvb/ttpci/av7110.c +++ b/linux/drivers/media/dvb/ttpci/av7110.c @@ -52,7 +52,7 @@ #include <linux/kthread.h> #include <asm/unaligned.h> #include <asm/byteorder.h> -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28) #include <linux/byteorder/swabb.h> #endif |