diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-12-30 17:41:32 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-12-30 17:41:32 -0800 |
commit | f54a6ec0fd85002d94d05b4bb679508eeb066683 (patch) | |
tree | 0f24dd66cce563d2c5e7656c2489e5b96eef31f9 /drivers/media/dvb | |
parent | 5ed1836814d908f45cafde0e79cb85314ab9d41d (diff) | |
parent | 134179823b3ca9c8b98e0631906459dbb022ff9b (diff) |
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (583 commits)
V4L/DVB (10130): use USB API functions rather than constants
V4L/DVB (10129): dvb: remove deprecated use of RW_LOCK_UNLOCKED in frontends
V4L/DVB (10128): modify V4L documentation to be a valid XHTML
V4L/DVB (10127): stv06xx: Avoid having y unitialized
V4L/DVB (10125): em28xx: Don't do AC97 vendor detection for i2s audio devices
V4L/DVB (10124): em28xx: expand output formats available
V4L/DVB (10123): em28xx: fix reversed definitions of I2S audio modes
V4L/DVB (10122): em28xx: don't load em28xx-alsa for em2870 based devices
V4L/DVB (10121): em28xx: remove worthless Pinnacle PCTV HD Mini 80e device profile
V4L/DVB (10120): em28xx: remove redundant Pinnacle Dazzle DVC 100 profile
V4L/DVB (10119): em28xx: fix corrupted XCLK value
V4L/DVB (10118): zoran: fix warning for a variable not used
V4L/DVB (10116): af9013: Fix gcc false warnings
V4L/DVB (10111a): usbvideo.h: remove an useless blank line
V4L/DVB (10111): quickcam_messenger.c: fix a warning
V4L/DVB (10110): v4l2-ioctl: Fix warnings when using .unlocked_ioctl = __video_ioctl2
V4L/DVB (10109): anysee: Fix usage of an unitialized function
V4L/DVB (10104): uvcvideo: Add support for video output devices
V4L/DVB (10102): uvcvideo: Ignore interrupt endpoint for built-in iSight webcams.
V4L/DVB (10101): uvcvideo: Fix bulk URB processing when the header is erroneous
...
Diffstat (limited to 'drivers/media/dvb')
59 files changed, 10364 insertions, 108 deletions
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index 0bcd852576d..40ebde53b3c 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -2,6 +2,19 @@ # DVB device configuration # +config DVB_DYNAMIC_MINORS + bool "Dynamic DVB minor allocation" + depends on DVB_CORE + default n + help + If you say Y here, the DVB subsystem will use dynamic minor + allocation for any device that uses the DVB major number. + This means that you can have more than 4 of a single type + of device (like demuxes and frontends) per adapter, but udev + will be required to manage the device nodes. + + If you are unsure about this, say N here. + menuconfig DVB_CAPTURE_DRIVERS bool "DVB/ATSC adapters" depends on DVB_CORE diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig index b34301d56cd..a8c6249c409 100644 --- a/drivers/media/dvb/b2c2/Kconfig +++ b/drivers/media/dvb/b2c2/Kconfig @@ -14,6 +14,7 @@ config DVB_B2C2_FLEXCOP select DVB_ISL6421 if !DVB_FE_CUSTOMISE select DVB_CX24123 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE + select DVB_TUNER_CX24113 if !DVB_FE_CUSTOMISE help Support for the digital TV receiver chip made by B2C2 Inc. included in Technisats PCI cards and USB boxes. diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c index a21ce9edcc7..f48f73aff19 100644 --- a/drivers/media/dvb/dm1105/dm1105.c +++ b/drivers/media/dvb/dm1105/dm1105.c @@ -19,7 +19,6 @@ * */ -#include <linux/version.h> #include <linux/i2c.h> #include <linux/init.h> #include <linux/kernel.h> @@ -368,7 +367,7 @@ static int __devinit dm1105dvb_dma_map(struct dm1105dvb *dm1105dvb) { dm1105dvb->ts_buf = pci_alloc_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, &dm1105dvb->dma_addr); - return pci_dma_mapping_error(dm1105dvb->pdev, dm1105dvb->dma_addr); + return !dm1105dvb->ts_buf; } static void dm1105dvb_dma_unmap(struct dm1105dvb *dm1105dvb) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 7a421e9dba5..171f9ca124f 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -128,6 +128,7 @@ struct dvb_frontend_private { unsigned int step_size; int quality; unsigned int check_wrapped; + enum dvbfe_search algo_status; }; static void dvb_frontend_wakeup(struct dvb_frontend *fe); @@ -516,6 +517,8 @@ static int dvb_frontend_thread(void *data) struct dvb_frontend_private *fepriv = fe->frontend_priv; unsigned long timeout; fe_status_t s; + enum dvbfe_algo algo; + struct dvb_frontend_parameters *params; dprintk("%s\n", __func__); @@ -562,23 +565,80 @@ restart: /* do an iteration of the tuning loop */ if (fe->ops.get_frontend_algo) { - if (fe->ops.get_frontend_algo(fe) == FE_ALGO_HW) { - /* have we been asked to retune? */ - params = NULL; + algo = fe->ops.get_frontend_algo(fe); + switch (algo) { + case DVBFE_ALGO_HW: + dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__); + params = NULL; /* have we been asked to RETUNE ? */ + if (fepriv->state & FESTATE_RETUNE) { + dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__); params = &fepriv->parameters; fepriv->state = FESTATE_TUNED; } - fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s); - if (s != fepriv->status) { + if (fe->ops.tune) + fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s); + + if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) { + dprintk("%s: state changed, adding current state\n", __func__); dvb_frontend_add_event(fe, s); fepriv->status = s; } - } else + break; + case DVBFE_ALGO_SW: + dprintk("%s: Frontend ALGO = DVBFE_ALGO_SW\n", __func__); dvb_frontend_swzigzag(fe); - } else + break; + case DVBFE_ALGO_CUSTOM: + params = NULL; /* have we been asked to RETUNE ? */ + dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state); + if (fepriv->state & FESTATE_RETUNE) { + dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__); + params = &fepriv->parameters; + fepriv->state = FESTATE_TUNED; + } + /* Case where we are going to search for a carrier + * User asked us to retune again for some reason, possibly + * requesting a search with a new set of parameters + */ + if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) { + if (fe->ops.search) { + fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters); + /* We did do a search as was requested, the flags are + * now unset as well and has the flags wrt to search. + */ + } else { + fepriv->algo_status &= ~DVBFE_ALGO_SEARCH_AGAIN; + } + } + /* Track the carrier if the search was successful */ + if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) { + if (fe->ops.track) + fe->ops.track(fe, &fepriv->parameters); + } else { + fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; + fepriv->delay = HZ / 2; + } + fe->ops.read_status(fe, &s); + if (s != fepriv->status) { + dvb_frontend_add_event(fe, s); /* update event list */ + fepriv->status = s; + if (!(s & FE_HAS_LOCK)) { + fepriv->delay = HZ / 10; + fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; + } else { + fepriv->delay = 60 * HZ; + } + } + break; + default: + dprintk("%s: UNDEFINED ALGO !\n", __func__); + break; + } + } else { dvb_frontend_swzigzag(fe); + } } if (dvb_powerdown_on_sleep) { @@ -1226,6 +1286,9 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp, dprintk("%s() Finalised property cache\n", __func__); dtv_property_cache_submit(fe); + /* Request the search algorithm to search */ + fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; + r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND, &fepriv->parameters); break; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index db4a63b0a32..e176da472d7 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -69,6 +69,125 @@ struct analog_parameters { u64 std; }; +enum dvbfe_modcod { + DVBFE_MODCOD_DUMMY_PLFRAME = 0, + DVBFE_MODCOD_QPSK_1_4, + DVBFE_MODCOD_QPSK_1_3, + DVBFE_MODCOD_QPSK_2_5, + DVBFE_MODCOD_QPSK_1_2, + DVBFE_MODCOD_QPSK_3_5, + DVBFE_MODCOD_QPSK_2_3, + DVBFE_MODCOD_QPSK_3_4, + DVBFE_MODCOD_QPSK_4_5, + DVBFE_MODCOD_QPSK_5_6, + DVBFE_MODCOD_QPSK_8_9, + DVBFE_MODCOD_QPSK_9_10, + DVBFE_MODCOD_8PSK_3_5, + DVBFE_MODCOD_8PSK_2_3, + DVBFE_MODCOD_8PSK_3_4, + DVBFE_MODCOD_8PSK_5_6, + DVBFE_MODCOD_8PSK_8_9, + DVBFE_MODCOD_8PSK_9_10, + DVBFE_MODCOD_16APSK_2_3, + DVBFE_MODCOD_16APSK_3_4, + DVBFE_MODCOD_16APSK_4_5, + DVBFE_MODCOD_16APSK_5_6, + DVBFE_MODCOD_16APSK_8_9, + DVBFE_MODCOD_16APSK_9_10, + DVBFE_MODCOD_32APSK_3_4, + DVBFE_MODCOD_32APSK_4_5, + DVBFE_MODCOD_32APSK_5_6, + DVBFE_MODCOD_32APSK_8_9, + DVBFE_MODCOD_32APSK_9_10, + DVBFE_MODCOD_RESERVED_1, + DVBFE_MODCOD_BPSK_1_3, + DVBFE_MODCOD_BPSK_1_4, + DVBFE_MODCOD_RESERVED_2 +}; + +enum tuner_param { + DVBFE_TUNER_FREQUENCY = (1 << 0), + DVBFE_TUNER_TUNERSTEP = (1 << 1), + DVBFE_TUNER_IFFREQ = (1 << 2), + DVBFE_TUNER_BANDWIDTH = (1 << 3), + DVBFE_TUNER_REFCLOCK = (1 << 4), + DVBFE_TUNER_IQSENSE = (1 << 5), + DVBFE_TUNER_DUMMY = (1 << 31) +}; + +/* + * ALGO_HW: (Hardware Algorithm) + * ---------------------------------------------------------------- + * Devices that support this algorithm do everything in hardware + * and no software support is needed to handle them. + * Requesting these devices to LOCK is the only thing required, + * device is supposed to do everything in the hardware. + * + * ALGO_SW: (Software Algorithm) + * ---------------------------------------------------------------- + * These are dumb devices, that require software to do everything + * + * ALGO_CUSTOM: (Customizable Agorithm) + * ---------------------------------------------------------------- + * Devices having this algorithm can be customized to have specific + * algorithms in the frontend driver, rather than simply doing a + * software zig-zag. In this case the zigzag maybe hardware assisted + * or it maybe completely done in hardware. In all cases, usage of + * this algorithm, in conjunction with the search and track + * callbacks, utilizes the driver specific algorithm. + * + * ALGO_RECOVERY: (Recovery Algorithm) + * ---------------------------------------------------------------- + * These devices have AUTO recovery capabilities from LOCK failure + */ +enum dvbfe_algo { + DVBFE_ALGO_HW = (1 << 0), + DVBFE_ALGO_SW = (1 << 1), + DVBFE_ALGO_CUSTOM = (1 << 2), + DVBFE_ALGO_RECOVERY = (1 << 31) +}; + +struct tuner_state { + u32 frequency; + u32 tunerstep; + u32 ifreq; + u32 bandwidth; + u32 iqsense; + u32 refclock; +}; + +/* + * search callback possible return status + * + * DVBFE_ALGO_SEARCH_SUCCESS + * The frontend search algorithm completed and returned succesfully + * + * DVBFE_ALGO_SEARCH_ASLEEP + * The frontend search algorithm is sleeping + * + * DVBFE_ALGO_SEARCH_FAILED + * The frontend search for a signal failed + * + * DVBFE_ALGO_SEARCH_INVALID + * The frontend search algorith was probably supplied with invalid + * parameters and the search is an invalid one + * + * DVBFE_ALGO_SEARCH_ERROR + * The frontend search algorithm failed due to some error + * + * DVBFE_ALGO_SEARCH_AGAIN + * The frontend search algorithm was requested to search again + */ +enum dvbfe_search { + DVBFE_ALGO_SEARCH_SUCCESS = (1 << 0), + DVBFE_ALGO_SEARCH_ASLEEP = (1 << 1), + DVBFE_ALGO_SEARCH_FAILED = (1 << 2), + DVBFE_ALGO_SEARCH_INVALID = (1 << 3), + DVBFE_ALGO_SEARCH_AGAIN = (1 << 4), + DVBFE_ALGO_SEARCH_ERROR = (1 << 31), +}; + + struct dvb_tuner_ops { struct dvb_tuner_info info; @@ -99,6 +218,13 @@ struct dvb_tuner_ops { * tuners which require sophisticated tuning loops, controlling each parameter seperately. */ int (*set_frequency)(struct dvb_frontend *fe, u32 frequency); int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth); + + /* + * These are provided seperately from set_params in order to facilitate silicon + * tuners which require sophisticated tuning loops, controlling each parameter seperately. + */ + int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state); + int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state); }; struct analog_demod_info { @@ -142,7 +268,7 @@ struct dvb_frontend_ops { unsigned int *delay, fe_status_t *status); /* get frontend tuning algorithm from the module */ - int (*get_frontend_algo)(struct dvb_frontend *fe); + enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe); /* these two are only used for the swzigzag code */ int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); @@ -167,6 +293,12 @@ struct dvb_frontend_ops { int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable); int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire); + /* These callbacks are for devices that implement their own + * tuning algorithms, rather than a simple swzigzag + */ + enum dvbfe_search (*search)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); + int (*track)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); + struct dvb_tuner_ops tuner_ops; struct analog_demod_ops analog_ops; diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index a113744a56c..6c571d9f011 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -50,33 +50,27 @@ static const char * const dnames[] = { "net", "osd" }; +#ifdef CONFIG_DVB_DYNAMIC_MINORS +#define MAX_DVB_MINORS 256 +#define DVB_MAX_IDS MAX_DVB_MINORS +#else #define DVB_MAX_IDS 4 #define nums2minor(num,type,id) ((num << 6) | (id << 4) | type) #define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64) +#endif static struct class *dvb_class; -static struct dvb_device* dvbdev_find_device (int minor) -{ - struct dvb_adapter *adap; - - list_for_each_entry(adap, &dvb_adapter_list, list_head) { - struct dvb_device *dev; - list_for_each_entry(dev, &adap->device_list, list_head) - if (nums2minor(adap->num, dev->type, dev->id) == minor) - return dev; - } - - return NULL; -} - +static struct dvb_device *dvb_minors[MAX_DVB_MINORS]; +static DECLARE_RWSEM(minor_rwsem); static int dvb_device_open(struct inode *inode, struct file *file) { struct dvb_device *dvbdev; lock_kernel(); - dvbdev = dvbdev_find_device (iminor(inode)); + down_read(&minor_rwsem); + dvbdev = dvb_minors[iminor(inode)]; if (dvbdev && dvbdev->fops) { int err = 0; @@ -92,9 +86,11 @@ static int dvb_device_open(struct inode *inode, struct file *file) file->f_op = fops_get(old_fops); } fops_put(old_fops); + up_read(&minor_rwsem); unlock_kernel(); return err; } + up_read(&minor_rwsem); unlock_kernel(); return -ENODEV; } @@ -192,6 +188,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, struct dvb_device *dvbdev; struct file_operations *dvbdevfops; struct device *clsdev; + int minor; int id; mutex_lock(&dvbdev_register_lock); @@ -231,11 +228,31 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, list_add_tail (&dvbdev->list_head, &adap->device_list); + down_write(&minor_rwsem); +#ifdef CONFIG_DVB_DYNAMIC_MINORS + for (minor = 0; minor < MAX_DVB_MINORS; minor++) + if (dvb_minors[minor] == NULL) + break; + + if (minor == MAX_DVB_MINORS) { + kfree(dvbdevfops); + kfree(dvbdev); + mutex_unlock(&dvbdev_register_lock); + return -EINVAL; + } +#else + minor = nums2minor(adap->num, type, id); +#endif + + dvbdev->minor = minor; + dvb_minors[minor] = dvbdev; + up_write(&minor_rwsem); + mutex_unlock(&dvbdev_register_lock); clsdev = device_create(dvb_class, adap->device, - MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), - NULL, "dvb%d.%s%d", adap->num, dnames[type], id); + MKDEV(DVB_MAJOR, minor), + dvbdev, "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", __func__, adap->num, dnames[type], id, PTR_ERR(clsdev)); @@ -243,8 +260,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, } dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", - adap->num, dnames[type], id, nums2minor(adap->num, type, id), - nums2minor(adap->num, type, id)); + adap->num, dnames[type], id, minor, minor); return 0; } @@ -256,8 +272,11 @@ void dvb_unregister_device(struct dvb_device *dvbdev) if (!dvbdev) return; - device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num, - dvbdev->type, dvbdev->id))); + down_write(&minor_rwsem); + dvb_minors[dvbdev->minor] = NULL; + up_write(&minor_rwsem); + + device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor)); list_del (&dvbdev->list_head); kfree (dvbdev->fops); @@ -413,6 +432,15 @@ out: return err; } +static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct dvb_device *dvbdev = dev_get_drvdata(dev); + + add_uevent_var(env, "DVB_DEVICE_NUM=%d", dvbdev->id); + add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num); + return 0; +} + static int __init init_dvbdev(void) { int retval; @@ -434,6 +462,7 @@ static int __init init_dvbdev(void) retval = PTR_ERR(dvb_class); goto error; } + dvb_class->dev_uevent = dvb_uevent; return 0; error: diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h index 574e336bac3..dca49cf962e 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.h +++ b/drivers/media/dvb/dvb-core/dvbdev.h @@ -74,6 +74,7 @@ struct dvb_device { struct file_operations *fops; struct dvb_adapter *adapter; int type; + int minor; u32 id; /* in theory, 'users' can vanish now, diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index e9ab0249d13..e1e9aa5c6b8 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -733,9 +733,19 @@ static int af9015_read_config(struct usb_device *udev) af9015_config.ir_table_size = ARRAY_SIZE(af9015_ir_table_mygictv); break; + case AF9015_REMOTE_DIGITTRADE_DVB_T: + af9015_properties[i].rc_key_map = + af9015_rc_keys_digittrade; + af9015_properties[i].rc_key_map_size = + ARRAY_SIZE(af9015_rc_keys_digittrade); + af9015_config.ir_table = + af9015_ir_table_digittrade; + af9015_config.ir_table_size = + ARRAY_SIZE(af9015_ir_table_digittrade); + break; } } else { - switch (udev->descriptor.idVendor) { + switch (le16_to_cpu(udev->descriptor.idVendor)) { case USB_VID_LEADTEK: af9015_properties[i].rc_key_map = af9015_rc_keys_leadtek; @@ -748,7 +758,7 @@ static int af9015_read_config(struct usb_device *udev) break; case USB_VID_VISIONPLUS: if (udev->descriptor.idProduct == - USB_PID_AZUREWAVE_AD_TU700) { + cpu_to_le16(USB_PID_AZUREWAVE_AD_TU700)) { af9015_properties[i].rc_key_map = af9015_rc_keys_twinhan; af9015_properties[i].rc_key_map_size = @@ -800,6 +810,16 @@ static int af9015_read_config(struct usb_device *udev) ARRAY_SIZE(af9015_ir_table_msi); } break; + case USB_VID_AVERMEDIA: + af9015_properties[i].rc_key_map = + af9015_rc_keys_avermedia; + af9015_properties[i].rc_key_map_size = + ARRAY_SIZE(af9015_rc_keys_avermedia); + af9015_config.ir_table = + af9015_ir_table_avermedia; + af9015_config.ir_table_size = + ARRAY_SIZE(af9015_ir_table_avermedia); + break; } } } @@ -1191,6 +1211,7 @@ static struct usb_device_id af9015_usb_table[] = { {USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2)}, {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)}, /* 15 */{USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)}, + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)}, {0}, }; MODULE_DEVICE_TABLE(usb, af9015_usb_table); @@ -1343,7 +1364,7 @@ static struct dvb_usb_device_properties af9015_properties[] = { .i2c_algo = &af9015_i2c_algo, - .num_device_descs = 6, + .num_device_descs = 7, .devices = { { .name = "Xtensions XD-380", @@ -1375,6 +1396,12 @@ static struct dvb_usb_device_properties af9015_properties[] = { .cold_ids = {&af9015_usb_table[15], NULL}, .warm_ids = {NULL}, }, + { + .name = "KWorld USB DVB-T TV Stick II " \ + "(VS-DVB-T 395U)", + .cold_ids = {&af9015_usb_table[16], NULL}, + .warm_ids = {NULL}, + }, } } }; diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h index 6c3c9729331..21c7782f488 100644 --- a/drivers/media/dvb/dvb-usb/af9015.h +++ b/drivers/media/dvb/dvb-usb/af9015.h @@ -123,6 +123,7 @@ enum af9015_remote { AF9015_REMOTE_A_LINK_DTU_M, AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, AF9015_REMOTE_MYGICTV_U718, + AF9015_REMOTE_DIGITTRADE_DVB_T, }; /* Leadtek WinFast DTV Dongle Gold */ @@ -520,4 +521,143 @@ static u8 af9015_ir_table_kworld[] = { 0x86, 0x6b, 0x23, 0xdc, 0x45, 0x07, 0x00, }; +/* AverMedia Volar X */ +static struct dvb_usb_rc_key af9015_rc_keys_avermedia[] = { + { 0x05, 0x3d, KEY_PROG1 }, /* SOURCE */ + { 0x05, 0x12, KEY_POWER }, /* POWER */ + { 0x05, 0x1e, KEY_1 }, /* 1 */ + { 0x05, 0x1f, KEY_2 }, /* 2 */ + { 0x05, 0x20, KEY_3 }, /* 3 */ + { 0x05, 0x21, KEY_4 }, /* 4 */ + { 0x05, 0x22, KEY_5 }, /* 5 */ + { 0x05, 0x23, KEY_6 }, /* 6 */ + { 0x05, 0x24, KEY_7 }, /* 7 */ + { 0x05, 0x25, KEY_8 }, /* 8 */ + { 0x05, 0x26, KEY_9 }, /* 9 */ + { 0x05, 0x3f, KEY_LEFT }, /* L / DISPLAY */ + { 0x05, 0x27, KEY_0 }, /* 0 */ + { 0x05, 0x0f, KEY_RIGHT }, /* R / CH RTN */ + { 0x05, 0x18, KEY_PROG2 }, /* SNAP SHOT */ + { 0x05, 0x1c, KEY_PROG3 }, /* 16-CH PREV */ + { 0x05, 0x2d, KEY_VOLUMEDOWN }, /* VOL DOWN */ + { 0x05, 0x3e, KEY_ZOOM }, /* FULL SCREEN */ + { 0x05, 0x2e, KEY_VOLUMEUP }, /* VOL UP */ + { 0x05, 0x10, KEY_MUTE }, /* MUTE */ + { 0x05, 0x04, KEY_AUDIO }, /* AUDIO */ + { 0x05, 0x15, KEY_RECORD }, /* RECORD */ + { 0x05, 0x11, KEY_PLAY }, /* PLAY */ + { 0x05, 0x16, KEY_STOP }, /* STOP */ + { 0x05, 0x0c, KEY_PLAYPAUSE }, /* TIMESHIFT / PAUSE */ + { 0x05, 0x05, KEY_BACK }, /* << / RED */ + { 0x05, 0x09, KEY_FORWARD }, /* >> / YELLOW */ + { 0x05, 0x17, KEY_TEXT }, /* TELETEXT */ + { 0x05, 0x0a, KEY_EPG }, /* EPG */ + { 0x05, 0x13, KEY_MENU }, /* MENU */ + + { 0x05, 0x0e, KEY_CHANNELUP }, /* CH UP */ + { 0x05, 0x0d, KEY_CHANNELDOWN }, /* CH DOWN */ + { 0x05, 0x19, KEY_FIRST }, /* |<< / GREEN */ + { 0x05, 0x08, KEY_LAST }, /* >>| / BLUE */ +}; + +static u8 af9015_ir_table_avermedia[] = { + 0x02, 0xfd, 0x00, 0xff, 0x12, 0x05, 0x00, + 0x02, 0xfd, 0x01, 0xfe, 0x3d, 0x05, 0x00, + 0x02, 0xfd, 0x03, 0xfc, 0x17, 0x05, 0x00, + 0x02, 0xfd, 0x04, 0xfb, 0x0a, 0x05, 0x00, + 0x02, 0xfd, 0x05, 0xfa, 0x1e, 0x05, 0x00, + 0x02, 0xfd, 0x06, 0xf9, 0x1f, 0x05, 0x00, + 0x02, 0xfd, 0x07, 0xf8, 0x20, 0x05, 0x00, + 0x02, 0xfd, 0x09, 0xf6, 0x21, 0x05, 0x00, + 0x02, 0xfd, 0x0a, 0xf5, 0x22, 0x05, 0x00, + 0x02, 0xfd, 0x0b, 0xf4, 0x23, 0x05, 0x00, + 0x02, 0xfd, 0x0d, 0xf2, 0x24, 0x05, 0x00, + 0x02, 0xfd, 0x0e, 0xf1, 0x25, 0x05, 0x00, + 0x02, 0xfd, 0x0f, 0xf0, 0x26, 0x05, 0x00, + 0x02, 0xfd, 0x11, 0xee, 0x27, 0x05, 0x00, + 0x02, 0xfd, 0x08, 0xf7, 0x04, 0x05, 0x00, + 0x02, 0xfd, 0x0c, 0xf3, 0x3e, 0x05, 0x00, + 0x02, 0xfd, 0x10, 0xef, 0x1c, 0x05, 0x00, + 0x02, 0xfd, 0x12, 0xed, 0x3f, 0x05, 0x00, + 0x02, 0xfd, 0x13, 0xec, 0x0f, 0x05, 0x00, + 0x02, 0xfd, 0x14, 0xeb, 0x10, 0x05, 0x00, + 0x02, 0xfd, 0x15, 0xea, 0x13, 0x05, 0x00, + 0x02, 0xfd, 0x17, 0xe8, 0x18, 0x05, 0x00, + 0x02, 0xfd, 0x18, 0xe7, 0x11, 0x05, 0x00, + 0x02, 0xfd, 0x19, 0xe6, 0x15, 0x05, 0x00, + 0x02, 0xfd, 0x1a, 0xe5, 0x0c, 0x05, 0x00, + 0x02, 0xfd, 0x1b, 0xe4, 0x16, 0x05, 0x00, + 0x02, 0xfd, 0x1c, 0xe3, 0x09, 0x05, 0x00, + 0x02, 0xfd, 0x1d, 0xe2, 0x05, 0x05, 0x00, + 0x02, 0xfd, 0x1e, 0xe1, 0x2d, 0x05, 0x00, + 0x02, 0xfd, 0x1f, 0xe0, 0x2e, 0x05, 0x00, + 0x03, 0xfc, 0x00, 0xff, 0x08, 0x05, 0x00, + 0x03, 0xfc, 0x01, 0xfe, 0x19, 0x05, 0x00, + 0x03, 0xfc, 0x02, 0xfd, 0x0d, 0x05, 0x00, + 0x03, 0xfc, 0x03, 0xfc, 0x0e, 0x05, 0x00, +}; + +/* Digittrade DVB-T USB Stick */ +static struct dvb_usb_rc_key af9015_rc_keys_digittrade[] = { + { 0x01, 0x0f, KEY_LAST }, /* RETURN */ + { 0x05, 0x17, KEY_TEXT }, /* TELETEXT */ + { 0x01, 0x08, KEY_EPG }, /* EPG */ + { 0x05, 0x13, KEY_POWER }, /* POWER */ + { 0x01, 0x09, KEY_ZOOM }, /* FULLSCREEN */ + { 0x00, 0x40, KEY_AUDIO }, /* DUAL SOUND */ + { 0x00, 0x2c, KEY_PRINT }, /* SNAPSHOT */ + { 0x05, 0x16, KEY_SUBTITLE }, /* SUBTITLE */ + { 0x00, 0x52, KEY_CHANNELUP }, /* CH Up */ + { 0x00, 0x51, KEY_CHANNELDOWN },/* Ch Dn */ + { 0x00, 0x57, KEY_VOLUMEUP }, /* Vol Up */ + { 0x00, 0x56, KEY_VOLUMEDOWN }, /* Vol Dn */ + { 0x01, 0x10, KEY_MUTE }, /* MUTE */ + { 0x00, 0x27, KEY_0 }, + { 0x00, 0x1e, KEY_1 }, + { 0x00, 0x1f, KEY_2 }, + { 0x00, 0x20, KEY_3 }, + { 0x00, 0x21, KEY_4 }, + { 0x00, 0x22, KEY_5 }, + { 0x00, 0x23, KEY_6 }, + { 0x00, 0x24, KEY_7 }, + { 0x00, 0x25, KEY_8 }, + { 0x00, 0x26, KEY_9 }, + { 0x01, 0x17, KEY_PLAYPAUSE }, /* TIMESHIFT */ + { 0x01, 0x15, KEY_RECORD }, /* RECORD */ + { 0x03, 0x13, KEY_PLAY }, /* PLAY */ + { 0x01, 0x16, KEY_STOP }, /* STOP */ + { 0x01, 0x13, KEY_PAUSE }, /* PAUSE */ +}; + +static u8 af9015_ir_table_digittrade[] = { + 0x00, 0xff, 0x06, 0xf9, 0x13, 0x05, 0x00, + 0x00, 0xff, 0x4d, 0xb2, 0x17, 0x01, 0x00, + 0x00, 0xff, 0x1f, 0xe0, 0x2c, 0x00, 0x00, + 0x00, 0xff, 0x0a, 0xf5, 0x15, 0x01, 0x00, + 0x00, 0xff, 0x0e, 0xf1, 0x16, 0x01, 0x00, + 0x00, 0xff, 0x09, 0xf6, 0x09, 0x01, 0x00, + 0x00, 0xff, 0x01, 0xfe, 0x08, 0x01, 0x00, + 0x00, 0xff, 0x05, 0xfa, 0x10, 0x01, 0x00, + 0x00, 0xff, 0x02, 0xfd, 0x56, 0x00, 0x00, + 0x00, 0xff, 0x40, 0xbf, 0x57, 0x00, 0x00, + 0x00, 0xff, 0x19, 0xe6, 0x52, 0x00, 0x00, + 0x00, 0xff, 0x17, 0xe8, 0x51, 0x00, 0x00, + 0x00, 0xff, 0x10, 0xef, 0x0f, 0x01, 0x00, + 0x00, 0xff, 0x54, 0xab, 0x27, 0x00, 0x00, + 0x00, 0xff, 0x1b, 0xe4, 0x1e, 0x00, 0x00, + 0x00, 0xff, 0x11, 0xee, 0x1f, 0x00, 0x00, + 0x00, 0xff, 0x15, 0xea, 0x20, 0x00, 0x00, + 0x00, 0xff, 0x12, 0xed, 0x21, 0x00, 0x00, + 0x00, 0xff, 0x16, 0xe9, 0x22, 0x00, 0x00, + 0x00, 0xff, 0x4c, 0xb3, 0x23, 0x00, 0x00, + 0x00, 0xff, 0x48, 0xb7, 0x24, 0x00, 0x00, + 0x00, 0xff, 0x04, 0xfb, 0x25, 0x00, 0x00, + 0x00, 0xff, 0x00, 0xff, 0x26, 0x00, 0x00, + 0x00, 0xff, 0x1e, 0xe1, 0x13, 0x03, 0x00, + 0x00, 0xff, 0x1a, 0xe5, 0x13, 0x01, 0x00, + 0x00, 0xff, 0x03, 0xfc, 0x17, 0x05, 0x00, + 0x00, 0xff, 0x0d, 0xf2, 0x16, 0x05, 0x00, + 0x00, 0xff, 0x1d, 0xe2, 0x40, 0x00, 0x00, +}; + #endif diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c index cd2edbcaa09..5017f08b14a 100644 --- a/drivers/media/dvb/dvb-usb/anysee.c +++ b/drivers/media/dvb/dvb-usb/anysee.c @@ -153,7 +153,7 @@ static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); - int ret, inc, i = 0; + int ret = 0, inc, i = 0; if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-core.c b/drivers/media/dvb/dvb-usb/cinergyT2-core.c index 3ac9f74e9fb..80e37a0d089 100644 --- a/drivers/media/dvb/dvb-usb/cinergyT2-core.c +++ b/drivers/media/dvb/dvb-usb/cinergyT2-core.c @@ -32,7 +32,6 @@ /* debug */ int dvb_usb_cinergyt2_debug; -int disable_remote; module_param_named(debug, dvb_usb_cinergyt2_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info, xfer=2, rc=4 " @@ -45,7 +44,7 @@ struct cinergyt2_state { }; /* We are missing a release hook with usb_device data */ -struct dvb_usb_device *cinergyt2_usb_device; +static struct dvb_usb_device *cinergyt2_usb_device; static struct dvb_usb_device_properties cinergyt2_properties; diff --git a/drivers/media/dvb/dvb-usb/cinergyT2.h b/drivers/media/dvb/dvb-usb/cinergyT2.h index 11d79eb384c..84efe03771e 100644 --- a/drivers/media/dvb/dvb-usb/cinergyT2.h +++ b/drivers/media/dvb/dvb-usb/cinergyT2.h @@ -70,11 +70,11 @@ struct dvbt_get_status_msg { uint8_t bandwidth; uint16_t tps; uint8_t flags; - uint16_t gain; + __le16 gain; uint8_t snr; - uint32_t viterbi_error_rate; + __le32 viterbi_error_rate; uint32_t rs_error_rate; - uint32_t uncorrected_block_count; + __le32 uncorrected_block_count; uint8_t lock_bits; uint8_t prev_lock_bits; } __attribute__((packed)); @@ -82,9 +82,9 @@ struct dvbt_get_status_msg { struct dvbt_set_parameters_msg { uint8_t cmd; - uint32_t freq; + __le32 freq; uint8_t bandwidth; - uint16_t tps; + __le16 tps; uint8_t flags; } __attribute__((packed)); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 7380b94b3b3..a4fca3fca5e 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -96,6 +96,7 @@ #define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 #define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 #define USB_PID_KWORLD_399U 0xe399 +#define USB_PID_KWORLD_395U 0xe396 #define USB_PID_KWORLD_PC160_2T 0xc160 #define USB_PID_KWORLD_VSTREAM_COLD 0x17de #define USB_PID_KWORLD_VSTREAM_WARM 0x17df diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 6286fbbe7fb..c65f273ff31 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -9,7 +9,6 @@ * * see Documentation/dvb/README.dvb-usb for more information */ -#include <linux/version.h> #include "dw2102.h" #include "si21xx.h" #include "stv0299.h" @@ -27,6 +26,10 @@ #define USB_PID_DW2104 0x2104 #endif +#ifndef USB_PID_CINERGY_S +#define USB_PID_CINERGY_S 0x0064 +#endif + #define DW210X_READ_MSG 0 #define DW210X_WRITE_MSG 1 @@ -578,6 +581,7 @@ static struct usb_device_id dw2102_table[] = { {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, {USB_DEVICE(USB_VID_CYPRESS, 0x2104)}, {USB_DEVICE(0x9022, 0xd650)}, + {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)}, { } }; @@ -647,6 +651,7 @@ static int dw2102_load_firmware(struct usb_device *dev, dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, DW210X_WRITE_MSG); break; + case USB_PID_CINERGY_S: case USB_PID_DW2102: dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, DW210X_WRITE_MSG); @@ -655,7 +660,7 @@ static int dw2102_load_firmware(struct usb_device *dev, /* check STV0299 frontend */ dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2, DW210X_READ_MSG); - if (reset16[0] == 0xa1) { + if ((reset16[0] == 0xa1) || (reset16[0] == 0x80)) { dw2102_properties.i2c_algo = &dw2102_i2c_algo; dw2102_properties.adapter->tuner_attach = &dw2102_tuner_attach; break; @@ -726,7 +731,7 @@ static struct dvb_usb_device_properties dw2102_properties = { }, } }, - .num_device_descs = 2, + .num_device_descs = 3, .devices = { {"DVBWorld DVB-S 2102 USB2.0", {&dw2102_table[0], NULL}, @@ -736,6 +741,10 @@ static struct dvb_usb_device_properties dw2102_properties = { {&dw2102_table[1], NULL}, {NULL}, }, + {"TerraTec Cinergy S USB", + {&dw2102_table[4], NULL}, + {NULL}, + }, } }; diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c index 262a858c306..20eadf9318e 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk-fe.c +++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c @@ -25,6 +25,20 @@ struct gp8psk_fe_state { unsigned long status_check_interval; }; +static int gp8psk_tuned_to_DCII(struct dvb_frontend *fe) +{ + struct gp8psk_fe_state *st = fe->demodulator_priv; + u8 status; + gp8psk_usb_in_op(st->d, GET_8PSK_CONFIG, 0, 0, &status, 1); + return status & bmDCtuned; +} + +static int gp8psk_set_tuner_mode(struct dvb_frontend *fe, int mode) +{ + struct gp8psk_fe_state *state = fe->demodulator_priv; + return gp8psk_usb_out_op(state->d, SET_8PSK_CONFIG, mode, 0, NULL, 0); +} + static int gp8psk_fe_update_status(struct gp8psk_fe_state *st) { u8 buf[6]; @@ -99,39 +113,114 @@ static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_front return 0; } +static int gp8psk_fe_set_property(struct dvb_frontend *fe, + struct dtv_property *tvp) +{ + deb_fe("%s(..)\n", __func__); + return 0; +} + +static int gp8psk_fe_get_property(struct dvb_frontend *fe, + struct dtv_property *tvp) +{ + deb_fe("%s(..)\n", __func__); + return 0; +} + + static int gp8psk_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct gp8psk_fe_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; u8 cmd[10]; u32 freq = fep->frequency * 1000; + int gp_product_id = le16_to_cpu(state->d->udev->descriptor.idProduct); + + deb_fe("%s()\n", __func__); cmd[4] = freq & 0xff; cmd[5] = (freq >> 8) & 0xff; cmd[6] = (freq >> 16) & 0xff; cmd[7] = (freq >> 24) & 0xff; - switch(fe->ops.info.type) { - case FE_QPSK: - cmd[0] = fep->u.qpsk.symbol_rate & 0xff; - cmd[1] = (fep->u.qpsk.symbol_rate >> 8) & 0xff; - cmd[2] = (fep->u.qpsk.symbol_rate >> 16) & 0xff; - cmd[3] = (fep->u.qpsk.symbol_rate >> 24) & 0xff; - cmd[8] = ADV_MOD_DVB_QPSK; - cmd[9] = 0x03; /*ADV_MOD_FEC_XXX*/ + switch (c->delivery_system) { + case SYS_DVBS: + /* Only QPSK is supported for DVB-S */ + if (c->modulation != QPSK) { + deb_fe("%s: unsupported modulation selected (%d)\n", + __func__, c->modulation); + return -EOPNOTSUPP; + } + c->fec_inner = FEC_AUTO; break; + case SYS_DVBS2: + deb_fe("%s: DVB-S2 delivery system selected\n", __func__); + break; + default: - // other modes are unsuported right now - cmd[0] = 0; - cmd[1] = 0; - cmd[2] = 0; - cmd[3] = 0; - cmd[8] = 0; + deb_fe("%s: unsupported delivery system selected (%d)\n", + __func__, c->delivery_system); + return -EOPNOTSUPP; + } + + cmd[0] = c->symbol_rate & 0xff; + cmd[1] = (c->symbol_rate >> 8) & 0xff; + cmd[2] = (c->symbol_rate >> 16) & 0xff; + cmd[3] = (c->symbol_rate >> 24) & 0xff; + switch (c->modulation) { + case QPSK: + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + if (gp8psk_tuned_to_DCII(fe)) + gp8psk_bcm4500_reload(state->d); + switch (c->fec_inner) { + case FEC_1_2: + cmd[9] = 0; break; + case FEC_2_3: + cmd[9] = 1; break; + case FEC_3_4: + cmd[9] = 2; break; + case FEC_5_6: + cmd[9] = 3; break; + case FEC_7_8: + cmd[9] = 4; break; + case FEC_AUTO: + cmd[9] = 5; break; + default: + cmd[9] = 5; break; + } + cmd[8] = ADV_MOD_DVB_QPSK; + break; + case PSK_8: /* PSK_8 is for compatibility with DN */ + cmd[8] = ADV_MOD_TURBO_8PSK; + switch (c->fec_inner) { + case FEC_2_3: + cmd[9] = 0; break; + case FEC_3_4: + cmd[9] = 1; break; + case FEC_3_5: + cmd[9] = 2; break; + case FEC_5_6: + cmd[9] = 3; break; + case FEC_8_9: + cmd[9] = 4; break; + default: + cmd[9] = 0; break; + } + break; + case QAM_16: /* QAM_16 is for compatibility with DN */ + cmd[8] = ADV_MOD_TURBO_16QAM; cmd[9] = 0; break; + default: /* Unknown modulation */ + deb_fe("%s: unsupported modulation selected (%d)\n", + __func__, c->modulation); + return -EOPNOTSUPP; } - gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10); + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + gp8psk_set_tuner_mode(fe, 0); + gp8psk_usb_out_op(state->d, TUNE_8PSK, 0, 0, cmd, 10); state->lock = 0; state->next_status_check = jiffies; @@ -140,13 +229,6 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe, return 0; } -static int gp8psk_fe_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) -{ - return 0; -} - - static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *m) { @@ -261,9 +343,13 @@ static struct dvb_frontend_ops gp8psk_fe_ops = { .symbol_rate_max = 45000000, .symbol_rate_tolerance = 500, /* ppm */ .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + /* + * FE_CAN_QAM_16 is for compatibility + * (Myth incorrectly detects Turbo-QPSK as plain QAM-16) + */ + FE_CAN_QPSK | FE_CAN_QAM_16 }, .release = gp8psk_fe_release, @@ -271,8 +357,10 @@ static struct dvb_frontend_ops gp8psk_fe_ops = { .init = NULL, .sleep = NULL, + .set_property = gp8psk_fe_set_property, + .get_property = gp8psk_fe_get_property, .set_frontend = gp8psk_fe_set_frontend, - .get_frontend = gp8psk_fe_get_frontend, + .get_tune_settings = gp8psk_fe_get_tune_settings, .read_status = gp8psk_fe_read_status, diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c index d965a923f39..c1da962cc88 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk.c +++ b/drivers/media/dvb/dvb-usb/gp8psk.c @@ -174,6 +174,22 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) 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) { diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h index e5cd8149c23..e83a57506cf 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk.h +++ b/drivers/media/dvb/dvb-usb/gp8psk.h @@ -92,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/usb-urb.c b/drivers/media/dvb/dvb-usb/usb-urb.c index da93b9e982c..9da2cc95ca1 100644 --- a/drivers/media/dvb/dvb-usb/usb-urb.c +++ b/drivers/media/dvb/dvb-usb/usb-urb.c @@ -156,7 +156,8 @@ static int usb_bulk_urb_init(struct usb_data_stream *stream) stream->props.u.bulk.buffersize, usb_urb_complete, stream); - stream->urb_list[i]->transfer_flags = 0; + stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + stream->urb_list[i]->transfer_dma = stream->dma_addr[i]; stream->urbs_initialized++; } return 0; diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 96b93e21a84..00269560793 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -12,6 +12,25 @@ config DVB_FE_CUSTOMISE If unsure say N. +comment "Multistandard (satellite) frontends" + depends on DVB_CORE + +config DVB_STB0899 + tristate "STB0899 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S/S2/DSS Multistandard demodulator. Say Y when you want + to support this demodulator based frontends + +config DVB_STB6100 + tristate "STB6100 based tuners" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A Silicon tuner from ST used in conjunction with the STB0899 + demodulator. Say Y when you want to support this tuner. + comment "DVB-S (satellite) frontends" depends on DVB_CORE @@ -78,6 +97,13 @@ config DVB_TDA10086 help A DVB-S tuner module. Say Y when you want to support this frontend. +config DVB_TDA8261 + tristate "Philips TDA8261 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + config DVB_VES1X93 tristate "VLSI VES1893 or VES1993 based" depends on DVB_CORE && I2C @@ -92,6 +118,14 @@ config DVB_TUNER_ITD1000 help A DVB-S tuner module. Say Y when you want to support this frontend. +config DVB_TUNER_CX24113 + tristate "Conexant CX24113/CX24128 tuner for DVB-S/DSS" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + + config DVB_TDA826X tristate "Philips TDA826X silicon tuner" depends on DVB_CORE && I2C @@ -345,6 +379,14 @@ config DVB_LGDT330X An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. +config DVB_LGDT3304 + tristate "LG Electronics LGDT3304" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want + to support this frontend. + config DVB_S5H1409 tristate "Samsung S5H1409 based" depends on DVB_CORE && I2C @@ -369,6 +411,17 @@ config DVB_S5H1411 An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. +comment "ISDB-T (terrestrial) frontends" + depends on DVB_CORE + +config DVB_S921 + tristate "Sharp S921 tuner" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + AN ISDB-T DQPSK, QPSK, 16QAM and 64QAM 1seg tuner module. + Say Y when you want to support this frontend. + comment "Digital terrestrial only tuners/PLL" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index aba79f4a63a..af7bdf0ad4c 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -5,8 +5,13 @@ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ EXTRA_CFLAGS += -Idrivers/media/common/tuners/ +s921-objs := s921_module.o s921_core.o +stb0899-objs = stb0899_drv.o stb0899_algo.o + obj-$(CONFIG_DVB_PLL) += dvb-pll.o obj-$(CONFIG_DVB_STV0299) += stv0299.o +obj-$(CONFIG_DVB_STB0899) += stb0899.o +obj-$(CONFIG_DVB_STB6100) += stb6100.o obj-$(CONFIG_DVB_SP8870) += sp8870.o obj-$(CONFIG_DVB_CX22700) += cx22700.o obj-$(CONFIG_DVB_CX24110) += cx24110.o @@ -35,18 +40,21 @@ obj-$(CONFIG_DVB_OR51132) += or51132.o obj-$(CONFIG_DVB_BCM3510) += bcm3510.o obj-$(CONFIG_DVB_S5H1420) += s5h1420.o obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o +obj-$(CONFIG_DVB_LGDT3304) += lgdt3304.o obj-$(CONFIG_DVB_CX24123) += cx24123.o obj-$(CONFIG_DVB_LNBP21) += lnbp21.o obj-$(CONFIG_DVB_ISL6405) += isl6405.o obj-$(CONFIG_DVB_ISL6421) += isl6421.o obj-$(CONFIG_DVB_TDA10086) += tda10086.o obj-$(CONFIG_DVB_TDA826X) += tda826x.o +obj-$(CONFIG_DVB_TDA8261) += tda8261.o obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o obj-$(CONFIG_DVB_S5H1409) += s5h1409.o obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o obj-$(CONFIG_DVB_AU8522) += au8522.o obj-$(CONFIG_DVB_TDA10048) += tda10048.o +obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o obj-$(CONFIG_DVB_S5H1411) += s5h1411.o obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o @@ -55,3 +63,5 @@ obj-$(CONFIG_DVB_CX24116) += cx24116.o obj-$(CONFIG_DVB_SI21XX) += si21xx.o obj-$(CONFIG_DVB_STV0288) += stv0288.o obj-$(CONFIG_DVB_STB6000) += stb6000.o +obj-$(CONFIG_DVB_S921) += s921.o + diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c index 692b68a9e73..b2b50fb4cfd 100644 --- a/drivers/media/dvb/frontends/af9013.c +++ b/drivers/media/dvb/frontends/af9013.c @@ -223,12 +223,12 @@ static int af9013_set_coeff(struct af9013_state *state, fe_bandwidth_t bw) int ret = 0; u8 i = 0; u8 buf[24]; - u32 ns_coeff1_2048nu; - u32 ns_coeff1_8191nu; - u32 ns_coeff1_8192nu; - u32 ns_coeff1_8193nu; - u32 ns_coeff2_2k; - u32 ns_coeff2_8k; + u32 uninitialized_var(ns_coeff1_2048nu); + u32 uninitialized_var(ns_coeff1_8191nu); + u32 uninitialized_var(ns_coeff1_8192nu); + u32 uninitialized_var(ns_coeff1_8193nu); + u32 uninitialized_var(ns_coeff2_2k); + u32 uninitialized_var(ns_coeff2_8k); deb_info("%s: adc_clock:%d bw:%d\n", __func__, state->config.adc_clock, bw); @@ -1009,7 +1009,7 @@ static int af9013_update_snr(struct dvb_frontend *fe) int ret; u8 buf[3], i, len; u32 quant = 0; - struct snr_table *snr_table; + struct snr_table *uninitialized_var(snr_table); /* check if quantizer ready (for snr) */ ret = af9013_read_reg_bits(state, 0xd2e1, 3, 1, &buf[0]); diff --git a/drivers/media/dvb/frontends/cx24113.c b/drivers/media/dvb/frontends/cx24113.c new file mode 100644 index 00000000000..f6e7b0380a5 --- /dev/null +++ b/drivers/media/dvb/frontends/cx24113.c @@ -0,0 +1,616 @@ +/* + * Driver for Conexant CX24113/CX24128 Tuner (Satellite) + * + * Copyright (C) 2007-8 Patrick Boettcher <pb@linuxtv.org> + * + * Developed for BBTI / Technisat + * + * 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/slab.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> + +#include "dvb_frontend.h" +#include "cx24113.h" + +static int debug; + +#define info(args...) do { printk(KERN_INFO "CX24113: " args); } while (0) +#define err(args...) do { printk(KERN_ERR "CX24113: " args); } while (0) + +#define dprintk(args...) \ + do { \ + if (debug) { \ + printk(KERN_DEBUG "CX24113: %s: ", __func__); \ + printk(args); \ + } \ + } while (0) + +struct cx24113_state { + struct i2c_adapter *i2c; + const struct cx24113_config *config; + +#define REV_CX24113 0x23 + u8 rev; + u8 ver; + + u8 icp_mode:1; + +#define ICP_LEVEL1 0 +#define ICP_LEVEL2 1 +#define ICP_LEVEL3 2 +#define ICP_LEVEL4 3 + u8 icp_man:2; + u8 icp_auto_low:2; + u8 icp_auto_mlow:2; + u8 icp_auto_mhi:2; + u8 icp_auto_hi:2; + u8 icp_dig; + +#define LNA_MIN_GAIN 0 +#define LNA_MID_GAIN 1 +#define LNA_MAX_GAIN 2 + u8 lna_gain:2; + + u8 acp_on:1; + + u8 vco_mode:2; + u8 vco_shift:1; +#define VCOBANDSEL_6 0x80 +#define VCOBANDSEL_5 0x01 +#define VCOBANDSEL_4 0x02 +#define VCOBANDSEL_3 0x04 +#define VCOBANDSEL_2 0x08 +#define VCOBANDSEL_1 0x10 + u8 vco_band; + +#define VCODIV4 4 +#define VCODIV2 2 + u8 vcodiv; + + u8 bs_delay:4; + u16 bs_freqcnt:13; + u16 bs_rdiv; + u8 prescaler_mode:1; + + u8 rfvga_bias_ctrl; + + s16 tuner_gain_thres; + u8 gain_level; + + u32 frequency; + + u8 refdiv; + + u8 Fwindow_enabled; +}; + +static int cx24113_writereg(struct cx24113_state *state, int reg, int data) +{ + u8 buf[] = { reg, data }; + struct i2c_msg msg = { .addr = state->config->i2c_addr, + .flags = 0, .buf = buf, .len = 2 }; + int err = i2c_transfer(state->i2c, &msg, 1); + if (err != 1) { + printk(KERN_DEBUG "%s: writereg error(err == %i, reg == 0x%02x," + " data == 0x%02x)\n", __func__, err, reg, data); + return err; + } + + return 0; +} + +static int cx24113_readreg(struct cx24113_state *state, u8 reg) +{ + int ret; + u8 b; + struct i2c_msg msg[] = { + { .addr = state->config->i2c_addr, + .flags = 0, .buf = ®, .len = 1 }, + { .addr = state->config->i2c_addr, + .flags = I2C_M_RD, .buf = &b, .len = 1 } + }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) { + printk(KERN_DEBUG "%s: reg=0x%x (error=%d)\n", + __func__, reg, ret); + return ret; + } + + return b; +} + +static void cx24113_set_parameters(struct cx24113_state *state) +{ + u8 r; + + r = cx24113_readreg(state, 0x10) & 0x82; + r |= state->icp_mode; + r |= state->icp_man << 4; + r |= state->icp_dig << 2; + r |= state->prescaler_mode << 5; + cx24113_writereg(state, 0x10, r); + + r = (state->icp_auto_low << 0) | (state->icp_auto_mlow << 2) + | (state->icp_auto_mhi << 4) | (state->icp_auto_hi << 6); + cx24113_writereg(state, 0x11, r); + + if (state->rev == REV_CX24113) { + r = cx24113_readreg(state, 0x20) & 0xec; + r |= state->lna_gain; + r |= state->rfvga_bias_ctrl << 4; + cx24113_writereg(state, 0x20, r); + } + + r = cx24113_readreg(state, 0x12) & 0x03; + r |= state->acp_on << 2; + r |= state->bs_delay << 4; + cx24113_writereg(state, 0x12, r); + + r = cx24113_readreg(state, 0x18) & 0x40; + r |= state->vco_shift; + if (state->vco_band == VCOBANDSEL_6) + r |= (1 << 7); + else + r |= (state->vco_band << 1); + cx24113_writereg(state, 0x18, r); + + r = cx24113_readreg(state, 0x14) & 0x20; + r |= (state->vco_mode << 6) | ((state->bs_freqcnt >> 8) & 0x1f); + cx24113_writereg(state, 0x14, r); + cx24113_writereg(state, 0x15, (state->bs_freqcnt & 0xff)); + + cx24113_writereg(state, 0x16, (state->bs_rdiv >> 4) & 0xff); + r = (cx24113_readreg(state, 0x17) & 0x0f) | + ((state->bs_rdiv & 0x0f) << 4); + cx24113_writereg(state, 0x17, r); +} + +#define VGA_0 0x00 +#define VGA_1 0x04 +#define VGA_2 0x02 +#define VGA_3 0x06 +#define VGA_4 0x01 +#define VGA_5 0x05 +#define VGA_6 0x03 +#define VGA_7 0x07 + +#define RFVGA_0 0x00 +#define RFVGA_1 0x01 +#define RFVGA_2 0x02 +#define RFVGA_3 0x03 + +static int cx24113_set_gain_settings(struct cx24113_state *state, + s16 power_estimation) +{ + u8 ampout = cx24113_readreg(state, 0x1d) & 0xf0, + vga = cx24113_readreg(state, 0x1f) & 0x3f, + rfvga = cx24113_readreg(state, 0x20) & 0xf3; + u8 gain_level = power_estimation >= state->tuner_gain_thres; + + dprintk("power estimation: %d, thres: %d, gain_level: %d/%d\n", + power_estimation, state->tuner_gain_thres, + state->gain_level, gain_level); + + if (gain_level == state->gain_level) + return 0; /* nothing to be done */ + + ampout |= 0xf; + + if (gain_level) { + rfvga |= RFVGA_0 << 2; + vga |= (VGA_7 << 3) | VGA_7; + } else { + rfvga |= RFVGA_2 << 2; + vga |= (VGA_6 << 3) | VGA_2; + } + state->gain_level = gain_level; + + cx24113_writereg(state, 0x1d, ampout); + cx24113_writereg(state, 0x1f, vga); + cx24113_writereg(state, 0x20, rfvga); + + return 1; /* did something */ +} + +static int cx24113_set_Fref(struct cx24113_state *state, u8 high) +{ + u8 xtal = cx24113_readreg(state, 0x02); + if (state->rev == 0x43 && state->vcodiv == VCODIV4) + high = 1; + + xtal &= ~0x2; + if (high) + xtal |= high << 1; + return cx24113_writereg(state, 0x02, xtal); +} + +static int cx24113_enable(struct cx24113_state *state, u8 enable) +{ + u8 r21 = (cx24113_readreg(state, 0x21) & 0xc0) | enable; + if (state->rev == REV_CX24113) + r21 |= (1 << 1); + return cx24113_writereg(state, 0x21, r21); +} + +static int cx24113_set_bandwidth(struct cx24113_state *state, u32 bandwidth_khz) +{ + u8 r; + + if (bandwidth_khz <= 19000) + r = 0x03 << 6; + else if (bandwidth_khz <= 25000) + r = 0x02 << 6; + else + r = 0x01 << 6; + + dprintk("bandwidth to be set: %d\n", bandwidth_khz); + bandwidth_khz *= 10; + bandwidth_khz -= 10000; + bandwidth_khz /= 1000; + bandwidth_khz += 5; + bandwidth_khz /= 10; + + dprintk("bandwidth: %d %d\n", r >> 6, bandwidth_khz); + + r |= bandwidth_khz & 0x3f; + + return cx24113_writereg(state, 0x1e, r); +} + +static int cx24113_set_clk_inversion(struct cx24113_state *state, u8 on) +{ + u8 r = (cx24113_readreg(state, 0x10) & 0x7f) | ((on & 0x1) << 7); + return cx24113_writereg(state, 0x10, r); +} + +static int cx24113_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct cx24113_state *state = fe->tuner_priv; + u8 r = (cx24113_readreg(state, 0x10) & 0x02) >> 1; + if (r) + *status |= TUNER_STATUS_LOCKED; + dprintk("PLL locked: %d\n", r); + return 0; +} + +static u8 cx24113_set_ref_div(struct cx24113_state *state, u8 refdiv) +{ + if (state->rev == 0x43 && state->vcodiv == VCODIV4) + refdiv = 2; + return state->refdiv = refdiv; +} + +static void cx24113_calc_pll_nf(struct cx24113_state *state, u16 *n, s32 *f) +{ + s32 N; + s64 F; + u8 R, r; + u8 vcodiv; + u8 factor; + s32 freq_hz = state->frequency * 1000; + + if (state->config->xtal_khz < 20000) + factor = 1; + else + factor = 2; + + if (state->rev == REV_CX24113) { + if (state->frequency >= 1100000) + vcodiv = VCODIV2; + else + vcodiv = VCODIV4; + } else { + if (state->frequency >= 1165000) + vcodiv = VCODIV2; + else + vcodiv = VCODIV4; + } + state->vcodiv = vcodiv; + + dprintk("calculating N/F for %dHz with vcodiv %d\n", freq_hz, vcodiv); + R = 0; + do { + R = cx24113_set_ref_div(state, R + 1); + + /* calculate tuner PLL settings: */ + N = (freq_hz / 100 * vcodiv) * R; + N /= (state->config->xtal_khz) * factor * 2; + N += 5; /* For round up. */ + N /= 10; + N -= 32; + } while (N < 6 && R < 3); + + if (N < 6) { + err("strange frequency: N < 6\n"); + return; + } + F = freq_hz; + F *= (u64) (R * vcodiv * 262144); + dprintk("1 N: %d, F: %lld, R: %d\n", N, (long long)F, R); + do_div(F, state->config->xtal_khz*1000 * factor * 2); + dprintk("2 N: %d, F: %lld, R: %d\n", N, (long long)F, R); + F -= (N + 32) * 262144; + + dprintk("3 N: %d, F: %lld, R: %d\n", N, (long long)F, R); + + if (state->Fwindow_enabled) { + if (F > (262144 / 2 - 1638)) + F = 262144 / 2 - 1638; + if (F < (-262144 / 2 + 1638)) + F = -262144 / 2 + 1638; + if ((F < 3277 && F > 0) || (F > -3277 && F < 0)) { + F = 0; + r = cx24113_readreg(state, 0x10); + cx24113_writereg(state, 0x10, r | (1 << 6)); + } + } + dprintk("4 N: %d, F: %lld, R: %d\n", N, (long long)F, R); + + *n = (u16) N; + *f = (s32) F; +} + + +static void cx24113_set_nfr(struct cx24113_state *state, u16 n, s32 f, u8 r) +{ + u8 reg; + cx24113_writereg(state, 0x19, (n >> 1) & 0xff); + + reg = ((n & 0x1) << 7) | ((f >> 11) & 0x7f); + cx24113_writereg(state, 0x1a, reg); + + cx24113_writereg(state, 0x1b, (f >> 3) & 0xff); + + reg = cx24113_readreg(state, 0x1c) & 0x1f; + cx24113_writereg(state, 0x1c, reg | ((f & 0x7) << 5)); + + cx24113_set_Fref(state, r - 1); +} + +static int cx24113_set_frequency(struct cx24113_state *state, u32 frequency) +{ + u8 r = 1; /* or 2 */ + u16 n = 6; + s32 f = 0; + + r = cx24113_readreg(state, 0x14); + cx24113_writereg(state, 0x14, r & 0x3f); + + r = cx24113_readreg(state, 0x10); + cx24113_writereg(state, 0x10, r & 0xbf); + + state->frequency = frequency; + + dprintk("tuning to frequency: %d\n", frequency); + + cx24113_calc_pll_nf(state, &n, &f); + cx24113_set_nfr(state, n, f, state->refdiv); + + r = cx24113_readreg(state, 0x18) & 0xbf; + if (state->vcodiv != VCODIV2) + r |= 1 << 6; + cx24113_writereg(state, 0x18, r); + + /* The need for this sleep is not clear. But helps in some cases */ + msleep(5); + + r = cx24113_readreg(state, 0x1c) & 0xef; + cx24113_writereg(state, 0x1c, r | (1 << 4)); + return 0; +} + +static int cx24113_init(struct dvb_frontend *fe) +{ + struct cx24113_state *state = fe->tuner_priv; + int ret; + + state->tuner_gain_thres = -50; + state->gain_level = 255; /* to force a gain-setting initialization */ + state->icp_mode = 0; + + if (state->config->xtal_khz < 11000) { + state->icp_auto_hi = ICP_LEVEL4; + state->icp_auto_mhi = ICP_LEVEL4; + state->icp_auto_mlow = ICP_LEVEL3; + state->icp_auto_low = ICP_LEVEL3; + } else { + state->icp_auto_hi = ICP_LEVEL4; + state->icp_auto_mhi = ICP_LEVEL4; + state->icp_auto_mlow = ICP_LEVEL3; + state->icp_auto_low = ICP_LEVEL2; + } + + state->icp_dig = ICP_LEVEL3; + state->icp_man = ICP_LEVEL1; + state->acp_on = 1; + state->vco_mode = 0; + state->vco_shift = 0; + state->vco_band = VCOBANDSEL_1; + state->bs_delay = 8; + state->bs_freqcnt = 0x0fff; + state->bs_rdiv = 0x0fff; + state->prescaler_mode = 0; + state->lna_gain = LNA_MAX_GAIN; + state->rfvga_bias_ctrl = 1; + state->Fwindow_enabled = 1; + + cx24113_set_Fref(state, 0); + cx24113_enable(state, 0x3d); + cx24113_set_parameters(state); + + cx24113_set_gain_settings(state, -30); + + cx24113_set_bandwidth(state, 18025); + cx24113_set_clk_inversion(state, 1); + + if (state->config->xtal_khz >= 40000) + ret = cx24113_writereg(state, 0x02, + (cx24113_readreg(state, 0x02) & 0xfb) | (1 << 2)); + else + ret = cx24113_writereg(state, 0x02, + (cx24113_readreg(state, 0x02) & 0xfb) | (0 << 2)); + + return ret; +} + +static int cx24113_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct cx24113_state *state = fe->tuner_priv; + /* for a ROLL-OFF factor of 0.35, 0.2: 600, 0.25: 625 */ + u32 roll_off = 675; + u32 bw; + + bw = ((p->u.qpsk.symbol_rate/100) * roll_off) / 1000; + bw += (10000000/100) + 5; + bw /= 10; + bw += 1000; + cx24113_set_bandwidth(state, bw); + + cx24113_set_frequency(state, p->frequency); + msleep(5); + return cx24113_get_status(fe, &bw); +} + +static s8 cx24113_agc_table[2][10] = { + {-54, -41, -35, -30, -25, -21, -16, -10, -6, -2}, + {-39, -35, -30, -25, -19, -15, -11, -5, 1, 9}, +}; + +void cx24113_agc_callback(struct dvb_frontend *fe) +{ + struct cx24113_state *state = fe->tuner_priv; + s16 s, i; + if (!fe->ops.read_signal_strength) + return; + + do { + /* this only works with the current CX24123 implementation */ + fe->ops.read_signal_strength(fe, (u16 *) &s); + s >>= 8; + dprintk("signal strength: %d\n", s); + for (i = 0; i < sizeof(cx24113_agc_table[0]); i++) + if (cx24113_agc_table[state->gain_level][i] > s) + break; + s = -25 - i*5; + } while (cx24113_set_gain_settings(state, s)); +} +EXPORT_SYMBOL(cx24113_agc_callback); + +static int cx24113_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct cx24113_state *state = fe->tuner_priv; + *frequency = state->frequency; + return 0; +} + +static int cx24113_release(struct dvb_frontend *fe) +{ + struct cx24113_state *state = fe->tuner_priv; + dprintk("\n"); + fe->tuner_priv = NULL; + kfree(state); + return 0; +} + +static const struct dvb_tuner_ops cx24113_tuner_ops = { + .info = { + .name = "Conexant CX24113", + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_step = 125, + }, + + .release = cx24113_release, + + .init = cx24113_init, + .sleep = NULL, + + .set_params = cx24113_set_params, + .get_frequency = cx24113_get_frequency, + .get_bandwidth = NULL, + .get_status = cx24113_get_status, +}; + +struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe, + const struct cx24113_config *config, struct i2c_adapter *i2c) +{ + /* allocate memory for the internal state */ + struct cx24113_state *state = + kzalloc(sizeof(struct cx24113_state), GFP_KERNEL); + int rc; + if (state == NULL) { + err("Unable to kmalloc\n"); + goto error; + } + + /* setup the state */ + state->config = config; + state->i2c = i2c; + + info("trying to detect myself\n"); + + /* making a dummy read, because of some expected troubles + * after power on */ + cx24113_readreg(state, 0x00); + + rc = cx24113_readreg(state, 0x00); + if (rc < 0) { + info("CX24113 not found.\n"); + goto error; + } + state->rev = rc; + + switch (rc) { + case 0x43: + info("detected CX24113 variant\n"); + break; + case REV_CX24113: + info("sucessfully detected\n"); + break; + default: + err("unsupported device id: %x\n", state->rev); + goto error; + } + state->ver = cx24113_readreg(state, 0x01); + info("version: %x\n", state->ver); + + /* create dvb_frontend */ + memcpy(&fe->ops.tuner_ops, &cx24113_tuner_ops, + sizeof(struct dvb_tuner_ops)); + fe->tuner_priv = state; + return fe; + +error: + kfree(state); + + return NULL; +} +EXPORT_SYMBOL(cx24113_attach); + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); + +MODULE_AUTHOR("Patrick Boettcher <pb@linuxtv.org>"); +MODULE_DESCRIPTION("DVB Frontend module for Conexant CX24113/CX24128hardware"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/media/dvb/frontends/cx24113.h b/drivers/media/dvb/frontends/cx24113.h index 5ab3dd11076..5de0f7ffd8d 100644 --- a/drivers/media/dvb/frontends/cx24113.h +++ b/drivers/media/dvb/frontends/cx24113.h @@ -16,7 +16,7 @@ * * 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.= + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef CX24113_H @@ -30,9 +30,13 @@ struct cx24113_config { u32 xtal_khz; }; -/* TODO: #if defined(CONFIG_DVB_TUNER_CX24113) || \ - * (defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE)) */ +#if defined(CONFIG_DVB_TUNER_CX24113) || \ + (defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE)) +extern struct dvb_frontend *cx24113_attach(struct dvb_frontend *, + const struct cx24113_config *config, struct i2c_adapter *i2c); +extern void cx24113_agc_callback(struct dvb_frontend *fe); +#else static inline struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe, const struct cx24113_config *config, struct i2c_adapter *i2c) { @@ -44,5 +48,6 @@ static inline void cx24113_agc_callback(struct dvb_frontend *fe) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); } +#endif #endif /* CX24113_H */ diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c index b144b308a4d..9b6c89e93f1 100644 --- a/drivers/media/dvb/frontends/cx24116.c +++ b/drivers/media/dvb/frontends/cx24116.c @@ -106,7 +106,7 @@ MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); #define CX24116_HAS_SYNCLOCK (0x08) #define CX24116_HAS_UNKNOWN1 (0x10) #define CX24116_HAS_UNKNOWN2 (0x20) -#define CX24116_STATUS_MASK (0x3f) +#define CX24116_STATUS_MASK (0x0f) #define CX24116_SIGNAL_MASK (0xc0) #define CX24116_DISEQC_TONEOFF (0) /* toneburst never sent */ @@ -160,6 +160,7 @@ struct cx24116_tuning { fe_spectral_inversion_t inversion; fe_code_rate_t fec; + fe_delivery_system_t delsys; fe_modulation_t modulation; fe_pilot_t pilot; fe_rolloff_t rolloff; @@ -411,14 +412,15 @@ struct cx24116_modfec { }; static int cx24116_lookup_fecmod(struct cx24116_state *state, - fe_modulation_t m, fe_code_rate_t f) + fe_delivery_system_t d, fe_modulation_t m, fe_code_rate_t f) { int i, ret = -EOPNOTSUPP; dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f); for (i = 0; i < ARRAY_SIZE(CX24116_MODFEC_MODES); i++) { - if ((m == CX24116_MODFEC_MODES[i].modulation) && + if ((d == CX24116_MODFEC_MODES[i].delivery_system) && + (m == CX24116_MODFEC_MODES[i].modulation) && (f == CX24116_MODFEC_MODES[i].fec)) { ret = i; break; @@ -429,13 +431,13 @@ static int cx24116_lookup_fecmod(struct cx24116_state *state, } static int cx24116_set_fec(struct cx24116_state *state, - fe_modulation_t mod, fe_code_rate_t fec) + fe_delivery_system_t delsys, fe_modulation_t mod, fe_code_rate_t fec) { int ret = 0; dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec); - ret = cx24116_lookup_fecmod(state, mod, fec); + ret = cx24116_lookup_fecmod(state, delsys, mod, fec); if (ret < 0) return ret; @@ -679,7 +681,8 @@ static int cx24116_read_status(struct dvb_frontend *fe, fe_status_t *status) { struct cx24116_state *state = fe->demodulator_priv; - int lock = cx24116_readreg(state, CX24116_REG_SSTATUS); + int lock = cx24116_readreg(state, CX24116_REG_SSTATUS) & + CX24116_STATUS_MASK; dprintk("%s: status = 0x%02x\n", __func__, lock); @@ -1205,7 +1208,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct cx24116_cmd cmd; fe_status_t tunerstat; - int i, status, ret, retune; + int i, status, ret, retune = 1; dprintk("%s()\n", __func__); @@ -1222,7 +1225,6 @@ static int cx24116_set_frontend(struct dvb_frontend *fe, /* Pilot doesn't exist in DVB-S, turn bit off */ state->dnxt.pilot_val = CX24116_PILOT_OFF; - retune = 1; /* DVB-S only supports 0.35 */ if (c->rolloff != ROLLOFF_35) { @@ -1250,7 +1252,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe, case PILOT_AUTO: /* Not supported but emulated */ state->dnxt.pilot_val = (c->modulation == QPSK) ? CX24116_PILOT_OFF : CX24116_PILOT_ON; - retune = 2; + retune++; break; case PILOT_OFF: state->dnxt.pilot_val = CX24116_PILOT_OFF; @@ -1287,6 +1289,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe, __func__, c->delivery_system); return -EOPNOTSUPP; } + state->dnxt.delsys = c->delivery_system; state->dnxt.modulation = c->modulation; state->dnxt.frequency = c->frequency; state->dnxt.pilot = c->pilot; @@ -1297,7 +1300,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe, return ret; /* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */ - ret = cx24116_set_fec(state, c->modulation, c->fec_inner); + ret = cx24116_set_fec(state, c->delivery_system, c->modulation, c->fec_inner); if (ret != 0) return ret; @@ -1308,6 +1311,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe, /* discard the 'current' tuning parameters and prepare to tune */ cx24116_clone_params(fe); + dprintk("%s: delsys = %d\n", __func__, state->dcur.delsys); dprintk("%s: modulation = %d\n", __func__, state->dcur.modulation); dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency); dprintk("%s: pilot = %d (val = 0x%02x)\n", __func__, @@ -1427,6 +1431,23 @@ tuned: /* Set/Reset B/W */ return ret; } +static int cx24116_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, + unsigned int mode_flags, unsigned int *delay, fe_status_t *status) +{ + *delay = HZ / 5; + if (params) { + int ret = cx24116_set_frontend(fe, params); + if (ret) + return ret; + } + return cx24116_read_status(fe, status); +} + +static int cx24116_get_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_HW; +} + static struct dvb_frontend_ops cx24116_ops = { .info = { @@ -1458,6 +1479,8 @@ static struct dvb_frontend_ops cx24116_ops = { .set_voltage = cx24116_set_voltage, .diseqc_send_master_cmd = cx24116_send_diseqc_msg, .diseqc_send_burst = cx24116_diseqc_send_burst, + .get_frontend_algo = cx24116_get_algo, + .tune = cx24116_tune, .set_property = cx24116_set_property, .get_property = cx24116_get_property, diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h index 3e812685712..aab8112e2db 100644 --- a/drivers/media/dvb/frontends/dib7000p.h +++ b/drivers/media/dvb/frontends/dib7000p.h @@ -66,7 +66,8 @@ struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe, return NULL; } -extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, +static inline +int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]) { @@ -74,13 +75,15 @@ extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, return -ENODEV; } -extern int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) +static inline +int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; } -extern int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value) +static inline +int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c index b9ca5c8d2dd..ec4e08dbc69 100644 --- a/drivers/media/dvb/frontends/drx397xD.c +++ b/drivers/media/dvb/frontends/drx397xD.c @@ -39,7 +39,7 @@ static const char mod_name[] = "drx397xD"; #define F_SET_0D4h 2 enum fw_ix { -#define _FW_ENTRY(a, b) b +#define _FW_ENTRY(a, b, c) b #include "drx397xD_fw.h" }; @@ -72,11 +72,11 @@ static struct { int refcnt; const u8 *data[ARRAY_SIZE(blob_name)]; } fw[] = { -#define _FW_ENTRY(a, b) { \ - .name = a, \ - .file = 0, \ - .lock = RW_LOCK_UNLOCKED, \ - .refcnt = 0, \ +#define _FW_ENTRY(a, b, c) { \ + .name = a, \ + .file = 0, \ + .lock = __RW_LOCK_UNLOCKED(fw[c].lock), \ + .refcnt = 0, \ .data = { } } #include "drx397xD_fw.h" }; diff --git a/drivers/media/dvb/frontends/drx397xD_fw.h b/drivers/media/dvb/frontends/drx397xD_fw.h index 01de02a81cd..c8b44c1e807 100644 --- a/drivers/media/dvb/frontends/drx397xD_fw.h +++ b/drivers/media/dvb/frontends/drx397xD_fw.h @@ -18,8 +18,8 @@ */ #ifdef _FW_ENTRY - _FW_ENTRY("drx397xD.A2.fw", DRXD_FW_A2 = 0 ), - _FW_ENTRY("drx397xD.B1.fw", DRXD_FW_B1 ), + _FW_ENTRY("drx397xD.A2.fw", DRXD_FW_A2 = 0, DRXD_FW_A2 ), + _FW_ENTRY("drx397xD.B1.fw", DRXD_FW_B1, DRXD_FW_B1 ), #undef _FW_ENTRY #endif /* _FW_ENTRY */ diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index ea058153ebf..9f6349964cd 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -311,7 +311,7 @@ static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = { .count = 4, .entries = { { 1250000, 500, 0xc4, 0x00}, - { 1550000, 500, 0xc4, 0x40}, + { 1450000, 500, 0xc4, 0x40}, { 2050000, 500, 0xc4, 0x80}, { 2150000, 500, 0xc4, 0xc0}, }, diff --git a/drivers/media/dvb/frontends/lgdt3304.c b/drivers/media/dvb/frontends/lgdt3304.c new file mode 100644 index 00000000000..469ace5692c --- /dev/null +++ b/drivers/media/dvb/frontends/lgdt3304.c @@ -0,0 +1,378 @@ +/* + * Driver for LG ATSC lgdt3304 driver + * + * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de> + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/delay.h> +#include "dvb_frontend.h" +#include "lgdt3304.h" + +static unsigned int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug,"lgdt3304 debugging (default off)"); + +#define dprintk(fmt, args...) if (debug) do {\ + printk("lgdt3304 debug: " fmt, ##args); } while (0) + +struct lgdt3304_state +{ + struct dvb_frontend frontend; + fe_modulation_t current_modulation; + __u32 snr; + __u32 current_frequency; + __u8 addr; + struct i2c_adapter *i2c; +}; + +static int i2c_write_demod_bytes (struct dvb_frontend *fe, __u8 *buf, int len) +{ + struct lgdt3304_state *state = fe->demodulator_priv; + struct i2c_msg i2cmsgs = { + .addr = state->addr, + .flags = 0, + .len = 3, + .buf = buf + }; + int i; + int err; + + for (i=0; i<len-1; i+=3){ + if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) { + printk("%s i2c_transfer error %d\n", __FUNCTION__, err); + if (err < 0) + return err; + else + return -EREMOTEIO; + } + i2cmsgs.buf += 3; + } + return 0; +} + +static int lgdt3304_i2c_read_reg(struct dvb_frontend *fe, unsigned int reg) +{ + struct lgdt3304_state *state = fe->demodulator_priv; + struct i2c_msg i2cmsgs[2]; + int ret; + __u8 buf; + + __u8 regbuf[2] = { reg>>8, reg&0xff }; + + i2cmsgs[0].addr = state->addr; + i2cmsgs[0].flags = 0; + i2cmsgs[0].len = 2; + i2cmsgs[0].buf = regbuf; + + i2cmsgs[1].addr = state->addr; + i2cmsgs[1].flags = I2C_M_RD; + i2cmsgs[1].len = 1; + i2cmsgs[1].buf = &buf; + + if((ret = i2c_transfer(state->i2c, i2cmsgs, 2))<0) { + printk("%s i2c_transfer error %d\n", __FUNCTION__, ret); + return ret; + } + + return buf; +} + +static int lgdt3304_i2c_write_reg(struct dvb_frontend *fe, int reg, int val) +{ + struct lgdt3304_state *state = fe->demodulator_priv; + char buffer[3] = { reg>>8, reg&0xff, val }; + int ret; + + struct i2c_msg i2cmsgs = { + .addr = state->addr, + .flags = 0, + .len = 3, + .buf=buffer + }; + ret = i2c_transfer(state->i2c, &i2cmsgs, 1); + if (ret != 1) { + printk("%s i2c_transfer error %d\n", __FUNCTION__, ret); + return ret; + } + + return 0; +} + + +static int lgdt3304_soft_Reset(struct dvb_frontend *fe) +{ + lgdt3304_i2c_write_reg(fe, 0x0002, 0x9a); + lgdt3304_i2c_write_reg(fe, 0x0002, 0x9b); + mdelay(200); + return 0; +} + +static int lgdt3304_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) { + int err = 0; + + static __u8 lgdt3304_vsb8_data[] = { + /* 16bit , 8bit */ + /* regs , val */ + 0x00, 0x00, 0x02, + 0x00, 0x00, 0x13, + 0x00, 0x0d, 0x02, + 0x00, 0x0e, 0x02, + 0x00, 0x12, 0x32, + 0x00, 0x13, 0xc4, + 0x01, 0x12, 0x17, + 0x01, 0x13, 0x15, + 0x01, 0x14, 0x18, + 0x01, 0x15, 0xff, + 0x01, 0x16, 0x2c, + 0x02, 0x14, 0x67, + 0x02, 0x24, 0x8d, + 0x04, 0x27, 0x12, + 0x04, 0x28, 0x4f, + 0x03, 0x08, 0x80, + 0x03, 0x09, 0x00, + 0x03, 0x0d, 0x00, + 0x03, 0x0e, 0x1c, + 0x03, 0x14, 0xe1, + 0x05, 0x0e, 0x5b, + }; + + /* not yet tested .. */ + static __u8 lgdt3304_qam64_data[] = { + /* 16bit , 8bit */ + /* regs , val */ + 0x00, 0x00, 0x18, + 0x00, 0x0d, 0x02, + //0x00, 0x0e, 0x02, + 0x00, 0x12, 0x2a, + 0x00, 0x13, 0x00, + 0x03, 0x14, 0xe3, + 0x03, 0x0e, 0x1c, + 0x03, 0x08, 0x66, + 0x03, 0x09, 0x66, + 0x03, 0x0a, 0x08, + 0x03, 0x0b, 0x9b, + 0x05, 0x0e, 0x5b, + }; + + + /* tested with KWorld a340 */ + static __u8 lgdt3304_qam256_data[] = { + /* 16bit , 8bit */ + /* regs , val */ + 0x00, 0x00, 0x01, //0x19, + 0x00, 0x12, 0x2a, + 0x00, 0x13, 0x80, + 0x00, 0x0d, 0x02, + 0x03, 0x14, 0xe3, + + 0x03, 0x0e, 0x1c, + 0x03, 0x08, 0x66, + 0x03, 0x09, 0x66, + 0x03, 0x0a, 0x08, + 0x03, 0x0b, 0x9b, + + 0x03, 0x0d, 0x14, + //0x05, 0x0e, 0x5b, + 0x01, 0x06, 0x4a, + 0x01, 0x07, 0x3d, + 0x01, 0x08, 0x70, + 0x01, 0x09, 0xa3, + + 0x05, 0x04, 0xfd, + + 0x00, 0x0d, 0x82, + + 0x05, 0x0e, 0x5b, + + 0x05, 0x0e, 0x5b, + + 0x00, 0x02, 0x9a, + + 0x00, 0x02, 0x9b, + + 0x00, 0x00, 0x01, + 0x00, 0x12, 0x2a, + 0x00, 0x13, 0x80, + 0x00, 0x0d, 0x02, + 0x03, 0x14, 0xe3, + + 0x03, 0x0e, 0x1c, + 0x03, 0x08, 0x66, + 0x03, 0x09, 0x66, + 0x03, 0x0a, 0x08, + 0x03, 0x0b, 0x9b, + + 0x03, 0x0d, 0x14, + 0x01, 0x06, 0x4a, + 0x01, 0x07, 0x3d, + 0x01, 0x08, 0x70, + 0x01, 0x09, 0xa3, + + 0x05, 0x04, 0xfd, + + 0x00, 0x0d, 0x82, + + 0x05, 0x0e, 0x5b, + }; + + struct lgdt3304_state *state = fe->demodulator_priv; + if (state->current_modulation != param->u.vsb.modulation) { + switch(param->u.vsb.modulation) { + case VSB_8: + err = i2c_write_demod_bytes(fe, lgdt3304_vsb8_data, + sizeof(lgdt3304_vsb8_data)); + break; + case QAM_64: + err = i2c_write_demod_bytes(fe, lgdt3304_qam64_data, + sizeof(lgdt3304_qam64_data)); + break; + case QAM_256: + err = i2c_write_demod_bytes(fe, lgdt3304_qam256_data, + sizeof(lgdt3304_qam256_data)); + break; + default: + break; + } + + if (err) { + printk("%s error setting modulation\n", __FUNCTION__); + } else { + state->current_modulation = param->u.vsb.modulation; + } + } + state->current_frequency = param->frequency; + + lgdt3304_soft_Reset(fe); + + + if (fe->ops.tuner_ops.set_params) + fe->ops.tuner_ops.set_params(fe, param); + + return 0; +} + +static int lgdt3304_init(struct dvb_frontend *fe) { + return 0; +} + +static int lgdt3304_sleep(struct dvb_frontend *fe) { + return 0; +} + + +static int lgdt3304_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct lgdt3304_state *state = fe->demodulator_priv; + int r011d; + int qam_lck; + + *status = 0; + dprintk("lgdt read status\n"); + + r011d = lgdt3304_i2c_read_reg(fe, 0x011d); + + dprintk("%02x\n", r011d); + + switch(state->current_modulation) { + case VSB_8: + if (r011d & 0x80) { + dprintk("VSB Locked\n"); + *status |= FE_HAS_CARRIER; + *status |= FE_HAS_LOCK; + *status |= FE_HAS_SYNC; + *status |= FE_HAS_SIGNAL; + } + break; + case QAM_64: + case QAM_256: + qam_lck = r011d & 0x7; + switch(qam_lck) { + case 0x0: dprintk("Unlock\n"); + break; + case 0x4: dprintk("1st Lock in acquisition state\n"); + break; + case 0x6: dprintk("2nd Lock in acquisition state\n"); + break; + case 0x7: dprintk("Final Lock in good reception state\n"); + *status |= FE_HAS_CARRIER; + *status |= FE_HAS_LOCK; + *status |= FE_HAS_SYNC; + *status |= FE_HAS_SIGNAL; + break; + } + break; + default: + printk("%s unhandled modulation\n", __FUNCTION__); + } + + + return 0; +} + +static int lgdt3304_read_ber(struct dvb_frontend *fe, __u32 *ber) +{ + dprintk("read ber\n"); + return 0; +} + +static int lgdt3304_read_snr(struct dvb_frontend *fe, __u16 *snr) +{ + dprintk("read snr\n"); + return 0; +} + +static int lgdt3304_read_ucblocks(struct dvb_frontend *fe, __u32 *ucblocks) +{ + dprintk("read ucblocks\n"); + return 0; +} + +static void lgdt3304_release(struct dvb_frontend *fe) +{ + struct lgdt3304_state *state = (struct lgdt3304_state *)fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops demod_lgdt3304={ + .info = { + .name = "LG 3304", + .type = FE_ATSC, + .frequency_min = 54000000, + .frequency_max = 858000000, + .frequency_stepsize = 62500, + .symbol_rate_min = 5056941, + .symbol_rate_max = 10762000, + .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + }, + .init = lgdt3304_init, + .sleep = lgdt3304_sleep, + .set_frontend = lgdt3304_set_parameters, + .read_snr = lgdt3304_read_snr, + .read_ber = lgdt3304_read_ber, + .read_status = lgdt3304_read_status, + .read_ucblocks = lgdt3304_read_ucblocks, + .release = lgdt3304_release, +}; + +struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config, + struct i2c_adapter *i2c) +{ + + struct lgdt3304_state *state; + state = kzalloc(sizeof(struct lgdt3304_state), GFP_KERNEL); + memset(state, 0x0, sizeof(struct lgdt3304_state)); + state->addr = config->i2c_address; + state->i2c = i2c; + + memcpy(&state->frontend.ops, &demod_lgdt3304, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; +} + +EXPORT_SYMBOL_GPL(lgdt3304_attach); +MODULE_AUTHOR("Markus Rechberger <mrechberger@empiatech.com>"); +MODULE_DESCRIPTION("LGE LGDT3304 DVB-T demodulator driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/lgdt3304.h b/drivers/media/dvb/frontends/lgdt3304.h new file mode 100644 index 00000000000..fc409fe59ac --- /dev/null +++ b/drivers/media/dvb/frontends/lgdt3304.h @@ -0,0 +1,45 @@ +/* + * Driver for DVB-T lgdt3304 demodulator + * + * Copyright (C) 2008 Markus Rechberger <mrechberger@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +#ifndef LGDT3304_H +#define LGDT3304_H + +#include <linux/dvb/frontend.h> + +struct lgdt3304_config +{ + /* demodulator's I2C address */ + u8 i2c_address; +}; + +#if defined(CONFIG_DVB_LGDT3304) || (defined(CONFIG_DVB_LGDT3304_MODULE) && defined(MODULE)) +extern struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_LGDT */ + +#endif /* LGDT3304_H */ diff --git a/drivers/media/dvb/frontends/s5h1411.c b/drivers/media/dvb/frontends/s5h1411.c index 40644aacffc..66e2dd6d6fe 100644 --- a/drivers/media/dvb/frontends/s5h1411.c +++ b/drivers/media/dvb/frontends/s5h1411.c @@ -874,6 +874,9 @@ struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config, /* Note: Leaving the I2C gate open here. */ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1); + /* Put the device into low-power mode until first use */ + s5h1411_set_powerstate(&state->frontend, 1); + return &state->frontend; error: diff --git a/drivers/media/dvb/frontends/s921_core.c b/drivers/media/dvb/frontends/s921_core.c new file mode 100644 index 00000000000..974b52be9ae --- /dev/null +++ b/drivers/media/dvb/frontends/s921_core.c @@ -0,0 +1,216 @@ +/* + * Driver for Sharp s921 driver + * + * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de> + * + */ + + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/delay.h> +#include "s921_core.h" + +static int s921_isdb_init(struct s921_isdb_t *dev); +static int s921_isdb_set_parameters(struct s921_isdb_t *dev, struct s921_isdb_t_transmission_mode_params *params); +static int s921_isdb_tune(struct s921_isdb_t *dev, struct s921_isdb_t_tune_params *params); +static int s921_isdb_get_status(struct s921_isdb_t *dev, void *data); + +static u8 init_table[]={ 0x01, 0x40, 0x02, 0x00, 0x03, 0x40, 0x04, 0x01, + 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, + 0x09, 0x00, 0x0a, 0x00, 0x0b, 0x5a, 0x0c, 0x00, + 0x0d, 0x00, 0x0f, 0x00, 0x13, 0x1b, 0x14, 0x80, + 0x15, 0x40, 0x17, 0x70, 0x18, 0x01, 0x19, 0x12, + 0x1a, 0x01, 0x1b, 0x12, 0x1c, 0xa0, 0x1d, 0x00, + 0x1e, 0x0a, 0x1f, 0x08, 0x20, 0x40, 0x21, 0xff, + 0x22, 0x4c, 0x23, 0x4e, 0x24, 0x4c, 0x25, 0x00, + 0x26, 0x00, 0x27, 0xf4, 0x28, 0x60, 0x29, 0x88, + 0x2a, 0x40, 0x2b, 0x40, 0x2c, 0xff, 0x2d, 0x00, + 0x2e, 0xff, 0x2f, 0x00, 0x30, 0x20, 0x31, 0x06, + 0x32, 0x0c, 0x34, 0x0f, 0x37, 0xfe, 0x38, 0x00, + 0x39, 0x63, 0x3a, 0x10, 0x3b, 0x10, 0x47, 0x00, + 0x49, 0xe5, 0x4b, 0x00, 0x50, 0xc0, 0x52, 0x20, + 0x54, 0x5a, 0x55, 0x5b, 0x56, 0x40, 0x57, 0x70, + 0x5c, 0x50, 0x5d, 0x00, 0x62, 0x17, 0x63, 0x2f, + 0x64, 0x6f, 0x68, 0x00, 0x69, 0x89, 0x6a, 0x00, + 0x6b, 0x00, 0x6c, 0x00, 0x6d, 0x00, 0x6e, 0x00, + 0x70, 0x00, 0x71, 0x00, 0x75, 0x00, 0x76, 0x30, + 0x77, 0x01, 0xaf, 0x00, 0xb0, 0xa0, 0xb2, 0x3d, + 0xb3, 0x25, 0xb4, 0x8b, 0xb5, 0x4b, 0xb6, 0x3f, + 0xb7, 0xff, 0xb8, 0xff, 0xb9, 0xfc, 0xba, 0x00, + 0xbb, 0x00, 0xbc, 0x00, 0xd0, 0x30, 0xe4, 0x84, + 0xf0, 0x48, 0xf1, 0x19, 0xf2, 0x5a, 0xf3, 0x8e, + 0xf4, 0x2d, 0xf5, 0x07, 0xf6, 0x5a, 0xf7, 0xba, + 0xf8, 0xd7 }; + +static u8 c_table[]={ 0x58, 0x8a, 0x7b, 0x59, 0x8c, 0x7b, 0x5a, 0x8e, 0x5b, + 0x5b, 0x90, 0x5b, 0x5c, 0x92, 0x5b, 0x5d, 0x94, 0x5b, + 0x5e, 0x96, 0x5b, 0x5f, 0x98, 0x3b, 0x60, 0x9a, 0x3b, + 0x61, 0x9c, 0x3b, 0x62, 0x9e, 0x3b, 0x63, 0xa0, 0x3b, + 0x64, 0xa2, 0x1b, 0x65, 0xa4, 0x1b, 0x66, 0xa6, 0x1b, + 0x67, 0xa8, 0x1b, 0x68, 0xaa, 0x1b, 0x69, 0xac, 0x1b, + 0x6a, 0xae, 0x1b, 0x6b, 0xb0, 0x1b, 0x6c, 0xb2, 0x1b, + 0x6d, 0xb4, 0xfb, 0x6e, 0xb6, 0xfb, 0x6f, 0xb8, 0xfb, + 0x70, 0xba, 0xfb, 0x71, 0xbc, 0xdb, 0x72, 0xbe, 0xdb, + 0x73, 0xc0, 0xdb, 0x74, 0xc2, 0xdb, 0x75, 0xc4, 0xdb, + 0x76, 0xc6, 0xdb, 0x77, 0xc8, 0xbb, 0x78, 0xca, 0xbb, + 0x79, 0xcc, 0xbb, 0x7a, 0xce, 0xbb, 0x7b, 0xd0, 0xbb, + 0x7c, 0xd2, 0xbb, 0x7d, 0xd4, 0xbb, 0x7e, 0xd6, 0xbb, + 0x7f, 0xd8, 0xbb, 0x80, 0xda, 0x9b, 0x81, 0xdc, 0x9b, + 0x82, 0xde, 0x9b, 0x83, 0xe0, 0x9b, 0x84, 0xe2, 0x9b, + 0x85, 0xe4, 0x9b, 0x86, 0xe6, 0x9b, 0x87, 0xe8, 0x9b, + 0x88, 0xea, 0x9b, 0x89, 0xec, 0x9b }; + +int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data) { + switch(cmd) { + case ISDB_T_CMD_INIT: + s921_isdb_init(dev); + break; + case ISDB_T_CMD_SET_PARAM: + s921_isdb_set_parameters(dev, data); + break; + case ISDB_T_CMD_TUNE: + s921_isdb_tune(dev, data); + break; + case ISDB_T_CMD_GET_STATUS: + s921_isdb_get_status(dev, data); + break; + default: + printk("unhandled command\n"); + return -EINVAL; + } + return 0; +} + +static int s921_isdb_init(struct s921_isdb_t *dev) { + unsigned int i; + unsigned int ret; + printk("isdb_init\n"); + for (i = 0; i < sizeof(init_table); i+=2) { + ret = dev->i2c_write(dev->priv_dev, init_table[i], init_table[i+1]); + if (ret != 0) { + printk("i2c write failed\n"); + return ret; + } + } + return 0; +} + +static int s921_isdb_set_parameters(struct s921_isdb_t *dev, struct s921_isdb_t_transmission_mode_params *params) { + + int ret; + /* auto is sufficient for now, lateron this should be reflected in an extra interface */ + + + + ret = dev->i2c_write(dev->priv_dev, 0xb0, 0xa0); //mod_b2); + ret = dev->i2c_write(dev->priv_dev, 0xb2, 0x3d); //mod_b2); + + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xb3, 0x25); //mod_b3); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xb4, 0x8b); //mod_b4); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xb5, 0x4b); //mod_b5); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xb6, 0x3f); //mod_b6); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xb7, 0x3f); //mod_b7); + if (ret < 0) + return -EINVAL; + + return E_OK; +} + +static int s921_isdb_tune(struct s921_isdb_t *dev, struct s921_isdb_t_tune_params *params) { + + int ret; + int index; + + index = (params->frequency - 473143000)/6000000; + + if (index > 48) { + return -EINVAL; + } + + dev->i2c_write(dev->priv_dev, 0x47, 0x60); + + ret = dev->i2c_write(dev->priv_dev, 0x68, 0x00); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0x69, 0x89); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf0, 0x48); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf1, 0x19); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf2, c_table[index*3]); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf3, c_table[index*3+1]); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf4, c_table[index*3+2]); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf5, 0xae); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf6, 0xb7); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf7, 0xba); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf8, 0xd7); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0x68, 0x0a); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0x69, 0x09); + if (ret < 0) + return -EINVAL; + + dev->i2c_write(dev->priv_dev, 0x01, 0x40); + return 0; +} + +static int s921_isdb_get_status(struct s921_isdb_t *dev, void *data) { + unsigned int *ret = (unsigned int*)data; + u8 ifagc_dt; + u8 rfagc_dt; + + mdelay(10); + ifagc_dt = dev->i2c_read(dev->priv_dev, 0x81); + rfagc_dt = dev->i2c_read(dev->priv_dev, 0x82); + if (rfagc_dt == 0x40) { + *ret = 1; + } + return 0; +} diff --git a/drivers/media/dvb/frontends/s921_core.h b/drivers/media/dvb/frontends/s921_core.h new file mode 100644 index 00000000000..de2f10a44e7 --- /dev/null +++ b/drivers/media/dvb/frontends/s921_core.h @@ -0,0 +1,114 @@ +#ifndef _S921_CORE_H +#define _S921_CORE_H +//#define u8 unsigned int +//#define u32 unsigned int + + + +//#define EINVAL -1 +#define E_OK 0 + +struct s921_isdb_t { + void *priv_dev; + int (*i2c_write)(void *dev, u8 reg, u8 val); + int (*i2c_read)(void *dev, u8 reg); +}; + +#define ISDB_T_CMD_INIT 0 +#define ISDB_T_CMD_SET_PARAM 1 +#define ISDB_T_CMD_TUNE 2 +#define ISDB_T_CMD_GET_STATUS 3 + +struct s921_isdb_t_tune_params { + u32 frequency; +}; + +struct s921_isdb_t_status { +}; + +struct s921_isdb_t_transmission_mode_params { + u8 mode; + u8 layer_a_mode; +#define ISDB_T_LA_MODE_1 0 +#define ISDB_T_LA_MODE_2 1 +#define ISDB_T_LA_MODE_3 2 + u8 layer_a_carrier_modulation; +#define ISDB_T_LA_CM_DQPSK 0 +#define ISDB_T_LA_CM_QPSK 1 +#define ISDB_T_LA_CM_16QAM 2 +#define ISDB_T_LA_CM_64QAM 3 +#define ISDB_T_LA_CM_NOLAYER 4 + u8 layer_a_code_rate; +#define ISDB_T_LA_CR_1_2 0 +#define ISDB_T_LA_CR_2_3 1 +#define ISDB_T_LA_CR_3_4 2 +#define ISDB_T_LA_CR_5_6 4 +#define ISDB_T_LA_CR_7_8 8 +#define ISDB_T_LA_CR_NOLAYER 16 + u8 layer_a_time_interleave; +#define ISDB_T_LA_TI_0 0 +#define ISDB_T_LA_TI_1 1 +#define ISDB_T_LA_TI_2 2 +#define ISDB_T_LA_TI_4 4 +#define ISDB_T_LA_TI_8 8 +#define ISDB_T_LA_TI_16 16 +#define ISDB_T_LA_TI_32 32 + u8 layer_a_nseg; + + u8 layer_b_mode; +#define ISDB_T_LB_MODE_1 0 +#define ISDB_T_LB_MODE_2 1 +#define ISDB_T_LB_MODE_3 2 + u8 layer_b_carrier_modulation; +#define ISDB_T_LB_CM_DQPSK 0 +#define ISDB_T_LB_CM_QPSK 1 +#define ISDB_T_LB_CM_16QAM 2 +#define ISDB_T_LB_CM_64QAM 3 +#define ISDB_T_LB_CM_NOLAYER 4 + u8 layer_b_code_rate; +#define ISDB_T_LB_CR_1_2 0 +#define ISDB_T_LB_CR_2_3 1 +#define ISDB_T_LB_CR_3_4 2 +#define ISDB_T_LB_CR_5_6 4 +#define ISDB_T_LB_CR_7_8 8 +#define ISDB_T_LB_CR_NOLAYER 16 + u8 layer_b_time_interleave; +#define ISDB_T_LB_TI_0 0 +#define ISDB_T_LB_TI_1 1 +#define ISDB_T_LB_TI_2 2 +#define ISDB_T_LB_TI_4 4 +#define ISDB_T_LB_TI_8 8 +#define ISDB_T_LB_TI_16 16 +#define ISDB_T_LB_TI_32 32 + u8 layer_b_nseg; + + u8 layer_c_mode; +#define ISDB_T_LC_MODE_1 0 +#define ISDB_T_LC_MODE_2 1 +#define ISDB_T_LC_MODE_3 2 + u8 layer_c_carrier_modulation; +#define ISDB_T_LC_CM_DQPSK 0 +#define ISDB_T_LC_CM_QPSK 1 +#define ISDB_T_LC_CM_16QAM 2 +#define ISDB_T_LC_CM_64QAM 3 +#define ISDB_T_LC_CM_NOLAYER 4 + u8 layer_c_code_rate; +#define ISDB_T_LC_CR_1_2 0 +#define ISDB_T_LC_CR_2_3 1 +#define ISDB_T_LC_CR_3_4 2 +#define ISDB_T_LC_CR_5_6 4 +#define ISDB_T_LC_CR_7_8 8 +#define ISDB_T_LC_CR_NOLAYER 16 + u8 layer_c_time_interleave; +#define ISDB_T_LC_TI_0 0 +#define ISDB_T_LC_TI_1 1 +#define ISDB_T_LC_TI_2 2 +#define ISDB_T_LC_TI_4 4 +#define ISDB_T_LC_TI_8 8 +#define ISDB_T_LC_TI_16 16 +#define ISDB_T_LC_TI_32 32 + u8 layer_c_nseg; +}; + +int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data); +#endif diff --git a/drivers/media/dvb/frontends/s921_module.c b/drivers/media/dvb/frontends/s921_module.c new file mode 100644 index 00000000000..3cbb9cb2cf4 --- /dev/null +++ b/drivers/media/dvb/frontends/s921_module.c @@ -0,0 +1,190 @@ +/* + * Driver for Sharp s921 driver + * + * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de> + * + * All rights reserved. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/delay.h> +#include "dvb_frontend.h" +#include "s921_module.h" +#include "s921_core.h" + +static unsigned int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug,"s921 debugging (default off)"); + +#define dprintk(fmt, args...) if (debug) do {\ + printk("s921 debug: " fmt, ##args); } while (0) + +struct s921_state +{ + struct dvb_frontend frontend; + fe_modulation_t current_modulation; + __u32 snr; + __u32 current_frequency; + __u8 addr; + struct s921_isdb_t dev; + struct i2c_adapter *i2c; +}; + +static int s921_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) { + struct s921_state *state = (struct s921_state *)fe->demodulator_priv; + struct s921_isdb_t_transmission_mode_params params; + struct s921_isdb_t_tune_params tune_params; + + tune_params.frequency = param->frequency; + s921_isdb_cmd(&state->dev, ISDB_T_CMD_SET_PARAM, ¶ms); + s921_isdb_cmd(&state->dev, ISDB_T_CMD_TUNE, &tune_params); + mdelay(100); + return 0; +} + +static int s921_init(struct dvb_frontend *fe) { + printk("s921 init\n"); + return 0; +} + +static int s921_sleep(struct dvb_frontend *fe) { + printk("s921 sleep\n"); + return 0; +} + +static int s921_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct s921_state *state = (struct s921_state *)fe->demodulator_priv; + unsigned int ret; + mdelay(5); + s921_isdb_cmd(&state->dev, ISDB_T_CMD_GET_STATUS, &ret); + *status = 0; + + printk("status: %02x\n", ret); + if (ret == 1) { + *status |= FE_HAS_CARRIER; + *status |= FE_HAS_VITERBI; + *status |= FE_HAS_LOCK; + *status |= FE_HAS_SYNC; + *status |= FE_HAS_SIGNAL; + } + + return 0; +} + +static int s921_read_ber(struct dvb_frontend *fe, __u32 *ber) +{ + dprintk("read ber\n"); + return 0; +} + +static int s921_read_snr(struct dvb_frontend *fe, __u16 *snr) +{ + dprintk("read snr\n"); + return 0; +} + +static int s921_read_ucblocks(struct dvb_frontend *fe, __u32 *ucblocks) +{ + dprintk("read ucblocks\n"); + return 0; +} + +static void s921_release(struct dvb_frontend *fe) +{ + struct s921_state *state = (struct s921_state *)fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops demod_s921={ + .info = { + .name = "SHARP S921", + .type = FE_OFDM, + .frequency_min = 473143000, + .frequency_max = 767143000, + .frequency_stepsize = 6000000, + .frequency_tolerance = 0, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | + FE_CAN_MUTE_TS + }, + .init = s921_init, + .sleep = s921_sleep, + .set_frontend = s921_set_parameters, + .read_snr = s921_read_snr, + .read_ber = s921_read_ber, + .read_status = s921_read_status, + .read_ucblocks = s921_read_ucblocks, + .release = s921_release, +}; + +static int s921_write(void *dev, u8 reg, u8 val) { + struct s921_state *state = dev; + char buf[2]={reg,val}; + int err; + struct i2c_msg i2cmsgs = { + .addr = state->addr, + .flags = 0, + .len = 2, + .buf = buf + }; + + if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) { + printk("%s i2c_transfer error %d\n", __FUNCTION__, err); + if (err < 0) + return err; + else + return -EREMOTEIO; + } + + return 0; +} + +static int s921_read(void *dev, u8 reg) { + struct s921_state *state = dev; + u8 b1; + int ret; + struct i2c_msg msg[2] = { { .addr = state->addr, + .flags = 0, + .buf = ®, .len = 1 }, + { .addr = state->addr, + .flags = I2C_M_RD, + .buf = &b1, .len = 1 } }; + + ret = i2c_transfer(state->i2c, msg, 2); + if (ret != 2) + return ret; + return b1; +} + +struct dvb_frontend* s921_attach(const struct s921_config *config, + struct i2c_adapter *i2c) +{ + + struct s921_state *state; + state = kzalloc(sizeof(struct s921_state), GFP_KERNEL); + memset(state, 0x0, sizeof(struct s921_state)); + + state->addr = config->i2c_address; + state->i2c = i2c; + state->dev.i2c_write = &s921_write; + state->dev.i2c_read = &s921_read; + state->dev.priv_dev = state; + + s921_isdb_cmd(&state->dev, ISDB_T_CMD_INIT, NULL); + + memcpy(&state->frontend.ops, &demod_s921, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; +} + +EXPORT_SYMBOL_GPL(s921_attach); +MODULE_AUTHOR("Markus Rechberger <mrechberger@empiatech.com>"); +MODULE_DESCRIPTION("Sharp S921 ISDB-T 1Seg"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/s921_module.h b/drivers/media/dvb/frontends/s921_module.h new file mode 100644 index 00000000000..78660424ba9 --- /dev/null +++ b/drivers/media/dvb/frontends/s921_module.h @@ -0,0 +1,49 @@ +/* + * Driver for DVB-T s921 demodulator + * + * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +#ifndef S921_MODULE_H +#define S921_MODULE_H + +#include <linux/dvb/frontend.h> +#include "s921_core.h" + +int s921_isdb_init(struct s921_isdb_t *dev); +int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data); + +struct s921_config +{ + /* demodulator's I2C address */ + u8 i2c_address; +}; + +#if defined(CONFIG_DVB_S921) || (defined(CONFIG_DVB_S921_MODULE) && defined(MODULE)) +extern struct dvb_frontend* s921_attach(const struct s921_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend* s921_attach(const struct s921_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_S921 */ + +#endif /* S921_H */ diff --git a/drivers/media/dvb/frontends/si21xx.c b/drivers/media/dvb/frontends/si21xx.c index 3ddbe69c45c..0bd16af8a6c 100644 --- a/drivers/media/dvb/frontends/si21xx.c +++ b/drivers/media/dvb/frontends/si21xx.c @@ -8,7 +8,6 @@ * (at your option) any later version. * */ -#include <linux/version.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/media/dvb/frontends/stb0899_algo.c b/drivers/media/dvb/frontends/stb0899_algo.c new file mode 100644 index 00000000000..ced9b7ae7d5 --- /dev/null +++ b/drivers/media/dvb/frontends/stb0899_algo.c @@ -0,0 +1,1519 @@ +/* + STB0899 Multistandard Frontend driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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 "stb0899_drv.h" +#include "stb0899_priv.h" +#include "stb0899_reg.h" + +inline u32 stb0899_do_div(u64 n, u32 d) +{ + /* wrap do_div() for ease of use */ + + do_div(n, d); + return n; +} + +/* + * stb0899_calc_srate + * Compute symbol rate + */ +static u32 stb0899_calc_srate(u32 master_clk, u8 *sfr) +{ + u64 tmp; + + /* srate = (SFR * master_clk) >> 20 */ + + /* sfr is of size 20 bit, stored with an offset of 4 bit */ + tmp = (((u32)sfr[0]) << 16) | (((u32)sfr[1]) << 8) | sfr[2]; + tmp &= ~0xf; + tmp *= master_clk; + tmp >>= 24; + + return tmp; +} + +/* + * stb0899_get_srate + * Get the current symbol rate + */ +u32 stb0899_get_srate(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + u8 sfr[3]; + + stb0899_read_regs(state, STB0899_SFRH, sfr, 3); + + return stb0899_calc_srate(internal->master_clk, sfr); +} + +/* + * stb0899_set_srate + * Set symbol frequency + * MasterClock: master clock frequency (hz) + * SymbolRate: symbol rate (bauds) + * return symbol frequency + */ +static u32 stb0899_set_srate(struct stb0899_state *state, u32 master_clk, u32 srate) +{ + u32 tmp; + u8 sfr[3]; + + dprintk(state->verbose, FE_DEBUG, 1, "-->"); + /* + * in order to have the maximum precision, the symbol rate entered into + * the chip is computed as the closest value of the "true value". + * In this purpose, the symbol rate value is rounded (1 is added on the bit + * below the LSB ) + * + * srate = (SFR * master_clk) >> 20 + * <=> + * SFR = srate << 20 / master_clk + * + * rounded: + * SFR = (srate << 21 + master_clk) / (2 * master_clk) + * + * stored as 20 bit number with an offset of 4 bit: + * sfr = SFR << 4; + */ + + tmp = stb0899_do_div((((u64)srate) << 21) + master_clk, 2 * master_clk); + tmp <<= 4; + + sfr[0] = tmp >> 16; + sfr[1] = tmp >> 8; + sfr[2] = tmp; + + stb0899_write_regs(state, STB0899_SFRH, sfr, 3); + + return srate; +} + +/* + * stb0899_calc_derot_time + * Compute the amount of time needed by the derotator to lock + * SymbolRate: Symbol rate + * return: derotator time constant (ms) + */ +static long stb0899_calc_derot_time(long srate) +{ + if (srate > 0) + return (100000 / (srate / 1000)); + else + return 0; +} + +/* + * stb0899_carr_width + * Compute the width of the carrier + * return: width of carrier (kHz or Mhz) + */ +long stb0899_carr_width(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + + return (internal->srate + (internal->srate * internal->rolloff) / 100); +} + +/* + * stb0899_first_subrange + * Compute the first subrange of the search + */ +static void stb0899_first_subrange(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_params *params = &state->params; + struct stb0899_config *config = state->config; + + int range = 0; + u32 bandwidth = 0; + + if (config->tuner_get_bandwidth) { + stb0899_i2c_gate_ctrl(&state->frontend, 1); + config->tuner_get_bandwidth(&state->frontend, &bandwidth); + stb0899_i2c_gate_ctrl(&state->frontend, 0); + range = bandwidth - stb0899_carr_width(state) / 2; + } + + if (range > 0) + internal->sub_range = MIN(internal->srch_range, range); + else + internal->sub_range = 0; + + internal->freq = params->freq; + internal->tuner_offst = 0L; + internal->sub_dir = 1; +} + +/* + * stb0899_check_tmg + * check for timing lock + * internal.Ttiming: time to wait for loop lock + */ +static enum stb0899_status stb0899_check_tmg(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + int lock; + u8 reg; + s8 timing; + + msleep(internal->t_derot); + + stb0899_write_reg(state, STB0899_RTF, 0xf2); + reg = stb0899_read_reg(state, STB0899_TLIR); + lock = STB0899_GETFIELD(TLIR_TMG_LOCK_IND, reg); + timing = stb0899_read_reg(state, STB0899_RTF); + + if (lock >= 42) { + if ((lock > 48) && (ABS(timing) >= 110)) { + internal->status = ANALOGCARRIER; + dprintk(state->verbose, FE_DEBUG, 1, "-->ANALOG Carrier !"); + } else { + internal->status = TIMINGOK; + dprintk(state->verbose, FE_DEBUG, 1, "------->TIMING OK !"); + } + } else { + internal->status = NOTIMING; + dprintk(state->verbose, FE_DEBUG, 1, "-->NO TIMING !"); + } + return internal->status; +} + +/* + * stb0899_search_tmg + * perform a fs/2 zig-zag to find timing + */ +static enum stb0899_status stb0899_search_tmg(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_params *params = &state->params; + + short int derot_step, derot_freq = 0, derot_limit, next_loop = 3; + int index = 0; + u8 cfr[2]; + + internal->status = NOTIMING; + + /* timing loop computation & symbol rate optimisation */ + derot_limit = (internal->sub_range / 2L) / internal->mclk; + derot_step = (params->srate / 2L) / internal->mclk; + + while ((stb0899_check_tmg(state) != TIMINGOK) && next_loop) { + index++; + derot_freq += index * internal->direction * derot_step; /* next derot zig zag position */ + + if (ABS(derot_freq) > derot_limit) + next_loop--; + + if (next_loop) { + STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq)); + STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq)); + stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */ + } + internal->direction = -internal->direction; /* Change zigzag direction */ + } + + if (internal->status == TIMINGOK) { + stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */ + internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]); + dprintk(state->verbose, FE_DEBUG, 1, "------->TIMING OK ! Derot Freq = %d", internal->derot_freq); + } + + return internal->status; +} + +/* + * stb0899_check_carrier + * Check for carrier found + */ +static enum stb0899_status stb0899_check_carrier(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + u8 reg; + + msleep(internal->t_derot); /* wait for derotator ok */ + + reg = stb0899_read_reg(state, STB0899_CFD); + STB0899_SETFIELD_VAL(CFD_ON, reg, 1); + stb0899_write_reg(state, STB0899_CFD, reg); + + reg = stb0899_read_reg(state, STB0899_DSTATUS); + dprintk(state->verbose, FE_DEBUG, 1, "--------------------> STB0899_DSTATUS=[0x%02x]", reg); + if (STB0899_GETFIELD(CARRIER_FOUND, reg)) { + internal->status = CARRIEROK; + dprintk(state->verbose, FE_DEBUG, 1, "-------------> CARRIEROK !"); + } else { + internal->status = NOCARRIER; + dprintk(state->verbose, FE_DEBUG, 1, "-------------> NOCARRIER !"); + } + + return internal->status; +} + +/* + * stb0899_search_carrier + * Search for a QPSK carrier with the derotator + */ +static enum stb0899_status stb0899_search_carrier(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + + short int derot_freq = 0, last_derot_freq = 0, derot_limit, next_loop = 3; + int index = 0; + u8 cfr[2]; + u8 reg; + + internal->status = NOCARRIER; + derot_limit = (internal->sub_range / 2L) / internal->mclk; + derot_freq = internal->derot_freq; + + reg = stb0899_read_reg(state, STB0899_CFD); + STB0899_SETFIELD_VAL(CFD_ON, reg, 1); + stb0899_write_reg(state, STB0899_CFD, reg); + + do { + dprintk(state->verbose, FE_DEBUG, 1, "Derot Freq=%d, mclk=%d", derot_freq, internal->mclk); + if (stb0899_check_carrier(state) == NOCARRIER) { + index++; + last_derot_freq = derot_freq; + derot_freq += index * internal->direction * internal->derot_step; /* next zig zag derotator position */ + + if(ABS(derot_freq) > derot_limit) + next_loop--; + + if (next_loop) { + reg = stb0899_read_reg(state, STB0899_CFD); + STB0899_SETFIELD_VAL(CFD_ON, reg, 1); + stb0899_write_reg(state, STB0899_CFD, reg); + + STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq)); + STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq)); + stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */ + } + } + + internal->direction = -internal->direction; /* Change zigzag direction */ + } while ((internal->status != CARRIEROK) && next_loop); + + if (internal->status == CARRIEROK) { + stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */ + internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]); + dprintk(state->verbose, FE_DEBUG, 1, "----> CARRIER OK !, Derot Freq=%d", internal->derot_freq); + } else { + internal->derot_freq = last_derot_freq; + } + + return internal->status; +} + +/* + * stb0899_check_data + * Check for data found + */ +static enum stb0899_status stb0899_check_data(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_params *params = &state->params; + + int lock = 0, index = 0, dataTime = 500, loop; + u8 reg; + + internal->status = NODATA; + + /* RESET FEC */ + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESACS, reg, 1); + stb0899_write_reg(state, STB0899_TSTRES, reg); + msleep(1); + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESACS, reg, 0); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + if (params->srate <= 2000000) + dataTime = 2000; + else if (params->srate <= 5000000) + dataTime = 1500; + else if (params->srate <= 15000000) + dataTime = 1000; + else + dataTime = 500; + + stb0899_write_reg(state, STB0899_DSTATUS2, 0x00); /* force search loop */ + while (1) { + /* WARNING! VIT LOCKED has to be tested before VIT_END_LOOOP */ + reg = stb0899_read_reg(state, STB0899_VSTATUS); + lock = STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg); + loop = STB0899_GETFIELD(VSTATUS_END_LOOPVIT, reg); + + if (lock || loop || (index > dataTime)) + break; + index++; + } + + if (lock) { /* DATA LOCK indicator */ + internal->status = DATAOK; + dprintk(state->verbose, FE_DEBUG, 1, "-----------------> DATA OK !"); + } + + return internal->status; +} + +/* + * stb0899_search_data + * Search for a QPSK carrier with the derotator + */ +static enum stb0899_status stb0899_search_data(struct stb0899_state *state) +{ + short int derot_freq, derot_step, derot_limit, next_loop = 3; + u8 cfr[2]; + u8 reg; + int index = 1; + + struct stb0899_internal *internal = &state->internal; + struct stb0899_params *params = &state->params; + + derot_step = (params->srate / 4L) / internal->mclk; + derot_limit = (internal->sub_range / 2L) / internal->mclk; + derot_freq = internal->derot_freq; + + do { + if ((internal->status != CARRIEROK) || (stb0899_check_data(state) != DATAOK)) { + + derot_freq += index * internal->direction * derot_step; /* next zig zag derotator position */ + if (ABS(derot_freq) > derot_limit) + next_loop--; + + if (next_loop) { + dprintk(state->verbose, FE_DEBUG, 1, "Derot freq=%d, mclk=%d", derot_freq, internal->mclk); + reg = stb0899_read_reg(state, STB0899_CFD); + STB0899_SETFIELD_VAL(CFD_ON, reg, 1); + stb0899_write_reg(state, STB0899_CFD, reg); + + STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq)); + STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq)); + stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */ + + stb0899_check_carrier(state); + index++; + } + } + internal->direction = -internal->direction; /* change zig zag direction */ + } while ((internal->status != DATAOK) && next_loop); + + if (internal->status == DATAOK) { + stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */ + internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]); + dprintk(state->verbose, FE_DEBUG, 1, "------> DATAOK ! Derot Freq=%d", internal->derot_freq); + } + + return internal->status; +} + +/* + * stb0899_check_range + * check if the found frequency is in the correct range + */ +static enum stb0899_status stb0899_check_range(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_params *params = &state->params; + + int range_offst, tp_freq; + + range_offst = internal->srch_range / 2000; + tp_freq = internal->freq + (internal->derot_freq * internal->mclk) / 1000; + + if ((tp_freq >= params->freq - range_offst) && (tp_freq <= params->freq + range_offst)) { + internal->status = RANGEOK; + dprintk(state->verbose, FE_DEBUG, 1, "----> RANGEOK !"); + } else { + internal->status = OUTOFRANGE; + dprintk(state->verbose, FE_DEBUG, 1, "----> OUT OF RANGE !"); + } + + return internal->status; +} + +/* + * NextSubRange + * Compute the next subrange of the search + */ +static void next_sub_range(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_params *params = &state->params; + + long old_sub_range; + + if (internal->sub_dir > 0) { + old_sub_range = internal->sub_range; + internal->sub_range = MIN((internal->srch_range / 2) - + (internal->tuner_offst + internal->sub_range / 2), + internal->sub_range); + + if (internal->sub_range < 0) + internal->sub_range = 0; + + internal->tuner_offst += (old_sub_range + internal->sub_range) / 2; + } + + internal->freq = params->freq + (internal->sub_dir * internal->tuner_offst) / 1000; + internal->sub_dir = -internal->sub_dir; +} + +/* + * stb0899_dvbs_algo + * Search for a signal, timing, carrier and data for a + * given frequency in a given range + */ +enum stb0899_status stb0899_dvbs_algo(struct stb0899_state *state) +{ + struct stb0899_params *params = &state->params; + struct stb0899_internal *internal = &state->internal; + struct stb0899_config *config = state->config; + + u8 bclc, reg; + u8 cfr[2]; + u8 eq_const[10]; + s32 clnI = 3; + u32 bandwidth = 0; + + /* BETA values rated @ 99MHz */ + s32 betaTab[5][4] = { + /* 5 10 20 30MBps */ + { 37, 34, 32, 31 }, /* QPSK 1/2 */ + { 37, 35, 33, 31 }, /* QPSK 2/3 */ + { 37, 35, 33, 31 }, /* QPSK 3/4 */ + { 37, 36, 33, 32 }, /* QPSK 5/6 */ + { 37, 36, 33, 32 } /* QPSK 7/8 */ + }; + + internal->direction = 1; + + stb0899_set_srate(state, internal->master_clk, params->srate); + /* Carrier loop optimization versus symbol rate for acquisition*/ + if (params->srate <= 5000000) { + stb0899_write_reg(state, STB0899_ACLC, 0x89); + bclc = stb0899_read_reg(state, STB0899_BCLC); + STB0899_SETFIELD_VAL(BETA, bclc, 0x1c); + stb0899_write_reg(state, STB0899_BCLC, bclc); + clnI = 0; + } else if (params->srate <= 15000000) { + stb0899_write_reg(state, STB0899_ACLC, 0xc9); + bclc = stb0899_read_reg(state, STB0899_BCLC); + STB0899_SETFIELD_VAL(BETA, bclc, 0x22); + stb0899_write_reg(state, STB0899_BCLC, bclc); + clnI = 1; + } else if(params->srate <= 25000000) { + stb0899_write_reg(state, STB0899_ACLC, 0x89); + bclc = stb0899_read_reg(state, STB0899_BCLC); + STB0899_SETFIELD_VAL(BETA, bclc, 0x27); + stb0899_write_reg(state, STB0899_BCLC, bclc); + clnI = 2; + } else { + stb0899_write_reg(state, STB0899_ACLC, 0xc8); + bclc = stb0899_read_reg(state, STB0899_BCLC); + STB0899_SETFIELD_VAL(BETA, bclc, 0x29); + stb0899_write_reg(state, STB0899_BCLC, bclc); + clnI = 3; + } + + dprintk(state->verbose, FE_DEBUG, 1, "Set the timing loop to acquisition"); + /* Set the timing loop to acquisition */ + stb0899_write_reg(state, STB0899_RTC, 0x46); + stb0899_write_reg(state, STB0899_CFD, 0xee); + + /* !! WARNING !! + * Do not read any status variables while acquisition, + * If any needed, read before the acquisition starts + * querying status while acquiring causes the + * acquisition to go bad and hence no locks. + */ + dprintk(state->verbose, FE_DEBUG, 1, "Derot Percent=%d Srate=%d mclk=%d", + internal->derot_percent, params->srate, internal->mclk); + + /* Initial calculations */ + internal->derot_step = internal->derot_percent * (params->srate / 1000L) / internal->mclk; /* DerotStep/1000 * Fsymbol */ + internal->t_derot = stb0899_calc_derot_time(params->srate); + internal->t_data = 500; + + dprintk(state->verbose, FE_DEBUG, 1, "RESET stream merger"); + /* RESET Stream merger */ + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESRS, reg, 1); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + /* + * Set KDIVIDER to an intermediate value between + * 1/2 and 7/8 for acquisition + */ + reg = stb0899_read_reg(state, STB0899_DEMAPVIT); + STB0899_SETFIELD_VAL(DEMAPVIT_KDIVIDER, reg, 60); + stb0899_write_reg(state, STB0899_DEMAPVIT, reg); + + stb0899_write_reg(state, STB0899_EQON, 0x01); /* Equalizer OFF while acquiring */ + stb0899_write_reg(state, STB0899_VITSYNC, 0x19); + + stb0899_first_subrange(state); + do { + /* Initialisations */ + cfr[0] = cfr[1] = 0; + stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* RESET derotator frequency */ + + stb0899_write_reg(state, STB0899_RTF, 0); + reg = stb0899_read_reg(state, STB0899_CFD); + STB0899_SETFIELD_VAL(CFD_ON, reg, 1); + stb0899_write_reg(state, STB0899_CFD, reg); + + internal->derot_freq = 0; + internal->status = NOAGC1; + + /* enable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 1); + + /* Move tuner to frequency */ + dprintk(state->verbose, FE_DEBUG, 1, "Tuner set frequency"); + if (state->config->tuner_set_frequency) + state->config->tuner_set_frequency(&state->frontend, internal->freq); + + if (state->config->tuner_get_frequency) + state->config->tuner_get_frequency(&state->frontend, &internal->freq); + + msleep(internal->t_agc1 + internal->t_agc2 + internal->t_derot); /* AGC1, AGC2 and timing loop */ + dprintk(state->verbose, FE_DEBUG, 1, "current derot freq=%d", internal->derot_freq); + internal->status = AGC1OK; + + /* There is signal in the band */ + if (config->tuner_get_bandwidth) + config->tuner_get_bandwidth(&state->frontend, &bandwidth); + + /* disable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 0); + + if (params->srate <= bandwidth / 2) + stb0899_search_tmg(state); /* For low rates (SCPC) */ + else + stb0899_check_tmg(state); /* For high rates (MCPC) */ + + if (internal->status == TIMINGOK) { + dprintk(state->verbose, FE_DEBUG, 1, + "TIMING OK ! Derot freq=%d, mclk=%d", + internal->derot_freq, internal->mclk); + + if (stb0899_search_carrier(state) == CARRIEROK) { /* Search for carrier */ + dprintk(state->verbose, FE_DEBUG, 1, + "CARRIER OK ! Derot freq=%d, mclk=%d", + internal->derot_freq, internal->mclk); + + if (stb0899_search_data(state) == DATAOK) { /* Check for data */ + dprintk(state->verbose, FE_DEBUG, 1, + "DATA OK ! Derot freq=%d, mclk=%d", + internal->derot_freq, internal->mclk); + + if (stb0899_check_range(state) == RANGEOK) { + dprintk(state->verbose, FE_DEBUG, 1, + "RANGE OK ! derot freq=%d, mclk=%d", + internal->derot_freq, internal->mclk); + + internal->freq = params->freq + ((internal->derot_freq * internal->mclk) / 1000); + reg = stb0899_read_reg(state, STB0899_PLPARM); + internal->fecrate = STB0899_GETFIELD(VITCURPUN, reg); + dprintk(state->verbose, FE_DEBUG, 1, + "freq=%d, internal resultant freq=%d", + params->freq, internal->freq); + + dprintk(state->verbose, FE_DEBUG, 1, + "internal puncture rate=%d", + internal->fecrate); + } + } + } + } + if (internal->status != RANGEOK) + next_sub_range(state); + + } while (internal->sub_range && internal->status != RANGEOK); + + /* Set the timing loop to tracking */ + stb0899_write_reg(state, STB0899_RTC, 0x33); + stb0899_write_reg(state, STB0899_CFD, 0xf7); + /* if locked and range ok, set Kdiv */ + if (internal->status == RANGEOK) { + dprintk(state->verbose, FE_DEBUG, 1, "Locked & Range OK !"); + stb0899_write_reg(state, STB0899_EQON, 0x41); /* Equalizer OFF while acquiring */ + stb0899_write_reg(state, STB0899_VITSYNC, 0x39); /* SN to b'11 for acquisition */ + + /* + * Carrier loop optimization versus + * symbol Rate/Puncture Rate for Tracking + */ + reg = stb0899_read_reg(state, STB0899_BCLC); + switch (internal->fecrate) { + case STB0899_FEC_1_2: /* 13 */ + stb0899_write_reg(state, STB0899_DEMAPVIT, 0x1a); + STB0899_SETFIELD_VAL(BETA, reg, betaTab[0][clnI]); + stb0899_write_reg(state, STB0899_BCLC, reg); + break; + case STB0899_FEC_2_3: /* 18 */ + stb0899_write_reg(state, STB0899_DEMAPVIT, 44); + STB0899_SETFIELD_VAL(BETA, reg, betaTab[1][clnI]); + stb0899_write_reg(state, STB0899_BCLC, reg); + break; + case STB0899_FEC_3_4: /* 21 */ + stb0899_write_reg(state, STB0899_DEMAPVIT, 60); + STB0899_SETFIELD_VAL(BETA, reg, betaTab[2][clnI]); + stb0899_write_reg(state, STB0899_BCLC, reg); + break; + case STB0899_FEC_5_6: /* 24 */ + stb0899_write_reg(state, STB0899_DEMAPVIT, 75); + STB0899_SETFIELD_VAL(BETA, reg, betaTab[3][clnI]); + stb0899_write_reg(state, STB0899_BCLC, reg); + break; + case STB0899_FEC_6_7: /* 25 */ + stb0899_write_reg(state, STB0899_DEMAPVIT, 88); + stb0899_write_reg(state, STB0899_ACLC, 0x88); + stb0899_write_reg(state, STB0899_BCLC, 0x9a); + break; + case STB0899_FEC_7_8: /* 26 */ + stb0899_write_reg(state, STB0899_DEMAPVIT, 94); + STB0899_SETFIELD_VAL(BETA, reg, betaTab[4][clnI]); + stb0899_write_reg(state, STB0899_BCLC, reg); + break; + default: + dprintk(state->verbose, FE_DEBUG, 1, "Unsupported Puncture Rate"); + break; + } + /* release stream merger RESET */ + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESRS, reg, 0); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + /* disable carrier detector */ + reg = stb0899_read_reg(state, STB0899_CFD); + STB0899_SETFIELD_VAL(CFD_ON, reg, 0); + stb0899_write_reg(state, STB0899_CFD, reg); + + stb0899_read_regs(state, STB0899_EQUAI1, eq_const, 10); + } + + return internal->status; +} + +/* + * stb0899_dvbs2_config_uwp + * Configure UWP state machine + */ +static void stb0899_dvbs2_config_uwp(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_config *config = state->config; + u32 uwp1, uwp2, uwp3, reg; + + uwp1 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL1); + uwp2 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL2); + uwp3 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL3); + + STB0899_SETFIELD_VAL(UWP_ESN0_AVE, uwp1, config->esno_ave); + STB0899_SETFIELD_VAL(UWP_ESN0_QUANT, uwp1, config->esno_quant); + STB0899_SETFIELD_VAL(UWP_TH_SOF, uwp1, config->uwp_threshold_sof); + + STB0899_SETFIELD_VAL(FE_COARSE_TRK, uwp2, internal->av_frame_coarse); + STB0899_SETFIELD_VAL(FE_FINE_TRK, uwp2, internal->av_frame_fine); + STB0899_SETFIELD_VAL(UWP_MISS_TH, uwp2, config->miss_threshold); + + STB0899_SETFIELD_VAL(UWP_TH_ACQ, uwp3, config->uwp_threshold_acq); + STB0899_SETFIELD_VAL(UWP_TH_TRACK, uwp3, config->uwp_threshold_track); + + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL1, STB0899_OFF0_UWP_CNTRL1, uwp1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL2, STB0899_OFF0_UWP_CNTRL2, uwp2); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL3, STB0899_OFF0_UWP_CNTRL3, uwp3); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, SOF_SRCH_TO); + STB0899_SETFIELD_VAL(SOF_SEARCH_TIMEOUT, reg, config->sof_search_timeout); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_SOF_SRCH_TO, STB0899_OFF0_SOF_SRCH_TO, reg); +} + +/* + * stb0899_dvbs2_config_csm_auto + * Set CSM to AUTO mode + */ +static void stb0899_dvbs2_config_csm_auto(struct stb0899_state *state) +{ + u32 reg; + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1); + STB0899_SETFIELD_VAL(CSM_AUTO_PARAM, reg, 1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, reg); +} + +long Log2Int(int number) +{ + int i; + + i = 0; + while ((1 << i) <= ABS(number)) + i++; + + if (number == 0) + i = 1; + + return i - 1; +} + +/* + * stb0899_dvbs2_calc_srate + * compute BTR_NOM_FREQ for the symbol rate + */ +static u32 stb0899_dvbs2_calc_srate(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_config *config = state->config; + + u32 dec_ratio, dec_rate, decim, remain, intval, btr_nom_freq; + u32 master_clk, srate; + + dec_ratio = (internal->master_clk * 2) / (5 * internal->srate); + dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio; + dec_rate = Log2Int(dec_ratio); + decim = 1 << dec_rate; + master_clk = internal->master_clk / 1000; + srate = internal->srate / 1000; + + if (decim <= 4) { + intval = (decim * (1 << (config->btr_nco_bits - 1))) / master_clk; + remain = (decim * (1 << (config->btr_nco_bits - 1))) % master_clk; + } else { + intval = (1 << (config->btr_nco_bits - 1)) / (master_clk / 100) * decim / 100; + remain = (decim * (1 << (config->btr_nco_bits - 1))) % master_clk; + } + btr_nom_freq = (intval * srate) + ((remain * srate) / master_clk); + + return btr_nom_freq; +} + +/* + * stb0899_dvbs2_calc_dev + * compute the correction to be applied to symbol rate + */ +static u32 stb0899_dvbs2_calc_dev(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + u32 dec_ratio, correction, master_clk, srate; + + dec_ratio = (internal->master_clk * 2) / (5 * internal->srate); + dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio; + + master_clk = internal->master_clk / 1000; /* for integer Caculation*/ + srate = internal->srate / 1000; /* for integer Caculation*/ + correction = (512 * master_clk) / (2 * dec_ratio * srate); + + return correction; +} + +/* + * stb0899_dvbs2_set_srate + * Set DVBS2 symbol rate + */ +static void stb0899_dvbs2_set_srate(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + + u32 dec_ratio, dec_rate, win_sel, decim, f_sym, btr_nom_freq; + u32 correction, freq_adj, band_lim, decim_cntrl, reg; + u8 anti_alias; + + /*set decimation to 1*/ + dec_ratio = (internal->master_clk * 2) / (5 * internal->srate); + dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio; + dec_rate = Log2Int(dec_ratio); + + win_sel = 0; + if (dec_rate >= 5) + win_sel = dec_rate - 4; + + decim = (1 << dec_rate); + /* (FSamp/Fsymbol *100) for integer Caculation */ + f_sym = internal->master_clk / ((decim * internal->srate) / 1000); + + if (f_sym <= 2250) /* don't band limit signal going into btr block*/ + band_lim = 1; + else + band_lim = 0; /* band limit signal going into btr block*/ + + decim_cntrl = ((win_sel << 3) & 0x18) + ((band_lim << 5) & 0x20) + (dec_rate & 0x7); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DECIM_CNTRL, STB0899_OFF0_DECIM_CNTRL, decim_cntrl); + + if (f_sym <= 3450) + anti_alias = 0; + else if (f_sym <= 4250) + anti_alias = 1; + else + anti_alias = 2; + + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ANTI_ALIAS_SEL, STB0899_OFF0_ANTI_ALIAS_SEL, anti_alias); + btr_nom_freq = stb0899_dvbs2_calc_srate(state); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_NOM_FREQ, STB0899_OFF0_BTR_NOM_FREQ, btr_nom_freq); + + correction = stb0899_dvbs2_calc_dev(state); + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_CNTRL); + STB0899_SETFIELD_VAL(BTR_FREQ_CORR, reg, correction); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_CNTRL, STB0899_OFF0_BTR_CNTRL, reg); + + /* scale UWP+CSM frequency to sample rate*/ + freq_adj = internal->srate / (internal->master_clk / 4096); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_FREQ_ADJ_SCALE, STB0899_OFF0_FREQ_ADJ_SCALE, freq_adj); +} + +/* + * stb0899_dvbs2_set_btr_loopbw + * set bit timing loop bandwidth as a percentage of the symbol rate + */ +static void stb0899_dvbs2_set_btr_loopbw(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_config *config = state->config; + + u32 sym_peak = 23, zeta = 707, loopbw_percent = 60; + s32 dec_ratio, dec_rate, k_btr1_rshft, k_btr1, k_btr0_rshft; + s32 k_btr0, k_btr2_rshft, k_direct_shift, k_indirect_shift; + u32 decim, K, wn, k_direct, k_indirect; + u32 reg; + + dec_ratio = (internal->master_clk * 2) / (5 * internal->srate); + dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio; + dec_rate = Log2Int(dec_ratio); + decim = (1 << dec_rate); + + sym_peak *= 576000; + K = (1 << config->btr_nco_bits) / (internal->master_clk / 1000); + K *= (internal->srate / 1000000) * decim; /*k=k 10^-8*/ + + if (K != 0) { + K = sym_peak / K; + wn = (4 * zeta * zeta) + 1000000; + wn = (2 * (loopbw_percent * 1000) * 40 * zeta) /wn; /*wn =wn 10^-8*/ + + k_indirect = (wn * wn) / K; + k_indirect = k_indirect; /*kindirect = kindirect 10^-6*/ + k_direct = (2 * wn * zeta) / K; /*kDirect = kDirect 10^-2*/ + k_direct *= 100; + + k_direct_shift = Log2Int(k_direct) - Log2Int(10000) - 2; + k_btr1_rshft = (-1 * k_direct_shift) + config->btr_gain_shift_offset; + k_btr1 = k_direct / (1 << k_direct_shift); + k_btr1 /= 10000; + + k_indirect_shift = Log2Int(k_indirect + 15) - 20 /*- 2*/; + k_btr0_rshft = (-1 * k_indirect_shift) + config->btr_gain_shift_offset; + k_btr0 = k_indirect * (1 << (-k_indirect_shift)); + k_btr0 /= 1000000; + + k_btr2_rshft = 0; + if (k_btr0_rshft > 15) { + k_btr2_rshft = k_btr0_rshft - 15; + k_btr0_rshft = 15; + } + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_LOOP_GAIN); + STB0899_SETFIELD_VAL(KBTR0_RSHFT, reg, k_btr0_rshft); + STB0899_SETFIELD_VAL(KBTR0, reg, k_btr0); + STB0899_SETFIELD_VAL(KBTR1_RSHFT, reg, k_btr1_rshft); + STB0899_SETFIELD_VAL(KBTR1, reg, k_btr1); + STB0899_SETFIELD_VAL(KBTR2_RSHFT, reg, k_btr2_rshft); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_LOOP_GAIN, STB0899_OFF0_BTR_LOOP_GAIN, reg); + } else + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_LOOP_GAIN, STB0899_OFF0_BTR_LOOP_GAIN, 0xc4c4f); +} + +/* + * stb0899_dvbs2_set_carr_freq + * set nominal frequency for carrier search + */ +static void stb0899_dvbs2_set_carr_freq(struct stb0899_state *state, s32 carr_freq, u32 master_clk) +{ + struct stb0899_config *config = state->config; + s32 crl_nom_freq; + u32 reg; + + crl_nom_freq = (1 << config->crl_nco_bits) / master_clk; + crl_nom_freq *= carr_freq; + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ); + STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, crl_nom_freq); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg); +} + +/* + * stb0899_dvbs2_init_calc + * Initialize DVBS2 UWP, CSM, carrier and timing loops + */ +static void stb0899_dvbs2_init_calc(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + s32 steps, step_size; + u32 range, reg; + + /* config uwp and csm */ + stb0899_dvbs2_config_uwp(state); + stb0899_dvbs2_config_csm_auto(state); + + /* initialize BTR */ + stb0899_dvbs2_set_srate(state); + stb0899_dvbs2_set_btr_loopbw(state); + + if (internal->srate / 1000000 >= 15) + step_size = (1 << 17) / 5; + else if (internal->srate / 1000000 >= 10) + step_size = (1 << 17) / 7; + else if (internal->srate / 1000000 >= 5) + step_size = (1 << 17) / 10; + else + step_size = (1 << 17) / 4; + + range = internal->srch_range / 1000000; + steps = (10 * range * (1 << 17)) / (step_size * (internal->srate / 1000000)); + steps = (steps + 6) / 10; + steps = (steps == 0) ? 1 : steps; + if (steps % 2 == 0) + stb0899_dvbs2_set_carr_freq(state, internal->center_freq - + (internal->step_size * (internal->srate / 20000000)), + (internal->master_clk) / 1000000); + else + stb0899_dvbs2_set_carr_freq(state, internal->center_freq, (internal->master_clk) / 1000000); + + /*Set Carrier Search params (zigzag, num steps and freq step size*/ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, ACQ_CNTRL2); + STB0899_SETFIELD_VAL(ZIGZAG, reg, 1); + STB0899_SETFIELD_VAL(NUM_STEPS, reg, steps); + STB0899_SETFIELD_VAL(FREQ_STEPSIZE, reg, step_size); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ACQ_CNTRL2, STB0899_OFF0_ACQ_CNTRL2, reg); +} + +/* + * stb0899_dvbs2_btr_init + * initialize the timing loop + */ +static void stb0899_dvbs2_btr_init(struct stb0899_state *state) +{ + u32 reg; + + /* set enable BTR loopback */ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_CNTRL); + STB0899_SETFIELD_VAL(INTRP_PHS_SENSE, reg, 1); + STB0899_SETFIELD_VAL(BTR_ERR_ENA, reg, 1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_CNTRL, STB0899_OFF0_BTR_CNTRL, reg); + + /* fix btr freq accum at 0 */ + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_FREQ_INIT, STB0899_OFF0_BTR_FREQ_INIT, 0x10000000); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_FREQ_INIT, STB0899_OFF0_BTR_FREQ_INIT, 0x00000000); + + /* fix btr freq accum at 0 */ + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_PHS_INIT, STB0899_OFF0_BTR_PHS_INIT, 0x10000000); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_PHS_INIT, STB0899_OFF0_BTR_PHS_INIT, 0x00000000); +} + +/* + * stb0899_dvbs2_reacquire + * trigger a DVB-S2 acquisition + */ +static void stb0899_dvbs2_reacquire(struct stb0899_state *state) +{ + u32 reg = 0; + + /* demod soft reset */ + STB0899_SETFIELD_VAL(DVBS2_RESET, reg, 1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_RESET_CNTRL, STB0899_OFF0_RESET_CNTRL, reg); + + /*Reset Timing Loop */ + stb0899_dvbs2_btr_init(state); + + /* reset Carrier loop */ + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_FREQ_INIT, STB0899_OFF0_CRL_FREQ_INIT, (1 << 30)); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_FREQ_INIT, STB0899_OFF0_CRL_FREQ_INIT, 0); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_LOOP_GAIN, STB0899_OFF0_CRL_LOOP_GAIN, 0); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_PHS_INIT, STB0899_OFF0_CRL_PHS_INIT, (1 << 30)); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_PHS_INIT, STB0899_OFF0_CRL_PHS_INIT, 0); + + /*release demod soft reset */ + reg = 0; + STB0899_SETFIELD_VAL(DVBS2_RESET, reg, 0); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_RESET_CNTRL, STB0899_OFF0_RESET_CNTRL, reg); + + /* start acquisition process */ + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ACQUIRE_TRIG, STB0899_OFF0_ACQUIRE_TRIG, 1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_LOCK_LOST, STB0899_OFF0_LOCK_LOST, 0); + + /* equalizer Init */ + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQUALIZER_INIT, STB0899_OFF0_EQUALIZER_INIT, 1); + + /*Start equilizer */ + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQUALIZER_INIT, STB0899_OFF0_EQUALIZER_INIT, 0); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL); + STB0899_SETFIELD_VAL(EQ_SHIFT, reg, 0); + STB0899_SETFIELD_VAL(EQ_DISABLE_UPDATE, reg, 0); + STB0899_SETFIELD_VAL(EQ_DELAY, reg, 0x05); + STB0899_SETFIELD_VAL(EQ_ADAPT_MODE, reg, 0x01); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg); + + /* RESET Packet delineator */ + stb0899_write_reg(state, STB0899_PDELCTRL, 0x4a); +} + +/* + * stb0899_dvbs2_get_dmd_status + * get DVB-S2 Demod LOCK status + */ +static enum stb0899_status stb0899_dvbs2_get_dmd_status(struct stb0899_state *state, int timeout) +{ + int time = -10, lock = 0, uwp, csm; + u32 reg; + + do { + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STATUS); + dprintk(state->verbose, FE_DEBUG, 1, "DMD_STATUS=[0x%02x]", reg); + if (STB0899_GETFIELD(IF_AGC_LOCK, reg)) + dprintk(state->verbose, FE_DEBUG, 1, "------------->IF AGC LOCKED !"); + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STAT2); + dprintk(state->verbose, FE_DEBUG, 1, "----------->DMD STAT2=[0x%02x]", reg); + uwp = STB0899_GETFIELD(UWP_LOCK, reg); + csm = STB0899_GETFIELD(CSM_LOCK, reg); + if (uwp && csm) + lock = 1; + + time += 10; + msleep(10); + + } while ((!lock) && (time <= timeout)); + + if (lock) { + dprintk(state->verbose, FE_DEBUG, 1, "----------------> DVB-S2 LOCK !"); + return DVBS2_DEMOD_LOCK; + } else { + return DVBS2_DEMOD_NOLOCK; + } +} + +/* + * stb0899_dvbs2_get_data_lock + * get FEC status + */ +static int stb0899_dvbs2_get_data_lock(struct stb0899_state *state, int timeout) +{ + int time = 0, lock = 0; + u8 reg; + + while ((!lock) && (time < timeout)) { + reg = stb0899_read_reg(state, STB0899_CFGPDELSTATUS1); + dprintk(state->verbose, FE_DEBUG, 1, "---------> CFGPDELSTATUS=[0x%02x]", reg); + lock = STB0899_GETFIELD(CFGPDELSTATUS_LOCK, reg); + time++; + } + + return lock; +} + +/* + * stb0899_dvbs2_get_fec_status + * get DVB-S2 FEC LOCK status + */ +static enum stb0899_status stb0899_dvbs2_get_fec_status(struct stb0899_state *state, int timeout) +{ + int time = 0, Locked; + + do { + Locked = stb0899_dvbs2_get_data_lock(state, 1); + time++; + msleep(1); + + } while ((!Locked) && (time < timeout)); + + if (Locked) { + dprintk(state->verbose, FE_DEBUG, 1, "---------->DVB-S2 FEC LOCK !"); + return DVBS2_FEC_LOCK; + } else { + return DVBS2_FEC_NOLOCK; + } +} + + +/* + * stb0899_dvbs2_init_csm + * set parameters for manual mode + */ +static void stb0899_dvbs2_init_csm(struct stb0899_state *state, int pilots, enum stb0899_modcod modcod) +{ + struct stb0899_internal *internal = &state->internal; + + s32 dvt_tbl = 1, two_pass = 0, agc_gain = 6, agc_shift = 0, loop_shift = 0, phs_diff_thr = 0x80; + s32 gamma_acq, gamma_rho_acq, gamma_trk, gamma_rho_trk, lock_count_thr; + u32 csm1, csm2, csm3, csm4; + + if (((internal->master_clk / internal->srate) <= 4) && (modcod <= 11) && (pilots == 1)) { + switch (modcod) { + case STB0899_QPSK_12: + gamma_acq = 25; + gamma_rho_acq = 2700; + gamma_trk = 12; + gamma_rho_trk = 180; + lock_count_thr = 8; + break; + case STB0899_QPSK_35: + gamma_acq = 38; + gamma_rho_acq = 7182; + gamma_trk = 14; + gamma_rho_trk = 308; + lock_count_thr = 8; + break; + case STB0899_QPSK_23: + gamma_acq = 42; + gamma_rho_acq = 9408; + gamma_trk = 17; + gamma_rho_trk = 476; + lock_count_thr = 8; + break; + case STB0899_QPSK_34: + gamma_acq = 53; + gamma_rho_acq = 16642; + gamma_trk = 19; + gamma_rho_trk = 646; + lock_count_thr = 8; + break; + case STB0899_QPSK_45: + gamma_acq = 53; + gamma_rho_acq = 17119; + gamma_trk = 22; + gamma_rho_trk = 880; + lock_count_thr = 8; + break; + case STB0899_QPSK_56: + gamma_acq = 55; + gamma_rho_acq = 19250; + gamma_trk = 23; + gamma_rho_trk = 989; + lock_count_thr = 8; + break; + case STB0899_QPSK_89: + gamma_acq = 60; + gamma_rho_acq = 24240; + gamma_trk = 24; + gamma_rho_trk = 1176; + lock_count_thr = 8; + break; + case STB0899_QPSK_910: + gamma_acq = 66; + gamma_rho_acq = 29634; + gamma_trk = 24; + gamma_rho_trk = 1176; + lock_count_thr = 8; + break; + default: + gamma_acq = 66; + gamma_rho_acq = 29634; + gamma_trk = 24; + gamma_rho_trk = 1176; + lock_count_thr = 8; + break; + } + + csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1); + STB0899_SETFIELD_VAL(CSM_AUTO_PARAM, csm1, 0); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1); + + csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1); + csm2 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL2); + csm3 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL3); + csm4 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL4); + + STB0899_SETFIELD_VAL(CSM_DVT_TABLE, csm1, dvt_tbl); + STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, two_pass); + STB0899_SETFIELD_VAL(CSM_AGC_GAIN, csm1, agc_gain); + STB0899_SETFIELD_VAL(CSM_AGC_SHIFT, csm1, agc_shift); + STB0899_SETFIELD_VAL(FE_LOOP_SHIFT, csm1, loop_shift); + STB0899_SETFIELD_VAL(CSM_GAMMA_ACQ, csm2, gamma_acq); + STB0899_SETFIELD_VAL(CSM_GAMMA_RHOACQ, csm2, gamma_rho_acq); + STB0899_SETFIELD_VAL(CSM_GAMMA_TRACK, csm3, gamma_trk); + STB0899_SETFIELD_VAL(CSM_GAMMA_RHOTRACK, csm3, gamma_rho_trk); + STB0899_SETFIELD_VAL(CSM_LOCKCOUNT_THRESH, csm4, lock_count_thr); + STB0899_SETFIELD_VAL(CSM_PHASEDIFF_THRESH, csm4, phs_diff_thr); + + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL2, STB0899_OFF0_CSM_CNTRL2, csm2); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL3, STB0899_OFF0_CSM_CNTRL3, csm3); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL4, STB0899_OFF0_CSM_CNTRL4, csm4); + } +} + +/* + * stb0899_dvbs2_get_srate + * get DVB-S2 Symbol Rate + */ +static u32 stb0899_dvbs2_get_srate(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_config *config = state->config; + + u32 bTrNomFreq, srate, decimRate, intval1, intval2, reg; + int div1, div2, rem1, rem2; + + div1 = config->btr_nco_bits / 2; + div2 = config->btr_nco_bits - div1 - 1; + + bTrNomFreq = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_NOM_FREQ); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DECIM_CNTRL); + decimRate = STB0899_GETFIELD(DECIM_RATE, reg); + decimRate = (1 << decimRate); + + intval1 = internal->master_clk / (1 << div1); + intval2 = bTrNomFreq / (1 << div2); + + rem1 = internal->master_clk % (1 << div1); + rem2 = bTrNomFreq % (1 << div2); + /* only for integer calculation */ + srate = (intval1 * intval2) + ((intval1 * rem2) / (1 << div2)) + ((intval2 * rem1) / (1 << div1)); + srate /= decimRate; /*symbrate = (btrnomfreq_register_val*MasterClock)/2^(27+decim_rate_field) */ + + return srate; +} + +/* + * stb0899_dvbs2_algo + * Search for signal, timing, carrier and data for a given + * frequency in a given range + */ +enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + enum stb0899_modcod modcod; + + s32 offsetfreq, searchTime, FecLockTime, pilots, iqSpectrum; + int i = 0; + u32 reg, csm1; + + if (internal->srate <= 2000000) { + searchTime = 5000; /* 5000 ms max time to lock UWP and CSM, SYMB <= 2Mbs */ + FecLockTime = 350; /* 350 ms max time to lock FEC, SYMB <= 2Mbs */ + } else if (internal->srate <= 5000000) { + searchTime = 2500; /* 2500 ms max time to lock UWP and CSM, 2Mbs < SYMB <= 5Mbs */ + FecLockTime = 170; /* 170 ms max time to lock FEC, 2Mbs< SYMB <= 5Mbs */ + } else if (internal->srate <= 10000000) { + searchTime = 1500; /* 1500 ms max time to lock UWP and CSM, 5Mbs <SYMB <= 10Mbs */ + FecLockTime = 80; /* 80 ms max time to lock FEC, 5Mbs< SYMB <= 10Mbs */ + } else if (internal->srate <= 15000000) { + searchTime = 500; /* 500 ms max time to lock UWP and CSM, 10Mbs <SYMB <= 15Mbs */ + FecLockTime = 50; /* 50 ms max time to lock FEC, 10Mbs< SYMB <= 15Mbs */ + } else if (internal->srate <= 20000000) { + searchTime = 300; /* 300 ms max time to lock UWP and CSM, 15Mbs < SYMB <= 20Mbs */ + FecLockTime = 30; /* 50 ms max time to lock FEC, 15Mbs< SYMB <= 20Mbs */ + } else if (internal->srate <= 25000000) { + searchTime = 250; /* 250 ms max time to lock UWP and CSM, 20 Mbs < SYMB <= 25Mbs */ + FecLockTime = 25; /* 25 ms max time to lock FEC, 20Mbs< SYMB <= 25Mbs */ + } else { + searchTime = 150; /* 150 ms max time to lock UWP and CSM, SYMB > 25Mbs */ + FecLockTime = 20; /* 20 ms max time to lock FEC, 20Mbs< SYMB <= 25Mbs */ + } + + /* Maintain Stream Merger in reset during acquisition */ + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESRS, reg, 1); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + /* enable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 1); + + /* Move tuner to frequency */ + if (state->config->tuner_set_frequency) + state->config->tuner_set_frequency(&state->frontend, internal->freq); + if (state->config->tuner_get_frequency) + state->config->tuner_get_frequency(&state->frontend, &internal->freq); + + /* disable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 0); + + /* Set IF AGC to acquisition */ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL); + STB0899_SETFIELD_VAL(IF_LOOP_GAIN, reg, 4); + STB0899_SETFIELD_VAL(IF_AGC_REF, reg, 32); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL2); + STB0899_SETFIELD_VAL(IF_AGC_DUMP_PER, reg, 0); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL2, STB0899_OFF0_IF_AGC_CNTRL2, reg); + + /* Initialisation */ + stb0899_dvbs2_init_calc(state); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2); + switch (internal->inversion) { + case IQ_SWAP_OFF: + STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 0); + break; + case IQ_SWAP_ON: + STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 1); + break; + case IQ_SWAP_AUTO: /* use last successful search first */ + STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 1); + break; + } + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DMD_CNTRL2, STB0899_OFF0_DMD_CNTRL2, reg); + stb0899_dvbs2_reacquire(state); + + /* Wait for demod lock (UWP and CSM) */ + internal->status = stb0899_dvbs2_get_dmd_status(state, searchTime); + + if (internal->status == DVBS2_DEMOD_LOCK) { + dprintk(state->verbose, FE_DEBUG, 1, "------------> DVB-S2 DEMOD LOCK !"); + i = 0; + /* Demod Locked, check FEC status */ + internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime); + + /*If false lock (UWP and CSM Locked but no FEC) try 3 time max*/ + while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) { + /* Read the frequency offset*/ + offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ); + + /* Set the Nominal frequency to the found frequency offset for the next reacquire*/ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ); + STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, offsetfreq); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg); + stb0899_dvbs2_reacquire(state); + internal->status = stb0899_dvbs2_get_fec_status(state, searchTime); + i++; + } + } + + if (internal->status != DVBS2_FEC_LOCK) { + if (internal->inversion == IQ_SWAP_AUTO) { + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2); + iqSpectrum = STB0899_GETFIELD(SPECTRUM_INVERT, reg); + /* IQ Spectrum Inversion */ + STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, !iqSpectrum); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DMD_CNTRL2, STB0899_OFF0_DMD_CNTRL2, reg); + /* start acquistion process */ + stb0899_dvbs2_reacquire(state); + + /* Wait for demod lock (UWP and CSM) */ + internal->status = stb0899_dvbs2_get_dmd_status(state, searchTime); + if (internal->status == DVBS2_DEMOD_LOCK) { + i = 0; + /* Demod Locked, check FEC */ + internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime); + /*try thrice for false locks, (UWP and CSM Locked but no FEC) */ + while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) { + /* Read the frequency offset*/ + offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ); + + /* Set the Nominal frequency to the found frequency offset for the next reacquire*/ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ); + STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, offsetfreq); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg); + + stb0899_dvbs2_reacquire(state); + internal->status = stb0899_dvbs2_get_fec_status(state, searchTime); + i++; + } + } +/* + if (pParams->DVBS2State == FE_DVBS2_FEC_LOCKED) + pParams->IQLocked = !iqSpectrum; +*/ + } + } + if (internal->status == DVBS2_FEC_LOCK) { + dprintk(state->verbose, FE_DEBUG, 1, "----------------> DVB-S2 FEC Lock !"); + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2); + modcod = STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 2; + pilots = STB0899_GETFIELD(UWP_DECODE_MOD, reg) & 0x01; + + if ((((10 * internal->master_clk) / (internal->srate / 10)) <= 410) && + (INRANGE(STB0899_QPSK_23, modcod, STB0899_QPSK_910)) && + (pilots == 1)) { + + stb0899_dvbs2_init_csm(state, pilots, modcod); + /* Wait for UWP,CSM and data LOCK 20ms max */ + internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime); + + i = 0; + while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) { + csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1); + STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, 1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1); + csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1); + STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, 0); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1); + + internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime); + i++; + } + } + + if ((((10 * internal->master_clk) / (internal->srate / 10)) <= 410) && + (INRANGE(STB0899_QPSK_12, modcod, STB0899_QPSK_35)) && + (pilots == 1)) { + + /* Equalizer Disable update */ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL); + STB0899_SETFIELD_VAL(EQ_DISABLE_UPDATE, reg, 1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg); + } + + /* slow down the Equalizer once locked */ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL); + STB0899_SETFIELD_VAL(EQ_SHIFT, reg, 0x02); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg); + + /* Store signal parameters */ + offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ); + + offsetfreq = offsetfreq / ((1 << 30) / 1000); + offsetfreq *= (internal->master_clk / 1000000); + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2); + if (STB0899_GETFIELD(SPECTRUM_INVERT, reg)) + offsetfreq *= -1; + + internal->freq = internal->freq - offsetfreq; + internal->srate = stb0899_dvbs2_get_srate(state); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2); + internal->modcod = STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 2; + internal->pilots = STB0899_GETFIELD(UWP_DECODE_MOD, reg) & 0x01; + internal->frame_length = (STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 1) & 0x01; + + /* Set IF AGC to tracking */ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL); + STB0899_SETFIELD_VAL(IF_LOOP_GAIN, reg, 3); + + /* if QPSK 1/2,QPSK 3/5 or QPSK 2/3 set IF AGC reference to 16 otherwise 32*/ + if (INRANGE(STB0899_QPSK_12, internal->modcod, STB0899_QPSK_23)) + STB0899_SETFIELD_VAL(IF_AGC_REF, reg, 16); + + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL2); + STB0899_SETFIELD_VAL(IF_AGC_DUMP_PER, reg, 7); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL2, STB0899_OFF0_IF_AGC_CNTRL2, reg); + } + + /* Release Stream Merger Reset */ + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESRS, reg, 0); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + return internal->status; +} diff --git a/drivers/media/dvb/frontends/stb0899_cfg.h b/drivers/media/dvb/frontends/stb0899_cfg.h new file mode 100644 index 00000000000..0867906d3ff --- /dev/null +++ b/drivers/media/dvb/frontends/stb0899_cfg.h @@ -0,0 +1,287 @@ +/* + STB0899 Multistandard Frontend driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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 __STB0899_CFG_H +#define __STB0899_CFG_H + +static const struct stb0899_s2_reg stb0899_s2_init_2[] = { + + { STB0899_OFF0_DMD_STATUS , STB0899_BASE_DMD_STATUS , 0x00000103 }, /* DMDSTATUS */ + { STB0899_OFF0_CRL_FREQ , STB0899_BASE_CRL_FREQ , 0x3ed1da56 }, /* CRLFREQ */ + { STB0899_OFF0_BTR_FREQ , STB0899_BASE_BTR_FREQ , 0x00004000 }, /* BTRFREQ */ + { STB0899_OFF0_IF_AGC_GAIN , STB0899_BASE_IF_AGC_GAIN , 0x00002ade }, /* IFAGCGAIN */ + { STB0899_OFF0_BB_AGC_GAIN , STB0899_BASE_BB_AGC_GAIN , 0x000001bc }, /* BBAGCGAIN */ + { STB0899_OFF0_DC_OFFSET , STB0899_BASE_DC_OFFSET , 0x00000200 }, /* DCOFFSET */ + { STB0899_OFF0_DMD_CNTRL , STB0899_BASE_DMD_CNTRL , 0x0000000f }, /* DMDCNTRL */ + + { STB0899_OFF0_IF_AGC_CNTRL , STB0899_BASE_IF_AGC_CNTRL , 0x03fb4a20 }, /* IFAGCCNTRL */ + { STB0899_OFF0_BB_AGC_CNTRL , STB0899_BASE_BB_AGC_CNTRL , 0x00200c97 }, /* BBAGCCNTRL */ + + { STB0899_OFF0_CRL_CNTRL , STB0899_BASE_CRL_CNTRL , 0x00000016 }, /* CRLCNTRL */ + { STB0899_OFF0_CRL_PHS_INIT , STB0899_BASE_CRL_PHS_INIT , 0x00000000 }, /* CRLPHSINIT */ + { STB0899_OFF0_CRL_FREQ_INIT , STB0899_BASE_CRL_FREQ_INIT , 0x00000000 }, /* CRLFREQINIT */ + { STB0899_OFF0_CRL_LOOP_GAIN , STB0899_BASE_CRL_LOOP_GAIN , 0x00000000 }, /* CRLLOOPGAIN */ + { STB0899_OFF0_CRL_NOM_FREQ , STB0899_BASE_CRL_NOM_FREQ , 0x3ed097b6 }, /* CRLNOMFREQ */ + { STB0899_OFF0_CRL_SWP_RATE , STB0899_BASE_CRL_SWP_RATE , 0x00000000 }, /* CRLSWPRATE */ + { STB0899_OFF0_CRL_MAX_SWP , STB0899_BASE_CRL_MAX_SWP , 0x00000000 }, /* CRLMAXSWP */ + { STB0899_OFF0_CRL_LK_CNTRL , STB0899_BASE_CRL_LK_CNTRL , 0x0f6cdc01 }, /* CRLLKCNTRL */ + { STB0899_OFF0_DECIM_CNTRL , STB0899_BASE_DECIM_CNTRL , 0x00000000 }, /* DECIMCNTRL */ + { STB0899_OFF0_BTR_CNTRL , STB0899_BASE_BTR_CNTRL , 0x00003993 }, /* BTRCNTRL */ + { STB0899_OFF0_BTR_LOOP_GAIN , STB0899_BASE_BTR_LOOP_GAIN , 0x000d3c6f }, /* BTRLOOPGAIN */ + { STB0899_OFF0_BTR_PHS_INIT , STB0899_BASE_BTR_PHS_INIT , 0x00000000 }, /* BTRPHSINIT */ + { STB0899_OFF0_BTR_FREQ_INIT , STB0899_BASE_BTR_FREQ_INIT , 0x00000000 }, /* BTRFREQINIT */ + { STB0899_OFF0_BTR_NOM_FREQ , STB0899_BASE_BTR_NOM_FREQ , 0x0238e38e }, /* BTRNOMFREQ */ + { STB0899_OFF0_BTR_LK_CNTRL , STB0899_BASE_BTR_LK_CNTRL , 0x00000000 }, /* BTRLKCNTRL */ + { STB0899_OFF0_DECN_CNTRL , STB0899_BASE_DECN_CNTRL , 0x00000000 }, /* DECNCNTRL */ + { STB0899_OFF0_TP_CNTRL , STB0899_BASE_TP_CNTRL , 0x00000000 }, /* TPCNTRL */ + { STB0899_OFF0_TP_BUF_STATUS , STB0899_BASE_TP_BUF_STATUS , 0x00000000 }, /* TPBUFSTATUS */ + { STB0899_OFF0_DC_ESTIM , STB0899_BASE_DC_ESTIM , 0x00000000 }, /* DCESTIM */ + { STB0899_OFF0_FLL_CNTRL , STB0899_BASE_FLL_CNTRL , 0x00000000 }, /* FLLCNTRL */ + { STB0899_OFF0_FLL_FREQ_WD , STB0899_BASE_FLL_FREQ_WD , 0x40070000 }, /* FLLFREQWD */ + { STB0899_OFF0_ANTI_ALIAS_SEL , STB0899_BASE_ANTI_ALIAS_SEL , 0x00000001 }, /* ANTIALIASSEL */ + { STB0899_OFF0_RRC_ALPHA , STB0899_BASE_RRC_ALPHA , 0x00000002 }, /* RRCALPHA */ + { STB0899_OFF0_DC_ADAPT_LSHFT , STB0899_BASE_DC_ADAPT_LSHFT , 0x00000000 }, /* DCADAPTISHFT */ + { STB0899_OFF0_IMB_OFFSET , STB0899_BASE_IMB_OFFSET , 0x0000fe01 }, /* IMBOFFSET */ + { STB0899_OFF0_IMB_ESTIMATE , STB0899_BASE_IMB_ESTIMATE , 0x00000000 }, /* IMBESTIMATE */ + { STB0899_OFF0_IMB_CNTRL , STB0899_BASE_IMB_CNTRL , 0x00000001 }, /* IMBCNTRL */ + { STB0899_OFF0_IF_AGC_CNTRL2 , STB0899_BASE_IF_AGC_CNTRL2 , 0x00005007 }, /* IFAGCCNTRL2 */ + { STB0899_OFF0_DMD_CNTRL2 , STB0899_BASE_DMD_CNTRL2 , 0x00000002 }, /* DMDCNTRL2 */ + { STB0899_OFF0_TP_BUFFER , STB0899_BASE_TP_BUFFER , 0x00000000 }, /* TPBUFFER */ + { STB0899_OFF0_TP_BUFFER1 , STB0899_BASE_TP_BUFFER1 , 0x00000000 }, /* TPBUFFER1 */ + { STB0899_OFF0_TP_BUFFER2 , STB0899_BASE_TP_BUFFER2 , 0x00000000 }, /* TPBUFFER2 */ + { STB0899_OFF0_TP_BUFFER3 , STB0899_BASE_TP_BUFFER3 , 0x00000000 }, /* TPBUFFER3 */ + { STB0899_OFF0_TP_BUFFER4 , STB0899_BASE_TP_BUFFER4 , 0x00000000 }, /* TPBUFFER4 */ + { STB0899_OFF0_TP_BUFFER5 , STB0899_BASE_TP_BUFFER5 , 0x00000000 }, /* TPBUFFER5 */ + { STB0899_OFF0_TP_BUFFER6 , STB0899_BASE_TP_BUFFER6 , 0x00000000 }, /* TPBUFFER6 */ + { STB0899_OFF0_TP_BUFFER7 , STB0899_BASE_TP_BUFFER7 , 0x00000000 }, /* TPBUFFER7 */ + { STB0899_OFF0_TP_BUFFER8 , STB0899_BASE_TP_BUFFER8 , 0x00000000 }, /* TPBUFFER8 */ + { STB0899_OFF0_TP_BUFFER9 , STB0899_BASE_TP_BUFFER9 , 0x00000000 }, /* TPBUFFER9 */ + { STB0899_OFF0_TP_BUFFER10 , STB0899_BASE_TP_BUFFER10 , 0x00000000 }, /* TPBUFFER10 */ + { STB0899_OFF0_TP_BUFFER11 , STB0899_BASE_TP_BUFFER11 , 0x00000000 }, /* TPBUFFER11 */ + { STB0899_OFF0_TP_BUFFER12 , STB0899_BASE_TP_BUFFER12 , 0x00000000 }, /* TPBUFFER12 */ + { STB0899_OFF0_TP_BUFFER13 , STB0899_BASE_TP_BUFFER13 , 0x00000000 }, /* TPBUFFER13 */ + { STB0899_OFF0_TP_BUFFER14 , STB0899_BASE_TP_BUFFER14 , 0x00000000 }, /* TPBUFFER14 */ + { STB0899_OFF0_TP_BUFFER15 , STB0899_BASE_TP_BUFFER15 , 0x00000000 }, /* TPBUFFER15 */ + { STB0899_OFF0_TP_BUFFER16 , STB0899_BASE_TP_BUFFER16 , 0x0000ff00 }, /* TPBUFFER16 */ + { STB0899_OFF0_TP_BUFFER17 , STB0899_BASE_TP_BUFFER17 , 0x00000100 }, /* TPBUFFER17 */ + { STB0899_OFF0_TP_BUFFER18 , STB0899_BASE_TP_BUFFER18 , 0x0000fe01 }, /* TPBUFFER18 */ + { STB0899_OFF0_TP_BUFFER19 , STB0899_BASE_TP_BUFFER19 , 0x000004fe }, /* TPBUFFER19 */ + { STB0899_OFF0_TP_BUFFER20 , STB0899_BASE_TP_BUFFER20 , 0x0000cfe7 }, /* TPBUFFER20 */ + { STB0899_OFF0_TP_BUFFER21 , STB0899_BASE_TP_BUFFER21 , 0x0000bec6 }, /* TPBUFFER21 */ + { STB0899_OFF0_TP_BUFFER22 , STB0899_BASE_TP_BUFFER22 , 0x0000c2bf }, /* TPBUFFER22 */ + { STB0899_OFF0_TP_BUFFER23 , STB0899_BASE_TP_BUFFER23 , 0x0000c1c1 }, /* TPBUFFER23 */ + { STB0899_OFF0_TP_BUFFER24 , STB0899_BASE_TP_BUFFER24 , 0x0000c1c1 }, /* TPBUFFER24 */ + { STB0899_OFF0_TP_BUFFER25 , STB0899_BASE_TP_BUFFER25 , 0x0000c1c1 }, /* TPBUFFER25 */ + { STB0899_OFF0_TP_BUFFER26 , STB0899_BASE_TP_BUFFER26 , 0x0000c1c1 }, /* TPBUFFER26 */ + { STB0899_OFF0_TP_BUFFER27 , STB0899_BASE_TP_BUFFER27 , 0x0000c1c0 }, /* TPBUFFER27 */ + { STB0899_OFF0_TP_BUFFER28 , STB0899_BASE_TP_BUFFER28 , 0x0000c0c0 }, /* TPBUFFER28 */ + { STB0899_OFF0_TP_BUFFER29 , STB0899_BASE_TP_BUFFER29 , 0x0000c1c1 }, /* TPBUFFER29 */ + { STB0899_OFF0_TP_BUFFER30 , STB0899_BASE_TP_BUFFER30 , 0x0000c1c1 }, /* TPBUFFER30 */ + { STB0899_OFF0_TP_BUFFER31 , STB0899_BASE_TP_BUFFER31 , 0x0000c0c1 }, /* TPBUFFER31 */ + { STB0899_OFF0_TP_BUFFER32 , STB0899_BASE_TP_BUFFER32 , 0x0000c0c1 }, /* TPBUFFER32 */ + { STB0899_OFF0_TP_BUFFER33 , STB0899_BASE_TP_BUFFER33 , 0x0000c1c1 }, /* TPBUFFER33 */ + { STB0899_OFF0_TP_BUFFER34 , STB0899_BASE_TP_BUFFER34 , 0x0000c1c1 }, /* TPBUFFER34 */ + { STB0899_OFF0_TP_BUFFER35 , STB0899_BASE_TP_BUFFER35 , 0x0000c0c1 }, /* TPBUFFER35 */ + { STB0899_OFF0_TP_BUFFER36 , STB0899_BASE_TP_BUFFER36 , 0x0000c1c1 }, /* TPBUFFER36 */ + { STB0899_OFF0_TP_BUFFER37 , STB0899_BASE_TP_BUFFER37 , 0x0000c0c1 }, /* TPBUFFER37 */ + { STB0899_OFF0_TP_BUFFER38 , STB0899_BASE_TP_BUFFER38 , 0x0000c1c1 }, /* TPBUFFER38 */ + { STB0899_OFF0_TP_BUFFER39 , STB0899_BASE_TP_BUFFER39 , 0x0000c0c0 }, /* TPBUFFER39 */ + { STB0899_OFF0_TP_BUFFER40 , STB0899_BASE_TP_BUFFER40 , 0x0000c1c0 }, /* TPBUFFER40 */ + { STB0899_OFF0_TP_BUFFER41 , STB0899_BASE_TP_BUFFER41 , 0x0000c1c1 }, /* TPBUFFER41 */ + { STB0899_OFF0_TP_BUFFER42 , STB0899_BASE_TP_BUFFER42 , 0x0000c0c0 }, /* TPBUFFER42 */ + { STB0899_OFF0_TP_BUFFER43 , STB0899_BASE_TP_BUFFER43 , 0x0000c1c0 }, /* TPBUFFER43 */ + { STB0899_OFF0_TP_BUFFER44 , STB0899_BASE_TP_BUFFER44 , 0x0000c0c1 }, /* TPBUFFER44 */ + { STB0899_OFF0_TP_BUFFER45 , STB0899_BASE_TP_BUFFER45 , 0x0000c1be }, /* TPBUFFER45 */ + { STB0899_OFF0_TP_BUFFER46 , STB0899_BASE_TP_BUFFER46 , 0x0000c1c9 }, /* TPBUFFER46 */ + { STB0899_OFF0_TP_BUFFER47 , STB0899_BASE_TP_BUFFER47 , 0x0000c0da }, /* TPBUFFER47 */ + { STB0899_OFF0_TP_BUFFER48 , STB0899_BASE_TP_BUFFER48 , 0x0000c0ba }, /* TPBUFFER48 */ + { STB0899_OFF0_TP_BUFFER49 , STB0899_BASE_TP_BUFFER49 , 0x0000c1c4 }, /* TPBUFFER49 */ + { STB0899_OFF0_TP_BUFFER50 , STB0899_BASE_TP_BUFFER50 , 0x0000c1bf }, /* TPBUFFER50 */ + { STB0899_OFF0_TP_BUFFER51 , STB0899_BASE_TP_BUFFER51 , 0x0000c0c1 }, /* TPBUFFER51 */ + { STB0899_OFF0_TP_BUFFER52 , STB0899_BASE_TP_BUFFER52 , 0x0000c1c0 }, /* TPBUFFER52 */ + { STB0899_OFF0_TP_BUFFER53 , STB0899_BASE_TP_BUFFER53 , 0x0000c0c1 }, /* TPBUFFER53 */ + { STB0899_OFF0_TP_BUFFER54 , STB0899_BASE_TP_BUFFER54 , 0x0000c1c1 }, /* TPBUFFER54 */ + { STB0899_OFF0_TP_BUFFER55 , STB0899_BASE_TP_BUFFER55 , 0x0000c1c1 }, /* TPBUFFER55 */ + { STB0899_OFF0_TP_BUFFER56 , STB0899_BASE_TP_BUFFER56 , 0x0000c1c1 }, /* TPBUFFER56 */ + { STB0899_OFF0_TP_BUFFER57 , STB0899_BASE_TP_BUFFER57 , 0x0000c1c1 }, /* TPBUFFER57 */ + { STB0899_OFF0_TP_BUFFER58 , STB0899_BASE_TP_BUFFER58 , 0x0000c1c1 }, /* TPBUFFER58 */ + { STB0899_OFF0_TP_BUFFER59 , STB0899_BASE_TP_BUFFER59 , 0x0000c1c1 }, /* TPBUFFER59 */ + { STB0899_OFF0_TP_BUFFER60 , STB0899_BASE_TP_BUFFER60 , 0x0000c1c1 }, /* TPBUFFER60 */ + { STB0899_OFF0_TP_BUFFER61 , STB0899_BASE_TP_BUFFER61 , 0x0000c1c1 }, /* TPBUFFER61 */ + { STB0899_OFF0_TP_BUFFER62 , STB0899_BASE_TP_BUFFER62 , 0x0000c1c1 }, /* TPBUFFER62 */ + { STB0899_OFF0_TP_BUFFER63 , STB0899_BASE_TP_BUFFER63 , 0x0000c1c0 }, /* TPBUFFER63 */ + { STB0899_OFF0_RESET_CNTRL , STB0899_BASE_RESET_CNTRL , 0x00000001 }, /* RESETCNTRL */ + { STB0899_OFF0_ACM_ENABLE , STB0899_BASE_ACM_ENABLE , 0x00005654 }, /* ACMENABLE */ + { STB0899_OFF0_DESCR_CNTRL , STB0899_BASE_DESCR_CNTRL , 0x00000000 }, /* DESCRCNTRL */ + { STB0899_OFF0_CSM_CNTRL1 , STB0899_BASE_CSM_CNTRL1 , 0x00020019 }, /* CSMCNTRL1 */ + { STB0899_OFF0_CSM_CNTRL2 , STB0899_BASE_CSM_CNTRL2 , 0x004b3237 }, /* CSMCNTRL2 */ + { STB0899_OFF0_CSM_CNTRL3 , STB0899_BASE_CSM_CNTRL3 , 0x0003dd17 }, /* CSMCNTRL3 */ + { STB0899_OFF0_CSM_CNTRL4 , STB0899_BASE_CSM_CNTRL4 , 0x00008008 }, /* CSMCNTRL4 */ + { STB0899_OFF0_UWP_CNTRL1 , STB0899_BASE_UWP_CNTRL1 , 0x002a3106 }, /* UWPCNTRL1 */ + { STB0899_OFF0_UWP_CNTRL2 , STB0899_BASE_UWP_CNTRL2 , 0x0006140a }, /* UWPCNTRL2 */ + { STB0899_OFF0_UWP_STAT1 , STB0899_BASE_UWP_STAT1 , 0x00008000 }, /* UWPSTAT1 */ + { STB0899_OFF0_UWP_STAT2 , STB0899_BASE_UWP_STAT2 , 0x00000000 }, /* UWPSTAT2 */ + { STB0899_OFF0_DMD_STAT2 , STB0899_BASE_DMD_STAT2 , 0x00000000 }, /* DMDSTAT2 */ + { STB0899_OFF0_FREQ_ADJ_SCALE , STB0899_BASE_FREQ_ADJ_SCALE , 0x00000471 }, /* FREQADJSCALE */ + { STB0899_OFF0_UWP_CNTRL3 , STB0899_BASE_UWP_CNTRL3 , 0x017b0465 }, /* UWPCNTRL3 */ + { STB0899_OFF0_SYM_CLK_SEL , STB0899_BASE_SYM_CLK_SEL , 0x00000002 }, /* SYMCLKSEL */ + { STB0899_OFF0_SOF_SRCH_TO , STB0899_BASE_SOF_SRCH_TO , 0x00196464 }, /* SOFSRCHTO */ + { STB0899_OFF0_ACQ_CNTRL1 , STB0899_BASE_ACQ_CNTRL1 , 0x00000603 }, /* ACQCNTRL1 */ + { STB0899_OFF0_ACQ_CNTRL2 , STB0899_BASE_ACQ_CNTRL2 , 0x02046666 }, /* ACQCNTRL2 */ + { STB0899_OFF0_ACQ_CNTRL3 , STB0899_BASE_ACQ_CNTRL3 , 0x10046583 }, /* ACQCNTRL3 */ + { STB0899_OFF0_FE_SETTLE , STB0899_BASE_FE_SETTLE , 0x00010404 }, /* FESETTLE */ + { STB0899_OFF0_AC_DWELL , STB0899_BASE_AC_DWELL , 0x0002aa8a }, /* ACDWELL */ + { STB0899_OFF0_ACQUIRE_TRIG , STB0899_BASE_ACQUIRE_TRIG , 0x00000000 }, /* ACQUIRETRIG */ + { STB0899_OFF0_LOCK_LOST , STB0899_BASE_LOCK_LOST , 0x00000001 }, /* LOCKLOST */ + { STB0899_OFF0_ACQ_STAT1 , STB0899_BASE_ACQ_STAT1 , 0x00000500 }, /* ACQSTAT1 */ + { STB0899_OFF0_ACQ_TIMEOUT , STB0899_BASE_ACQ_TIMEOUT , 0x0028a0a0 }, /* ACQTIMEOUT */ + { STB0899_OFF0_ACQ_TIME , STB0899_BASE_ACQ_TIME , 0x00000000 }, /* ACQTIME */ + { STB0899_OFF0_FINAL_AGC_CNTRL , STB0899_BASE_FINAL_AGC_CNTRL , 0x00800c17 }, /* FINALAGCCNTRL*/ + { STB0899_OFF0_FINAL_AGC_GAIN , STB0899_BASE_FINAL_AGC_GAIN , 0x00000000 }, /* FINALAGCCGAIN*/ + { STB0899_OFF0_EQUALIZER_INIT , STB0899_BASE_EQUALIZER_INIT , 0x00000000 }, /* EQUILIZERINIT*/ + { STB0899_OFF0_EQ_CNTRL , STB0899_BASE_EQ_CNTRL , 0x00054802 }, /* EQCNTL */ + { STB0899_OFF0_EQ_I_INIT_COEFF_0, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF0 */ + { STB0899_OFF1_EQ_I_INIT_COEFF_1, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF1 */ + { STB0899_OFF2_EQ_I_INIT_COEFF_2, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF2 */ + { STB0899_OFF3_EQ_I_INIT_COEFF_3, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF3 */ + { STB0899_OFF4_EQ_I_INIT_COEFF_4, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF4 */ + { STB0899_OFF5_EQ_I_INIT_COEFF_5, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000400 }, /* EQIINITCOEFF5 */ + { STB0899_OFF6_EQ_I_INIT_COEFF_6, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF6 */ + { STB0899_OFF7_EQ_I_INIT_COEFF_7, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF7 */ + { STB0899_OFF8_EQ_I_INIT_COEFF_8, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF8 */ + { STB0899_OFF9_EQ_I_INIT_COEFF_9, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF9 */ + { STB0899_OFFa_EQ_I_INIT_COEFF_10,STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF10*/ + { STB0899_OFF0_EQ_Q_INIT_COEFF_0, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF0 */ + { STB0899_OFF1_EQ_Q_INIT_COEFF_1, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF1 */ + { STB0899_OFF2_EQ_Q_INIT_COEFF_2, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF2 */ + { STB0899_OFF3_EQ_Q_INIT_COEFF_3, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF3 */ + { STB0899_OFF4_EQ_Q_INIT_COEFF_4, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF4 */ + { STB0899_OFF5_EQ_Q_INIT_COEFF_5, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF5 */ + { STB0899_OFF6_EQ_Q_INIT_COEFF_6, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF6 */ + { STB0899_OFF7_EQ_Q_INIT_COEFF_7, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF7 */ + { STB0899_OFF8_EQ_Q_INIT_COEFF_8, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF8 */ + { STB0899_OFF9_EQ_Q_INIT_COEFF_9, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF9 */ + { STB0899_OFFa_EQ_Q_INIT_COEFF_10,STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF10*/ + { STB0899_OFF0_EQ_I_OUT_COEFF_0 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT0 */ + { STB0899_OFF1_EQ_I_OUT_COEFF_1 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT1 */ + { STB0899_OFF2_EQ_I_OUT_COEFF_2 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT2 */ + { STB0899_OFF3_EQ_I_OUT_COEFF_3 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT3 */ + { STB0899_OFF4_EQ_I_OUT_COEFF_4 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT4 */ + { STB0899_OFF5_EQ_I_OUT_COEFF_5 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT5 */ + { STB0899_OFF6_EQ_I_OUT_COEFF_6 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT6 */ + { STB0899_OFF7_EQ_I_OUT_COEFF_7 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT7 */ + { STB0899_OFF8_EQ_I_OUT_COEFF_8 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT8 */ + { STB0899_OFF9_EQ_I_OUT_COEFF_9 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT9 */ + { STB0899_OFFa_EQ_I_OUT_COEFF_10,STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT10*/ + { STB0899_OFF0_EQ_Q_OUT_COEFF_0 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT0 */ + { STB0899_OFF1_EQ_Q_OUT_COEFF_1 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT1 */ + { STB0899_OFF2_EQ_Q_OUT_COEFF_2 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT2 */ + { STB0899_OFF3_EQ_Q_OUT_COEFF_3 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT3 */ + { STB0899_OFF4_EQ_Q_OUT_COEFF_4 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT4 */ + { STB0899_OFF5_EQ_Q_OUT_COEFF_5 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT5 */ + { STB0899_OFF6_EQ_Q_OUT_COEFF_6 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT6 */ + { STB0899_OFF7_EQ_Q_OUT_COEFF_7 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT7 */ + { STB0899_OFF8_EQ_Q_OUT_COEFF_8 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT8 */ + { STB0899_OFF9_EQ_Q_OUT_COEFF_9 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT9 */ + { STB0899_OFFa_EQ_Q_OUT_COEFF_10, STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT10*/ + { 0xffff , 0xffffffff , 0xffffffff }, +}; +static const struct stb0899_s2_reg stb0899_s2_init_4[] = { + { STB0899_OFF0_BLOCK_LNGTH , STB0899_BASE_BLOCK_LNGTH , 0x00000008 }, /* BLOCKLNGTH */ + { STB0899_OFF0_ROW_STR , STB0899_BASE_ROW_STR , 0x000000b4 }, /* ROWSTR */ + { STB0899_OFF0_BN_END_ADDR , STB0899_BASE_BN_END_ADDR , 0x000004b5 }, /* BNANDADDR */ + { STB0899_OFF0_CN_END_ADDR , STB0899_BASE_CN_END_ADDR , 0x00000b4b }, /* CNANDADDR */ + { STB0899_OFF0_INFO_LENGTH , STB0899_BASE_INFO_LENGTH , 0x00000078 }, /* INFOLENGTH */ + { STB0899_OFF0_BOT_ADDR , STB0899_BASE_BOT_ADDR , 0x000001e0 }, /* BOT_ADDR */ + { STB0899_OFF0_BCH_BLK_LN , STB0899_BASE_BCH_BLK_LN , 0x0000a8c0 }, /* BCHBLKLN */ + { STB0899_OFF0_BCH_T , STB0899_BASE_BCH_T , 0x0000000c }, /* BCHT */ + { STB0899_OFF0_CNFG_MODE , STB0899_BASE_CNFG_MODE , 0x00000001 }, /* CNFGMODE */ + { STB0899_OFF0_LDPC_STAT , STB0899_BASE_LDPC_STAT , 0x0000000d }, /* LDPCSTAT */ + { STB0899_OFF0_ITER_SCALE , STB0899_BASE_ITER_SCALE , 0x00000040 }, /* ITERSCALE */ + { STB0899_OFF0_INPUT_MODE , STB0899_BASE_INPUT_MODE , 0x00000000 }, /* INPUTMODE */ + { STB0899_OFF0_LDPCDECRST , STB0899_BASE_LDPCDECRST , 0x00000000 }, /* LDPCDECRST */ + { STB0899_OFF0_CLK_PER_BYTE_RW , STB0899_BASE_CLK_PER_BYTE_RW , 0x00000008 }, /* CLKPERBYTE */ + { STB0899_OFF0_BCH_ERRORS , STB0899_BASE_BCH_ERRORS , 0x00000000 }, /* BCHERRORS */ + { STB0899_OFF0_LDPC_ERRORS , STB0899_BASE_LDPC_ERRORS , 0x00000000 }, /* LDPCERRORS */ + { STB0899_OFF0_BCH_MODE , STB0899_BASE_BCH_MODE , 0x00000000 }, /* BCHMODE */ + { STB0899_OFF0_ERR_ACC_PER , STB0899_BASE_ERR_ACC_PER , 0x00000008 }, /* ERRACCPER */ + { STB0899_OFF0_BCH_ERR_ACC , STB0899_BASE_BCH_ERR_ACC , 0x00000000 }, /* BCHERRACC */ + { STB0899_OFF0_FEC_TP_SEL , STB0899_BASE_FEC_TP_SEL , 0x00000000 }, /* FECTPSEL */ + { 0xffff , 0xffffffff , 0xffffffff }, +}; + +static const struct stb0899_s1_reg stb0899_s1_init_5[] = { + { STB0899_TSTCK , 0x00 }, + { STB0899_TSTRES , 0x00 }, + { STB0899_TSTOUT , 0x00 }, + { STB0899_TSTIN , 0x00 }, + { STB0899_TSTSYS , 0x00 }, + { STB0899_TSTCHIP , 0x00 }, + { STB0899_TSTFREE , 0x00 }, + { STB0899_TSTI2C , 0x00 }, + { STB0899_BITSPEEDM , 0x00 }, + { STB0899_BITSPEEDL , 0x00 }, + { STB0899_TBUSBIT , 0x00 }, + { STB0899_TSTDIS , 0x00 }, + { STB0899_TSTDISRX , 0x00 }, + { STB0899_TSTJETON , 0x00 }, + { STB0899_TSTDCADJ , 0x00 }, + { STB0899_TSTAGC1 , 0x00 }, + { STB0899_TSTAGC1N , 0x00 }, + { STB0899_TSTPOLYPH , 0x00 }, + { STB0899_TSTR , 0x00 }, + { STB0899_TSTAGC2 , 0x00 }, + { STB0899_TSTCTL1 , 0x00 }, + { STB0899_TSTCTL2 , 0x00 }, + { STB0899_TSTCTL3 , 0x00 }, + { STB0899_TSTDEMAP , 0x00 }, + { STB0899_TSTDEMAP2 , 0x00 }, + { STB0899_TSTDEMMON , 0x00 }, + { STB0899_TSTRATE , 0x00 }, + { STB0899_TSTSELOUT , 0x00 }, + { STB0899_TSYNC , 0x00 }, + { STB0899_TSTERR , 0x00 }, + { STB0899_TSTRAM1 , 0x00 }, + { STB0899_TSTVSELOUT , 0x00 }, + { STB0899_TSTFORCEIN , 0x00 }, + { STB0899_TSTRS1 , 0x00 }, + { STB0899_TSTRS2 , 0x00 }, + { STB0899_TSTRS3 , 0x00 }, + { STB0899_GHOSTREG , 0x81 }, + { 0xffff , 0xff }, +}; + +#define STB0899_DVBS2_ESNO_AVE 3 +#define STB0899_DVBS2_ESNO_QUANT 32 +#define STB0899_DVBS2_AVFRAMES_COARSE 10 +#define STB0899_DVBS2_AVFRAMES_FINE 20 +#define STB0899_DVBS2_MISS_THRESHOLD 6 +#define STB0899_DVBS2_UWP_THRESHOLD_ACQ 1125 +#define STB0899_DVBS2_UWP_THRESHOLD_TRACK 758 +#define STB0899_DVBS2_UWP_THRESHOLD_SOF 1350 +#define STB0899_DVBS2_SOF_SEARCH_TIMEOUT 1664100 + +#define STB0899_DVBS2_BTR_NCO_BITS 28 +#define STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET 15 +#define STB0899_DVBS2_CRL_NCO_BITS 30 +#define STB0899_DVBS2_LDPC_MAX_ITER 70 + +#endif //__STB0899_CFG_H diff --git a/drivers/media/dvb/frontends/stb0899_drv.c b/drivers/media/dvb/frontends/stb0899_drv.c new file mode 100644 index 00000000000..52882017022 --- /dev/null +++ b/drivers/media/dvb/frontends/stb0899_drv.c @@ -0,0 +1,1684 @@ +/* + STB0899 Multistandard Frontend driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/string.h> + +#include <linux/dvb/frontend.h> +#include "dvb_frontend.h" + +#include "stb0899_drv.h" +#include "stb0899_priv.h" +#include "stb0899_reg.h" + +static unsigned int verbose = 0;//1; +module_param(verbose, int, 0644); + +/* C/N in dB/10, NIRM/NIRL */ +static const struct stb0899_tab stb0899_cn_tab[] = { + { 200, 2600 }, + { 190, 2700 }, + { 180, 2860 }, + { 170, 3020 }, + { 160, 3210 }, + { 150, 3440 }, + { 140, 3710 }, + { 130, 4010 }, + { 120, 4360 }, + { 110, 4740 }, + { 100, 5190 }, + { 90, 5670 }, + { 80, 6200 }, + { 70, 6770 }, + { 60, 7360 }, + { 50, 7970 }, + { 40, 8250 }, + { 30, 9000 }, + { 20, 9450 }, + { 15, 9600 }, +}; + +/* DVB-S AGCIQ_VALUE vs. signal level in dBm/10. + * As measured, connected to a modulator. + * -8.0 to -50.0 dBm directly connected, + * -52.0 to -74.8 with extra attenuation. + * Cut-off to AGCIQ_VALUE = 0x80 below -74.8dBm. + * Crude linear extrapolation below -84.8dBm and above -8.0dBm. + */ +static const struct stb0899_tab stb0899_dvbsrf_tab[] = { + { -950, -128 }, + { -748, -94 }, + { -745, -92 }, + { -735, -90 }, + { -720, -87 }, + { -670, -77 }, + { -640, -70 }, + { -610, -62 }, + { -600, -60 }, + { -590, -56 }, + { -560, -41 }, + { -540, -25 }, + { -530, -17 }, + { -520, -11 }, + { -500, 1 }, + { -490, 6 }, + { -480, 10 }, + { -440, 22 }, + { -420, 27 }, + { -400, 31 }, + { -380, 34 }, + { -340, 40 }, + { -320, 43 }, + { -280, 48 }, + { -250, 52 }, + { -230, 55 }, + { -180, 61 }, + { -140, 66 }, + { -90, 73 }, + { -80, 74 }, + { 500, 127 } +}; + +/* DVB-S2 IF_AGC_GAIN vs. signal level in dBm/10. + * As measured, connected to a modulator. + * -8.0 to -50.1 dBm directly connected, + * -53.0 to -76.6 with extra attenuation. + * Cut-off to IF_AGC_GAIN = 0x3fff below -76.6dBm. + * Crude linear extrapolation below -76.6dBm and above -8.0dBm. + */ +static const struct stb0899_tab stb0899_dvbs2rf_tab[] = { + { 700, 0 }, + { -80, 3217 }, + { -150, 3893 }, + { -190, 4217 }, + { -240, 4621 }, + { -280, 4945 }, + { -320, 5273 }, + { -350, 5545 }, + { -370, 5741 }, + { -410, 6147 }, + { -450, 6671 }, + { -490, 7413 }, + { -501, 7665 }, + { -530, 8767 }, + { -560, 10219 }, + { -580, 10939 }, + { -590, 11518 }, + { -600, 11723 }, + { -650, 12659 }, + { -690, 13219 }, + { -730, 13645 }, + { -750, 13909 }, + { -766, 14153 }, + { -999, 16383 } +}; + +/* DVB-S2 Es/N0 quant in dB/100 vs read value * 100*/ +struct stb0899_tab stb0899_quant_tab[] = { + { 0, 0 }, + { 0, 100 }, + { 600, 200 }, + { 950, 299 }, + { 1200, 398 }, + { 1400, 501 }, + { 1560, 603 }, + { 1690, 700 }, + { 1810, 804 }, + { 1910, 902 }, + { 2000, 1000 }, + { 2080, 1096 }, + { 2160, 1202 }, + { 2230, 1303 }, + { 2350, 1496 }, + { 2410, 1603 }, + { 2460, 1698 }, + { 2510, 1799 }, + { 2600, 1995 }, + { 2650, 2113 }, + { 2690, 2213 }, + { 2720, 2291 }, + { 2760, 2399 }, + { 2800, 2512 }, + { 2860, 2692 }, + { 2930, 2917 }, + { 2960, 3020 }, + { 3010, 3199 }, + { 3040, 3311 }, + { 3060, 3388 }, + { 3120, 3631 }, + { 3190, 3936 }, + { 3400, 5012 }, + { 3610, 6383 }, + { 3800, 7943 }, + { 4210, 12735 }, + { 4500, 17783 }, + { 4690, 22131 }, + { 4810, 25410 } +}; + +/* DVB-S2 Es/N0 estimate in dB/100 vs read value */ +struct stb0899_tab stb0899_est_tab[] = { + { 0, 0 }, + { 0, 1 }, + { 301, 2 }, + { 1204, 16 }, + { 1806, 64 }, + { 2408, 256 }, + { 2709, 512 }, + { 3010, 1023 }, + { 3311, 2046 }, + { 3612, 4093 }, + { 3823, 6653 }, + { 3913, 8185 }, + { 4010, 10233 }, + { 4107, 12794 }, + { 4214, 16368 }, + { 4266, 18450 }, + { 4311, 20464 }, + { 4353, 22542 }, + { 4391, 24604 }, + { 4425, 26607 }, + { 4457, 28642 }, + { 4487, 30690 }, + { 4515, 32734 }, + { 4612, 40926 }, + { 4692, 49204 }, + { 4816, 65464 }, + { 4913, 81846 }, + { 4993, 98401 }, + { 5060, 114815 }, + { 5118, 131220 }, + { 5200, 158489 }, + { 5300, 199526 }, + { 5400, 251189 }, + { 5500, 316228 }, + { 5600, 398107 }, + { 5720, 524807 }, + { 5721, 526017 }, +}; + +int _stb0899_read_reg(struct stb0899_state *state, unsigned int reg) +{ + int ret; + + u8 b0[] = { reg >> 8, reg & 0xff }; + u8 buf; + + struct i2c_msg msg[] = { + { + .addr = state->config->demod_address, + .flags = 0, + .buf = b0, + .len = 2 + },{ + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = &buf, + .len = 1 + } + }; + + ret = i2c_transfer(state->i2c, msg, 2); + if (ret != 2) { + if (ret != -ERESTARTSYS) + dprintk(state->verbose, FE_ERROR, 1, + "Read error, Reg=[0x%02x], Status=%d", + reg, ret); + + return ret < 0 ? ret : -EREMOTEIO; + } + if (unlikely(*state->verbose >= FE_DEBUGREG)) + dprintk(state->verbose, FE_ERROR, 1, "Reg=[0x%02x], data=%02x", + reg, buf); + + return (unsigned int)buf; +} + +int stb0899_read_reg(struct stb0899_state *state, unsigned int reg) +{ + int result; + + result = _stb0899_read_reg(state, reg); + /* + * Bug ID 9: + * access to 0xf2xx/0xf6xx + * must be followed by read from 0xf2ff/0xf6ff. + */ + if ((reg != 0xf2ff) && (reg != 0xf6ff) && + (((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600))) + _stb0899_read_reg(state, (reg | 0x00ff)); + + return result; +} + +u32 _stb0899_read_s2reg(struct stb0899_state *state, + u32 stb0899_i2cdev, + u32 stb0899_base_addr, + u16 stb0899_reg_offset) +{ + int status; + u32 data; + u8 buf[7] = { 0 }; + u16 tmpaddr; + + u8 buf_0[] = { + GETBYTE(stb0899_i2cdev, BYTE1), /* 0xf3 S2 Base Address (MSB) */ + GETBYTE(stb0899_i2cdev, BYTE0), /* 0xfc S2 Base Address (LSB) */ + GETBYTE(stb0899_base_addr, BYTE0), /* 0x00 Base Address (LSB) */ + GETBYTE(stb0899_base_addr, BYTE1), /* 0x04 Base Address (LSB) */ + GETBYTE(stb0899_base_addr, BYTE2), /* 0x00 Base Address (MSB) */ + GETBYTE(stb0899_base_addr, BYTE3), /* 0x00 Base Address (MSB) */ + }; + u8 buf_1[] = { + 0x00, /* 0xf3 Reg Offset */ + 0x00, /* 0x44 Reg Offset */ + }; + + struct i2c_msg msg_0 = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf_0, + .len = 6 + }; + + struct i2c_msg msg_1 = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf_1, + .len = 2 + }; + + struct i2c_msg msg_r = { + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = buf, + .len = 4 + }; + + tmpaddr = stb0899_reg_offset & 0xff00; + if (!(stb0899_reg_offset & 0x8)) + tmpaddr = stb0899_reg_offset | 0x20; + + buf_1[0] = GETBYTE(tmpaddr, BYTE1); + buf_1[1] = GETBYTE(tmpaddr, BYTE0); + + status = i2c_transfer(state->i2c, &msg_0, 1); + if (status < 1) { + if (status != -ERESTARTSYS) + printk(KERN_ERR "%s ERR(1), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n", + __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status); + + goto err; + } + + /* Dummy */ + status = i2c_transfer(state->i2c, &msg_1, 1); + if (status < 1) + goto err; + + status = i2c_transfer(state->i2c, &msg_r, 1); + if (status < 1) + goto err; + + buf_1[0] = GETBYTE(stb0899_reg_offset, BYTE1); + buf_1[1] = GETBYTE(stb0899_reg_offset, BYTE0); + + /* Actual */ + status = i2c_transfer(state->i2c, &msg_1, 1); + if (status < 1) { + if (status != -ERESTARTSYS) + printk(KERN_ERR "%s ERR(2), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n", + __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status); + goto err; + } + + status = i2c_transfer(state->i2c, &msg_r, 1); + if (status < 1) { + if (status != -ERESTARTSYS) + printk(KERN_ERR "%s ERR(3), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n", + __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status); + return status < 0 ? status : -EREMOTEIO; + } + + data = MAKEWORD32(buf[3], buf[2], buf[1], buf[0]); + if (unlikely(*state->verbose >= FE_DEBUGREG)) + printk(KERN_DEBUG "%s Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Data=[0x%08x]\n", + __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, data); + + return data; + +err: + return status < 0 ? status : -EREMOTEIO; +} + +int stb0899_write_s2reg(struct stb0899_state *state, + u32 stb0899_i2cdev, + u32 stb0899_base_addr, + u16 stb0899_reg_offset, + u32 stb0899_data) +{ + int status; + + /* Base Address Setup */ + u8 buf_0[] = { + GETBYTE(stb0899_i2cdev, BYTE1), /* 0xf3 S2 Base Address (MSB) */ + GETBYTE(stb0899_i2cdev, BYTE0), /* 0xfc S2 Base Address (LSB) */ + GETBYTE(stb0899_base_addr, BYTE0), /* 0x00 Base Address (LSB) */ + GETBYTE(stb0899_base_addr, BYTE1), /* 0x04 Base Address (LSB) */ + GETBYTE(stb0899_base_addr, BYTE2), /* 0x00 Base Address (MSB) */ + GETBYTE(stb0899_base_addr, BYTE3), /* 0x00 Base Address (MSB) */ + }; + u8 buf_1[] = { + 0x00, /* 0xf3 Reg Offset */ + 0x00, /* 0x44 Reg Offset */ + 0x00, /* data */ + 0x00, /* data */ + 0x00, /* data */ + 0x00, /* data */ + }; + + struct i2c_msg msg_0 = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf_0, + .len = 6 + }; + + struct i2c_msg msg_1 = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf_1, + .len = 6 + }; + + buf_1[0] = GETBYTE(stb0899_reg_offset, BYTE1); + buf_1[1] = GETBYTE(stb0899_reg_offset, BYTE0); + buf_1[2] = GETBYTE(stb0899_data, BYTE0); + buf_1[3] = GETBYTE(stb0899_data, BYTE1); + buf_1[4] = GETBYTE(stb0899_data, BYTE2); + buf_1[5] = GETBYTE(stb0899_data, BYTE3); + + if (unlikely(*state->verbose >= FE_DEBUGREG)) + printk(KERN_DEBUG "%s Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x]\n", + __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data); + + status = i2c_transfer(state->i2c, &msg_0, 1); + if (unlikely(status < 1)) { + if (status != -ERESTARTSYS) + printk(KERN_ERR "%s ERR (1), Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x], status=%d\n", + __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data, status); + goto err; + } + status = i2c_transfer(state->i2c, &msg_1, 1); + if (unlikely(status < 1)) { + if (status != -ERESTARTSYS) + printk(KERN_ERR "%s ERR (2), Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x], status=%d\n", + __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data, status); + + return status < 0 ? status : -EREMOTEIO; + } + + return 0; + +err: + return status < 0 ? status : -EREMOTEIO; +} + +int stb0899_read_regs(struct stb0899_state *state, unsigned int reg, u8 *buf, u32 count) +{ + int status; + + u8 b0[] = { reg >> 8, reg & 0xff }; + + struct i2c_msg msg[] = { + { + .addr = state->config->demod_address, + .flags = 0, + .buf = b0, + .len = 2 + },{ + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = buf, + .len = count + } + }; + + status = i2c_transfer(state->i2c, msg, 2); + if (status != 2) { + if (status != -ERESTARTSYS) + printk(KERN_ERR "%s Read error, Reg=[0x%04x], Count=%u, Status=%d\n", + __func__, reg, count, status); + goto err; + } + /* + * Bug ID 9: + * access to 0xf2xx/0xf6xx + * must be followed by read from 0xf2ff/0xf6ff. + */ + if ((reg != 0xf2ff) && (reg != 0xf6ff) && + (((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600))) + _stb0899_read_reg(state, (reg | 0x00ff)); + + if (unlikely(*state->verbose >= FE_DEBUGREG)) { + int i; + + printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg); + for (i = 0; i < count; i++) { + printk(" %02x", buf[i]); + } + printk("\n"); + } + + return 0; +err: + return status < 0 ? status : -EREMOTEIO; +} + +int stb0899_write_regs(struct stb0899_state *state, unsigned int reg, u8 *data, u32 count) +{ + int ret; + u8 buf[2 + count]; + struct i2c_msg i2c_msg = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf, + .len = 2 + count + }; + + buf[0] = reg >> 8; + buf[1] = reg & 0xff; + memcpy(&buf[2], data, count); + + if (unlikely(*state->verbose >= FE_DEBUGREG)) { + int i; + + printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg); + for (i = 0; i < count; i++) + printk(" %02x", data[i]); + printk("\n"); + } + ret = i2c_transfer(state->i2c, &i2c_msg, 1); + + /* + * Bug ID 9: + * access to 0xf2xx/0xf6xx + * must be followed by read from 0xf2ff/0xf6ff. + */ + if ((((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600))) + stb0899_read_reg(state, (reg | 0x00ff)); + + if (ret != 1) { + if (ret != -ERESTARTSYS) + dprintk(state->verbose, FE_ERROR, 1, "Reg=[0x%04x], Data=[0x%02x ...], Count=%u, Status=%d", + reg, data[0], count, ret); + return ret < 0 ? ret : -EREMOTEIO; + } + + return 0; +} + +int stb0899_write_reg(struct stb0899_state *state, unsigned int reg, u8 data) +{ + return stb0899_write_regs(state, reg, &data, 1); +} + +/* + * stb0899_get_mclk + * Get STB0899 master clock frequency + * ExtClk: external clock frequency (Hz) + */ +static u32 stb0899_get_mclk(struct stb0899_state *state) +{ + u32 mclk = 0, div = 0; + + div = stb0899_read_reg(state, STB0899_NCOARSE); + mclk = (div + 1) * state->config->xtal_freq / 6; + dprintk(state->verbose, FE_DEBUG, 1, "div=%d, mclk=%d", div, mclk); + + return mclk; +} + +/* + * stb0899_set_mclk + * Set STB0899 master Clock frequency + * Mclk: demodulator master clock + * ExtClk: external clock frequency (Hz) + */ +static void stb0899_set_mclk(struct stb0899_state *state, u32 Mclk) +{ + struct stb0899_internal *internal = &state->internal; + u8 mdiv = 0; + + dprintk(state->verbose, FE_DEBUG, 1, "state->config=%p", state->config); + mdiv = ((6 * Mclk) / state->config->xtal_freq) - 1; + dprintk(state->verbose, FE_DEBUG, 1, "mdiv=%d", mdiv); + + stb0899_write_reg(state, STB0899_NCOARSE, mdiv); + internal->master_clk = stb0899_get_mclk(state); + + dprintk(state->verbose, FE_DEBUG, 1, "MasterCLOCK=%d", internal->master_clk); +} + +static int stb0899_postproc(struct stb0899_state *state, u8 ctl, int enable) +{ + struct stb0899_config *config = state->config; + const struct stb0899_postproc *postproc = config->postproc; + + /* post process event */ + if (postproc) { + if (enable) { + if (postproc[ctl].level == STB0899_GPIOPULLUP) + stb0899_write_reg(state, postproc[ctl].gpio, 0x02); + else + stb0899_write_reg(state, postproc[ctl].gpio, 0x82); + } else { + if (postproc[ctl].level == STB0899_GPIOPULLUP) + stb0899_write_reg(state, postproc[ctl].gpio, 0x82); + else + stb0899_write_reg(state, postproc[ctl].gpio, 0x02); + } + } + return 0; +} + +static void stb0899_release(struct dvb_frontend *fe) +{ + struct stb0899_state *state = fe->demodulator_priv; + + dprintk(state->verbose, FE_DEBUG, 1, "Release Frontend"); + /* post process event */ + stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 0); + kfree(state); +} + +/* + * stb0899_get_alpha + * return: rolloff + */ +static int stb0899_get_alpha(struct stb0899_state *state) +{ + u8 mode_coeff; + + mode_coeff = stb0899_read_reg(state, STB0899_DEMOD); + + if (STB0899_GETFIELD(MODECOEFF, mode_coeff) == 1) + return 20; + else + return 35; +} + +/* + * stb0899_init_calc + */ +static void stb0899_init_calc(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + int master_clk; + u8 agc[2]; + u8 agc1cn; + u32 reg; + + /* Read registers (in burst mode) */ + agc1cn = stb0899_read_reg(state, STB0899_AGC1CN); + stb0899_read_regs(state, STB0899_AGC1REF, agc, 2); /* AGC1R and AGC2O */ + + /* Initial calculations */ + master_clk = stb0899_get_mclk(state); + internal->t_agc1 = 0; + internal->t_agc2 = 0; + internal->master_clk = master_clk; + internal->mclk = master_clk / 65536L; + internal->rolloff = stb0899_get_alpha(state); + + /* DVBS2 Initial calculations */ + /* Set AGC value to the middle */ + internal->agc_gain = 8154; + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL); + STB0899_SETFIELD_VAL(IF_GAIN_INIT, reg, internal->agc_gain); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, RRC_ALPHA); + internal->rrc_alpha = STB0899_GETFIELD(RRC_ALPHA, reg); + + internal->center_freq = 0; + internal->av_frame_coarse = 10; + internal->av_frame_fine = 20; + internal->step_size = 2; +/* + if ((pParams->SpectralInv == FE_IQ_NORMAL) || (pParams->SpectralInv == FE_IQ_AUTO)) + pParams->IQLocked = 0; + else + pParams->IQLocked = 1; +*/ +} + +static int stb0899_wait_diseqc_fifo_empty(struct stb0899_state *state, int timeout) +{ + u8 reg = 0; + unsigned long start = jiffies; + + while (1) { + reg = stb0899_read_reg(state, STB0899_DISSTATUS); + if (!STB0899_GETFIELD(FIFOFULL, reg)) + break; + if ((jiffies - start) > timeout) { + dprintk(state->verbose, FE_ERROR, 1, "timed out !!"); + return -ETIMEDOUT; + } + } + + return 0; +} + +static int stb0899_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) +{ + struct stb0899_state *state = fe->demodulator_priv; + u8 reg, i; + + if (cmd->msg_len > 8) + return -EINVAL; + + /* enable FIFO precharge */ + reg = stb0899_read_reg(state, STB0899_DISCNTRL1); + STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 1); + stb0899_write_reg(state, STB0899_DISCNTRL1, reg); + for (i = 0; i < cmd->msg_len; i++) { + /* wait for FIFO empty */ + if (stb0899_wait_diseqc_fifo_empty(state, 10) < 0) + return -ETIMEDOUT; + + stb0899_write_reg(state, STB0899_DISFIFO, cmd->msg[i]); + } + reg = stb0899_read_reg(state, STB0899_DISCNTRL1); + STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0); + stb0899_write_reg(state, STB0899_DISCNTRL1, reg); + + return 0; +} + +static int stb0899_wait_diseqc_rxidle(struct stb0899_state *state, int timeout) +{ + u8 reg = 0; + unsigned long start = jiffies; + + while (!STB0899_GETFIELD(RXEND, reg)) { + reg = stb0899_read_reg(state, STB0899_DISRX_ST0); + if (jiffies - start > timeout) { + dprintk(state->verbose, FE_ERROR, 1, "timed out!!"); + return -ETIMEDOUT; + } + msleep(10); + } + + return 0; +} + +static int stb0899_recv_slave_reply(struct dvb_frontend *fe, struct dvb_diseqc_slave_reply *reply) +{ + struct stb0899_state *state = fe->demodulator_priv; + u8 reg, length = 0, i; + int result; + + if (stb0899_wait_diseqc_rxidle(state, 100) < 0) + return -ETIMEDOUT; + + reg = stb0899_read_reg(state, STB0899_DISRX_ST0); + if (STB0899_GETFIELD(RXEND, reg)) { + + reg = stb0899_read_reg(state, STB0899_DISRX_ST1); + length = STB0899_GETFIELD(FIFOBYTENBR, reg); + + if (length > sizeof (reply->msg)) { + result = -EOVERFLOW; + goto exit; + } + reply->msg_len = length; + + /* extract data */ + for (i = 0; i < length; i++) + reply->msg[i] = stb0899_read_reg(state, STB0899_DISFIFO); + } + + return 0; +exit: + + return result; +} + +static int stb0899_wait_diseqc_txidle(struct stb0899_state *state, int timeout) +{ + u8 reg = 0; + unsigned long start = jiffies; + + while (!STB0899_GETFIELD(TXIDLE, reg)) { + reg = stb0899_read_reg(state, STB0899_DISSTATUS); + if (jiffies - start > timeout) { + dprintk(state->verbose, FE_ERROR, 1, "timed out!!"); + return -ETIMEDOUT; + } + msleep(10); + } + return 0; +} + +static int stb0899_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst) +{ + struct stb0899_state *state = fe->demodulator_priv; + u8 reg, old_state; + + /* wait for diseqc idle */ + if (stb0899_wait_diseqc_txidle(state, 100) < 0) + return -ETIMEDOUT; + + reg = stb0899_read_reg(state, STB0899_DISCNTRL1); + old_state = reg; + /* set to burst mode */ + STB0899_SETFIELD_VAL(DISEQCMODE, reg, 0x02); + STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0x01); + stb0899_write_reg(state, STB0899_DISCNTRL1, reg); + switch (burst) { + case SEC_MINI_A: + /* unmodulated */ + stb0899_write_reg(state, STB0899_DISFIFO, 0x00); + break; + case SEC_MINI_B: + /* modulated */ + stb0899_write_reg(state, STB0899_DISFIFO, 0xff); + break; + } + reg = stb0899_read_reg(state, STB0899_DISCNTRL1); + STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0x00); + stb0899_write_reg(state, STB0899_DISCNTRL1, reg); + /* wait for diseqc idle */ + if (stb0899_wait_diseqc_txidle(state, 100) < 0) + return -ETIMEDOUT; + + /* restore state */ + stb0899_write_reg(state, STB0899_DISCNTRL1, old_state); + + return 0; +} + +static int stb0899_diseqc_init(struct stb0899_state *state) +{ + struct dvb_diseqc_master_cmd tx_data; +/* + struct dvb_diseqc_slave_reply rx_data; +*/ + u8 f22_tx, f22_rx, reg; + + u32 mclk, tx_freq = 22000;/* count = 0, i; */ + tx_data.msg[0] = 0xe2; + tx_data.msg_len = 3; + reg = stb0899_read_reg(state, STB0899_DISCNTRL2); + STB0899_SETFIELD_VAL(ONECHIP_TRX, reg, 0); + stb0899_write_reg(state, STB0899_DISCNTRL2, reg); + + /* disable Tx spy */ + reg = stb0899_read_reg(state, STB0899_DISCNTRL1); + STB0899_SETFIELD_VAL(DISEQCRESET, reg, 1); + stb0899_write_reg(state, STB0899_DISCNTRL1, reg); + + reg = stb0899_read_reg(state, STB0899_DISCNTRL1); + STB0899_SETFIELD_VAL(DISEQCRESET, reg, 0); + stb0899_write_reg(state, STB0899_DISCNTRL1, reg); + + mclk = stb0899_get_mclk(state); + f22_tx = mclk / (tx_freq * 32); + stb0899_write_reg(state, STB0899_DISF22, f22_tx); /* DiSEqC Tx freq */ + state->rx_freq = 20000; + f22_rx = mclk / (state->rx_freq * 32); + + return 0; +} + +static int stb0899_sleep(struct dvb_frontend *fe) +{ + struct stb0899_state *state = fe->demodulator_priv; +/* + u8 reg; +*/ + dprintk(state->verbose, FE_DEBUG, 1, "Going to Sleep .. (Really tired .. :-))"); + /* post process event */ + stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 0); + + return 0; +} + +static int stb0899_wakeup(struct dvb_frontend *fe) +{ + int rc; + struct stb0899_state *state = fe->demodulator_priv; + + if ((rc = stb0899_write_reg(state, STB0899_SYNTCTRL, STB0899_SELOSCI))) + return rc; + /* Activate all clocks; DVB-S2 registers are inaccessible otherwise. */ + if ((rc = stb0899_write_reg(state, STB0899_STOPCLK1, 0x00))) + return rc; + if ((rc = stb0899_write_reg(state, STB0899_STOPCLK2, 0x00))) + return rc; + + /* post process event */ + stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 1); + + return 0; +} + +static int stb0899_init(struct dvb_frontend *fe) +{ + int i; + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_config *config = state->config; + + dprintk(state->verbose, FE_DEBUG, 1, "Initializing STB0899 ... "); + + /* init device */ + dprintk(state->verbose, FE_DEBUG, 1, "init device"); + for (i = 0; config->init_dev[i].address != 0xffff; i++) + stb0899_write_reg(state, config->init_dev[i].address, config->init_dev[i].data); + + dprintk(state->verbose, FE_DEBUG, 1, "init S2 demod"); + /* init S2 demod */ + for (i = 0; config->init_s2_demod[i].offset != 0xffff; i++) + stb0899_write_s2reg(state, STB0899_S2DEMOD, + config->init_s2_demod[i].base_address, + config->init_s2_demod[i].offset, + config->init_s2_demod[i].data); + + dprintk(state->verbose, FE_DEBUG, 1, "init S1 demod"); + /* init S1 demod */ + for (i = 0; config->init_s1_demod[i].address != 0xffff; i++) + stb0899_write_reg(state, config->init_s1_demod[i].address, config->init_s1_demod[i].data); + + dprintk(state->verbose, FE_DEBUG, 1, "init S2 FEC"); + /* init S2 fec */ + for (i = 0; config->init_s2_fec[i].offset != 0xffff; i++) + stb0899_write_s2reg(state, STB0899_S2FEC, + config->init_s2_fec[i].base_address, + config->init_s2_fec[i].offset, + config->init_s2_fec[i].data); + + dprintk(state->verbose, FE_DEBUG, 1, "init TST"); + /* init test */ + for (i = 0; config->init_tst[i].address != 0xffff; i++) + stb0899_write_reg(state, config->init_tst[i].address, config->init_tst[i].data); + + stb0899_init_calc(state); + stb0899_diseqc_init(state); + + return 0; +} + +static int stb0899_table_lookup(const struct stb0899_tab *tab, int max, int val) +{ + int res = 0; + int min = 0, med; + + if (val < tab[min].read) + res = tab[min].real; + else if (val >= tab[max].read) + res = tab[max].real; + else { + while ((max - min) > 1) { + med = (max + min) / 2; + if (val >= tab[min].read && val < tab[med].read) + max = med; + else + min = med; + } + res = ((val - tab[min].read) * + (tab[max].real - tab[min].real) / + (tab[max].read - tab[min].read)) + + tab[min].real; + } + + return res; +} + +static int stb0899_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_internal *internal = &state->internal; + + int val; + u32 reg; + switch (state->delsys) { + case SYS_DVBS: + case SYS_DSS: + if (internal->lock) { + reg = stb0899_read_reg(state, STB0899_VSTATUS); + if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) { + + reg = stb0899_read_reg(state, STB0899_AGCIQIN); + val = (s32)(s8)STB0899_GETFIELD(AGCIQVALUE, reg); + + *strength = stb0899_table_lookup(stb0899_dvbsrf_tab, ARRAY_SIZE(stb0899_dvbsrf_tab) - 1, val); + *strength += 750; + dprintk(state->verbose, FE_DEBUG, 1, "AGCIQVALUE = 0x%02x, C = %d * 0.1 dBm", + val & 0xff, *strength); + } + } + break; + case SYS_DVBS2: + if (internal->lock) { + reg = STB0899_READ_S2REG(STB0899_DEMOD, IF_AGC_GAIN); + val = STB0899_GETFIELD(IF_AGC_GAIN, reg); + + *strength = stb0899_table_lookup(stb0899_dvbs2rf_tab, ARRAY_SIZE(stb0899_dvbs2rf_tab) - 1, val); + *strength += 750; + dprintk(state->verbose, FE_DEBUG, 1, "IF_AGC_GAIN = 0x%04x, C = %d * 0.1 dBm", + val & 0x3fff, *strength); + } + break; + default: + dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system"); + return -EINVAL; + } + + return 0; +} + +static int stb0899_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_internal *internal = &state->internal; + + unsigned int val, quant, quantn = -1, est, estn = -1; + u8 buf[2]; + u32 reg; + + reg = stb0899_read_reg(state, STB0899_VSTATUS); + switch (state->delsys) { + case SYS_DVBS: + case SYS_DSS: + if (internal->lock) { + if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) { + + stb0899_read_regs(state, STB0899_NIRM, buf, 2); + val = MAKEWORD16(buf[0], buf[1]); + + *snr = stb0899_table_lookup(stb0899_cn_tab, ARRAY_SIZE(stb0899_cn_tab) - 1, val); + dprintk(state->verbose, FE_DEBUG, 1, "NIR = 0x%02x%02x = %u, C/N = %d * 0.1 dBm\n", + buf[0], buf[1], val, *snr); + } + } + break; + case SYS_DVBS2: + if (internal->lock) { + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL1); + quant = STB0899_GETFIELD(UWP_ESN0_QUANT, reg); + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2); + est = STB0899_GETFIELD(ESN0_EST, reg); + if (est == 1) + val = 301; /* C/N = 30.1 dB */ + else if (est == 2) + val = 270; /* C/N = 27.0 dB */ + else { + /* quantn = 100 * log(quant^2) */ + quantn = stb0899_table_lookup(stb0899_quant_tab, ARRAY_SIZE(stb0899_quant_tab) - 1, quant * 100); + /* estn = 100 * log(est) */ + estn = stb0899_table_lookup(stb0899_est_tab, ARRAY_SIZE(stb0899_est_tab) - 1, est); + /* snr(dBm/10) = -10*(log(est)-log(quant^2)) => snr(dBm/10) = (100*log(quant^2)-100*log(est))/10 */ + val = (quantn - estn) / 10; + } + *snr = val; + dprintk(state->verbose, FE_DEBUG, 1, "Es/N0 quant = %d (%d) estimate = %u (%d), C/N = %d * 0.1 dBm", + quant, quantn, est, estn, val); + } + break; + default: + dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system"); + return -EINVAL; + } + + return 0; +} + +static int stb0899_read_status(struct dvb_frontend *fe, enum fe_status *status) +{ + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_internal *internal = &state->internal; + u8 reg; + *status = 0; + + switch (state->delsys) { + case SYS_DVBS: + case SYS_DSS: + dprintk(state->verbose, FE_DEBUG, 1, "Delivery system DVB-S/DSS"); + if (internal->lock) { + reg = stb0899_read_reg(state, STB0899_VSTATUS); + if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) { + dprintk(state->verbose, FE_DEBUG, 1, "--------> FE_HAS_CARRIER | FE_HAS_LOCK"); + *status |= FE_HAS_CARRIER | FE_HAS_LOCK; + + reg = stb0899_read_reg(state, STB0899_PLPARM); + if (STB0899_GETFIELD(VITCURPUN, reg)) { + dprintk(state->verbose, FE_DEBUG, 1, "--------> FE_HAS_VITERBI | FE_HAS_SYNC"); + *status |= FE_HAS_VITERBI | FE_HAS_SYNC; + /* post process event */ + stb0899_postproc(state, STB0899_POSTPROC_GPIO_LOCK, 1); + } + } + } + break; + case SYS_DVBS2: + dprintk(state->verbose, FE_DEBUG, 1, "Delivery system DVB-S2"); + if (internal->lock) { + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STAT2); + if (STB0899_GETFIELD(UWP_LOCK, reg) && STB0899_GETFIELD(CSM_LOCK, reg)) { + *status |= FE_HAS_CARRIER; + dprintk(state->verbose, FE_DEBUG, 1, + "UWP & CSM Lock ! ---> DVB-S2 FE_HAS_CARRIER"); + + reg = stb0899_read_reg(state, STB0899_CFGPDELSTATUS1); + if (STB0899_GETFIELD(CFGPDELSTATUS_LOCK, reg)) { + *status |= FE_HAS_LOCK; + dprintk(state->verbose, FE_DEBUG, 1, + "Packet Delineator Locked ! -----> DVB-S2 FE_HAS_LOCK"); + + } + if (STB0899_GETFIELD(CONTINUOUS_STREAM, reg)) { + *status |= FE_HAS_VITERBI; + dprintk(state->verbose, FE_DEBUG, 1, + "Packet Delineator found VITERBI ! -----> DVB-S2 FE_HAS_VITERBI"); + } + if (STB0899_GETFIELD(ACCEPTED_STREAM, reg)) { + *status |= FE_HAS_SYNC; + dprintk(state->verbose, FE_DEBUG, 1, + "Packet Delineator found SYNC ! -----> DVB-S2 FE_HAS_SYNC"); + /* post process event */ + stb0899_postproc(state, STB0899_POSTPROC_GPIO_LOCK, 1); + } + } + } + break; + default: + dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system"); + return -EINVAL; + } + return 0; +} + +/* + * stb0899_get_error + * viterbi error for DVB-S/DSS + * packet error for DVB-S2 + * Bit Error Rate or Packet Error Rate * 10 ^ 7 + */ +static int stb0899_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_internal *internal = &state->internal; + + u8 lsb, msb; + u32 i; + + *ber = 0; + + switch (state->delsys) { + case SYS_DVBS: + case SYS_DSS: + if (internal->lock) { + /* average 5 BER values */ + for (i = 0; i < 5; i++) { + msleep(100); + lsb = stb0899_read_reg(state, STB0899_ECNT1L); + msb = stb0899_read_reg(state, STB0899_ECNT1M); + *ber += MAKEWORD16(msb, lsb); + } + *ber /= 5; + /* Viterbi Check */ + if (STB0899_GETFIELD(VSTATUS_PRFVIT, internal->v_status)) { + /* Error Rate */ + *ber *= 9766; + /* ber = ber * 10 ^ 7 */ + *ber /= (-1 + (1 << (2 * STB0899_GETFIELD(NOE, internal->err_ctrl)))); + *ber /= 8; + } + } + break; + case SYS_DVBS2: + if (internal->lock) { + /* Average 5 PER values */ + for (i = 0; i < 5; i++) { + msleep(100); + lsb = stb0899_read_reg(state, STB0899_ECNT1L); + msb = stb0899_read_reg(state, STB0899_ECNT1M); + *ber += MAKEWORD16(msb, lsb); + } + /* ber = ber * 10 ^ 7 */ + *ber *= 10000000; + *ber /= (-1 + (1 << (4 + 2 * STB0899_GETFIELD(NOE, internal->err_ctrl)))); + } + break; + default: + dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system"); + return -EINVAL; + } + + return 0; +} + +static int stb0899_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct stb0899_state *state = fe->demodulator_priv; + + switch (voltage) { + case SEC_VOLTAGE_13: + stb0899_write_reg(state, STB0899_GPIO00CFG, 0x82); + stb0899_write_reg(state, STB0899_GPIO01CFG, 0x02); + stb0899_write_reg(state, STB0899_GPIO02CFG, 0x00); + break; + case SEC_VOLTAGE_18: + stb0899_write_reg(state, STB0899_GPIO00CFG, 0x02); + stb0899_write_reg(state, STB0899_GPIO01CFG, 0x02); + stb0899_write_reg(state, STB0899_GPIO02CFG, 0x82); + break; + case SEC_VOLTAGE_OFF: + stb0899_write_reg(state, STB0899_GPIO00CFG, 0x82); + stb0899_write_reg(state, STB0899_GPIO01CFG, 0x82); + stb0899_write_reg(state, STB0899_GPIO02CFG, 0x82); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int stb0899_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +{ + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_internal *internal = &state->internal; + + u8 div, reg; + + /* wait for diseqc idle */ + if (stb0899_wait_diseqc_txidle(state, 100) < 0) + return -ETIMEDOUT; + + switch (tone) { + case SEC_TONE_ON: + div = (internal->master_clk / 100) / 5632; + div = (div + 5) / 10; + stb0899_write_reg(state, STB0899_DISEQCOCFG, 0x66); + reg = stb0899_read_reg(state, STB0899_ACRPRESC); + STB0899_SETFIELD_VAL(ACRPRESC, reg, 0x03); + stb0899_write_reg(state, STB0899_ACRPRESC, reg); + stb0899_write_reg(state, STB0899_ACRDIV1, div); + break; + case SEC_TONE_OFF: + stb0899_write_reg(state, STB0899_DISEQCOCFG, 0x20); + break; + default: + return -EINVAL; + } + return 0; +} + +int stb0899_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + int i2c_stat; + struct stb0899_state *state = fe->demodulator_priv; + + i2c_stat = stb0899_read_reg(state, STB0899_I2CRPT); + if (i2c_stat < 0) + goto err; + + if (enable) { + dprintk(state->verbose, FE_DEBUG, 1, "Enabling I2C Repeater ..."); + i2c_stat |= STB0899_I2CTON; + if (stb0899_write_reg(state, STB0899_I2CRPT, i2c_stat) < 0) + goto err; + } else { + dprintk(state->verbose, FE_DEBUG, 1, "Disabling I2C Repeater ..."); + i2c_stat &= ~STB0899_I2CTON; + if (stb0899_write_reg(state, STB0899_I2CRPT, i2c_stat) < 0) + goto err; + } + return 0; +err: + dprintk(state->verbose, FE_ERROR, 1, "I2C Repeater control failed"); + return -EREMOTEIO; +} + + +static inline void CONVERT32(u32 x, char *str) +{ + *str++ = (x >> 24) & 0xff; + *str++ = (x >> 16) & 0xff; + *str++ = (x >> 8) & 0xff; + *str++ = (x >> 0) & 0xff; + *str = '\0'; +} + +int stb0899_get_dev_id(struct stb0899_state *state) +{ + u8 chip_id, release; + u16 id; + u32 demod_ver = 0, fec_ver = 0; + char demod_str[5] = { 0 }; + char fec_str[5] = { 0 }; + + id = stb0899_read_reg(state, STB0899_DEV_ID); + dprintk(state->verbose, FE_DEBUG, 1, "ID reg=[0x%02x]", id); + chip_id = STB0899_GETFIELD(CHIP_ID, id); + release = STB0899_GETFIELD(CHIP_REL, id); + + dprintk(state->verbose, FE_ERROR, 1, "Device ID=[%d], Release=[%d]", + chip_id, release); + + CONVERT32(STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CORE_ID), (char *)&demod_str); + + demod_ver = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_VERSION_ID); + dprintk(state->verbose, FE_ERROR, 1, "Demodulator Core ID=[%s], Version=[%d]", (char *) &demod_str, demod_ver); + CONVERT32(STB0899_READ_S2REG(STB0899_S2FEC, FEC_CORE_ID_REG), (char *)&fec_str); + fec_ver = STB0899_READ_S2REG(STB0899_S2FEC, FEC_VER_ID_REG); + if (! (chip_id > 0)) { + dprintk(state->verbose, FE_ERROR, 1, "couldn't find a STB 0899"); + + return -ENODEV; + } + dprintk(state->verbose, FE_ERROR, 1, "FEC Core ID=[%s], Version=[%d]", (char*) &fec_str, fec_ver); + + return 0; +} + +static void stb0899_set_delivery(struct stb0899_state *state) +{ + u8 reg; + u8 stop_clk[2]; + + stop_clk[0] = stb0899_read_reg(state, STB0899_STOPCLK1); + stop_clk[1] = stb0899_read_reg(state, STB0899_STOPCLK2); + + switch (state->delsys) { + case SYS_DVBS: + dprintk(state->verbose, FE_DEBUG, 1, "Delivery System -- DVB-S"); + /* FECM/Viterbi ON */ + reg = stb0899_read_reg(state, STB0899_FECM); + STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 0); + STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 1); + stb0899_write_reg(state, STB0899_FECM, reg); + + stb0899_write_reg(state, STB0899_RSULC, 0xb1); + stb0899_write_reg(state, STB0899_TSULC, 0x40); + stb0899_write_reg(state, STB0899_RSLLC, 0x42); + stb0899_write_reg(state, STB0899_TSLPL, 0x12); + + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESLDPC, reg, 1); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1); + STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 1); + STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 1); + + STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 1); + STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 1); + + STB0899_SETFIELD_VAL(STOP_CKINTBUF216, stop_clk[0], 1); + STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0); + + STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 1); + break; + case SYS_DVBS2: + /* FECM/Viterbi OFF */ + reg = stb0899_read_reg(state, STB0899_FECM); + STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 0); + STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 0); + stb0899_write_reg(state, STB0899_FECM, reg); + + stb0899_write_reg(state, STB0899_RSULC, 0xb1); + stb0899_write_reg(state, STB0899_TSULC, 0x42); + stb0899_write_reg(state, STB0899_RSLLC, 0x40); + stb0899_write_reg(state, STB0899_TSLPL, 0x02); + + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESLDPC, reg, 0); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1); + STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 0); + STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 0); + + STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 0); + STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 0); + + STB0899_SETFIELD_VAL(STOP_CKINTBUF216, stop_clk[0], 0); + STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0); + + STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 0); + break; + case SYS_DSS: + /* FECM/Viterbi ON */ + reg = stb0899_read_reg(state, STB0899_FECM); + STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 1); + STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 1); + stb0899_write_reg(state, STB0899_FECM, reg); + + stb0899_write_reg(state, STB0899_RSULC, 0xa1); + stb0899_write_reg(state, STB0899_TSULC, 0x61); + stb0899_write_reg(state, STB0899_RSLLC, 0x42); + + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESLDPC, reg, 1); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1); + STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 1); + STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 1); + + STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 1); + STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 1); + + STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0); + + STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 1); + break; + default: + dprintk(state->verbose, FE_ERROR, 1, "Unsupported delivery system"); + break; + } + STB0899_SETFIELD_VAL(STOP_CKADCI108, stop_clk[0], 0); + stb0899_write_regs(state, STB0899_STOPCLK1, stop_clk, 2); +} + +/* + * stb0899_set_iterations + * set the LDPC iteration scale function + */ +static void stb0899_set_iterations(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_config *config = state->config; + + s32 iter_scale; + u32 reg; + + iter_scale = 17 * (internal->master_clk / 1000); + iter_scale += 410000; + iter_scale /= (internal->srate / 1000000); + iter_scale /= 1000; + + if (iter_scale > config->ldpc_max_iter) + iter_scale = config->ldpc_max_iter; + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, MAX_ITER); + STB0899_SETFIELD_VAL(MAX_ITERATIONS, reg, iter_scale); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_MAX_ITER, STB0899_OFF0_MAX_ITER, reg); +} + +static enum dvbfe_search stb0899_search(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +{ + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_params *i_params = &state->params; + struct stb0899_internal *internal = &state->internal; + struct stb0899_config *config = state->config; + struct dtv_frontend_properties *props = &fe->dtv_property_cache; + + u32 SearchRange, gain; + + i_params->freq = p->frequency; + i_params->srate = p->u.qpsk.symbol_rate; + state->delsys = props->delivery_system; + dprintk(state->verbose, FE_DEBUG, 1, "delivery system=%d", state->delsys); + + SearchRange = 10000000; + dprintk(state->verbose, FE_DEBUG, 1, "Frequency=%d, Srate=%d", i_params->freq, i_params->srate); + /* checking Search Range is meaningless for a fixed 3 Mhz */ + if (INRANGE(i_params->srate, 1000000, 45000000)) { + dprintk(state->verbose, FE_DEBUG, 1, "Parameters IN RANGE"); + stb0899_set_delivery(state); + + if (state->config->tuner_set_rfsiggain) { + if (internal->srate > 15000000) + gain = 8; /* 15Mb < srate < 45Mb, gain = 8dB */ + else if (internal->srate > 5000000) + gain = 12; /* 5Mb < srate < 15Mb, gain = 12dB */ + else + gain = 14; /* 1Mb < srate < 5Mb, gain = 14db */ + state->config->tuner_set_rfsiggain(fe, gain); + } + + if (i_params->srate <= 5000000) + stb0899_set_mclk(state, config->lo_clk); + else + stb0899_set_mclk(state, config->hi_clk); + + switch (state->delsys) { + case SYS_DVBS: + case SYS_DSS: + dprintk(state->verbose, FE_DEBUG, 1, "DVB-S delivery system"); + internal->freq = i_params->freq; + internal->srate = i_params->srate; + /* + * search = user search range + + * 500Khz + + * 2 * Tuner_step_size + + * 10% of the symbol rate + */ + internal->srch_range = SearchRange + 1500000 + (i_params->srate / 5); + internal->derot_percent = 30; + + /* What to do for tuners having no bandwidth setup ? */ + /* enable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 1); + + if (state->config->tuner_set_bandwidth) + state->config->tuner_set_bandwidth(fe, (13 * (stb0899_carr_width(state) + SearchRange)) / 10); + if (state->config->tuner_get_bandwidth) + state->config->tuner_get_bandwidth(fe, &internal->tuner_bw); + + /* disable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 0); + + /* Set DVB-S1 AGC */ + stb0899_write_reg(state, STB0899_AGCRFCFG, 0x11); + + /* Run the search algorithm */ + dprintk(state->verbose, FE_DEBUG, 1, "running DVB-S search algo .."); + if (stb0899_dvbs_algo(state) == RANGEOK) { + internal->lock = 1; + dprintk(state->verbose, FE_DEBUG, 1, + "-------------------------------------> DVB-S LOCK !"); + +// stb0899_write_reg(state, STB0899_ERRCTRL1, 0x3d); /* Viterbi Errors */ +// internal->v_status = stb0899_read_reg(state, STB0899_VSTATUS); +// internal->err_ctrl = stb0899_read_reg(state, STB0899_ERRCTRL1); +// dprintk(state->verbose, FE_DEBUG, 1, "VSTATUS=0x%02x", internal->v_status); +// dprintk(state->verbose, FE_DEBUG, 1, "ERR_CTRL=0x%02x", internal->err_ctrl); + + return DVBFE_ALGO_SEARCH_SUCCESS; + } else { + internal->lock = 0; + + return DVBFE_ALGO_SEARCH_FAILED; + } + break; + case SYS_DVBS2: + internal->freq = i_params->freq; + internal->srate = i_params->srate; + internal->srch_range = SearchRange; + + /* enable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 1); + + if (state->config->tuner_set_bandwidth) + state->config->tuner_set_bandwidth(fe, (stb0899_carr_width(state) + SearchRange)); + if (state->config->tuner_get_bandwidth) + state->config->tuner_get_bandwidth(fe, &internal->tuner_bw); + + /* disable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 0); + +// pParams->SpectralInv = pSearch->IQ_Inversion; + + /* Set DVB-S2 AGC */ + stb0899_write_reg(state, STB0899_AGCRFCFG, 0x1c); + + /* Set IterScale =f(MCLK,SYMB) */ + stb0899_set_iterations(state); + + /* Run the search algorithm */ + dprintk(state->verbose, FE_DEBUG, 1, "running DVB-S2 search algo .."); + if (stb0899_dvbs2_algo(state) == DVBS2_FEC_LOCK) { + internal->lock = 1; + dprintk(state->verbose, FE_DEBUG, 1, + "-------------------------------------> DVB-S2 LOCK !"); + +// stb0899_write_reg(state, STB0899_ERRCTRL1, 0xb6); /* Packet Errors */ +// internal->v_status = stb0899_read_reg(state, STB0899_VSTATUS); +// internal->err_ctrl = stb0899_read_reg(state, STB0899_ERRCTRL1); + + return DVBFE_ALGO_SEARCH_SUCCESS; + } else { + internal->lock = 0; + + return DVBFE_ALGO_SEARCH_FAILED; + } + break; + default: + dprintk(state->verbose, FE_ERROR, 1, "Unsupported delivery system"); + return DVBFE_ALGO_SEARCH_INVALID; + } + } + + return DVBFE_ALGO_SEARCH_ERROR; +} +/* + * stb0899_track + * periodically check the signal level against a specified + * threshold level and perform derotator centering. + * called once we have a lock from a succesful search + * event. + * + * Will be called periodically called to maintain the + * lock. + * + * Will be used to get parameters as well as info from + * the decoded baseband header + * + * Once a new lock has established, the internal state + * frequency (internal->freq) is updated + */ +static int stb0899_track(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +{ + return 0; +} + +static int stb0899_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +{ + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_internal *internal = &state->internal; + + dprintk(state->verbose, FE_DEBUG, 1, "Get params"); + p->u.qpsk.symbol_rate = internal->srate; + + return 0; +} + +static enum dvbfe_algo stb0899_frontend_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_CUSTOM; +} + +static struct dvb_frontend_ops stb0899_ops = { + + .info = { + .name = "STB0899 Multistandard", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 0, + .frequency_tolerance = 0, + .symbol_rate_min = 5000000, + .symbol_rate_max = 45000000, + + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK + }, + + .release = stb0899_release, + .init = stb0899_init, + .sleep = stb0899_sleep, +// .wakeup = stb0899_wakeup, + + .i2c_gate_ctrl = stb0899_i2c_gate_ctrl, + + .get_frontend_algo = stb0899_frontend_algo, + .search = stb0899_search, + .track = stb0899_track, + .get_frontend = stb0899_get_frontend, + + + .read_status = stb0899_read_status, + .read_snr = stb0899_read_snr, + .read_signal_strength = stb0899_read_signal_strength, + .read_ber = stb0899_read_ber, + + .set_voltage = stb0899_set_voltage, + .set_tone = stb0899_set_tone, + + .diseqc_send_master_cmd = stb0899_send_diseqc_msg, + .diseqc_recv_slave_reply = stb0899_recv_slave_reply, + .diseqc_send_burst = stb0899_send_diseqc_burst, +}; + +struct dvb_frontend *stb0899_attach(struct stb0899_config *config, struct i2c_adapter *i2c) +{ + struct stb0899_state *state = NULL; + enum stb0899_inversion inversion; + + state = kzalloc(sizeof (struct stb0899_state), GFP_KERNEL); + if (state == NULL) + goto error; + + inversion = config->inversion; + state->verbose = &verbose; + state->config = config; + state->i2c = i2c; + state->frontend.ops = stb0899_ops; + state->frontend.demodulator_priv = state; + state->internal.inversion = inversion; + + stb0899_wakeup(&state->frontend); + if (stb0899_get_dev_id(state) == -ENODEV) { + printk("%s: Exiting .. !\n", __func__); + goto error; + } + + printk("%s: Attaching STB0899 \n", __func__); + return &state->frontend; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(stb0899_attach); +MODULE_PARM_DESC(verbose, "Set Verbosity level"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_DESCRIPTION("STB0899 Multi-Std frontend"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/stb0899_drv.h b/drivers/media/dvb/frontends/stb0899_drv.h new file mode 100644 index 00000000000..98b200ce0c3 --- /dev/null +++ b/drivers/media/dvb/frontends/stb0899_drv.h @@ -0,0 +1,162 @@ +/* + STB0899 Multistandard Frontend driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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 __STB0899_DRV_H +#define __STB0899_DRV_H + +#include <linux/kernel.h> +#include <linux/module.h> + +#include "dvb_frontend.h" + +#define STB0899_TSMODE_SERIAL 1 +#define STB0899_CLKPOL_FALLING 2 +#define STB0899_CLKNULL_PARITY 3 +#define STB0899_SYNC_FORCED 4 +#define STB0899_FECMODE_DSS 5 + +struct stb0899_s1_reg { + u16 address; + u8 data; +}; + +struct stb0899_s2_reg { + u16 offset; + u32 base_address; + u32 data; +}; + +enum stb0899_inversion { + IQ_SWAP_OFF = 0, + IQ_SWAP_ON, + IQ_SWAP_AUTO +}; + +#define STB0899_GPIO00 0xf140 +#define STB0899_GPIO01 0xf141 +#define STB0899_GPIO02 0xf142 +#define STB0899_GPIO03 0xf143 +#define STB0899_GPIO04 0xf144 +#define STB0899_GPIO05 0xf145 +#define STB0899_GPIO06 0xf146 +#define STB0899_GPIO07 0xf147 +#define STB0899_GPIO08 0xf148 +#define STB0899_GPIO09 0xf149 +#define STB0899_GPIO10 0xf14a +#define STB0899_GPIO11 0xf14b +#define STB0899_GPIO12 0xf14c +#define STB0899_GPIO13 0xf14d +#define STB0899_GPIO14 0xf14e +#define STB0899_GPIO15 0xf14f +#define STB0899_GPIO16 0xf150 +#define STB0899_GPIO17 0xf151 +#define STB0899_GPIO18 0xf152 +#define STB0899_GPIO19 0xf153 +#define STB0899_GPIO20 0xf154 + +#define STB0899_GPIOPULLUP 0x01 /* Output device is connected to Vdd */ +#define STB0899_GPIOPULLDN 0x00 /* Output device is connected to Vss */ + +#define STB0899_POSTPROC_GPIO_POWER 0x00 +#define STB0899_POSTPROC_GPIO_LOCK 0x01 + +/* + * Post process output configuration control + * 1. POWER ON/OFF (index 0) + * 2. FE_HAS_LOCK/LOCK_LOSS (index 1) + * + * @gpio = one of the above listed GPIO's + * @level = output state: pulled up or low + */ +struct stb0899_postproc { + u16 gpio; + u8 level; +}; + +struct stb0899_config { + const struct stb0899_s1_reg *init_dev; + const struct stb0899_s2_reg *init_s2_demod; + const struct stb0899_s1_reg *init_s1_demod; + const struct stb0899_s2_reg *init_s2_fec; + const struct stb0899_s1_reg *init_tst; + + const struct stb0899_postproc *postproc; + + enum stb0899_inversion inversion; + + u32 xtal_freq; + + u8 demod_address; + u8 ts_output_mode; + u8 block_sync_mode; + u8 ts_pfbit_toggle; + + u8 clock_polarity; + u8 data_clk_parity; + u8 fec_mode; + u8 data_output_ctl; + u8 data_fifo_mode; + u8 out_rate_comp; + u8 i2c_repeater; +// int inversion; + int lo_clk; + int hi_clk; + + u32 esno_ave; + u32 esno_quant; + u32 avframes_coarse; + u32 avframes_fine; + u32 miss_threshold; + u32 uwp_threshold_acq; + u32 uwp_threshold_track; + u32 uwp_threshold_sof; + u32 sof_search_timeout; + + u32 btr_nco_bits; + u32 btr_gain_shift_offset; + u32 crl_nco_bits; + u32 ldpc_max_iter; + + int (*tuner_set_frequency)(struct dvb_frontend *fe, u32 frequency); + int (*tuner_get_frequency)(struct dvb_frontend *fe, u32 *frequency); + int (*tuner_set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth); + int (*tuner_get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); + int (*tuner_set_rfsiggain)(struct dvb_frontend *fe, u32 rf_gain); +}; + +#if defined(CONFIG_DVB_STB0899) || (defined(CONFIG_DVB_STB0899_MODULE) && defined(MODULE)) + +extern struct dvb_frontend *stb0899_attach(struct stb0899_config *config, + struct i2c_adapter *i2c); + +#else + +static inline struct dvb_frontend *stb0899_attach(struct stb0899_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); + return NULL; +} + +#endif //CONFIG_DVB_STB0899 + + +#endif diff --git a/drivers/media/dvb/frontends/stb0899_priv.h b/drivers/media/dvb/frontends/stb0899_priv.h new file mode 100644 index 00000000000..24619e3689d --- /dev/null +++ b/drivers/media/dvb/frontends/stb0899_priv.h @@ -0,0 +1,267 @@ +/* + STB0899 Multistandard Frontend driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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 __STB0899_PRIV_H +#define __STB0899_PRIV_H + +#include "dvb_frontend.h" +#include "stb0899_drv.h" + +#define FE_ERROR 0 +#define FE_NOTICE 1 +#define FE_INFO 2 +#define FE_DEBUG 3 +#define FE_DEBUGREG 4 + +#define dprintk(x, y, z, format, arg...) do { \ + if (z) { \ + if ((*x > FE_ERROR) && (*x > y)) \ + printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ + else if ((*x > FE_NOTICE) && (*x > y)) \ + printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ + else if ((*x > FE_INFO) && (*x > y)) \ + printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ + else if ((*x > FE_DEBUG) && (*x > y)) \ + printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ + } else { \ + if (*x > y) \ + printk(format, ##arg); \ + } \ +} while(0) + +#define INRANGE(val, x, y) (((x <= val) && (val <= y)) || \ + ((y <= val) && (val <= x)) ? 1 : 0) + +#define BYTE0 0 +#define BYTE1 8 +#define BYTE2 16 +#define BYTE3 24 + +#define GETBYTE(x, y) (((x) >> (y)) & 0xff) +#define MAKEWORD32(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) +#define MAKEWORD16(a, b) (((a) << 8) | (b)) + +#define MIN(x, y) ((x) <= (y) ? (x) : (y)) +#define MAX(x, y) ((x) >= (y) ? (x) : (y)) +#define ABS(x) ((x) >= 0 ? (x) : -(x)) + +#define LSB(x) ((x & 0xff)) +#define MSB(y) ((y >> 8) & 0xff) + + +#define STB0899_GETFIELD(bitf, val) ((val >> STB0899_OFFST_##bitf) & ((1 << STB0899_WIDTH_##bitf) - 1)) + + +#define STB0899_SETFIELD(mask, val, width, offset) (mask & (~(((1 << width) - 1) << \ + offset))) | ((val & \ + ((1 << width) - 1)) << offset) + +#define STB0899_SETFIELD_VAL(bitf, mask, val) (mask = (mask & (~(((1 << STB0899_WIDTH_##bitf) - 1) <<\ + STB0899_OFFST_##bitf))) | \ + (val << STB0899_OFFST_##bitf)) + + +enum stb0899_status { + NOAGC1 = 0, + AGC1OK, + NOTIMING, + ANALOGCARRIER, + TIMINGOK, + NOAGC2, + AGC2OK, + NOCARRIER, + CARRIEROK, + NODATA, + FALSELOCK, + DATAOK, + OUTOFRANGE, + RANGEOK, + DVBS2_DEMOD_LOCK, + DVBS2_DEMOD_NOLOCK, + DVBS2_FEC_LOCK, + DVBS2_FEC_NOLOCK +}; + +enum stb0899_modcod { + STB0899_DUMMY_PLF, + STB0899_QPSK_14, + STB0899_QPSK_13, + STB0899_QPSK_25, + STB0899_QPSK_12, + STB0899_QPSK_35, + STB0899_QPSK_23, + STB0899_QPSK_34, + STB0899_QPSK_45, + STB0899_QPSK_56, + STB0899_QPSK_89, + STB0899_QPSK_910, + STB0899_8PSK_35, + STB0899_8PSK_23, + STB0899_8PSK_34, + STB0899_8PSK_56, + STB0899_8PSK_89, + STB0899_8PSK_910, + STB0899_16APSK_23, + STB0899_16APSK_34, + STB0899_16APSK_45, + STB0899_16APSK_56, + STB0899_16APSK_89, + STB0899_16APSK_910, + STB0899_32APSK_34, + STB0899_32APSK_45, + STB0899_32APSK_56, + STB0899_32APSK_89, + STB0899_32APSK_910 +}; + +enum stb0899_frame { + STB0899_LONG_FRAME, + STB0899_SHORT_FRAME +}; + +enum stb0899_alpha { + RRC_20, + RRC_25, + RRC_35 +}; + +struct stb0899_tab { + s32 real; + s32 read; +}; + +enum stb0899_fec { + STB0899_FEC_1_2 = 13, + STB0899_FEC_2_3 = 18, + STB0899_FEC_3_4 = 21, + STB0899_FEC_5_6 = 24, + STB0899_FEC_6_7 = 25, + STB0899_FEC_7_8 = 26 +}; + +struct stb0899_params { + u32 freq; /* Frequency */ + u32 srate; /* Symbol rate */ + enum fe_code_rate fecrate; +}; + +struct stb0899_internal { + u32 master_clk; + u32 freq; /* Demod internal Frequency */ + u32 srate; /* Demod internal Symbol rate */ + enum stb0899_fec fecrate; /* Demod internal FEC rate */ + u32 srch_range; /* Demod internal Search Range */ + u32 sub_range; /* Demod current sub range (Hz) */ + u32 tuner_step; /* Tuner step (Hz) */ + u32 tuner_offst; /* Relative offset to carrier (Hz) */ + u32 tuner_bw; /* Current bandwidth of the tuner (Hz) */ + + s32 mclk; /* Masterclock Divider factor (binary) */ + s32 rolloff; /* Current RollOff of the filter (x100) */ + + s16 derot_freq; /* Current derotator frequency (Hz) */ + s16 derot_percent; + + s16 direction; /* Current derotator search direction */ + s16 derot_step; /* Derotator step (binary value) */ + s16 t_derot; /* Derotator time constant (ms) */ + s16 t_data; /* Data recovery time constant (ms) */ + s16 sub_dir; /* Direction of the next sub range */ + + s16 t_agc1; /* Agc1 time constant (ms) */ + s16 t_agc2; /* Agc2 time constant (ms) */ + + u32 lock; /* Demod internal lock state */ + enum stb0899_status status; /* Demod internal status */ + + /* DVB-S2 */ + s32 agc_gain; /* RF AGC Gain */ + s32 center_freq; /* Nominal carrier frequency */ + s32 av_frame_coarse; /* Coarse carrier freq search frames */ + s32 av_frame_fine; /* Fine carrier freq search frames */ + + s16 step_size; /* Carrier frequency search step size */ + + enum stb0899_alpha rrc_alpha; + enum stb0899_inversion inversion; + enum stb0899_modcod modcod; + u8 pilots; /* Pilots found */ + + enum stb0899_frame frame_length; + u8 v_status; /* VSTATUS */ + u8 err_ctrl; /* ERRCTRLn */ +}; + +struct stb0899_state { + struct i2c_adapter *i2c; + struct stb0899_config *config; + struct dvb_frontend frontend; + + u32 *verbose; /* Cached module verbosity level */ + + struct stb0899_internal internal; /* Device internal parameters */ + + /* cached params from API */ + enum fe_delivery_system delsys; + struct stb0899_params params; + + u32 rx_freq; /* DiSEqC 2.0 receiver freq */ + struct mutex search_lock; +}; +/* stb0899.c */ +extern int stb0899_read_reg(struct stb0899_state *state, + unsigned int reg); + +extern u32 _stb0899_read_s2reg(struct stb0899_state *state, + u32 stb0899_i2cdev, + u32 stb0899_base_addr, + u16 stb0899_reg_offset); + +extern int stb0899_read_regs(struct stb0899_state *state, + unsigned int reg, u8 *buf, + u32 count); + +extern int stb0899_write_regs(struct stb0899_state *state, + unsigned int reg, u8 *data, + u32 count); + +extern int stb0899_write_reg(struct stb0899_state *state, + unsigned int reg, + u8 data); + +extern int stb0899_write_s2reg(struct stb0899_state *state, + u32 stb0899_i2cdev, + u32 stb0899_base_addr, + u16 stb0899_reg_offset, + u32 stb0899_data); + +extern int stb0899_i2c_gate_ctrl(struct dvb_frontend *fe, int enable); + + +#define STB0899_READ_S2REG(DEVICE, REG) (_stb0899_read_s2reg(state, DEVICE, STB0899_BASE_##REG, STB0899_OFF0_##REG)) +//#define STB0899_WRITE_S2REG(DEVICE, REG, DATA) (_stb0899_write_s2reg(state, DEVICE, STB0899_BASE_##REG, STB0899_OFF0_##REG, DATA)) + +/* stb0899_algo.c */ +extern enum stb0899_status stb0899_dvbs_algo(struct stb0899_state *state); +extern enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state); +extern long stb0899_carr_width(struct stb0899_state *state); + +#endif //__STB0899_PRIV_H diff --git a/drivers/media/dvb/frontends/stb0899_reg.h b/drivers/media/dvb/frontends/stb0899_reg.h new file mode 100644 index 00000000000..ba1ed56304a --- /dev/null +++ b/drivers/media/dvb/frontends/stb0899_reg.h @@ -0,0 +1,2027 @@ +/* + STB0899 Multistandard Frontend driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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 __STB0899_REG_H +#define __STB0899_REG_H + +/* S1 */ +#define STB0899_DEV_ID 0xf000 +#define STB0899_CHIP_ID (0x0f << 4) +#define STB0899_OFFST_CHIP_ID 4 +#define STB0899_WIDTH_CHIP_ID 4 +#define STB0899_CHIP_REL (0x0f << 0) +#define STB0899_OFFST_CHIP_REL 0 +#define STB0899_WIDTH_CHIP_REL 4 + +#define STB0899_DEMOD 0xf40e +#define STB0899_MODECOEFF (0x01 << 0) +#define STB0899_OFFST_MODECOEFF 0 +#define STB0899_WIDTH_MODECOEFF 1 + +#define STB0899_RCOMPC 0xf410 +#define STB0899_AGC1CN 0xf412 +#define STB0899_AGC1REF 0xf413 +#define STB0899_RTC 0xf417 +#define STB0899_TMGCFG 0xf418 +#define STB0899_AGC2REF 0xf419 +#define STB0899_TLSR 0xf41a + +#define STB0899_CFD 0xf41b +#define STB0899_CFD_ON (0x01 << 7) +#define STB0899_OFFST_CFD_ON 7 +#define STB0899_WIDTH_CFD_ON 1 + +#define STB0899_ACLC 0xf41c + +#define STB0899_BCLC 0xf41d +#define STB0899_OFFST_ALGO 6 +#define STB0899_WIDTH_ALGO_QPSK2 2 +#define STB0899_ALGO_QPSK2 (2 << 6) +#define STB0899_ALGO_QPSK1 (1 << 6) +#define STB0899_ALGO_BPSK (0 << 6) +#define STB0899_OFFST_BETA 0 +#define STB0899_WIDTH_BETA 6 + +#define STB0899_EQON 0xf41e +#define STB0899_LDT 0xf41f +#define STB0899_LDT2 0xf420 +#define STB0899_EQUALREF 0xf425 +#define STB0899_TMGRAMP 0xf426 +#define STB0899_TMGTHD 0xf427 +#define STB0899_IDCCOMP 0xf428 +#define STB0899_QDCCOMP 0xf429 +#define STB0899_POWERI 0xf42a +#define STB0899_POWERQ 0xf42b +#define STB0899_RCOMP 0xf42c + +#define STB0899_AGCIQIN 0xf42e +#define STB0899_AGCIQVALUE (0xff << 0) +#define STB0899_OFFST_AGCIQVALUE 0 +#define STB0899_WIDTH_AGCIQVALUE 8 + +#define STB0899_AGC2I1 0xf436 +#define STB0899_AGC2I2 0xf437 + +#define STB0899_TLIR 0xf438 +#define STB0899_TLIR_TMG_LOCK_IND (0xff << 0) +#define STB0899_OFFST_TLIR_TMG_LOCK_IND 0 +#define STB0899_WIDTH_TLIR_TMG_LOCK_IND 8 + +#define STB0899_RTF 0xf439 +#define STB0899_RTF_TIMING_LOOP_FREQ (0xff << 0) +#define STB0899_OFFST_RTF_TIMING_LOOP_FREQ 0 +#define STB0899_WIDTH_RTF_TIMING_LOOP_FREQ 8 + +#define STB0899_DSTATUS 0xf43a +#define STB0899_CARRIER_FOUND (0x01 << 7) +#define STB0899_OFFST_CARRIER_FOUND 7 +#define STB0899_WIDTH_CARRIER_FOUND 1 +#define STB0899_TMG_LOCK (0x01 << 6) +#define STB0899_OFFST_TMG_LOCK 6 +#define STB0899_WIDTH_TMG_LOCK 1 +#define STB0899_DEMOD_LOCK (0x01 << 5) +#define STB0899_OFFST_DEMOD_LOCK 5 +#define STB0899_WIDTH_DEMOD_LOCK 1 +#define STB0899_TMG_AUTO (0x01 << 4) +#define STB0899_OFFST_TMG_AUTO 4 +#define STB0899_WIDTH_TMG_AUTO 1 +#define STB0899_END_MAIN (0x01 << 3) +#define STB0899_OFFST_END_MAIN 3 +#define STB0899_WIDTH_END_MAIN 1 + +#define STB0899_LDI 0xf43b +#define STB0899_OFFST_LDI 0 +#define STB0899_WIDTH_LDI 8 + +#define STB0899_CFRM 0xf43e +#define STB0899_OFFST_CFRM 0 +#define STB0899_WIDTH_CFRM 8 + +#define STB0899_CFRL 0xf43f +#define STB0899_OFFST_CFRL 0 +#define STB0899_WIDTH_CFRL 8 + +#define STB0899_NIRM 0xf440 +#define STB0899_OFFST_NIRM 0 +#define STB0899_WIDTH_NIRM 8 + +#define STB0899_NIRL 0xf441 +#define STB0899_OFFST_NIRL 0 +#define STB0899_WIDTH_NIRL 8 + +#define STB0899_ISYMB 0xf444 +#define STB0899_QSYMB 0xf445 + +#define STB0899_SFRH 0xf446 +#define STB0899_OFFST_SFRH 0 +#define STB0899_WIDTH_SFRH 8 + +#define STB0899_SFRM 0xf447 +#define STB0899_OFFST_SFRM 0 +#define STB0899_WIDTH_SFRM 8 + +#define STB0899_SFRL 0xf448 +#define STB0899_OFFST_SFRL 4 +#define STB0899_WIDTH_SFRL 4 + +#define STB0899_SFRUPH 0xf44c +#define STB0899_SFRUPM 0xf44d +#define STB0899_SFRUPL 0xf44e + +#define STB0899_EQUAI1 0xf4e0 +#define STB0899_EQUAQ1 0xf4e1 +#define STB0899_EQUAI2 0xf4e2 +#define STB0899_EQUAQ2 0xf4e3 +#define STB0899_EQUAI3 0xf4e4 +#define STB0899_EQUAQ3 0xf4e5 +#define STB0899_EQUAI4 0xf4e6 +#define STB0899_EQUAQ4 0xf4e7 +#define STB0899_EQUAI5 0xf4e8 +#define STB0899_EQUAQ5 0xf4e9 + +#define STB0899_DSTATUS2 0xf50c +#define STB0899_DS2_TMG_AUTOSRCH (0x01 << 7) +#define STB8999_OFFST_DS2_TMG_AUTOSRCH 7 +#define STB0899_WIDTH_DS2_TMG_AUTOSRCH 1 +#define STB0899_DS2_END_MAINLOOP (0x01 << 6) +#define STB0899_OFFST_DS2_END_MAINLOOP 6 +#define STB0899_WIDTH_DS2_END_MAINLOOP 1 +#define STB0899_DS2_CFSYNC (0x01 << 5) +#define STB0899_OFFST_DS2_CFSYNC 5 +#define STB0899_WIDTH_DS2_CFSYNC 1 +#define STB0899_DS2_TMGLOCK (0x01 << 4) +#define STB0899_OFFST_DS2_TMGLOCK 4 +#define STB0899_WIDTH_DS2_TMGLOCK 1 +#define STB0899_DS2_DEMODWAIT (0x01 << 3) +#define STB0899_OFFST_DS2_DEMODWAIT 3 +#define STB0899_WIDTH_DS2_DEMODWAIT 1 +#define STB0899_DS2_FECON (0x01 << 1) +#define STB0899_OFFST_DS2_FECON 1 +#define STB0899_WIDTH_DS2_FECON 1 + +/* S1 FEC */ +#define STB0899_VSTATUS 0xf50d +#define STB0899_VSTATUS_VITERBI_ON (0x01 << 7) +#define STB0899_OFFST_VSTATUS_VITERBI_ON 7 +#define STB0899_WIDTH_VSTATUS_VITERBI_ON 1 +#define STB0899_VSTATUS_END_LOOPVIT (0x01 << 6) +#define STB0899_OFFST_VSTATUS_END_LOOPVIT 6 +#define STB0899_WIDTH_VSTATUS_END_LOOPVIT 1 +#define STB0899_VSTATUS_PRFVIT (0x01 << 4) +#define STB0899_OFFST_VSTATUS_PRFVIT 4 +#define STB0899_WIDTH_VSTATUS_PRFVIT 1 +#define STB0899_VSTATUS_LOCKEDVIT (0x01 << 3) +#define STB0899_OFFST_VSTATUS_LOCKEDVIT 3 +#define STB0899_WIDTH_VSTATUS_LOCKEDVIT 1 + +#define STB0899_VERROR 0xf50f + +#define STB0899_IQSWAP 0xf523 +#define STB0899_SYM (0x01 << 3) +#define STB0899_OFFST_SYM 3 +#define STB0899_WIDTH_SYM 1 + +#define STB0899_FECAUTO1 0xf530 +#define STB0899_DSSSRCH (0x01 << 3) +#define STB0899_OFFST_DSSSRCH 3 +#define STB0899_WIDTH_DSSSRCH 1 +#define STB0899_SYMSRCH (0x01 << 2) +#define STB0899_OFFST_SYMSRCH 2 +#define STB0899_WIDTH_SYMSRCH 1 +#define STB0899_QPSKSRCH (0x01 << 1) +#define STB0899_OFFST_QPSKSRCH 1 +#define STB0899_WIDTH_QPSKSRCH 1 +#define STB0899_BPSKSRCH (0x01 << 0) +#define STB0899_OFFST_BPSKSRCH 0 +#define STB0899_WIDTH_BPSKSRCH 1 + +#define STB0899_FECM 0xf533 +#define STB0899_FECM_NOT_DVB (0x01 << 7) +#define STB0899_OFFST_FECM_NOT_DVB 7 +#define STB0899_WIDTH_FECM_NOT_DVB 1 +#define STB0899_FECM_RSVD1 (0x07 << 4) +#define STB0899_OFFST_FECM_RSVD1 4 +#define STB0899_WIDTH_FECM_RSVD1 3 +#define STB0899_FECM_VITERBI_ON (0x01 << 3) +#define STB0899_OFFST_FECM_VITERBI_ON 3 +#define STB0899_WIDTH_FECM_VITERBI_ON 1 +#define STB0899_FECM_RSVD0 (0x01 << 2) +#define STB0899_OFFST_FECM_RSVD0 2 +#define STB0899_WIDTH_FECM_RSVD0 1 +#define STB0899_FECM_SYNCDIS (0x01 << 1) +#define STB0899_OFFST_FECM_SYNCDIS 1 +#define STB0899_WIDTH_FECM_SYNCDIS 1 +#define STB0899_FECM_SYMI (0x01 << 0) +#define STB0899_OFFST_FECM_SYMI 0 +#define STB0899_WIDTH_FECM_SYMI 1 + +#define STB0899_VTH12 0xf534 +#define STB0899_VTH23 0xf535 +#define STB0899_VTH34 0xf536 +#define STB0899_VTH56 0xf537 +#define STB0899_VTH67 0xf538 +#define STB0899_VTH78 0xf539 + +#define STB0899_PRVIT 0xf53c +#define STB0899_PR_7_8 (0x01 << 5) +#define STB0899_OFFST_PR_7_8 5 +#define STB0899_WIDTH_PR_7_8 1 +#define STB0899_PR_6_7 (0x01 << 4) +#define STB0899_OFFST_PR_6_7 4 +#define STB0899_WIDTH_PR_6_7 1 +#define STB0899_PR_5_6 (0x01 << 3) +#define STB0899_OFFST_PR_5_6 3 +#define STB0899_WIDTH_PR_5_6 1 +#define STB0899_PR_3_4 (0x01 << 2) +#define STB0899_OFFST_PR_3_4 2 +#define STB0899_WIDTH_PR_3_4 1 +#define STB0899_PR_2_3 (0x01 << 1) +#define STB0899_OFFST_PR_2_3 1 +#define STB0899_WIDTH_PR_2_3 1 +#define STB0899_PR_1_2 (0x01 << 0) +#define STB0899_OFFST_PR_1_2 0 +#define STB0899_WIDTH_PR_1_2 1 + +#define STB0899_VITSYNC 0xf53d +#define STB0899_AM (0x01 << 7) +#define STB0899_OFFST_AM 7 +#define STB0899_WIDTH_AM 1 +#define STB0899_FREEZE (0x01 << 6) +#define STB0899_OFFST_FREEZE 6 +#define STB0899_WIDTH_FREEZE 1 +#define STB0899_SN_65536 (0x03 << 4) +#define STB0899_OFFST_SN_65536 4 +#define STB0899_WIDTH_SN_65536 2 +#define STB0899_SN_16384 (0x01 << 5) +#define STB0899_OFFST_SN_16384 5 +#define STB0899_WIDTH_SN_16384 1 +#define STB0899_SN_4096 (0x01 << 4) +#define STB0899_OFFST_SN_4096 4 +#define STB0899_WIDTH_SN_4096 1 +#define STB0899_SN_1024 (0x00 << 4) +#define STB0899_OFFST_SN_1024 4 +#define STB0899_WIDTH_SN_1024 0 +#define STB0899_TO_128 (0x03 << 2) +#define STB0899_OFFST_TO_128 2 +#define STB0899_WIDTH_TO_128 2 +#define STB0899_TO_64 (0x01 << 3) +#define STB0899_OFFST_TO_64 3 +#define STB0899_WIDTH_TO_64 1 +#define STB0899_TO_32 (0x01 << 2) +#define STB0899_OFFST_TO_32 2 +#define STB0899_WIDTH_TO_32 1 +#define STB0899_TO_16 (0x00 << 2) +#define STB0899_OFFST_TO_16 2 +#define STB0899_WIDTH_TO_16 0 +#define STB0899_HYST_128 (0x03 << 1) +#define STB0899_OFFST_HYST_128 1 +#define STB0899_WIDTH_HYST_128 2 +#define STB0899_HYST_64 (0x01 << 1) +#define STB0899_OFFST_HYST_64 1 +#define STB0899_WIDTH_HYST_64 1 +#define STB0899_HYST_32 (0x01 << 0) +#define STB0899_OFFST_HYST_32 0 +#define STB0899_WIDTH_HYST_32 1 +#define STB0899_HYST_16 (0x00 << 0) +#define STB0899_OFFST_HYST_16 0 +#define STB0899_WIDTH_HYST_16 0 + +#define STB0899_RSULC 0xf548 +#define STB0899_ULDIL_ON (0x01 << 7) +#define STB0899_OFFST_ULDIL_ON 7 +#define STB0899_WIDTH_ULDIL_ON 1 +#define STB0899_ULAUTO_ON (0x01 << 6) +#define STB0899_OFFST_ULAUTO_ON 6 +#define STB0899_WIDTH_ULAUTO_ON 1 +#define STB0899_ULRS_ON (0x01 << 5) +#define STB0899_OFFST_ULRS_ON 5 +#define STB0899_WIDTH_ULRS_ON 1 +#define STB0899_ULDESCRAM_ON (0x01 << 4) +#define STB0899_OFFST_ULDESCRAM_ON 4 +#define STB0899_WIDTH_ULDESCRAM_ON 1 +#define STB0899_UL_DISABLE (0x01 << 2) +#define STB0899_OFFST_UL_DISABLE 2 +#define STB0899_WIDTH_UL_DISABLE 1 +#define STB0899_NOFTHRESHOLD (0x01 << 0) +#define STB0899_OFFST_NOFTHRESHOLD 0 +#define STB0899_WIDTH_NOFTHRESHOLD 1 + +#define STB0899_RSLLC 0xf54a +#define STB0899_DEMAPVIT 0xf583 +#define STB0899_DEMAPVIT_RSVD (0x01 << 7) +#define STB0899_OFFST_DEMAPVIT_RSVD 7 +#define STB0899_WIDTH_DEMAPVIT_RSVD 1 +#define STB0899_DEMAPVIT_KDIVIDER (0x7f << 0) +#define STB0899_OFFST_DEMAPVIT_KDIVIDER 0 +#define STB0899_WIDTH_DEMAPVIT_KDIVIDER 7 + +#define STB0899_PLPARM 0xf58c +#define STB0899_VITMAPPING (0x07 << 5) +#define STB0899_OFFST_VITMAPPING 5 +#define STB0899_WIDTH_VITMAPPING 3 +#define STB0899_VITMAPPING_BPSK (0x01 << 5) +#define STB0899_OFFST_VITMAPPING_BPSK 5 +#define STB0899_WIDTH_VITMAPPING_BPSK 1 +#define STB0899_VITMAPPING_QPSK (0x00 << 5) +#define STB0899_OFFST_VITMAPPING_QPSK 5 +#define STB0899_WIDTH_VITMAPPING_QPSK 0 +#define STB0899_VITCURPUN (0x1f << 0) +#define STB0899_OFFST_VITCURPUN 0 +#define STB0899_WIDTH_VITCURPUN 5 +#define STB0899_VITCURPUN_1_2 (0x0d << 0) +#define STB0899_VITCURPUN_2_3 (0x12 << 0) +#define STB0899_VITCURPUN_3_4 (0x15 << 0) +#define STB0899_VITCURPUN_5_6 (0x18 << 0) +#define STB0899_VITCURPUN_6_7 (0x19 << 0) +#define STB0899_VITCURPUN_7_8 (0x1a << 0) + +/* S2 DEMOD */ +#define STB0899_OFF0_DMD_STATUS 0xf300 +#define STB0899_BASE_DMD_STATUS 0x00000000 +#define STB0899_IF_AGC_LOCK (0x01 << 8) +#define STB0899_OFFST_IF_AGC_LOCK 0 +#define STB0899_WIDTH_IF_AGC_LOCK 1 + +#define STB0899_OFF0_CRL_FREQ 0xf304 +#define STB0899_BASE_CRL_FREQ 0x00000000 +#define STB0899_CARR_FREQ (0x3fffffff << 0) +#define STB0899_OFFST_CARR_FREQ 0 +#define STB0899_WIDTH_CARR_FREQ 30 + +#define STB0899_OFF0_BTR_FREQ 0xf308 +#define STB0899_BASE_BTR_FREQ 0x00000000 +#define STB0899_BTR_FREQ (0xfffffff << 0) +#define STB0899_OFFST_BTR_FREQ 0 +#define STB0899_WIDTH_BTR_FREQ 28 + +#define STB0899_OFF0_IF_AGC_GAIN 0xf30c +#define STB0899_BASE_IF_AGC_GAIN 0x00000000 +#define STB0899_IF_AGC_GAIN (0x3fff < 0) +#define STB0899_OFFST_IF_AGC_GAIN 0 +#define STB0899_WIDTH_IF_AGC_GAIN 14 + +#define STB0899_OFF0_BB_AGC_GAIN 0xf310 +#define STB0899_BASE_BB_AGC_GAIN 0x00000000 +#define STB0899_BB_AGC_GAIN (0x3fff < 0) +#define STB0899_OFFST_BB_AGC_GAIN 0 +#define STB0899_WIDTH_BB_AGC_GAIN 14 + +#define STB0899_OFF0_DC_OFFSET 0xf314 +#define STB0899_BASE_DC_OFFSET 0x00000000 +#define STB0899_I (0xff < 8) +#define STB0899_OFFST_I 8 +#define STB0899_WIDTH_I 8 +#define STB0899_Q (0xff < 0) +#define STB0899_OFFST_Q 8 +#define STB0899_WIDTH_Q 8 + +#define STB0899_OFF0_DMD_CNTRL 0xf31c +#define STB0899_BASE_DMD_CNTRL 0x00000000 +#define STB0899_ADC0_PINS1IN (0x01 << 6) +#define STB0899_OFFST_ADC0_PINS1IN 6 +#define STB0899_WIDTH_ADC0_PINS1IN 1 +#define STB0899_IN2COMP1_OFFBIN0 (0x01 << 3) +#define STB0899_OFFST_IN2COMP1_OFFBIN0 3 +#define STB0899_WIDTH_IN2COMP1_OFFBIN0 1 +#define STB0899_DC_COMP (0x01 << 2) +#define STB0899_OFFST_DC_COMP 2 +#define STB0899_WIDTH_DC_COMP 1 +#define STB0899_MODMODE (0x03 << 0) +#define STB0899_OFFST_MODMODE 0 +#define STB0899_WIDTH_MODMODE 2 + +#define STB0899_OFF0_IF_AGC_CNTRL 0xf320 +#define STB0899_BASE_IF_AGC_CNTRL 0x00000000 +#define STB0899_IF_GAIN_INIT (0x3fff << 13) +#define STB0899_OFFST_IF_GAIN_INIT 13 +#define STB0899_WIDTH_IF_GAIN_INIT 14 +#define STB0899_IF_GAIN_SENSE (0x01 << 12) +#define STB0899_OFFST_IF_GAIN_SENSE 12 +#define STB0899_WIDTH_IF_GAIN_SENSE 1 +#define STB0899_IF_LOOP_GAIN (0x0f << 8) +#define STB0899_OFFST_IF_LOOP_GAIN 8 +#define STB0899_WIDTH_IF_LOOP_GAIN 4 +#define STB0899_IF_LD_GAIN_INIT (0x01 << 7) +#define STB0899_OFFST_IF_LD_GAIN_INIT 7 +#define STB0899_WIDTH_IF_LD_GAIN_INIT 1 +#define STB0899_IF_AGC_REF (0x7f << 0) +#define STB0899_OFFST_IF_AGC_REF 0 +#define STB0899_WIDTH_IF_AGC_REF 7 + +#define STB0899_OFF0_BB_AGC_CNTRL 0xf324 +#define STB0899_BASE_BB_AGC_CNTRL 0x00000000 +#define STB0899_BB_GAIN_INIT (0x3fff << 12) +#define STB0899_OFFST_BB_GAIN_INIT 12 +#define STB0899_WIDTH_BB_GAIN_INIT 14 +#define STB0899_BB_LOOP_GAIN (0x0f << 8) +#define STB0899_OFFST_BB_LOOP_GAIN 8 +#define STB0899_WIDTH_BB_LOOP_GAIN 4 +#define STB0899_BB_LD_GAIN_INIT (0x01 << 7) +#define STB0899_OFFST_BB_LD_GAIN_INIT 7 +#define STB0899_WIDTH_BB_LD_GAIN_INIT 1 +#define STB0899_BB_AGC_REF (0x7f << 0) +#define STB0899_OFFST_BB_AGC_REF 0 +#define STB0899_WIDTH_BB_AGC_REF 7 + +#define STB0899_OFF0_CRL_CNTRL 0xf328 +#define STB0899_BASE_CRL_CNTRL 0x00000000 +#define STB0899_CRL_LOCK_CLEAR (0x01 << 5) +#define STB0899_OFFST_CRL_LOCK_CLEAR 5 +#define STB0899_WIDTH_CRL_LOCK_CLEAR 1 +#define STB0899_CRL_SWPR_CLEAR (0x01 << 4) +#define STB0899_OFFST_CRL_SWPR_CLEAR 4 +#define STB0899_WIDTH_CRL_SWPR_CLEAR 1 +#define STB0899_CRL_SWP_ENA (0x01 << 3) +#define STB0899_OFFST_CRL_SWP_ENA 3 +#define STB0899_WIDTH_CRL_SWP_ENA 1 +#define STB0899_CRL_DET_SEL (0x01 << 2) +#define STB0899_OFFST_CRL_DET_SEL 2 +#define STB0899_WIDTH_CRL_DET_SEL 1 +#define STB0899_CRL_SENSE (0x01 << 1) +#define STB0899_OFFST_CRL_SENSE 1 +#define STB0899_WIDTH_CRL_SENSE 1 +#define STB0899_CRL_PHSERR_CLEAR (0x01 << 0) +#define STB0899_OFFST_CRL_PHSERR_CLEAR 0 +#define STB0899_WIDTH_CRL_PHSERR_CLEAR 1 + +#define STB0899_OFF0_CRL_PHS_INIT 0xf32c +#define STB0899_BASE_CRL_PHS_INIT 0x00000000 +#define STB0899_CRL_PHS_INIT_31 (0x1 << 30) +#define STB0899_OFFST_CRL_PHS_INIT_31 30 +#define STB0899_WIDTH_CRL_PHS_INIT_31 1 +#define STB0899_CRL_LD_INIT_PHASE (0x1 << 24) +#define STB0899_OFFST_CRL_LD_INIT_PHASE 24 +#define STB0899_WIDTH_CRL_LD_INIT_PHASE 1 +#define STB0899_CRL_INIT_PHASE (0xffffff << 0) +#define STB0899_OFFST_CRL_INIT_PHASE 0 +#define STB0899_WIDTH_CRL_INIT_PHASE 24 + +#define STB0899_OFF0_CRL_FREQ_INIT 0xf330 +#define STB0899_BASE_CRL_FREQ_INIT 0x00000000 +#define STB0899_CRL_FREQ_INIT_31 (0x1 << 30) +#define STB0899_OFFST_CRL_FREQ_INIT_31 30 +#define STB0899_WIDTH_CRL_FREQ_INIT_31 1 +#define STB0899_CRL_LD_FREQ_INIT (0x1 << 24) +#define STB0899_OFFST_CRL_LD_FREQ_INIT 24 +#define STB0899_WIDTH_CRL_LD_FREQ_INIT 1 +#define STB0899_CRL_FREQ_INIT (0xffffff << 0) +#define STB0899_OFFST_CRL_FREQ_INIT 0 +#define STB0899_WIDTH_CRL_FREQ_INIT 24 + +#define STB0899_OFF0_CRL_LOOP_GAIN 0xf334 +#define STB0899_BASE_CRL_LOOP_GAIN 0x00000000 +#define STB0899_KCRL2_RSHFT (0xf << 16) +#define STB0899_OFFST_KCRL2_RSHFT 16 +#define STB0899_WIDTH_KCRL2_RSHFT 4 +#define STB0899_KCRL1 (0xf << 12) +#define STB0899_OFFST_KCRL1 12 +#define STB0899_WIDTH_KCRL1 4 +#define STB0899_KCRL1_RSHFT (0xf << 8) +#define STB0899_OFFST_KCRL1_RSHFT 8 +#define STB0899_WIDTH_KCRL1_RSHFT 4 +#define STB0899_KCRL0 (0xf << 4) +#define STB0899_OFFST_KCRL0 4 +#define STB0899_WIDTH_KCRL0 4 +#define STB0899_KCRL0_RSHFT (0xf << 0) +#define STB0899_OFFST_KCRL0_RSHFT 0 +#define STB0899_WIDTH_KCRL0_RSHFT 4 + +#define STB0899_OFF0_CRL_NOM_FREQ 0xf338 +#define STB0899_BASE_CRL_NOM_FREQ 0x00000000 +#define STB0899_CRL_NOM_FREQ (0x3fffffff << 0) +#define STB0899_OFFST_CRL_NOM_FREQ 0 +#define STB0899_WIDTH_CRL_NOM_FREQ 30 + +#define STB0899_OFF0_CRL_SWP_RATE 0xf33c +#define STB0899_BASE_CRL_SWP_RATE 0x00000000 +#define STB0899_CRL_SWP_RATE (0x3fffffff << 0) +#define STB0899_OFFST_CRL_SWP_RATE 0 +#define STB0899_WIDTH_CRL_SWP_RATE 30 + +#define STB0899_OFF0_CRL_MAX_SWP 0xf340 +#define STB0899_BASE_CRL_MAX_SWP 0x00000000 +#define STB0899_CRL_MAX_SWP (0x3fffffff << 0) +#define STB0899_OFFST_CRL_MAX_SWP 0 +#define STB0899_WIDTH_CRL_MAX_SWP 30 + +#define STB0899_OFF0_CRL_LK_CNTRL 0xf344 +#define STB0899_BASE_CRL_LK_CNTRL 0x00000000 + +#define STB0899_OFF0_DECIM_CNTRL 0xf348 +#define STB0899_BASE_DECIM_CNTRL 0x00000000 +#define STB0899_BAND_LIMIT_B (0x01 << 5) +#define STB0899_OFFST_BAND_LIMIT_B 5 +#define STB0899_WIDTH_BAND_LIMIT_B 1 +#define STB0899_WIN_SEL (0x03 << 3) +#define STB0899_OFFST_WIN_SEL 3 +#define STB0899_WIDTH_WIN_SEL 2 +#define STB0899_DECIM_RATE (0x07 << 0) +#define STB0899_OFFST_DECIM_RATE 0 +#define STB0899_WIDTH_DECIM_RATE 3 + +#define STB0899_OFF0_BTR_CNTRL 0xf34c +#define STB0899_BASE_BTR_CNTRL 0x00000000 +#define STB0899_BTR_FREQ_CORR (0x7ff << 4) +#define STB0899_OFFST_BTR_FREQ_CORR 4 +#define STB0899_WIDTH_BTR_FREQ_CORR 11 +#define STB0899_BTR_CLR_LOCK (0x01 << 3) +#define STB0899_OFFST_BTR_CLR_LOCK 3 +#define STB0899_WIDTH_BTR_CLR_LOCK 1 +#define STB0899_BTR_SENSE (0x01 << 2) +#define STB0899_OFFST_BTR_SENSE 2 +#define STB0899_WIDTH_BTR_SENSE 1 +#define STB0899_BTR_ERR_ENA (0x01 << 1) +#define STB0899_OFFST_BTR_ERR_ENA 1 +#define STB0899_WIDTH_BTR_ERR_ENA 1 +#define STB0899_INTRP_PHS_SENSE (0x01 << 0) +#define STB0899_OFFST_INTRP_PHS_SENSE 0 +#define STB0899_WIDTH_INTRP_PHS_SENSE 1 + +#define STB0899_OFF0_BTR_LOOP_GAIN 0xf350 +#define STB0899_BASE_BTR_LOOP_GAIN 0x00000000 +#define STB0899_KBTR2_RSHFT (0x0f << 16) +#define STB0899_OFFST_KBTR2_RSHFT 16 +#define STB0899_WIDTH_KBTR2_RSHFT 4 +#define STB0899_KBTR1 (0x0f << 12) +#define STB0899_OFFST_KBTR1 12 +#define STB0899_WIDTH_KBTR1 4 +#define STB0899_KBTR1_RSHFT (0x0f << 8) +#define STB0899_OFFST_KBTR1_RSHFT 8 +#define STB0899_WIDTH_KBTR1_RSHFT 4 +#define STB0899_KBTR0 (0x0f << 4) +#define STB0899_OFFST_KBTR0 4 +#define STB0899_WIDTH_KBTR0 4 +#define STB0899_KBTR0_RSHFT (0x0f << 0) +#define STB0899_OFFST_KBTR0_RSHFT 0 +#define STB0899_WIDTH_KBTR0_RSHFT 4 + +#define STB0899_OFF0_BTR_PHS_INIT 0xf354 +#define STB0899_BASE_BTR_PHS_INIT 0x00000000 +#define STB0899_BTR_LD_PHASE_INIT (0x01 << 28) +#define STB0899_OFFST_BTR_LD_PHASE_INIT 28 +#define STB0899_WIDTH_BTR_LD_PHASE_INIT 1 +#define STB0899_BTR_INIT_PHASE (0xfffffff << 0) +#define STB0899_OFFST_BTR_INIT_PHASE 0 +#define STB0899_WIDTH_BTR_INIT_PHASE 28 + +#define STB0899_OFF0_BTR_FREQ_INIT 0xf358 +#define STB0899_BASE_BTR_FREQ_INIT 0x00000000 +#define STB0899_BTR_LD_FREQ_INIT (1 << 28) +#define STB0899_OFFST_BTR_LD_FREQ_INIT 28 +#define STB0899_WIDTH_BTR_LD_FREQ_INIT 1 +#define STB0899_BTR_FREQ_INIT (0xfffffff << 0) +#define STB0899_OFFST_BTR_FREQ_INIT 0 +#define STB0899_WIDTH_BTR_FREQ_INIT 28 + +#define STB0899_OFF0_BTR_NOM_FREQ 0xf35c +#define STB0899_BASE_BTR_NOM_FREQ 0x00000000 +#define STB0899_BTR_NOM_FREQ (0xfffffff << 0) +#define STB0899_OFFST_BTR_NOM_FREQ 0 +#define STB0899_WIDTH_BTR_NOM_FREQ 28 + +#define STB0899_OFF0_BTR_LK_CNTRL 0xf360 +#define STB0899_BASE_BTR_LK_CNTRL 0x00000000 +#define STB0899_BTR_MIN_ENERGY (0x0f << 24) +#define STB0899_OFFST_BTR_MIN_ENERGY 24 +#define STB0899_WIDTH_BTR_MIN_ENERGY 4 +#define STB0899_BTR_LOCK_TH_LO (0xff << 16) +#define STB0899_OFFST_BTR_LOCK_TH_LO 16 +#define STB0899_WIDTH_BTR_LOCK_TH_LO 8 +#define STB0899_BTR_LOCK_TH_HI (0xff << 8) +#define STB0899_OFFST_BTR_LOCK_TH_HI 8 +#define STB0899_WIDTH_BTR_LOCK_TH_HI 8 +#define STB0899_BTR_LOCK_GAIN (0x03 << 6) +#define STB0899_OFFST_BTR_LOCK_GAIN 6 +#define STB0899_WIDTH_BTR_LOCK_GAIN 2 +#define STB0899_BTR_LOCK_LEAK (0x3f << 0) +#define STB0899_OFFST_BTR_LOCK_LEAK 0 +#define STB0899_WIDTH_BTR_LOCK_LEAK 6 + +#define STB0899_OFF0_DECN_CNTRL 0xf364 +#define STB0899_BASE_DECN_CNTRL 0x00000000 + +#define STB0899_OFF0_TP_CNTRL 0xf368 +#define STB0899_BASE_TP_CNTRL 0x00000000 + +#define STB0899_OFF0_TP_BUF_STATUS 0xf36c +#define STB0899_BASE_TP_BUF_STATUS 0x00000000 +#define STB0899_TP_BUFFER_FULL (1 << 0) + +#define STB0899_OFF0_DC_ESTIM 0xf37c +#define STB0899_BASE_DC_ESTIM 0x0000 +#define STB0899_I_DC_ESTIMATE (0xff << 8) +#define STB0899_OFFST_I_DC_ESTIMATE 8 +#define STB0899_WIDTH_I_DC_ESTIMATE 8 +#define STB0899_Q_DC_ESTIMATE (0xff << 0) +#define STB0899_OFFST_Q_DC_ESTIMATE 0 +#define STB0899_WIDTH_Q_DC_ESTIMATE 8 + +#define STB0899_OFF0_FLL_CNTRL 0xf310 +#define STB0899_BASE_FLL_CNTRL 0x00000020 +#define STB0899_CRL_FLL_ACC (0x01 << 4) +#define STB0899_OFFST_CRL_FLL_ACC 4 +#define STB0899_WIDTH_CRL_FLL_ACC 1 +#define STB0899_FLL_AVG_PERIOD (0x0f << 0) +#define STB0899_OFFST_FLL_AVG_PERIOD 0 +#define STB0899_WIDTH_FLL_AVG_PERIOD 4 + +#define STB0899_OFF0_FLL_FREQ_WD 0xf314 +#define STB0899_BASE_FLL_FREQ_WD 0x00000020 +#define STB0899_FLL_FREQ_WD (0xffffffff << 0) +#define STB0899_OFFST_FLL_FREQ_WD 0 +#define STB0899_WIDTH_FLL_FREQ_WD 32 + +#define STB0899_OFF0_ANTI_ALIAS_SEL 0xf358 +#define STB0899_BASE_ANTI_ALIAS_SEL 0x00000020 +#define STB0899_ANTI_ALIAS_SELB (0x03 << 0) +#define STB0899_OFFST_ANTI_ALIAS_SELB 0 +#define STB0899_WIDTH_ANTI_ALIAS_SELB 2 + +#define STB0899_OFF0_RRC_ALPHA 0xf35c +#define STB0899_BASE_RRC_ALPHA 0x00000020 +#define STB0899_RRC_ALPHA (0x03 << 0) +#define STB0899_OFFST_RRC_ALPHA 0 +#define STB0899_WIDTH_RRC_ALPHA 2 + +#define STB0899_OFF0_DC_ADAPT_LSHFT 0xf360 +#define STB0899_BASE_DC_ADAPT_LSHFT 0x00000020 +#define STB0899_DC_ADAPT_LSHFT (0x077 << 0) +#define STB0899_OFFST_DC_ADAPT_LSHFT 0 +#define STB0899_WIDTH_DC_ADAPT_LSHFT 3 + +#define STB0899_OFF0_IMB_OFFSET 0xf364 +#define STB0899_BASE_IMB_OFFSET 0x00000020 +#define STB0899_PHS_IMB_COMP (0xff << 8) +#define STB0899_OFFST_PHS_IMB_COMP 8 +#define STB0899_WIDTH_PHS_IMB_COMP 8 +#define STB0899_AMPL_IMB_COMP (0xff << 0) +#define STB0899_OFFST_AMPL_IMB_COMP 0 +#define STB0899_WIDTH_AMPL_IMB_COMP 8 + +#define STB0899_OFF0_IMB_ESTIMATE 0xf368 +#define STB0899_BASE_IMB_ESTIMATE 0x00000020 +#define STB0899_PHS_IMB_ESTIMATE (0xff << 8) +#define STB0899_OFFST_PHS_IMB_ESTIMATE 8 +#define STB0899_WIDTH_PHS_IMB_ESTIMATE 8 +#define STB0899_AMPL_IMB_ESTIMATE (0xff << 0) +#define STB0899_OFFST_AMPL_IMB_ESTIMATE 0 +#define STB0899_WIDTH_AMPL_IMB_ESTIMATE 8 + +#define STB0899_OFF0_IMB_CNTRL 0xf36c +#define STB0899_BASE_IMB_CNTRL 0x00000020 +#define STB0899_PHS_ADAPT_LSHFT (0x07 << 4) +#define STB0899_OFFST_PHS_ADAPT_LSHFT 4 +#define STB0899_WIDTH_PHS_ADAPT_LSHFT 3 +#define STB0899_AMPL_ADAPT_LSHFT (0x07 << 1) +#define STB0899_OFFST_AMPL_ADAPT_LSHFT 1 +#define STB0899_WIDTH_AMPL_ADAPT_LSHFT 3 +#define STB0899_IMB_COMP (0x01 << 0) +#define STB0899_OFFST_IMB_COMP 0 +#define STB0899_WIDTH_IMB_COMP 1 + +#define STB0899_OFF0_IF_AGC_CNTRL2 0xf374 +#define STB0899_BASE_IF_AGC_CNTRL2 0x00000020 +#define STB0899_IF_AGC_LOCK_TH (0xff << 11) +#define STB0899_OFFST_IF_AGC_LOCK_TH 11 +#define STB0899_WIDTH_IF_AGC_LOCK_TH 8 +#define STB0899_IF_AGC_SD_DIV (0xff << 3) +#define STB0899_OFFST_IF_AGC_SD_DIV 3 +#define STB0899_WIDTH_IF_AGC_SD_DIV 8 +#define STB0899_IF_AGC_DUMP_PER (0x07 << 0) +#define STB0899_OFFST_IF_AGC_DUMP_PER 0 +#define STB0899_WIDTH_IF_AGC_DUMP_PER 3 + +#define STB0899_OFF0_DMD_CNTRL2 0xf378 +#define STB0899_BASE_DMD_CNTRL2 0x00000020 +#define STB0899_SPECTRUM_INVERT (0x01 << 2) +#define STB0899_OFFST_SPECTRUM_INVERT 2 +#define STB0899_WIDTH_SPECTRUM_INVERT 1 +#define STB0899_AGC_MODE (0x01 << 1) +#define STB0899_OFFST_AGC_MODE 1 +#define STB0899_WIDTH_AGC_MODE 1 +#define STB0899_CRL_FREQ_ADJ (0x01 << 0) +#define STB0899_OFFST_CRL_FREQ_ADJ 0 +#define STB0899_WIDTH_CRL_FREQ_ADJ 1 + +#define STB0899_OFF0_TP_BUFFER 0xf300 +#define STB0899_BASE_TP_BUFFER 0x00000040 +#define STB0899_TP_BUFFER_IN (0xffff << 0) +#define STB0899_OFFST_TP_BUFFER_IN 0 +#define STB0899_WIDTH_TP_BUFFER_IN 16 + +#define STB0899_OFF0_TP_BUFFER1 0xf304 +#define STB0899_BASE_TP_BUFFER1 0x00000040 +#define STB0899_OFF0_TP_BUFFER2 0xf308 +#define STB0899_BASE_TP_BUFFER2 0x00000040 +#define STB0899_OFF0_TP_BUFFER3 0xf30c +#define STB0899_BASE_TP_BUFFER3 0x00000040 +#define STB0899_OFF0_TP_BUFFER4 0xf310 +#define STB0899_BASE_TP_BUFFER4 0x00000040 +#define STB0899_OFF0_TP_BUFFER5 0xf314 +#define STB0899_BASE_TP_BUFFER5 0x00000040 +#define STB0899_OFF0_TP_BUFFER6 0xf318 +#define STB0899_BASE_TP_BUFFER6 0x00000040 +#define STB0899_OFF0_TP_BUFFER7 0xf31c +#define STB0899_BASE_TP_BUFFER7 0x00000040 +#define STB0899_OFF0_TP_BUFFER8 0xf320 +#define STB0899_BASE_TP_BUFFER8 0x00000040 +#define STB0899_OFF0_TP_BUFFER9 0xf324 +#define STB0899_BASE_TP_BUFFER9 0x00000040 +#define STB0899_OFF0_TP_BUFFER10 0xf328 +#define STB0899_BASE_TP_BUFFER10 0x00000040 +#define STB0899_OFF0_TP_BUFFER11 0xf32c +#define STB0899_BASE_TP_BUFFER11 0x00000040 +#define STB0899_OFF0_TP_BUFFER12 0xf330 +#define STB0899_BASE_TP_BUFFER12 0x00000040 +#define STB0899_OFF0_TP_BUFFER13 0xf334 +#define STB0899_BASE_TP_BUFFER13 0x00000040 +#define STB0899_OFF0_TP_BUFFER14 0xf338 +#define STB0899_BASE_TP_BUFFER14 0x00000040 +#define STB0899_OFF0_TP_BUFFER15 0xf33c +#define STB0899_BASE_TP_BUFFER15 0x00000040 +#define STB0899_OFF0_TP_BUFFER16 0xf340 +#define STB0899_BASE_TP_BUFFER16 0x00000040 +#define STB0899_OFF0_TP_BUFFER17 0xf344 +#define STB0899_BASE_TP_BUFFER17 0x00000040 +#define STB0899_OFF0_TP_BUFFER18 0xf348 +#define STB0899_BASE_TP_BUFFER18 0x00000040 +#define STB0899_OFF0_TP_BUFFER19 0xf34c +#define STB0899_BASE_TP_BUFFER19 0x00000040 +#define STB0899_OFF0_TP_BUFFER20 0xf350 +#define STB0899_BASE_TP_BUFFER20 0x00000040 +#define STB0899_OFF0_TP_BUFFER21 0xf354 +#define STB0899_BASE_TP_BUFFER21 0x00000040 +#define STB0899_OFF0_TP_BUFFER22 0xf358 +#define STB0899_BASE_TP_BUFFER22 0x00000040 +#define STB0899_OFF0_TP_BUFFER23 0xf35c +#define STB0899_BASE_TP_BUFFER23 0x00000040 +#define STB0899_OFF0_TP_BUFFER24 0xf360 +#define STB0899_BASE_TP_BUFFER24 0x00000040 +#define STB0899_OFF0_TP_BUFFER25 0xf364 +#define STB0899_BASE_TP_BUFFER25 0x00000040 +#define STB0899_OFF0_TP_BUFFER26 0xf368 +#define STB0899_BASE_TP_BUFFER26 0x00000040 +#define STB0899_OFF0_TP_BUFFER27 0xf36c +#define STB0899_BASE_TP_BUFFER27 0x00000040 +#define STB0899_OFF0_TP_BUFFER28 0xf370 +#define STB0899_BASE_TP_BUFFER28 0x00000040 +#define STB0899_OFF0_TP_BUFFER29 0xf374 +#define STB0899_BASE_TP_BUFFER29 0x00000040 +#define STB0899_OFF0_TP_BUFFER30 0xf378 +#define STB0899_BASE_TP_BUFFER30 0x00000040 +#define STB0899_OFF0_TP_BUFFER31 0xf37c +#define STB0899_BASE_TP_BUFFER31 0x00000040 +#define STB0899_OFF0_TP_BUFFER32 0xf300 +#define STB0899_BASE_TP_BUFFER32 0x00000060 +#define STB0899_OFF0_TP_BUFFER33 0xf304 +#define STB0899_BASE_TP_BUFFER33 0x00000060 +#define STB0899_OFF0_TP_BUFFER34 0xf308 +#define STB0899_BASE_TP_BUFFER34 0x00000060 +#define STB0899_OFF0_TP_BUFFER35 0xf30c +#define STB0899_BASE_TP_BUFFER35 0x00000060 +#define STB0899_OFF0_TP_BUFFER36 0xf310 +#define STB0899_BASE_TP_BUFFER36 0x00000060 +#define STB0899_OFF0_TP_BUFFER37 0xf314 +#define STB0899_BASE_TP_BUFFER37 0x00000060 +#define STB0899_OFF0_TP_BUFFER38 0xf318 +#define STB0899_BASE_TP_BUFFER38 0x00000060 +#define STB0899_OFF0_TP_BUFFER39 0xf31c +#define STB0899_BASE_TP_BUFFER39 0x00000060 +#define STB0899_OFF0_TP_BUFFER40 0xf320 +#define STB0899_BASE_TP_BUFFER40 0x00000060 +#define STB0899_OFF0_TP_BUFFER41 0xf324 +#define STB0899_BASE_TP_BUFFER41 0x00000060 +#define STB0899_OFF0_TP_BUFFER42 0xf328 +#define STB0899_BASE_TP_BUFFER42 0x00000060 +#define STB0899_OFF0_TP_BUFFER43 0xf32c +#define STB0899_BASE_TP_BUFFER43 0x00000060 +#define STB0899_OFF0_TP_BUFFER44 0xf330 +#define STB0899_BASE_TP_BUFFER44 0x00000060 +#define STB0899_OFF0_TP_BUFFER45 0xf334 +#define STB0899_BASE_TP_BUFFER45 0x00000060 +#define STB0899_OFF0_TP_BUFFER46 0xf338 +#define STB0899_BASE_TP_BUFFER46 0x00000060 +#define STB0899_OFF0_TP_BUFFER47 0xf33c +#define STB0899_BASE_TP_BUFFER47 0x00000060 +#define STB0899_OFF0_TP_BUFFER48 0xf340 +#define STB0899_BASE_TP_BUFFER48 0x00000060 +#define STB0899_OFF0_TP_BUFFER49 0xf344 +#define STB0899_BASE_TP_BUFFER49 0x00000060 +#define STB0899_OFF0_TP_BUFFER50 0xf348 +#define STB0899_BASE_TP_BUFFER50 0x00000060 +#define STB0899_OFF0_TP_BUFFER51 0xf34c +#define STB0899_BASE_TP_BUFFER51 0x00000060 +#define STB0899_OFF0_TP_BUFFER52 0xf350 +#define STB0899_BASE_TP_BUFFER52 0x00000060 +#define STB0899_OFF0_TP_BUFFER53 0xf354 +#define STB0899_BASE_TP_BUFFER53 0x00000060 +#define STB0899_OFF0_TP_BUFFER54 0xf358 +#define STB0899_BASE_TP_BUFFER54 0x00000060 +#define STB0899_OFF0_TP_BUFFER55 0xf35c +#define STB0899_BASE_TP_BUFFER55 0x00000060 +#define STB0899_OFF0_TP_BUFFER56 0xf360 +#define STB0899_BASE_TP_BUFFER56 0x00000060 +#define STB0899_OFF0_TP_BUFFER57 0xf364 +#define STB0899_BASE_TP_BUFFER57 0x00000060 +#define STB0899_OFF0_TP_BUFFER58 0xf368 +#define STB0899_BASE_TP_BUFFER58 0x00000060 +#define STB0899_OFF0_TP_BUFFER59 0xf36c +#define STB0899_BASE_TP_BUFFER59 0x00000060 +#define STB0899_OFF0_TP_BUFFER60 0xf370 +#define STB0899_BASE_TP_BUFFER60 0x00000060 +#define STB0899_OFF0_TP_BUFFER61 0xf374 +#define STB0899_BASE_TP_BUFFER61 0x00000060 +#define STB0899_OFF0_TP_BUFFER62 0xf378 +#define STB0899_BASE_TP_BUFFER62 0x00000060 +#define STB0899_OFF0_TP_BUFFER63 0xf37c +#define STB0899_BASE_TP_BUFFER63 0x00000060 + +#define STB0899_OFF0_RESET_CNTRL 0xf300 +#define STB0899_BASE_RESET_CNTRL 0x00000400 +#define STB0899_DVBS2_RESET (0x01 << 0) +#define STB0899_OFFST_DVBS2_RESET 0 +#define STB0899_WIDTH_DVBS2_RESET 1 + +#define STB0899_OFF0_ACM_ENABLE 0xf304 +#define STB0899_BASE_ACM_ENABLE 0x00000400 +#define STB0899_ACM_ENABLE 1 + +#define STB0899_OFF0_DESCR_CNTRL 0xf30c +#define STB0899_BASE_DESCR_CNTRL 0x00000400 +#define STB0899_OFFST_DESCR_CNTRL 0 +#define STB0899_WIDTH_DESCR_CNTRL 16 + +#define STB0899_OFF0_UWP_CNTRL1 0xf320 +#define STB0899_BASE_UWP_CNTRL1 0x00000400 +#define STB0899_UWP_TH_SOF (0x7fff << 11) +#define STB0899_OFFST_UWP_TH_SOF 11 +#define STB0899_WIDTH_UWP_TH_SOF 15 +#define STB0899_UWP_ESN0_QUANT (0xff << 3) +#define STB0899_OFFST_UWP_ESN0_QUANT 3 +#define STB0899_WIDTH_UWP_ESN0_QUANT 8 +#define STB0899_UWP_ESN0_AVE (0x03 << 1) +#define STB0899_OFFST_UWP_ESN0_AVE 1 +#define STB0899_WIDTH_UWP_ESN0_AVE 2 +#define STB0899_UWP_START (0x01 << 0) +#define STB0899_OFFST_UWP_START 0 +#define STB0899_WIDTH_UWP_START 1 + +#define STB0899_OFF0_UWP_CNTRL2 0xf324 +#define STB0899_BASE_UWP_CNTRL2 0x00000400 +#define STB0899_UWP_MISS_TH (0xff << 16) +#define STB0899_OFFST_UWP_MISS_TH 16 +#define STB0899_WIDTH_UWP_MISS_TH 8 +#define STB0899_FE_FINE_TRK (0xff << 8) +#define STB0899_OFFST_FE_FINE_TRK 8 +#define STB0899_WIDTH_FE_FINE_TRK 8 +#define STB0899_FE_COARSE_TRK (0xff << 0) +#define STB0899_OFFST_FE_COARSE_TRK 0 +#define STB0899_WIDTH_FE_COARSE_TRK 8 + +#define STB0899_OFF0_UWP_STAT1 0xf328 +#define STB0899_BASE_UWP_STAT1 0x00000400 +#define STB0899_UWP_STATE (0x03ff << 15) +#define STB0899_OFFST_UWP_STATE 15 +#define STB0899_WIDTH_UWP_STATE 10 +#define STB0899_UW_MAX_PEAK (0x7fff << 0) +#define STB0899_OFFST_UW_MAX_PEAK 0 +#define STB0899_WIDTH_UW_MAX_PEAK 15 + +#define STB0899_OFF0_UWP_STAT2 0xf32c +#define STB0899_BASE_UWP_STAT2 0x00000400 +#define STB0899_ESNO_EST (0x07ffff << 7) +#define STB0899_OFFST_ESN0_EST 7 +#define STB0899_WIDTH_ESN0_EST 19 +#define STB0899_UWP_DECODE_MOD (0x7f << 0) +#define STB0899_OFFST_UWP_DECODE_MOD 0 +#define STB0899_WIDTH_UWP_DECODE_MOD 7 + +#define STB0899_OFF0_DMD_CORE_ID 0xf334 +#define STB0899_BASE_DMD_CORE_ID 0x00000400 +#define STB0899_CORE_ID (0xffffffff << 0) +#define STB0899_OFFST_CORE_ID 0 +#define STB0899_WIDTH_CORE_ID 32 + +#define STB0899_OFF0_DMD_VERSION_ID 0xf33c +#define STB0899_BASE_DMD_VERSION_ID 0x00000400 +#define STB0899_VERSION_ID (0xff << 0) +#define STB0899_OFFST_VERSION_ID 0 +#define STB0899_WIDTH_VERSION_ID 8 + +#define STB0899_OFF0_DMD_STAT2 0xf340 +#define STB0899_BASE_DMD_STAT2 0x00000400 +#define STB0899_CSM_LOCK (0x01 << 1) +#define STB0899_OFFST_CSM_LOCK 1 +#define STB0899_WIDTH_CSM_LOCK 1 +#define STB0899_UWP_LOCK (0x01 << 0) +#define STB0899_OFFST_UWP_LOCK 0 +#define STB0899_WIDTH_UWP_LOCK 1 + +#define STB0899_OFF0_FREQ_ADJ_SCALE 0xf344 +#define STB0899_BASE_FREQ_ADJ_SCALE 0x00000400 +#define STB0899_FREQ_ADJ_SCALE (0x0fff << 0) +#define STB0899_OFFST_FREQ_ADJ_SCALE 0 +#define STB0899_WIDTH_FREQ_ADJ_SCALE 12 + +#define STB0899_OFF0_UWP_CNTRL3 0xf34c +#define STB0899_BASE_UWP_CNTRL3 0x00000400 +#define STB0899_UWP_TH_TRACK (0x7fff << 15) +#define STB0899_OFFST_UWP_TH_TRACK 15 +#define STB0899_WIDTH_UWP_TH_TRACK 15 +#define STB0899_UWP_TH_ACQ (0x7fff << 0) +#define STB0899_OFFST_UWP_TH_ACQ 0 +#define STB0899_WIDTH_UWP_TH_ACQ 15 + +#define STB0899_OFF0_SYM_CLK_SEL 0xf350 +#define STB0899_BASE_SYM_CLK_SEL 0x00000400 +#define STB0899_SYM_CLK_SEL (0x03 << 0) +#define STB0899_OFFST_SYM_CLK_SEL 0 +#define STB0899_WIDTH_SYM_CLK_SEL 2 + +#define STB0899_OFF0_SOF_SRCH_TO 0xf354 +#define STB0899_BASE_SOF_SRCH_TO 0x00000400 +#define STB0899_SOF_SEARCH_TIMEOUT (0x3fffff << 0) +#define STB0899_OFFST_SOF_SEARCH_TIMEOUT 0 +#define STB0899_WIDTH_SOF_SEARCH_TIMEOUT 22 + +#define STB0899_OFF0_ACQ_CNTRL1 0xf358 +#define STB0899_BASE_ACQ_CNTRL1 0x00000400 +#define STB0899_FE_FINE_ACQ (0xff << 8) +#define STB0899_OFFST_FE_FINE_ACQ 8 +#define STB0899_WIDTH_FE_FINE_ACQ 8 +#define STB0899_FE_COARSE_ACQ (0xff << 0) +#define STB0899_OFFST_FE_COARSE_ACQ 0 +#define STB0899_WIDTH_FE_COARSE_ACQ 8 + +#define STB0899_OFF0_ACQ_CNTRL2 0xf35c +#define STB0899_BASE_ACQ_CNTRL2 0x00000400 +#define STB0899_ZIGZAG (0x01 << 25) +#define STB0899_OFFST_ZIGZAG 25 +#define STB0899_WIDTH_ZIGZAG 1 +#define STB0899_NUM_STEPS (0xff << 17) +#define STB0899_OFFST_NUM_STEPS 17 +#define STB0899_WIDTH_NUM_STEPS 8 +#define STB0899_FREQ_STEPSIZE (0x1ffff << 0) +#define STB0899_OFFST_FREQ_STEPSIZE 0 +#define STB0899_WIDTH_FREQ_STEPSIZE 17 + +#define STB0899_OFF0_ACQ_CNTRL3 0xf360 +#define STB0899_BASE_ACQ_CNTRL3 0x00000400 +#define STB0899_THRESHOLD_SCL (0x3f << 23) +#define STB0899_OFFST_THRESHOLD_SCL 23 +#define STB0899_WIDTH_THRESHOLD_SCL 6 +#define STB0899_UWP_TH_SRCH (0x7fff << 8) +#define STB0899_OFFST_UWP_TH_SRCH 8 +#define STB0899_WIDTH_UWP_TH_SRCH 15 +#define STB0899_AUTO_REACQUIRE (0x01 << 7) +#define STB0899_OFFST_AUTO_REACQUIRE 7 +#define STB0899_WIDTH_AUTO_REACQUIRE 1 +#define STB0899_TRACK_LOCK_SEL (0x01 << 6) +#define STB0899_OFFST_TRACK_LOCK_SEL 6 +#define STB0899_WIDTH_TRACK_LOCK_SEL 1 +#define STB0899_ACQ_SEARCH_MODE (0x03 << 4) +#define STB0899_OFFST_ACQ_SEARCH_MODE 4 +#define STB0899_WIDTH_ACQ_SEARCH_MODE 2 +#define STB0899_CONFIRM_FRAMES (0x0f << 0) +#define STB0899_OFFST_CONFIRM_FRAMES 0 +#define STB0899_WIDTH_CONFIRM_FRAMES 4 + +#define STB0899_OFF0_FE_SETTLE 0xf364 +#define STB0899_BASE_FE_SETTLE 0x00000400 +#define STB0899_SETTLING_TIME (0x3fffff << 0) +#define STB0899_OFFST_SETTLING_TIME 0 +#define STB0899_WIDTH_SETTLING_TIME 22 + +#define STB0899_OFF0_AC_DWELL 0xf368 +#define STB0899_BASE_AC_DWELL 0x00000400 +#define STB0899_DWELL_TIME (0x3fffff << 0) +#define STB0899_OFFST_DWELL_TIME 0 +#define STB0899_WIDTH_DWELL_TIME 22 + +#define STB0899_OFF0_ACQUIRE_TRIG 0xf36c +#define STB0899_BASE_ACQUIRE_TRIG 0x00000400 +#define STB0899_ACQUIRE (0x01 << 0) +#define STB0899_OFFST_ACQUIRE 0 +#define STB0899_WIDTH_ACQUIRE 1 + +#define STB0899_OFF0_LOCK_LOST 0xf370 +#define STB0899_BASE_LOCK_LOST 0x00000400 +#define STB0899_LOCK_LOST (0x01 << 0) +#define STB0899_OFFST_LOCK_LOST 0 +#define STB0899_WIDTH_LOCK_LOST 1 + +#define STB0899_OFF0_ACQ_STAT1 0xf374 +#define STB0899_BASE_ACQ_STAT1 0x00000400 +#define STB0899_STEP_FREQ (0x1fffff << 11) +#define STB0899_OFFST_STEP_FREQ 11 +#define STB0899_WIDTH_STEP_FREQ 21 +#define STB0899_ACQ_STATE (0x07 << 8) +#define STB0899_OFFST_ACQ_STATE 8 +#define STB0899_WIDTH_ACQ_STATE 3 +#define STB0899_UW_DETECT_COUNT (0xff << 0) +#define STB0899_OFFST_UW_DETECT_COUNT 0 +#define STB0899_WIDTH_UW_DETECT_COUNT 8 + +#define STB0899_OFF0_ACQ_TIMEOUT 0xf378 +#define STB0899_BASE_ACQ_TIMEOUT 0x00000400 +#define STB0899_ACQ_TIMEOUT (0x3fffff << 0) +#define STB0899_OFFST_ACQ_TIMEOUT 0 +#define STB0899_WIDTH_ACQ_TIMEOUT 22 + +#define STB0899_OFF0_ACQ_TIME 0xf37c +#define STB0899_BASE_ACQ_TIME 0x00000400 +#define STB0899_ACQ_TIME_SYM (0xffffff << 0) +#define STB0899_OFFST_ACQ_TIME_SYM 0 +#define STB0899_WIDTH_ACQ_TIME_SYM 24 + +#define STB0899_OFF0_FINAL_AGC_CNTRL 0xf308 +#define STB0899_BASE_FINAL_AGC_CNTRL 0x00000440 +#define STB0899_FINAL_GAIN_INIT (0x3fff << 12) +#define STB0899_OFFST_FINAL_GAIN_INIT 12 +#define STB0899_WIDTH_FINAL_GAIN_INIT 14 +#define STB0899_FINAL_LOOP_GAIN (0x0f << 8) +#define STB0899_OFFST_FINAL_LOOP_GAIN 8 +#define STB0899_WIDTH_FINAL_LOOP_GAIN 4 +#define STB0899_FINAL_LD_GAIN_INIT (0x01 << 7) +#define STB0899_OFFST_FINAL_LD_GAIN_INIT 7 +#define STB0899_WIDTH_FINAL_LD_GAIN_INIT 1 +#define STB0899_FINAL_AGC_REF (0x7f << 0) +#define STB0899_OFFST_FINAL_AGC_REF 0 +#define STB0899_WIDTH_FINAL_AGC_REF 7 + +#define STB0899_OFF0_FINAL_AGC_GAIN 0xf30c +#define STB0899_BASE_FINAL_AGC_GAIN 0x00000440 +#define STB0899_FINAL_AGC_GAIN (0x3fff << 0) +#define STB0899_OFFST_FINAL_AGC_GAIN 0 +#define STB0899_WIDTH_FINAL_AGC_GAIN 14 + +#define STB0899_OFF0_EQUALIZER_INIT 0xf310 +#define STB0899_BASE_EQUALIZER_INIT 0x00000440 +#define STB0899_EQ_SRST (0x01 << 1) +#define STB0899_OFFST_EQ_SRST 1 +#define STB0899_WIDTH_EQ_SRST 1 +#define STB0899_EQ_INIT (0x01 << 0) +#define STB0899_OFFST_EQ_INIT 0 +#define STB0899_WIDTH_EQ_INIT 1 + +#define STB0899_OFF0_EQ_CNTRL 0xf314 +#define STB0899_BASE_EQ_CNTRL 0x00000440 +#define STB0899_EQ_ADAPT_MODE (0x01 << 18) +#define STB0899_OFFST_EQ_ADAPT_MODE 18 +#define STB0899_WIDTH_EQ_ADAPT_MODE 1 +#define STB0899_EQ_DELAY (0x0f << 14) +#define STB0899_OFFST_EQ_DELAY 14 +#define STB0899_WIDTH_EQ_DELAY 4 +#define STB0899_EQ_QUANT_LEVEL (0xff << 6) +#define STB0899_OFFST_EQ_QUANT_LEVEL 6 +#define STB0899_WIDTH_EQ_QUANT_LEVEL 8 +#define STB0899_EQ_DISABLE_UPDATE (0x01 << 5) +#define STB0899_OFFST_EQ_DISABLE_UPDATE 5 +#define STB0899_WIDTH_EQ_DISABLE_UPDATE 1 +#define STB0899_EQ_BYPASS (0x01 << 4) +#define STB0899_OFFST_EQ_BYPASS 4 +#define STB0899_WIDTH_EQ_BYPASS 1 +#define STB0899_EQ_SHIFT (0x0f << 0) +#define STB0899_OFFST_EQ_SHIFT 0 +#define STB0899_WIDTH_EQ_SHIFT 4 + +#define STB0899_OFF0_EQ_I_INIT_COEFF_0 0xf320 +#define STB0899_OFF1_EQ_I_INIT_COEFF_1 0xf324 +#define STB0899_OFF2_EQ_I_INIT_COEFF_2 0xf328 +#define STB0899_OFF3_EQ_I_INIT_COEFF_3 0xf32c +#define STB0899_OFF4_EQ_I_INIT_COEFF_4 0xf330 +#define STB0899_OFF5_EQ_I_INIT_COEFF_5 0xf334 +#define STB0899_OFF6_EQ_I_INIT_COEFF_6 0xf338 +#define STB0899_OFF7_EQ_I_INIT_COEFF_7 0xf33c +#define STB0899_OFF8_EQ_I_INIT_COEFF_8 0xf340 +#define STB0899_OFF9_EQ_I_INIT_COEFF_9 0xf344 +#define STB0899_OFFa_EQ_I_INIT_COEFF_10 0xf348 +#define STB0899_BASE_EQ_I_INIT_COEFF_N 0x00000440 +#define STB0899_EQ_I_INIT_COEFF_N (0x0fff << 0) +#define STB0899_OFFST_EQ_I_INIT_COEFF_N 0 +#define STB0899_WIDTH_EQ_I_INIT_COEFF_N 12 + +#define STB0899_OFF0_EQ_Q_INIT_COEFF_0 0xf350 +#define STB0899_OFF1_EQ_Q_INIT_COEFF_1 0xf354 +#define STB0899_OFF2_EQ_Q_INIT_COEFF_2 0xf358 +#define STB0899_OFF3_EQ_Q_INIT_COEFF_3 0xf35c +#define STB0899_OFF4_EQ_Q_INIT_COEFF_4 0xf360 +#define STB0899_OFF5_EQ_Q_INIT_COEFF_5 0xf364 +#define STB0899_OFF6_EQ_Q_INIT_COEFF_6 0xf368 +#define STB0899_OFF7_EQ_Q_INIT_COEFF_7 0xf36c +#define STB0899_OFF8_EQ_Q_INIT_COEFF_8 0xf370 +#define STB0899_OFF9_EQ_Q_INIT_COEFF_9 0xf374 +#define STB0899_OFFa_EQ_Q_INIT_COEFF_10 0xf378 +#define STB0899_BASE_EQ_Q_INIT_COEFF_N 0x00000440 +#define STB0899_EQ_Q_INIT_COEFF_N (0x0fff << 0) +#define STB0899_OFFST_EQ_Q_INIT_COEFF_N 0 +#define STB0899_WIDTH_EQ_Q_INIT_COEFF_N 12 + +#define STB0899_OFF0_EQ_I_OUT_COEFF_0 0xf300 +#define STB0899_OFF1_EQ_I_OUT_COEFF_1 0xf304 +#define STB0899_OFF2_EQ_I_OUT_COEFF_2 0xf308 +#define STB0899_OFF3_EQ_I_OUT_COEFF_3 0xf30c +#define STB0899_OFF4_EQ_I_OUT_COEFF_4 0xf310 +#define STB0899_OFF5_EQ_I_OUT_COEFF_5 0xf314 +#define STB0899_OFF6_EQ_I_OUT_COEFF_6 0xf318 +#define STB0899_OFF7_EQ_I_OUT_COEFF_7 0xf31c +#define STB0899_OFF8_EQ_I_OUT_COEFF_8 0xf320 +#define STB0899_OFF9_EQ_I_OUT_COEFF_9 0xf324 +#define STB0899_OFFa_EQ_I_OUT_COEFF_10 0xf328 +#define STB0899_BASE_EQ_I_OUT_COEFF_N 0x00000460 +#define STB0899_EQ_I_OUT_COEFF_N (0x0fff << 0) +#define STB0899_OFFST_EQ_I_OUT_COEFF_N 0 +#define STB0899_WIDTH_EQ_I_OUT_COEFF_N 12 + +#define STB0899_OFF0_EQ_Q_OUT_COEFF_0 0xf330 +#define STB0899_OFF1_EQ_Q_OUT_COEFF_1 0xf334 +#define STB0899_OFF2_EQ_Q_OUT_COEFF_2 0xf338 +#define STB0899_OFF3_EQ_Q_OUT_COEFF_3 0xf33c +#define STB0899_OFF4_EQ_Q_OUT_COEFF_4 0xf340 +#define STB0899_OFF5_EQ_Q_OUT_COEFF_5 0xf344 +#define STB0899_OFF6_EQ_Q_OUT_COEFF_6 0xf348 +#define STB0899_OFF7_EQ_Q_OUT_COEFF_7 0xf34c +#define STB0899_OFF8_EQ_Q_OUT_COEFF_8 0xf350 +#define STB0899_OFF9_EQ_Q_OUT_COEFF_9 0xf354 +#define STB0899_OFFa_EQ_Q_OUT_COEFF_10 0xf358 +#define STB0899_BASE_EQ_Q_OUT_COEFF_N 0x00000460 +#define STB0899_EQ_Q_OUT_COEFF_N (0x0fff << 0) +#define STB0899_OFFST_EQ_Q_OUT_COEFF_N 0 +#define STB0899_WIDTH_EQ_Q_OUT_COEFF_N 12 + +/* S2 FEC */ +#define STB0899_OFF0_BLOCK_LNGTH 0xfa04 +#define STB0899_BASE_BLOCK_LNGTH 0x00000000 +#define STB0899_BLOCK_LENGTH (0xff << 0) +#define STB0899_OFFST_BLOCK_LENGTH 0 +#define STB0899_WIDTH_BLOCK_LENGTH 8 + +#define STB0899_OFF0_ROW_STR 0xfa08 +#define STB0899_BASE_ROW_STR 0x00000000 +#define STB0899_ROW_STRIDE (0xff << 0) +#define STB0899_OFFST_ROW_STRIDE 0 +#define STB0899_WIDTH_ROW_STRIDE 8 + +#define STB0899_OFF0_MAX_ITER 0xfa0c +#define STB0899_BASE_MAX_ITER 0x00000000 +#define STB0899_MAX_ITERATIONS (0xff << 0) +#define STB0899_OFFST_MAX_ITERATIONS 0 +#define STB0899_WIDTH_MAX_ITERATIONS 8 + +#define STB0899_OFF0_BN_END_ADDR 0xfa10 +#define STB0899_BASE_BN_END_ADDR 0x00000000 +#define STB0899_BN_END_ADDR (0x0fff << 0) +#define STB0899_OFFST_BN_END_ADDR 0 +#define STB0899_WIDTH_BN_END_ADDR 12 + +#define STB0899_OFF0_CN_END_ADDR 0xfa14 +#define STB0899_BASE_CN_END_ADDR 0x00000000 +#define STB0899_CN_END_ADDR (0x0fff << 0) +#define STB0899_OFFST_CN_END_ADDR 0 +#define STB0899_WIDTH_CN_END_ADDR 12 + +#define STB0899_OFF0_INFO_LENGTH 0xfa1c +#define STB0899_BASE_INFO_LENGTH 0x00000000 +#define STB0899_INFO_LENGTH (0xff << 0) +#define STB0899_OFFST_INFO_LENGTH 0 +#define STB0899_WIDTH_INFO_LENGTH 8 + +#define STB0899_OFF0_BOT_ADDR 0xfa20 +#define STB0899_BASE_BOT_ADDR 0x00000000 +#define STB0899_BOTTOM_BASE_ADDR (0x03ff << 0) +#define STB0899_OFFST_BOTTOM_BASE_ADDR 0 +#define STB0899_WIDTH_BOTTOM_BASE_ADDR 10 + +#define STB0899_OFF0_BCH_BLK_LN 0xfa24 +#define STB0899_BASE_BCH_BLK_LN 0x00000000 +#define STB0899_BCH_BLOCK_LENGTH (0xffff << 0) +#define STB0899_OFFST_BCH_BLOCK_LENGTH 0 +#define STB0899_WIDTH_BCH_BLOCK_LENGTH 16 + +#define STB0899_OFF0_BCH_T 0xfa28 +#define STB0899_BASE_BCH_T 0x00000000 +#define STB0899_BCH_T (0x0f << 0) +#define STB0899_OFFST_BCH_T 0 +#define STB0899_WIDTH_BCH_T 4 + +#define STB0899_OFF0_CNFG_MODE 0xfa00 +#define STB0899_BASE_CNFG_MODE 0x00000800 +#define STB0899_MODCOD (0x1f << 2) +#define STB0899_OFFST_MODCOD 2 +#define STB0899_WIDTH_MODCOD 5 +#define STB0899_MODCOD_SEL (0x01 << 1) +#define STB0899_OFFST_MODCOD_SEL 1 +#define STB0899_WIDTH_MODCOD_SEL 1 +#define STB0899_CONFIG_MODE (0x01 << 0) +#define STB0899_OFFST_CONFIG_MODE 0 +#define STB0899_WIDTH_CONFIG_MODE 1 + +#define STB0899_OFF0_LDPC_STAT 0xfa04 +#define STB0899_BASE_LDPC_STAT 0x00000800 +#define STB0899_ITERATION (0xff << 3) +#define STB0899_OFFST_ITERATION 3 +#define STB0899_WIDTH_ITERATION 8 +#define STB0899_LDPC_DEC_STATE (0x07 << 0) +#define STB0899_OFFST_LDPC_DEC_STATE 0 +#define STB0899_WIDTH_LDPC_DEC_STATE 3 + +#define STB0899_OFF0_ITER_SCALE 0xfa08 +#define STB0899_BASE_ITER_SCALE 0x00000800 +#define STB0899_ITERATION_SCALE (0xff << 0) +#define STB0899_OFFST_ITERATION_SCALE 0 +#define STB0899_WIDTH_ITERATION_SCALE 8 + +#define STB0899_OFF0_INPUT_MODE 0xfa0c +#define STB0899_BASE_INPUT_MODE 0x00000800 +#define STB0899_SD_BLOCK1_STREAM0 (0x01 << 0) +#define STB0899_OFFST_SD_BLOCK1_STREAM0 0 +#define STB0899_WIDTH_SD_BLOCK1_STREAM0 1 + +#define STB0899_OFF0_LDPCDECRST 0xfa10 +#define STB0899_BASE_LDPCDECRST 0x00000800 +#define STB0899_LDPC_DEC_RST (0x01 << 0) +#define STB0899_OFFST_LDPC_DEC_RST 0 +#define STB0899_WIDTH_LDPC_DEC_RST 1 + +#define STB0899_OFF0_CLK_PER_BYTE_RW 0xfa14 +#define STB0899_BASE_CLK_PER_BYTE_RW 0x00000800 +#define STB0899_CLKS_PER_BYTE (0x0f << 0) +#define STB0899_OFFST_CLKS_PER_BYTE 0 +#define STB0899_WIDTH_CLKS_PER_BYTE 5 + +#define STB0899_OFF0_BCH_ERRORS 0xfa18 +#define STB0899_BASE_BCH_ERRORS 0x00000800 +#define STB0899_BCH_ERRORS (0x0f << 0) +#define STB0899_OFFST_BCH_ERRORS 0 +#define STB0899_WIDTH_BCH_ERRORS 4 + +#define STB0899_OFF0_LDPC_ERRORS 0xfa1c +#define STB0899_BASE_LDPC_ERRORS 0x00000800 +#define STB0899_LDPC_ERRORS (0xffff << 0) +#define STB0899_OFFST_LDPC_ERRORS 0 +#define STB0899_WIDTH_LDPC_ERRORS 16 + +#define STB0899_OFF0_BCH_MODE 0xfa20 +#define STB0899_BASE_BCH_MODE 0x00000800 +#define STB0899_BCH_CORRECT_N (0x01 << 1) +#define STB0899_OFFST_BCH_CORRECT_N 1 +#define STB0899_WIDTH_BCH_CORRECT_N 1 +#define STB0899_FULL_BYPASS (0x01 << 0) +#define STB0899_OFFST_FULL_BYPASS 0 +#define STB0899_WIDTH_FULL_BYPASS 1 + +#define STB0899_OFF0_ERR_ACC_PER 0xfa24 +#define STB0899_BASE_ERR_ACC_PER 0x00000800 +#define STB0899_BCH_ERR_ACC_PERIOD (0x0f << 0) +#define STB0899_OFFST_BCH_ERR_ACC_PERIOD 0 +#define STB0899_WIDTH_BCH_ERR_ACC_PERIOD 4 + +#define STB0899_OFF0_BCH_ERR_ACC 0xfa28 +#define STB0899_BASE_BCH_ERR_ACC 0x00000800 +#define STB0899_BCH_ERR_ACCUM (0xff << 0) +#define STB0899_OFFST_BCH_ERR_ACCUM 0 +#define STB0899_WIDTH_BCH_ERR_ACCUM 8 + +#define STB0899_OFF0_FEC_CORE_ID_REG 0xfa2c +#define STB0899_BASE_FEC_CORE_ID_REG 0x00000800 +#define STB0899_FEC_CORE_ID (0xffffffff << 0) +#define STB0899_OFFST_FEC_CORE_ID 0 +#define STB0899_WIDTH_FEC_CORE_ID 32 + +#define STB0899_OFF0_FEC_VER_ID_REG 0xfa34 +#define STB0899_BASE_FEC_VER_ID_REG 0x00000800 +#define STB0899_FEC_VER_ID (0xff << 0) +#define STB0899_OFFST_FEC_VER_ID 0 +#define STB0899_WIDTH_FEC_VER_ID 8 + +#define STB0899_OFF0_FEC_TP_SEL 0xfa38 +#define STB0899_BASE_FEC_TP_SEL 0x00000800 + +#define STB0899_OFF0_CSM_CNTRL1 0xf310 +#define STB0899_BASE_CSM_CNTRL1 0x00000400 +#define STB0899_CSM_FORCE_FREQLOCK (0x01 << 19) +#define STB0899_OFFST_CSM_FORCE_FREQLOCK 19 +#define STB0899_WIDTH_CSM_FORCE_FREQLOCK 1 +#define STB0899_CSM_FREQ_LOCKSTATE (0x01 << 18) +#define STB0899_OFFST_CSM_FREQ_LOCKSTATE 18 +#define STB0899_WIDTH_CSM_FREQ_LOCKSTATE 1 +#define STB0899_CSM_AUTO_PARAM (0x01 << 17) +#define STB0899_OFFST_CSM_AUTO_PARAM 17 +#define STB0899_WIDTH_CSM_AUTO_PARAM 1 +#define STB0899_FE_LOOP_SHIFT (0x07 << 14) +#define STB0899_OFFST_FE_LOOP_SHIFT 14 +#define STB0899_WIDTH_FE_LOOP_SHIFT 3 +#define STB0899_CSM_AGC_SHIFT (0x07 << 11) +#define STB0899_OFFST_CSM_AGC_SHIFT 11 +#define STB0899_WIDTH_CSM_AGC_SHIFT 3 +#define STB0899_CSM_AGC_GAIN (0x1ff << 2) +#define STB0899_OFFST_CSM_AGC_GAIN 2 +#define STB0899_WIDTH_CSM_AGC_GAIN 9 +#define STB0899_CSM_TWO_PASS (0x01 << 1) +#define STB0899_OFFST_CSM_TWO_PASS 1 +#define STB0899_WIDTH_CSM_TWO_PASS 1 +#define STB0899_CSM_DVT_TABLE (0x01 << 0) +#define STB0899_OFFST_CSM_DVT_TABLE 0 +#define STB0899_WIDTH_CSM_DVT_TABLE 1 + +#define STB0899_OFF0_CSM_CNTRL2 0xf314 +#define STB0899_BASE_CSM_CNTRL2 0x00000400 +#define STB0899_CSM_GAMMA_RHO_ACQ (0x1ff << 9) +#define STB0899_OFFST_CSM_GAMMA_RHOACQ 9 +#define STB0899_WIDTH_CSM_GAMMA_RHOACQ 9 +#define STB0899_CSM_GAMMA_ACQ (0x1ff << 0) +#define STB0899_OFFST_CSM_GAMMA_ACQ 0 +#define STB0899_WIDTH_CSM_GAMMA_ACQ 9 + +#define STB0899_OFF0_CSM_CNTRL3 0xf318 +#define STB0899_BASE_CSM_CNTRL3 0x00000400 +#define STB0899_CSM_GAMMA_RHO_TRACK (0x1ff << 9) +#define STB0899_OFFST_CSM_GAMMA_RHOTRACK 9 +#define STB0899_WIDTH_CSM_GAMMA_RHOTRACK 9 +#define STB0899_CSM_GAMMA_TRACK (0x1ff << 0) +#define STB0899_OFFST_CSM_GAMMA_TRACK 0 +#define STB0899_WIDTH_CSM_GAMMA_TRACK 9 + +#define STB0899_OFF0_CSM_CNTRL4 0xf31c +#define STB0899_BASE_CSM_CNTRL4 0x00000400 +#define STB0899_CSM_PHASEDIFF_THRESH (0x0f << 8) +#define STB0899_OFFST_CSM_PHASEDIFF_THRESH 8 +#define STB0899_WIDTH_CSM_PHASEDIFF_THRESH 4 +#define STB0899_CSM_LOCKCOUNT_THRESH (0xff << 0) +#define STB0899_OFFST_CSM_LOCKCOUNT_THRESH 0 +#define STB0899_WIDTH_CSM_LOCKCOUNT_THRESH 8 + +/* Check on chapter 8 page 42 */ +#define STB0899_ERRCTRL1 0xf574 +#define STB0899_ERRCTRL2 0xf575 +#define STB0899_ERRCTRL3 0xf576 +#define STB0899_ERR_SRC_S1 (0x1f << 3) +#define STB0899_OFFST_ERR_SRC_S1 3 +#define STB0899_WIDTH_ERR_SRC_S1 5 +#define STB0899_ERR_SRC_S2 (0x0f << 0) +#define STB0899_OFFST_ERR_SRC_S2 0 +#define STB0899_WIDTH_ERR_SRC_S2 4 +#define STB0899_NOE (0x07 << 0) +#define STB0899_OFFST_NOE 0 +#define STB0899_WIDTH_NOE 3 + +#define STB0899_ECNT1M 0xf524 +#define STB0899_ECNT1L 0xf525 +#define STB0899_ECNT2M 0xf526 +#define STB0899_ECNT2L 0xf527 +#define STB0899_ECNT3M 0xf528 +#define STB0899_ECNT3L 0xf529 + +#define STB0899_DMONMSK1 0xf57b +#define STB0899_DMONMSK1_WAIT_1STEP (1 << 7) +#define STB0899_DMONMSK1_FREE_14 (1 << 6) +#define STB0899_DMONMSK1_AVRGVIT_CALC (1 << 5) +#define STB0899_DMONMSK1_FREE_12 (1 << 4) +#define STB0899_DMONMSK1_FREE_11 (1 << 3) +#define STB0899_DMONMSK1_B0DIV_CALC (1 << 2) +#define STB0899_DMONMSK1_KDIVB1_CALC (1 << 1) +#define STB0899_DMONMSK1_KDIVB2_CALC (1 << 0) + +#define STB0899_DMONMSK0 0xf57c +#define STB0899_DMONMSK0_SMOTTH_CALC (1 << 7) +#define STB0899_DMONMSK0_FREE_6 (1 << 6) +#define STB0899_DMONMSK0_SIGPOWER_CALC (1 << 5) +#define STB0899_DMONMSK0_QSEUIL_CALC (1 << 4) +#define STB0899_DMONMSK0_FREE_3 (1 << 3) +#define STB0899_DMONMSK0_FREE_2 (1 << 2) +#define STB0899_DMONMSK0_KVDIVB1_CALC (1 << 1) +#define STB0899_DMONMSK0_KVDIVB2_CALC (1 << 0) + +#define STB0899_TSULC 0xf549 +#define STB0899_ULNOSYNCBYTES (0x01 << 7) +#define STB0899_OFFST_ULNOSYNCBYTES 7 +#define STB0899_WIDTH_ULNOSYNCBYTES 1 +#define STB0899_ULPARITY_ON (0x01 << 6) +#define STB0899_OFFST_ULPARITY_ON 6 +#define STB0899_WIDTH_ULPARITY_ON 1 +#define STB0899_ULSYNCOUTRS (0x01 << 5) +#define STB0899_OFFST_ULSYNCOUTRS 5 +#define STB0899_WIDTH_ULSYNCOUTRS 1 +#define STB0899_ULDSS_PACKETS (0x01 << 0) +#define STB0899_OFFST_ULDSS_PACKETS 0 +#define STB0899_WIDTH_ULDSS_PACKETS 1 + +#define STB0899_TSLPL 0xf54b +#define STB0899_LLDVBS2_MODE (0x01 << 4) +#define STB0899_OFFST_LLDVBS2_MODE 4 +#define STB0899_WIDTH_LLDVBS2_MODE 1 +#define STB0899_LLISSYI_ON (0x01 << 3) +#define STB0899_OFFST_LLISSYI_ON 3 +#define STB0899_WIDTH_LLISSYI_ON 1 +#define STB0899_LLNPD_ON (0x01 << 2) +#define STB0899_OFFST_LLNPD_ON 2 +#define STB0899_WIDTH_LLNPD_ON 1 +#define STB0899_LLCRC8_ON (0x01 << 1) +#define STB0899_OFFST_LLCRC8_ON 1 +#define STB0899_WIDTH_LLCRC8_ON 1 + +#define STB0899_TSCFGH 0xf54c +#define STB0899_OUTRS_PS (0x01 << 6) +#define STB0899_OFFST_OUTRS_PS 6 +#define STB0899_WIDTH_OUTRS_PS 1 +#define STB0899_SYNCBYTE (0x01 << 5) +#define STB0899_OFFST_SYNCBYTE 5 +#define STB0899_WIDTH_SYNCBYTE 1 +#define STB0899_PFBIT (0x01 << 4) +#define STB0899_OFFST_PFBIT 4 +#define STB0899_WIDTH_PFBIT 1 +#define STB0899_ERR_BIT (0x01 << 3) +#define STB0899_OFFST_ERR_BIT 3 +#define STB0899_WIDTH_ERR_BIT 1 +#define STB0899_MPEG (0x01 << 2) +#define STB0899_OFFST_MPEG 2 +#define STB0899_WIDTH_MPEG 1 +#define STB0899_CLK_POL (0x01 << 1) +#define STB0899_OFFST_CLK_POL 1 +#define STB0899_WIDTH_CLK_POL 1 +#define STB0899_FORCE0 (0x01 << 0) +#define STB0899_OFFST_FORCE0 0 +#define STB0899_WIDTH_FORCE0 1 + +#define STB0899_TSCFGM 0xf54d +#define STB0899_LLPRIORITY (0x01 << 3) +#define STB0899_OFFST_LLPRIORIY 3 +#define STB0899_WIDTH_LLPRIORITY 1 +#define STB0899_EN188 (0x01 << 2) +#define STB0899_OFFST_EN188 2 +#define STB0899_WIDTH_EN188 1 + +#define STB0899_TSCFGL 0xf54e +#define STB0899_DEL_ERRPCK (0x01 << 7) +#define STB0899_OFFST_DEL_ERRPCK 7 +#define STB0899_WIDTH_DEL_ERRPCK 1 +#define STB0899_ERRFLAGSTD (0x01 << 5) +#define STB0899_OFFST_ERRFLAGSTD 5 +#define STB0899_WIDTH_ERRFLAGSTD 1 +#define STB0899_MPEGERR (0x01 << 4) +#define STB0899_OFFST_MPEGERR 4 +#define STB0899_WIDTH_MPEGERR 1 +#define STB0899_BCH_CHK (0x01 << 3) +#define STB0899_OFFST_BCH_CHK 5 +#define STB0899_WIDTH_BCH_CHK 1 +#define STB0899_CRC8CHK (0x01 << 2) +#define STB0899_OFFST_CRC8CHK 2 +#define STB0899_WIDTH_CRC8CHK 1 +#define STB0899_SPEC_INFO (0x01 << 1) +#define STB0899_OFFST_SPEC_INFO 1 +#define STB0899_WIDTH_SPEC_INFO 1 +#define STB0899_LOW_PRIO_CLK (0x01 << 0) +#define STB0899_OFFST_LOW_PRIO_CLK 0 +#define STB0899_WIDTH_LOW_PRIO_CLK 1 +#define STB0899_ERROR_NORM (0x00 << 0) +#define STB0899_OFFST_ERROR_NORM 0 +#define STB0899_WIDTH_ERROR_NORM 0 + +#define STB0899_TSOUT 0xf54f +#define STB0899_RSSYNCDEL 0xf550 +#define STB0899_TSINHDELH 0xf551 +#define STB0899_TSINHDELM 0xf552 +#define STB0899_TSINHDELL 0xf553 +#define STB0899_TSLLSTKM 0xf55a +#define STB0899_TSLLSTKL 0xf55b +#define STB0899_TSULSTKM 0xf55c +#define STB0899_TSULSTKL 0xf55d +#define STB0899_TSSTATUS 0xf561 + +#define STB0899_PDELCTRL 0xf600 +#define STB0899_INVERT_RES (0x01 << 7) +#define STB0899_OFFST_INVERT_RES 7 +#define STB0899_WIDTH_INVERT_RES 1 +#define STB0899_FORCE_ACCEPTED (0x01 << 6) +#define STB0899_OFFST_FORCE_ACCEPTED 6 +#define STB0899_WIDTH_FORCE_ACCEPTED 1 +#define STB0899_FILTER_EN (0x01 << 5) +#define STB0899_OFFST_FILTER_EN 5 +#define STB0899_WIDTH_FILTER_EN 1 +#define STB0899_LOCKFALL_THRESH (0x01 << 4) +#define STB0899_OFFST_LOCKFALL_THRESH 4 +#define STB0899_WIDTH_LOCKFALL_THRESH 1 +#define STB0899_HYST_EN (0x01 << 3) +#define STB0899_OFFST_HYST_EN 3 +#define STB0899_WIDTH_HYST_EN 1 +#define STB0899_HYST_SWRST (0x01 << 2) +#define STB0899_OFFST_HYST_SWRST 2 +#define STB0899_WIDTH_HYST_SWRST 1 +#define STB0899_ALGO_EN (0x01 << 1) +#define STB0899_OFFST_ALGO_EN 1 +#define STB0899_WIDTH_ALGO_EN 1 +#define STB0899_ALGO_SWRST (0x01 << 0) +#define STB0899_OFFST_ALGO_SWRST 0 +#define STB0899_WIDTH_ALGO_SWRST 1 + +#define STB0899_PDELCTRL2 0xf601 +#define STB0899_BBHCTRL1 0xf602 +#define STB0899_BBHCTRL2 0xf603 +#define STB0899_HYSTTHRESH 0xf604 + +#define STB0899_MATCSTM 0xf605 +#define STB0899_MATCSTL 0xf606 +#define STB0899_UPLCSTM 0xf607 +#define STB0899_UPLCSTL 0xf608 +#define STB0899_DFLCSTM 0xf609 +#define STB0899_DFLCSTL 0xf60a +#define STB0899_SYNCCST 0xf60b +#define STB0899_SYNCDCSTM 0xf60c +#define STB0899_SYNCDCSTL 0xf60d +#define STB0899_ISI_ENTRY 0xf60e +#define STB0899_ISI_BIT_EN 0xf60f +#define STB0899_MATSTRM 0xf610 +#define STB0899_MATSTRL 0xf611 +#define STB0899_UPLSTRM 0xf612 +#define STB0899_UPLSTRL 0xf613 +#define STB0899_DFLSTRM 0xf614 +#define STB0899_DFLSTRL 0xf615 +#define STB0899_SYNCSTR 0xf616 +#define STB0899_SYNCDSTRM 0xf617 +#define STB0899_SYNCDSTRL 0xf618 + +#define STB0899_CFGPDELSTATUS1 0xf619 +#define STB0899_BADDFL (0x01 << 6) +#define STB0899_OFFST_BADDFL 6 +#define STB0899_WIDTH_BADDFL 1 +#define STB0899_CONTINUOUS_STREAM (0x01 << 5) +#define STB0899_OFFST_CONTINUOUS_STREAM 5 +#define STB0899_WIDTH_CONTINUOUS_STREAM 1 +#define STB0899_ACCEPTED_STREAM (0x01 << 4) +#define STB0899_OFFST_ACCEPTED_STREAM 4 +#define STB0899_WIDTH_ACCEPTED_STREAM 1 +#define STB0899_BCH_ERRFLAG (0x01 << 3) +#define STB0899_OFFST_BCH_ERRFLAG 3 +#define STB0899_WIDTH_BCH_ERRFLAG 1 +#define STB0899_CRCRES (0x01 << 2) +#define STB0899_OFFST_CRCRES 2 +#define STB0899_WIDTH_CRCRES 1 +#define STB0899_CFGPDELSTATUS_LOCK (0x01 << 1) +#define STB0899_OFFST_CFGPDELSTATUS_LOCK 1 +#define STB0899_WIDTH_CFGPDELSTATUS_LOCK 1 +#define STB0899_1STLOCK (0x01 << 0) +#define STB0899_OFFST_1STLOCK 0 +#define STB0899_WIDTH_1STLOCK 1 + +#define STB0899_CFGPDELSTATUS2 0xf61a +#define STB0899_BBFERRORM 0xf61b +#define STB0899_BBFERRORL 0xf61c +#define STB0899_UPKTERRORM 0xf61d +#define STB0899_UPKTERRORL 0xf61e + +#define STB0899_TSTCK 0xff10 + +#define STB0899_TSTRES 0xff11 +#define STB0899_FRESLDPC (0x01 << 7) +#define STB0899_OFFST_FRESLDPC 7 +#define STB0899_WIDTH_FRESLDPC 1 +#define STB0899_FRESRS (0x01 << 6) +#define STB0899_OFFST_FRESRS 6 +#define STB0899_WIDTH_FRESRS 1 +#define STB0899_FRESVIT (0x01 << 5) +#define STB0899_OFFST_FRESVIT 5 +#define STB0899_WIDTH_FRESVIT 1 +#define STB0899_FRESMAS1_2 (0x01 << 4) +#define STB0899_OFFST_FRESMAS1_2 4 +#define STB0899_WIDTH_FRESMAS1_2 1 +#define STB0899_FRESACS (0x01 << 3) +#define STB0899_OFFST_FRESACS 3 +#define STB0899_WIDTH_FRESACS 1 +#define STB0899_FRESSYM (0x01 << 2) +#define STB0899_OFFST_FRESSYM 2 +#define STB0899_WIDTH_FRESSYM 1 +#define STB0899_FRESMAS (0x01 << 1) +#define STB0899_OFFST_FRESMAS 1 +#define STB0899_WIDTH_FRESMAS 1 +#define STB0899_FRESINT (0x01 << 0) +#define STB0899_OFFST_FRESINIT 0 +#define STB0899_WIDTH_FRESINIT 1 + +#define STB0899_TSTOUT 0xff12 +#define STB0899_EN_SIGNATURE (0x01 << 7) +#define STB0899_OFFST_EN_SIGNATURE 7 +#define STB0899_WIDTH_EN_SIGNATURE 1 +#define STB0899_BCLK_CLK (0x01 << 6) +#define STB0899_OFFST_BCLK_CLK 6 +#define STB0899_WIDTH_BCLK_CLK 1 +#define STB0899_SGNL_OUT (0x01 << 5) +#define STB0899_OFFST_SGNL_OUT 5 +#define STB0899_WIDTH_SGNL_OUT 1 +#define STB0899_TS (0x01 << 4) +#define STB0899_OFFST_TS 4 +#define STB0899_WIDTH_TS 1 +#define STB0899_CTEST (0x01 << 0) +#define STB0899_OFFST_CTEST 0 +#define STB0899_WIDTH_CTEST 1 + +#define STB0899_TSTIN 0xff13 +#define STB0899_TEST_IN (0x01 << 7) +#define STB0899_OFFST_TEST_IN 7 +#define STB0899_WIDTH_TEST_IN 1 +#define STB0899_EN_ADC (0x01 << 6) +#define STB0899_OFFST_EN_ADC 6 +#define STB0899_WIDTH_ENADC 1 +#define STB0899_SGN_ADC (0x01 << 5) +#define STB0899_OFFST_SGN_ADC 5 +#define STB0899_WIDTH_SGN_ADC 1 +#define STB0899_BCLK_IN (0x01 << 4) +#define STB0899_OFFST_BCLK_IN 4 +#define STB0899_WIDTH_BCLK_IN 1 +#define STB0899_JETONIN_MODE (0x01 << 3) +#define STB0899_OFFST_JETONIN_MODE 3 +#define STB0899_WIDTH_JETONIN_MODE 1 +#define STB0899_BCLK_VALUE (0x01 << 2) +#define STB0899_OFFST_BCLK_VALUE 2 +#define STB0899_WIDTH_BCLK_VALUE 1 +#define STB0899_SGNRST_T12 (0x01 << 1) +#define STB0899_OFFST_SGNRST_T12 1 +#define STB0899_WIDTH_SGNRST_T12 1 +#define STB0899_LOWSP_ENAX (0x01 << 0) +#define STB0899_OFFST_LOWSP_ENAX 0 +#define STB0899_WIDTH_LOWSP_ENAX 1 + +#define STB0899_TSTSYS 0xff14 +#define STB0899_TSTCHIP 0xff15 +#define STB0899_TSTFREE 0xff16 +#define STB0899_TSTI2C 0xff17 +#define STB0899_BITSPEEDM 0xff1c +#define STB0899_BITSPEEDL 0xff1d +#define STB0899_TBUSBIT 0xff1e +#define STB0899_TSTDIS 0xff24 +#define STB0899_TSTDISRX 0xff25 +#define STB0899_TSTJETON 0xff28 +#define STB0899_TSTDCADJ 0xff40 +#define STB0899_TSTAGC1 0xff41 +#define STB0899_TSTAGC1N 0xff42 +#define STB0899_TSTPOLYPH 0xff48 +#define STB0899_TSTR 0xff49 +#define STB0899_TSTAGC2 0xff4a +#define STB0899_TSTCTL1 0xff4b +#define STB0899_TSTCTL2 0xff4c +#define STB0899_TSTCTL3 0xff4d +#define STB0899_TSTDEMAP 0xff50 +#define STB0899_TSTDEMAP2 0xff51 +#define STB0899_TSTDEMMON 0xff52 +#define STB0899_TSTRATE 0xff53 +#define STB0899_TSTSELOUT 0xff54 +#define STB0899_TSYNC 0xff55 +#define STB0899_TSTERR 0xff56 +#define STB0899_TSTRAM1 0xff58 +#define STB0899_TSTVSELOUT 0xff59 +#define STB0899_TSTFORCEIN 0xff5a +#define STB0899_TSTRS1 0xff5c +#define STB0899_TSTRS2 0xff5d +#define STB0899_TSTRS3 0xff53 + +#define STB0899_INTBUFSTATUS 0xf200 +#define STB0899_INTBUFCTRL 0xf201 +#define STB0899_PCKLENUL 0xf55e +#define STB0899_PCKLENLL 0xf55f +#define STB0899_RSPCKLEN 0xf560 + +/* 2 registers */ +#define STB0899_SYNCDCST 0xf60c + +/* DiSEqC */ +#define STB0899_DISCNTRL1 0xf0a0 +#define STB0899_TIMOFF (0x01 << 7) +#define STB0899_OFFST_TIMOFF 7 +#define STB0899_WIDTH_TIMOFF 1 +#define STB0899_DISEQCRESET (0x01 << 6) +#define STB0899_OFFST_DISEQCRESET 6 +#define STB0899_WIDTH_DISEQCRESET 1 +#define STB0899_TIMCMD (0x03 << 4) +#define STB0899_OFFST_TIMCMD 4 +#define STB0899_WIDTH_TIMCMD 2 +#define STB0899_DISPRECHARGE (0x01 << 2) +#define STB0899_OFFST_DISPRECHARGE 2 +#define STB0899_WIDTH_DISPRECHARGE 1 +#define STB0899_DISEQCMODE (0x03 << 0) +#define STB0899_OFFST_DISEQCMODE 0 +#define STB0899_WIDTH_DISEQCMODE 2 + +#define STB0899_DISCNTRL2 0xf0a1 +#define STB0899_RECEIVER_ON (0x01 << 7) +#define STB0899_OFFST_RECEIVER_ON 7 +#define STB0899_WIDTH_RECEIVER_ON 1 +#define STB0899_IGNO_SHORT_22K (0x01 << 6) +#define STB0899_OFFST_IGNO_SHORT_22K 6 +#define STB0899_WIDTH_IGNO_SHORT_22K 1 +#define STB0899_ONECHIP_TRX (0x01 << 5) +#define STB0899_OFFST_ONECHIP_TRX 5 +#define STB0899_WIDTH_ONECHIP_TRX 1 +#define STB0899_EXT_ENVELOP (0x01 << 4) +#define STB0899_OFFST_EXT_ENVELOP 4 +#define STB0899_WIDTH_EXT_ENVELOP 1 +#define STB0899_PIN_SELECT (0x03 << 2) +#define STB0899_OFFST_PIN_SELCT 2 +#define STB0899_WIDTH_PIN_SELCT 2 +#define STB0899_IRQ_RXEND (0x01 << 1) +#define STB0899_OFFST_IRQ_RXEND 1 +#define STB0899_WIDTH_IRQ_RXEND 1 +#define STB0899_IRQ_4NBYTES (0x01 << 0) +#define STB0899_OFFST_IRQ_4NBYTES 0 +#define STB0899_WIDTH_IRQ_4NBYTES 1 + +#define STB0899_DISRX_ST0 0xf0a4 +#define STB0899_RXEND (0x01 << 7) +#define STB0899_OFFST_RXEND 7 +#define STB0899_WIDTH_RXEND 1 +#define STB0899_RXACTIVE (0x01 << 6) +#define STB0899_OFFST_RXACTIVE 6 +#define STB0899_WIDTH_RXACTIVE 1 +#define STB0899_SHORT22K (0x01 << 5) +#define STB0899_OFFST_SHORT22K 5 +#define STB0899_WIDTH_SHORT22K 1 +#define STB0899_CONTTONE (0x01 << 4) +#define STB0899_OFFST_CONTTONE 4 +#define STB0899_WIDTH_CONTONE 1 +#define STB0899_4BFIFOREDY (0x01 << 3) +#define STB0899_OFFST_4BFIFOREDY 3 +#define STB0899_WIDTH_4BFIFOREDY 1 +#define STB0899_FIFOEMPTY (0x01 << 2) +#define STB0899_OFFST_FIFOEMPTY 2 +#define STB0899_WIDTH_FIFOEMPTY 1 +#define STB0899_ABORTTRX (0x01 << 0) +#define STB0899_OFFST_ABORTTRX 0 +#define STB0899_WIDTH_ABORTTRX 1 + +#define STB0899_DISRX_ST1 0xf0a5 +#define STB0899_RXFAIL (0x01 << 7) +#define STB0899_OFFST_RXFAIL 7 +#define STB0899_WIDTH_RXFAIL 1 +#define STB0899_FIFOPFAIL (0x01 << 6) +#define STB0899_OFFST_FIFOPFAIL 6 +#define STB0899_WIDTH_FIFOPFAIL 1 +#define STB0899_RXNONBYTES (0x01 << 5) +#define STB0899_OFFST_RXNONBYTES 5 +#define STB0899_WIDTH_RXNONBYTES 1 +#define STB0899_FIFOOVF (0x01 << 4) +#define STB0899_OFFST_FIFOOVF 4 +#define STB0899_WIDTH_FIFOOVF 1 +#define STB0899_FIFOBYTENBR (0x0f << 0) +#define STB0899_OFFST_FIFOBYTENBR 0 +#define STB0899_WIDTH_FIFOBYTENBR 4 + +#define STB0899_DISPARITY 0xf0a6 + +#define STB0899_DISFIFO 0xf0a7 + +#define STB0899_DISSTATUS 0xf0a8 +#define STB0899_FIFOFULL (0x01 << 6) +#define STB0899_OFFST_FIFOFULL 6 +#define STB0899_WIDTH_FIFOFULL 1 +#define STB0899_TXIDLE (0x01 << 5) +#define STB0899_OFFST_TXIDLE 5 +#define STB0899_WIDTH_TXIDLE 1 +#define STB0899_GAPBURST (0x01 << 4) +#define STB0899_OFFST_GAPBURST 4 +#define STB0899_WIDTH_GAPBURST 1 +#define STB0899_TXFIFOBYTES (0x0f << 0) +#define STB0899_OFFST_TXFIFOBYTES 0 +#define STB0899_WIDTH_TXFIFOBYTES 4 +#define STB0899_DISF22 0xf0a9 + +#define STB0899_DISF22RX 0xf0aa + +/* General Purpose */ +#define STB0899_SYSREG 0xf101 +#define STB0899_ACRPRESC 0xf110 +#define STB0899_OFFST_RSVD2 7 +#define STB0899_WIDTH_RSVD2 1 +#define STB0899_OFFST_ACRPRESC 4 +#define STB0899_WIDTH_ACRPRESC 3 +#define STB0899_OFFST_RSVD1 3 +#define STB0899_WIDTH_RSVD1 1 +#define STB0899_OFFST_ACRPRESC2 0 +#define STB0899_WIDTH_ACRPRESC2 3 + +#define STB0899_ACRDIV1 0xf111 +#define STB0899_ACRDIV2 0xf112 +#define STB0899_DACR1 0xf113 +#define STB0899_DACR2 0xf114 +#define STB0899_OUTCFG 0xf11c +#define STB0899_MODECFG 0xf11d +#define STB0899_NCOARSE 0xf1b3 + +#define STB0899_SYNTCTRL 0xf1b6 +#define STB0899_STANDBY (0x01 << 7) +#define STB0899_OFFST_STANDBY 7 +#define STB0899_WIDTH_STANDBY 1 +#define STB0899_BYPASSPLL (0x01 << 6) +#define STB0899_OFFST_BYPASSPLL 6 +#define STB0899_WIDTH_BYPASSPLL 1 +#define STB0899_SEL1XRATIO (0x01 << 5) +#define STB0899_OFFST_SEL1XRATIO 5 +#define STB0899_WIDTH_SEL1XRATIO 1 +#define STB0899_SELOSCI (0x01 << 1) +#define STB0899_OFFST_SELOSCI 1 +#define STB0899_WIDTH_SELOSCI 1 + +#define STB0899_FILTCTRL 0xf1b7 +#define STB0899_SYSCTRL 0xf1b8 + +#define STB0899_STOPCLK1 0xf1c2 +#define STB0899_STOP_CKINTBUF108 (0x01 << 7) +#define STB0899_OFFST_STOP_CKINTBUF108 7 +#define STB0899_WIDTH_STOP_CKINTBUF108 1 +#define STB0899_STOP_CKINTBUF216 (0x01 << 6) +#define STB0899_OFFST_STOP_CKINTBUF216 6 +#define STB0899_WIDTH_STOP_CKINTBUF216 1 +#define STB0899_STOP_CHK8PSK (0x01 << 5) +#define STB0899_OFFST_STOP_CHK8PSK 5 +#define STB0899_WIDTH_STOP_CHK8PSK 1 +#define STB0899_STOP_CKFEC108 (0x01 << 4) +#define STB0899_OFFST_STOP_CKFEC108 4 +#define STB0899_WIDTH_STOP_CKFEC108 1 +#define STB0899_STOP_CKFEC216 (0x01 << 3) +#define STB0899_OFFST_STOP_CKFEC216 3 +#define STB0899_WIDTH_STOP_CKFEC216 1 +#define STB0899_STOP_CKCORE216 (0x01 << 2) +#define STB0899_OFFST_STOP_CKCORE216 2 +#define STB0899_WIDTH_STOP_CKCORE216 1 +#define STB0899_STOP_CKADCI108 (0x01 << 1) +#define STB0899_OFFST_STOP_CKADCI108 1 +#define STB0899_WIDTH_STOP_CKADCI108 1 +#define STB0899_STOP_INVCKADCI108 (0x01 << 0) +#define STB0899_OFFST_STOP_INVCKADCI108 0 +#define STB0899_WIDTH_STOP_INVCKADCI108 1 + +#define STB0899_STOPCLK2 0xf1c3 +#define STB0899_STOP_CKS2DMD108 (0x01 << 2) +#define STB0899_OFFST_STOP_CKS2DMD108 2 +#define STB0899_WIDTH_STOP_CKS2DMD108 1 +#define STB0899_STOP_CKPKDLIN108 (0x01 << 1) +#define STB0899_OFFST_STOP_CKPKDLIN108 1 +#define STB0899_WIDTH_STOP_CKPKDLIN108 1 +#define STB0899_STOP_CKPKDLIN216 (0x01 << 0) +#define STB0899_OFFST_STOP_CKPKDLIN216 0 +#define STB0899_WIDTH_STOP_CKPKDLIN216 1 + +#define STB0899_TSTTNR1 0xf1e0 +#define STB0899_BYPASS_ADC (0x01 << 7) +#define STB0899_OFFST_BYPASS_ADC 7 +#define STB0899_WIDTH_BYPASS_ADC 1 +#define STB0899_INVADCICKOUT (0x01 << 6) +#define STB0899_OFFST_INVADCICKOUT 6 +#define STB0899_WIDTH_INVADCICKOUT 1 +#define STB0899_ADCTEST_VOLTAGE (0x03 << 4) +#define STB0899_OFFST_ADCTEST_VOLTAGE 4 +#define STB0899_WIDTH_ADCTEST_VOLTAGE 1 +#define STB0899_ADC_RESET (0x01 << 3) +#define STB0899_OFFST_ADC_RESET 3 +#define STB0899_WIDTH_ADC_RESET 1 +#define STB0899_TSTTNR1_2 (0x01 << 2) +#define STB0899_OFFST_TSTTNR1_2 2 +#define STB0899_WIDTH_TSTTNR1_2 1 +#define STB0899_ADCPON (0x01 << 1) +#define STB0899_OFFST_ADCPON 1 +#define STB0899_WIDTH_ADCPON 1 +#define STB0899_ADCIN_MODE (0x01 << 0) +#define STB0899_OFFST_ADCIN_MODE 0 +#define STB0899_WIDTH_ADCIN_MODE 1 + +#define STB0899_TSTTNR2 0xf1e1 +#define STB0899_TSTTNR2_7 (0x01 << 7) +#define STB0899_OFFST_TSTTNR2_7 7 +#define STB0899_WIDTH_TSTTNR2_7 1 +#define STB0899_NOT_DISRX_WIRED (0x01 << 6) +#define STB0899_OFFST_NOT_DISRX_WIRED 6 +#define STB0899_WIDTH_NOT_DISRX_WIRED 1 +#define STB0899_DISEQC_DCURRENT (0x01 << 5) +#define STB0899_OFFST_DISEQC_DCURRENT 5 +#define STB0899_WIDTH_DISEQC_DCURRENT 1 +#define STB0899_DISEQC_ZCURRENT (0x01 << 4) +#define STB0899_OFFST_DISEQC_ZCURRENT 4 +#define STB0899_WIDTH_DISEQC_ZCURRENT 1 +#define STB0899_DISEQC_SINC_SOURCE (0x03 << 2) +#define STB0899_OFFST_DISEQC_SINC_SOURCE 2 +#define STB0899_WIDTH_DISEQC_SINC_SOURCE 2 +#define STB0899_SELIQSRC (0x03 << 0) +#define STB0899_OFFST_SELIQSRC 0 +#define STB0899_WIDTH_SELIQSRC 2 + +#define STB0899_TSTTNR3 0xf1e2 + +#define STB0899_I2CCFG 0xf129 +#define STB0899_I2CCFGRSVD (0x0f << 4) +#define STB0899_OFFST_I2CCFGRSVD 4 +#define STB0899_WIDTH_I2CCFGRSVD 4 +#define STB0899_I2CFASTMODE (0x01 << 3) +#define STB0899_OFFST_I2CFASTMODE 3 +#define STB0899_WIDTH_I2CFASTMODE 1 +#define STB0899_STATUSWR (0x01 << 2) +#define STB0899_OFFST_STATUSWR 2 +#define STB0899_WIDTH_STATUSWR 1 +#define STB0899_I2CADDRINC (0x03 << 0) +#define STB0899_OFFST_I2CADDRINC 0 +#define STB0899_WIDTH_I2CADDRINC 2 + +#define STB0899_I2CRPT 0xf12a +#define STB0899_I2CTON (0x01 << 7) +#define STB0899_OFFST_I2CTON 7 +#define STB0899_WIDTH_I2CTON 1 +#define STB0899_ENARPTLEVEL (0x01 << 6) +#define STB0899_OFFST_ENARPTLEVEL 6 +#define STB0899_WIDTH_ENARPTLEVEL 2 +#define STB0899_SCLTDELAY (0x01 << 3) +#define STB0899_OFFST_SCLTDELAY 3 +#define STB0899_WIDTH_SCLTDELAY 1 +#define STB0899_STOPENA (0x01 << 2) +#define STB0899_OFFST_STOPENA 2 +#define STB0899_WIDTH_STOPENA 1 +#define STB0899_STOPSDAT2SDA (0x01 << 1) +#define STB0899_OFFST_STOPSDAT2SDA 1 +#define STB0899_WIDTH_STOPSDAT2SDA 1 + +#define STB0899_IOPVALUE8 0xf136 +#define STB0899_IOPVALUE7 0xf137 +#define STB0899_IOPVALUE6 0xf138 +#define STB0899_IOPVALUE5 0xf139 +#define STB0899_IOPVALUE4 0xf13a +#define STB0899_IOPVALUE3 0xf13b +#define STB0899_IOPVALUE2 0xf13c +#define STB0899_IOPVALUE1 0xf13d +#define STB0899_IOPVALUE0 0xf13e + +#define STB0899_GPIO00CFG 0xf140 + +#define STB0899_GPIO01CFG 0xf141 +#define STB0899_GPIO02CFG 0xf142 +#define STB0899_GPIO03CFG 0xf143 +#define STB0899_GPIO04CFG 0xf144 +#define STB0899_GPIO05CFG 0xf145 +#define STB0899_GPIO06CFG 0xf146 +#define STB0899_GPIO07CFG 0xf147 +#define STB0899_GPIO08CFG 0xf148 +#define STB0899_GPIO09CFG 0xf149 +#define STB0899_GPIO10CFG 0xf14a +#define STB0899_GPIO11CFG 0xf14b +#define STB0899_GPIO12CFG 0xf14c +#define STB0899_GPIO13CFG 0xf14d +#define STB0899_GPIO14CFG 0xf14e +#define STB0899_GPIO15CFG 0xf14f +#define STB0899_GPIO16CFG 0xf150 +#define STB0899_GPIO17CFG 0xf151 +#define STB0899_GPIO18CFG 0xf152 +#define STB0899_GPIO19CFG 0xf153 +#define STB0899_GPIO20CFG 0xf154 + +#define STB0899_SDATCFG 0xf155 +#define STB0899_SCLTCFG 0xf156 +#define STB0899_AGCRFCFG 0xf157 +#define STB0899_GPIO22 0xf158 /* AGCBB2CFG */ +#define STB0899_GPIO21 0xf159 /* AGCBB1CFG */ +#define STB0899_DIRCLKCFG 0xf15a +#define STB0899_CLKOUT27CFG 0xf15b +#define STB0899_STDBYCFG 0xf15c +#define STB0899_CS0CFG 0xf15d +#define STB0899_CS1CFG 0xf15e +#define STB0899_DISEQCOCFG 0xf15f + +#define STB0899_GPIO32CFG 0xf160 +#define STB0899_GPIO33CFG 0xf161 +#define STB0899_GPIO34CFG 0xf162 +#define STB0899_GPIO35CFG 0xf163 +#define STB0899_GPIO36CFG 0xf164 +#define STB0899_GPIO37CFG 0xf165 +#define STB0899_GPIO38CFG 0xf166 +#define STB0899_GPIO39CFG 0xf167 + +#define STB0899_IRQSTATUS_3 0xf120 +#define STB0899_IRQSTATUS_2 0xf121 +#define STB0899_IRQSTATUS_1 0xf122 +#define STB0899_IRQSTATUS_0 0xf123 + +#define STB0899_IRQMSK_3 0xf124 +#define STB0899_IRQMSK_2 0xf125 +#define STB0899_IRQMSK_1 0xf126 +#define STB0899_IRQMSK_0 0xf127 + +#define STB0899_IRQCFG 0xf128 + +#define STB0899_GHOSTREG 0xf000 + +#define STB0899_S2DEMOD 0xf3fc +#define STB0899_S2FEC 0xfafc + + +#endif diff --git a/drivers/media/dvb/frontends/stb6100.c b/drivers/media/dvb/frontends/stb6100.c new file mode 100644 index 00000000000..ff39275ab49 --- /dev/null +++ b/drivers/media/dvb/frontends/stb6100.c @@ -0,0 +1,545 @@ +/* + STB6100 Silicon Tuner + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/string.h> + +#include "dvb_frontend.h" +#include "stb6100.h" + +static unsigned int verbose; +module_param(verbose, int, 0644); + + +#define FE_ERROR 0 +#define FE_NOTICE 1 +#define FE_INFO 2 +#define FE_DEBUG 3 + +#define dprintk(x, y, z, format, arg...) do { \ + if (z) { \ + if ((x > FE_ERROR) && (x > y)) \ + printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ + else if ((x > FE_NOTICE) && (x > y)) \ + printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ + else if ((x > FE_INFO) && (x > y)) \ + printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ + else if ((x > FE_DEBUG) && (x > y)) \ + printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ + } else { \ + if (x > y) \ + printk(format, ##arg); \ + } \ +} while(0) + +struct stb6100_lkup { + u32 val_low; + u32 val_high; + u8 reg; +}; + +static int stb6100_release(struct dvb_frontend *fe); + +static const struct stb6100_lkup lkup[] = { + { 0, 950000, 0x0a }, + { 950000, 1000000, 0x0a }, + { 1000000, 1075000, 0x0c }, + { 1075000, 1200000, 0x00 }, + { 1200000, 1300000, 0x01 }, + { 1300000, 1370000, 0x02 }, + { 1370000, 1470000, 0x04 }, + { 1470000, 1530000, 0x05 }, + { 1530000, 1650000, 0x06 }, + { 1650000, 1800000, 0x08 }, + { 1800000, 1950000, 0x0a }, + { 1950000, 2150000, 0x0c }, + { 2150000, 9999999, 0x0c }, + { 0, 0, 0x00 } +}; + +/* Register names for easy debugging. */ +static const char *stb6100_regnames[] = { + [STB6100_LD] = "LD", + [STB6100_VCO] = "VCO", + [STB6100_NI] = "NI", + [STB6100_NF_LSB] = "NF", + [STB6100_K] = "K", + [STB6100_G] = "G", + [STB6100_F] = "F", + [STB6100_DLB] = "DLB", + [STB6100_TEST1] = "TEST1", + [STB6100_FCCK] = "FCCK", + [STB6100_LPEN] = "LPEN", + [STB6100_TEST3] = "TEST3", +}; + +/* Template for normalisation, i.e. setting unused or undocumented + * bits as required according to the documentation. + */ +struct stb6100_regmask { + u8 mask; + u8 set; +}; + +static const struct stb6100_regmask stb6100_template[] = { + [STB6100_LD] = { 0xff, 0x00 }, + [STB6100_VCO] = { 0xff, 0x00 }, + [STB6100_NI] = { 0xff, 0x00 }, + [STB6100_NF_LSB] = { 0xff, 0x00 }, + [STB6100_K] = { 0xc7, 0x38 }, + [STB6100_G] = { 0xef, 0x10 }, + [STB6100_F] = { 0x1f, 0xc0 }, + [STB6100_DLB] = { 0x38, 0xc4 }, + [STB6100_TEST1] = { 0x00, 0x8f }, + [STB6100_FCCK] = { 0x40, 0x0d }, + [STB6100_LPEN] = { 0xf0, 0x0b }, + [STB6100_TEST3] = { 0x00, 0xde }, +}; + +static void stb6100_normalise_regs(u8 regs[]) +{ + int i; + + for (i = 0; i < STB6100_NUMREGS; i++) + regs[i] = (regs[i] & stb6100_template[i].mask) | stb6100_template[i].set; +} + +static int stb6100_read_regs(struct stb6100_state *state, u8 regs[]) +{ + int rc; + struct i2c_msg msg = { + .addr = state->config->tuner_address, + .flags = I2C_M_RD, + .buf = regs, + .len = STB6100_NUMREGS + }; + + rc = i2c_transfer(state->i2c, &msg, 1); + if (unlikely(rc != 1)) { + dprintk(verbose, FE_ERROR, 1, "Read (0x%x) err, rc=[%d]", + state->config->tuner_address, rc); + + return -EREMOTEIO; + } + if (unlikely(verbose > FE_DEBUG)) { + int i; + + dprintk(verbose, FE_DEBUG, 1, " Read from 0x%02x", state->config->tuner_address); + for (i = 0; i < STB6100_NUMREGS; i++) + dprintk(verbose, FE_DEBUG, 1, " %s: 0x%02x", stb6100_regnames[i], regs[i]); + } + return 0; +} + +static int stb6100_read_reg(struct stb6100_state *state, u8 reg) +{ + u8 regs[STB6100_NUMREGS]; + int rc; + + if (unlikely(reg >= STB6100_NUMREGS)) { + dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg); + return -EINVAL; + } + if ((rc = stb6100_read_regs(state, regs)) < 0) + return rc; + return (unsigned int)regs[reg]; +} + +static int stb6100_write_reg_range(struct stb6100_state *state, u8 buf[], int start, int len) +{ + int rc; + u8 cmdbuf[len + 1]; + struct i2c_msg msg = { + .addr = state->config->tuner_address, + .flags = 0, + .buf = cmdbuf, + .len = len + 1 + }; + + if (unlikely(start < 1 || start + len > STB6100_NUMREGS)) { + dprintk(verbose, FE_ERROR, 1, "Invalid register range %d:%d", + start, len); + return -EINVAL; + } + memcpy(&cmdbuf[1], buf, len); + cmdbuf[0] = start; + + if (unlikely(verbose > FE_DEBUG)) { + int i; + + dprintk(verbose, FE_DEBUG, 1, " Write @ 0x%02x: [%d:%d]", state->config->tuner_address, start, len); + for (i = 0; i < len; i++) + dprintk(verbose, FE_DEBUG, 1, " %s: 0x%02x", stb6100_regnames[start + i], buf[i]); + } + rc = i2c_transfer(state->i2c, &msg, 1); + if (unlikely(rc != 1)) { + dprintk(verbose, FE_ERROR, 1, "(0x%x) write err [%d:%d], rc=[%d]", + (unsigned int)state->config->tuner_address, start, len, rc); + return -EREMOTEIO; + } + return 0; +} + +static int stb6100_write_reg(struct stb6100_state *state, u8 reg, u8 data) +{ + if (unlikely(reg >= STB6100_NUMREGS)) { + dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg); + return -EREMOTEIO; + } + data = (data & stb6100_template[reg].mask) | stb6100_template[reg].set; + return stb6100_write_reg_range(state, &data, reg, 1); +} + +static int stb6100_write_regs(struct stb6100_state *state, u8 regs[]) +{ + stb6100_normalise_regs(regs); + return stb6100_write_reg_range(state, ®s[1], 1, STB6100_NUMREGS - 1); +} + +static int stb6100_get_status(struct dvb_frontend *fe, u32 *status) +{ + int rc; + struct stb6100_state *state = fe->tuner_priv; + + if ((rc = stb6100_read_reg(state, STB6100_LD)) < 0) + return rc; + + return (rc & STB6100_LD_LOCK) ? TUNER_STATUS_LOCKED : 0; +} + +static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + int rc; + u8 f; + struct stb6100_state *state = fe->tuner_priv; + + if ((rc = stb6100_read_reg(state, STB6100_F)) < 0) + return rc; + f = rc & STB6100_F_F; + + state->status.bandwidth = (f + 5) * 2000; /* x2 for ZIF */ + + *bandwidth = state->bandwidth = state->status.bandwidth * 1000; + dprintk(verbose, FE_DEBUG, 1, "bandwidth = %u Hz", state->bandwidth); + return 0; +} + +static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth) +{ + u32 tmp; + int rc; + struct stb6100_state *state = fe->tuner_priv; + + dprintk(verbose, FE_DEBUG, 1, "set bandwidth to %u Hz", bandwidth); + + bandwidth /= 2; /* ZIF */ + + if (bandwidth >= 36000000) /* F[4:0] BW/2 max =31+5=36 mhz for F=31 */ + tmp = 31; + else if (bandwidth <= 5000000) /* bw/2 min = 5Mhz for F=0 */ + tmp = 0; + else /* if 5 < bw/2 < 36 */ + tmp = (bandwidth + 500000) / 1000000 - 5; + + /* Turn on LPF bandwidth setting clock control, + * set bandwidth, wait 10ms, turn off. + */ + if ((rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d | STB6100_FCCK_FCCK)) < 0) + return rc; + if ((rc = stb6100_write_reg(state, STB6100_F, 0xc0 | tmp)) < 0) + return rc; + msleep(1); + if ((rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d)) < 0) + return rc; + + return 0; +} + +static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + int rc; + u32 nint, nfrac, fvco; + int psd2, odiv; + struct stb6100_state *state = fe->tuner_priv; + u8 regs[STB6100_NUMREGS]; + + if ((rc = stb6100_read_regs(state, regs)) < 0) + return rc; + + odiv = (regs[STB6100_VCO] & STB6100_VCO_ODIV) >> STB6100_VCO_ODIV_SHIFT; + psd2 = (regs[STB6100_K] & STB6100_K_PSD2) >> STB6100_K_PSD2_SHIFT; + nint = regs[STB6100_NI]; + nfrac = ((regs[STB6100_K] & STB6100_K_NF_MSB) << 8) | regs[STB6100_NF_LSB]; + fvco = (nfrac * state->reference >> (9 - psd2)) + (nint * state->reference << psd2); + *frequency = state->frequency = fvco >> (odiv + 1); + + dprintk(verbose, FE_DEBUG, 1, + "frequency = %u kHz, odiv = %u, psd2 = %u, fxtal = %u kHz, fvco = %u kHz, N(I) = %u, N(F) = %u", + state->frequency, odiv, psd2, state->reference, fvco, nint, nfrac); + return 0; +} + + +static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency) +{ + int rc; + const struct stb6100_lkup *ptr; + struct stb6100_state *state = fe->tuner_priv; + struct dvb_frontend_parameters p; + + u32 srate = 0, fvco, nint, nfrac; + u8 regs[STB6100_NUMREGS]; + u8 g, psd2, odiv; + + if ((rc = stb6100_read_regs(state, regs)) < 0) + return rc; + + if (fe->ops.get_frontend) { + dprintk(verbose, FE_DEBUG, 1, "Get frontend parameters"); + fe->ops.get_frontend(fe, &p); + } + srate = p.u.qpsk.symbol_rate; + + regs[STB6100_DLB] = 0xdc; + /* Disable LPEN */ + regs[STB6100_LPEN] &= ~STB6100_LPEN_LPEN; /* PLL Loop disabled */ + + if ((rc = stb6100_write_regs(state, regs)) < 0) + return rc; + + /* Baseband gain. */ + if (srate >= 15000000) + g = 9; // +4 dB + else if (srate >= 5000000) + g = 11; // +8 dB + else + g = 14; // +14 dB + + regs[STB6100_G] = (regs[STB6100_G] & ~STB6100_G_G) | g; + regs[STB6100_G] &= ~STB6100_G_GCT; /* mask GCT */ + regs[STB6100_G] |= (1 << 5); /* 2Vp-p Mode */ + + /* VCO divide ratio (LO divide ratio, VCO prescaler enable). */ + if (frequency <= 1075000) + odiv = 1; + else + odiv = 0; + regs[STB6100_VCO] = (regs[STB6100_VCO] & ~STB6100_VCO_ODIV) | (odiv << STB6100_VCO_ODIV_SHIFT); + + if ((frequency > 1075000) && (frequency <= 1325000)) + psd2 = 0; + else + psd2 = 1; + regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_PSD2) | (psd2 << STB6100_K_PSD2_SHIFT); + + /* OSM */ + for (ptr = lkup; + (ptr->val_high != 0) && !CHKRANGE(frequency, ptr->val_low, ptr->val_high); + ptr++); + if (ptr->val_high == 0) { + printk(KERN_ERR "%s: frequency out of range: %u kHz\n", __func__, frequency); + return -EINVAL; + } + regs[STB6100_VCO] = (regs[STB6100_VCO] & ~STB6100_VCO_OSM) | ptr->reg; + + /* F(VCO) = F(LO) * (ODIV == 0 ? 2 : 4) */ + fvco = frequency << (1 + odiv); + /* N(I) = floor(f(VCO) / (f(XTAL) * (PSD2 ? 2 : 1))) */ + nint = fvco / (state->reference << psd2); + /* N(F) = round(f(VCO) / f(XTAL) * (PSD2 ? 2 : 1) - N(I)) * 2 ^ 9 */ + nfrac = (((fvco - (nint * state->reference << psd2)) << (9 - psd2)) + state->reference / 2) / state->reference; + dprintk(verbose, FE_DEBUG, 1, + "frequency = %u, srate = %u, g = %u, odiv = %u, psd2 = %u, fxtal = %u, osm = %u, fvco = %u, N(I) = %u, N(F) = %u", + frequency, srate, (unsigned int)g, (unsigned int)odiv, + (unsigned int)psd2, state->reference, + ptr->reg, fvco, nint, nfrac); + regs[STB6100_NI] = nint; + regs[STB6100_NF_LSB] = nfrac; + regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_NF_MSB) | ((nfrac >> 8) & STB6100_K_NF_MSB); + regs[STB6100_VCO] |= STB6100_VCO_OSCH; /* VCO search enabled */ + regs[STB6100_VCO] |= STB6100_VCO_OCK; /* VCO search clock off */ + regs[STB6100_FCCK] |= STB6100_FCCK_FCCK; /* LPF BW setting clock enabled */ + regs[STB6100_LPEN] &= ~STB6100_LPEN_LPEN; /* PLL loop disabled */ + /* Power up. */ + regs[STB6100_LPEN] |= STB6100_LPEN_SYNP | STB6100_LPEN_OSCP | STB6100_LPEN_BEN; + + msleep(2); + if ((rc = stb6100_write_regs(state, regs)) < 0) + return rc; + + msleep(2); + regs[STB6100_LPEN] |= STB6100_LPEN_LPEN; /* PLL loop enabled */ + if ((rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN])) < 0) + return rc; + + regs[STB6100_VCO] &= ~STB6100_VCO_OCK; /* VCO fast search */ + if ((rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO])) < 0) + return rc; + + msleep(10); /* wait for LO to lock */ + regs[STB6100_VCO] &= ~STB6100_VCO_OSCH; /* vco search disabled */ + regs[STB6100_VCO] |= STB6100_VCO_OCK; /* search clock off */ + if ((rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO])) < 0) + return rc; + regs[STB6100_FCCK] &= ~STB6100_FCCK_FCCK; /* LPF BW clock disabled */ + stb6100_normalise_regs(regs); + if ((rc = stb6100_write_reg_range(state, ®s[1], 1, STB6100_NUMREGS - 3)) < 0) + return rc; + + msleep(100); + + return 0; +} + +static int stb6100_sleep(struct dvb_frontend *fe) +{ + /* TODO: power down */ + return 0; +} + +static int stb6100_init(struct dvb_frontend *fe) +{ + struct stb6100_state *state = fe->tuner_priv; + struct tuner_state *status = &state->status; + + status->tunerstep = 125000; + status->ifreq = 0; + status->refclock = 27000000; /* Hz */ + status->iqsense = 1; + status->bandwidth = 36000; /* kHz */ + state->bandwidth = status->bandwidth * 1000; /* MHz */ + state->reference = status->refclock / 1000; /* kHz */ + + /* Set default bandwidth. */ + return stb6100_set_bandwidth(fe, status->bandwidth); +} + +static int stb6100_get_state(struct dvb_frontend *fe, + enum tuner_param param, + struct tuner_state *state) +{ + switch (param) { + case DVBFE_TUNER_FREQUENCY: + stb6100_get_frequency(fe, &state->frequency); + break; + case DVBFE_TUNER_TUNERSTEP: + break; + case DVBFE_TUNER_IFFREQ: + break; + case DVBFE_TUNER_BANDWIDTH: + stb6100_get_bandwidth(fe, &state->bandwidth); + break; + case DVBFE_TUNER_REFCLOCK: + break; + default: + break; + } + + return 0; +} + +static int stb6100_set_state(struct dvb_frontend *fe, + enum tuner_param param, + struct tuner_state *state) +{ + struct stb6100_state *tstate = fe->tuner_priv; + + switch (param) { + case DVBFE_TUNER_FREQUENCY: + stb6100_set_frequency(fe, state->frequency); + tstate->frequency = state->frequency; + break; + case DVBFE_TUNER_TUNERSTEP: + break; + case DVBFE_TUNER_IFFREQ: + break; + case DVBFE_TUNER_BANDWIDTH: + stb6100_set_bandwidth(fe, state->bandwidth); + tstate->bandwidth = state->bandwidth; + break; + case DVBFE_TUNER_REFCLOCK: + break; + default: + break; + } + + return 0; +} + +static struct dvb_tuner_ops stb6100_ops = { + .info = { + .name = "STB6100 Silicon Tuner", + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_step = 0, + }, + + .init = stb6100_init, + .sleep = stb6100_sleep, + .get_status = stb6100_get_status, + .get_state = stb6100_get_state, + .set_state = stb6100_set_state, + .release = stb6100_release +}; + +struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, + struct stb6100_config *config, + struct i2c_adapter *i2c) +{ + struct stb6100_state *state = NULL; + + state = kzalloc(sizeof (struct stb6100_state), GFP_KERNEL); + if (state == NULL) + goto error; + + state->config = config; + state->i2c = i2c; + state->frontend = fe; + state->reference = config->refclock / 1000; /* kHz */ + fe->tuner_priv = state; + fe->ops.tuner_ops = stb6100_ops; + + printk("%s: Attaching STB6100 \n", __func__); + return fe; + +error: + kfree(state); + return NULL; +} + +static int stb6100_release(struct dvb_frontend *fe) +{ + struct stb6100_state *state = fe->tuner_priv; + + fe->tuner_priv = NULL; + kfree(state); + + return 0; +} + +EXPORT_SYMBOL(stb6100_attach); +MODULE_PARM_DESC(verbose, "Set Verbosity level"); + +MODULE_AUTHOR("Manu Abraham"); +MODULE_DESCRIPTION("STB6100 Silicon tuner"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/stb6100.h b/drivers/media/dvb/frontends/stb6100.h new file mode 100644 index 00000000000..395d056599a --- /dev/null +++ b/drivers/media/dvb/frontends/stb6100.h @@ -0,0 +1,115 @@ +/* + STB6100 Silicon Tuner + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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 __STB_6100_REG_H +#define __STB_6100_REG_H + +#include <linux/dvb/frontend.h> +#include "dvb_frontend.h" + +#define STB6100_LD 0x00 +#define STB6100_LD_LOCK (1 << 0) + +#define STB6100_VCO 0x01 +#define STB6100_VCO_OSCH (0x01 << 7) +#define STB6100_VCO_OSCH_SHIFT 7 +#define STB6100_VCO_OCK (0x03 << 5) +#define STB6100_VCO_OCK_SHIFT 5 +#define STB6100_VCO_ODIV (0x01 << 4) +#define STB6100_VCO_ODIV_SHIFT 4 +#define STB6100_VCO_OSM (0x0f << 0) + +#define STB6100_NI 0x02 +#define STB6100_NF_LSB 0x03 + +#define STB6100_K 0x04 +#define STB6100_K_PSD2 (0x01 << 2) +#define STB6100_K_PSD2_SHIFT 2 +#define STB6100_K_NF_MSB (0x03 << 0) + +#define STB6100_G 0x05 +#define STB6100_G_G (0x0f << 0) +#define STB6100_G_GCT (0x07 << 5) + +#define STB6100_F 0x06 +#define STB6100_F_F (0x1f << 0) + +#define STB6100_DLB 0x07 + +#define STB6100_TEST1 0x08 + +#define STB6100_FCCK 0x09 +#define STB6100_FCCK_FCCK (0x01 << 6) + +#define STB6100_LPEN 0x0a +#define STB6100_LPEN_LPEN (0x01 << 4) +#define STB6100_LPEN_SYNP (0x01 << 5) +#define STB6100_LPEN_OSCP (0x01 << 6) +#define STB6100_LPEN_BEN (0x01 << 7) + +#define STB6100_TEST3 0x0b + +#define STB6100_NUMREGS 0x0c + + +#define INRANGE(val, x, y) (((x <= val) && (val <= y)) || \ + ((y <= val) && (val <= x)) ? 1 : 0) + +#define CHKRANGE(val, x, y) (((val >= x) && (val < y)) ? 1 : 0) + +struct stb6100_config { + u8 tuner_address; + u32 refclock; +}; + +struct stb6100_state { + struct i2c_adapter *i2c; + + const struct stb6100_config *config; + struct dvb_tuner_ops ops; + struct dvb_frontend *frontend; + struct tuner_state status; + + u32 frequency; + u32 srate; + u32 bandwidth; + u32 reference; +}; + +#if defined(CONFIG_DVB_STB6100) || (defined(CONFIG_DVB_STB6100_MODULE) && defined(MODULE)) + +extern struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, + struct stb6100_config *config, + struct i2c_adapter *i2c); + +#else + +static inline struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, + struct stb6100_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); + return NULL; +} + +#endif //CONFIG_DVB_STB6100 + +#endif diff --git a/drivers/media/dvb/frontends/stb6100_cfg.h b/drivers/media/dvb/frontends/stb6100_cfg.h new file mode 100644 index 00000000000..d3133405dc0 --- /dev/null +++ b/drivers/media/dvb/frontends/stb6100_cfg.h @@ -0,0 +1,108 @@ +/* + STB6100 Silicon Tuner + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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. +*/ + +static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + struct tuner_state t_state; + int err = 0; + + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->get_state) { + if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) { + printk("%s: Invalid parameter\n", __func__); + return err; + } + *frequency = t_state.frequency; + printk("%s: Frequency=%d\n", __func__, t_state.frequency); + } + return 0; +} + +static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + struct tuner_state t_state; + int err = 0; + + t_state.frequency = frequency; + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->set_state) { + if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) { + printk("%s: Invalid parameter\n", __func__); + return err; + } + } + printk("%s: Frequency=%d\n", __func__, t_state.frequency); + return 0; +} + +static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct dvb_frontend_ops *frontend_ops = &fe->ops; + struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops; + struct tuner_state t_state; + int err = 0; + + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->get_state) { + if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) { + printk("%s: Invalid parameter\n", __func__); + return err; + } + *bandwidth = t_state.bandwidth; + } + printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth); + return 0; +} + +static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + struct tuner_state t_state; + int err = 0; + + t_state.bandwidth = bandwidth; + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->set_state) { + if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) { + printk("%s: Invalid parameter\n", __func__); + return err; + } + } + printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth); + return 0; +} diff --git a/drivers/media/dvb/frontends/tda8261.c b/drivers/media/dvb/frontends/tda8261.c new file mode 100644 index 00000000000..b6d17779910 --- /dev/null +++ b/drivers/media/dvb/frontends/tda8261.c @@ -0,0 +1,230 @@ +/* + TDA8261 8PSK/QPSK tuner driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> + +#include "dvb_frontend.h" +#include "tda8261.h" + +struct tda8261_state { + struct dvb_frontend *fe; + struct i2c_adapter *i2c; + const struct tda8261_config *config; + + /* state cache */ + u32 frequency; + u32 bandwidth; +}; + +static int tda8261_read(struct tda8261_state *state, u8 *buf) +{ + const struct tda8261_config *config = state->config; + int err = 0; + struct i2c_msg msg = { .addr = config->addr, .flags = I2C_M_RD,.buf = buf, .len = 2 }; + + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) + printk("%s: read error, err=%d\n", __func__, err); + + return err; +} + +static int tda8261_write(struct tda8261_state *state, u8 *buf) +{ + const struct tda8261_config *config = state->config; + int err = 0; + struct i2c_msg msg = { .addr = config->addr, .flags = 0, .buf = buf, .len = 4 }; + + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) + printk("%s: write error, err=%d\n", __func__, err); + + return err; +} + +static int tda8261_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct tda8261_state *state = fe->tuner_priv; + u8 result = 0; + int err = 0; + + *status = 0; + + if ((err = tda8261_read(state, &result)) < 0) { + printk("%s: I/O Error\n", __func__); + return err; + } + if ((result >> 6) & 0x01) { + printk("%s: Tuner Phase Locked\n", __func__); + *status = 1; + } + + return err; +} + +static const u32 div_tab[] = { 2000, 1000, 500, 250, 125 }; /* kHz */ +static const u8 ref_div[] = { 0x00, 0x01, 0x02, 0x05, 0x07 }; + +static int tda8261_get_state(struct dvb_frontend *fe, + enum tuner_param param, + struct tuner_state *tstate) +{ + struct tda8261_state *state = fe->tuner_priv; + int err = 0; + + switch (param) { + case DVBFE_TUNER_FREQUENCY: + tstate->frequency = state->frequency; + break; + case DVBFE_TUNER_BANDWIDTH: + tstate->bandwidth = 40000000; /* FIXME! need to calculate Bandwidth */ + break; + default: + printk("%s: Unknown parameter (param=%d)\n", __func__, param); + err = -EINVAL; + break; + } + + return err; +} + +static int tda8261_set_state(struct dvb_frontend *fe, + enum tuner_param param, + struct tuner_state *tstate) +{ + struct tda8261_state *state = fe->tuner_priv; + const struct tda8261_config *config = state->config; + u32 frequency, N, status = 0; + u8 buf[4]; + int err = 0; + + if (param & DVBFE_TUNER_FREQUENCY) { + /** + * N = Max VCO Frequency / Channel Spacing + * Max VCO Frequency = VCO frequency + (channel spacing - 1) + * (to account for half channel spacing on either side) + */ + frequency = tstate->frequency; + if ((frequency < 950000) || (frequency > 2150000)) { + printk("%s: Frequency beyond limits, frequency=%d\n", __func__, frequency); + return -EINVAL; + } + N = (frequency + (div_tab[config->step_size] - 1)) / div_tab[config->step_size]; + printk("%s: Step size=%d, Divider=%d, PG=0x%02x (%d)\n", + __func__, config->step_size, div_tab[config->step_size], N, N); + + buf[0] = (N >> 8) & 0xff; + buf[1] = N & 0xff; + buf[2] = (0x01 << 7) | ((ref_div[config->step_size] & 0x07) << 1); + + if (frequency < 1450000) + buf[3] = 0x00; + if (frequency < 2000000) + buf[3] = 0x40; + if (frequency < 2150000) + buf[3] = 0x80; + + /* Set params */ + if ((err = tda8261_write(state, buf)) < 0) { + printk("%s: I/O Error\n", __func__); + return err; + } + /* sleep for some time */ + printk("%s: Waiting to Phase LOCK\n", __func__); + msleep(20); + /* check status */ + if ((err = tda8261_get_status(fe, &status)) < 0) { + printk("%s: I/O Error\n", __func__); + return err; + } + if (status == 1) { + printk("%s: Tuner Phase locked: status=%d\n", __func__, status); + state->frequency = frequency; /* cache successful state */ + } else { + printk("%s: No Phase lock: status=%d\n", __func__, status); + } + } else { + printk("%s: Unknown parameter (param=%d)\n", __func__, param); + return -EINVAL; + } + + return 0; +} + +static int tda8261_release(struct dvb_frontend *fe) +{ + struct tda8261_state *state = fe->tuner_priv; + + fe->tuner_priv = NULL; + kfree(state); + return 0; +} + +static struct dvb_tuner_ops tda8261_ops = { + + .info = { + .name = "TDA8261", +// .tuner_name = NULL, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_step = 0 + }, + + .set_state = tda8261_set_state, + .get_state = tda8261_get_state, + .get_status = tda8261_get_status, + .release = tda8261_release +}; + +struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe, + const struct tda8261_config *config, + struct i2c_adapter *i2c) +{ + struct tda8261_state *state = NULL; + + if ((state = kzalloc(sizeof (struct tda8261_state), GFP_KERNEL)) == NULL) + goto exit; + + state->config = config; + state->i2c = i2c; + state->fe = fe; + fe->tuner_priv = state; + fe->ops.tuner_ops = tda8261_ops; + + fe->ops.tuner_ops.info.frequency_step = div_tab[config->step_size]; +// fe->ops.tuner_ops.tuner_name = &config->buf; + +// printk("%s: Attaching %s TDA8261 8PSK/QPSK tuner\n", +// __func__, fe->ops.tuner_ops.tuner_name); + printk("%s: Attaching TDA8261 8PSK/QPSK tuner\n", __func__); + + return fe; + +exit: + kfree(state); + return NULL; +} + +EXPORT_SYMBOL(tda8261_attach); +MODULE_PARM_DESC(verbose, "Set verbosity level"); + +MODULE_AUTHOR("Manu Abraham"); +MODULE_DESCRIPTION("TDA8261 8PSK/QPSK Tuner"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/tda8261.h b/drivers/media/dvb/frontends/tda8261.h new file mode 100644 index 00000000000..006e45351b9 --- /dev/null +++ b/drivers/media/dvb/frontends/tda8261.h @@ -0,0 +1,55 @@ +/* + TDA8261 8PSK/QPSK tuner driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TDA8261_H +#define __TDA8261_H + +enum tda8261_step { + TDA8261_STEP_2000 = 0, /* 2000 kHz */ + TDA8261_STEP_1000, /* 1000 kHz */ + TDA8261_STEP_500, /* 500 kHz */ + TDA8261_STEP_250, /* 250 kHz */ + TDA8261_STEP_125 /* 125 kHz */ +}; + +struct tda8261_config { +// u8 buf[16]; + u8 addr; + enum tda8261_step step_size; +}; + +#if defined(CONFIG_DVB_TDA8261) || (defined(CONFIG_DVB_TDA8261_MODULE) && defined(MODULE)) + +extern struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe, + const struct tda8261_config *config, + struct i2c_adapter *i2c); + +#else + +static inline struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe, + const struct tda8261_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); + return NULL; +} + +#endif //CONFIG_DVB_TDA8261 + +#endif// __TDA8261_H diff --git a/drivers/media/dvb/frontends/tda8261_cfg.h b/drivers/media/dvb/frontends/tda8261_cfg.h new file mode 100644 index 00000000000..1af1ee49b54 --- /dev/null +++ b/drivers/media/dvb/frontends/tda8261_cfg.h @@ -0,0 +1,84 @@ +/* + TDA8261 8PSK/QPSK tuner driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +static int tda8261_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + struct tuner_state t_state; + int err = 0; + + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->get_state) { + if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) { + printk("%s: Invalid parameter\n", __func__); + return err; + } + *frequency = t_state.frequency; + printk("%s: Frequency=%d\n", __func__, t_state.frequency); + } + return 0; +} + +static int tda8261_set_frequency(struct dvb_frontend *fe, u32 frequency) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + struct tuner_state t_state; + int err = 0; + + t_state.frequency = frequency; + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->set_state) { + if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) { + printk("%s: Invalid parameter\n", __func__); + return err; + } + } + printk("%s: Frequency=%d\n", __func__, t_state.frequency); + return 0; +} + +static int tda8261_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct dvb_frontend_ops *frontend_ops = &fe->ops; + struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops; + struct tuner_state t_state; + int err = 0; + + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->get_state) { + if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) { + printk("%s: Invalid parameter\n", __func__); + return err; + } + *bandwidth = t_state.bandwidth; + } + printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth); + return 0; +} diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c index 36a5a1c101d..5506f80e180 100644 --- a/drivers/media/dvb/frontends/zl10353.c +++ b/drivers/media/dvb/frontends/zl10353.c @@ -220,15 +220,18 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, /* These are extrapolated from the 7 and 8MHz values */ zl10353_single_write(fe, MCLK_RATIO, 0x97); zl10353_single_write(fe, 0x64, 0x34); + zl10353_single_write(fe, 0xcc, 0xdd); break; case BANDWIDTH_7_MHZ: zl10353_single_write(fe, MCLK_RATIO, 0x86); zl10353_single_write(fe, 0x64, 0x35); + zl10353_single_write(fe, 0xcc, 0x73); break; case BANDWIDTH_8_MHZ: default: zl10353_single_write(fe, MCLK_RATIO, 0x75); zl10353_single_write(fe, 0x64, 0x36); + zl10353_single_write(fe, 0xcc, 0x73); } zl10353_calc_nominal_rate(fe, op->bandwidth, &nominal_rate); diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c index e98d6caf2c2..fd62e0b8562 100644 --- a/drivers/media/dvb/siano/sms-cards.c +++ b/drivers/media/dvb/siano/sms-cards.c @@ -38,6 +38,16 @@ struct usb_device_id smsusb_id_table[] = { .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A }, { USB_DEVICE(0x2040, 0x1801), .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B }, + { USB_DEVICE(0x2040, 0x2000), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, + { USB_DEVICE(0x2040, 0x2009), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 }, + { USB_DEVICE(0x2040, 0x200a), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, + { USB_DEVICE(0x2040, 0x2010), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, + { USB_DEVICE(0x2040, 0x2019), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, { USB_DEVICE(0x2040, 0x5500), .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, { USB_DEVICE(0x2040, 0x5510), @@ -96,6 +106,21 @@ static struct sms_board sms_boards[] = { .name = "Hauppauge WinTV MiniStick", .type = SMS_NOVA_B0, .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .led_power = 26, + .led_lo = 27, + .led_hi = 28, + }, + [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD] = { + .name = "Hauppauge WinTV MiniCard", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .lna_ctrl = 29, + }, + [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = { + .name = "Hauppauge WinTV MiniCard", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .lna_ctrl = 1, }, }; @@ -106,3 +131,88 @@ struct sms_board *sms_get_board(int id) return &sms_boards[id]; } +static int sms_set_gpio(struct smscore_device_t *coredev, u32 pin, int enable) +{ + int ret; + struct smscore_gpio_config gpioconfig = { + .direction = SMS_GPIO_DIRECTION_OUTPUT, + .pullupdown = SMS_GPIO_PULLUPDOWN_NONE, + .inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL, + .outputslewrate = SMS_GPIO_OUTPUTSLEWRATE_FAST, + .outputdriving = SMS_GPIO_OUTPUTDRIVING_4mA, + }; + + if (pin == 0) + return -EINVAL; + + ret = smscore_configure_gpio(coredev, pin, &gpioconfig); + + if (ret < 0) + return ret; + + return smscore_set_gpio(coredev, pin, enable); +} + +int sms_board_setup(struct smscore_device_t *coredev) +{ + int board_id = smscore_get_board_id(coredev); + struct sms_board *board = sms_get_board(board_id); + + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + /* turn off all LEDs */ + sms_set_gpio(coredev, board->led_power, 0); + sms_set_gpio(coredev, board->led_hi, 0); + sms_set_gpio(coredev, board->led_lo, 0); + break; + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: + /* turn off LNA */ + sms_set_gpio(coredev, board->lna_ctrl, 0); + break; + } + return 0; +} + +int sms_board_power(struct smscore_device_t *coredev, int onoff) +{ + int board_id = smscore_get_board_id(coredev); + struct sms_board *board = sms_get_board(board_id); + + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + /* power LED */ + sms_set_gpio(coredev, + board->led_power, onoff ? 1 : 0); + break; + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: + /* LNA */ + sms_set_gpio(coredev, + board->lna_ctrl, onoff ? 1 : 0); + break; + } + return 0; +} + +int sms_board_led_feedback(struct smscore_device_t *coredev, int led) +{ + int board_id = smscore_get_board_id(coredev); + struct sms_board *board = sms_get_board(board_id); + + /* dont touch GPIO if LEDs are already set */ + if (smscore_led_state(coredev, -1) == led) + return 0; + + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + sms_set_gpio(coredev, + board->led_lo, (led & SMS_LED_LO) ? 1 : 0); + sms_set_gpio(coredev, + board->led_hi, (led & SMS_LED_HI) ? 1 : 0); + + smscore_led_state(coredev, led); + break; + } + return 0; +} diff --git a/drivers/media/dvb/siano/sms-cards.h b/drivers/media/dvb/siano/sms-cards.h index c8f3da6f9bc..8e0fe9fd261 100644 --- a/drivers/media/dvb/siano/sms-cards.h +++ b/drivers/media/dvb/siano/sms-cards.h @@ -32,14 +32,27 @@ #define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A 6 #define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B 7 #define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8 +#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9 +#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10 struct sms_board { enum sms_device_type_st type; char *name, *fw[DEVICE_MODE_MAX]; + + /* gpios */ + int led_power, led_hi, led_lo, lna_ctrl; }; struct sms_board *sms_get_board(int id); +int sms_board_setup(struct smscore_device_t *coredev); + +#define SMS_LED_OFF 0 +#define SMS_LED_LO 1 +#define SMS_LED_HI 2 +int sms_board_led_feedback(struct smscore_device_t *coredev, int led); +int sms_board_power(struct smscore_device_t *coredev, int onoff); + extern struct usb_device_id smsusb_id_table[]; #endif /* __SMS_CARDS_H__ */ diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c index 6576fbb40fc..cf613f22fb8 100644 --- a/drivers/media/dvb/siano/smscoreapi.c +++ b/drivers/media/dvb/siano/smscoreapi.c @@ -91,6 +91,7 @@ struct smscore_device_t { struct completion init_device_done, reload_start_done, resume_done; int board_id; + int led_state; }; void smscore_set_board_id(struct smscore_device_t *core, int id) @@ -98,6 +99,13 @@ void smscore_set_board_id(struct smscore_device_t *core, int id) core->board_id = id; } +int smscore_led_state(struct smscore_device_t *core, int led) +{ + if (led >= 0) + core->led_state = led; + return core->led_state; +} + int smscore_get_board_id(struct smscore_device_t *core) { return core->board_id; @@ -1187,6 +1195,76 @@ int smsclient_sendrequest(struct smscore_client_t *client, } +int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, + struct smscore_gpio_config *pinconfig) +{ + struct { + struct SmsMsgHdr_ST hdr; + u32 data[6]; + } msg; + + if (coredev->device_flags & SMS_DEVICE_FAMILY2) { + msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + msg.hdr.msgDstId = HIF_TASK; + msg.hdr.msgFlags = 0; + msg.hdr.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ; + msg.hdr.msgLength = sizeof(msg); + + msg.data[0] = pin; + msg.data[1] = pinconfig->pullupdown; + + /* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */ + msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0; + + switch (pinconfig->outputdriving) { + case SMS_GPIO_OUTPUTDRIVING_16mA: + msg.data[3] = 7; /* Nova - 16mA */ + break; + case SMS_GPIO_OUTPUTDRIVING_12mA: + msg.data[3] = 5; /* Nova - 11mA */ + break; + case SMS_GPIO_OUTPUTDRIVING_8mA: + msg.data[3] = 3; /* Nova - 7mA */ + break; + case SMS_GPIO_OUTPUTDRIVING_4mA: + default: + msg.data[3] = 2; /* Nova - 4mA */ + break; + } + + msg.data[4] = pinconfig->direction; + msg.data[5] = 0; + } else /* TODO: SMS_DEVICE_FAMILY1 */ + return -EINVAL; + + return coredev->sendrequest_handler(coredev->context, + &msg, sizeof(msg)); +} + +int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level) +{ + struct { + struct SmsMsgHdr_ST hdr; + u32 data[3]; + } msg; + + if (pin > MAX_GPIO_PIN_NUMBER) + return -EINVAL; + + msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + msg.hdr.msgDstId = HIF_TASK; + msg.hdr.msgFlags = 0; + msg.hdr.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ; + msg.hdr.msgLength = sizeof(msg); + + msg.data[0] = pin; + msg.data[1] = level ? 1 : 0; + msg.data[2] = 0; + + return coredev->sendrequest_handler(coredev->context, + &msg, sizeof(msg)); +} + static int __init smscore_module_init(void) { int rc = 0; diff --git a/drivers/media/dvb/siano/smscoreapi.h b/drivers/media/dvb/siano/smscoreapi.h index 8d973f726fb..760e233fcbc 100644 --- a/drivers/media/dvb/siano/smscoreapi.h +++ b/drivers/media/dvb/siano/smscoreapi.h @@ -186,6 +186,8 @@ struct smsclient_params_t { #define MSG_SW_RELOAD_EXEC_REQ 704 #define MSG_SW_RELOAD_EXEC_RES 705 #define MSG_SMS_SPI_INT_LINE_SET_REQ 710 +#define MSG_SMS_GPIO_CONFIG_EX_REQ 712 +#define MSG_SMS_GPIO_CONFIG_EX_RES 713 #define MSG_SMS_ISDBT_TUNE_REQ 776 #define MSG_SMS_ISDBT_TUNE_RES 777 @@ -341,6 +343,32 @@ struct SmsMsgStatisticsInfo_ST { }; +struct smscore_gpio_config { +#define SMS_GPIO_DIRECTION_INPUT 0 +#define SMS_GPIO_DIRECTION_OUTPUT 1 + u8 direction; + +#define SMS_GPIO_PULLUPDOWN_NONE 0 +#define SMS_GPIO_PULLUPDOWN_PULLDOWN 1 +#define SMS_GPIO_PULLUPDOWN_PULLUP 2 +#define SMS_GPIO_PULLUPDOWN_KEEPER 3 + u8 pullupdown; + +#define SMS_GPIO_INPUTCHARACTERISTICS_NORMAL 0 +#define SMS_GPIO_INPUTCHARACTERISTICS_SCHMITT 1 + u8 inputcharacteristics; + +#define SMS_GPIO_OUTPUTSLEWRATE_FAST 0 +#define SMS_GPIO_OUTPUTSLEWRATE_SLOW 1 + u8 outputslewrate; + +#define SMS_GPIO_OUTPUTDRIVING_4mA 0 +#define SMS_GPIO_OUTPUTDRIVING_8mA 1 +#define SMS_GPIO_OUTPUTDRIVING_12mA 2 +#define SMS_GPIO_OUTPUTDRIVING_16mA 3 + u8 outputdriving; +}; + struct smsdvb_client_t { struct list_head entry; @@ -353,7 +381,7 @@ struct smsdvb_client_t { struct dvb_frontend frontend; fe_status_t fe_status; - int fe_ber, fe_snr, fe_signal_strength; + int fe_ber, fe_snr, fe_unc, fe_signal_strength; struct completion tune_done, stat_done; @@ -396,9 +424,15 @@ struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev); extern void smscore_putbuffer(struct smscore_device_t *coredev, struct smscore_buffer_t *cb); +int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, + struct smscore_gpio_config *pinconfig); +int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level); + void smscore_set_board_id(struct smscore_device_t *core, int id); int smscore_get_board_id(struct smscore_device_t *core); +int smscore_led_state(struct smscore_device_t *core, int led); + /* smsdvb.c */ int smsdvb_register(void); void smsdvb_unregister(void); diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c index 8d490e133f3..2da953a4f4f 100644 --- a/drivers/media/dvb/siano/smsdvb.c +++ b/drivers/media/dvb/siano/smsdvb.c @@ -60,6 +60,7 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) client->fe_snr = p->Stat.SNR; client->fe_ber = p->Stat.BER; + client->fe_unc = p->Stat.BERErrorCount; if (p->Stat.InBandPwr < -95) client->fe_signal_strength = 0; @@ -72,6 +73,7 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) client->fe_status = 0; client->fe_snr = client->fe_ber = + client->fe_unc = client->fe_signal_strength = 0; } @@ -165,8 +167,18 @@ static int smsdvb_send_statistics_request(struct smsdvb_client_t *client) struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ, DVBT_BDA_CONTROL_MSG_ID, HIF_TASK, sizeof(struct SmsMsgHdr_ST), 0 }; - return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->stat_done); + int ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), + &client->stat_done); + if (ret < 0) + return ret; + + if (client->fe_status & FE_HAS_LOCK) + sms_board_led_feedback(client->coredev, + (client->fe_unc == 0) ? + SMS_LED_HI : SMS_LED_LO); + else + sms_board_led_feedback(client->coredev, SMS_LED_OFF); + return ret; } static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat) @@ -217,6 +229,18 @@ static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr) return rc; } +static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + int rc = smsdvb_send_statistics_request(client); + + if (!rc) + *ucblocks = client->fe_unc; + + return rc; +} + static int smsdvb_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) { @@ -273,6 +297,28 @@ static int smsdvb_get_frontend(struct dvb_frontend *fe, /* todo: */ memcpy(fep, &client->fe_params, sizeof(struct dvb_frontend_parameters)); + + return 0; +} + +static int smsdvb_init(struct dvb_frontend *fe) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + + sms_board_power(client->coredev, 1); + + return 0; +} + +static int smsdvb_sleep(struct dvb_frontend *fe) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + + sms_board_led_feedback(client->coredev, SMS_LED_OFF); + sms_board_power(client->coredev, 0); + return 0; } @@ -308,6 +354,10 @@ static struct dvb_frontend_ops smsdvb_fe_ops = { .read_ber = smsdvb_read_ber, .read_signal_strength = smsdvb_read_signal_strength, .read_snr = smsdvb_read_snr, + .read_ucblocks = smsdvb_read_ucblocks, + + .init = smsdvb_init, + .sleep = smsdvb_sleep, }; static int smsdvb_hotplug(struct smscore_device_t *coredev, @@ -402,6 +452,8 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev, sms_info("success"); + sms_board_setup(coredev); + return 0; client_error: diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c index 87a3c24454b..5d7ca341771 100644 --- a/drivers/media/dvb/siano/smsusb.c +++ b/drivers/media/dvb/siano/smsusb.c @@ -432,11 +432,56 @@ static void smsusb_disconnect(struct usb_interface *intf) smsusb_term_device(intf); } +static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg) +{ + struct smsusb_device_t *dev = + (struct smsusb_device_t *)usb_get_intfdata(intf); + printk(KERN_INFO "%s Entering status %d.\n", __func__, msg.event); + smsusb_stop_streaming(dev); + return 0; +} + +static int smsusb_resume(struct usb_interface *intf) +{ + int rc, i; + struct smsusb_device_t *dev = + (struct smsusb_device_t *)usb_get_intfdata(intf); + struct usb_device *udev = interface_to_usbdev(intf); + + printk(KERN_INFO "%s Entering.\n", __func__); + usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81)); + usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02)); + + for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) + printk(KERN_INFO "endpoint %d %02x %02x %d\n", i, + intf->cur_altsetting->endpoint[i].desc.bEndpointAddress, + intf->cur_altsetting->endpoint[i].desc.bmAttributes, + intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize); + + if (intf->num_altsetting > 0) { + rc = usb_set_interface(udev, + intf->cur_altsetting->desc. + bInterfaceNumber, 0); + if (rc < 0) { + printk(KERN_INFO + "%s usb_set_interface failed, rc %d\n", + __func__, rc); + return rc; + } + } + + smsusb_start_streaming(dev); + return 0; +} + static struct usb_driver smsusb_driver = { .name = "sms1xxx", .probe = smsusb_probe, .disconnect = smsusb_disconnect, .id_table = smsusb_id_table, + + .suspend = smsusb_suspend, + .resume = smsusb_resume, }; int smsusb_register(void) diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index 401a04effc0..ab0bcd208c7 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig @@ -104,6 +104,8 @@ config DVB_BUDGET_CI select DVB_STV0297 if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE + select DVB_STB0899 if !DVB_FE_CUSTOMISE + select DVB_STB6100 if !DVB_FE_CUSTOMISE select DVB_LNBP21 if !DVB_FE_CUSTOMISE select DVB_TDA10023 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMIZE @@ -131,6 +133,8 @@ config DVB_BUDGET_AV select DVB_TDA1004X if !DVB_FE_CUSTOMISE select DVB_TDA10021 if !DVB_FE_CUSTOMISE select DVB_TDA10023 if !DVB_FE_CUSTOMISE + select DVB_STB0899 if !DVB_FE_CUSTOMISE + select DVB_TDA8261 if !DVB_FE_CUSTOMISE select DVB_TUA6100 if !DVB_FE_CUSTOMISE help Support for simple SAA7146 based DVB cards diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 1032ea77837..f996cef79ec 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -35,6 +35,11 @@ #include "budget.h" #include "stv0299.h" +#include "stb0899_drv.h" +#include "stb0899_reg.h" +#include "stb0899_cfg.h" +#include "tda8261.h" +#include "tda8261_cfg.h" #include "tda1002x.h" #include "tda1004x.h" #include "tua6100.h" @@ -882,6 +887,281 @@ static struct stv0299_config philips_sd1878_config = { .set_symbol_rate = philips_sd1878_ci_set_symbol_rate, }; +/* KNC1 DVB-S (STB0899) Inittab */ +static const struct stb0899_s1_reg knc1_stb0899_s1_init_1[] = { + + { STB0899_DEV_ID , 0x81 }, + { STB0899_DISCNTRL1 , 0x32 }, + { STB0899_DISCNTRL2 , 0x80 }, + { STB0899_DISRX_ST0 , 0x04 }, + { STB0899_DISRX_ST1 , 0x00 }, + { STB0899_DISPARITY , 0x00 }, + { STB0899_DISFIFO , 0x00 }, + { STB0899_DISSTATUS , 0x20 }, + { STB0899_DISF22 , 0x8c }, + { STB0899_DISF22RX , 0x9a }, + { STB0899_SYSREG , 0x0b }, + { STB0899_ACRPRESC , 0x11 }, + { STB0899_ACRDIV1 , 0x0a }, + { STB0899_ACRDIV2 , 0x05 }, + { STB0899_DACR1 , 0x00 }, + { STB0899_DACR2 , 0x00 }, + { STB0899_OUTCFG , 0x00 }, + { STB0899_MODECFG , 0x00 }, + { STB0899_IRQSTATUS_3 , 0x30 }, + { STB0899_IRQSTATUS_2 , 0x00 }, + { STB0899_IRQSTATUS_1 , 0x00 }, + { STB0899_IRQSTATUS_0 , 0x00 }, + { STB0899_IRQMSK_3 , 0xf3 }, + { STB0899_IRQMSK_2 , 0xfc }, + { STB0899_IRQMSK_1 , 0xff }, + { STB0899_IRQMSK_0 , 0xff }, + { STB0899_IRQCFG , 0x00 }, + { STB0899_I2CCFG , 0x88 }, + { STB0899_I2CRPT , 0x58 }, /* Repeater=8, Stop=disabled */ + { STB0899_IOPVALUE5 , 0x00 }, + { STB0899_IOPVALUE4 , 0x20 }, + { STB0899_IOPVALUE3 , 0xc9 }, + { STB0899_IOPVALUE2 , 0x90 }, + { STB0899_IOPVALUE1 , 0x40 }, + { STB0899_IOPVALUE0 , 0x00 }, + { STB0899_GPIO00CFG , 0x82 }, + { STB0899_GPIO01CFG , 0x82 }, + { STB0899_GPIO02CFG , 0x82 }, + { STB0899_GPIO03CFG , 0x82 }, + { STB0899_GPIO04CFG , 0x82 }, + { STB0899_GPIO05CFG , 0x82 }, + { STB0899_GPIO06CFG , 0x82 }, + { STB0899_GPIO07CFG , 0x82 }, + { STB0899_GPIO08CFG , 0x82 }, + { STB0899_GPIO09CFG , 0x82 }, + { STB0899_GPIO10CFG , 0x82 }, + { STB0899_GPIO11CFG , 0x82 }, + { STB0899_GPIO12CFG , 0x82 }, + { STB0899_GPIO13CFG , 0x82 }, + { STB0899_GPIO14CFG , 0x82 }, + { STB0899_GPIO15CFG , 0x82 }, + { STB0899_GPIO16CFG , 0x82 }, + { STB0899_GPIO17CFG , 0x82 }, + { STB0899_GPIO18CFG , 0x82 }, + { STB0899_GPIO19CFG , 0x82 }, + { STB0899_GPIO20CFG , 0x82 }, + { STB0899_SDATCFG , 0xb8 }, + { STB0899_SCLTCFG , 0xba }, + { STB0899_AGCRFCFG , 0x08 }, /* 0x1c */ + { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ + { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ + { STB0899_DIRCLKCFG , 0x82 }, + { STB0899_CLKOUT27CFG , 0x7e }, + { STB0899_STDBYCFG , 0x82 }, + { STB0899_CS0CFG , 0x82 }, + { STB0899_CS1CFG , 0x82 }, + { STB0899_DISEQCOCFG , 0x20 }, + { STB0899_GPIO32CFG , 0x82 }, + { STB0899_GPIO33CFG , 0x82 }, + { STB0899_GPIO34CFG , 0x82 }, + { STB0899_GPIO35CFG , 0x82 }, + { STB0899_GPIO36CFG , 0x82 }, + { STB0899_GPIO37CFG , 0x82 }, + { STB0899_GPIO38CFG , 0x82 }, + { STB0899_GPIO39CFG , 0x82 }, + { STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ + { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ + { STB0899_FILTCTRL , 0x00 }, + { STB0899_SYSCTRL , 0x00 }, + { STB0899_STOPCLK1 , 0x20 }, + { STB0899_STOPCLK2 , 0x00 }, + { STB0899_INTBUFSTATUS , 0x00 }, + { STB0899_INTBUFCTRL , 0x0a }, + { 0xffff , 0xff }, +}; + +static const struct stb0899_s1_reg knc1_stb0899_s1_init_3[] = { + { STB0899_DEMOD , 0x00 }, + { STB0899_RCOMPC , 0xc9 }, + { STB0899_AGC1CN , 0x41 }, + { STB0899_AGC1REF , 0x08 }, + { STB0899_RTC , 0x7a }, + { STB0899_TMGCFG , 0x4e }, + { STB0899_AGC2REF , 0x33 }, + { STB0899_TLSR , 0x84 }, + { STB0899_CFD , 0xee }, + { STB0899_ACLC , 0x87 }, + { STB0899_BCLC , 0x94 }, + { STB0899_EQON , 0x41 }, + { STB0899_LDT , 0xdd }, + { STB0899_LDT2 , 0xc9 }, + { STB0899_EQUALREF , 0xb4 }, + { STB0899_TMGRAMP , 0x10 }, + { STB0899_TMGTHD , 0x30 }, + { STB0899_IDCCOMP , 0xfb }, + { STB0899_QDCCOMP , 0x03 }, + { STB0899_POWERI , 0x3b }, + { STB0899_POWERQ , 0x3d }, + { STB0899_RCOMP , 0x81 }, + { STB0899_AGCIQIN , 0x80 }, + { STB0899_AGC2I1 , 0x04 }, + { STB0899_AGC2I2 , 0xf5 }, + { STB0899_TLIR , 0x25 }, + { STB0899_RTF , 0x80 }, + { STB0899_DSTATUS , 0x00 }, + { STB0899_LDI , 0xca }, + { STB0899_CFRM , 0xf1 }, + { STB0899_CFRL , 0xf3 }, + { STB0899_NIRM , 0x2a }, + { STB0899_NIRL , 0x05 }, + { STB0899_ISYMB , 0x17 }, + { STB0899_QSYMB , 0xfa }, + { STB0899_SFRH , 0x2f }, + { STB0899_SFRM , 0x68 }, + { STB0899_SFRL , 0x40 }, + { STB0899_SFRUPH , 0x2f }, + { STB0899_SFRUPM , 0x68 }, + { STB0899_SFRUPL , 0x40 }, + { STB0899_EQUAI1 , 0xfd }, + { STB0899_EQUAQ1 , 0x04 }, + { STB0899_EQUAI2 , 0x0f }, + { STB0899_EQUAQ2 , 0xff }, + { STB0899_EQUAI3 , 0xdf }, + { STB0899_EQUAQ3 , 0xfa }, + { STB0899_EQUAI4 , 0x37 }, + { STB0899_EQUAQ4 , 0x0d }, + { STB0899_EQUAI5 , 0xbd }, + { STB0899_EQUAQ5 , 0xf7 }, + { STB0899_DSTATUS2 , 0x00 }, + { STB0899_VSTATUS , 0x00 }, + { STB0899_VERROR , 0xff }, + { STB0899_IQSWAP , 0x2a }, + { STB0899_ECNT1M , 0x00 }, + { STB0899_ECNT1L , 0x00 }, + { STB0899_ECNT2M , 0x00 }, + { STB0899_ECNT2L , 0x00 }, + { STB0899_ECNT3M , 0x00 }, + { STB0899_ECNT3L , 0x00 }, + { STB0899_FECAUTO1 , 0x06 }, + { STB0899_FECM , 0x01 }, + { STB0899_VTH12 , 0xf0 }, + { STB0899_VTH23 , 0xa0 }, + { STB0899_VTH34 , 0x78 }, + { STB0899_VTH56 , 0x4e }, + { STB0899_VTH67 , 0x48 }, + { STB0899_VTH78 , 0x38 }, + { STB0899_PRVIT , 0xff }, + { STB0899_VITSYNC , 0x19 }, + { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ + { STB0899_TSULC , 0x42 }, + { STB0899_RSLLC , 0x40 }, + { STB0899_TSLPL , 0x12 }, + { STB0899_TSCFGH , 0x0c }, + { STB0899_TSCFGM , 0x00 }, + { STB0899_TSCFGL , 0x0c }, + { STB0899_TSOUT , 0x0d }, /* 0x0d for CAM */ + { STB0899_RSSYNCDEL , 0x00 }, + { STB0899_TSINHDELH , 0x02 }, + { STB0899_TSINHDELM , 0x00 }, + { STB0899_TSINHDELL , 0x00 }, + { STB0899_TSLLSTKM , 0x00 }, + { STB0899_TSLLSTKL , 0x00 }, + { STB0899_TSULSTKM , 0x00 }, + { STB0899_TSULSTKL , 0xab }, + { STB0899_PCKLENUL , 0x00 }, + { STB0899_PCKLENLL , 0xcc }, + { STB0899_RSPCKLEN , 0xcc }, + { STB0899_TSSTATUS , 0x80 }, + { STB0899_ERRCTRL1 , 0xb6 }, + { STB0899_ERRCTRL2 , 0x96 }, + { STB0899_ERRCTRL3 , 0x89 }, + { STB0899_DMONMSK1 , 0x27 }, + { STB0899_DMONMSK0 , 0x03 }, + { STB0899_DEMAPVIT , 0x5c }, + { STB0899_PLPARM , 0x1f }, + { STB0899_PDELCTRL , 0x48 }, + { STB0899_PDELCTRL2 , 0x00 }, + { STB0899_BBHCTRL1 , 0x00 }, + { STB0899_BBHCTRL2 , 0x00 }, + { STB0899_HYSTTHRESH , 0x77 }, + { STB0899_MATCSTM , 0x00 }, + { STB0899_MATCSTL , 0x00 }, + { STB0899_UPLCSTM , 0x00 }, + { STB0899_UPLCSTL , 0x00 }, + { STB0899_DFLCSTM , 0x00 }, + { STB0899_DFLCSTL , 0x00 }, + { STB0899_SYNCCST , 0x00 }, + { STB0899_SYNCDCSTM , 0x00 }, + { STB0899_SYNCDCSTL , 0x00 }, + { STB0899_ISI_ENTRY , 0x00 }, + { STB0899_ISI_BIT_EN , 0x00 }, + { STB0899_MATSTRM , 0x00 }, + { STB0899_MATSTRL , 0x00 }, + { STB0899_UPLSTRM , 0x00 }, + { STB0899_UPLSTRL , 0x00 }, + { STB0899_DFLSTRM , 0x00 }, + { STB0899_DFLSTRL , 0x00 }, + { STB0899_SYNCSTR , 0x00 }, + { STB0899_SYNCDSTRM , 0x00 }, + { STB0899_SYNCDSTRL , 0x00 }, + { STB0899_CFGPDELSTATUS1 , 0x10 }, + { STB0899_CFGPDELSTATUS2 , 0x00 }, + { STB0899_BBFERRORM , 0x00 }, + { STB0899_BBFERRORL , 0x00 }, + { STB0899_UPKTERRORM , 0x00 }, + { STB0899_UPKTERRORL , 0x00 }, + { 0xffff , 0xff }, +}; + +/* STB0899 demodulator config for the KNC1 and clones */ +static struct stb0899_config knc1_dvbs2_config = { + .init_dev = knc1_stb0899_s1_init_1, + .init_s2_demod = stb0899_s2_init_2, + .init_s1_demod = knc1_stb0899_s1_init_3, + .init_s2_fec = stb0899_s2_init_4, + .init_tst = stb0899_s1_init_5, + + .postproc = NULL, + + .demod_address = 0x68, +// .ts_output_mode = STB0899_OUT_PARALLEL, /* types = SERIAL/PARALLEL */ + .block_sync_mode = STB0899_SYNC_FORCED, /* DSS, SYNC_FORCED/UNSYNCED */ +// .ts_pfbit_toggle = STB0899_MPEG_NORMAL, /* DirecTV, MPEG toggling seq */ + + .xtal_freq = 27000000, + .inversion = IQ_SWAP_OFF, /* 1 */ + + .lo_clk = 76500000, + .hi_clk = 90000000, + + .esno_ave = STB0899_DVBS2_ESNO_AVE, + .esno_quant = STB0899_DVBS2_ESNO_QUANT, + .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, + .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, + .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, + .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, + .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, + .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, + .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, + + .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, + .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, + .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, + .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, + + .tuner_get_frequency = tda8261_get_frequency, + .tuner_set_frequency = tda8261_set_frequency, + .tuner_set_bandwidth = NULL, + .tuner_get_bandwidth = tda8261_get_bandwidth, + .tuner_set_rfsiggain = NULL +}; + +/* + * SD1878/SHA tuner config + * 1F, Single I/P, Horizontal mount, High Sensitivity + */ +static const struct tda8261_config sd1878c_config = { +// .name = "SD1878/SHA", + .addr = 0x60, + .step_size = TDA8261_STEP_1000 /* kHz */ +}; + static u8 read_pwm(struct budget_av *budget_av) { u8 b = 0xff; @@ -905,8 +1185,11 @@ static u8 read_pwm(struct budget_av *budget_av) #define SUBID_DVBS_TV_STAR 0x0014 #define SUBID_DVBS_TV_STAR_PLUS_X4 0x0015 #define SUBID_DVBS_TV_STAR_CI 0x0016 +#define SUBID_DVBS2_KNC1 0x0018 +#define SUBID_DVBS2_KNC1_OEM 0x0019 #define SUBID_DVBS_EASYWATCH_1 0x001a #define SUBID_DVBS_EASYWATCH_2 0x001b +#define SUBID_DVBS2_EASYWATCH 0x001d #define SUBID_DVBS_EASYWATCH 0x001e #define SUBID_DVBC_EASYWATCH 0x002a @@ -941,6 +1224,9 @@ static void frontend_init(struct budget_av *budget_av) case SUBID_DVBT_KNC1_PLUS: case SUBID_DVBC_EASYWATCH: case SUBID_DVBC_KNC1_PLUS_MK3: + case SUBID_DVBS2_KNC1: + case SUBID_DVBS2_KNC1_OEM: + case SUBID_DVBS2_EASYWATCH: saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI); break; } @@ -993,7 +1279,14 @@ static void frontend_init(struct budget_av *budget_av) fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params; } break; + case SUBID_DVBS2_KNC1: + case SUBID_DVBS2_KNC1_OEM: + case SUBID_DVBS2_EASYWATCH: + budget_av->reinitialise_demod = 1; + if ((fe = dvb_attach(stb0899_attach, &knc1_dvbs2_config, &budget_av->budget.i2c_adap))) + dvb_attach(tda8261_attach, fe, &sd1878c_config, &budget_av->budget.i2c_adap); + break; case SUBID_DVBS_CINERGY1200: fe = dvb_attach(stv0299_attach, &cinergy_1200s_config, &budget_av->budget.i2c_adap); @@ -1260,6 +1553,8 @@ static struct saa7146_ext_vv vv_data = { static struct saa7146_extension budget_extension; MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S); +MAKE_BUDGET_INFO(knc1s2,"KNC1 DVB-S2", BUDGET_KNC1S2); +MAKE_BUDGET_INFO(sates2,"Satelco EasyWatch DVB-S2", BUDGET_KNC1S2); MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C); MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T); MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR); @@ -1290,6 +1585,9 @@ static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014), MAKE_EXTENSION_PCI(knc1spx4, 0x1894, 0x0015), MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016), + MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0018), + MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0019), + MAKE_EXTENSION_PCI(sates2, 0x1894, 0x001d), MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e), MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a), MAKE_EXTENSION_PCI(satewps, 0x1894, 0x001b), diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 0a5aad45435..3507463fdac 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -43,6 +43,11 @@ #include "stv0299.h" #include "stv0297.h" #include "tda1004x.h" +#include "stb0899_drv.h" +#include "stb0899_reg.h" +#include "stb0899_cfg.h" +#include "stb6100.h" +#include "stb6100_cfg.h" #include "lnbp21.h" #include "bsbe1.h" #include "bsru6.h" @@ -1071,7 +1076,271 @@ static struct tda10023_config tda10023_config = { .deltaf = 0xa511, }; +/* TT S2-3200 DVB-S (STB0899) Inittab */ +static const struct stb0899_s1_reg tt3200_stb0899_s1_init_1[] = { + + { STB0899_DEV_ID , 0x81 }, + { STB0899_DISCNTRL1 , 0x32 }, + { STB0899_DISCNTRL2 , 0x80 }, + { STB0899_DISRX_ST0 , 0x04 }, + { STB0899_DISRX_ST1 , 0x00 }, + { STB0899_DISPARITY , 0x00 }, + { STB0899_DISFIFO , 0x00 }, + { STB0899_DISSTATUS , 0x20 }, + { STB0899_DISF22 , 0x8c }, + { STB0899_DISF22RX , 0x9a }, + { STB0899_SYSREG , 0x0b }, + { STB0899_ACRPRESC , 0x11 }, + { STB0899_ACRDIV1 , 0x0a }, + { STB0899_ACRDIV2 , 0x05 }, + { STB0899_DACR1 , 0x00 }, + { STB0899_DACR2 , 0x00 }, + { STB0899_OUTCFG , 0x00 }, + { STB0899_MODECFG , 0x00 }, + { STB0899_IRQSTATUS_3 , 0x30 }, + { STB0899_IRQSTATUS_2 , 0x00 }, + { STB0899_IRQSTATUS_1 , 0x00 }, + { STB0899_IRQSTATUS_0 , 0x00 }, + { STB0899_IRQMSK_3 , 0xf3 }, + { STB0899_IRQMSK_2 , 0xfc }, + { STB0899_IRQMSK_1 , 0xff }, + { STB0899_IRQMSK_0 , 0xff }, + { STB0899_IRQCFG , 0x00 }, + { STB0899_I2CCFG , 0x88 }, + { STB0899_I2CRPT , 0x48 }, /* 12k Pullup, Repeater=16, Stop=disabled */ + { STB0899_IOPVALUE5 , 0x00 }, + { STB0899_IOPVALUE4 , 0x20 }, + { STB0899_IOPVALUE3 , 0xc9 }, + { STB0899_IOPVALUE2 , 0x90 }, + { STB0899_IOPVALUE1 , 0x40 }, + { STB0899_IOPVALUE0 , 0x00 }, + { STB0899_GPIO00CFG , 0x82 }, + { STB0899_GPIO01CFG , 0x82 }, + { STB0899_GPIO02CFG , 0x82 }, + { STB0899_GPIO03CFG , 0x82 }, + { STB0899_GPIO04CFG , 0x82 }, + { STB0899_GPIO05CFG , 0x82 }, + { STB0899_GPIO06CFG , 0x82 }, + { STB0899_GPIO07CFG , 0x82 }, + { STB0899_GPIO08CFG , 0x82 }, + { STB0899_GPIO09CFG , 0x82 }, + { STB0899_GPIO10CFG , 0x82 }, + { STB0899_GPIO11CFG , 0x82 }, + { STB0899_GPIO12CFG , 0x82 }, + { STB0899_GPIO13CFG , 0x82 }, + { STB0899_GPIO14CFG , 0x82 }, + { STB0899_GPIO15CFG , 0x82 }, + { STB0899_GPIO16CFG , 0x82 }, + { STB0899_GPIO17CFG , 0x82 }, + { STB0899_GPIO18CFG , 0x82 }, + { STB0899_GPIO19CFG , 0x82 }, + { STB0899_GPIO20CFG , 0x82 }, + { STB0899_SDATCFG , 0xb8 }, + { STB0899_SCLTCFG , 0xba }, + { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */ + { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ + { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ + { STB0899_DIRCLKCFG , 0x82 }, + { STB0899_CLKOUT27CFG , 0x7e }, + { STB0899_STDBYCFG , 0x82 }, + { STB0899_CS0CFG , 0x82 }, + { STB0899_CS1CFG , 0x82 }, + { STB0899_DISEQCOCFG , 0x20 }, + { STB0899_GPIO32CFG , 0x82 }, + { STB0899_GPIO33CFG , 0x82 }, + { STB0899_GPIO34CFG , 0x82 }, + { STB0899_GPIO35CFG , 0x82 }, + { STB0899_GPIO36CFG , 0x82 }, + { STB0899_GPIO37CFG , 0x82 }, + { STB0899_GPIO38CFG , 0x82 }, + { STB0899_GPIO39CFG , 0x82 }, + { STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ + { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ + { STB0899_FILTCTRL , 0x00 }, + { STB0899_SYSCTRL , 0x00 }, + { STB0899_STOPCLK1 , 0x20 }, + { STB0899_STOPCLK2 , 0x00 }, + { STB0899_INTBUFSTATUS , 0x00 }, + { STB0899_INTBUFCTRL , 0x0a }, + { 0xffff , 0xff }, +}; + +static const struct stb0899_s1_reg tt3200_stb0899_s1_init_3[] = { + { STB0899_DEMOD , 0x00 }, + { STB0899_RCOMPC , 0xc9 }, + { STB0899_AGC1CN , 0x41 }, + { STB0899_AGC1REF , 0x10 }, + { STB0899_RTC , 0x7a }, + { STB0899_TMGCFG , 0x4e }, + { STB0899_AGC2REF , 0x34 }, + { STB0899_TLSR , 0x84 }, + { STB0899_CFD , 0xc7 }, + { STB0899_ACLC , 0x87 }, + { STB0899_BCLC , 0x94 }, + { STB0899_EQON , 0x41 }, + { STB0899_LDT , 0xdd }, + { STB0899_LDT2 , 0xc9 }, + { STB0899_EQUALREF , 0xb4 }, + { STB0899_TMGRAMP , 0x10 }, + { STB0899_TMGTHD , 0x30 }, + { STB0899_IDCCOMP , 0xfb }, + { STB0899_QDCCOMP , 0x03 }, + { STB0899_POWERI , 0x3b }, + { STB0899_POWERQ , 0x3d }, + { STB0899_RCOMP , 0x81 }, + { STB0899_AGCIQIN , 0x80 }, + { STB0899_AGC2I1 , 0x04 }, + { STB0899_AGC2I2 , 0xf5 }, + { STB0899_TLIR , 0x25 }, + { STB0899_RTF , 0x80 }, + { STB0899_DSTATUS , 0x00 }, + { STB0899_LDI , 0xca }, + { STB0899_CFRM , 0xf1 }, + { STB0899_CFRL , 0xf3 }, + { STB0899_NIRM , 0x2a }, + { STB0899_NIRL , 0x05 }, + { STB0899_ISYMB , 0x17 }, + { STB0899_QSYMB , 0xfa }, + { STB0899_SFRH , 0x2f }, + { STB0899_SFRM , 0x68 }, + { STB0899_SFRL , 0x40 }, + { STB0899_SFRUPH , 0x2f }, + { STB0899_SFRUPM , 0x68 }, + { STB0899_SFRUPL , 0x40 }, + { STB0899_EQUAI1 , 0xfd }, + { STB0899_EQUAQ1 , 0x04 }, + { STB0899_EQUAI2 , 0x0f }, + { STB0899_EQUAQ2 , 0xff }, + { STB0899_EQUAI3 , 0xdf }, + { STB0899_EQUAQ3 , 0xfa }, + { STB0899_EQUAI4 , 0x37 }, + { STB0899_EQUAQ4 , 0x0d }, + { STB0899_EQUAI5 , 0xbd }, + { STB0899_EQUAQ5 , 0xf7 }, + { STB0899_DSTATUS2 , 0x00 }, + { STB0899_VSTATUS , 0x00 }, + { STB0899_VERROR , 0xff }, + { STB0899_IQSWAP , 0x2a }, + { STB0899_ECNT1M , 0x00 }, + { STB0899_ECNT1L , 0x00 }, + { STB0899_ECNT2M , 0x00 }, + { STB0899_ECNT2L , 0x00 }, + { STB0899_ECNT3M , 0x00 }, + { STB0899_ECNT3L , 0x00 }, + { STB0899_FECAUTO1 , 0x06 }, + { STB0899_FECM , 0x01 }, + { STB0899_VTH12 , 0xf0 }, + { STB0899_VTH23 , 0xa0 }, + { STB0899_VTH34 , 0x78 }, + { STB0899_VTH56 , 0x4e }, + { STB0899_VTH67 , 0x48 }, + { STB0899_VTH78 , 0x38 }, + { STB0899_PRVIT , 0xff }, + { STB0899_VITSYNC , 0x19 }, + { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ + { STB0899_TSULC , 0x42 }, + { STB0899_RSLLC , 0x40 }, + { STB0899_TSLPL , 0x12 }, + { STB0899_TSCFGH , 0x0c }, + { STB0899_TSCFGM , 0x00 }, + { STB0899_TSCFGL , 0x0c }, + { STB0899_TSOUT , 0x0d }, /* 0x0d for CAM */ + { STB0899_RSSYNCDEL , 0x00 }, + { STB0899_TSINHDELH , 0x02 }, + { STB0899_TSINHDELM , 0x00 }, + { STB0899_TSINHDELL , 0x00 }, + { STB0899_TSLLSTKM , 0x00 }, + { STB0899_TSLLSTKL , 0x00 }, + { STB0899_TSULSTKM , 0x00 }, + { STB0899_TSULSTKL , 0xab }, + { STB0899_PCKLENUL , 0x00 }, + { STB0899_PCKLENLL , 0xcc }, + { STB0899_RSPCKLEN , 0xcc }, + { STB0899_TSSTATUS , 0x80 }, + { STB0899_ERRCTRL1 , 0xb6 }, + { STB0899_ERRCTRL2 , 0x96 }, + { STB0899_ERRCTRL3 , 0x89 }, + { STB0899_DMONMSK1 , 0x27 }, + { STB0899_DMONMSK0 , 0x03 }, + { STB0899_DEMAPVIT , 0x5c }, + { STB0899_PLPARM , 0x1f }, + { STB0899_PDELCTRL , 0x48 }, + { STB0899_PDELCTRL2 , 0x00 }, + { STB0899_BBHCTRL1 , 0x00 }, + { STB0899_BBHCTRL2 , 0x00 }, + { STB0899_HYSTTHRESH , 0x77 }, + { STB0899_MATCSTM , 0x00 }, + { STB0899_MATCSTL , 0x00 }, + { STB0899_UPLCSTM , 0x00 }, + { STB0899_UPLCSTL , 0x00 }, + { STB0899_DFLCSTM , 0x00 }, + { STB0899_DFLCSTL , 0x00 }, + { STB0899_SYNCCST , 0x00 }, + { STB0899_SYNCDCSTM , 0x00 }, + { STB0899_SYNCDCSTL , 0x00 }, + { STB0899_ISI_ENTRY , 0x00 }, + { STB0899_ISI_BIT_EN , 0x00 }, + { STB0899_MATSTRM , 0x00 }, + { STB0899_MATSTRL , 0x00 }, + { STB0899_UPLSTRM , 0x00 }, + { STB0899_UPLSTRL , 0x00 }, + { STB0899_DFLSTRM , 0x00 }, + { STB0899_DFLSTRL , 0x00 }, + { STB0899_SYNCSTR , 0x00 }, + { STB0899_SYNCDSTRM , 0x00 }, + { STB0899_SYNCDSTRL , 0x00 }, + { STB0899_CFGPDELSTATUS1 , 0x10 }, + { STB0899_CFGPDELSTATUS2 , 0x00 }, + { STB0899_BBFERRORM , 0x00 }, + { STB0899_BBFERRORL , 0x00 }, + { STB0899_UPKTERRORM , 0x00 }, + { STB0899_UPKTERRORL , 0x00 }, + { 0xffff , 0xff }, +}; +static struct stb0899_config tt3200_config = { + .init_dev = tt3200_stb0899_s1_init_1, + .init_s2_demod = stb0899_s2_init_2, + .init_s1_demod = tt3200_stb0899_s1_init_3, + .init_s2_fec = stb0899_s2_init_4, + .init_tst = stb0899_s1_init_5, + + .postproc = NULL, + + .demod_address = 0x68, + + .xtal_freq = 27000000, + .inversion = IQ_SWAP_ON, /* 1 */ + + .lo_clk = 76500000, + .hi_clk = 99000000, + + .esno_ave = STB0899_DVBS2_ESNO_AVE, + .esno_quant = STB0899_DVBS2_ESNO_QUANT, + .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, + .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, + .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, + .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, + .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, + .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, + .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, + + .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, + .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, + .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, + .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, + + .tuner_get_frequency = stb6100_get_frequency, + .tuner_set_frequency = stb6100_set_frequency, + .tuner_set_bandwidth = stb6100_set_bandwidth, + .tuner_get_bandwidth = stb6100_get_bandwidth, + .tuner_set_rfsiggain = NULL +}; + +struct stb6100_config tt3200_stb6100_config = { + .tuner_address = 0x60, + .refclock = 27000000, +}; static void frontend_init(struct budget_ci *budget_ci) { @@ -1152,6 +1421,46 @@ static void frontend_init(struct budget_ci *budget_ci) } } break; + + case 0x1019: // TT S2-3200 PCI + /* + * NOTE! on some STB0899 versions, the internal PLL takes a longer time + * to settle, aka LOCK. On the older revisions of the chip, we don't see + * this, as a result on the newer chips the entire clock tree, will not + * be stable after a freshly POWER 'ed up situation. + * In this case, we should RESET the STB0899 (Active LOW) and wait for + * PLL stabilization. + * + * On the TT S2 3200 and clones, the STB0899 demodulator's RESETB is + * connected to the SAA7146 GPIO, GPIO2, Pin 142 + */ + /* Reset Demodulator */ + saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTLO); + /* Wait for everything to die */ + msleep(50); + /* Pull it up out of Reset state */ + saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTHI); + /* Wait for PLL to stabilize */ + msleep(250); + /* + * PLL state should be stable now. Ideally, we should check + * for PLL LOCK status. But well, never mind! + */ + budget_ci->budget.dvb_frontend = dvb_attach(stb0899_attach, &tt3200_config, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + if (dvb_attach(stb6100_attach, budget_ci->budget.dvb_frontend, &tt3200_stb6100_config, &budget_ci->budget.i2c_adap)) { + if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) { + printk("%s: No LNBP21 found!\n", __FUNCTION__); + dvb_frontend_detach(budget_ci->budget.dvb_frontend); + budget_ci->budget.dvb_frontend = NULL; + } + } else { + dvb_frontend_detach(budget_ci->budget.dvb_frontend); + budget_ci->budget.dvb_frontend = NULL; + } + } + break; + } if (budget_ci->budget.dvb_frontend == NULL) { @@ -1242,6 +1551,7 @@ MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT); MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT); MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT); +MAKE_BUDGET_INFO(tt3200, "TT-Budget S2-3200 PCI", BUDGET_TT); static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c), @@ -1251,6 +1561,7 @@ static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012), MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017), MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a), + MAKE_EXTENSION_PCI(tt3200, 0x13c2, 0x1019), { .vendor = 0, } diff --git a/drivers/media/dvb/ttpci/budget.h b/drivers/media/dvb/ttpci/budget.h index 86435bf1626..3ad0c6789ba 100644 --- a/drivers/media/dvb/ttpci/budget.h +++ b/drivers/media/dvb/ttpci/budget.h @@ -103,6 +103,7 @@ static struct saa7146_pci_extension_data x_var = { \ #define BUDGET_CIN1200C_MK3 15 #define BUDGET_KNC1C_MK3 16 #define BUDGET_KNC1CP_MK3 17 +#define BUDGET_KNC1S2 18 #define BUDGET_VIDEO_PORTA 0 #define BUDGET_VIDEO_PORTB 1 |