Hi there! The attached patches should add support for zl10313 chip to mt312-driver. This driver now works for my A700 dvb-s card. @Jan D. Louw: I used register write logs of your driver to compare them to mt312 driver. Maybe this driver works also for your Compro card. 01_mt312-fix-22k: Sets the correct diseqc frequency. 02_mt312-var-types: changes data types for read/write functions to u8* instead of void*. 03_mt312-changable-xtal: Handle xtal freq. and multiplicator in state instead of hardcoding them 04_mt312-add-zl10313-support.diff: Adds basic support for zl10313 Regards Matthias -- Matthias Schwarzott (zzam)
Index: v4l-dvb/linux/drivers/media/dvb/frontends/mt312.c =================================================================== --- v4l-dvb.orig/linux/drivers/media/dvb/frontends/mt312.c +++ v4l-dvb/linux/drivers/media/dvb/frontends/mt312.c @@ -1,7 +1,8 @@ /* - Driver for Zarlink VP310/MT312 Satellite Channel Decoder + Driver for Zarlink VP310/MT312/ZL10313 Satellite Channel Decoder Copyright (C) 2003 Andreas Oberritter <obi@xxxxxxxxxxx> + Copyright (C) 2008 Matthias Schwarzott <zzam@xxxxxxxxxx> 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 @@ -55,6 +56,7 @@ static int debug; } while (0) #define MT312_PLL_CLK 10000000UL /* 10 MHz */ +#define MT312_PLL_CLK_10_111 10111000UL /* 10.111 MHz */ static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg, u8 *buf, const size_t count) @@ -264,6 +266,32 @@ static int mt312_initfe(struct dvb_front return ret; } + switch (state->id) { + case ID_ZL10313: + /* enable ADC */ + ret = mt312_writereg(state, GPP_CTRL, 0x80); + if (ret < 0) + return ret; + + /* for optimal ADC performance according to datasheet */ + buf[0] = 0x80; + buf[1] = 0xB0; + ret = mt312_write(state, HW_CTRL, buf, 2); + if (ret < 0) + return ret; + + /* enable MPEG output */ + ret = mt312_writereg(state, HW_CTRL, 0x00); + if (ret < 0) + return ret; + + ret = mt312_writereg(state, MPEG_CTRL, 0x00); + if (ret < 0) + return ret; + + break; + } + /* SYS_CLK */ buf[0] = mt312_div(state->xtal * state->freq_mult * 2, 1000000); @@ -278,21 +306,28 @@ static int mt312_initfe(struct dvb_front if (ret < 0) return ret; - ret = mt312_writereg(state, OP_CTRL, 0x53); - if (ret < 0) - return ret; + switch (state->id) { + case ID_VP310: + case ID_MT312: + /* this code seems to prevent zl10313 from delivering useful data */ - /* TS_SW_LIM */ - buf[0] = 0x8c; - buf[1] = 0x98; + ret = mt312_writereg(state, OP_CTRL, 0x53); + if (ret < 0) + return ret; - ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf)); - if (ret < 0) - return ret; + /* TS_SW_LIM */ + buf[0] = 0x8c; + buf[1] = 0x98; - ret = mt312_writereg(state, CS_SW_LIM, 0x69); - if (ret < 0) - return ret; + ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf)); + if (ret < 0) + return ret; + + ret = mt312_writereg(state, CS_SW_LIM, 0x69); + if (ret < 0) + return ret; + break; + } return 0; } @@ -321,6 +356,9 @@ static int mt312_send_master_cmd(struct if (ret < 0) return ret; + /* is this needed? */ + msleep(100); + /* set DISEQC_MODE[2:0] to zero if a return message is expected */ if (c->msg[0] & 0x02) { ret = mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40)); @@ -492,6 +530,9 @@ static int mt312_set_frontend(struct dvb int ret; u8 buf[5], config_val; u16 sr; + u32 real_frequency; + s16 foffset = 0; + s8 fr_off; const u8 fec_tab[10] = { 0x00, 0x01, 0x02, 0x04, 0x3f, 0x08, 0x10, 0x20, 0x3f, 0x3f }; @@ -549,6 +590,7 @@ static int mt312_set_frontend(struct dvb break; case ID_MT312: + case ID_ZL10313: break; default: @@ -561,6 +603,20 @@ static int mt312_set_frontend(struct dvb fe->ops.i2c_gate_ctrl(fe, 0); } +#if 0 + // should a demod handle this - or a tune algo call demod functions? + if (state->id == ID_ZL10313 && fe->ops.tuner_ops.get_frequency) { + fe->ops.tuner_ops.get_frequency(fe, &real_frequency); + foffset = p->frequency - real_frequency; + fr_off = foffset / 32; + dprintk("%s: Foffset %d -> %i\n", __FUNCTION__, + foffset, fr_off); + ret = mt312_writereg(state, FR_OFF, fr_off); + if (ret < 0) + return ret; + } +#endif + /* sr = (u16)(sr * 256.0 / 1000000.0) */ sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625); @@ -614,11 +670,25 @@ static int mt312_i2c_gate_ctrl(struct dv { struct mt312_state *state = fe->demodulator_priv; - if (enable) { - return mt312_writereg(state, GPP_CTRL, 0x40); - } else { - return mt312_writereg(state, GPP_CTRL, 0x00); - } + u8 val = 0x00; + int ret; + + ret = mt312_readreg(state, GPP_CTRL, &val); + if (ret < 0) + goto error; + + /* just preserver this bit for now */ +// val &= 0x80; + + if (enable) + val |= 0x40; + else + val &= ~0x40; + + ret = mt312_writereg(state, GPP_CTRL, val); + +error: + return ret; } static int mt312_sleep(struct dvb_frontend *fe) @@ -632,6 +702,18 @@ static int mt312_sleep(struct dvb_fronte if (ret < 0) return ret; + if (state->id == ID_ZL10313) { + /* reset ADC */ + ret = mt312_writereg(state, GPP_CTRL, 0x00); + if (ret < 0) + return ret; + + /* shutdown ADCs and set mpeg bus to tristated */ + ret = mt312_writereg(state, HW_CTRL, 0x0d); + if (ret < 0) + return ret; + } + ret = mt312_readreg(state, CONFIG, &config); if (ret < 0) return ret; @@ -675,6 +757,7 @@ static struct dvb_frontend_ops vp310_mt3 FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_MUTE_TS | FE_CAN_RECOVER + //| FE_CAN_INVERSION_AUTO }, .release = mt312_release, @@ -733,8 +816,13 @@ struct dvb_frontend *vp310_mt312_attach( state->xtal = MT312_PLL_CLK; state->freq_mult = 6; break; + case ID_ZL10313: + strcpy(state->frontend.ops.info.name, "Zarlink ZL10313 DVB-S"); + state->xtal = MT312_PLL_CLK_10_111; + state->freq_mult = 9; + break; default: - printk(KERN_WARNING "Only Zarlink VP310/MT312" + printk(KERN_WARNING "Only Zarlink VP310/MT312/ZL10313" " are supported chips.\n"); goto error; } @@ -750,7 +838,7 @@ EXPORT_SYMBOL(vp310_mt312_attach); module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); -MODULE_DESCRIPTION("Zarlink VP310/MT312 DVB-S Demodulator driver"); +MODULE_DESCRIPTION("Zarlink VP310/MT312/ZL10313 DVB-S Demodulator driver"); MODULE_AUTHOR("Andreas Oberritter <obi@xxxxxxxxxxx>"); MODULE_LICENSE("GPL"); Index: v4l-dvb/linux/drivers/media/dvb/frontends/mt312_priv.h =================================================================== --- v4l-dvb.orig/linux/drivers/media/dvb/frontends/mt312_priv.h +++ v4l-dvb/linux/drivers/media/dvb/frontends/mt312_priv.h @@ -110,6 +110,8 @@ enum mt312_reg_addr { VIT_ERRPER_H = 83, VIT_ERRPER_M = 84, VIT_ERRPER_L = 85, + HW_CTRL = 84, /* ZL10313 only */ + MPEG_CTRL = 85, /* ZL10313 only */ VIT_SETUP = 86, VIT_REF0 = 87, VIT_REF1 = 88, @@ -156,7 +158,8 @@ enum mt312_reg_addr { enum mt312_model_id { ID_VP310 = 1, - ID_MT312 = 3 + ID_MT312 = 3, + ID_ZL10313 = 5, }; #endif /* DVB_FRONTENDS_MT312_PRIV */
Index: v4l-dvb/linux/drivers/media/dvb/frontends/mt312.c =================================================================== --- v4l-dvb.orig/linux/drivers/media/dvb/frontends/mt312.c +++ v4l-dvb/linux/drivers/media/dvb/frontends/mt312.c @@ -43,7 +43,8 @@ struct mt312_state { struct dvb_frontend frontend; u8 id; - u8 frequency; + unsigned long xtal; + u8 freq_mult; }; static int debug; @@ -53,8 +54,6 @@ static int debug; printk(KERN_DEBUG "mt312: " args); \ } while (0) -#define MT312_SYS_CLK 90000000UL /* 90 MHz */ -#define MT312_LPOWER_SYS_CLK 60000000UL /* 60 MHz */ #define MT312_PLL_CLK 10000000UL /* 10 MHz */ static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg, @@ -209,7 +208,7 @@ static int mt312_get_symbol_rate(struct dprintk("sym_rat_op=%d dec_ratio=%d\n", sym_rat_op, dec_ratio); dprintk("*sr(manual) = %lu\n", - (((MT312_PLL_CLK * 8192) / (sym_rat_op + 8192)) * + (((state->xtal * 8192) / (sym_rat_op + 8192)) * 2) - dec_ratio); } @@ -242,7 +241,7 @@ static int mt312_initfe(struct dvb_front /* wake up */ ret = mt312_writereg(state, CONFIG, - (state->frequency == 60 ? 0x88 : 0x8c)); + (state->freq_mult == 6 ? 0x88 : 0x8c)); if (ret < 0) return ret; @@ -266,11 +265,10 @@ static int mt312_initfe(struct dvb_front } /* SYS_CLK */ - buf[0] = mt312_div((state->frequency == 60 ? MT312_LPOWER_SYS_CLK : - MT312_SYS_CLK) * 2, 1000000); + buf[0] = mt312_div(state->xtal * state->freq_mult * 2, 1000000); /* DISEQC_RATIO */ - buf[1] = mt312_div(MT312_PLL_CLK, 22000 * 4); + buf[1] = mt312_div(state->xtal, 22000 * 4); ret = mt312_write(state, SYS_CLK, buf, sizeof(buf)); if (ret < 0) @@ -532,17 +530,17 @@ static int mt312_set_frontend(struct dvb return ret; if (p->u.qpsk.symbol_rate >= 30000000) { /* Note that 30MS/s should use 90MHz */ - if ((config_val & 0x0c) == 0x08) { + if (state->freq_mult == 6) { /* We are running 60MHz */ - state->frequency = 90; + state->freq_mult = 9; ret = mt312_initfe(fe); if (ret < 0) return ret; } } else { - if ((config_val & 0x0c) == 0x0C) { + if (state->freq_mult == 9) { /* We are running 90MHz */ - state->frequency = 60; + state->freq_mult = 6; ret = mt312_initfe(fe); if (ret < 0) return ret; @@ -661,6 +659,7 @@ static void mt312_release(struct dvb_fro kfree(state); } +#define MT312_SYS_CLK 90000000UL /* 90 MHz */ static struct dvb_frontend_ops vp310_mt312_ops = { .info = { @@ -668,8 +667,8 @@ static struct dvb_frontend_ops vp310_mt3 .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, - .frequency_stepsize = (MT312_PLL_CLK / 1000) / 128, - .symbol_rate_min = MT312_SYS_CLK / 128, + .frequency_stepsize = (MT312_PLL_CLK / 1000) / 128, /* FIXME: adjust freq to real used xtal */ + .symbol_rate_min = MT312_SYS_CLK / 128, /* FIXME as above */ .symbol_rate_max = MT312_SYS_CLK / 2, .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | @@ -726,11 +725,13 @@ struct dvb_frontend *vp310_mt312_attach( switch (state->id) { case ID_VP310: strcpy(state->frontend.ops.info.name, "Zarlink VP310 DVB-S"); - state->frequency = 90; + state->xtal = MT312_PLL_CLK; + state->freq_mult = 9; break; case ID_MT312: strcpy(state->frontend.ops.info.name, "Zarlink MT312 DVB-S"); - state->frequency = 60; + state->xtal = MT312_PLL_CLK; + state->freq_mult = 6; break; default: printk(KERN_WARNING "Only Zarlink VP310/MT312"
Corrects the frequency of the emitted diseqc signal to 22kHz. Signed-off-by: Matthias Schwarzott <zzam@xxxxxxxxxx> Index: v4l-dvb/linux/drivers/media/dvb/frontends/mt312.c =================================================================== --- v4l-dvb.orig/linux/drivers/media/dvb/frontends/mt312.c +++ v4l-dvb/linux/drivers/media/dvb/frontends/mt312.c @@ -270,7 +270,7 @@ static int mt312_initfe(struct dvb_front MT312_SYS_CLK) * 2, 1000000); /* DISEQC_RATIO */ - buf[1] = mt312_div(MT312_PLL_CLK, 15000 * 4); + buf[1] = mt312_div(MT312_PLL_CLK, 22000 * 4); ret = mt312_write(state, SYS_CLK, buf, sizeof(buf)); if (ret < 0)
Index: v4l-dvb/linux/drivers/media/dvb/frontends/mt312.c =================================================================== --- v4l-dvb.orig/linux/drivers/media/dvb/frontends/mt312.c +++ v4l-dvb/linux/drivers/media/dvb/frontends/mt312.c @@ -58,7 +58,7 @@ static int debug; #define MT312_PLL_CLK 10000000UL /* 10 MHz */ static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg, - void *buf, const size_t count) + u8 *buf, const size_t count) { int ret; struct i2c_msg msg[2]; @@ -84,7 +84,7 @@ static int mt312_read(struct mt312_state int i; dprintk("R(%d):", reg & 0x7f); for (i = 0; i < count; i++) - printk(" %02x", ((const u8 *) buf)[i]); + printk(" %02x", buf[i]); printk("\n"); } @@ -92,7 +92,7 @@ static int mt312_read(struct mt312_state } static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg, - const void *src, const size_t count) + const u8 *src, const size_t count) { int ret; u8 buf[count + 1]; @@ -102,7 +102,7 @@ static int mt312_write(struct mt312_stat int i; dprintk("W(%d):", reg & 0x7f); for (i = 0; i < count; i++) - printk(" %02x", ((const u8 *) src)[i]); + printk(" %02x", src[i]); printk("\n"); } @@ -463,7 +463,7 @@ static int mt312_read_snr(struct dvb_fro int ret; u8 buf[2]; - ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf)); + ret = mt312_read(state, M_SNR_H, buf, sizeof(buf)); if (ret < 0) return ret; @@ -478,7 +478,7 @@ static int mt312_read_ucblocks(struct dv int ret; u8 buf[2]; - ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf)); + ret = mt312_read(state, RS_UBC_H, buf, sizeof(buf)); if (ret < 0) return ret;
_______________________________________________ linux-dvb mailing list linux-dvb@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb