diff options
Diffstat (limited to 'drivers/media/dvb')
75 files changed, 4634 insertions, 1005 deletions
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c index df72b4b8ee1..eca602d9b3d 100644 --- a/drivers/media/dvb/bt8xx/bt878.c +++ b/drivers/media/dvb/bt8xx/bt878.c @@ -28,7 +28,6 @@ */ #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/kernel.h> #include <linux/pci.h> #include <asm/io.h> diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h index f685bc12960..d593bc14562 100644 --- a/drivers/media/dvb/bt8xx/bt878.h +++ b/drivers/media/dvb/bt8xx/bt878.h @@ -149,11 +149,10 @@ void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin, void bt878_stop(struct bt878 *bt); #if defined(__powerpc__) /* big-endian */ -extern __inline__ void io_st_le32(volatile unsigned __iomem *addr, unsigned val) +static inline void io_st_le32(volatile unsigned __iomem *addr, unsigned val) { - __asm__ __volatile__("stwbrx %1,0,%2":"=m"(*addr):"r"(val), - "r"(addr)); - __asm__ __volatile__("eieio":::"memory"); + st_le32(addr, val); + eieio(); } #define bmtwrite(dat,adr) io_st_le32((adr),(dat)) diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index 67613eb6fa3..dedd30a8356 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -21,7 +21,6 @@ #include <linux/bitops.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/device.h> diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index 28929b618e2..5a12b567955 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -548,19 +548,19 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct { struct dvb_device *dvbdev = file->private_data; struct cinergyt2 *cinergyt2 = dvbdev->priv; - unsigned int mask = 0; + unsigned int mask = 0; if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem)) return -ERESTARTSYS; poll_wait(file, &cinergyt2->poll_wq, wait); - if (cinergyt2->pending_fe_events != 0) + if (cinergyt2->pending_fe_events != 0) mask |= (POLLIN | POLLRDNORM | POLLPRI); mutex_unlock(&cinergyt2->sem); - return mask; + return mask; } @@ -1008,6 +1008,8 @@ static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state) cinergyt2_sleep(cinergyt2, 1); mutex_unlock(&cinergyt2->sem); + mutex_unlock(&cinergyt2->wq_sem); + return 0; } diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index 5394de2e4ce..f94bc31e3b3 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -24,7 +24,6 @@ #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/poll.h> #include <linux/ioctl.h> #include <linux/wait.h> diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 4fadddb264d..084a508a03d 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -32,11 +32,11 @@ #include <linux/slab.h> #include <linux/list.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/vmalloc.h> #include <linux/delay.h> #include <linux/spinlock.h> #include <linux/sched.h> +#include <linux/kthread.h> #include "dvb_ca_en50221.h" #include "dvb_ringbuffer.h" @@ -140,13 +140,7 @@ struct dvb_ca_private { wait_queue_head_t wait_queue; /* PID of the monitoring thread */ - pid_t thread_pid; - - /* Wait queue used when shutting thread down */ - wait_queue_head_t thread_queue; - - /* Flag indicating when thread should exit */ - unsigned int exit:1; + struct task_struct *thread; /* Flag indicating if the CA device is open */ unsigned int open:1; @@ -902,28 +896,10 @@ static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca) ca->wakeup = 1; mb(); - wake_up_interruptible(&ca->thread_queue); + wake_up_process(ca->thread); } /** - * Used by the CA thread to determine if an early wakeup is necessary - * - * @param ca CA instance. - */ -static int dvb_ca_en50221_thread_should_wakeup(struct dvb_ca_private *ca) -{ - if (ca->wakeup) { - ca->wakeup = 0; - return 1; - } - if (ca->exit) - return 1; - - return 0; -} - - -/** * Update the delay used by the thread. * * @param ca CA instance. @@ -982,7 +958,6 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca) static int dvb_ca_en50221_thread(void *data) { struct dvb_ca_private *ca = data; - char name[15]; int slot; int flags; int status; @@ -991,28 +966,17 @@ static int dvb_ca_en50221_thread(void *data) dprintk("%s\n", __FUNCTION__); - /* setup kernel thread */ - snprintf(name, sizeof(name), "kdvb-ca-%i:%i", ca->dvbdev->adapter->num, ca->dvbdev->id); - - lock_kernel(); - daemonize(name); - sigfillset(¤t->blocked); - unlock_kernel(); - /* choose the correct initial delay */ dvb_ca_en50221_thread_update_delay(ca); /* main loop */ - while (!ca->exit) { + while (!kthread_should_stop()) { /* sleep for a bit */ - if (!ca->wakeup) { - flags = wait_event_interruptible_timeout(ca->thread_queue, - dvb_ca_en50221_thread_should_wakeup(ca), - ca->delay); - if ((flags == -ERESTARTSYS) || ca->exit) { - /* got signal or quitting */ - break; - } + while (!ca->wakeup) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(ca->delay); + if (kthread_should_stop()) + return 0; } ca->wakeup = 0; @@ -1181,10 +1145,6 @@ static int dvb_ca_en50221_thread(void *data) } } - /* completed */ - ca->thread_pid = 0; - mb(); - wake_up_interruptible(&ca->thread_queue); return 0; } @@ -1536,8 +1496,10 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) return -EIO; err = dvb_generic_open(inode, file); - if (err < 0) + if (err < 0) { + module_put(ca->pub->owner); return err; + } for (i = 0; i < ca->slot_count; i++) { @@ -1570,7 +1532,7 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) { struct dvb_device *dvbdev = file->private_data; struct dvb_ca_private *ca = dvbdev->priv; - int err = 0; + int err; dprintk("%s\n", __FUNCTION__); @@ -1582,7 +1544,7 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) module_put(ca->pub->owner); - return 0; + return err; } @@ -1682,9 +1644,6 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, goto error; } init_waitqueue_head(&ca->wait_queue); - ca->thread_pid = 0; - init_waitqueue_head(&ca->thread_queue); - ca->exit = 0; ca->open = 0; ca->wakeup = 0; ca->next_read_slot = 0; @@ -1710,14 +1669,14 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, mb(); /* create a kthread for monitoring this CA device */ - - ret = kernel_thread(dvb_ca_en50221_thread, ca, 0); - - if (ret < 0) { - printk("dvb_ca_init: failed to start kernel_thread (%d)\n", ret); + ca->thread = kthread_run(dvb_ca_en50221_thread, ca, "kdvb-ca-%i:%i", + ca->dvbdev->adapter->num, ca->dvbdev->id); + if (IS_ERR(ca->thread)) { + ret = PTR_ERR(ca->thread); + printk("dvb_ca_init: failed to start kernel_thread (%d)\n", + ret); goto error; } - ca->thread_pid = ret; return 0; error: @@ -1748,17 +1707,7 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) dprintk("%s\n", __FUNCTION__); /* shutdown the thread if there was one */ - if (ca->thread_pid) { - if (kill_proc(ca->thread_pid, 0, 1) == -ESRCH) { - printk("dvb_ca_release adapter %d: thread PID %d already died\n", - ca->dvbdev->adapter->num, ca->thread_pid); - } else { - ca->exit = 1; - mb(); - dvb_ca_en50221_thread_wakeup(ca); - wait_event_interruptible(ca->thread_queue, ca->thread_pid == 0); - } - } + kthread_stop(ca->thread); for (i = 0; i < ca->slot_count; i++) { dvb_ca_en50221_slot_shutdown(ca, i); diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c index cb6987fce26..7959020f931 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/drivers/media/dvb/dvb-core/dvb_demux.c @@ -373,13 +373,10 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) { struct dvb_demux_feed *feed; - struct list_head *pos, *head = &demux->feed_list; u16 pid = ts_pid(buf); int dvr_done = 0; - list_for_each(pos, head) { - feed = list_entry(pos, struct dvb_demux_feed, list_head); - + list_for_each_entry(feed, &demux->feed_list, list_head) { if ((feed->pid != pid) && (feed->pid != 0x2000)) continue; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index b6c7f6610ec..b203640ef1c 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -32,7 +32,6 @@ #include <linux/slab.h> #include <linux/poll.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/list.h> #include <linux/freezer.h> #include <linux/jiffies.h> @@ -43,7 +42,7 @@ #include "dvbdev.h" static int dvb_frontend_debug; -static int dvb_shutdown_timeout = 5; +static int dvb_shutdown_timeout; static int dvb_force_auto_inversion; static int dvb_override_tune_delay; static int dvb_powerdown_on_sleep = 1; @@ -138,7 +137,7 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) dprintk ("%s\n", __FUNCTION__); - if (down_interruptible (&events->sem)) + if (mutex_lock_interruptible (&events->mtx)) return; wp = (events->eventw + 1) % MAX_EVENT; @@ -159,7 +158,7 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) events->eventw = wp; - up (&events->sem); + mutex_unlock(&events->mtx); e->status = status; @@ -197,7 +196,7 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe, return ret; } - if (down_interruptible (&events->sem)) + if (mutex_lock_interruptible (&events->mtx)) return -ERESTARTSYS; memcpy (event, &events->events[events->eventr], @@ -205,7 +204,7 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe, events->eventr = (events->eventr + 1) % MAX_EVENT; - up (&events->sem); + mutex_unlock(&events->mtx); return 0; } @@ -574,10 +573,9 @@ restart: dvb_frontend_swzigzag(fe); } - if (dvb_shutdown_timeout) { - if (dvb_powerdown_on_sleep) - if (fe->ops.set_voltage) - fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF); + if (dvb_powerdown_on_sleep) { + if (fe->ops.set_voltage) + fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF); if (fe->ops.tuner_ops.sleep) { fe->ops.tuner_ops.sleep(fe); if (fe->ops.i2c_gate_ctrl) @@ -697,6 +695,65 @@ static int dvb_frontend_start(struct dvb_frontend *fe) return 0; } +static void dvb_frontend_get_frequeny_limits(struct dvb_frontend *fe, + u32 *freq_min, u32 *freq_max) +{ + *freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min); + + if (fe->ops.info.frequency_max == 0) + *freq_max = fe->ops.tuner_ops.info.frequency_max; + else if (fe->ops.tuner_ops.info.frequency_max == 0) + *freq_max = fe->ops.info.frequency_max; + else + *freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max); + + if (*freq_min == 0 || *freq_max == 0) + printk(KERN_WARNING "DVB: frontend %u frequency limits undefined - fix the driver\n", + fe->dvb->num); +} + +static int dvb_frontend_check_parameters(struct dvb_frontend *fe, + struct dvb_frontend_parameters *parms) +{ + u32 freq_min; + u32 freq_max; + + /* range check: frequency */ + dvb_frontend_get_frequeny_limits(fe, &freq_min, &freq_max); + if ((freq_min && parms->frequency < freq_min) || + (freq_max && parms->frequency > freq_max)) { + printk(KERN_WARNING "DVB: frontend %u frequency %u out of range (%u..%u)\n", + fe->dvb->num, parms->frequency, freq_min, freq_max); + return -EINVAL; + } + + /* range check: symbol rate */ + if (fe->ops.info.type == FE_QPSK) { + if ((fe->ops.info.symbol_rate_min && + parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) || + (fe->ops.info.symbol_rate_max && + parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) { + printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n", + fe->dvb->num, parms->u.qpsk.symbol_rate, + fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max); + return -EINVAL; + } + + } else if (fe->ops.info.type == FE_QAM) { + if ((fe->ops.info.symbol_rate_min && + parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) || + (fe->ops.info.symbol_rate_max && + parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) { + printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n", + fe->dvb->num, parms->u.qam.symbol_rate, + fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max); + return -EINVAL; + } + } + + return 0; +} + static int dvb_frontend_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) { @@ -707,7 +764,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, dprintk ("%s\n", __FUNCTION__); - if (!fe || fepriv->exit) + if (fepriv->exit) return -ENODEV; if ((file->f_flags & O_ACCMODE) == O_RDONLY && @@ -722,6 +779,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, case FE_GET_INFO: { struct dvb_frontend_info* info = parg; memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info)); + dvb_frontend_get_frequeny_limits(fe, &info->frequency_min, &info->frequency_max); /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't * do it, it is done for it. */ @@ -883,6 +941,11 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, case FE_SET_FRONTEND: { struct dvb_frontend_tune_settings fetunesettings; + if (dvb_frontend_check_parameters(fe, parg) < 0) { + err = -EINVAL; + break; + } + memcpy (&fepriv->parameters, parg, sizeof (struct dvb_frontend_parameters)); @@ -992,18 +1055,15 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) dprintk ("%s\n", __FUNCTION__); - if ((ret = dvb_generic_open (inode, file)) < 0) - return ret; - - if (fe->ops.ts_bus_ctrl) { - if ((ret = fe->ops.ts_bus_ctrl (fe, 1)) < 0) { - dvb_generic_release (inode, file); + if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) { + if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0) return ret; - } } - if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + if ((ret = dvb_generic_open (inode, file)) < 0) + goto err1; + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { /* normal tune mode when opened R/W */ fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT; fepriv->tone = -1; @@ -1011,13 +1071,20 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) ret = dvb_frontend_start (fe); if (ret) - dvb_generic_release (inode, file); + goto err2; /* empty event queue */ fepriv->events.eventr = fepriv->events.eventw = 0; } return ret; + +err2: + dvb_generic_release(inode, file); +err1: + if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) + fe->ops.ts_bus_ctrl(fe, 0); + return ret; } static int dvb_frontend_release(struct inode *inode, struct file *file) @@ -1032,16 +1099,18 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) if ((file->f_flags & O_ACCMODE) != O_RDONLY) fepriv->release_jiffies = jiffies; - if (fe->ops.ts_bus_ctrl) - fe->ops.ts_bus_ctrl (fe, 0); - ret = dvb_generic_release (inode, file); - if (dvbdev->users==-1 && fepriv->exit==1) { - fops_put(file->f_op); - file->f_op = NULL; - wake_up(&dvbdev->wait_queue); + if (dvbdev->users == -1) { + if (fepriv->exit == 1) { + fops_put(file->f_op); + file->f_op = NULL; + wake_up(&dvbdev->wait_queue); + } + if (fe->ops.ts_bus_ctrl) + fe->ops.ts_bus_ctrl(fe, 0); } + return ret; } @@ -1080,7 +1149,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb, init_MUTEX (&fepriv->sem); init_waitqueue_head (&fepriv->wait_queue); init_waitqueue_head (&fepriv->events.wait_queue); - init_MUTEX (&fepriv->events.sem); + mutex_init(&fepriv->events.mtx); fe->dvb = dvb; fepriv->inversion = INVERSION_OFF; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index a770a87b9a9..a5262e852c8 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -35,6 +35,7 @@ #include <linux/module.h> #include <linux/errno.h> #include <linux/delay.h> +#include <linux/mutex.h> #include <linux/dvb/frontend.h> @@ -61,6 +62,13 @@ struct dvb_tuner_info { u32 bandwidth_step; }; +struct analog_parameters { + unsigned int frequency; + unsigned int mode; + unsigned int audmode; + u64 std; +}; + struct dvb_tuner_ops { struct dvb_tuner_info info; @@ -71,6 +79,7 @@ struct dvb_tuner_ops { /** This is for simple PLLs - set all parameters in one go. */ int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); + int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p); /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */ int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len); @@ -79,7 +88,9 @@ struct dvb_tuner_ops { int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); #define TUNER_STATUS_LOCKED 1 +#define TUNER_STATUS_STEREO 2 int (*get_status)(struct dvb_frontend *fe, u32 *status); + int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength); /** These are provided seperately from set_params in order to facilitate silicon * tuners which require sophisticated tuning loops, controlling each parameter seperately. */ @@ -142,7 +153,7 @@ struct dvb_fe_events { int eventr; int overflow; wait_queue_head_t wait_queue; - struct semaphore sem; + struct mutex mtx; }; struct dvb_frontend { diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index bdd797071cb..2117377c141 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -357,11 +357,6 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) static unsigned char *ule_where = ule_hist, ule_dump = 0; #endif - if (dev == NULL) { - printk( KERN_ERR "NO netdev struct!\n" ); - return; - } - /* For all TS cells in current buffer. * Appearently, we are called for every single TS cell. */ @@ -800,8 +795,8 @@ static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len, } -static void dvb_net_sec(struct net_device *dev, const u8 *pkt, int -pkt_len) +static void dvb_net_sec(struct net_device *dev, + const u8 *pkt, int pkt_len) { u8 *eth; struct sk_buff *skb; @@ -1446,18 +1441,9 @@ static int dvb_net_close(struct inode *inode, struct file *file) struct dvb_device *dvbdev = file->private_data; struct dvb_net *dvbnet = dvbdev->priv; - if (!dvbdev) - return -ENODEV; - - if ((file->f_flags & O_ACCMODE) == O_RDONLY) { - dvbdev->readers++; - } else { - dvbdev->writers++; - } - - dvbdev->users++; + dvb_generic_release(inode, file); - if(dvbdev->users == 1 && dvbnet->exit==1) { + if(dvbdev->users == 1 && dvbnet->exit == 1) { fops_put(file->f_op); file->f_op = NULL; wake_up(&dvbdev->wait_queue); diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 9ef0c00605e..56231d8edc0 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -25,7 +25,6 @@ #include <linux/errno.h> #include <linux/string.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/slab.h> @@ -59,18 +58,13 @@ static struct class *dvb_class; static struct dvb_device* dvbdev_find_device (int minor) { - struct list_head *entry; + struct dvb_adapter *adap; - list_for_each (entry, &dvb_adapter_list) { - struct list_head *entry0; - struct dvb_adapter *adap; - adap = list_entry (entry, struct dvb_adapter, list_head); - list_for_each (entry0, &adap->device_list) { - struct dvb_device *dev; - dev = list_entry (entry0, struct dvb_device, list_head); + 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; @@ -180,13 +174,10 @@ static int dvbdev_get_free_id (struct dvb_adapter *adap, int type) u32 id = 0; while (id < DVB_MAX_IDS) { - struct list_head *entry; - list_for_each (entry, &adap->device_list) { - struct dvb_device *dev; - dev = list_entry (entry, struct dvb_device, list_head); + struct dvb_device *dev; + list_for_each_entry(dev, &adap->device_list, list_head) if (dev->type == type && dev->id == id) goto skip; - } return id; skip: id++; @@ -200,7 +191,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, { struct dvb_device *dvbdev; struct file_operations *dvbdevfops; - struct class_device *clsdev; + struct device *clsdev; int id; mutex_lock(&dvbdev_register_lock); @@ -242,10 +233,9 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, mutex_unlock(&dvbdev_register_lock); - clsdev = class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR, - nums2minor(adap->num, type, id)), - adap->device, "dvb%d.%s%d", adap->num, - dnames[type], id); + clsdev = device_create(dvb_class, adap->device, + MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), + "dvb%d.%s%d", adap->num, dnames[type], id); if (IS_ERR(clsdev)) { printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n", __FUNCTION__, adap->num, dnames[type], id, PTR_ERR(clsdev)); @@ -266,8 +256,8 @@ void dvb_unregister_device(struct dvb_device *dvbdev) if (!dvbdev) return; - class_device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num, - dvbdev->type, dvbdev->id))); + device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num, + dvbdev->type, dvbdev->id))); list_del (&dvbdev->list_head); kfree (dvbdev->fops); @@ -281,13 +271,10 @@ static int dvbdev_get_free_adapter_num (void) int num = 0; while (num < DVB_MAX_ADAPTERS) { - struct list_head *entry; - list_for_each (entry, &dvb_adapter_list) { - struct dvb_adapter *adap; - adap = list_entry (entry, struct dvb_adapter, list_head); + struct dvb_adapter *adap; + list_for_each_entry(adap, &dvb_adapter_list, list_head) if (adap->num == num) goto skip; - } return num; skip: num++; diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 40e41f2f5af..d73934dd4c5 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -74,6 +74,8 @@ config DVB_USB_DIB0700 select DVB_DIB7000M select DVB_DIB3000MC select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select DVB_TUNER_MT2266 if !DVB_FE_CUSTOMISE + select DVB_TUNER_DIB0070 help Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The USB bridge is also present in devices having the DiB7700 DVB-T-USB diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h index cda3adea24f..4a903ea9589 100644 --- a/drivers/media/dvb/dvb-usb/dib0700.h +++ b/drivers/media/dvb/dvb-usb/dib0700.h @@ -30,17 +30,19 @@ extern int dvb_usb_dib0700_debug; // 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog) // 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1) // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " ) +#define REQUEST_SET_RC 0x11 #define REQUEST_GET_VERSION 0x15 struct dib0700_state { u8 channel_state; u16 mt2060_if1[2]; - + u8 rc_toggle; u8 is_dib7000pc; }; extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val); extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3); +extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen); extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw); extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff); extern struct i2c_algorithm dib0700_i2c_algo; @@ -50,5 +52,4 @@ extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device extern int dib0700_device_count; extern struct dvb_usb_device_properties dib0700_devices[]; extern struct usb_device_id dib0700_usb_id_table[]; - #endif diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index dddf164f269..3ea294eb96b 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -13,6 +13,10 @@ int dvb_usb_dib0700_debug; module_param_named(debug,dvb_usb_dib0700_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS); +static int dvb_usb_dib0700_ir_proto = 1; +module_param(dvb_usb_dib0700_ir_proto, int, 0644); +MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (default), 2=RC6)."); + /* expecting rx buffer: request data[0] data[1] ... data[2] */ static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen) { @@ -32,7 +36,7 @@ static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen) } /* expecting tx buffer: request data[0] ... data[n] (n <= 4) */ -static int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen) +int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen) { u16 index, value; int status; @@ -260,14 +264,29 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) return dib0700_ctrl_wr(adap->dev, b, 4); } +static int dib0700_rc_setup(struct dvb_usb_device *d) +{ + u8 rc_setup[3] = {REQUEST_SET_RC, dvb_usb_dib0700_ir_proto, 0}; + int i = dib0700_ctrl_wr(d, rc_setup, 3); + if (i<0) { + err("ir protocol setup failed"); + return -1; + } + return 0; +} + static int dib0700_probe(struct usb_interface *intf, const struct usb_device_id *id) { int i; + struct dvb_usb_device *dev; for (i = 0; i < dib0700_device_count; i++) - if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, NULL) == 0) + if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, &dev) == 0) + { + dib0700_rc_setup(dev); return 0; + } return -ENODEV; } diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 2208757d901..e8c4a869453 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -4,7 +4,7 @@ * under the terms of the GNU General Public License as published by the Free * Software Foundation, version 2. * - * Copyright (C) 2005-6 DiBcom, SA + * Copyright (C) 2005-7 DiBcom, SA */ #include "dib0700.h" @@ -12,13 +12,19 @@ #include "dib7000m.h" #include "dib7000p.h" #include "mt2060.h" +#include "mt2266.h" +#include "dib0070.h" static int force_lna_activation; module_param(force_lna_activation, int, 0644); MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifyer(s) (LNA), " "if applicable for the device (default: 0=automatic/off)."); -/* Hauppauge Nova-T 500 +struct dib0700_adapter_state { + int (*set_param_save) (struct dvb_frontend *, struct dvb_frontend_parameters *); +}; + +/* Hauppauge Nova-T 500 (aka Bristol) * has a LNA on GPIO0 which is enabled by setting 1 */ static struct mt2060_config bristol_mt2060_config[2] = { { @@ -96,6 +102,321 @@ static int bristol_tuner_attach(struct dvb_usb_adapter *adap) st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; } +/* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */ + +/* MT226x */ +static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = { + { + BAND_UHF, // band_caps + + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup + + 1130, // inv_gain + 21, // time_stabiliz + + 0, // alpha_level + 118, // thlock + + 0, // wbd_inv + 3530, // wbd_ref + 1, // wbd_sel + 0, // wbd_alpha + + 65535, // agc1_max + 33770, // agc1_min + 65535, // agc2_max + 23592, // agc2_min + + 0, // agc1_pt1 + 62, // agc1_pt2 + 255, // agc1_pt3 + 64, // agc1_slope1 + 64, // agc1_slope2 + 132, // agc2_pt1 + 192, // agc2_pt2 + 80, // agc2_slope1 + 80, // agc2_slope2 + + 17, // alpha_mant + 27, // alpha_exp + 23, // beta_mant + 51, // beta_exp + + 1, // perform_agc_softsplit + }, { + BAND_VHF | BAND_LBAND, // band_caps + + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup + + 2372, // inv_gain + 21, // time_stabiliz + + 0, // alpha_level + 118, // thlock + + 0, // wbd_inv + 3530, // wbd_ref + 1, // wbd_sel + 0, // wbd_alpha + + 65535, // agc1_max + 0, // agc1_min + 65535, // agc2_max + 23592, // agc2_min + + 0, // agc1_pt1 + 128, // agc1_pt2 + 128, // agc1_pt3 + 128, // agc1_slope1 + 0, // agc1_slope2 + 128, // agc2_pt1 + 253, // agc2_pt2 + 81, // agc2_slope1 + 0, // agc2_slope2 + + 17, // alpha_mant + 27, // alpha_exp + 23, // beta_mant + 51, // beta_exp + + 1, // perform_agc_softsplit + } +}; + +static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = { + 60000, 30000, // internal, sampling + 1, 8, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass + 0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo + (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k + 0, // ifreq + 20452225, // timf +}; + +static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = { + { .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + + .agc_config_count = 2, + .agc = stk7700d_7000p_mt2266_agc_config, + .bw = &stk7700d_mt2266_pll_config, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + }, + { .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + + .agc_config_count = 2, + .agc = stk7700d_7000p_mt2266_agc_config, + .bw = &stk7700d_mt2266_pll_config, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + } +}; + +static struct mt2266_config stk7700d_mt2266_config[2] = { + { .i2c_address = 0x60 + }, + { .i2c_address = 0x60 + } +}; + +static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (adap->id == 0) { + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + dib7000p_i2c_enumeration(&adap->dev->i2c_adap,2,18,stk7700d_dib7000p_mt2266_config); + } + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), + &stk7700d_dib7000p_mt2266_config[adap->id]); + + return adap->fe == NULL ? -ENODEV : 0; +} + +static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct i2c_adapter *tun_i2c; + tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + return dvb_attach(mt2266_attach, adap->fe, tun_i2c, + &stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0;; +} + +#define DEFAULT_RC_INTERVAL 150 + +static u8 rc_request[] = { REQUEST_POLL_RC, 0 }; + +static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + u8 key[4]; + int i; + struct dvb_usb_rc_key *keymap = d->props.rc_key_map; + struct dib0700_state *st = d->priv; + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + i=dib0700_ctrl_rd(d,rc_request,2,key,4); + if (i<=0) { + err("RC Query Failed"); + return -1; + } + if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0; + if (key[3-1]!=st->rc_toggle) { + for (i=0;i<d->props.rc_key_map_size; i++) { + if (keymap[i].custom == key[3-2] && keymap[i].data == key[3-3]) { + *event = keymap[i].event; + *state = REMOTE_KEY_PRESSED; + st->rc_toggle=key[3-1]; + return 0; + } + } + err("Unknown remote controller key : %2X %2X",(int)key[3-2],(int)key[3-3]); + } + return 0; +} + +static struct dvb_usb_rc_key dib0700_rc_keys[] = { + /* Key codes for the tiny Pinnacle remote*/ + { 0x07, 0x00, KEY_MUTE }, + { 0x07, 0x01, KEY_MENU }, // Pinnacle logo + { 0x07, 0x39, KEY_POWER }, + { 0x07, 0x03, KEY_VOLUMEUP }, + { 0x07, 0x09, KEY_VOLUMEDOWN }, + { 0x07, 0x06, KEY_CHANNELUP }, + { 0x07, 0x0c, KEY_CHANNELDOWN }, + { 0x07, 0x0f, KEY_1 }, + { 0x07, 0x15, KEY_2 }, + { 0x07, 0x10, KEY_3 }, + { 0x07, 0x18, KEY_4 }, + { 0x07, 0x1b, KEY_5 }, + { 0x07, 0x1e, KEY_6 }, + { 0x07, 0x11, KEY_7 }, + { 0x07, 0x21, KEY_8 }, + { 0x07, 0x12, KEY_9 }, + { 0x07, 0x27, KEY_0 }, + { 0x07, 0x24, KEY_SCREEN }, // 'Square' key + { 0x07, 0x2a, KEY_TEXT }, // 'T' key + { 0x07, 0x2d, KEY_REWIND }, + { 0x07, 0x30, KEY_PLAY }, + { 0x07, 0x33, KEY_FASTFORWARD }, + { 0x07, 0x36, KEY_RECORD }, + { 0x07, 0x3c, KEY_STOP }, + { 0x07, 0x3f, KEY_CANCEL }, // '?' key + /* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */ + { 0xeb, 0x01, KEY_POWER }, + { 0xeb, 0x02, KEY_1 }, + { 0xeb, 0x03, KEY_2 }, + { 0xeb, 0x04, KEY_3 }, + { 0xeb, 0x05, KEY_4 }, + { 0xeb, 0x06, KEY_5 }, + { 0xeb, 0x07, KEY_6 }, + { 0xeb, 0x08, KEY_7 }, + { 0xeb, 0x09, KEY_8 }, + { 0xeb, 0x0a, KEY_9 }, + { 0xeb, 0x0b, KEY_VIDEO }, + { 0xeb, 0x0c, KEY_0 }, + { 0xeb, 0x0d, KEY_REFRESH }, + { 0xeb, 0x0f, KEY_EPG }, + { 0xeb, 0x10, KEY_UP }, + { 0xeb, 0x11, KEY_LEFT }, + { 0xeb, 0x12, KEY_OK }, + { 0xeb, 0x13, KEY_RIGHT }, + { 0xeb, 0x14, KEY_DOWN }, + { 0xeb, 0x16, KEY_INFO }, + { 0xeb, 0x17, KEY_RED }, + { 0xeb, 0x18, KEY_GREEN }, + { 0xeb, 0x19, KEY_YELLOW }, + { 0xeb, 0x1a, KEY_BLUE }, + { 0xeb, 0x1b, KEY_CHANNELUP }, + { 0xeb, 0x1c, KEY_VOLUMEUP }, + { 0xeb, 0x1d, KEY_MUTE }, + { 0xeb, 0x1e, KEY_VOLUMEDOWN }, + { 0xeb, 0x1f, KEY_CHANNELDOWN }, + { 0xeb, 0x40, KEY_PAUSE }, + { 0xeb, 0x41, KEY_HOME }, + { 0xeb, 0x42, KEY_MENU }, /* DVD Menu */ + { 0xeb, 0x43, KEY_SUBTITLE }, + { 0xeb, 0x44, KEY_TEXT }, /* Teletext */ + { 0xeb, 0x45, KEY_DELETE }, + { 0xeb, 0x46, KEY_TV }, + { 0xeb, 0x47, KEY_DVD }, + { 0xeb, 0x48, KEY_STOP }, + { 0xeb, 0x49, KEY_VIDEO }, + { 0xeb, 0x4a, KEY_AUDIO }, /* Music */ + { 0xeb, 0x4b, KEY_SCREEN }, /* Pic */ + { 0xeb, 0x4c, KEY_PLAY }, + { 0xeb, 0x4d, KEY_BACK }, + { 0xeb, 0x4e, KEY_REWIND }, + { 0xeb, 0x4f, KEY_FASTFORWARD }, + { 0xeb, 0x54, KEY_PREVIOUS }, + { 0xeb, 0x58, KEY_RECORD }, + { 0xeb, 0x5c, KEY_NEXT }, + + /* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */ + { 0x1e, 0x00, KEY_0 }, + { 0x1e, 0x01, KEY_1 }, + { 0x1e, 0x02, KEY_2 }, + { 0x1e, 0x03, KEY_3 }, + { 0x1e, 0x04, KEY_4 }, + { 0x1e, 0x05, KEY_5 }, + { 0x1e, 0x06, KEY_6 }, + { 0x1e, 0x07, KEY_7 }, + { 0x1e, 0x08, KEY_8 }, + { 0x1e, 0x09, KEY_9 }, + { 0x1e, 0x0a, KEY_KPASTERISK }, + { 0x1e, 0x0b, KEY_RED }, + { 0x1e, 0x0c, KEY_RADIO }, + { 0x1e, 0x0d, KEY_MENU }, + { 0x1e, 0x0e, KEY_GRAVE }, /* # */ + { 0x1e, 0x0f, KEY_MUTE }, + { 0x1e, 0x10, KEY_VOLUMEUP }, + { 0x1e, 0x11, KEY_VOLUMEDOWN }, + { 0x1e, 0x12, KEY_CHANNEL }, + { 0x1e, 0x14, KEY_UP }, + { 0x1e, 0x15, KEY_DOWN }, + { 0x1e, 0x16, KEY_LEFT }, + { 0x1e, 0x17, KEY_RIGHT }, + { 0x1e, 0x18, KEY_VIDEO }, + { 0x1e, 0x19, KEY_AUDIO }, + { 0x1e, 0x1a, KEY_MEDIA }, + { 0x1e, 0x1b, KEY_EPG }, + { 0x1e, 0x1c, KEY_TV }, + { 0x1e, 0x1e, KEY_NEXT }, + { 0x1e, 0x1f, KEY_BACK }, + { 0x1e, 0x20, KEY_CHANNELUP }, + { 0x1e, 0x21, KEY_CHANNELDOWN }, + { 0x1e, 0x24, KEY_LAST }, /* Skip backwards */ + { 0x1e, 0x25, KEY_OK }, + { 0x1e, 0x29, KEY_BLUE}, + { 0x1e, 0x2e, KEY_GREEN }, + { 0x1e, 0x30, KEY_PAUSE }, + { 0x1e, 0x32, KEY_REWIND }, + { 0x1e, 0x34, KEY_FASTFORWARD }, + { 0x1e, 0x35, KEY_PLAY }, + { 0x1e, 0x36, KEY_STOP }, + { 0x1e, 0x37, KEY_RECORD }, + { 0x1e, 0x38, KEY_YELLOW }, + { 0x1e, 0x3b, KEY_GOTO }, + { 0x1e, 0x3d, KEY_POWER }, +}; + /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = { BAND_UHF | BAND_VHF, // band_caps @@ -194,6 +515,7 @@ static struct dibx000_bandwidth_config stk7700p_pll_config = { (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k 60258167, // ifreq 20452225, // timf + 30000000, // xtal }; static struct dib7000m_config stk7700p_dib7000m_config = { @@ -213,6 +535,7 @@ static struct dib7000m_config stk7700p_dib7000m_config = { static struct dib7000p_config stk7700p_dib7000p_config = { .output_mpeg2_in_188_bytes = 1, + .agc_config_count = 1, .agc = &stk7700p_7000p_mt2060_agc_config, .bw = &stk7700p_pll_config, @@ -267,27 +590,245 @@ static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap) st->mt2060_if1[0]) == NULL ? -ENODEV : 0; } +/* DIB7070 generic */ +static struct dibx000_agc_config dib7070_agc_config = { + BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup + + 600, // inv_gain + 10, // time_stabiliz + + 0, // alpha_level + 118, // thlock + + 0, // wbd_inv + 3530, // wbd_ref + 1, // wbd_sel + 5, // wbd_alpha + + 65535, // agc1_max + 0, // agc1_min + + 65535, // agc2_max + 0, // agc2_min + + 0, // agc1_pt1 + 40, // agc1_pt2 + 183, // agc1_pt3 + 206, // agc1_slope1 + 255, // agc1_slope2 + 72, // agc2_pt1 + 152, // agc2_pt2 + 88, // agc2_slope1 + 90, // agc2_slope2 + + 17, // alpha_mant + 27, // alpha_exp + 23, // beta_mant + 51, // beta_exp + + 0, // perform_agc_softsplit +}; + +static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) +{ + return dib7000p_set_gpio(fe, 8, 0, !onoff); +} + +static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + return dib7000p_set_gpio(fe, 9, 0, onoff); +} + +static struct dib0070_config dib7070p_dib0070_config[2] = { + { + .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, + .reset = dib7070_tuner_reset, + .sleep = dib7070_tuner_sleep, + .clock_khz = 12000, + .clock_pad_drive = 4 + }, { + .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, + .reset = dib7070_tuner_reset, + .sleep = dib7070_tuner_sleep, + .clock_khz = 12000, + + } +}; + +static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + + u16 offset; + u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + switch (band) { + case BAND_VHF: offset = 950; break; + case BAND_UHF: + default: offset = 550; break; + } + deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe)); + dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); + return state->set_param_save(fe, fep); +} + +static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + + if (adap->id == 0) { + if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[0]) == NULL) + return -ENODEV; + } else { + if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[1]) == NULL) + return -ENODEV; + } + + st->set_param_save = adap->fe->ops.tuner_ops.set_params; + adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override; + return 0; +} + +static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { + 60000, 15000, // internal, sampling + 1, 20, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass + 0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo + (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k + (0 << 25) | 0, // ifreq = 0.000000 MHz + 20452225, // timf + 12000000, // xtal_hz +}; + +static struct dib7000p_config dib7070p_dib7000p_config = { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, +}; + +/* STK7070P */ +static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, &dib7070p_dib7000p_config); + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &dib7070p_dib7000p_config); + return adap->fe == NULL ? -ENODEV : 0; +} + +/* STK7070PD */ +static struct dib7000p_config stk7070pd_dib7000p_config[2] = { + { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + }, { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + } +}; + +static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, stk7070pd_dib7000p_config); + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]); + return adap->fe == NULL ? -ENODEV : 0; +} + +static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap) +{ + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]); + return adap->fe == NULL ? -ENODEV : 0; +} + +/* DVB-USB and USB stuff follows */ struct usb_device_id dib0700_usb_id_table[] = { - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) }, +/* 0 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) }, { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P_PC) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) }, - { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) }, +/* 5 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) }, { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500) }, { USB_DEVICE(USB_VID_UNIWILL, USB_PID_UNIWILL_STK7700P) }, { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) }, - { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) }, - { } /* Terminating entry */ +/* 10 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV2000E) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700D) }, +/* 15 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070P) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DVB_T_FLASH) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070PD) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) }, + { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) }, +/* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) }, + { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); #define DIB0700_DEFAULT_DEVICE_PROPERTIES \ .caps = DVB_USB_IS_AN_I2C_ADAPTER, \ .usb_ctrl = DEVICE_SPECIFIC, \ - .firmware = "dvb-usb-dib0700-01.fw", \ + .firmware = "dvb-usb-dib0700-03-pre1.fw", \ .download_firmware = dib0700_download_firmware, \ .no_reconnect = 1, \ .size_of_priv = sizeof(struct dib0700_state), \ @@ -321,7 +862,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 6, + .num_device_descs = 7, .devices = { { "DiBcom STK7700P reference design", { &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] }, @@ -336,7 +877,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { { NULL }, }, { "Compro Videomate U500", - { &dib0700_usb_id_table[6], NULL }, + { &dib0700_usb_id_table[6], &dib0700_usb_id_table[19] }, { NULL }, }, { "Uniwill STK7700P based (Hama and others)", @@ -346,8 +887,17 @@ struct dvb_usb_device_properties dib0700_devices[] = { { "Leadtek Winfast DTV Dongle (STK7700P based)", { &dib0700_usb_id_table[8], NULL }, { NULL }, + }, + { "AVerMedia AVerTV DVB-T Express", + { &dib0700_usb_id_table[20] }, + { NULL }, } - } + }, + + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_key_map = dib0700_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), + .rc_query = dib0700_rc_query }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, .num_adapters = 2, @@ -371,8 +921,112 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[2], &dib0700_usb_id_table[3], NULL }, { NULL }, }, + }, + + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_key_map = dib0700_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), + .rc_query = dib0700_rc_query + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 2, + .adapter = { + { + .frontend_attach = stk7700d_frontend_attach, + .tuner_attach = stk7700d_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }, { + .frontend_attach = stk7700d_frontend_attach, + .tuner_attach = stk7700d_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + } + }, + + .num_device_descs = 4, + .devices = { + { "Pinnacle PCTV 2000e", + { &dib0700_usb_id_table[11], NULL }, + { NULL }, + }, + { "Terratec Cinergy DT XS Diversity", + { &dib0700_usb_id_table[12], NULL }, + { NULL }, + }, + { "Hauppauge Nova-TD Stick/Elgato Eye-TV Diversity", + { &dib0700_usb_id_table[13], NULL }, + { NULL }, + }, + { "DiBcom STK7700D reference design", + { &dib0700_usb_id_table[14], NULL }, + { NULL }, + }, + }, + + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_key_map = dib0700_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), + .rc_query = dib0700_rc_query + + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .frontend_attach = stk7070p_frontend_attach, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 2, + .devices = { + { "DiBcom STK7070P reference design", + { &dib0700_usb_id_table[15], NULL }, + { NULL }, + }, + { "Pinnacle PCTV DVB-T Flash Stick", + { &dib0700_usb_id_table[16], NULL }, + { NULL }, + }, } - } + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 2, + .adapter = { + { + .frontend_attach = stk7070pd_frontend_attach0, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = sizeof(struct dib0700_adapter_state), + }, { + .frontend_attach = stk7070pd_frontend_attach1, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + + .size_of_priv = sizeof(struct dib0700_adapter_state), + } + }, + + .num_device_descs = 2, + .devices = { + { "DiBcom STK7070PD reference design", + { &dib0700_usb_id_table[17], NULL }, + { NULL }, + }, + { "Pinnacle PCTV Dual DVB-T Diversity Stick", + { &dib0700_usb_id_table[18], NULL }, + { NULL }, + }, + } + }, }; int dib0700_device_count = ARRAY_SIZE(dib0700_devices); diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c index 7dbe1432101..d86cf9bee91 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.c +++ b/drivers/media/dvb/dvb-usb/dtt200u.c @@ -1,5 +1,5 @@ /* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/ - * Typhoon/ Yuan DVB-T USB2.0 receiver. + * Typhoon/ Yuan/ Miglia DVB-T USB2.0 receiver. * * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) * @@ -96,6 +96,7 @@ static struct dvb_usb_device_properties dtt200u_properties; static struct dvb_usb_device_properties wt220u_fc_properties; static struct dvb_usb_device_properties wt220u_properties; static struct dvb_usb_device_properties wt220u_zl0353_properties; +static struct dvb_usb_device_properties wt220u_miglia_properties; static int dtt200u_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -103,7 +104,8 @@ static int dtt200u_usb_probe(struct usb_interface *intf, if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE,NULL) == 0 || dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE,NULL) == 0 || dvb_usb_device_init(intf,&wt220u_fc_properties,THIS_MODULE,NULL) == 0 || - dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0) + dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&wt220u_miglia_properties,THIS_MODULE,NULL) == 0) return 0; return -ENODEV; @@ -119,6 +121,7 @@ static struct usb_device_id dtt200u_usb_table [] = { { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD) }, { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM) }, { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD) }, + { USB_DEVICE(USB_VID_MIGLIA, USB_PID_WT220U_ZAP250_COLD) }, { 0 }, }; MODULE_DEVICE_TABLE(usb, dtt200u_usb_table); @@ -303,6 +306,25 @@ static struct dvb_usb_device_properties wt220u_zl0353_properties = { } }; +static struct dvb_usb_device_properties wt220u_miglia_properties = { + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-wt220u-miglia-01.fw", + + .num_adapters = 1, + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { .name = "WideView WT-220U PenType Receiver (Miglia)", + .cold_ids = { &dtt200u_usb_table[9], NULL }, + /* This device turns into WT220U_ZL0353_WARM when fw + has been uploaded */ + .warm_ids = { NULL }, + }, + { NULL }, + } +}; + /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver dtt200u_usb_driver = { .name = "dvb_usb_dtt200u", @@ -333,6 +355,6 @@ module_init(dtt200u_usb_module_init); module_exit(dtt200u_usb_module_exit); MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>"); -MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D DVB-T USB2.0 devices"); +MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D/Miglia DVB-T USB2.0 devices"); MODULE_VERSION("1.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 4dfab02a8a0..4fa3e895028 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -12,7 +12,7 @@ /* Vendor IDs */ #define USB_VID_ADSTECH 0x06e1 #define USB_VID_AFATECH 0x15a4 -#define USB_VID_ALCOR_MICRO 0x058f +#define USB_VID_ALCOR_MICRO 0x058f #define USB_VID_ALINK 0x05e3 #define USB_VID_ANCHOR 0x0547 #define USB_VID_ANUBIS_ELECTRONIC 0x10fd @@ -34,6 +34,7 @@ #define USB_VID_LEADTEK 0x0413 #define USB_VID_LITEON 0x04ca #define USB_VID_MEDION 0x1660 +#define USB_VID_MIGLIA 0x18f3 #define USB_VID_MSI 0x0db0 #define USB_VID_OPERA1 0x695c #define USB_VID_PINNACLE 0x2304 @@ -58,6 +59,7 @@ #define USB_PID_COMPRO_DVBU2000_UNK_COLD 0x010c #define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d #define USB_PID_COMPRO_VIDEOMATE_U500 0x1e78 +#define USB_PID_COMPRO_VIDEOMATE_U500_PC 0x1e80 #define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064 #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065 #define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8 @@ -66,6 +68,9 @@ #define USB_PID_DIBCOM_MOD3001_WARM 0x0bc7 #define USB_PID_DIBCOM_STK7700P 0x1e14 #define USB_PID_DIBCOM_STK7700P_PC 0x1e78 +#define USB_PID_DIBCOM_STK7700D 0x1ef0 +#define USB_PID_DIBCOM_STK7070P 0x1ebc +#define USB_PID_DIBCOM_STK7070PD 0x1ebe #define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 #define USB_PID_DPOSH_M9206_COLD 0x9206 #define USB_PID_DPOSH_M9206_WARM 0xa090 @@ -115,8 +120,17 @@ #define USB_PID_HAUPPAUGE_NOVA_T_500_2 0x9950 #define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060 +#define USB_PID_HAUPPAUGE_NOVA_TD_STICK 0x9580 +#define USB_PID_AVERMEDIA_EXPRESS 0xb568 #define USB_PID_AVERMEDIA_VOLAR 0xa807 #define USB_PID_AVERMEDIA_VOLAR_2 0xb808 +#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a +#define USB_PID_PINNACLE_PCTV2000E 0x022c +#define USB_PID_PINNACLE_PCTV_DVB_T_FLASH 0x0228 +#define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T 0x0229 +#define USB_PID_PCTV_200E 0x020e +#define USB_PID_PCTV_400E 0x020f +#define USB_PID_PCTV_450E 0x0222 #define USB_PID_NEBULA_DIGITV 0x0201 #define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820 #define USB_PID_DVICO_BLUEBIRD_LG064F_COLD 0xd500 @@ -136,9 +150,6 @@ #define USB_PID_MSI_MEGASKY580_55801 0x5581 #define USB_PID_KYE_DVB_T_COLD 0x701e #define USB_PID_KYE_DVB_T_WARM 0x701f -#define USB_PID_PCTV_200E 0x020e -#define USB_PID_PCTV_400E 0x020f -#define USB_PID_PCTV_450E 0x0222 #define USB_PID_LITEON_DVB_T_COLD 0xf000 #define USB_PID_LITEON_DVB_T_WARM 0xf001 #define USB_PID_DIGIVOX_MINI_SL_COLD 0xe360 @@ -148,8 +159,11 @@ #define USB_PID_WINFAST_DTV_DONGLE_COLD 0x6025 #define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00 -#define USB_PID_GENPIX_8PSK_COLD 0x0200 -#define USB_PID_GENPIX_8PSK_WARM 0x0201 +#define USB_PID_GENPIX_8PSK_REV_1_COLD 0x0200 +#define USB_PID_GENPIX_8PSK_REV_1_WARM 0x0201 +#define USB_PID_GENPIX_8PSK_REV_2 0x0202 +#define USB_PID_GENPIX_SKYWALKER_1 0x0203 +#define USB_PID_GENPIX_SKYWALKER_CW3K 0x0204 #define USB_PID_SIGMATEK_DVB_110 0x6610 #define USB_PID_MSI_DIGI_VOX_MINI_II 0x1513 #define USB_PID_OPERA1_COLD 0x2830 diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c index ffdde83d1e7..cdd717c3fe4 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c @@ -24,7 +24,7 @@ MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0 static int dvb_usb_force_pid_filter_usage; module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444); -MODULE_PARM_DESC(disable_rc_polling, "force all dvb-usb-devices to use a PID filter, if any (default: 0)."); +MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID filter, if any (default: 0)."); static int dvb_usb_adapter_init(struct dvb_usb_device *d) { diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c index 6ccbdc9cd77..e37142d9271 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk-fe.c +++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c @@ -1,7 +1,8 @@ /* DVB USB compliant Linux driver for the - * - GENPIX 8pks/qpsk USB2.0 DVB-S module + * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module * - * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com) * * Thanks to GENPIX for the sample code used to implement this module. * @@ -17,27 +18,39 @@ struct gp8psk_fe_state { struct dvb_frontend fe; - struct dvb_usb_device *d; - + u8 lock; u16 snr; - - unsigned long next_snr_check; + unsigned long next_status_check; + unsigned long status_check_interval; }; +static int gp8psk_fe_update_status(struct gp8psk_fe_state *st) +{ + u8 buf[6]; + if (time_after(jiffies,st->next_status_check)) { + gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0,0,&st->lock,1); + gp8psk_usb_in_op(st->d, GET_SIGNAL_STRENGTH, 0,0,buf,6); + st->snr = (buf[1]) << 8 | buf[0]; + st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000; + } + return 0; +} + static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) { struct gp8psk_fe_state *st = fe->demodulator_priv; - u8 lock; + gp8psk_fe_update_status(st); - if (gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0, 0, &lock,1)) - return -EINVAL; - - if (lock) + if (st->lock) *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER; else *status = 0; + if (*status & FE_HAS_LOCK) + st->status_check_interval = 1000; + else + st->status_check_interval = 100; return 0; } @@ -60,33 +73,29 @@ static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr) { struct gp8psk_fe_state *st = fe->demodulator_priv; - u8 buf[2]; - - if (time_after(jiffies,st->next_snr_check)) { - gp8psk_usb_in_op(st->d,GET_SIGNAL_STRENGTH,0,0,buf,2); - *snr = (int)(buf[1]) << 8 | buf[0]; - /* snr is reported in dBu*256 */ - /* snr / 38.4 ~= 100% strength */ - /* snr * 17 returns 100% strength as 65535 */ - if (*snr <= 3855) - *snr = (*snr<<4) + *snr; // snr * 17 - else - *snr = 65535; - st->next_snr_check = jiffies + (10*HZ)/1000; - } else { - *snr = st->snr; - } + gp8psk_fe_update_status(st); + /* snr is reported in dBu*256 */ + *snr = st->snr; return 0; } static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) { - return gp8psk_fe_read_snr(fe, strength); + struct gp8psk_fe_state *st = fe->demodulator_priv; + gp8psk_fe_update_status(st); + /* snr is reported in dBu*256 */ + /* snr / 38.4 ~= 100% strength */ + /* snr * 17 returns 100% strength as 65535 */ + if (st->snr > 0xf00) + *strength = 0xffff; + else + *strength = (st->snr << 4) + st->snr; /* snr*17 */ + return 0; } static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) { - tune->min_delay_ms = 800; + tune->min_delay_ms = 200; return 0; } @@ -124,7 +133,9 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe, gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10); - state->next_snr_check = jiffies; + state->lock = 0; + state->next_status_check = jiffies; + state->status_check_interval = 200; return 0; } @@ -190,6 +201,12 @@ static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t volt return 0; } +static int gp8psk_fe_enable_high_lnb_voltage(struct dvb_frontend* fe, long onoff) +{ + struct gp8psk_fe_state* state = fe->demodulator_priv; + return gp8psk_usb_out_op(state->d, USE_EXTRA_VOLT, onoff, 0,NULL,0); +} + static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd) { struct gp8psk_fe_state* state = fe->demodulator_priv; @@ -235,10 +252,10 @@ success: static struct dvb_frontend_ops gp8psk_fe_ops = { .info = { - .name = "Genpix 8psk-USB DVB-S", + .name = "Genpix 8psk-to-USB2 DVB-S", .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, + .frequency_min = 800000, + .frequency_max = 2250000, .frequency_stepsize = 100, .symbol_rate_min = 1000000, .symbol_rate_max = 45000000, @@ -269,4 +286,5 @@ static struct dvb_frontend_ops gp8psk_fe_ops = { .set_tone = gp8psk_fe_set_tone, .set_voltage = gp8psk_fe_set_voltage, .dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd, + .enable_high_lnb_voltage = gp8psk_fe_enable_high_lnb_voltage }; diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c index 518d67fca5e..92147ee3e14 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk.c +++ b/drivers/media/dvb/dvb-usb/gp8psk.c @@ -1,7 +1,8 @@ /* DVB USB compliant Linux driver for the - * - GENPIX 8pks/qpsk USB2.0 DVB-S module + * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module * - * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com) * * Thanks to GENPIX for the sample code used to implement this module. * @@ -40,7 +41,7 @@ int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 } if (ret < 0 || ret != blen) { - warn("usb in operation failed."); + warn("usb in %d operation failed.", req); ret = -EIO; } else ret = 0; @@ -97,10 +98,10 @@ static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d) if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0)) goto out_rel_fw; - info("downloaidng bcm4500 firmware from file '%s'",bcm4500_firmware); + info("downloading bcm4500 firmware from file '%s'",bcm4500_firmware); ptr = fw->data; - buf = kmalloc(512, GFP_KERNEL | GFP_DMA); + buf = kmalloc(64, GFP_KERNEL | GFP_DMA); while (ptr[0] != 0xff) { u16 buflen = ptr[0] + 4; @@ -129,25 +130,34 @@ out_rel_fw: static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) { u8 status, buf; + int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); + if (onoff) { gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1); - if (! (status & 0x01)) /* started */ + if (! (status & bm8pskStarted)) { /* started */ + if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K) + gp8psk_usb_out_op(d, CW3K_INIT, 1, 0, NULL, 0); if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1)) return -EINVAL; + } - if (! (status & 0x02)) /* BCM4500 firmware loaded */ - if(gp8psk_load_bcm4500fw(d)) - return EINVAL; + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + if (! (status & bm8pskFW_Loaded)) /* BCM4500 firmware loaded */ + if(gp8psk_load_bcm4500fw(d)) + return EINVAL; - if (! (status & 0x04)) /* LNB Power */ + if (! (status & bmIntersilOn)) /* LNB Power */ if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0, &buf, 1)) return EINVAL; - /* Set DVB mode */ - if(gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0)) - return -EINVAL; - gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1); + /* Set DVB mode to 1 */ + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + if (gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0)) + return EINVAL; + /* Abort possible TS (if previous tune crashed) */ + if (gp8psk_usb_out_op(d, ARM_TRANSFER, 0, 0, NULL, 0)) + return EINVAL; } else { /* Turn off LNB power */ if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1)) @@ -155,11 +165,28 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) /* Turn off 8psk power */ if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) return -EINVAL; - + if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K) + gp8psk_usb_out_op(d, CW3K_INIT, 0, 0, NULL, 0); } return 0; } +int gp8psk_bcm4500_reload(struct dvb_usb_device *d) +{ + u8 buf; + int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); + /* Turn off 8psk power */ + if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) + return -EINVAL; + /* Turn On 8psk power */ + if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1)) + return -EINVAL; + /* load BCM4500 firmware */ + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + if (gp8psk_load_bcm4500fw(d)) + return EINVAL; + return 0; +} static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { @@ -177,12 +204,22 @@ static struct dvb_usb_device_properties gp8psk_properties; static int gp8psk_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL); + int ret; + struct usb_device *udev = interface_to_usbdev(intf); + ret = dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL); + if (ret == 0) { + info("found Genpix USB device pID = %x (hex)", + le16_to_cpu(udev->descriptor.idProduct)); + } + return ret; } static struct usb_device_id gp8psk_usb_table [] = { - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_COLD) }, - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_WARM) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_COLD) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, { 0 }, }; MODULE_DEVICE_TABLE(usb, gp8psk_usb_table); @@ -213,12 +250,24 @@ static struct dvb_usb_device_properties gp8psk_properties = { .generic_bulk_ctrl_endpoint = 0x01, - .num_device_descs = 1, + .num_device_descs = 4, .devices = { - { .name = "Genpix 8PSK-USB DVB-S USB2.0 receiver", + { .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver", .cold_ids = { &gp8psk_usb_table[0], NULL }, .warm_ids = { &gp8psk_usb_table[1], NULL }, }, + { .name = "Genpix 8PSK-to-USB2 Rev.2 DVB-S receiver", + .cold_ids = { NULL }, + .warm_ids = { &gp8psk_usb_table[2], NULL }, + }, + { .name = "Genpix SkyWalker-1 DVB-S receiver", + .cold_ids = { NULL }, + .warm_ids = { &gp8psk_usb_table[3], NULL }, + }, + { .name = "Genpix SkyWalker-CW3K DVB-S receiver", + .cold_ids = { NULL }, + .warm_ids = { &gp8psk_usb_table[4], NULL }, + }, { NULL }, } }; @@ -253,6 +302,6 @@ module_init(gp8psk_usb_module_init); module_exit(gp8psk_usb_module_exit); MODULE_AUTHOR("Alan Nisota <alannisota@gamil.com>"); -MODULE_DESCRIPTION("Driver for Genpix 8psk-USB DVB-S USB2.0"); -MODULE_VERSION("1.0"); +MODULE_DESCRIPTION("Driver for Genpix 8psk-to-USB2 DVB-S"); +MODULE_VERSION("1.1"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h index 3eba7061011..e83a57506cf 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk.h +++ b/drivers/media/dvb/dvb-usb/gp8psk.h @@ -1,7 +1,8 @@ /* DVB USB compliant Linux driver for the - * - GENPIX 8pks/qpsk USB2.0 DVB-S module + * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module * * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) * * Thanks to GENPIX for the sample code used to implement this module. * @@ -30,21 +31,37 @@ extern int dvb_usb_gp8psk_debug; #define TH_COMMAND_IN 0xC0 #define TH_COMMAND_OUT 0xC1 -/* command bytes */ -#define GET_8PSK_CONFIG 0x80 +/* gp8psk commands */ + +#define GET_8PSK_CONFIG 0x80 /* in */ #define SET_8PSK_CONFIG 0x81 +#define I2C_WRITE 0x83 +#define I2C_READ 0x84 #define ARM_TRANSFER 0x85 #define TUNE_8PSK 0x86 -#define GET_SIGNAL_STRENGTH 0x87 +#define GET_SIGNAL_STRENGTH 0x87 /* in */ #define LOAD_BCM4500 0x88 -#define BOOT_8PSK 0x89 -#define START_INTERSIL 0x8A +#define BOOT_8PSK 0x89 /* in */ +#define START_INTERSIL 0x8A /* in */ #define SET_LNB_VOLTAGE 0x8B #define SET_22KHZ_TONE 0x8C #define SEND_DISEQC_COMMAND 0x8D #define SET_DVB_MODE 0x8E #define SET_DN_SWITCH 0x8F -#define GET_SIGNAL_LOCK 0x90 +#define GET_SIGNAL_LOCK 0x90 /* in */ +#define GET_SERIAL_NUMBER 0x93 /* in */ +#define USE_EXTRA_VOLT 0x94 +#define CW3K_INIT 0x9d + +/* PSK_configuration bits */ +#define bm8pskStarted 0x01 +#define bm8pskFW_Loaded 0x02 +#define bmIntersilOn 0x04 +#define bmDVBmode 0x08 +#define bm22kHz 0x10 +#define bmSEL18V 0x20 +#define bmDCtuned 0x40 +#define bmArmed 0x80 /* Satellite modulation modes */ #define ADV_MOD_DVB_QPSK 0 /* DVB-S QPSK */ @@ -75,5 +92,6 @@ extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d); extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); +extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d); #endif diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 69a46b3607a..5bbd2d5192f 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -159,7 +159,7 @@ static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } - for (i = 0; i < sizeof(vp7045_rc_keys)/sizeof(struct dvb_usb_rc_key); i++) + for (i = 0; i < ARRAY_SIZE(vp7045_rc_keys); i++) if (vp7045_rc_keys[i].data == key) { *state = REMOTE_KEY_PRESSED; *event = vp7045_rc_keys[i].event; diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index ff448761dce..59b9ed1f1ae 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -283,6 +283,14 @@ config DVB_LGDT330X 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 + default m if DVB_FE_CUSTOMISE + help + An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want + to support this frontend. + comment "Tuners/PLL support" depends on DVB_CORE @@ -291,7 +299,7 @@ config DVB_PLL depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help - This module driver a number of tuners based on PLL chips with a + This module drives a number of tuners based on PLL chips with a common I2C interface. Say Y when you want to support these tuners. config DVB_TDA826X @@ -322,6 +330,29 @@ config DVB_TUNER_MT2060 help A driver for the silicon IF tuner MT2060 from Microtune. +config DVB_TUNER_MT2266 + tristate "Microtune MT2266 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon baseband tuner MT2266 from Microtune. + +config DVB_TUNER_MT2131 + tristate "Microtune MT2131 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon baseband tuner MT2131 from Microtune. + +config DVB_TUNER_DIB0070 + tristate "DiBcom DiB0070 silicon base-band tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon baseband tuner DiB0070 from DiBcom. + This device is only used inside a SiP called togther with a + demodulator for now. + comment "Miscellaneous devices" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 156b062e02c..4b8ad1f132a 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -40,5 +40,9 @@ obj-$(CONFIG_DVB_TDA10086) += tda10086.o obj-$(CONFIG_DVB_TDA826X) += tda826x.o obj-$(CONFIG_DVB_TDA827X) += tda827x.o obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o +obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o +obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o +obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o +obj-$(CONFIG_DVB_S5H1409) += s5h1409.o diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c index baeb311de89..a913f49c062 100644 --- a/drivers/media/dvb/frontends/bcm3510.c +++ b/drivers/media/dvb/frontends/bcm3510.c @@ -33,7 +33,6 @@ #include <linux/init.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/device.h> #include <linux/firmware.h> #include <linux/jiffies.h> diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c index 13ad1bfae66..11a4968f18c 100644 --- a/drivers/media/dvb/frontends/cx22700.c +++ b/drivers/media/dvb/frontends/cx22700.c @@ -23,7 +23,6 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/string.h> #include <linux/slab.h> #include "dvb_frontend.h" diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c index 10fc0c8316d..b03d8283c37 100644 --- a/drivers/media/dvb/frontends/cx24110.c +++ b/drivers/media/dvb/frontends/cx24110.c @@ -25,7 +25,6 @@ #include <linux/slab.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/init.h> #include "dvb_frontend.h" diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c index 0834c0677fe..d74fdbd6336 100644 --- a/drivers/media/dvb/frontends/cx24123.c +++ b/drivers/media/dvb/frontends/cx24123.c @@ -23,7 +23,6 @@ #include <linux/slab.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/init.h> #include "dvb_frontend.h" diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c new file mode 100644 index 00000000000..481eaa68415 --- /dev/null +++ b/drivers/media/dvb/frontends/dib0070.c @@ -0,0 +1,580 @@ +/* + * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner. + * + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) + * + * 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, version 2. + */ +#include <linux/kernel.h> +#include <linux/i2c.h> + +#include "dvb_frontend.h" + +#include "dib0070.h" +#include "dibx000_common.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); + +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB0070: "); printk(args); printk("\n"); } } while (0) + +#define DIB0070_P1D 0x00 +#define DIB0070_P1F 0x01 +#define DIB0070_P1G 0x03 +#define DIB0070S_P1A 0x02 + +struct dib0070_state { + struct i2c_adapter *i2c; + struct dvb_frontend *fe; + const struct dib0070_config *cfg; + u16 wbd_ff_offset; + u8 revision; +}; + +static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg) +{ + u8 b[2]; + struct i2c_msg msg[2] = { + { .addr = state->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2 }, + }; + if (i2c_transfer(state->i2c, msg, 2) != 2) { + printk(KERN_WARNING "DiB0070 I2C read failed\n"); + return 0; + } + return (b[0] << 8) | b[1]; +} + +static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) +{ + u8 b[3] = { reg, val >> 8, val & 0xff }; + struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = b, .len = 3 }; + if (i2c_transfer(state->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "DiB0070 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +#define HARD_RESET(state) do { if (state->cfg->reset) { state->cfg->reset(state->fe,1); msleep(10); state->cfg->reset(state->fe,0); msleep(10); } } while (0) + +static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) +{ + struct dib0070_state *st = fe->tuner_priv; + u16 tmp = 0; + tmp = dib0070_read_reg(st, 0x02) & 0x3fff; + + switch(BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)) { + case 8000: + tmp |= (0 << 14); + break; + case 7000: + tmp |= (1 << 14); + break; + case 6000: + tmp |= (2 << 14); + break; + case 5000: + default: + tmp |= (3 << 14); + break; + } + dib0070_write_reg(st, 0x02, tmp); + return 0; +} + +static void dib0070_captrim(struct dib0070_state *st, u16 LO4) +{ + int8_t captrim, fcaptrim, step_sign, step; + u16 adc, adc_diff = 3000; + + + + dib0070_write_reg(st, 0x0f, 0xed10); + dib0070_write_reg(st, 0x17, 0x0034); + + dib0070_write_reg(st, 0x18, 0x0032); + msleep(2); + + step = captrim = fcaptrim = 64; + + do { + step /= 2; + dib0070_write_reg(st, 0x14, LO4 | captrim); + msleep(1); + adc = dib0070_read_reg(st, 0x19); + + dprintk( "CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", captrim, adc, (u32) adc*(u32)1800/(u32)1024); + + if (adc >= 400) { + adc -= 400; + step_sign = -1; + } else { + adc = 400 - adc; + step_sign = 1; + } + + if (adc < adc_diff) { + dprintk( "CAPTRIM=%hd is closer to target (%hd/%hd)", captrim, adc, adc_diff); + adc_diff = adc; + fcaptrim = captrim; + + + + } + captrim += (step_sign * step); + } while (step >= 1); + + dib0070_write_reg(st, 0x14, LO4 | fcaptrim); + dib0070_write_reg(st, 0x18, 0x07ff); +} + +#define LPF 100 // define for the loop filter 100kHz by default 16-07-06 +#define LO4_SET_VCO_HFDIV(l, v, h) l |= ((v) << 11) | ((h) << 7) +#define LO4_SET_SD(l, s) l |= ((s) << 14) | ((s) << 12) +#define LO4_SET_CTRIM(l, c) l |= (c) << 10 +static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) +{ + struct dib0070_state *st = fe->tuner_priv; + u32 freq = ch->frequency/1000 + (BAND_OF_FREQUENCY(ch->frequency/1000) == BAND_VHF ? st->cfg->freq_offset_khz_vhf : st->cfg->freq_offset_khz_uhf); + + u8 band = BAND_OF_FREQUENCY(freq), c; + + /*******************VCO***********************************/ + u16 lo4 = 0; + + u8 REFDIV, PRESC = 2; + u32 FBDiv, Rest, FREF, VCOF_kHz; + u16 Num, Den; + /*******************FrontEnd******************************/ + u16 value = 0; + + dprintk( "Tuning for Band: %hd (%d kHz)", band, freq); + + + dib0070_write_reg(st, 0x17, 0x30); + + dib0070_set_bandwidth(fe, ch); /* c is used as HF */ + switch (st->revision) { + case DIB0070S_P1A: + switch (band) { + case BAND_LBAND: + LO4_SET_VCO_HFDIV(lo4, 1, 1); + c = 2; + break; + case BAND_SBAND: + LO4_SET_VCO_HFDIV(lo4, 0, 0); + LO4_SET_CTRIM(lo4, 1);; + c = 1; + break; + case BAND_UHF: + default: + if (freq < 570000) { + LO4_SET_VCO_HFDIV(lo4, 1, 3); + PRESC = 6; c = 6; + } else if (freq < 680000) { + LO4_SET_VCO_HFDIV(lo4, 0, 2); + c = 4; + } else { + LO4_SET_VCO_HFDIV(lo4, 1, 2); + c = 4; + } + break; + } break; + + case DIB0070_P1G: + case DIB0070_P1F: + default: + switch (band) { + case BAND_FM: + LO4_SET_VCO_HFDIV(lo4, 0, 7); + c = 24; + break; + case BAND_LBAND: + LO4_SET_VCO_HFDIV(lo4, 1, 0); + c = 2; + break; + case BAND_VHF: + if (freq < 180000) { + LO4_SET_VCO_HFDIV(lo4, 0, 3); + c = 16; + } else if (freq < 190000) { + LO4_SET_VCO_HFDIV(lo4, 1, 3); + c = 16; + } else { + LO4_SET_VCO_HFDIV(lo4, 0, 6); + c = 12; + } + break; + + case BAND_UHF: + default: + if (freq < 570000) { + LO4_SET_VCO_HFDIV(lo4, 1, 5); + c = 6; + } else if (freq < 700000) { + LO4_SET_VCO_HFDIV(lo4, 0, 1); + c = 4; + } else { + LO4_SET_VCO_HFDIV(lo4, 1, 1); + c = 4; + } + break; + } + break; + } + + dprintk( "HFDIV code: %hd", (lo4 >> 7) & 0xf); + dprintk( "VCO = %hd", (lo4 >> 11) & 0x3); + + + VCOF_kHz = (c * freq) * 2; + dprintk( "VCOF in kHz: %d ((%hd*%d) << 1))",VCOF_kHz, c, freq); + + switch (band) { + case BAND_VHF: + REFDIV = (u8) ((st->cfg->clock_khz + 9999) / 10000); + break; + case BAND_FM: + REFDIV = (u8) ((st->cfg->clock_khz) / 1000); + break; + default: + REFDIV = (u8) ( st->cfg->clock_khz / 10000); + break; + } + FREF = st->cfg->clock_khz / REFDIV; + + dprintk( "REFDIV: %hd, FREF: %d", REFDIV, FREF); + + + + switch (st->revision) { + case DIB0070S_P1A: + FBDiv = (VCOF_kHz / PRESC / FREF); + Rest = (VCOF_kHz / PRESC) - FBDiv * FREF; + break; + + case DIB0070_P1G: + case DIB0070_P1F: + default: + FBDiv = (freq / (FREF / 2)); + Rest = 2 * freq - FBDiv * FREF; + break; + } + + + if (Rest < LPF) Rest = 0; + else if (Rest < 2 * LPF) Rest = 2 * LPF; + else if (Rest > (FREF - LPF)) { Rest = 0 ; FBDiv += 1; } + else if (Rest > (FREF - 2 * LPF)) Rest = FREF - 2 * LPF; + Rest = (Rest * 6528) / (FREF / 10); + dprintk( "FBDIV: %d, Rest: %d", FBDiv, Rest); + + Num = 0; + Den = 1; + + if (Rest > 0) { + LO4_SET_SD(lo4, 1); + Den = 255; + Num = (u16)Rest; + } + dprintk( "Num: %hd, Den: %hd, SD: %hd",Num, Den, (lo4 >> 12) & 0x1); + + + + dib0070_write_reg(st, 0x11, (u16)FBDiv); + + + dib0070_write_reg(st, 0x12, (Den << 8) | REFDIV); + + + dib0070_write_reg(st, 0x13, Num); + + + value = 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001; + + switch (band) { + case BAND_UHF: value |= 0x4000 | 0x0800; break; + case BAND_LBAND: value |= 0x2000 | 0x0400; break; + default: value |= 0x8000 | 0x1000; break; + } + dib0070_write_reg(st, 0x20, value); + + dib0070_captrim(st, lo4); + if (st->revision == DIB0070S_P1A) { + if (band == BAND_SBAND) + dib0070_write_reg(st, 0x15, 0x16e2); + else + dib0070_write_reg(st, 0x15, 0x56e5); + } + + + + switch (band) { + case BAND_UHF: value = 0x7c82; break; + case BAND_LBAND: value = 0x7c84; break; + default: value = 0x7c81; break; + } + dib0070_write_reg(st, 0x0f, value); + dib0070_write_reg(st, 0x06, 0x3fff); + + /* Front End */ + /* c == TUNE, value = SWITCH */ + c = 0; + value = 0; + switch (band) { + case BAND_FM: + c = 0; value = 1; + break; + + case BAND_VHF: + if (freq <= 180000) c = 0; + else if (freq <= 188200) c = 1; + else if (freq <= 196400) c = 2; + else c = 3; + value = 1; + break; + + case BAND_LBAND: + if (freq <= 1500000) c = 0; + else if (freq <= 1600000) c = 1; + else c = 3; + break; + + case BAND_SBAND: + c = 7; + dib0070_write_reg(st, 0x1d,0xFFFF); + break; + + case BAND_UHF: + default: + if (st->cfg->flip_chip) { + if (freq <= 550000) c = 0; + else if (freq <= 590000) c = 1; + else if (freq <= 666000) c = 3; + else c = 5; + } else { + if (freq <= 550000) c = 2; + else if (freq <= 650000) c = 3; + else if (freq <= 750000) c = 5; + else if (freq <= 850000) c = 6; + else c = 7; + } + value = 2; + break; + } + + /* default: LNA_MATCH=7, BIAS=3 */ + dib0070_write_reg(st, 0x07, (value << 11) | (7 << 8) | (c << 3) | (3 << 0)); + dib0070_write_reg(st, 0x08, (c << 10) | (3 << 7) | (127)); + dib0070_write_reg(st, 0x0d, 0x0d80); + + + dib0070_write_reg(st, 0x18, 0x07ff); + dib0070_write_reg(st, 0x17, 0x0033); + + return 0; +} + +static int dib0070_wakeup(struct dvb_frontend *fe) +{ + struct dib0070_state *st = fe->tuner_priv; + if (st->cfg->sleep) + st->cfg->sleep(fe, 0); + return 0; +} + +static int dib0070_sleep(struct dvb_frontend *fe) +{ + struct dib0070_state *st = fe->tuner_priv; + if (st->cfg->sleep) + st->cfg->sleep(fe, 1); + return 0; +} + +static u16 dib0070_p1f_defaults[] = + +{ + 7, 0x02, + 0x0008, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0002, + 0x0100, + + 3, 0x0d, + 0x0d80, + 0x0001, + 0x0000, + + 4, 0x11, + 0x0000, + 0x0103, + 0x0000, + 0x0000, + + 3, 0x16, + 0x0004 | 0x0040, + 0x0030, + 0x07ff, + + 6, 0x1b, + 0x4112, + 0xff00, + 0xc07f, + 0x0000, + 0x0180, + 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001, + + 0, +}; + +static void dib0070_wbd_calibration(struct dib0070_state *state) +{ + u16 wbd_offs; + dib0070_write_reg(state, 0x0f, 0x6d81); + dib0070_write_reg(state, 0x20, 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001); + msleep(9); + wbd_offs = dib0070_read_reg(state, 0x19); + dib0070_write_reg(state, 0x20, 0); + state->wbd_ff_offset = ((wbd_offs * 8 * 18 / 33 + 1) / 2); + dprintk( "WBDStart = %d (Vargen) - FF = %hd", (u32) wbd_offs * 1800/1024, state->wbd_ff_offset); +} + +u16 dib0070_wbd_offset(struct dvb_frontend *fe) +{ + struct dib0070_state *st = fe->tuner_priv; + return st->wbd_ff_offset; +} + +EXPORT_SYMBOL(dib0070_wbd_offset); +static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt) +{ + struct dib0070_state *state = fe->tuner_priv; + u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0); + dprintk( "CTRL_LO5: 0x%x", lo5); + return dib0070_write_reg(state, 0x15, lo5); +} + +#define pgm_read_word(w) (*w) +static int dib0070_reset(struct dib0070_state *state) +{ + u16 l, r, *n; + + HARD_RESET(state); + + +#ifndef FORCE_SBAND_TUNER + if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1) + state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff; + else +#endif + state->revision = DIB0070S_P1A; + + /* P1F or not */ + dprintk( "Revision: %x", state->revision); + + if (state->revision == DIB0070_P1D) { + dprintk( "Error: this driver is not to be used meant for P1D or earlier"); + return -EINVAL; + } + + n = (u16 *) dib0070_p1f_defaults; + l = pgm_read_word(n++); + while (l) { + r = pgm_read_word(n++); + do { + dib0070_write_reg(state, (u8)r, pgm_read_word(n++)); + r++; + } while (--l); + l = pgm_read_word(n++); + } + + if (state->cfg->force_crystal_mode != 0) + r = state->cfg->force_crystal_mode; + else if (state->cfg->clock_khz >= 24000) + r = 1; + else + r = 2; + + r |= state->cfg->osc_buffer_state << 3; + + dib0070_write_reg(state, 0x10, r); + dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 4)); + + if (state->cfg->invert_iq) { + r = dib0070_read_reg(state, 0x02) & 0xffdf; + dib0070_write_reg(state, 0x02, r | (1 << 5)); + } + + + if (state->revision == DIB0070S_P1A) + dib0070_set_ctrl_lo5(state->fe, 4, 7, 3, 1); + else + dib0070_set_ctrl_lo5(state->fe, 4, 4, 2, 0); + + dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8); + return 0; +} + + +static int dib0070_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static struct dvb_tuner_ops dib0070_ops = { + .info = { + .name = "DiBcom DiB0070", + .frequency_min = 45000000, + .frequency_max = 860000000, + .frequency_step = 1000, + }, + .release = dib0070_release, + + .init = dib0070_wakeup, + .sleep = dib0070_sleep, + .set_params = dib0070_tune_digital, +// .get_frequency = dib0070_get_frequency, +// .get_bandwidth = dib0070_get_bandwidth +}; + +struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg) +{ + struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL); + if (state == NULL) + return NULL; + + state->cfg = cfg; + state->i2c = i2c; + state->fe = fe; + fe->tuner_priv = state; + + if (dib0070_reset(state) != 0) + goto free_mem; + + dib0070_wbd_calibration(state); + + printk(KERN_INFO "DiB0070: successfully identified\n"); + memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = state; + return fe; + +free_mem: + kfree(state); + fe->tuner_priv = NULL; + return NULL; +} +EXPORT_SYMBOL(dib0070_attach); + +MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); +MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/dib0070.h b/drivers/media/dvb/frontends/dib0070.h new file mode 100644 index 00000000000..786e37d3388 --- /dev/null +++ b/drivers/media/dvb/frontends/dib0070.h @@ -0,0 +1,44 @@ +/* + * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner. + * + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) + * + * 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, version 2. + */ +#ifndef DIB0070_H +#define DIB0070_H + +struct dvb_frontend; +struct i2c_adapter; + +#define DEFAULT_DIB0070_I2C_ADDRESS 0x60 + +struct dib0070_config { + u8 i2c_address; + + /* tuner pins controlled externally */ + int (*reset) (struct dvb_frontend *, int); + int (*sleep) (struct dvb_frontend *, int); + + /* offset in kHz */ + int freq_offset_khz_uhf; + int freq_offset_khz_vhf; + + u8 osc_buffer_state; /* 0= normal, 1= tri-state */ + u32 clock_khz; + u8 clock_pad_drive; /* (Drive + 1) * 2mA */ + + u8 invert_iq; /* invert Q - in case I or Q is inverted on the board */ + + u8 force_crystal_mode; /* if == 0 -> decision is made in the driver default: <24 -> 2, >=24 -> 1 */ + + u8 flip_chip; +}; + +extern struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg); +extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, uint8_t open); +extern u16 dib0070_wbd_offset(struct dvb_frontend *); + +#endif diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c index b6adea5ffeb..136b9d2164d 100644 --- a/drivers/media/dvb/frontends/dib3000mb.c +++ b/drivers/media/dvb/frontends/dib3000mb.c @@ -23,7 +23,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/string.h> diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index 054d7e6d966..edae0be063f 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -1,7 +1,7 @@ /* * Driver for DiBcom DiB3000MC/P-demodulator. * - * Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/) + * Copyright (C) 2004-7 DiBcom (http://www.dibcom.fr/) * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) * * This code is partially based on the previous dib3000mc.c . @@ -13,10 +13,6 @@ #include <linux/kernel.h> #include <linux/i2c.h> -//#include <linux/init.h> -//#include <linux/delay.h> -//#include <linux/string.h> -//#include <linux/slab.h> #include "dvb_frontend.h" @@ -26,7 +22,11 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); } } while (0) +static int buggy_sfn_workaround; +module_param(buggy_sfn_workaround, int, 0644); +MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)"); + +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); printk("\n"); } } while (0) struct dib3000mc_state { struct dvb_frontend demod; @@ -42,6 +42,8 @@ struct dib3000mc_state { fe_bandwidth_t current_bandwidth; u16 dev_id; + + u8 sfn_workaround_active :1; }; static u16 dib3000mc_read_word(struct dib3000mc_state *state, u16 reg) @@ -71,7 +73,6 @@ static int dib3000mc_write_word(struct dib3000mc_state *state, u16 reg, u16 val) return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; } - static int dib3000mc_identify(struct dib3000mc_state *state) { u16 value; @@ -92,7 +93,7 @@ static int dib3000mc_identify(struct dib3000mc_state *state) return 0; } -static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, u8 update_offset) +static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u32 bw, u8 update_offset) { u32 timf; @@ -103,7 +104,7 @@ static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, } else timf = state->timf; - timf *= (BW_INDEX_TO_KHZ(bw) / 1000); + timf *= (bw / 1000); if (update_offset) { s16 tim_offs = dib3000mc_read_word(state, 416); @@ -111,17 +112,17 @@ static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, if (tim_offs & 0x2000) tim_offs -= 0x4000; - if (nfft == 0) + if (nfft == TRANSMISSION_MODE_2K) tim_offs *= 4; timf += tim_offs; - state->timf = timf / (BW_INDEX_TO_KHZ(bw) / 1000); + state->timf = timf / (bw / 1000); } dprintk("timf: %d\n", timf); - dib3000mc_write_word(state, 23, timf >> 16); - dib3000mc_write_word(state, 24, timf & 0xffff); + dib3000mc_write_word(state, 23, (u16) (timf >> 16)); + dib3000mc_write_word(state, 24, (u16) (timf ) & 0xffff); return 0; } @@ -209,31 +210,30 @@ static int dib3000mc_set_output_mode(struct dib3000mc_state *state, int mode) return ret; } -static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw) +static int dib3000mc_set_bandwidth(struct dib3000mc_state *state, u32 bw) { - struct dib3000mc_state *state = demod->demodulator_priv; u16 bw_cfg[6] = { 0 }; u16 imp_bw_cfg[3] = { 0 }; u16 reg; /* settings here are for 27.7MHz */ switch (bw) { - case BANDWIDTH_8_MHZ: + case 8000: bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20; imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7; break; - case BANDWIDTH_7_MHZ: + case 7000: bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7; imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0; break; - case BANDWIDTH_6_MHZ: + case 6000: bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5; imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089; break; - case 255 /* BANDWIDTH_5_MHZ */: + case 5000: bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500; imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072; break; @@ -257,7 +257,7 @@ static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw) dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]); // Timing configuration - dib3000mc_set_timing(state, 0, bw, 0); + dib3000mc_set_timing(state, TRANSMISSION_MODE_2K, bw, 0); return 0; } @@ -276,7 +276,7 @@ static void dib3000mc_set_impulse_noise(struct dib3000mc_state *state, u8 mode, for (i = 58; i < 87; i++) dib3000mc_write_word(state, i, impulse_noise_val[i-58]); - if (nfft == 1) { + if (nfft == TRANSMISSION_MODE_8K) { dib3000mc_write_word(state, 58, 0x3b); dib3000mc_write_word(state, 84, 0x00); dib3000mc_write_word(state, 85, 0x8200); @@ -376,7 +376,7 @@ static int dib3000mc_init(struct dvb_frontend *demod) // P_search_maxtrial=1 dib3000mc_write_word(state, 5, 1); - dib3000mc_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ); + dib3000mc_set_bandwidth(state, 8000); // div_lock_mask dib3000mc_write_word(state, 4, 0x814); @@ -397,7 +397,7 @@ static int dib3000mc_init(struct dvb_frontend *demod) dib3000mc_write_word(state, 180, 0x2FF0); // Impulse noise configuration - dib3000mc_set_impulse_noise(state, 0, 1); + dib3000mc_set_impulse_noise(state, 0, TRANSMISSION_MODE_8K); // output mode set-up dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z); @@ -423,13 +423,13 @@ static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam) { u16 cfg[4] = { 0 },reg; switch (qam) { - case 0: + case QPSK: cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0; break; - case 1: + case QAM_16: cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0; break; - case 2: + case QAM_64: cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8; break; } @@ -437,11 +437,11 @@ static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam) dib3000mc_write_word(state, reg, cfg[reg - 129]); } -static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx000_ofdm_channel *chan, u16 seq) +static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_frontend_parameters *ch, u16 seq) { - u16 tmp; - - dib3000mc_set_timing(state, chan->nfft, chan->Bw, 0); + u16 value; + dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 0); // if (boost) // dib3000mc_write_word(state, 100, (11 << 6) + 6); @@ -455,7 +455,7 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx dib3000mc_write_word(state, 26, 0x6680); dib3000mc_write_word(state, 29, 0x1273); dib3000mc_write_word(state, 33, 5); - dib3000mc_set_adp_cfg(state, 1); + dib3000mc_set_adp_cfg(state, QAM_16); dib3000mc_write_word(state, 133, 15564); dib3000mc_write_word(state, 12 , 0x0); @@ -470,52 +470,98 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx dib3000mc_write_word(state, 97,0); dib3000mc_write_word(state, 98,0); - dib3000mc_set_impulse_noise(state, 0, chan->nfft); - - tmp = ((chan->nfft & 0x1) << 7) | (chan->guard << 5) | (chan->nqam << 3) | chan->vit_alpha; - dib3000mc_write_word(state, 0, tmp); + dib3000mc_set_impulse_noise(state, 0, ch->u.ofdm.transmission_mode); + value = 0; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= (0 << 7); break; + default: + case TRANSMISSION_MODE_8K: value |= (1 << 7); break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_32: value |= (0 << 5); break; + case GUARD_INTERVAL_1_16: value |= (1 << 5); break; + case GUARD_INTERVAL_1_4: value |= (3 << 5); break; + default: + case GUARD_INTERVAL_1_8: value |= (2 << 5); break; + } + switch (ch->u.ofdm.constellation) { + case QPSK: value |= (0 << 3); break; + case QAM_16: value |= (1 << 3); break; + default: + case QAM_64: value |= (2 << 3); break; + } + switch (HIERARCHY_1) { + case HIERARCHY_2: value |= 2; break; + case HIERARCHY_4: value |= 4; break; + default: + case HIERARCHY_1: value |= 1; break; + } + dib3000mc_write_word(state, 0, value); dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4)); - tmp = (chan->vit_hrch << 4) | (chan->vit_select_hp); - if (!chan->vit_hrch || (chan->vit_hrch && chan->vit_select_hp)) - tmp |= chan->vit_code_rate_hp << 1; - else - tmp |= chan->vit_code_rate_lp << 1; - dib3000mc_write_word(state, 181, tmp); + value = 0; + if (ch->u.ofdm.hierarchy_information == 1) + value |= (1 << 4); + if (1 == 1) + value |= 1; + switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + case FEC_2_3: value |= (2 << 1); break; + case FEC_3_4: value |= (3 << 1); break; + case FEC_5_6: value |= (5 << 1); break; + case FEC_7_8: value |= (7 << 1); break; + default: + case FEC_1_2: value |= (1 << 1); break; + } + dib3000mc_write_word(state, 181, value); - // diversity synchro delay - tmp = dib3000mc_read_word(state, 180) & 0x000f; - tmp |= ((chan->nfft == 0) ? 64 : 256) * ((1 << (chan->guard)) * 3 / 2) << 4; // add 50% SFN margin - dib3000mc_write_word(state, 180, tmp); + // diversity synchro delay add 50% SFN margin + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_8K: value = 256; break; + case TRANSMISSION_MODE_2K: + default: value = 64; break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_16: value *= 2; break; + case GUARD_INTERVAL_1_8: value *= 4; break; + case GUARD_INTERVAL_1_4: value *= 8; break; + default: + case GUARD_INTERVAL_1_32: value *= 1; break; + } + value <<= 4; + value |= dib3000mc_read_word(state, 180) & 0x000f; + dib3000mc_write_word(state, 180, value); // restart demod - tmp = dib3000mc_read_word(state, 0); - dib3000mc_write_word(state, 0, tmp | (1 << 9)); - dib3000mc_write_word(state, 0, tmp); + value = dib3000mc_read_word(state, 0); + dib3000mc_write_word(state, 0, value | (1 << 9)); + dib3000mc_write_word(state, 0, value); msleep(30); - dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, chan->nfft); + dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->u.ofdm.transmission_mode); } -static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *chan) +static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *chan) { struct dib3000mc_state *state = demod->demodulator_priv; u16 reg; // u32 val; - struct dibx000_ofdm_channel fchan; + struct dvb_frontend_parameters schan; - INIT_OFDM_CHANNEL(&fchan); - fchan = *chan; + schan = *chan; + /* TODO what is that ? */ /* a channel for autosearch */ - fchan.nfft = 1; fchan.guard = 0; fchan.nqam = 2; - fchan.vit_alpha = 1; fchan.vit_code_rate_hp = 2; fchan.vit_code_rate_lp = 2; - fchan.vit_hrch = 0; fchan.vit_select_hp = 1; + schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + schan.u.ofdm.constellation = QAM_64; + schan.u.ofdm.code_rate_HP = FEC_2_3; + schan.u.ofdm.code_rate_LP = FEC_2_3; + schan.u.ofdm.hierarchy_information = 0; - dib3000mc_set_channel_cfg(state, &fchan, 11); + dib3000mc_set_channel_cfg(state, &schan, 11); reg = dib3000mc_read_word(state, 0); dib3000mc_write_word(state, 0, reg | (1 << 8)); @@ -539,7 +585,7 @@ static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod) return 0; // still pending } -static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib3000mc_state *state = demod->demodulator_priv; @@ -547,11 +593,17 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channe dib3000mc_set_channel_cfg(state, ch, 0); // activates isi - dib3000mc_write_word(state, 29, 0x1073); - - dib3000mc_set_adp_cfg(state, (u8)ch->nqam); + if (state->sfn_workaround_active) { + dprintk("SFN workaround is active\n"); + dib3000mc_write_word(state, 29, 0x1273); + dib3000mc_write_word(state, 108, 0x4000); // P_pha3_force_pha_shift + } else { + dib3000mc_write_word(state, 29, 0x1073); + dib3000mc_write_word(state, 108, 0x0000); // P_pha3_force_pha_shift + } - if (ch->nfft == 1) { + dib3000mc_set_adp_cfg(state, (u8)ch->u.ofdm.constellation); + if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) { dib3000mc_write_word(state, 26, 38528); dib3000mc_write_word(state, 33, 8); } else { @@ -560,7 +612,7 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channe } if (dib3000mc_read_word(state, 509) & 0x80) - dib3000mc_set_timing(state, ch->nfft, ch->Bw, 1); + dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 1); return 0; } @@ -632,13 +684,12 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib3000mc_state *state = fe->demodulator_priv; - struct dibx000_ofdm_channel ch; - - INIT_OFDM_CHANNEL(&ch); - FEP2DIB(fep,&ch); state->current_bandwidth = fep->u.ofdm.bandwidth; - dib3000mc_set_bandwidth(fe, fep->u.ofdm.bandwidth); + dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); + + /* maybe the parameter has been changed */ + state->sfn_workaround_active = buggy_sfn_workaround; if (fe->ops.tuner_ops.set_params) { fe->ops.tuner_ops.set_params(fe, fep); @@ -651,7 +702,7 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, fep->u.ofdm.code_rate_HP == FEC_AUTO) { int i = 100, found; - dib3000mc_autosearch_start(fe, &ch); + dib3000mc_autosearch_start(fe, fep); do { msleep(1); found = dib3000mc_autosearch_is_irq(fe); @@ -662,13 +713,12 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, return 0; // no channel found dib3000mc_get_frontend(fe, fep); - FEP2DIB(fep,&ch); } /* make this a config parameter */ dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO); - return dib3000mc_tune(fe, &ch); + return dib3000mc_tune(fe, fep); } static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat) diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c index f64546c6aeb..fb18441a8c5 100644 --- a/drivers/media/dvb/frontends/dib7000m.c +++ b/drivers/media/dvb/frontends/dib7000m.c @@ -2,7 +2,7 @@ * Linux-DVB Driver for DiBcom's DiB7000M and * first generation DiB7000P-demodulator-family. * - * Copyright (C) 2005-6 DiBcom (http://www.dibcom.fr/) + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -19,7 +19,7 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M:"); printk(args); } } while (0) +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M: "); printk(args); printk("\n"); } } while (0) struct dib7000m_state { struct dvb_frontend demod; @@ -39,8 +39,16 @@ struct dib7000m_state { fe_bandwidth_t current_bandwidth; struct dibx000_agc_config *current_agc; u32 timf; + u32 timf_default; + u32 internal_clk; + + u8 div_force_off : 1; + u8 div_state : 1; + u16 div_sync_wait; u16 revision; + + u8 agc_state; }; enum dib7000m_power_mode { @@ -63,7 +71,7 @@ static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg) }; if (i2c_transfer(state->i2c_adap, msg, 2) != 2) - dprintk("i2c read error on %d\n",reg); + dprintk("i2c read error on %d",reg); return (rb[0] << 8) | rb[1]; } @@ -79,6 +87,25 @@ static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val) }; return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; } +static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf) +{ + u16 l = 0, r, *n; + n = buf; + l = *n++; + while (l) { + r = *n++; + + if (state->reg_offs && (r >= 112 && r <= 331)) // compensate for 7000MC + r++; + + do { + dib7000m_write_word(state, r, *n++); + r++; + } while (--l); + l = *n++; + } +} + static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) { int ret = 0; @@ -89,8 +116,7 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) fifo_threshold = 1792; smo_mode = (dib7000m_read_word(state, 294 + state->reg_offs) & 0x0010) | (1 << 1); - dprintk("-I- Setting output mode for demod %p to %d\n", - &state->demod, mode); + dprintk( "setting output mode for demod %p to %d", &state->demod, mode); switch (mode) { case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock @@ -117,7 +143,7 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) outreg = 0; break; default: - dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod); + dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod); break; } @@ -129,13 +155,20 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) ret |= dib7000m_write_word(state, 1795, outreg); ret |= dib7000m_write_word(state, 1805, sram); + if (state->revision == 0x4003) { + u16 clk_cfg1 = dib7000m_read_word(state, 909) & 0xfffd; + if (mode == OUTMODE_DIVERSITY) + clk_cfg1 |= (1 << 1); // P_O_CLK_en + dib7000m_write_word(state, 909, clk_cfg1); + } return ret; } -static int dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode) +static void dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode) { /* by default everything is going to be powered off */ u16 reg_903 = 0xffff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906 = 0x3fff; + u8 offset = 0; /* now, depending on the requested mode, we power on */ switch (mode) { @@ -170,16 +203,17 @@ static int dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_p if (!state->cfg.mobile_mode) reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1); - /* P_sdio_select_clk = 0 on MC */ + /* P_sdio_select_clk = 0 on MC and after*/ if (state->revision != 0x4000) reg_906 <<= 1; - dib7000m_write_word(state, 903, reg_903); - dib7000m_write_word(state, 904, reg_904); - dib7000m_write_word(state, 905, reg_905); - dib7000m_write_word(state, 906, reg_906); + if (state->revision == 0x4003) + offset = 1; - return 0; + dib7000m_write_word(state, 903 + offset, reg_903); + dib7000m_write_word(state, 904 + offset, reg_904); + dib7000m_write_word(state, 905 + offset, reg_905); + dib7000m_write_word(state, 906 + offset, reg_906); } static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc_states no) @@ -230,34 +264,55 @@ static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc break; } -// dprintk("-D- 913: %x, 914: %x\n", reg_913, reg_914); - +// dprintk( "913: %x, 914: %x", reg_913, reg_914); ret |= dib7000m_write_word(state, 913, reg_913); ret |= dib7000m_write_word(state, 914, reg_914); return ret; } -static int dib7000m_set_bandwidth(struct dvb_frontend *demod, u8 bw_idx) +static int dib7000m_set_bandwidth(struct dib7000m_state *state, u32 bw) { - struct dib7000m_state *state = demod->demodulator_priv; u32 timf; // store the current bandwidth for later use - state->current_bandwidth = bw_idx; + state->current_bandwidth = bw; if (state->timf == 0) { - dprintk("-D- Using default timf\n"); - timf = state->cfg.bw->timf; + dprintk( "using default timf"); + timf = state->timf_default; } else { - dprintk("-D- Using updated timf\n"); + dprintk( "using updated timf"); timf = state->timf; } - timf = timf * (BW_INDEX_TO_KHZ(bw_idx) / 100) / 80; + timf = timf * (bw / 50) / 160; - dib7000m_write_word(state, 23, (timf >> 16) & 0xffff); - dib7000m_write_word(state, 24, (timf ) & 0xffff); + dib7000m_write_word(state, 23, (u16) ((timf >> 16) & 0xffff)); + dib7000m_write_word(state, 24, (u16) ((timf ) & 0xffff)); + + return 0; +} + +static int dib7000m_set_diversity_in(struct dvb_frontend *demod, int onoff) +{ + struct dib7000m_state *state = demod->demodulator_priv; + + if (state->div_force_off) { + dprintk( "diversity combination deactivated - forced by COFDM parameters"); + onoff = 0; + } + state->div_state = (u8)onoff; + + if (onoff) { + dib7000m_write_word(state, 263 + state->reg_offs, 6); + dib7000m_write_word(state, 264 + state->reg_offs, 6); + dib7000m_write_word(state, 266 + state->reg_offs, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0)); + } else { + dib7000m_write_word(state, 263 + state->reg_offs, 1); + dib7000m_write_word(state, 264 + state->reg_offs, 0); + dib7000m_write_word(state, 266 + state->reg_offs, 0); + } return 0; } @@ -266,7 +321,7 @@ static int dib7000m_sad_calib(struct dib7000m_state *state) { /* internal */ -// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth +// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth dib7000m_write_word(state, 929, (0 << 1) | (0 << 0)); dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096 @@ -281,10 +336,10 @@ static int dib7000m_sad_calib(struct dib7000m_state *state) static void dib7000m_reset_pll_common(struct dib7000m_state *state, const struct dibx000_bandwidth_config *bw) { - dib7000m_write_word(state, 18, ((bw->internal*1000) >> 16) & 0xffff); - dib7000m_write_word(state, 19, (bw->internal*1000) & 0xffff); - dib7000m_write_word(state, 21, (bw->ifreq >> 16) & 0xffff); - dib7000m_write_word(state, 22, bw->ifreq & 0xffff); + dib7000m_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff)); + dib7000m_write_word(state, 19, (u16) ( (bw->internal*1000) & 0xffff)); + dib7000m_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff)); + dib7000m_write_word(state, 22, (u16) ( bw->ifreq & 0xffff)); dib7000m_write_word(state, 928, bw->sad_cfg); } @@ -325,15 +380,19 @@ static void dib7000m_reset_pll(struct dib7000m_state *state) static void dib7000mc_reset_pll(struct dib7000m_state *state) { const struct dibx000_bandwidth_config *bw = state->cfg.bw; + u16 clk_cfg1; // clk_cfg0 dib7000m_write_word(state, 907, (bw->pll_prediv << 8) | (bw->pll_ratio << 0)); // clk_cfg1 //dib7000m_write_word(state, 908, (1 << 14) | (3 << 12) |(0 << 11) | - dib7000m_write_word(state, 908, (0 << 14) | (3 << 12) |(0 << 11) | + clk_cfg1 = (0 << 14) | (3 << 12) |(0 << 11) | (bw->IO_CLK_en_core << 10) | (bw->bypclk_div << 5) | (bw->enable_refdiv << 4) | - (bw->pll_bypass << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0)); + (1 << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0); + dib7000m_write_word(state, 908, clk_cfg1); + clk_cfg1 = (clk_cfg1 & 0xfff7) | (bw->pll_bypass << 3); + dib7000m_write_word(state, 908, clk_cfg1); // smpl_cfg dib7000m_write_word(state, 910, (1 << 12) | (2 << 10) | (bw->modulo << 8) | (bw->ADClkSrc << 7)); @@ -344,9 +403,6 @@ static void dib7000mc_reset_pll(struct dib7000m_state *state) static int dib7000m_reset_gpio(struct dib7000m_state *st) { /* reset the GPIOs */ - dprintk("-D- gpio dir: %x: gpio val: %x, gpio pwm pos: %x\n", - st->cfg.gpio_dir, st->cfg.gpio_val,st->cfg.gpio_pwm_pos); - dib7000m_write_word(st, 773, st->cfg.gpio_dir); dib7000m_write_word(st, 774, st->cfg.gpio_val); @@ -358,6 +414,107 @@ static int dib7000m_reset_gpio(struct dib7000m_state *st) return 0; } +static u16 dib7000m_defaults_common[] = + +{ + // auto search configuration + 3, 2, + 0x0004, + 0x1000, + 0x0814, + + 12, 6, + 0x001b, + 0x7740, + 0x005b, + 0x8d80, + 0x01c9, + 0xc380, + 0x0000, + 0x0080, + 0x0000, + 0x0090, + 0x0001, + 0xd4c0, + + 1, 26, + 0x6680, // P_corm_thres Lock algorithms configuration + + 1, 170, + 0x0410, // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on + + 8, 173, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + + 1, 182, + 8192, // P_fft_nb_to_cut + + 2, 195, + 0x0ccd, // P_pha3_thres + 0, // P_cti_use_cpe, P_cti_use_prog + + 1, 205, + 0x200f, // P_cspu_regul, P_cspu_win_cut + + 5, 214, + 0x023d, // P_adp_regul_cnt + 0x00a4, // P_adp_noise_cnt + 0x00a4, // P_adp_regul_ext + 0x7ff0, // P_adp_noise_ext + 0x3ccc, // P_adp_fil + + 1, 226, + 0, // P_2d_byp_ti_num + + 1, 255, + 0x800, // P_equal_thres_wgn + + 1, 263, + 0x0001, + + 1, 281, + 0x0010, // P_fec_* + + 1, 294, + 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard + + 0 +}; + +static u16 dib7000m_defaults[] = + +{ + /* set ADC level to -16 */ + 11, 76, + (1 << 13) - 825 - 117, + (1 << 13) - 837 - 117, + (1 << 13) - 811 - 117, + (1 << 13) - 766 - 117, + (1 << 13) - 737 - 117, + (1 << 13) - 693 - 117, + (1 << 13) - 648 - 117, + (1 << 13) - 619 - 117, + (1 << 13) - 575 - 117, + (1 << 13) - 531 - 117, + (1 << 13) - 501 - 117, + + // Tuner IO bank: max drive (14mA) + 1, 912, + 0x2c8a, + + 1, 1817, + 1, + + 0, +}; + static int dib7000m_demod_reset(struct dib7000m_state *state) { dib7000m_set_power_mode(state, DIB7000M_POWER_ALL); @@ -382,22 +539,47 @@ static int dib7000m_demod_reset(struct dib7000m_state *state) dib7000mc_reset_pll(state); if (dib7000m_reset_gpio(state) != 0) - dprintk("-E- GPIO reset was not successful.\n"); + dprintk( "GPIO reset was not successful."); if (dib7000m_set_output_mode(state, OUTMODE_HIGH_Z) != 0) - dprintk("-E- OUTPUT_MODE could not be resetted.\n"); + dprintk( "OUTPUT_MODE could not be reset."); /* unforce divstr regardless whether i2c enumeration was done or not */ dib7000m_write_word(state, 1794, dib7000m_read_word(state, 1794) & ~(1 << 1) ); - dib7000m_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ); + dib7000m_set_bandwidth(state, 8000); dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON); dib7000m_sad_calib(state); dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_OFF); + if (state->cfg.dvbt_mode) + dib7000m_write_word(state, 1796, 0x0); // select DVB-T output + + if (state->cfg.mobile_mode) + dib7000m_write_word(state, 261 + state->reg_offs, 2); + else + dib7000m_write_word(state, 224 + state->reg_offs, 1); + + // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ... + if(state->cfg.tuner_is_baseband) + dib7000m_write_word(state, 36, 0x0755); + else + dib7000m_write_word(state, 36, 0x1f55); + + // P_divclksel=3 P_divbitsel=1 + if (state->revision == 0x4000) + dib7000m_write_word(state, 909, (3 << 10) | (1 << 6)); + else + dib7000m_write_word(state, 909, (3 << 4) | 1); + + dib7000m_write_tab(state, dib7000m_defaults_common); + dib7000m_write_tab(state, dib7000m_defaults); + dib7000m_set_power_mode(state, DIB7000M_POWER_INTERFACE_ONLY); + state->internal_clk = state->cfg.bw->internal; + return 0; } @@ -427,7 +609,7 @@ static int dib7000m_agc_soft_split(struct dib7000m_state *state) (agc - state->current_agc->split.min_thres) / (state->current_agc->split.max_thres - state->current_agc->split.min_thres); - dprintk("AGC split_offset: %d\n",split_offset); + dprintk( "AGC split_offset: %d",split_offset); // P_agc_force_split and P_agc_split_offset return dib7000m_write_word(state, 103, (dib7000m_read_word(state, 103) & 0xff00) | split_offset); @@ -435,35 +617,26 @@ static int dib7000m_agc_soft_split(struct dib7000m_state *state) static int dib7000m_update_lna(struct dib7000m_state *state) { - int i; u16 dyn_gain; - // when there is no LNA to program return immediatly - if (state->cfg.update_lna == NULL) - return 0; - - msleep(60); - for (i = 0; i < 20; i++) { - // read dyn_gain here (because it is demod-dependent and not tuner) + if (state->cfg.update_lna) { + // read dyn_gain here (because it is demod-dependent and not fe) dyn_gain = dib7000m_read_word(state, 390); - dprintk("agc global: %d\n", dyn_gain); - if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed dib7000m_restart_agc(state); - msleep(60); - } else - break; + return 1; + } } return 0; } -static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) +static int dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) { struct dibx000_agc_config *agc = NULL; int i; - if (state->current_band == band) - return; + if (state->current_band == band && state->current_agc != NULL) + return 0; state->current_band = band; for (i = 0; i < state->cfg.agc_config_count; i++) @@ -473,8 +646,8 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) } if (agc == NULL) { - dprintk("-E- No valid AGC configuration found for band 0x%02x\n",band); - return; + dprintk( "no valid AGC configuration found for band 0x%02x",band); + return -EINVAL; } state->current_agc = agc; @@ -489,7 +662,7 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) dib7000m_write_word(state, 98, (agc->alpha_mant << 5) | agc->alpha_exp); dib7000m_write_word(state, 99, (agc->beta_mant << 6) | agc->beta_exp); - dprintk("-D- WBD: ref: %d, sel: %d, active: %d, alpha: %d\n", + dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d", state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); /* AGC continued */ @@ -510,7 +683,7 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) if (state->revision > 0x4000) { // settings for the MC dib7000m_write_word(state, 71, agc->agc1_pt3); -// dprintk("-D- 929: %x %d %d\n", +// dprintk( "929: %x %d %d", // (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2), agc->wbd_inv, agc->wbd_sel); dib7000m_write_word(state, 929, (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); } else { @@ -519,33 +692,160 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) for (i = 0; i < 9; i++) dib7000m_write_word(state, 88 + i, b[i]); } + return 0; } -static void dib7000m_update_timf_freq(struct dib7000m_state *state) +static void dib7000m_update_timf(struct dib7000m_state *state) { u32 timf = (dib7000m_read_word(state, 436) << 16) | dib7000m_read_word(state, 437); - state->timf = timf * 80 / (BW_INDEX_TO_KHZ(state->current_bandwidth) / 100); + state->timf = timf * 160 / (state->current_bandwidth / 50); dib7000m_write_word(state, 23, (u16) (timf >> 16)); dib7000m_write_word(state, 24, (u16) (timf & 0xffff)); - dprintk("-D- Updated timf_frequency: %d (default: %d)\n",state->timf, state->cfg.bw->timf); + dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->timf_default); +} + +static int dib7000m_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +{ + struct dib7000m_state *state = demod->demodulator_priv; + u16 cfg_72 = dib7000m_read_word(state, 72); + int ret = -1; + u8 *agc_state = &state->agc_state; + u8 agc_split; + + switch (state->agc_state) { + case 0: + // set power-up level: interf+analog+AGC + dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC); + dib7000m_set_adc_state(state, DIBX000_ADC_ON); + + if (dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0) + return -1; + + ret = 7; /* ADC power up */ + (*agc_state)++; + break; + + case 1: + /* AGC initialization */ + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 1); + + dib7000m_write_word(state, 75, 32768); + if (!state->current_agc->perform_agc_softsplit) { + /* we are using the wbd - so slow AGC startup */ + dib7000m_write_word(state, 103, 1 << 8); /* force 0 split on WBD and restart AGC */ + (*agc_state)++; + ret = 5; + } else { + /* default AGC startup */ + (*agc_state) = 4; + /* wait AGC rough lock time */ + ret = 7; + } + + dib7000m_restart_agc(state); + break; + + case 2: /* fast split search path after 5sec */ + dib7000m_write_word(state, 72, cfg_72 | (1 << 4)); /* freeze AGC loop */ + dib7000m_write_word(state, 103, 2 << 9); /* fast split search 0.25kHz */ + (*agc_state)++; + ret = 14; + break; + + case 3: /* split search ended */ + agc_split = (u8)dib7000m_read_word(state, 392); /* store the split value for the next time */ + dib7000m_write_word(state, 75, dib7000m_read_word(state, 390)); /* set AGC gain start value */ + + dib7000m_write_word(state, 72, cfg_72 & ~(1 << 4)); /* std AGC loop */ + dib7000m_write_word(state, 103, (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */ + + dib7000m_restart_agc(state); + + dprintk( "SPLIT %p: %hd", demod, agc_split); + + (*agc_state)++; + ret = 5; + break; + + case 4: /* LNA startup */ + /* wait AGC accurate lock time */ + ret = 7; + + if (dib7000m_update_lna(state)) + // wait only AGC rough lock time + ret = 5; + else + (*agc_state)++; + break; + + case 5: + dib7000m_agc_soft_split(state); + + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 0); + + (*agc_state)++; + break; + + default: + break; + } + return ret; } -static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_ofdm_channel *ch, u8 seq) +static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_frontend_parameters *ch, u8 seq) { u16 value, est[4]; - dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->RF_kHz)); + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); /* nfft, guard, qam, alpha */ - dib7000m_write_word(state, 0, (ch->nfft << 7) | (ch->guard << 5) | (ch->nqam << 3) | (ch->vit_alpha)); + value = 0; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= (0 << 7); break; + case /* 4K MODE */ 255: value |= (2 << 7); break; + default: + case TRANSMISSION_MODE_8K: value |= (1 << 7); break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_32: value |= (0 << 5); break; + case GUARD_INTERVAL_1_16: value |= (1 << 5); break; + case GUARD_INTERVAL_1_4: value |= (3 << 5); break; + default: + case GUARD_INTERVAL_1_8: value |= (2 << 5); break; + } + switch (ch->u.ofdm.constellation) { + case QPSK: value |= (0 << 3); break; + case QAM_16: value |= (1 << 3); break; + default: + case QAM_64: value |= (2 << 3); break; + } + switch (HIERARCHY_1) { + case HIERARCHY_2: value |= 2; break; + case HIERARCHY_4: value |= 4; break; + default: + case HIERARCHY_1: value |= 1; break; + } + dib7000m_write_word(state, 0, value); dib7000m_write_word(state, 5, (seq << 4)); - /* P_dintl_native, P_dintlv_inv, P_vit_hrch, P_vit_code_rate, P_vit_select_hp */ - value = (ch->intlv_native << 6) | (ch->vit_hrch << 4) | (ch->vit_select_hp & 0x1); - if (ch->vit_hrch == 0 || ch->vit_select_hp == 1) - value |= (ch->vit_code_rate_hp << 1); - else - value |= (ch->vit_code_rate_lp << 1); + /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */ + value = 0; + if (1 != 0) + value |= (1 << 6); + if (ch->u.ofdm.hierarchy_information == 1) + value |= (1 << 4); + if (1 == 1) + value |= 1; + switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + case FEC_2_3: value |= (2 << 1); break; + case FEC_3_4: value |= (3 << 1); break; + case FEC_5_6: value |= (5 << 1); break; + case FEC_7_8: value |= (7 << 1); break; + default: + case FEC_1_2: value |= (1 << 1); break; + } dib7000m_write_word(state, 267 + state->reg_offs, value); /* offset loop parameters */ @@ -563,32 +863,38 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_of dib7000m_write_word(state, 33, (0 << 4) | 0x5); /* P_dvsy_sync_wait */ - switch (ch->nfft) { - case 1: value = 256; break; - case 2: value = 128; break; - case 0: + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_8K: value = 256; break; + case /* 4K MODE */ 255: value = 128; break; + case TRANSMISSION_MODE_2K: default: value = 64; break; } - value *= ((1 << (ch->guard)) * 3 / 2); // add 50% SFN margin - value <<= 4; + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_16: value *= 2; break; + case GUARD_INTERVAL_1_8: value *= 4; break; + case GUARD_INTERVAL_1_4: value *= 8; break; + default: + case GUARD_INTERVAL_1_32: value *= 1; break; + } + state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO /* deactive the possibility of diversity reception if extended interleave - not for 7000MC */ /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ - if (ch->intlv_native || state->revision > 0x4000) - value |= (1 << 2) | (2 << 0); + if (1 == 1 || state->revision > 0x4000) + state->div_force_off = 0; else - value |= 0; - dib7000m_write_word(state, 266 + state->reg_offs, value); + state->div_force_off = 1; + dib7000m_set_diversity_in(&state->demod, state->div_state); /* channel estimation fine configuration */ - switch (ch->nqam) { - case 2: + switch (ch->u.ofdm.constellation) { + case QAM_64: est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */ break; - case 1: + case QAM_16: est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */ est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ @@ -604,70 +910,48 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_of for (value = 0; value < 4; value++) dib7000m_write_word(state, 214 + value + state->reg_offs, est[value]); - // set power-up level: interf+analog+AGC - dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC); - dib7000m_set_adc_state(state, DIBX000_ADC_ON); - - msleep(7); - - //AGC initialization - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 1); - - dib7000m_restart_agc(state); - - // wait AGC rough lock time - msleep(5); - - dib7000m_update_lna(state); - dib7000m_agc_soft_split(state); - - // wait AGC accurate lock time - msleep(7); - - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 0); - // set power-up level: autosearch dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD); } -static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib7000m_state *state = demod->demodulator_priv; - struct dibx000_ofdm_channel auto_ch; + struct dvb_frontend_parameters schan; int ret = 0; - u32 value; - - INIT_OFDM_CHANNEL(&auto_ch); - auto_ch.RF_kHz = ch->RF_kHz; - auto_ch.Bw = ch->Bw; - auto_ch.nqam = 2; - auto_ch.guard = 0; - auto_ch.nfft = 1; - auto_ch.vit_alpha = 1; - auto_ch.vit_select_hp = 1; - auto_ch.vit_code_rate_hp = 2; - auto_ch.vit_code_rate_lp = 3; - auto_ch.vit_hrch = 0; - auto_ch.intlv_native = 1; - - dib7000m_set_channel(state, &auto_ch, 7); + u32 value, factor; + + schan = *ch; + + schan.u.ofdm.constellation = QAM_64; + schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + schan.u.ofdm.code_rate_HP = FEC_2_3; + schan.u.ofdm.code_rate_LP = FEC_3_4; + schan.u.ofdm.hierarchy_information = 0; + + dib7000m_set_channel(state, &schan, 7); + + factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth); + if (factor >= 5000) + factor = 1; + else + factor = 6; // always use the setting for 8MHz here lock_time for 7,6 MHz are longer - value = 30 * state->cfg.bw->internal; + value = 30 * state->internal_clk * factor; ret |= dib7000m_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time ret |= dib7000m_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time - value = 100 * state->cfg.bw->internal; + value = 100 * state->internal_clk * factor; ret |= dib7000m_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time ret |= dib7000m_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time - value = 500 * state->cfg.bw->internal; + value = 500 * state->internal_clk * factor; ret |= dib7000m_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time ret |= dib7000m_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time // start search value = dib7000m_read_word(state, 0); - ret |= dib7000m_write_word(state, 0, value | (1 << 9)); + ret |= dib7000m_write_word(state, 0, (u16) (value | (1 << 9))); /* clear n_irq_pending */ if (state->revision == 0x4000) @@ -685,12 +969,12 @@ static int dib7000m_autosearch_irq(struct dib7000m_state *state, u16 reg) u16 irq_pending = dib7000m_read_word(state, reg); if (irq_pending & 0x1) { // failed - dprintk("#\n"); + dprintk( "autosearch failed"); return 1; } if (irq_pending & 0x2) { // succeeded - dprintk("!\n"); + dprintk( "autosearch succeeded"); return 2; } return 0; // still pending @@ -705,7 +989,7 @@ static int dib7000m_autosearch_is_irq(struct dvb_frontend *demod) return dib7000m_autosearch_irq(state, 537); } -static int dib7000m_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib7000m_state *state = demod->demodulator_priv; int ret = 0; @@ -722,182 +1006,103 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel ret |= dib7000m_write_word(state, 898, 0x0000); msleep(45); - ret |= dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD); + dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD); /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */ ret |= dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3)); - // never achieved a lock with that bandwidth so far - wait for timfreq to update + // never achieved a lock before - wait for timfreq to update if (state->timf == 0) msleep(200); //dump_reg(state); /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */ value = (6 << 8) | 0x80; - switch (ch->nfft) { - case 0: value |= (7 << 12); break; - case 1: value |= (9 << 12); break; - case 2: value |= (8 << 12); break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= (7 << 12); break; + case /* 4K MODE */ 255: value |= (8 << 12); break; + default: + case TRANSMISSION_MODE_8K: value |= (9 << 12); break; } ret |= dib7000m_write_word(state, 26, value); /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */ value = (0 << 4); - switch (ch->nfft) { - case 0: value |= 0x6; break; - case 1: value |= 0x8; break; - case 2: value |= 0x7; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= 0x6; break; + case /* 4K MODE */ 255: value |= 0x7; break; + default: + case TRANSMISSION_MODE_8K: value |= 0x8; break; } ret |= dib7000m_write_word(state, 32, value); /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */ value = (0 << 4); - switch (ch->nfft) { - case 0: value |= 0x6; break; - case 1: value |= 0x8; break; - case 2: value |= 0x7; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= 0x6; break; + case /* 4K MODE */ 255: value |= 0x7; break; + default: + case TRANSMISSION_MODE_8K: value |= 0x8; break; } ret |= dib7000m_write_word(state, 33, value); - // we achieved a lock - it's time to update the osc freq + // we achieved a lock - it's time to update the timf freq if ((dib7000m_read_word(state, 535) >> 6) & 0x1) - dib7000m_update_timf_freq(state); + dib7000m_update_timf(state); + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); return ret; } -static int dib7000m_init(struct dvb_frontend *demod) +static int dib7000m_wakeup(struct dvb_frontend *demod) { struct dib7000m_state *state = demod->demodulator_priv; - int ret = 0; - u8 o = state->reg_offs; dib7000m_set_power_mode(state, DIB7000M_POWER_ALL); if (dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0) - dprintk("-E- could not start Slow ADC\n"); - - if (state->cfg.dvbt_mode) - dib7000m_write_word(state, 1796, 0x0); // select DVB-T output - - if (state->cfg.mobile_mode) - ret |= dib7000m_write_word(state, 261 + o, 2); - else - ret |= dib7000m_write_word(state, 224 + o, 1); - - ret |= dib7000m_write_word(state, 173 + o, 0); - ret |= dib7000m_write_word(state, 174 + o, 0); - ret |= dib7000m_write_word(state, 175 + o, 0); - ret |= dib7000m_write_word(state, 176 + o, 0); - ret |= dib7000m_write_word(state, 177 + o, 0); - ret |= dib7000m_write_word(state, 178 + o, 0); - ret |= dib7000m_write_word(state, 179 + o, 0); - ret |= dib7000m_write_word(state, 180 + o, 0); - - // P_corm_thres Lock algorithms configuration - ret |= dib7000m_write_word(state, 26, 0x6680); - - // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on - ret |= dib7000m_write_word(state, 170 + o, 0x0410); - // P_fft_nb_to_cut - ret |= dib7000m_write_word(state, 182 + o, 8192); - // P_pha3_thres - ret |= dib7000m_write_word(state, 195 + o, 0x0ccd); - // P_cti_use_cpe, P_cti_use_prog - ret |= dib7000m_write_word(state, 196 + o, 0); - // P_cspu_regul, P_cspu_win_cut - ret |= dib7000m_write_word(state, 205 + o, 0x200f); - // P_adp_regul_cnt - ret |= dib7000m_write_word(state, 214 + o, 0x023d); - // P_adp_noise_cnt - ret |= dib7000m_write_word(state, 215 + o, 0x00a4); - // P_adp_regul_ext - ret |= dib7000m_write_word(state, 216 + o, 0x00a4); - // P_adp_noise_ext - ret |= dib7000m_write_word(state, 217 + o, 0x7ff0); - // P_adp_fil - ret |= dib7000m_write_word(state, 218 + o, 0x3ccc); - - // P_2d_byp_ti_num - ret |= dib7000m_write_word(state, 226 + o, 0); - - // P_fec_* - ret |= dib7000m_write_word(state, 281 + o, 0x0010); - // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard - ret |= dib7000m_write_word(state, 294 + o,0x0062); - - // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ... - if(state->cfg.tuner_is_baseband) - ret |= dib7000m_write_word(state, 36, 0x0755); - else - ret |= dib7000m_write_word(state, 36, 0x1f55); - - // auto search configuration - ret |= dib7000m_write_word(state, 2, 0x0004); - ret |= dib7000m_write_word(state, 3, 0x1000); - ret |= dib7000m_write_word(state, 4, 0x0814); - ret |= dib7000m_write_word(state, 6, 0x001b); - ret |= dib7000m_write_word(state, 7, 0x7740); - ret |= dib7000m_write_word(state, 8, 0x005b); - ret |= dib7000m_write_word(state, 9, 0x8d80); - ret |= dib7000m_write_word(state, 10, 0x01c9); - ret |= dib7000m_write_word(state, 11, 0xc380); - ret |= dib7000m_write_word(state, 12, 0x0000); - ret |= dib7000m_write_word(state, 13, 0x0080); - ret |= dib7000m_write_word(state, 14, 0x0000); - ret |= dib7000m_write_word(state, 15, 0x0090); - ret |= dib7000m_write_word(state, 16, 0x0001); - ret |= dib7000m_write_word(state, 17, 0xd4c0); - ret |= dib7000m_write_word(state, 263 + o,0x0001); - - // P_divclksel=3 P_divbitsel=1 - if (state->revision == 0x4000) - dib7000m_write_word(state, 909, (3 << 10) | (1 << 6)); - else - dib7000m_write_word(state, 909, (3 << 4) | 1); - - // Tuner IO bank: max drive (14mA) - ret |= dib7000m_write_word(state, 912 ,0x2c8a); + dprintk( "could not start Slow ADC"); - ret |= dib7000m_write_word(state, 1817, 1); - - return ret; + return 0; } static int dib7000m_sleep(struct dvb_frontend *demod) { struct dib7000m_state *st = demod->demodulator_priv; dib7000m_set_output_mode(st, OUTMODE_HIGH_Z); - return dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY) | - dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) | + dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY); + return dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) | dib7000m_set_adc_state(st, DIBX000_ADC_OFF); } static int dib7000m_identify(struct dib7000m_state *state) { u16 value; + if ((value = dib7000m_read_word(state, 896)) != 0x01b3) { - dprintk("-E- DiB7000M: wrong Vendor ID (read=0x%x)\n",value); + dprintk( "wrong Vendor ID (0x%x)",value); return -EREMOTEIO; } state->revision = dib7000m_read_word(state, 897); if (state->revision != 0x4000 && state->revision != 0x4001 && - state->revision != 0x4002) { - dprintk("-E- DiB7000M: wrong Device ID (%x)\n",value); + state->revision != 0x4002 && + state->revision != 0x4003) { + dprintk( "wrong Device ID (0x%x)",value); return -EREMOTEIO; } /* protect this driver to be used with 7000PC */ if (state->revision == 0x4000 && dib7000m_read_word(state, 769) == 0x4000) { - dprintk("-E- DiB7000M: this driver does not work with DiB7000PC\n"); + dprintk( "this driver does not work with DiB7000PC"); return -EREMOTEIO; } switch (state->revision) { - case 0x4000: dprintk("-I- found DiB7000MA/PA/MB/PB\n"); break; - case 0x4001: state->reg_offs = 1; dprintk("-I- found DiB7000HC\n"); break; - case 0x4002: state->reg_offs = 1; dprintk("-I- found DiB7000MC\n"); break; + case 0x4000: dprintk( "found DiB7000MA/PA/MB/PB"); break; + case 0x4001: state->reg_offs = 1; dprintk( "found DiB7000HC"); break; + case 0x4002: state->reg_offs = 1; dprintk( "found DiB7000MC"); break; + case 0x4003: state->reg_offs = 1; dprintk( "found DiB9000"); break; } return 0; @@ -966,41 +1171,45 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib7000m_state *state = fe->demodulator_priv; - struct dibx000_ofdm_channel ch; - - INIT_OFDM_CHANNEL(&ch); - FEP2DIB(fep,&ch); + int time; state->current_bandwidth = fep->u.ofdm.bandwidth; - dib7000m_set_bandwidth(fe, fep->u.ofdm.bandwidth); + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); if (fe->ops.tuner_ops.set_params) fe->ops.tuner_ops.set_params(fe, fep); + /* start up the AGC */ + state->agc_state = 0; + do { + time = dib7000m_agc_startup(fe, fep); + if (time != -1) + msleep(time); + } while (time != -1); + if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { int i = 800, found; - dib7000m_autosearch_start(fe, &ch); + dib7000m_autosearch_start(fe, fep); do { msleep(1); found = dib7000m_autosearch_is_irq(fe); } while (found == 0 && i--); - dprintk("autosearch returns: %d\n",found); + dprintk("autosearch returns: %d",found); if (found == 0 || found == 1) return 0; // no channel found dib7000m_get_frontend(fe, fep); - FEP2DIB(fep, &ch); } /* make this a config parameter */ dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO); - return dib7000m_tune(fe, &ch); + return dib7000m_tune(fe, fep); } static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat) @@ -1087,7 +1296,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau if (dib7000m_identify(&st) != 0) { st.i2c_addr = default_addr; if (dib7000m_identify(&st) != 0) { - dprintk("DiB7000M #%d: not identified\n", k); + dprintk("DiB7000M #%d: not identified", k); return -EIO; } } @@ -1100,7 +1309,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau /* set new i2c address and force divstart */ dib7000m_write_word(&st, 1794, (new_addr << 2) | 0x2); - dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr); + dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); } for (k = 0; k < no_of_demods; k++) { @@ -1135,6 +1344,8 @@ struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, demod->demodulator_priv = st; memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops)); + st->timf_default = cfg->bw->timf; + if (dib7000m_identify(st) != 0) goto error; @@ -1172,7 +1383,7 @@ static struct dvb_frontend_ops dib7000m_ops = { .release = dib7000m_release, - .init = dib7000m_init, + .init = dib7000m_wakeup, .sleep = dib7000m_sleep, .set_frontend = dib7000m_set_frontend, diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index aece458cfe1..f45bcfc51cf 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -1,7 +1,7 @@ /* * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC). * - * Copyright (C) 2005-6 DiBcom (http://www.dibcom.fr/) + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -18,7 +18,11 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P:"); printk(args); } } while (0) +static int buggy_sfn_workaround; +module_param(buggy_sfn_workaround, int, 0644); +MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)"); + +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0) struct dib7000p_state { struct dvb_frontend demod; @@ -36,12 +40,21 @@ struct dib7000p_state { struct dibx000_agc_config *current_agc; u32 timf; + u8 div_force_off : 1; + u8 div_state : 1; + u16 div_sync_wait; + + u8 agc_state; + u16 gpio_dir; u16 gpio_val; + + u8 sfn_workaround_active :1; }; enum dib7000p_power_mode { DIB7000P_POWER_ALL = 0, + DIB7000P_POWER_ANALOG_ADC, DIB7000P_POWER_INTERFACE_ONLY, }; @@ -55,7 +68,7 @@ static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg) }; if (i2c_transfer(state->i2c_adap, msg, 2) != 2) - dprintk("i2c read error on %d\n",reg); + dprintk("i2c read error on %d",reg); return (rb[0] << 8) | rb[1]; } @@ -71,6 +84,22 @@ static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val) }; return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; } +static void dib7000p_write_tab(struct dib7000p_state *state, u16 *buf) +{ + u16 l = 0, r, *n; + n = buf; + l = *n++; + while (l) { + r = *n++; + + do { + dib7000p_write_word(state, r, *n++); + r++; + } while (--l); + l = *n++; + } +} + static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) { int ret = 0; @@ -80,7 +109,7 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) fifo_threshold = 1792; smo_mode = (dib7000p_read_word(state, 235) & 0x0010) | (1 << 1); - dprintk("-I- Setting output mode for demod %p to %d\n", + dprintk( "setting output mode for demod %p to %d", &state->demod, mode); switch (mode) { @@ -104,11 +133,14 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) fifo_threshold = 512; outreg = (1 << 10) | (5 << 6); break; + case OUTMODE_ANALOG_ADC: + outreg = (1 << 10) | (3 << 6); + break; case OUTMODE_HIGH_Z: // disable outreg = 0; break; default: - dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod); + dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod); break; } @@ -122,6 +154,30 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) return ret; } +static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff) +{ + struct dib7000p_state *state = demod->demodulator_priv; + + if (state->div_force_off) { + dprintk( "diversity combination deactivated - forced by COFDM parameters"); + onoff = 0; + } + state->div_state = (u8)onoff; + + if (onoff) { + dib7000p_write_word(state, 204, 6); + dib7000p_write_word(state, 205, 16); + /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ + dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0)); + } else { + dib7000p_write_word(state, 204, 1); + dib7000p_write_word(state, 205, 0); + dib7000p_write_word(state, 207, 0); + } + + return 0; +} + static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode) { /* by default everything is powered off */ @@ -134,10 +190,21 @@ static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_p case DIB7000P_POWER_ALL: reg_774 = 0x0000; reg_775 = 0x0000; reg_776 = 0x0; reg_899 = 0x0; reg_1280 &= 0x01ff; break; + + case DIB7000P_POWER_ANALOG_ADC: + /* dem, cfg, iqc, sad, agc */ + reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9)); + /* nud */ + reg_776 &= ~((1 << 0)); + /* Dout */ + reg_1280 &= ~((1 << 11)); + /* fall through wanted to enable the interfaces */ + /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */ case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */ reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10)); break; + /* TODO following stuff is just converted from the dib7000-driver - check when is used what */ } @@ -188,34 +255,31 @@ static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_ad break; } -// dprintk("908: %x, 909: %x\n", reg_908, reg_909); +// dprintk( "908: %x, 909: %x\n", reg_908, reg_909); dib7000p_write_word(state, 908, reg_908); dib7000p_write_word(state, 909, reg_909); } -static int dib7000p_set_bandwidth(struct dvb_frontend *demod, u8 BW_Idx) +static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw) { - struct dib7000p_state *state = demod->demodulator_priv; u32 timf; // store the current bandwidth for later use - state->current_bandwidth = BW_Idx; + state->current_bandwidth = bw; if (state->timf == 0) { - dprintk("-D- Using default timf\n"); + dprintk( "using default timf"); timf = state->cfg.bw->timf; } else { - dprintk("-D- Using updated timf\n"); + dprintk( "using updated timf"); timf = state->timf; } - timf = timf * (BW_INDEX_TO_KHZ(BW_Idx) / 100) / 80; - - dprintk("timf: %d\n",timf); + timf = timf * (bw / 50) / 160; - dib7000p_write_word(state, 23, (timf >> 16) & 0xffff); - dib7000p_write_word(state, 24, (timf ) & 0xffff); + dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff)); + dib7000p_write_word(state, 24, (u16) ((timf ) & 0xffff)); return 0; } @@ -223,7 +287,7 @@ static int dib7000p_set_bandwidth(struct dvb_frontend *demod, u8 BW_Idx) static int dib7000p_sad_calib(struct dib7000p_state *state) { /* internal */ -// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth +// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth dib7000p_write_word(state, 73, (0 << 1) | (0 << 0)); dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096 @@ -236,18 +300,37 @@ static int dib7000p_sad_calib(struct dib7000p_state *state) return 0; } +int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value) +{ + struct dib7000p_state *state = demod->demodulator_priv; + if (value > 4095) + value = 4095; + state->wbd_ref = value; + return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value); +} + +EXPORT_SYMBOL(dib7000p_set_wbd_ref); static void dib7000p_reset_pll(struct dib7000p_state *state) { struct dibx000_bandwidth_config *bw = &state->cfg.bw[0]; + u16 clk_cfg0; + + /* force PLL bypass */ + clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) | + (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | + (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0); + dib7000p_write_word(state, 900, clk_cfg0); + + /* P_pll_cfg */ dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset); - dib7000p_write_word(state, 900, ((bw->pll_ratio & 0x3f) << 9) | (bw->pll_bypass << 15) | (bw->modulo << 7) | (bw->ADClkSrc << 6) | - (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0)); + clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff); + dib7000p_write_word(state, 900, clk_cfg0); - dib7000p_write_word(state, 18, ((bw->internal*1000) >> 16) & 0xffff); - dib7000p_write_word(state, 19, (bw->internal*1000 ) & 0xffff); - dib7000p_write_word(state, 21, (bw->ifreq >> 16) & 0xffff); - dib7000p_write_word(state, 22, (bw->ifreq ) & 0xffff); + dib7000p_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff)); + dib7000p_write_word(state, 19, (u16) ( (bw->internal*1000 ) & 0xffff)); + dib7000p_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff)); + dib7000p_write_word(state, 22, (u16) ( (bw->ifreq ) & 0xffff)); dib7000p_write_word(state, 72, bw->sad_cfg); } @@ -255,7 +338,7 @@ static void dib7000p_reset_pll(struct dib7000p_state *state) static int dib7000p_reset_gpio(struct dib7000p_state *st) { /* reset the GPIOs */ - dprintk("-D- gpio dir: %x: gpio val: %x, gpio pwm pos: %x\n",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos); + dprintk( "gpio dir: %x: val: %x, pwm_pos: %x",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos); dib7000p_write_word(st, 1029, st->gpio_dir); dib7000p_write_word(st, 1030, st->gpio_val); @@ -268,6 +351,120 @@ static int dib7000p_reset_gpio(struct dib7000p_state *st) return 0; } +static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val) +{ + st->gpio_dir = dib7000p_read_word(st, 1029); + st->gpio_dir &= ~(1 << num); /* reset the direction bit */ + st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */ + dib7000p_write_word(st, 1029, st->gpio_dir); + + st->gpio_val = dib7000p_read_word(st, 1030); + st->gpio_val &= ~(1 << num); /* reset the direction bit */ + st->gpio_val |= (val & 0x01) << num; /* set the new value */ + dib7000p_write_word(st, 1030, st->gpio_val); + + return 0; +} + +int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val) +{ + struct dib7000p_state *state = demod->demodulator_priv; + return dib7000p_cfg_gpio(state, num, dir, val); +} + +EXPORT_SYMBOL(dib7000p_set_gpio); +static u16 dib7000p_defaults[] = + +{ + // auto search configuration + 3, 2, + 0x0004, + 0x1000, + 0x0814, /* Equal Lock */ + + 12, 6, + 0x001b, + 0x7740, + 0x005b, + 0x8d80, + 0x01c9, + 0xc380, + 0x0000, + 0x0080, + 0x0000, + 0x0090, + 0x0001, + 0xd4c0, + + 1, 26, + 0x6680, // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26 + + /* set ADC level to -16 */ + 11, 79, + (1 << 13) - 825 - 117, + (1 << 13) - 837 - 117, + (1 << 13) - 811 - 117, + (1 << 13) - 766 - 117, + (1 << 13) - 737 - 117, + (1 << 13) - 693 - 117, + (1 << 13) - 648 - 117, + (1 << 13) - 619 - 117, + (1 << 13) - 575 - 117, + (1 << 13) - 531 - 117, + (1 << 13) - 501 - 117, + + 1, 142, + 0x0410, // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16 + + /* disable power smoothing */ + 8, 145, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + + 1, 154, + 1 << 13, // P_fft_freq_dir=1, P_fft_nb_to_cut=0 + + 1, 168, + 0x0ccd, // P_pha3_thres, default 0x3000 + +// 1, 169, +// 0x0010, // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010 + + 1, 183, + 0x200f, // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005 + + 5, 187, + 0x023d, // P_adp_regul_cnt=573, default: 410 + 0x00a4, // P_adp_noise_cnt= + 0x00a4, // P_adp_regul_ext + 0x7ff0, // P_adp_noise_ext + 0x3ccc, // P_adp_fil + + 1, 198, + 0x800, // P_equal_thres_wgn + + 1, 222, + 0x0010, // P_fec_ber_rs_len=2 + + 1, 235, + 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard + + 2, 901, + 0x0006, // P_clk_cfg1 + (3 << 10) | (1 << 6), // P_divclksel=3 P_divbitsel=1 + + 1, 905, + 0x2c8e, // Tuner IO bank: max drive (14mA) + divout pads max drive + + 0, +}; + static int dib7000p_demod_reset(struct dib7000p_state *state) { dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); @@ -292,111 +489,307 @@ static int dib7000p_demod_reset(struct dib7000p_state *state) dib7000p_reset_pll(state); if (dib7000p_reset_gpio(state) != 0) - dprintk("-E- GPIO reset was not successful.\n"); + dprintk( "GPIO reset was not successful."); if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0) - dprintk("-E- OUTPUT_MODE could not be resetted.\n"); + dprintk( "OUTPUT_MODE could not be reset."); /* unforce divstr regardless whether i2c enumeration was done or not */ dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1) ); + dib7000p_set_bandwidth(state, 8000); + + dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON); + dib7000p_sad_calib(state); + dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF); + + // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ... + if(state->cfg.tuner_is_baseband) + dib7000p_write_word(state, 36,0x0755); + else + dib7000p_write_word(state, 36,0x1f55); + + dib7000p_write_tab(state, dib7000p_defaults); + dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); + return 0; } +static void dib7000p_pll_clk_cfg(struct dib7000p_state *state) +{ + u16 tmp = 0; + tmp = dib7000p_read_word(state, 903); + dib7000p_write_word(state, 903, (tmp | 0x1)); //pwr-up pll + tmp = dib7000p_read_word(state, 900); + dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock +} + static void dib7000p_restart_agc(struct dib7000p_state *state) { // P_restart_iqc & P_restart_agc - dib7000p_write_word(state, 770, 0x0c00); + dib7000p_write_word(state, 770, (1 << 11) | (1 << 9)); dib7000p_write_word(state, 770, 0x0000); } -static void dib7000p_update_lna(struct dib7000p_state *state) +static int dib7000p_update_lna(struct dib7000p_state *state) { - int i; u16 dyn_gain; // when there is no LNA to program return immediatly - if (state->cfg.update_lna == NULL) - return; - - for (i = 0; i < 5; i++) { - // read dyn_gain here (because it is demod-dependent and not tuner) + if (state->cfg.update_lna) { + // read dyn_gain here (because it is demod-dependent and not fe) dyn_gain = dib7000p_read_word(state, 394); - if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed dib7000p_restart_agc(state); - msleep(5); - } else + return 1; + } + } + + return 0; +} + +static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band) +{ + struct dibx000_agc_config *agc = NULL; + int i; + if (state->current_band == band && state->current_agc != NULL) + return 0; + state->current_band = band; + + for (i = 0; i < state->cfg.agc_config_count; i++) + if (state->cfg.agc[i].band_caps & band) { + agc = &state->cfg.agc[i]; break; + } + + if (agc == NULL) { + dprintk( "no valid AGC configuration found for band 0x%02x",band); + return -EINVAL; } + + state->current_agc = agc; + + /* AGC */ + dib7000p_write_word(state, 75 , agc->setup ); + dib7000p_write_word(state, 76 , agc->inv_gain ); + dib7000p_write_word(state, 77 , agc->time_stabiliz ); + dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock); + + // Demod AGC loop configuration + dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp); + dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp); + + /* AGC continued */ + dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d", + state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); + + if (state->wbd_ref != 0) + dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref); + else + dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref); + + dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8)); + + dib7000p_write_word(state, 107, agc->agc1_max); + dib7000p_write_word(state, 108, agc->agc1_min); + dib7000p_write_word(state, 109, agc->agc2_max); + dib7000p_write_word(state, 110, agc->agc2_min); + dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2); + dib7000p_write_word(state, 112, agc->agc1_pt3); + dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2); + dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2); + dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2); + return 0; } -static void dib7000p_pll_clk_cfg(struct dib7000p_state *state) +static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { - u16 tmp = 0; - tmp = dib7000p_read_word(state, 903); - dib7000p_write_word(state, 903, (tmp | 0x1)); //pwr-up pll - tmp = dib7000p_read_word(state, 900); - dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock + struct dib7000p_state *state = demod->demodulator_priv; + int ret = -1; + u8 *agc_state = &state->agc_state; + u8 agc_split; + + switch (state->agc_state) { + case 0: + // set power-up level: interf+analog+AGC + dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); + dib7000p_set_adc_state(state, DIBX000_ADC_ON); + dib7000p_pll_clk_cfg(state); + + if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0) + return -1; + + ret = 7; + (*agc_state)++; + break; + + case 1: + // AGC initialization + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 1); + + dib7000p_write_word(state, 78, 32768); + if (!state->current_agc->perform_agc_softsplit) { + /* we are using the wbd - so slow AGC startup */ + /* force 0 split on WBD and restart AGC */ + dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8)); + (*agc_state)++; + ret = 5; + } else { + /* default AGC startup */ + (*agc_state) = 4; + /* wait AGC rough lock time */ + ret = 7; + } + + dib7000p_restart_agc(state); + break; + + case 2: /* fast split search path after 5sec */ + dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */ + dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */ + (*agc_state)++; + ret = 14; + break; + + case 3: /* split search ended */ + agc_split = (u8)dib7000p_read_word(state, 396); /* store the split value for the next time */ + dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */ + + dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */ + dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */ + + dib7000p_restart_agc(state); + + dprintk( "SPLIT %p: %hd", demod, agc_split); + + (*agc_state)++; + ret = 5; + break; + + case 4: /* LNA startup */ + // wait AGC accurate lock time + ret = 7; + + if (dib7000p_update_lna(state)) + // wait only AGC rough lock time + ret = 5; + else // nothing was done, go to the next state + (*agc_state)++; + break; + + case 5: + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 0); + (*agc_state)++; + break; + default: + break; + } + return ret; } -static void dib7000p_update_timf_freq(struct dib7000p_state *state) +static void dib7000p_update_timf(struct dib7000p_state *state) { u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428); - state->timf = timf * 80 / (BW_INDEX_TO_KHZ(state->current_bandwidth) / 100); + state->timf = timf * 160 / (state->current_bandwidth / 50); dib7000p_write_word(state, 23, (u16) (timf >> 16)); dib7000p_write_word(state, 24, (u16) (timf & 0xffff)); - dprintk("-D- Updated timf_frequency: %d (default: %d)\n",state->timf, state->cfg.bw->timf); + dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->cfg.bw->timf); + } -static void dib7000p_set_channel(struct dib7000p_state *state, struct dibx000_ofdm_channel *ch, u8 seq) +static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq) { - u16 tmp, est[4]; // reg_26, reg_32, reg_33, reg_187, reg_188, reg_189, reg_190, reg_207, reg_208; + u16 value, est[4]; + + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); /* nfft, guard, qam, alpha */ - dib7000p_write_word(state, 0, (ch->nfft << 7) | (ch->guard << 5) | (ch->nqam << 3) | (ch->vit_alpha)); + value = 0; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= (0 << 7); break; + case /* 4K MODE */ 255: value |= (2 << 7); break; + default: + case TRANSMISSION_MODE_8K: value |= (1 << 7); break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_32: value |= (0 << 5); break; + case GUARD_INTERVAL_1_16: value |= (1 << 5); break; + case GUARD_INTERVAL_1_4: value |= (3 << 5); break; + default: + case GUARD_INTERVAL_1_8: value |= (2 << 5); break; + } + switch (ch->u.ofdm.constellation) { + case QPSK: value |= (0 << 3); break; + case QAM_16: value |= (1 << 3); break; + default: + case QAM_64: value |= (2 << 3); break; + } + switch (HIERARCHY_1) { + case HIERARCHY_2: value |= 2; break; + case HIERARCHY_4: value |= 4; break; + default: + case HIERARCHY_1: value |= 1; break; + } + dib7000p_write_word(state, 0, value); dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */ - /* P_dintl_native, P_dintlv_inv, P_vit_hrch, P_vit_code_rate, P_vit_select_hp */ - tmp = (ch->intlv_native << 6) | (ch->vit_hrch << 4) | (ch->vit_select_hp & 0x1); - if (ch->vit_hrch == 0 || ch->vit_select_hp == 1) - tmp |= (ch->vit_code_rate_hp << 1); - else - tmp |= (ch->vit_code_rate_lp << 1); - dib7000p_write_word(state, 208, tmp); + /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */ + value = 0; + if (1 != 0) + value |= (1 << 6); + if (ch->u.ofdm.hierarchy_information == 1) + value |= (1 << 4); + if (1 == 1) + value |= 1; + switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + case FEC_2_3: value |= (2 << 1); break; + case FEC_3_4: value |= (3 << 1); break; + case FEC_5_6: value |= (5 << 1); break; + case FEC_7_8: value |= (7 << 1); break; + default: + case FEC_1_2: value |= (1 << 1); break; + } + dib7000p_write_word(state, 208, value); + + /* offset loop parameters */ + dib7000p_write_word(state, 26, 0x6680); // timf(6xxx) + dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3) + dib7000p_write_word(state, 29, 0x1273); // isi + dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5) /* P_dvsy_sync_wait */ - switch (ch->nfft) { - case 1: tmp = 256; break; - case 2: tmp = 128; break; - case 0: - default: tmp = 64; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_8K: value = 256; break; + case /* 4K MODE */ 255: value = 128; break; + case TRANSMISSION_MODE_2K: + default: value = 64; break; } - tmp *= ((1 << (ch->guard)) * 3 / 2); // add 50% SFN margin - tmp <<= 4; - - /* deactive the possibility of diversity reception if extended interleave */ - /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ - if (ch->intlv_native || ch->nfft == 1) - tmp |= (1 << 2) | (2 << 0); - dib7000p_write_word(state, 207, tmp); + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_16: value *= 2; break; + case GUARD_INTERVAL_1_8: value *= 4; break; + case GUARD_INTERVAL_1_4: value *= 8; break; + default: + case GUARD_INTERVAL_1_32: value *= 1; break; + } + state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO - dib7000p_write_word(state, 26, 0x6680); // timf(6xxx) - dib7000p_write_word(state, 29, 0x1273); // isi inh1273 on1073 - dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3) - dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5) + /* deactive the possibility of diversity reception if extended interleaver */ + state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K; + dib7000p_set_diversity_in(&state->demod, state->div_state); /* channel estimation fine configuration */ - switch (ch->nqam) { - case 2: + switch (ch->u.ofdm.constellation) { + case QAM_64: est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */ break; - case 1: + case QAM_16: est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */ est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ @@ -409,66 +802,45 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dibx000_of est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */ break; } - for (tmp = 0; tmp < 4; tmp++) - dib7000p_write_word(state, 187 + tmp, est[tmp]); - - // set power-up level: interf+analog+AGC - dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); - dib7000p_set_adc_state(state, DIBX000_ADC_ON); - dib7000p_pll_clk_cfg(state); - msleep(7); - - // AGC initialization - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 1); - - dib7000p_restart_agc(state); - - // wait AGC rough lock time - msleep(5); - - dib7000p_update_lna(state); - - // wait AGC accurate lock time - msleep(7); - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 0); + for (value = 0; value < 4; value++) + dib7000p_write_word(state, 187 + value, est[value]); } -static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib7000p_state *state = demod->demodulator_priv; - struct dibx000_ofdm_channel auto_ch; - u32 value; - - INIT_OFDM_CHANNEL(&auto_ch); - auto_ch.RF_kHz = ch->RF_kHz; - auto_ch.Bw = ch->Bw; - auto_ch.nqam = 2; - auto_ch.guard = 0; - auto_ch.nfft = 1; - auto_ch.vit_alpha = 1; - auto_ch.vit_select_hp = 1; - auto_ch.vit_code_rate_hp = 2; - auto_ch.vit_code_rate_lp = 3; - auto_ch.vit_hrch = 0; - auto_ch.intlv_native = 1; - - dib7000p_set_channel(state, &auto_ch, 7); + struct dvb_frontend_parameters schan; + u32 value, factor; + + schan = *ch; + schan.u.ofdm.constellation = QAM_64; + schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + schan.u.ofdm.code_rate_HP = FEC_2_3; + schan.u.ofdm.code_rate_LP = FEC_3_4; + schan.u.ofdm.hierarchy_information = 0; + + dib7000p_set_channel(state, &schan, 7); + + factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth); + if (factor >= 5000) + factor = 1; + else + factor = 6; // always use the setting for 8MHz here lock_time for 7,6 MHz are longer - value = 30 * state->cfg.bw->internal; + value = 30 * state->cfg.bw->internal * factor; dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time dib7000p_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time - value = 100 * state->cfg.bw->internal; + value = 100 * state->cfg.bw->internal * factor; dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time dib7000p_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time - value = 500 * state->cfg.bw->internal; + value = 500 * state->cfg.bw->internal * factor; dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time dib7000p_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time value = dib7000p_read_word(state, 0); - dib7000p_write_word(state, 0, (1 << 9) | value); + dib7000p_write_word(state, 0, (u16) ((1 << 9) | value)); dib7000p_read_word(state, 1284); dib7000p_write_word(state, 0, (u16) value); @@ -489,7 +861,95 @@ static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod) return 0; // still pending } -static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw) +{ + static s16 notch[]={16143, 14402, 12238, 9713, 6902, 3888, 759, -2392}; + static u8 sine [] ={0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22, + 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51, + 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80, + 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105, + 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126, + 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146, + 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165, + 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182, + 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212, + 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224, + 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235, + 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243, + 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249, + 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254, + 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255}; + + u32 xtal = state->cfg.bw->xtal_hz / 1000; + int f_rel = ( (rf_khz + xtal/2) / xtal) * xtal - rf_khz; + int k; + int coef_re[8],coef_im[8]; + int bw_khz = bw; + u32 pha; + + dprintk( "relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal); + + + if (f_rel < -bw_khz/2 || f_rel > bw_khz/2) + return; + + bw_khz /= 100; + + dib7000p_write_word(state, 142 ,0x0610); + + for (k = 0; k < 8; k++) { + pha = ((f_rel * (k+1) * 112 * 80/bw_khz) /1000) & 0x3ff; + + if (pha==0) { + coef_re[k] = 256; + coef_im[k] = 0; + } else if(pha < 256) { + coef_re[k] = sine[256-(pha&0xff)]; + coef_im[k] = sine[pha&0xff]; + } else if (pha == 256) { + coef_re[k] = 0; + coef_im[k] = 256; + } else if (pha < 512) { + coef_re[k] = -sine[pha&0xff]; + coef_im[k] = sine[256 - (pha&0xff)]; + } else if (pha == 512) { + coef_re[k] = -256; + coef_im[k] = 0; + } else if (pha < 768) { + coef_re[k] = -sine[256-(pha&0xff)]; + coef_im[k] = -sine[pha&0xff]; + } else if (pha == 768) { + coef_re[k] = 0; + coef_im[k] = -256; + } else { + coef_re[k] = sine[pha&0xff]; + coef_im[k] = -sine[256 - (pha&0xff)]; + } + + coef_re[k] *= notch[k]; + coef_re[k] += (1<<14); + if (coef_re[k] >= (1<<24)) + coef_re[k] = (1<<24) - 1; + coef_re[k] /= (1<<15); + + coef_im[k] *= notch[k]; + coef_im[k] += (1<<14); + if (coef_im[k] >= (1<<24)) + coef_im[k] = (1<<24)-1; + coef_im[k] /= (1<<15); + + dprintk( "PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]); + + dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff)); + dib7000p_write_word(state, 144, coef_im[k] & 0x3ff); + dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff)); + } + dib7000p_write_word(state,143 ,0); +} + +static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib7000p_state *state = demod->demodulator_priv; u16 tmp = 0; @@ -505,7 +965,15 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel msleep(45); /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */ - dib7000p_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3)); + tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3); + if (state->sfn_workaround_active) { + dprintk( "SFN workaround is active"); + tmp |= (1 << 9); + dib7000p_write_word(state, 166, 0x4000); // P_pha3_force_pha_shift + } else { + dib7000p_write_word(state, 166, 0x0000); // P_pha3_force_pha_shift + } + dib7000p_write_word(state, 29, tmp); // never achieved a lock with that bandwidth so far - wait for osc-freq to update if (state->timf == 0) @@ -515,28 +983,31 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */ tmp = (6 << 8) | 0x80; - switch (ch->nfft) { - case 0: tmp |= (7 << 12); break; - case 1: tmp |= (9 << 12); break; - case 2: tmp |= (8 << 12); break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: tmp |= (7 << 12); break; + case /* 4K MODE */ 255: tmp |= (8 << 12); break; + default: + case TRANSMISSION_MODE_8K: tmp |= (9 << 12); break; } dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */ /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */ tmp = (0 << 4); - switch (ch->nfft) { - case 0: tmp |= 0x6; break; - case 1: tmp |= 0x8; break; - case 2: tmp |= 0x7; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: tmp |= 0x6; break; + case /* 4K MODE */ 255: tmp |= 0x7; break; + default: + case TRANSMISSION_MODE_8K: tmp |= 0x8; break; } dib7000p_write_word(state, 32, tmp); /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */ tmp = (0 << 4); - switch (ch->nfft) { - case 0: tmp |= 0x6; break; - case 1: tmp |= 0x8; break; - case 2: tmp |= 0x7; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: tmp |= 0x6; break; + case /* 4K MODE */ 255: tmp |= 0x7; break; + default: + case TRANSMISSION_MODE_8K: tmp |= 0x8; break; } dib7000p_write_word(state, 33, tmp); @@ -552,131 +1023,21 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel // we achieved a lock - it's time to update the osc freq if ((tmp >> 6) & 0x1) - dib7000p_update_timf_freq(state); + dib7000p_update_timf(state); + if (state->cfg.spur_protect) + dib7000p_spur_protect(state, ch->frequency/1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); return 0; } -static int dib7000p_init(struct dvb_frontend *demod) +static int dib7000p_wakeup(struct dvb_frontend *demod) { - struct dibx000_agc_config *agc; struct dib7000p_state *state = demod->demodulator_priv; - int ret = 0; - - // Demodulator default configuration - agc = state->cfg.agc; - dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON); - - /* AGC */ - ret |= dib7000p_write_word(state, 75 , agc->setup ); - ret |= dib7000p_write_word(state, 76 , agc->inv_gain ); - ret |= dib7000p_write_word(state, 77 , agc->time_stabiliz ); - ret |= dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock); - - // Demod AGC loop configuration - ret |= dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp); - ret |= dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp); - - /* AGC continued */ - dprintk("-D- WBD: ref: %d, sel: %d, active: %d, alpha: %d\n", - state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); - - if (state->wbd_ref != 0) - ret |= dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref); - else - ret |= dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref); - - ret |= dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8) ); - - ret |= dib7000p_write_word(state, 107, agc->agc1_max); - ret |= dib7000p_write_word(state, 108, agc->agc1_min); - ret |= dib7000p_write_word(state, 109, agc->agc2_max); - ret |= dib7000p_write_word(state, 110, agc->agc2_min); - ret |= dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2 ); - ret |= dib7000p_write_word(state, 112, agc->agc1_pt3); - ret |= dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2); - ret |= dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2); - ret |= dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2); - - /* disable power smoothing */ - ret |= dib7000p_write_word(state, 145, 0); - ret |= dib7000p_write_word(state, 146, 0); - ret |= dib7000p_write_word(state, 147, 0); - ret |= dib7000p_write_word(state, 148, 0); - ret |= dib7000p_write_word(state, 149, 0); - ret |= dib7000p_write_word(state, 150, 0); - ret |= dib7000p_write_word(state, 151, 0); - ret |= dib7000p_write_word(state, 152, 0); - - // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26 - ret |= dib7000p_write_word(state, 26 ,0x6680); - - // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16 - ret |= dib7000p_write_word(state, 142,0x0410); - // P_fft_freq_dir=1, P_fft_nb_to_cut=0 - ret |= dib7000p_write_word(state, 154,1 << 13); - // P_pha3_thres, default 0x3000 - ret |= dib7000p_write_word(state, 168,0x0ccd); - // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010 - //ret |= dib7000p_write_word(state, 169,0x0010); - // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005 - ret |= dib7000p_write_word(state, 183,0x200f); - // P_adp_regul_cnt=573, default: 410 - ret |= dib7000p_write_word(state, 187,0x023d); - // P_adp_noise_cnt= - ret |= dib7000p_write_word(state, 188,0x00a4); - // P_adp_regul_ext - ret |= dib7000p_write_word(state, 189,0x00a4); - // P_adp_noise_ext - ret |= dib7000p_write_word(state, 190,0x7ff0); - // P_adp_fil - ret |= dib7000p_write_word(state, 191,0x3ccc); - - ret |= dib7000p_write_word(state, 222,0x0010); - // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard - ret |= dib7000p_write_word(state, 235,0x0062); - - // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ... - if(state->cfg.tuner_is_baseband) - ret |= dib7000p_write_word(state, 36,0x0755); - else - ret |= dib7000p_write_word(state, 36,0x1f55); - - // auto search configuration - ret |= dib7000p_write_word(state, 2 ,0x0004); - ret |= dib7000p_write_word(state, 3 ,0x1000); - - /* Equal Lock */ - ret |= dib7000p_write_word(state, 4 ,0x0814); - - ret |= dib7000p_write_word(state, 6 ,0x001b); - ret |= dib7000p_write_word(state, 7 ,0x7740); - ret |= dib7000p_write_word(state, 8 ,0x005b); - ret |= dib7000p_write_word(state, 9 ,0x8d80); - ret |= dib7000p_write_word(state, 10 ,0x01c9); - ret |= dib7000p_write_word(state, 11 ,0xc380); - ret |= dib7000p_write_word(state, 12 ,0x0000); - ret |= dib7000p_write_word(state, 13 ,0x0080); - ret |= dib7000p_write_word(state, 14 ,0x0000); - ret |= dib7000p_write_word(state, 15 ,0x0090); - ret |= dib7000p_write_word(state, 16 ,0x0001); - ret |= dib7000p_write_word(state, 17 ,0xd4c0); - - // P_clk_cfg1 - ret |= dib7000p_write_word(state, 901, 0x0006); - - // P_divclksel=3 P_divbitsel=1 - ret |= dib7000p_write_word(state, 902, (3 << 10) | (1 << 6)); - - // Tuner IO bank: max drive (14mA) + divout pads max drive - ret |= dib7000p_write_word(state, 905, 0x2c8e); - - ret |= dib7000p_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ); - dib7000p_sad_calib(state); - - return ret; + return 0; } static int dib7000p_sleep(struct dvb_frontend *demod) @@ -688,16 +1049,16 @@ static int dib7000p_sleep(struct dvb_frontend *demod) static int dib7000p_identify(struct dib7000p_state *st) { u16 value; - dprintk("-I- DiB7000PC: checking demod on I2C address: %d (%x)\n", + dprintk( "checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr); if ((value = dib7000p_read_word(st, 768)) != 0x01b3) { - dprintk("-E- DiB7000PC: wrong Vendor ID (read=0x%x)\n",value); + dprintk( "wrong Vendor ID (read=0x%x)",value); return -EREMOTEIO; } if ((value = dib7000p_read_word(st, 769)) != 0x4000) { - dprintk("-E- DiB7000PC: wrong Device ID (%x)\n",value); + dprintk( "wrong Device ID (%x)",value); return -EREMOTEIO; } @@ -767,41 +1128,48 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib7000p_state *state = fe->demodulator_priv; - struct dibx000_ofdm_channel ch; - - INIT_OFDM_CHANNEL(&ch); - FEP2DIB(fep,&ch); + int time; state->current_bandwidth = fep->u.ofdm.bandwidth; - dib7000p_set_bandwidth(fe, fep->u.ofdm.bandwidth); + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); + + /* maybe the parameter has been changed */ + state->sfn_workaround_active = buggy_sfn_workaround; if (fe->ops.tuner_ops.set_params) fe->ops.tuner_ops.set_params(fe, fep); + /* start up the AGC */ + state->agc_state = 0; + do { + time = dib7000p_agc_startup(fe, fep); + if (time != -1) + msleep(time); + } while (time != -1); + if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { int i = 800, found; - dib7000p_autosearch_start(fe, &ch); + dib7000p_autosearch_start(fe, fep); do { msleep(1); found = dib7000p_autosearch_is_irq(fe); } while (found == 0 && i--); - dprintk("autosearch returns: %d\n",found); + dprintk("autosearch returns: %d",found); if (found == 0 || found == 1) return 0; // no channel found dib7000p_get_frontend(fe, fep); - FEP2DIB(fep, &ch); } /* make this a config parameter */ dib7000p_set_output_mode(state, OUTMODE_MPEG2_FIFO); - return dib7000p_tune(fe, &ch); + return dib7000p_tune(fe, fep); } static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat) @@ -879,7 +1247,7 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap) if (i2c_transfer(i2c_adap, msg, 2) == 2) if (rx[0] == 0x01 && rx[1] == 0xb3) { - dprintk("-D- DiB7000PC detected\n"); + dprintk("-D- DiB7000PC detected"); return 1; } @@ -887,11 +1255,11 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap) if (i2c_transfer(i2c_adap, msg, 2) == 2) if (rx[0] == 0x01 && rx[1] == 0xb3) { - dprintk("-D- DiB7000PC detected\n"); + dprintk("-D- DiB7000PC detected"); return 1; } - dprintk("-D- DiB7000PC not detected\n"); + dprintk("-D- DiB7000PC not detected"); return 0; } EXPORT_SYMBOL(dib7000pc_detection); @@ -929,7 +1297,7 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau /* set new i2c address and force divstart */ dib7000p_write_word(&st, 1285, (new_addr << 2) | 0x2); - dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr); + dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); } for (k = 0; k < no_of_demods; k++) { @@ -1000,7 +1368,7 @@ static struct dvb_frontend_ops dib7000p_ops = { .release = dib7000p_release, - .init = dib7000p_init, + .init = dib7000p_wakeup, .sleep = dib7000p_sleep, .set_frontend = dib7000p_set_frontend, diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h index 79465cf1ace..eefcac8b524 100644 --- a/drivers/media/dvb/frontends/dib7000p.h +++ b/drivers/media/dvb/frontends/dib7000p.h @@ -9,6 +9,7 @@ struct dib7000p_config { u8 tuner_is_baseband; int (*update_lna) (struct dvb_frontend *, u16 agc_global); + u8 agc_config_count; struct dibx000_agc_config *agc; struct dibx000_bandwidth_config *bw; @@ -27,20 +28,19 @@ struct dib7000p_config { u8 quartz_direct; + u8 spur_protect; + int (*agc_control) (struct dvb_frontend *, u8 before); }; #define DEFAULT_DIB7000P_I2C_ADDRESS 18 extern struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg); +extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]); + extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); extern int dib7000pc_detection(struct i2c_adapter *i2c_adap); - -/* TODO -extern INT dib7000p_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val); -extern INT dib7000p_enable_vbg_voltage(struct dibDemod *demod); -extern void dib7000p_set_hostbus_diversity(struct dibDemod *demod, UCHAR onoff); -extern USHORT dib7000p_get_current_agc_global(struct dibDemod *demod); -*/ +extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); +extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value); #endif diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h index a1df604366c..5e17275afd2 100644 --- a/drivers/media/dvb/frontends/dibx000_common.h +++ b/drivers/media/dvb/frontends/dibx000_common.h @@ -111,6 +111,8 @@ struct dibx000_bandwidth_config { u32 ifreq; u32 timf; + + u32 xtal_hz; }; enum dibx000_adc_states { @@ -122,56 +124,17 @@ enum dibx000_adc_states { DIBX000_VBG_DISABLE, }; -#define BW_INDEX_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ ? 8000 : \ +#define BANDWIDTH_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ ? 8000 : \ (v) == BANDWIDTH_7_MHZ ? 7000 : \ (v) == BANDWIDTH_6_MHZ ? 6000 : 8000 ) /* Chip output mode. */ -#define OUTMODE_HIGH_Z 0 -#define OUTMODE_MPEG2_PAR_GATED_CLK 1 -#define OUTMODE_MPEG2_PAR_CONT_CLK 2 -#define OUTMODE_MPEG2_SERIAL 7 -#define OUTMODE_DIVERSITY 4 -#define OUTMODE_MPEG2_FIFO 5 - -/* I hope I can get rid of the following kludge in the near future */ -struct dibx000_ofdm_channel { - u32 RF_kHz; - u8 Bw; - s16 nfft; - s16 guard; - s16 nqam; - s16 vit_hrch; - s16 vit_select_hp; - s16 vit_alpha; - s16 vit_code_rate_hp; - s16 vit_code_rate_lp; - u8 intlv_native; -}; - -#define FEP2DIB(fep,ch) \ - (ch)->RF_kHz = (fep)->frequency / 1000; \ - (ch)->Bw = (fep)->u.ofdm.bandwidth; \ - (ch)->nfft = (fep)->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ? -1 : (fep)->u.ofdm.transmission_mode; \ - (ch)->guard = (fep)->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ? -1 : (fep)->u.ofdm.guard_interval; \ - (ch)->nqam = (fep)->u.ofdm.constellation == QAM_AUTO ? -1 : (fep)->u.ofdm.constellation == QAM_64 ? 2 : (fep)->u.ofdm.constellation; \ - (ch)->vit_hrch = 0; /* linux-dvb is not prepared for HIERARCHICAL TRANSMISSION */ \ - (ch)->vit_select_hp = 1; \ - (ch)->vit_alpha = 1; \ - (ch)->vit_code_rate_hp = (fep)->u.ofdm.code_rate_HP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_HP; \ - (ch)->vit_code_rate_lp = (fep)->u.ofdm.code_rate_LP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_LP; \ - (ch)->intlv_native = 1; - -#define INIT_OFDM_CHANNEL(ch) do {\ - (ch)->Bw = 0; \ - (ch)->nfft = -1; \ - (ch)->guard = -1; \ - (ch)->nqam = -1; \ - (ch)->vit_hrch = -1; \ - (ch)->vit_select_hp = -1; \ - (ch)->vit_alpha = -1; \ - (ch)->vit_code_rate_hp = -1; \ - (ch)->vit_code_rate_lp = -1; \ -} while (0) +#define OUTMODE_HIGH_Z 0 +#define OUTMODE_MPEG2_PAR_GATED_CLK 1 +#define OUTMODE_MPEG2_PAR_CONT_CLK 2 +#define OUTMODE_MPEG2_SERIAL 7 +#define OUTMODE_DIVERSITY 4 +#define OUTMODE_MPEG2_FIFO 5 +#define OUTMODE_ANALOG_ADC 6 #endif diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 11f7d5939bd..8c8d7342d0b 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -24,12 +24,48 @@ #include "dvb-pll.h" +struct dvb_pll_priv { + /* pll number */ + int nr; + + /* i2c details */ + int pll_i2c_address; + struct i2c_adapter *i2c; + + /* the PLL descriptor */ + struct dvb_pll_desc *pll_desc; + + /* cached frequency/bandwidth */ + u32 frequency; + u32 bandwidth; +}; + +#define DVB_PLL_MAX 64 + +static unsigned int dvb_pll_devcount; + +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +static unsigned int input[DVB_PLL_MAX] = { [ 0 ... (DVB_PLL_MAX-1) ] = 0 }; +module_param_array(input, int, NULL, 0644); +MODULE_PARM_DESC(input,"specify rf input choice, 0 for autoselect (default)"); + +static unsigned int id[DVB_PLL_MAX] = + { [ 0 ... (DVB_PLL_MAX-1) ] = DVB_PLL_UNDEFINED }; +module_param_array(id, int, NULL, 0644); +MODULE_PARM_DESC(id, "force pll id to use (DEBUG ONLY)"); + +/* ----------------------------------------------------------- */ + struct dvb_pll_desc { char *name; u32 min; u32 max; u32 iffreq; - void (*set)(u8 *buf, const struct dvb_frontend_parameters *params); + void (*set)(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params); u8 *initdata; u8 *sleepdata; int count; @@ -89,7 +125,7 @@ static struct dvb_pll_desc dvb_pll_thomson_dtt7610 = { }, }; -static void thomson_dtt759x_bw(u8 *buf, +static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf, const struct dvb_frontend_parameters *params) { if (BANDWIDTH_7_MHZ == params->u.ofdm.bandwidth) @@ -210,7 +246,8 @@ static struct dvb_pll_desc dvb_pll_env57h1xd5 = { /* Philips TDA6650/TDA6651 * used in Panasonic ENV77H11D5 */ -static void tda665x_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void tda665x_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) buf[3] |= 0x08; @@ -243,7 +280,8 @@ static struct dvb_pll_desc dvb_pll_tda665x = { /* Infineon TUA6034 * used in LG TDTP E102P */ -static void tua6034_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void tua6034_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { if (BANDWIDTH_7_MHZ != params->u.ofdm.bandwidth) buf[3] |= 0x08; @@ -283,7 +321,8 @@ static struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = { /* Philips FMD1216ME * used in Medion Hybrid PCMCIA card and USB Box */ -static void fmd1216me_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void fmd1216me_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ && params->frequency >= 158870000) @@ -313,7 +352,8 @@ static struct dvb_pll_desc dvb_pll_fmd1216me = { /* ALPS TDED4 * used in Nebula-Cards and USB boxes */ -static void tded4_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void tded4_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) buf[3] |= 0x04; @@ -354,16 +394,35 @@ static struct dvb_pll_desc dvb_pll_tdhu2 = { /* Philips TUV1236D * used in ATI HDTV Wonder */ -static void tuv1236d_rf(u8 *buf, const struct dvb_frontend_parameters *params) +static void tuv1236d_rf(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { - switch (params->u.vsb.modulation) { - case QAM_64: - case QAM_256: + struct dvb_pll_priv *priv = fe->tuner_priv; + unsigned int new_rf = input[priv->nr]; + + if ((new_rf == 0) || (new_rf > 2)) { + switch (params->u.vsb.modulation) { + case QAM_64: + case QAM_256: + new_rf = 1; + break; + case VSB_8: + default: + new_rf = 2; + } + } + + switch (new_rf) { + case 1: buf[3] |= 0x08; break; - case VSB_8: - default: + case 2: buf[3] &= ~0x08; + break; + default: + printk(KERN_WARNING + "%s: unhandled rf input selection: %d", + __FUNCTION__, new_rf); } } @@ -420,7 +479,8 @@ static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = { /* * Philips TD1316 Tuner. */ -static void td1316_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void td1316_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { u8 band; @@ -474,7 +534,8 @@ static struct dvb_pll_desc dvb_pll_thomson_fe6600 = { } }; -static void opera1_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void opera1_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) buf[2] |= 0x08; @@ -546,30 +607,13 @@ static struct dvb_pll_desc *pll_list[] = { }; /* ----------------------------------------------------------- */ - -struct dvb_pll_priv { - /* i2c details */ - int pll_i2c_address; - struct i2c_adapter *i2c; - - /* the PLL descriptor */ - struct dvb_pll_desc *pll_desc; - - /* cached frequency/bandwidth */ - u32 frequency; - u32 bandwidth; -}; - -/* ----------------------------------------------------------- */ /* code */ -static int debug = 0; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable verbose debug messages"); - -static int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, +static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf, const struct dvb_frontend_parameters *params) { + struct dvb_pll_priv *priv = fe->tuner_priv; + struct dvb_pll_desc *desc = priv->pll_desc; u32 div; int i; @@ -597,7 +641,7 @@ static int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, buf[3] = desc->entries[i].cb; if (desc->set) - desc->set(buf, params); + desc->set(fe, buf, params); if (debug) printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", @@ -654,7 +698,7 @@ static int dvb_pll_set_params(struct dvb_frontend *fe, if (priv->i2c == NULL) return -EINVAL; - if ((result = dvb_pll_configure(priv->pll_desc, buf, params)) < 0) + if ((result = dvb_pll_configure(fe, buf, params)) < 0) return result; else frequency = result; @@ -682,7 +726,7 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe, if (buf_len < 5) return -EINVAL; - if ((result = dvb_pll_configure(priv->pll_desc, buf+1, params)) < 0) + if ((result = dvb_pll_configure(fe, buf+1, params)) < 0) return result; else frequency = result; @@ -755,6 +799,10 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, int ret; struct dvb_pll_desc *desc; + if ((id[dvb_pll_devcount] > DVB_PLL_UNDEFINED) && + (id[dvb_pll_devcount] < ARRAY_SIZE(pll_list))) + pll_desc_id = id[dvb_pll_devcount]; + BUG_ON(pll_desc_id < 1 || pll_desc_id >= ARRAY_SIZE(pll_list)); desc = pll_list[pll_desc_id]; @@ -777,6 +825,7 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, priv->pll_i2c_address = pll_addr; priv->i2c = i2c; priv->pll_desc = desc; + priv->nr = dvb_pll_devcount++; memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, sizeof(struct dvb_tuner_ops)); @@ -791,6 +840,30 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, fe->ops.tuner_ops.sleep = NULL; fe->tuner_priv = priv; + + if ((debug) || (id[priv->nr] == pll_desc_id)) { + printk("dvb-pll[%d]", priv->nr); + if (i2c != NULL) + printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr); + printk(": id# %d (%s) attached, %s\n", pll_desc_id, desc->name, + id[priv->nr] == pll_desc_id ? + "insmod option" : "autodetected"); + } + if ((debug) || (input[priv->nr] > 0)) { + printk("dvb-pll[%d]", priv->nr); + if (i2c != NULL) + printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr); + printk(": tuner rf input will be "); + switch (input[priv->nr]) { + case 0: + printk("autoselected\n"); + break; + default: + printk("set to input %d (insmod option)\n", + input[priv->nr]); + } + } + return fe; } EXPORT_SYMBOL(dvb_pll_attach); diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c index 6271b1e7f6a..fed09dfb2b7 100644 --- a/drivers/media/dvb/frontends/dvb_dummy_fe.c +++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c @@ -20,7 +20,6 @@ */ #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/init.h> #include <linux/string.h> #include <linux/slab.h> diff --git a/drivers/media/dvb/frontends/isl6421.c b/drivers/media/dvb/frontends/isl6421.c index c967148a594..684c8ec166c 100644 --- a/drivers/media/dvb/frontends/isl6421.c +++ b/drivers/media/dvb/frontends/isl6421.c @@ -29,7 +29,6 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/string.h> #include <linux/slab.h> diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c index 1aeacb1c4af..443d9045d4c 100644 --- a/drivers/media/dvb/frontends/l64781.c +++ b/drivers/media/dvb/frontends/l64781.c @@ -23,7 +23,6 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/string.h> #include <linux/slab.h> #include "dvb_frontend.h" diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c index e25286e2d43..bdc9fa88b86 100644 --- a/drivers/media/dvb/frontends/lgdt330x.c +++ b/drivers/media/dvb/frontends/lgdt330x.c @@ -35,7 +35,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/string.h> diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c index 2d2f58c2622..76f935d9755 100644 --- a/drivers/media/dvb/frontends/lnbp21.c +++ b/drivers/media/dvb/frontends/lnbp21.c @@ -28,7 +28,6 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/string.h> #include <linux/slab.h> diff --git a/drivers/media/dvb/frontends/mt2060.c b/drivers/media/dvb/frontends/mt2060.c index 450fad8d9b6..1305b0e63ce 100644 --- a/drivers/media/dvb/frontends/mt2060.c +++ b/drivers/media/dvb/frontends/mt2060.c @@ -22,7 +22,6 @@ /* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/delay.h> #include <linux/dvb/frontend.h> #include <linux/i2c.h> diff --git a/drivers/media/dvb/frontends/mt2131.c b/drivers/media/dvb/frontends/mt2131.c new file mode 100644 index 00000000000..4b93931de4e --- /dev/null +++ b/drivers/media/dvb/frontends/mt2131.c @@ -0,0 +1,314 @@ +/* + * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2006 Steven Toth <stoth@hauppauge.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. + */ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/dvb/frontend.h> +#include <linux/i2c.h> + +#include "dvb_frontend.h" + +#include "mt2131.h" +#include "mt2131_priv.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +#define dprintk(level,fmt, arg...) if (debug >= level) \ + printk(KERN_INFO "%s: " fmt, "mt2131", ## arg) + +static u8 mt2131_config1[] = { + 0x01, + 0x50, 0x00, 0x50, 0x80, 0x00, 0x49, 0xfa, 0x88, + 0x08, 0x77, 0x41, 0x04, 0x00, 0x00, 0x00, 0x32, + 0x7f, 0xda, 0x4c, 0x00, 0x10, 0xaa, 0x78, 0x80, + 0xff, 0x68, 0xa0, 0xff, 0xdd, 0x00, 0x00 +}; + +static u8 mt2131_config2[] = { + 0x10, + 0x7f, 0xc8, 0x0a, 0x5f, 0x00, 0x04 +}; + +static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val) +{ + struct i2c_msg msg[2] = { + { .addr = priv->cfg->i2c_address, .flags = 0, + .buf = ®, .len = 1 }, + { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, + .buf = val, .len = 1 }, + }; + + if (i2c_transfer(priv->i2c, msg, 2) != 2) { + printk(KERN_WARNING "mt2131 I2C read failed\n"); + return -EREMOTEIO; + } + return 0; +} + +static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val) +{ + u8 buf[2] = { reg, val }; + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, + .buf = buf, .len = 2 }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "mt2131 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len) +{ + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, + .flags = 0, .buf = buf, .len = len }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n", + (int)len); + return -EREMOTEIO; + } + return 0; +} + +static int mt2131_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct mt2131_priv *priv; + int ret=0, i; + u32 freq; + u8 if_band_center; + u32 f_lo1, f_lo2; + u32 div1, num1, div2, num2; + u8 b[8]; + u8 lockval = 0; + + priv = fe->tuner_priv; + if (fe->ops.info.type == FE_OFDM) + priv->bandwidth = params->u.ofdm.bandwidth; + else + priv->bandwidth = 0; + + freq = params->frequency / 1000; // Hz -> kHz + dprintk(1, "%s() freq=%d\n", __FUNCTION__, freq); + + f_lo1 = freq + MT2131_IF1 * 1000; + f_lo1 = (f_lo1 / 250) * 250; + f_lo2 = f_lo1 - freq - MT2131_IF2; + + priv->frequency = (f_lo1 - f_lo2 - MT2131_IF2) * 1000, + + /* Frequency LO1 = 16MHz * (DIV1 + NUM1/8192 ) */ + num1 = f_lo1 * 64 / (MT2131_FREF / 128); + div1 = num1 / 8192; + num1 &= 0x1fff; + + /* Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) */ + num2 = f_lo2 * 64 / (MT2131_FREF / 128); + div2 = num2 / 8192; + num2 &= 0x1fff; + + if (freq <= 82500) if_band_center = 0x00; else + if (freq <= 137500) if_band_center = 0x01; else + if (freq <= 192500) if_band_center = 0x02; else + if (freq <= 247500) if_band_center = 0x03; else + if (freq <= 302500) if_band_center = 0x04; else + if (freq <= 357500) if_band_center = 0x05; else + if (freq <= 412500) if_band_center = 0x06; else + if (freq <= 467500) if_band_center = 0x07; else + if (freq <= 522500) if_band_center = 0x08; else + if (freq <= 577500) if_band_center = 0x09; else + if (freq <= 632500) if_band_center = 0x0A; else + if (freq <= 687500) if_band_center = 0x0B; else + if (freq <= 742500) if_band_center = 0x0C; else + if (freq <= 797500) if_band_center = 0x0D; else + if (freq <= 852500) if_band_center = 0x0E; else + if (freq <= 907500) if_band_center = 0x0F; else + if (freq <= 962500) if_band_center = 0x10; else + if (freq <= 1017500) if_band_center = 0x11; else + if (freq <= 1072500) if_band_center = 0x12; else if_band_center = 0x13; + + b[0] = 1; + b[1] = (num1 >> 5) & 0xFF; + b[2] = (num1 & 0x1F); + b[3] = div1; + b[4] = (num2 >> 5) & 0xFF; + b[5] = num2 & 0x1F; + b[6] = div2; + + dprintk(1, "IF1: %dMHz IF2: %dMHz\n", MT2131_IF1, MT2131_IF2); + dprintk(1, "PLL freq=%dkHz band=%d\n", (int)freq, (int)if_band_center); + dprintk(1, "PLL f_lo1=%dkHz f_lo2=%dkHz\n", (int)f_lo1, (int)f_lo2); + dprintk(1, "PLL div1=%d num1=%d div2=%d num2=%d\n", + (int)div1, (int)num1, (int)div2, (int)num2); + dprintk(1, "PLL [1..6]: %2x %2x %2x %2x %2x %2x\n", + (int)b[1], (int)b[2], (int)b[3], (int)b[4], (int)b[5], + (int)b[6]); + + ret = mt2131_writeregs(priv,b,7); + if (ret < 0) + return ret; + + mt2131_writereg(priv, 0x0b, if_band_center); + + /* Wait for lock */ + i = 0; + do { + mt2131_readreg(priv, 0x08, &lockval); + if ((lockval & 0x88) == 0x88) + break; + msleep(4); + i++; + } while (i < 10); + + return ret; +} + +static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mt2131_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __FUNCTION__); + *frequency = priv->frequency; + return 0; +} + +static int mt2131_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct mt2131_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __FUNCTION__); + *bandwidth = priv->bandwidth; + return 0; +} + +static int mt2131_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct mt2131_priv *priv = fe->tuner_priv; + u8 lock_status = 0; + u8 afc_status = 0; + + *status = 0; + + mt2131_readreg(priv, 0x08, &lock_status); + if ((lock_status & 0x88) == 0x88) + *status = TUNER_STATUS_LOCKED; + + mt2131_readreg(priv, 0x09, &afc_status); + dprintk(1, "%s() - LO Status = 0x%x, AFC Status = 0x%x\n", + __FUNCTION__, lock_status, afc_status); + + return 0; +} + +static int mt2131_init(struct dvb_frontend *fe) +{ + struct mt2131_priv *priv = fe->tuner_priv; + int ret; + dprintk(1, "%s()\n", __FUNCTION__); + + if ((ret = mt2131_writeregs(priv, mt2131_config1, + sizeof(mt2131_config1))) < 0) + return ret; + + mt2131_writereg(priv, 0x0b, 0x09); + mt2131_writereg(priv, 0x15, 0x47); + mt2131_writereg(priv, 0x07, 0xf2); + mt2131_writereg(priv, 0x0b, 0x01); + + if ((ret = mt2131_writeregs(priv, mt2131_config2, + sizeof(mt2131_config2))) < 0) + return ret; + + return ret; +} + +static int mt2131_release(struct dvb_frontend *fe) +{ + dprintk(1, "%s()\n", __FUNCTION__); + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static const struct dvb_tuner_ops mt2131_tuner_ops = { + .info = { + .name = "Microtune MT2131", + .frequency_min = 48000000, + .frequency_max = 860000000, + .frequency_step = 50000, + }, + + .release = mt2131_release, + .init = mt2131_init, + + .set_params = mt2131_set_params, + .get_frequency = mt2131_get_frequency, + .get_bandwidth = mt2131_get_bandwidth, + .get_status = mt2131_get_status +}; + +struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mt2131_config *cfg, u16 if1) +{ + struct mt2131_priv *priv = NULL; + u8 id = 0; + + dprintk(1, "%s()\n", __FUNCTION__); + + priv = kzalloc(sizeof(struct mt2131_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->bandwidth = 6000000; /* 6MHz */ + priv->i2c = i2c; + + if (mt2131_readreg(priv, 0, &id) != 0) { + kfree(priv); + return NULL; + } + if ( (id != 0x3E) && (id != 0x3F) ) { + printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n", + cfg->i2c_address); + kfree(priv); + return NULL; + } + + printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n", + cfg->i2c_address); + memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + return fe; +} +EXPORT_SYMBOL(mt2131_attach); + +MODULE_AUTHOR("Steven Toth"); +MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver"); +MODULE_LICENSE("GPL"); + +/* + * Local variables: + * c-basic-offset: 8 + */ diff --git a/drivers/media/dvb/frontends/mt2131.h b/drivers/media/dvb/frontends/mt2131.h new file mode 100644 index 00000000000..1e4ffe7dc8c --- /dev/null +++ b/drivers/media/dvb/frontends/mt2131.h @@ -0,0 +1,54 @@ +/* + * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2006 Steven Toth <stoth@hauppauge.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 __MT2131_H__ +#define __MT2131_H__ + +struct dvb_frontend; +struct i2c_adapter; + +struct mt2131_config { + u8 i2c_address; + u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ +}; + +#if defined(CONFIG_DVB_TUNER_MT2131) || (defined(CONFIG_DVB_TUNER_MT2131_MODULE) && defined(MODULE)) +extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mt2131_config *cfg, + u16 if1); +#else +static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mt2131_config *cfg, + u16 if1) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif /* CONFIG_DVB_TUNER_MT2131 */ + +#endif /* __MT2131_H__ */ + +/* + * Local variables: + * c-basic-offset: 8 + */ diff --git a/drivers/media/dvb/frontends/mt2131_priv.h b/drivers/media/dvb/frontends/mt2131_priv.h new file mode 100644 index 00000000000..e930759c2c0 --- /dev/null +++ b/drivers/media/dvb/frontends/mt2131_priv.h @@ -0,0 +1,49 @@ +/* + * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2006 Steven Toth <stoth@hauppauge.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 __MT2131_PRIV_H__ +#define __MT2131_PRIV_H__ + +/* Regs */ +#define MT2131_PWR 0x07 +#define MT2131_UPC_1 0x0b +#define MT2131_AGC_RL 0x10 +#define MT2131_MISC_2 0x15 + +/* frequency values in KHz */ +#define MT2131_IF1 1220 +#define MT2131_IF2 44000 +#define MT2131_FREF 16000 + +struct mt2131_priv { + struct mt2131_config *cfg; + struct i2c_adapter *i2c; + + u32 frequency; + u32 bandwidth; +}; + +#endif /* __MT2131_PRIV_H__ */ + +/* + * Local variables: + * c-basic-offset: 8 + */ diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/dvb/frontends/mt2266.c new file mode 100644 index 00000000000..03fe8265745 --- /dev/null +++ b/drivers/media/dvb/frontends/mt2266.c @@ -0,0 +1,287 @@ +/* + * Driver for Microtune MT2266 "Direct conversion low power broadband tuner" + * + * Copyright (c) 2007 Olivier DANET <odanet@caramail.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. + */ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/dvb/frontend.h> +#include <linux/i2c.h> + +#include "dvb_frontend.h" +#include "mt2266.h" + +#define I2C_ADDRESS 0x60 + +#define REG_PART_REV 0 +#define REG_TUNE 1 +#define REG_BAND 6 +#define REG_BANDWIDTH 8 +#define REG_LOCK 0x12 + +#define PART_REV 0x85 + +struct mt2266_priv { + struct mt2266_config *cfg; + struct i2c_adapter *i2c; + + u32 frequency; + u32 bandwidth; +}; + +/* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2266: " args); printk("\n"); }} while (0) + +// Reads a single register +static int mt2266_readreg(struct mt2266_priv *priv, u8 reg, u8 *val) +{ + struct i2c_msg msg[2] = { + { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, + }; + if (i2c_transfer(priv->i2c, msg, 2) != 2) { + printk(KERN_WARNING "MT2266 I2C read failed\n"); + return -EREMOTEIO; + } + return 0; +} + +// Writes a single register +static int mt2266_writereg(struct mt2266_priv *priv, u8 reg, u8 val) +{ + u8 buf[2] = { reg, val }; + struct i2c_msg msg = { + .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 + }; + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "MT2266 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +// Writes a set of consecutive registers +static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len) +{ + struct i2c_msg msg = { + .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len + }; + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "MT2266 I2C write failed (len=%i)\n",(int)len); + return -EREMOTEIO; + } + return 0; +} + +// Initialisation sequences +static u8 mt2266_init1[] = { + REG_TUNE, + 0x00, 0x00, 0x28, 0x00, 0x52, 0x99, 0x3f }; + +static u8 mt2266_init2[] = { + 0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, + 0xd4, 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x77, 0x0f, 0x2d }; + +static u8 mt2266_init_8mhz[] = { + REG_BANDWIDTH, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 }; + +static u8 mt2266_init_7mhz[] = { + REG_BANDWIDTH, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32 }; + +static u8 mt2266_init_6mhz[] = { + REG_BANDWIDTH, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7 }; + +#define FREF 30000 // Quartz oscillator 30 MHz + +static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct mt2266_priv *priv; + int ret=0; + u32 freq; + u32 tune; + u8 lnaband; + u8 b[10]; + int i; + + priv = fe->tuner_priv; + + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0xff); + + freq = params->frequency / 1000; // Hz -> kHz + priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; + priv->frequency = freq * 1000; + tune=2 * freq * (8192/16) / (FREF/16); + + if (freq <= 495000) lnaband = 0xEE; else + if (freq <= 525000) lnaband = 0xDD; else + if (freq <= 550000) lnaband = 0xCC; else + if (freq <= 580000) lnaband = 0xBB; else + if (freq <= 605000) lnaband = 0xAA; else + if (freq <= 630000) lnaband = 0x99; else + if (freq <= 655000) lnaband = 0x88; else + if (freq <= 685000) lnaband = 0x77; else + if (freq <= 710000) lnaband = 0x66; else + if (freq <= 735000) lnaband = 0x55; else + if (freq <= 765000) lnaband = 0x44; else + if (freq <= 802000) lnaband = 0x33; else + if (freq <= 840000) lnaband = 0x22; else lnaband = 0x11; + + msleep(100); + mt2266_writeregs(priv,(params->u.ofdm.bandwidth==BANDWIDTH_6_MHZ)?mt2266_init_6mhz: + (params->u.ofdm.bandwidth==BANDWIDTH_7_MHZ)?mt2266_init_7mhz: + mt2266_init_8mhz,sizeof(mt2266_init_8mhz)); + + b[0] = REG_TUNE; + b[1] = (tune >> 8) & 0x1F; + b[2] = tune & 0xFF; + b[3] = tune >> 13; + mt2266_writeregs(priv,b,4); + + dprintk("set_parms: tune=%d band=%d",(int)tune,(int)lnaband); + dprintk("set_parms: [1..3]: %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3]); + + b[0] = 0x05; + b[1] = 0x62; + b[2] = lnaband; + mt2266_writeregs(priv,b,3); + + //Waits for pll lock or timeout + i = 0; + do { + mt2266_readreg(priv,REG_LOCK,b); + if ((b[0] & 0x40)==0x40) + break; + msleep(10); + i++; + } while (i<10); + dprintk("Lock when i=%i",(int)i); + return ret; +} + +static void mt2266_calibrate(struct mt2266_priv *priv) +{ + mt2266_writereg(priv,0x11,0x03); + mt2266_writereg(priv,0x11,0x01); + + mt2266_writeregs(priv,mt2266_init1,sizeof(mt2266_init1)); + mt2266_writeregs(priv,mt2266_init2,sizeof(mt2266_init2)); + + mt2266_writereg(priv,0x33,0x5e); + mt2266_writereg(priv,0x10,0x10); + mt2266_writereg(priv,0x10,0x00); + + mt2266_writeregs(priv,mt2266_init_8mhz,sizeof(mt2266_init_8mhz)); + + msleep(25); + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0x00); + msleep(75); + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0xff); +} + +static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mt2266_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct mt2266_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +static int mt2266_init(struct dvb_frontend *fe) +{ + struct mt2266_priv *priv = fe->tuner_priv; + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0xff); + return 0; +} + +static int mt2266_sleep(struct dvb_frontend *fe) +{ + struct mt2266_priv *priv = fe->tuner_priv; + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0x00); + return 0; +} + +static int mt2266_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static const struct dvb_tuner_ops mt2266_tuner_ops = { + .info = { + .name = "Microtune MT2266", + .frequency_min = 470000000, + .frequency_max = 860000000, + .frequency_step = 50000, + }, + .release = mt2266_release, + .init = mt2266_init, + .sleep = mt2266_sleep, + .set_params = mt2266_set_params, + .get_frequency = mt2266_get_frequency, + .get_bandwidth = mt2266_get_bandwidth +}; + +struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) +{ + struct mt2266_priv *priv = NULL; + u8 id = 0; + + priv = kzalloc(sizeof(struct mt2266_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->i2c = i2c; + + if (mt2266_readreg(priv,0,&id) != 0) { + kfree(priv); + return NULL; + } + if (id != PART_REV) { + kfree(priv); + return NULL; + } + printk(KERN_INFO "MT2266: successfully identified\n"); + memcpy(&fe->ops.tuner_ops, &mt2266_tuner_ops, sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + mt2266_calibrate(priv); + return fe; +} +EXPORT_SYMBOL(mt2266_attach); + +MODULE_AUTHOR("Olivier DANET"); +MODULE_DESCRIPTION("Microtune MT2266 silicon tuner driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/mt2266.h b/drivers/media/dvb/frontends/mt2266.h new file mode 100644 index 00000000000..f31dd613ad3 --- /dev/null +++ b/drivers/media/dvb/frontends/mt2266.h @@ -0,0 +1,37 @@ +/* + * Driver for Microtune MT2266 "Direct conversion low power broadband tuner" + * + * Copyright (c) 2007 Olivier DANET <odanet@caramail.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. + */ + +#ifndef MT2266_H +#define MT2266_H + +struct dvb_frontend; +struct i2c_adapter; + +struct mt2266_config { + u8 i2c_address; +}; + +#if defined(CONFIG_DVB_TUNER_MT2266) || (defined(CONFIG_DVB_TUNER_MT2266_MODULE) && defined(MODULE)) +extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg); +#else +static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif // CONFIG_DVB_TUNER_MT2266 + +#endif diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c index 1ef82182564..0606b9a5b61 100644 --- a/drivers/media/dvb/frontends/mt312.c +++ b/drivers/media/dvb/frontends/mt312.c @@ -28,7 +28,6 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/string.h> #include <linux/slab.h> diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c index 87e31ca7e10..5dd9b731f6f 100644 --- a/drivers/media/dvb/frontends/mt352.c +++ b/drivers/media/dvb/frontends/mt352.c @@ -32,7 +32,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/string.h> diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c index ddc84899cf8..fcf964fe1d6 100644 --- a/drivers/media/dvb/frontends/nxt200x.c +++ b/drivers/media/dvb/frontends/nxt200x.c @@ -44,7 +44,6 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/slab.h> #include <linux/string.h> diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c index 3cc8b444b8f..b314a1f2dee 100644 --- a/drivers/media/dvb/frontends/or51132.c +++ b/drivers/media/dvb/frontends/or51132.c @@ -36,7 +36,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/string.h> diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c index f46d5a46683..f02bd944595 100644 --- a/drivers/media/dvb/frontends/or51211.c +++ b/drivers/media/dvb/frontends/or51211.c @@ -32,7 +32,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/device.h> #include <linux/firmware.h> #include <linux/string.h> diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c new file mode 100644 index 00000000000..30e8a705fad --- /dev/null +++ b/drivers/media/dvb/frontends/s5h1409.c @@ -0,0 +1,729 @@ +/* + Samsung S5H1409 VSB/QAM demodulator driver + + Copyright (C) 2006 Steven Toth <stoth@hauppauge.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. + +*/ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include "dvb_frontend.h" +#include "dvb-pll.h" +#include "s5h1409.h" + +struct s5h1409_state { + + struct i2c_adapter* i2c; + + /* configuration settings */ + const struct s5h1409_config* config; + + struct dvb_frontend frontend; + + /* previous uncorrected block counter */ + fe_modulation_t current_modulation; + + u32 current_frequency; +}; + +static int debug = 0; +#define dprintk if (debug) printk + +/* Register values to initialise the demod, this will set VSB by default */ +static struct init_tab { + u8 reg; + u16 data; +} init_tab[] = { + { 0x00, 0x0071, }, + { 0x01, 0x3213, }, + { 0x09, 0x0025, }, + { 0x1c, 0x001d, }, + { 0x1f, 0x002d, }, + { 0x20, 0x001d, }, + { 0x22, 0x0022, }, + { 0x23, 0x0020, }, + { 0x29, 0x110f, }, + { 0x2a, 0x10b4, }, + { 0x2b, 0x10ae, }, + { 0x2c, 0x0031, }, + { 0x31, 0x010d, }, + { 0x32, 0x0100, }, + { 0x44, 0x0510, }, + { 0x54, 0x0104, }, + { 0x58, 0x2222, }, + { 0x59, 0x1162, }, + { 0x5a, 0x3211, }, + { 0x5d, 0x0370, }, + { 0x5e, 0x0296, }, + { 0x61, 0x0010, }, + { 0x63, 0x4a00, }, + { 0x65, 0x0800, }, + { 0x71, 0x0003, }, + { 0x72, 0x0470, }, + { 0x81, 0x0002, }, + { 0x82, 0x0600, }, + { 0x86, 0x0002, }, + { 0x8a, 0x2c38, }, + { 0x8b, 0x2a37, }, + { 0x92, 0x302f, }, + { 0x93, 0x3332, }, + { 0x96, 0x000c, }, + { 0x99, 0x0101, }, + { 0x9c, 0x2e37, }, + { 0x9d, 0x2c37, }, + { 0x9e, 0x2c37, }, + { 0xab, 0x0100, }, + { 0xac, 0x1003, }, + { 0xad, 0x103f, }, + { 0xe2, 0x0100, }, + { 0x28, 0x1010, }, + { 0xb1, 0x000e, }, +}; + +/* VSB SNR lookup table */ +static struct vsb_snr_tab { + u16 val; + u16 data; +} vsb_snr_tab[] = { + { 1023, 770, }, + { 923, 300, }, + { 918, 295, }, + { 915, 290, }, + { 911, 285, }, + { 906, 280, }, + { 901, 275, }, + { 896, 270, }, + { 891, 265, }, + { 885, 260, }, + { 879, 255, }, + { 873, 250, }, + { 864, 245, }, + { 858, 240, }, + { 850, 235, }, + { 841, 230, }, + { 832, 225, }, + { 823, 220, }, + { 812, 215, }, + { 802, 210, }, + { 788, 205, }, + { 778, 200, }, + { 767, 195, }, + { 753, 190, }, + { 740, 185, }, + { 725, 180, }, + { 707, 175, }, + { 689, 170, }, + { 671, 165, }, + { 656, 160, }, + { 637, 155, }, + { 616, 150, }, + { 542, 145, }, + { 519, 140, }, + { 507, 135, }, + { 497, 130, }, + { 492, 125, }, + { 474, 120, }, + { 300, 111, }, + { 0, 0, }, +}; + +/* QAM64 SNR lookup table */ +static struct qam64_snr_tab { + u16 val; + u16 data; +} qam64_snr_tab[] = { + { 12, 300, }, + { 15, 290, }, + { 18, 280, }, + { 22, 270, }, + { 23, 268, }, + { 24, 266, }, + { 25, 264, }, + { 27, 262, }, + { 28, 260, }, + { 29, 258, }, + { 30, 256, }, + { 32, 254, }, + { 33, 252, }, + { 34, 250, }, + { 35, 249, }, + { 36, 248, }, + { 37, 247, }, + { 38, 246, }, + { 39, 245, }, + { 40, 244, }, + { 41, 243, }, + { 42, 241, }, + { 43, 240, }, + { 44, 239, }, + { 45, 238, }, + { 46, 237, }, + { 47, 236, }, + { 48, 235, }, + { 49, 234, }, + { 50, 233, }, + { 51, 232, }, + { 52, 231, }, + { 53, 230, }, + { 55, 229, }, + { 56, 228, }, + { 57, 227, }, + { 58, 226, }, + { 59, 225, }, + { 60, 224, }, + { 62, 223, }, + { 63, 222, }, + { 65, 221, }, + { 66, 220, }, + { 68, 219, }, + { 69, 218, }, + { 70, 217, }, + { 72, 216, }, + { 73, 215, }, + { 75, 214, }, + { 76, 213, }, + { 78, 212, }, + { 80, 211, }, + { 81, 210, }, + { 83, 209, }, + { 84, 208, }, + { 85, 207, }, + { 87, 206, }, + { 89, 205, }, + { 91, 204, }, + { 93, 203, }, + { 95, 202, }, + { 96, 201, }, + { 104, 200, }, +}; + +/* QAM256 SNR lookup table */ +static struct qam256_snr_tab { + u16 val; + u16 data; +} qam256_snr_tab[] = { + { 12, 400, }, + { 13, 390, }, + { 15, 380, }, + { 17, 360, }, + { 19, 350, }, + { 22, 348, }, + { 23, 346, }, + { 24, 344, }, + { 25, 342, }, + { 26, 340, }, + { 27, 336, }, + { 28, 334, }, + { 29, 332, }, + { 30, 330, }, + { 31, 328, }, + { 32, 326, }, + { 33, 325, }, + { 34, 322, }, + { 35, 320, }, + { 37, 318, }, + { 39, 316, }, + { 40, 314, }, + { 41, 312, }, + { 42, 310, }, + { 43, 308, }, + { 46, 306, }, + { 47, 304, }, + { 49, 302, }, + { 51, 300, }, + { 53, 298, }, + { 54, 297, }, + { 55, 296, }, + { 56, 295, }, + { 57, 294, }, + { 59, 293, }, + { 60, 292, }, + { 61, 291, }, + { 63, 290, }, + { 64, 289, }, + { 65, 288, }, + { 66, 287, }, + { 68, 286, }, + { 69, 285, }, + { 71, 284, }, + { 72, 283, }, + { 74, 282, }, + { 75, 281, }, + { 76, 280, }, + { 77, 279, }, + { 78, 278, }, + { 81, 277, }, + { 83, 276, }, + { 84, 275, }, + { 86, 274, }, + { 87, 273, }, + { 89, 272, }, + { 90, 271, }, + { 92, 270, }, + { 93, 269, }, + { 95, 268, }, + { 96, 267, }, + { 98, 266, }, + { 100, 265, }, + { 102, 264, }, + { 104, 263, }, + { 105, 262, }, + { 106, 261, }, + { 110, 260, }, +}; + +/* 8 bit registers, 16 bit values */ +static int s5h1409_writereg(struct s5h1409_state* state, u8 reg, u16 data) +{ + int ret; + u8 buf [] = { reg, data >> 8, data & 0xff }; + + struct i2c_msg msg = { .addr = state->config->demod_address, + .flags = 0, .buf = buf, .len = 3 }; + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, " + "ret == %i)\n", __FUNCTION__, reg, data, ret); + + return (ret != 1) ? -1 : 0; +} + +static u16 s5h1409_readreg(struct s5h1409_state* state, u8 reg) +{ + int ret; + u8 b0 [] = { reg }; + u8 b1 [] = { 0, 0 }; + + struct i2c_msg msg [] = { + { .addr = state->config->demod_address, .flags = 0, + .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, + .buf = b1, .len = 2 } }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) + printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); + return (b1[0] << 8) | b1[1]; +} + +static int s5h1409_softreset(struct dvb_frontend* fe) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s()\n", __FUNCTION__); + + s5h1409_writereg(state, 0xf5, 0); + s5h1409_writereg(state, 0xf5, 1); + return 0; +} + +static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz) +{ + struct s5h1409_state* state = fe->demodulator_priv; + int ret = 0; + + dprintk("%s(%d KHz)\n", __FUNCTION__, KHz); + + if( (KHz == 44000) || (KHz == 5380) ) { + s5h1409_writereg(state, 0x87, 0x01be); + s5h1409_writereg(state, 0x88, 0x0436); + s5h1409_writereg(state, 0x89, 0x054d); + } else { + printk("%s() Invalid arg = %d KHz\n", __FUNCTION__, KHz); + ret = -1; + } + + return ret; +} + +static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s()\n", __FUNCTION__); + + if(inverted == 1) + return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */ + else + return s5h1409_writereg(state, 0x1b, 0x0110); /* Normal */ +} + +static int s5h1409_enable_modulation(struct dvb_frontend* fe, + fe_modulation_t m) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s(0x%08x)\n", __FUNCTION__, m); + + switch(m) { + case VSB_8: + dprintk("%s() VSB_8\n", __FUNCTION__); + s5h1409_writereg(state, 0xf4, 0); + break; + case QAM_64: + dprintk("%s() QAM_64\n", __FUNCTION__); + s5h1409_writereg(state, 0xf4, 1); + s5h1409_writereg(state, 0x85, 0x100); + break; + case QAM_256: + dprintk("%s() QAM_256\n", __FUNCTION__); + s5h1409_writereg(state, 0xf4, 1); + s5h1409_writereg(state, 0x85, 0x101); + break; + default: + dprintk("%s() Invalid modulation\n", __FUNCTION__); + return -EINVAL; + } + + state->current_modulation = m; + s5h1409_softreset(fe); + + return 0; +} + +static int s5h1409_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s(%d)\n", __FUNCTION__, enable); + + if (enable) + return s5h1409_writereg(state, 0xf3, 1); + else + return s5h1409_writereg(state, 0xf3, 0); +} + +static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s(%d)\n", __FUNCTION__, enable); + + if (enable) + return s5h1409_writereg(state, 0xe3, 0x1100); + else + return s5h1409_writereg(state, 0xe3, 0); +} + +static int s5h1409_sleep(struct dvb_frontend* fe, int enable) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s(%d)\n", __FUNCTION__, enable); + + return s5h1409_writereg(state, 0xf2, enable); +} + +static int s5h1409_register_reset(struct dvb_frontend* fe) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s()\n", __FUNCTION__); + + return s5h1409_writereg(state, 0xfa, 0); +} + +/* Talk to the demod, set the FEC, GUARD, QAM settings etc */ +static int s5h1409_set_frontend (struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s(frequency=%d)\n", __FUNCTION__, p->frequency); + + s5h1409_softreset(fe); + + state->current_frequency = p->frequency; + + s5h1409_enable_modulation(fe, p->u.vsb.modulation); + + if (fe->ops.tuner_ops.set_params) { + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + + return 0; +} + +/* Reset the demod hardware and reset all of the configuration registers + to a default state. */ +static int s5h1409_init (struct dvb_frontend* fe) +{ + int i; + + struct s5h1409_state* state = fe->demodulator_priv; + dprintk("%s()\n", __FUNCTION__); + + s5h1409_sleep(fe, 0); + s5h1409_register_reset(fe); + + for (i=0; i < ARRAY_SIZE(init_tab); i++) + s5h1409_writereg(state, init_tab[i].reg, init_tab[i].data); + + /* The datasheet says that after initialisation, VSB is default */ + state->current_modulation = VSB_8; + + if (state->config->output_mode == S5H1409_SERIAL_OUTPUT) + s5h1409_writereg(state, 0xab, 0x100); /* Serial */ + else + s5h1409_writereg(state, 0xab, 0x0); /* Parallel */ + + s5h1409_set_spectralinversion(fe, state->config->inversion); + s5h1409_set_if_freq(fe, state->config->if_freq); + s5h1409_set_gpio(fe, state->config->gpio); + s5h1409_softreset(fe); + + /* Note: Leaving the I2C gate open here. */ + s5h1409_i2c_gate_ctrl(fe, 1); + + return 0; +} + +static int s5h1409_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct s5h1409_state* state = fe->demodulator_priv; + u16 reg; + u32 tuner_status = 0; + + *status = 0; + + /* Get the demodulator status */ + reg = s5h1409_readreg(state, 0xf1); + if(reg & 0x1000) + *status |= FE_HAS_VITERBI; + if(reg & 0x8000) + *status |= FE_HAS_LOCK | FE_HAS_SYNC; + + switch(state->config->status_mode) { + case S5H1409_DEMODLOCKING: + if (*status & FE_HAS_VITERBI) + *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; + break; + case S5H1409_TUNERLOCKING: + /* Get the tuner status */ + if (fe->ops.tuner_ops.get_status) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + fe->ops.tuner_ops.get_status(fe, &tuner_status); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + if (tuner_status) + *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; + break; + } + + dprintk("%s() status 0x%08x\n", __FUNCTION__, *status); + + return 0; +} + +static int s5h1409_qam256_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v) +{ + int i, ret = -EINVAL; + dprintk("%s()\n", __FUNCTION__); + + for (i=0; i < ARRAY_SIZE(qam256_snr_tab); i++) { + if (v < qam256_snr_tab[i].val) { + *snr = qam256_snr_tab[i].data; + ret = 0; + break; + } + } + return ret; +} + +static int s5h1409_qam64_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v) +{ + int i, ret = -EINVAL; + dprintk("%s()\n", __FUNCTION__); + + for (i=0; i < ARRAY_SIZE(qam64_snr_tab); i++) { + if (v < qam64_snr_tab[i].val) { + *snr = qam64_snr_tab[i].data; + ret = 0; + break; + } + } + return ret; +} + +static int s5h1409_vsb_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v) +{ + int i, ret = -EINVAL; + dprintk("%s()\n", __FUNCTION__); + + for (i=0; i < ARRAY_SIZE(vsb_snr_tab); i++) { + if (v > vsb_snr_tab[i].val) { + *snr = vsb_snr_tab[i].data; + ret = 0; + break; + } + } + dprintk("%s() snr=%d\n", __FUNCTION__, *snr); + return ret; +} + +static int s5h1409_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct s5h1409_state* state = fe->demodulator_priv; + u16 reg; + dprintk("%s()\n", __FUNCTION__); + + reg = s5h1409_readreg(state, 0xf1) & 0x1ff; + + switch(state->current_modulation) { + case QAM_64: + return s5h1409_qam64_lookup_snr(fe, snr, reg); + case QAM_256: + return s5h1409_qam256_lookup_snr(fe, snr, reg); + case VSB_8: + return s5h1409_vsb_lookup_snr(fe, snr, reg); + default: + break; + } + + return -EINVAL; +} + +static int s5h1409_read_signal_strength(struct dvb_frontend* fe, + u16* signal_strength) +{ + return s5h1409_read_snr(fe, signal_strength); +} + +static int s5h1409_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + *ucblocks = s5h1409_readreg(state, 0xb5); + + return 0; +} + +static int s5h1409_read_ber(struct dvb_frontend* fe, u32* ber) +{ + return s5h1409_read_ucblocks(fe, ber); +} + +static int s5h1409_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + p->frequency = state->current_frequency; + p->u.vsb.modulation = state->current_modulation; + + return 0; +} + +static int s5h1409_get_tune_settings(struct dvb_frontend* fe, + struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 1000; + return 0; +} + +static void s5h1409_release(struct dvb_frontend* fe) +{ + struct s5h1409_state* state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops s5h1409_ops; + +struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, + struct i2c_adapter* i2c) +{ + struct s5h1409_state* state = NULL; + + /* allocate memory for the internal state */ + state = kmalloc(sizeof(struct s5h1409_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->current_modulation = 0; + + /* check if the demod exists */ + if (s5h1409_readreg(state, 0x04) != 0x0066) + goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &s5h1409_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + /* Note: Leaving the I2C gate open here. */ + s5h1409_writereg(state, 0xf3, 1); + + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops s5h1409_ops = { + + .info = { + .name = "Samsung S5H1409 QAM/8VSB Frontend", + .type = FE_ATSC, + .frequency_min = 54000000, + .frequency_max = 858000000, + .frequency_stepsize = 62500, + .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + }, + + .init = s5h1409_init, + .i2c_gate_ctrl = s5h1409_i2c_gate_ctrl, + .set_frontend = s5h1409_set_frontend, + .get_frontend = s5h1409_get_frontend, + .get_tune_settings = s5h1409_get_tune_settings, + .read_status = s5h1409_read_status, + .read_ber = s5h1409_read_ber, + .read_signal_strength = s5h1409_read_signal_strength, + .read_snr = s5h1409_read_snr, + .read_ucblocks = s5h1409_read_ucblocks, + .release = s5h1409_release, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Enable verbose debug messages"); + +MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver"); +MODULE_AUTHOR("Steven Toth"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(s5h1409_attach); + +/* + * Local variables: + * c-basic-offset: 8 + */ diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h new file mode 100644 index 00000000000..20f9af1af44 --- /dev/null +++ b/drivers/media/dvb/frontends/s5h1409.h @@ -0,0 +1,73 @@ +/* + Samsung S5H1409 VSB/QAM demodulator driver + + Copyright (C) 2006 Steven Toth <stoth@hauppauge.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 __S5H1409_H__ +#define __S5H1409_H__ + +#include <linux/dvb/frontend.h> + +struct s5h1409_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* serial/parallel output */ +#define S5H1409_PARALLEL_OUTPUT 0 +#define S5H1409_SERIAL_OUTPUT 1 + u8 output_mode; + + /* GPIO Setting */ +#define S5H1409_GPIO_OFF 0 +#define S5H1409_GPIO_ON 1 + u8 gpio; + + /* IF Freq in KHz */ + u16 if_freq; + + /* Spectral Inversion */ +#define S5H1409_INVERSION_OFF 0 +#define S5H1409_INVERSION_ON 1 + u8 inversion; + + /* Return lock status based on tuner lock, or demod lock */ +#define S5H1409_TUNERLOCKING 0 +#define S5H1409_DEMODLOCKING 1 + u8 status_mode; +}; + +#if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) && defined(MODULE)) +extern struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, + struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif /* CONFIG_DVB_S5H1409 */ + +#endif /* __S5H1409_H__ */ + +/* + * Local variables: + * c-basic-offset: 8 + */ diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c index d98fd5c2e13..da876f7bfe3 100644 --- a/drivers/media/dvb/frontends/sp8870.c +++ b/drivers/media/dvb/frontends/sp8870.c @@ -29,7 +29,6 @@ #include <linux/init.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/device.h> #include <linux/firmware.h> #include <linux/delay.h> diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c index 5c2f8f4e0ae..1aa2539f509 100644 --- a/drivers/media/dvb/frontends/sp887x.c +++ b/drivers/media/dvb/frontends/sp887x.c @@ -12,7 +12,6 @@ #include <linux/init.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/device.h> #include <linux/firmware.h> #include <linux/string.h> diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c index 9a343972ff5..17e5cb561cd 100644 --- a/drivers/media/dvb/frontends/stv0297.c +++ b/drivers/media/dvb/frontends/stv0297.c @@ -680,8 +680,8 @@ static struct dvb_frontend_ops stv0297_ops = { .info = { .name = "ST STV0297 DVB-C", .type = FE_QAM, - .frequency_min = 64000000, - .frequency_max = 1300000000, + .frequency_min = 47000000, + .frequency_max = 862000000, .frequency_stepsize = 62500, .symbol_rate_min = 870000, .symbol_rate_max = 11700000, diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index 6c607302c1b..035dd7ba651 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c @@ -45,7 +45,6 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/string.h> #include <linux/slab.h> #include <linux/jiffies.h> diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c index e725f612a6b..4cd9e82c466 100644 --- a/drivers/media/dvb/frontends/tda10021.c +++ b/drivers/media/dvb/frontends/tda10021.c @@ -439,8 +439,8 @@ static struct dvb_frontend_ops tda10021_ops = { .name = "Philips TDA10021 DVB-C", .type = FE_QAM, .frequency_stepsize = 62500, - .frequency_min = 51000000, - .frequency_max = 858000000, + .frequency_min = 47000000, + .frequency_max = 862000000, .symbol_rate_min = (XIN/2)/64, /* SACLK/64 == (XIN/2)/64 */ .symbol_rate_max = (XIN/2)/4, /* SACLK/4 */ #if 0 diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c index 4bb06f97938..364bc01971a 100644 --- a/drivers/media/dvb/frontends/tda10023.c +++ b/drivers/media/dvb/frontends/tda10023.c @@ -215,12 +215,6 @@ static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr) s16 SFIL=0; u16 NDEC = 0; - if (sr > (SYSCLK/(2*4))) - sr=SYSCLK/(2*4); - - if (sr<870000) - sr=870000; - if (sr < (u32)(SYSCLK/98.40)) { NDEC=3; SFIL=1; @@ -506,8 +500,8 @@ static struct dvb_frontend_ops tda10023_ops = { .name = "Philips TDA10023 DVB-C", .type = FE_QAM, .frequency_stepsize = 62500, - .frequency_min = 51000000, - .frequency_max = 858000000, + .frequency_min = 47000000, + .frequency_max = 862000000, .symbol_rate_min = (SYSCLK/2)/64, /* SACLK/64 == (SYSCLK/2)/64 */ .symbol_rate_max = (SYSCLK/2)/4, /* SACLK/4 */ .caps = 0x400 | //FE_CAN_QAM_4 diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index 33a84372c9e..8415a8a5247 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -31,7 +31,6 @@ #include <linux/init.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/device.h> #include <linux/jiffies.h> #include <linux/string.h> diff --git a/drivers/media/dvb/frontends/tda10086.c b/drivers/media/dvb/frontends/tda10086.c index 0f2d4b41556..9a8ddc537f8 100644 --- a/drivers/media/dvb/frontends/tda10086.c +++ b/drivers/media/dvb/frontends/tda10086.c @@ -22,7 +22,6 @@ #include <linux/init.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/device.h> #include <linux/jiffies.h> #include <linux/string.h> diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c index 67415c9db6f..011b74f798a 100644 --- a/drivers/media/dvb/frontends/tda8083.c +++ b/drivers/media/dvb/frontends/tda8083.c @@ -27,7 +27,6 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/string.h> #include <linux/slab.h> #include <linux/jiffies.h> @@ -443,12 +442,12 @@ static struct dvb_frontend_ops tda8083_ops = { .info = { .name = "Philips TDA8083 DVB-S", .type = FE_QPSK, - .frequency_min = 950000, /* FIXME: guessed! */ - .frequency_max = 1400000, /* FIXME: guessed! */ + .frequency_min = 920000, /* TDA8060 */ + .frequency_max = 2200000, /* TDA8060 */ .frequency_stepsize = 125, /* kHz for QPSK frontends */ /* .frequency_tolerance = ???,*/ - .symbol_rate_min = 1000000, /* FIXME: guessed! */ - .symbol_rate_max = 45000000, /* FIXME: guessed! */ + .symbol_rate_min = 12000000, + .symbol_rate_max = 30000000, /* .symbol_rate_tolerance = ???,*/ .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c index 9b57576bfeb..066b73b7569 100644 --- a/drivers/media/dvb/frontends/ves1820.c +++ b/drivers/media/dvb/frontends/ves1820.c @@ -410,8 +410,8 @@ static struct dvb_frontend_ops ves1820_ops = { .name = "VLSI VES1820 DVB-C", .type = FE_QAM, .frequency_stepsize = 62500, - .frequency_min = 51000000, - .frequency_max = 858000000, + .frequency_min = 47000000, + .frequency_max = 862000000, .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c index 245f9b7dddf..a97a7fd2c89 100644 --- a/drivers/media/dvb/frontends/zl10353.c +++ b/drivers/media/dvb/frontends/zl10353.c @@ -21,7 +21,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/string.h> diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 8178832d14a..8b8144f77a7 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -40,7 +40,6 @@ #include <linux/smp_lock.h> #include <linux/kernel.h> -#include <linux/moduleparam.h> #include <linux/sched.h> #include <linux/types.h> #include <linux/fcntl.h> @@ -1543,7 +1542,7 @@ static int get_firmware(struct av7110* av7110) } /* check if the firmware is available */ - av7110->bin_fw = (unsigned char *) vmalloc(fw->size); + av7110->bin_fw = vmalloc(fw->size); if (NULL == av7110->bin_fw) { dprintk(1, "out of memory\n"); release_firmware(fw); diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c index 515e8232e02..a468aa2e485 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.c +++ b/drivers/media/dvb/ttpci/av7110_hw.c @@ -978,24 +978,24 @@ static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 ble static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last) { - int i; - int length = last - first + 1; + int i; + int length = last - first + 1; - if (length * 4 > DATA_BUFF3_SIZE) - return -EINVAL; + if (length * 4 > DATA_BUFF3_SIZE) + return -EINVAL; - for (i = 0; i < length; i++) { - u32 color, blend, yuv; + for (i = 0; i < length; i++) { + u32 color, blend, yuv; - if (get_user(color, colors + i)) - return -EFAULT; - blend = (color & 0xF0000000) >> 4; - yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF, + if (get_user(color, colors + i)) + return -EFAULT; + blend = (color & 0xF0000000) >> 4; + yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF, (color >> 16) & 0xFF) | blend : 0; - yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16); - wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4); - } - return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4, + yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16); + wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4); + } + return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], first, last); diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c index 6322800ee12..5d19c402dad 100644 --- a/drivers/media/dvb/ttpci/av7110_ir.c +++ b/drivers/media/dvb/ttpci/av7110_ir.c @@ -25,7 +25,6 @@ #include <linux/types.h> #include <linux/init.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/proc_fs.h> #include <linux/kernel.h> #include <asm/bitops.h> @@ -280,7 +279,7 @@ static int av7110_ir_write_proc(struct file *file, const char __user *buffer, if (count < size) return -EINVAL; - page = (char *) vmalloc(size); + page = vmalloc(size); if (!page) return -ENOMEM; diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index 87afaebc070..76cca003252 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c @@ -129,23 +129,25 @@ static struct v4l2_input inputs[4] = { static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data) { + struct av7110 *av7110 = dev->ext_priv; u8 buf[] = { 0x00, reg, data }; struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 }; dprintk(4, "dev: %p\n", dev); - if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1)) + if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1)) return -1; return 0; } static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4]) { + struct av7110 *av7110 = dev->ext_priv; struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 }; dprintk(4, "dev: %p\n", dev); - if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1)) + if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1)) return -1; return 0; } diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 0aee7a13a07..3439c9864f6 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -1232,7 +1232,7 @@ static struct saa7146_ext_vv vv_data = { .capabilities = 0, // perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113 .flags = 0, .stds = &standard[0], - .num_stds = sizeof(standard) / sizeof(struct saa7146_standard), + .num_stds = ARRAY_SIZE(standard), .ioctls = &ioctls[0], .ioctl = av_ioctl, }; diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 873c3ba296f..509349211d4 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -214,7 +214,6 @@ static int msp430_ir_init(struct budget_ci *budget_ci) case 0x100f: case 0x1011: case 0x1012: - case 0x1017: /* The hauppauge keymap is a superset of these remotes */ ir_input_init(input_dev, &budget_ci->ir.state, IR_TYPE_RC5, ir_codes_hauppauge_new); @@ -225,6 +224,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci) budget_ci->ir.rc5_device = rc5_device; break; case 0x1010: + case 0x1017: /* for the Technotrend 1500 bundled remote */ ir_input_init(input_dev, &budget_ci->ir.state, IR_TYPE_RC5, ir_codes_tt_1500); diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c index b611f2b1f8b..0252081f013 100644 --- a/drivers/media/dvb/ttpci/budget-core.c +++ b/drivers/media/dvb/ttpci/budget-core.c @@ -34,7 +34,6 @@ * the project's page is at http://www.linuxtv.org/dvb/ */ -#include <linux/moduleparam.h> #include "budget.h" #include "ttpci-eeprom.h" diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index b60cdc93d6d..288e79f2cb0 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -13,7 +13,6 @@ #include <linux/slab.h> #include <linux/wait.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/usb.h> #include <linux/delay.h> #include <linux/time.h> diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 78c98b08997..5e691fd7990 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -22,7 +22,6 @@ #include <linux/list.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/pci.h> #include <linux/slab.h> #include <linux/spinlock.h> |