diff --git a/apps/setmod3.c b/apps/setmod3.c index ed3a6f2..302cb09 100644 --- a/apps/setmod3.c +++ b/apps/setmod3.c @@ -63,12 +63,18 @@ int main() /* gain 0-255 */ get_property(fd, MODULATOR_GAIN, &data); printf("Modulator gain = %u\n", data); - set_property(fd, MODULATOR_GAIN, 120); + set_property(fd, MODULATOR_GAIN, 100); + get_property(fd, MODULATOR_GAIN, &data); printf("Modulator gain = %u\n", data); + get_property(fd, MODULATOR_ATTENUATOR, &data); + printf("Modulator attenuator = %u\n", data); + + get_property(fd, MODULATOR_STATUS, &data); printf("Modulator status = %u\n", data); + set_property(fd, MODULATOR_STATUS, 2); //set_property(fd, MODULATOR_RESET, 0); diff --git a/ddbridge/ddbridge-core.c b/ddbridge/ddbridge-core.c index 27adc79..2517636 100644 --- a/ddbridge/ddbridge-core.c +++ b/ddbridge/ddbridge-core.c @@ -4341,6 +4341,7 @@ static int ddb_init_boards(struct ddb *dev) int ddb_init(struct ddb *dev) { mutex_init(&dev->link[0].flash_mutex); + mutex_init(&dev->ioctl_mutex); if (no_init) { ddb_device_create(dev); return 0; diff --git a/ddbridge/ddbridge-hw.c b/ddbridge/ddbridge-hw.c index 0ddddb6..739b1d9 100644 --- a/ddbridge/ddbridge-hw.c +++ b/ddbridge/ddbridge-hw.c @@ -437,6 +437,7 @@ static const struct ddb_info ddb_mod_fsm_24 = { .port_num = 24, .temp_num = 1, .tempmon_irq = 8, + .lostlock_irq = 9, }; static const struct ddb_info ddb_mod_fsm_16 = { @@ -447,6 +448,7 @@ static const struct ddb_info ddb_mod_fsm_16 = { .port_num = 16, .temp_num = 1, .tempmon_irq = 8, + .lostlock_irq = 9, }; static const struct ddb_info ddb_mod_fsm_8 = { @@ -457,6 +459,7 @@ static const struct ddb_info ddb_mod_fsm_8 = { .port_num = 8, .temp_num = 1, .tempmon_irq = 8, + .lostlock_irq = 9, }; static const struct ddb_info ddb_mod_fsm_4 = { @@ -467,6 +470,7 @@ static const struct ddb_info ddb_mod_fsm_4 = { .port_num = 4, .temp_num = 1, .tempmon_irq = 8, + .lostlock_irq = 9, }; static const struct ddb_info ddb_sdr = { diff --git a/ddbridge/ddbridge-modulator.c b/ddbridge/ddbridge-modulator.c index a453895..93c6162 100644 --- a/ddbridge/ddbridge-modulator.c +++ b/ddbridge/ddbridge-modulator.c @@ -434,6 +434,16 @@ static u32 max2871_sdr[6] = { 0x007A8098, 0x600080C9, 0x510061C2, 0x010000CB, 0x6199003C, 0x60440005 }; +static void lostlock_handler(unsigned long data) +{ + struct ddb *dev = (struct ddb *)data; + + dev_err(dev->dev, "Lost PLL lock!\n"); + ddbwritel(dev, 0, RF_VGA); + udelay(10); + ddbwritel(dev, 31, RF_ATTENUATOR); +} + static int mod_setup_max2871(struct ddb *dev, u32 *reg) { int status = 0; @@ -467,6 +477,12 @@ static int mod_setup_max2871(struct ddb *dev, u32 *reg) ddbwritel(dev, MAX2871_CONTROL_CE | MAX2871_CONTROL_LOSTLOCK, MAX2871_CONTROL); + if (dev->link[0].info->lostlock_irq) { + dev->handler_data[0][dev->link[0].info->lostlock_irq] = + (unsigned long)dev; + dev->handler[0][dev->link[0].info->lostlock_irq] = + lostlock_handler; + } } return status; } @@ -1536,6 +1552,17 @@ static int mod_prop_proc(struct ddb_mod *mod, struct dtv_property *tvp) if (mod->port->dev->link[0].info->version == 2) return mod_fsm_setup(mod->port->dev,0 ); return -EINVAL; + + case MODULATOR_STATUS: + if (mod->port->dev->link[0].info->version != 2) + return -EINVAL; + if (tvp->u.data & 2) + ddbwritel(mod->port->dev, + MAX2871_CONTROL_CE | + MAX2871_CONTROL_LOSTLOCK | + MAX2871_CONTROL_ENABLE_LOSTLOCK_EVENT, + MAX2871_CONTROL); + return 0; } return 0; } @@ -1560,8 +1587,6 @@ static int mod_prop_get(struct ddb_mod *mod, struct dtv_property *tvp) u32 status = 0, val; val = ddbreadl(dev, MAX2871_CONTROL); - if (!(val & MAX2871_CONTROL_LOCK)) - status |= 1; if (!(val & MAX2871_CONTROL_LOCK)) status |= 1; if (val & MAX2871_CONTROL_LOSTLOCK) @@ -1571,6 +1596,9 @@ static int mod_prop_get(struct ddb_mod *mod, struct dtv_property *tvp) val = ddbreadl(dev, TEMPMON_CONTROL); if (val & TEMPMON_CONTROL_OVERTEMP) status |= 4; + val = ddbreadl(dev, HARDWARE_VERSION); + if (val == 0xffffffff) + status |= 8; tvp->u.data = status; return 0; } @@ -1592,13 +1620,18 @@ int ddbridge_mod_do_ioctl(struct file *file, unsigned int cmd, void *parg) if (dev->link[0].info->version == 3 && cmd != FE_SET_PROPERTY) return -EINVAL; + mutex_lock(&dev->ioctl_mutex); switch (cmd) { case FE_SET_PROPERTY: - if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) - return -EINVAL; + if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) { + ret = -EINVAL; + break; + } tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); - if (IS_ERR(tvp)) - return PTR_ERR(tvp); + if (IS_ERR(tvp)) { + ret = PTR_ERR(tvp); + break; + } for (i = 0; i < tvps->num; i++) { ret = mod_prop_proc(mod, tvp + i); if (ret < 0) @@ -1606,14 +1639,18 @@ int ddbridge_mod_do_ioctl(struct file *file, unsigned int cmd, void *parg) (tvp + i)->result = ret; } kfree(tvp); - return ret; + break; case FE_GET_PROPERTY: - if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) - return -EINVAL; + if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) { + ret = -EINVAL; + break; + } tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); - if (IS_ERR(tvp)) - return PTR_ERR(tvp); + if (IS_ERR(tvp)) { + ret = PTR_ERR(tvp); + break; + } for (i = 0; i < tvps->num; i++) { ret = mod_prop_get(mod, tvp + i); if (ret < 0) @@ -1625,7 +1662,7 @@ int ddbridge_mod_do_ioctl(struct file *file, unsigned int cmd, void *parg) tvps->num * sizeof(struct dtv_property))) ret = -EFAULT; kfree(tvp); - return ret; + break; case DVB_MOD_SET: { @@ -1633,8 +1670,10 @@ int ddbridge_mod_do_ioctl(struct file *file, unsigned int cmd, void *parg) if (dev->link[0].info->version < 2) { if (mp->base_frequency != dev->mod_base.frequency) - if (set_base_frequency(dev, mp->base_frequency)) - return -EINVAL; + if (set_base_frequency(dev, mp->base_frequency)) { + ret = -EINVAL; + break; + } } else { int i, streams = dev->link[0].info->port_num; @@ -1659,11 +1698,15 @@ int ddbridge_mod_do_ioctl(struct file *file, unsigned int cmd, void *parg) int res; res = mod_set_modulation(mod, cp->modulation); - if (res) - return res; + if (res) { + ret = res; + break; + } res = mod_set_ibitrate(mod, cp->input_bitrate); - if (res) - return res; + if (res) { + ret = res; + break; + } mod->pcr_correction = cp->pcr_correction; break; } @@ -1671,6 +1714,7 @@ int ddbridge_mod_do_ioctl(struct file *file, unsigned int cmd, void *parg) ret = -EINVAL; break; } + mutex_unlock(&dev->ioctl_mutex); return ret; } @@ -1699,7 +1743,8 @@ static int mod_init_2(struct ddb *dev, u32 Frequency) mod_set_vga(dev, RF_VGA_GAIN_N16); else mod_set_vga(dev, RF_VGA_GAIN_N24); - + + udelay(10); mod_set_attenuator(dev, 0); return 0; } diff --git a/ddbridge/ddbridge.h b/ddbridge/ddbridge.h index 8eacd00..0e891d7 100644 --- a/ddbridge/ddbridge.h +++ b/ddbridge/ddbridge.h @@ -171,7 +171,8 @@ struct ddb_info { #define TS_QUIRK_REVERSED 2 #define TS_QUIRK_NO_OUTPUT 4 #define TS_QUIRK_ALT_OSC 8 - u32 tempmon_irq; + u32 tempmon_irq; + u32 lostlock_irq; const struct ddb_regmap *regmap; }; @@ -474,7 +475,7 @@ struct ddb { struct mod_base mod_base; struct ddb_mod mod[24]; - + struct mutex ioctl_mutex; /* lock extra ioctls */ }; /****************************************************************************/ diff --git a/docs/modulator b/docs/modulator index d468a49..36e2631 100644 --- a/docs/modulator +++ b/docs/modulator @@ -102,7 +102,7 @@ MODULATOR_STATUS and MODULATOR_RESET have been added to debug possible problems with too high temperatures (overtemperature) or PLL lock loss on FSM type cards. -The MODUALTOR_STATUS property returns a __u32 with the following status bits: +The MODULATOR_STATUS property returns a __u32 with the following status bits: - bit 0 : Lock status 1=lock OK, 0 = lock lost @@ -113,8 +113,18 @@ The MODUALTOR_STATUS property returns a __u32 with the following status bits: - bit 2 : 0 = no overtemperature 1 = overtemperature detected +- bit 4 : 0 = PCIe link OK + 1 = PCIe link lost + +In case of overtemperratur or PCIe link loss you will have to reboot the PC. + + +Putting a MODULATOR_STATUS property with value 2 will enable the lost lock +interrupt. This will set the gain to 0 and the attenuation to 31 in case +of a lost PLL lock. + The MODULATOR_RESET property can be used to reset the modulator without -needing to reload the driver or rebooting. +needing to reload the driver or rebooting in case of PLL lock loss. All channels should be stopped before using it and restarted after using it. Otherwise, results are unpredictable.