diff options
-rw-r--r-- | drivers/media/dvb/dvb-usb/dibusb-common.c | 87 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/dibusb.h | 1 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/mt2060.c | 190 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/mt2060.h | 15 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/mt2060_priv.h | 10 |
5 files changed, 140 insertions, 163 deletions
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c index a32ff63d170b..78a604dfadfc 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-common.c +++ b/drivers/media/dvb/dvb-usb/dibusb-common.c | |||
@@ -168,40 +168,6 @@ int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val) | |||
168 | } | 168 | } |
169 | EXPORT_SYMBOL(dibusb_read_eeprom_byte); | 169 | EXPORT_SYMBOL(dibusb_read_eeprom_byte); |
170 | 170 | ||
171 | static struct mt2060_config stk3000p_mt2060_config = { | ||
172 | .i2c_address = 0x60, | ||
173 | }; | ||
174 | |||
175 | static int dibusb_tuner_init(struct dvb_frontend *fe) | ||
176 | { | ||
177 | struct dvb_usb_device *d = fe->dvb->priv; | ||
178 | struct dibusb_state *st = d->priv; | ||
179 | |||
180 | if (d->tuner_pass_ctrl && st->mt2060_present) { | ||
181 | int ret; | ||
182 | d->tuner_pass_ctrl(d->fe, 1, stk3000p_mt2060_config.i2c_address); | ||
183 | ret = mt2060_init(&st->mt2060); | ||
184 | d->tuner_pass_ctrl(d->fe, 0, 0); | ||
185 | return ret; | ||
186 | } | ||
187 | return dvb_usb_pll_init_i2c(fe); | ||
188 | } | ||
189 | |||
190 | static int dibusb_tuner_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) | ||
191 | { | ||
192 | struct dvb_usb_device *d = fe->dvb->priv; | ||
193 | struct dibusb_state *st = d->priv; | ||
194 | |||
195 | if (d->tuner_pass_ctrl && st->mt2060_present) { | ||
196 | int ret; | ||
197 | d->tuner_pass_ctrl(d->fe, 1, stk3000p_mt2060_config.i2c_address); | ||
198 | ret = mt2060_set(&st->mt2060,fep); | ||
199 | d->tuner_pass_ctrl(d->fe,0,0); | ||
200 | return ret; | ||
201 | } | ||
202 | return dvb_usb_pll_set_i2c(fe,fep); | ||
203 | } | ||
204 | |||
205 | static const struct dib3000p_agc_config dib3000p_agc_panasonic_env57h1xd5 = { | 171 | static const struct dib3000p_agc_config dib3000p_agc_panasonic_env57h1xd5 = { |
206 | { 0x51, 0x301d, 0x0, 0x1cc7, 0xdc29, 0x570a, | 172 | { 0x51, 0x301d, 0x0, 0x1cc7, 0xdc29, 0x570a, |
207 | 0xbae1, 0x8ccd, 0x3b6d, 0x551d, 0xa, 0x951e } | 173 | 0xbae1, 0x8ccd, 0x3b6d, 0x551d, 0xa, 0x951e } |
@@ -212,64 +178,21 @@ static const struct dib3000p_agc_config dib3000p_agc_microtune_mt2060 = { | |||
212 | 0xa8f6, 0x5eb8, 0x65ff, 0x40ff, 0x8a, 0x1114 } | 178 | 0xa8f6, 0x5eb8, 0x65ff, 0x40ff, 0x8a, 0x1114 } |
213 | }; | 179 | }; |
214 | 180 | ||
181 | static struct mt2060_config stk3000p_mt2060_config = { | ||
182 | .i2c_address = 0x60, | ||
183 | }; | ||
184 | |||
215 | int dibusb_dib3000mc_frontend_attach(struct dvb_usb_device *d) | 185 | int dibusb_dib3000mc_frontend_attach(struct dvb_usb_device *d) |
216 | { | 186 | { |
217 | struct dib3000_config demod_cfg; | 187 | struct dib3000_config demod_cfg; |
218 | struct dibusb_state *st = d->priv; | 188 | struct dibusb_state *st = d->priv; |
219 | |||
220 | demod_cfg.agc = &dib3000p_agc_panasonic_env57h1xd5; | ||
221 | demod_cfg.pll_set = dibusb_tuner_set; | ||
222 | demod_cfg.pll_init = dibusb_tuner_init; | ||
223 | |||
224 | for (demod_cfg.demod_address = 0x8; demod_cfg.demod_address < 0xd; demod_cfg.demod_address++) | ||
225 | if ((d->fe = dib3000mc_attach(&demod_cfg,&d->i2c_adap,&st->ops)) != NULL) { | ||
226 | d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl; | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | return -ENODEV; | 189 | return -ENODEV; |
231 | } | 190 | } |
232 | EXPORT_SYMBOL(dibusb_dib3000mc_frontend_attach); | 191 | EXPORT_SYMBOL(dibusb_dib3000mc_frontend_attach); |
233 | 192 | ||
234 | int dibusb_dib3000mc_tuner_attach (struct dvb_usb_device *d) | 193 | int dibusb_dib3000mc_tuner_attach (struct dvb_usb_device *d) |
235 | { | 194 | { |
236 | int ret; | 195 | return -ENODEV; |
237 | u8 a,b; | ||
238 | u16 if1 = 1220; | ||
239 | |||
240 | if (d->tuner_pass_ctrl) { | ||
241 | struct dibusb_state *st = d->priv; | ||
242 | d->tuner_pass_ctrl(d->fe, 1, stk3000p_mt2060_config.i2c_address); | ||
243 | // First IF calibration for Liteon Sticks | ||
244 | if (d->udev->descriptor.idVendor == USB_VID_LITEON && | ||
245 | d->udev->descriptor.idProduct == USB_PID_LITEON_DVB_T_WARM) { | ||
246 | |||
247 | dibusb_read_eeprom_byte(d,0x7E,&a); | ||
248 | dibusb_read_eeprom_byte(d,0x7F,&b); | ||
249 | |||
250 | if (a == 0xFF && b == 0xFF) | ||
251 | if1 = 1220; | ||
252 | else if (a == 0x00) | ||
253 | if1 = 1220+b; | ||
254 | else if (a == 0x80) | ||
255 | if1 = 1220-b; | ||
256 | else { | ||
257 | warn("LITE-ON DVB-T Tuner : Strange IF1 calibration :%2X %2X\n",(int)a,(int)b); | ||
258 | if1 = 1220; | ||
259 | } | ||
260 | } | ||
261 | if ((ret = mt2060_attach(&st->mt2060,&stk3000p_mt2060_config, &d->i2c_adap,if1)) != 0) { | ||
262 | /* not found - use panasonic pll parameters */ | ||
263 | d->pll_addr = 0x60; | ||
264 | d->pll_desc = &dvb_pll_env57h1xd5; | ||
265 | } else { | ||
266 | st->mt2060_present = 1; | ||
267 | /* set the correct agc parameters for the dib3000p */ | ||
268 | dib3000mc_set_agc_config(d->fe, &dib3000p_agc_microtune_mt2060); | ||
269 | } | ||
270 | d->tuner_pass_ctrl(d->fe,0,0); | ||
271 | } | ||
272 | return 0; | ||
273 | } | 196 | } |
274 | EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach); | 197 | EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach); |
275 | 198 | ||
diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h index 7fd57d053b9f..e21de8b668f6 100644 --- a/drivers/media/dvb/dvb-usb/dibusb.h +++ b/drivers/media/dvb/dvb-usb/dibusb.h | |||
@@ -97,7 +97,6 @@ | |||
97 | 97 | ||
98 | struct dibusb_state { | 98 | struct dibusb_state { |
99 | struct dib_fe_xfer_ops ops; | 99 | struct dib_fe_xfer_ops ops; |
100 | struct mt2060_state mt2060; | ||
101 | int mt2060_present; | 100 | int mt2060_present; |
102 | 101 | ||
103 | /* for RC5 remote control */ | 102 | /* for RC5 remote control */ |
diff --git a/drivers/media/dvb/frontends/mt2060.c b/drivers/media/dvb/frontends/mt2060.c index 14b4f588eeb7..cc38e7077a0b 100644 --- a/drivers/media/dvb/frontends/mt2060.c +++ b/drivers/media/dvb/frontends/mt2060.c | |||
@@ -19,14 +19,16 @@ | |||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= | 19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= |
20 | */ | 20 | */ |
21 | 21 | ||
22 | /* See mt2060_priv.h for details */ | ||
23 | |||
24 | /* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ | 22 | /* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ |
25 | 23 | ||
26 | #include <linux/module.h> | 24 | #include <linux/module.h> |
27 | #include <linux/moduleparam.h> | 25 | #include <linux/moduleparam.h> |
28 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
29 | #include <linux/dvb/frontend.h> | 27 | #include <linux/dvb/frontend.h> |
28 | #include <linux/i2c.h> | ||
29 | |||
30 | #include "dvb_frontend.h" | ||
31 | |||
30 | #include "mt2060.h" | 32 | #include "mt2060.h" |
31 | #include "mt2060_priv.h" | 33 | #include "mt2060_priv.h" |
32 | 34 | ||
@@ -34,17 +36,17 @@ static int debug=0; | |||
34 | module_param(debug, int, 0644); | 36 | module_param(debug, int, 0644); |
35 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | 37 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); |
36 | 38 | ||
37 | #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "MT2060: " args); printk("\n"); } } while (0) | 39 | #define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2060: " args); printk("\n"); }} while (0) |
38 | 40 | ||
39 | // Reads a single register | 41 | // Reads a single register |
40 | static int mt2060_readreg(struct mt2060_state *state, u8 reg, u8 *val) | 42 | static int mt2060_readreg(struct mt2060_priv *priv, u8 reg, u8 *val) |
41 | { | 43 | { |
42 | struct i2c_msg msg[2] = { | 44 | struct i2c_msg msg[2] = { |
43 | { .addr = state->config->i2c_address, .flags = 0, .buf = ®, .len = 1 }, | 45 | { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, |
44 | { .addr = state->config->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, | 46 | { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, |
45 | }; | 47 | }; |
46 | 48 | ||
47 | if (i2c_transfer(state->i2c, msg, 2) != 2) { | 49 | if (i2c_transfer(priv->i2c, msg, 2) != 2) { |
48 | printk(KERN_WARNING "mt2060 I2C read failed\n"); | 50 | printk(KERN_WARNING "mt2060 I2C read failed\n"); |
49 | return -EREMOTEIO; | 51 | return -EREMOTEIO; |
50 | } | 52 | } |
@@ -52,16 +54,14 @@ static int mt2060_readreg(struct mt2060_state *state, u8 reg, u8 *val) | |||
52 | } | 54 | } |
53 | 55 | ||
54 | // Writes a single register | 56 | // Writes a single register |
55 | static int mt2060_writereg(struct mt2060_state *state, u8 reg, u8 val) | 57 | static int mt2060_writereg(struct mt2060_priv *priv, u8 reg, u8 val) |
56 | { | 58 | { |
57 | u8 buf[2]; | 59 | u8 buf[2] = { reg, val }; |
58 | struct i2c_msg msg = { | 60 | struct i2c_msg msg = { |
59 | .addr = state->config->i2c_address, .flags = 0, .buf = buf, .len = 2 | 61 | .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 |
60 | }; | 62 | }; |
61 | buf[0]=reg; | ||
62 | buf[1]=val; | ||
63 | 63 | ||
64 | if (i2c_transfer(state->i2c, &msg, 1) != 1) { | 64 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { |
65 | printk(KERN_WARNING "mt2060 I2C write failed\n"); | 65 | printk(KERN_WARNING "mt2060 I2C write failed\n"); |
66 | return -EREMOTEIO; | 66 | return -EREMOTEIO; |
67 | } | 67 | } |
@@ -69,12 +69,12 @@ static int mt2060_writereg(struct mt2060_state *state, u8 reg, u8 val) | |||
69 | } | 69 | } |
70 | 70 | ||
71 | // Writes a set of consecutive registers | 71 | // Writes a set of consecutive registers |
72 | static int mt2060_writeregs(struct mt2060_state *state,u8 *buf, u8 len) | 72 | static int mt2060_writeregs(struct mt2060_priv *priv,u8 *buf, u8 len) |
73 | { | 73 | { |
74 | struct i2c_msg msg = { | 74 | struct i2c_msg msg = { |
75 | .addr = state->config->i2c_address, .flags = 0, .buf = buf, .len = len | 75 | .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len |
76 | }; | 76 | }; |
77 | if (i2c_transfer(state->i2c, &msg, 1) != 1) { | 77 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { |
78 | printk(KERN_WARNING "mt2060 I2C write failed (len=%i)\n",(int)len); | 78 | printk(KERN_WARNING "mt2060 I2C write failed (len=%i)\n",(int)len); |
79 | return -EREMOTEIO; | 79 | return -EREMOTEIO; |
80 | } | 80 | } |
@@ -95,20 +95,6 @@ static u8 mt2060_config2[] = { | |||
95 | }; | 95 | }; |
96 | 96 | ||
97 | // VGAG=3, V1CSE=1 | 97 | // VGAG=3, V1CSE=1 |
98 | static u8 mt2060_config3[] = { | ||
99 | REG_VGAG, | ||
100 | 0x33 | ||
101 | }; | ||
102 | |||
103 | int mt2060_init(struct mt2060_state *state) | ||
104 | { | ||
105 | if (mt2060_writeregs(state,mt2060_config1,sizeof(mt2060_config1))) | ||
106 | return -EREMOTEIO; | ||
107 | if (mt2060_writeregs(state,mt2060_config3,sizeof(mt2060_config3))) | ||
108 | return -EREMOTEIO; | ||
109 | return 0; | ||
110 | } | ||
111 | EXPORT_SYMBOL(mt2060_init); | ||
112 | 98 | ||
113 | #ifdef MT2060_SPURCHECK | 99 | #ifdef MT2060_SPURCHECK |
114 | /* The function below calculates the frequency offset between the output frequency if2 | 100 | /* The function below calculates the frequency offset between the output frequency if2 |
@@ -167,8 +153,9 @@ static int mt2060_spurcheck(u32 lo1,u32 lo2,u32 if2) | |||
167 | #define IF2 36150 // IF2 frequency = 36.150 MHz | 153 | #define IF2 36150 // IF2 frequency = 36.150 MHz |
168 | #define FREF 16000 // Quartz oscillator 16 MHz | 154 | #define FREF 16000 // Quartz oscillator 16 MHz |
169 | 155 | ||
170 | int mt2060_set(struct mt2060_state *state, struct dvb_frontend_parameters *fep) | 156 | static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) |
171 | { | 157 | { |
158 | struct mt2060_priv *priv; | ||
172 | int ret=0; | 159 | int ret=0; |
173 | int i=0; | 160 | int i=0; |
174 | u32 freq; | 161 | u32 freq; |
@@ -178,17 +165,23 @@ int mt2060_set(struct mt2060_state *state, struct dvb_frontend_parameters *fep) | |||
178 | u8 b[8]; | 165 | u8 b[8]; |
179 | u32 if1; | 166 | u32 if1; |
180 | 167 | ||
181 | if1 = state->if1_freq; | 168 | priv = fe->tuner_priv; |
169 | |||
170 | if1 = priv->if1_freq; | ||
182 | b[0] = REG_LO1B1; | 171 | b[0] = REG_LO1B1; |
183 | b[1] = 0xFF; | 172 | b[1] = 0xFF; |
184 | mt2060_writeregs(state,b,2); | ||
185 | 173 | ||
186 | freq = fep->frequency / 1000; // Hz -> kHz | 174 | mt2060_writeregs(priv,b,2); |
187 | 175 | ||
188 | f_lo1 = freq + if1 * 1000; | 176 | freq = params->frequency / 1000; // Hz -> kHz |
189 | f_lo1 = (f_lo1/250)*250; | 177 | priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; |
190 | f_lo2 = f_lo1 - freq - IF2; | 178 | |
191 | f_lo2 = (f_lo2/50)*50; | 179 | f_lo1 = freq + if1 * 1000; |
180 | f_lo1 = (f_lo1 / 250) * 250; | ||
181 | f_lo2 = f_lo1 - freq - IF2; | ||
182 | // From the Comtech datasheet, the step used is 50kHz. The tuner chip could be more precise | ||
183 | f_lo2 = ((f_lo2 + 25) / 50) * 50; | ||
184 | priv->frequency = (f_lo1 - f_lo2 - IF2) * 1000, | ||
192 | 185 | ||
193 | #ifdef MT2060_SPURCHECK | 186 | #ifdef MT2060_SPURCHECK |
194 | // LO-related spurs detection and correction | 187 | // LO-related spurs detection and correction |
@@ -197,12 +190,14 @@ int mt2060_set(struct mt2060_state *state, struct dvb_frontend_parameters *fep) | |||
197 | f_lo2 += num1; | 190 | f_lo2 += num1; |
198 | #endif | 191 | #endif |
199 | //Frequency LO1 = 16MHz * (DIV1 + NUM1/64 ) | 192 | //Frequency LO1 = 16MHz * (DIV1 + NUM1/64 ) |
200 | div1 = f_lo1 / FREF; | 193 | num1 = f_lo1 / (FREF / 64); |
201 | num1 = (64 * (f_lo1 % FREF) )/FREF; | 194 | div1 = num1 / 64; |
195 | num1 &= 0x3f; | ||
202 | 196 | ||
203 | // Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) | 197 | // Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) |
204 | div2 = f_lo2 / FREF; | 198 | num2 = f_lo2 * 64 / (FREF / 128); |
205 | num2 = (16384 * (f_lo2 % FREF) /FREF +1)/2; | 199 | div2 = num2 / 8192; |
200 | num2 &= 0x1fff; | ||
206 | 201 | ||
207 | if (freq <= 95000) lnaband = 0xB0; else | 202 | if (freq <= 95000) lnaband = 0xB0; else |
208 | if (freq <= 180000) lnaband = 0xA0; else | 203 | if (freq <= 180000) lnaband = 0xA0; else |
@@ -223,85 +218,144 @@ int mt2060_set(struct mt2060_state *state, struct dvb_frontend_parameters *fep) | |||
223 | b[5] = ((num2 >>12) & 1) | (div2 << 1); | 218 | b[5] = ((num2 >>12) & 1) | (div2 << 1); |
224 | 219 | ||
225 | dprintk("IF1: %dMHz",(int)if1); | 220 | dprintk("IF1: %dMHz",(int)if1); |
226 | dprintk("PLL freq: %d f_lo1: %d f_lo2: %d (kHz)",(int)freq,(int)f_lo1,(int)f_lo2); | 221 | dprintk("PLL freq=%dkHz f_lo1=%dkHz f_lo2=%dkHz",(int)freq,(int)f_lo1,(int)f_lo2); |
227 | dprintk("PLL div1: %d num1: %d div2: %d num2: %d",(int)div1,(int)num1,(int)div2,(int)num2); | 222 | dprintk("PLL div1=%d num1=%d div2=%d num2=%d",(int)div1,(int)num1,(int)div2,(int)num2); |
228 | dprintk("PLL [1..5]: %2x %2x %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3],(int)b[4],(int)b[5]); | 223 | dprintk("PLL [1..5]: %2x %2x %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3],(int)b[4],(int)b[5]); |
229 | 224 | ||
230 | mt2060_writeregs(state,b,6); | 225 | mt2060_writeregs(priv,b,6); |
231 | 226 | ||
232 | //Waits for pll lock or timeout | 227 | //Waits for pll lock or timeout |
233 | i=0; | 228 | i = 0; |
234 | do { | 229 | do { |
235 | mt2060_readreg(state,REG_LO_STATUS,b); | 230 | mt2060_readreg(priv,REG_LO_STATUS,b); |
236 | if ((b[0] & 0x88)==0x88) break; | 231 | if ((b[0] & 0x88)==0x88) |
232 | break; | ||
237 | msleep(4); | 233 | msleep(4); |
238 | i++; | 234 | i++; |
239 | } while (i<10); | 235 | } while (i<10); |
240 | 236 | ||
241 | return ret; | 237 | return ret; |
242 | } | 238 | } |
243 | EXPORT_SYMBOL(mt2060_set); | ||
244 | 239 | ||
245 | /* from usbsnoop.log */ | 240 | static void mt2060_calibrate(struct mt2060_priv *priv) |
246 | static void mt2060_calibrate(struct mt2060_state *state) | ||
247 | { | 241 | { |
248 | u8 b = 0; | 242 | u8 b = 0; |
249 | int i = 0; | 243 | int i = 0; |
250 | 244 | ||
251 | if (mt2060_writeregs(state,mt2060_config1,sizeof(mt2060_config1))) | 245 | if (mt2060_writeregs(priv,mt2060_config1,sizeof(mt2060_config1))) |
252 | return; | 246 | return; |
253 | if (mt2060_writeregs(state,mt2060_config2,sizeof(mt2060_config2))) | 247 | if (mt2060_writeregs(priv,mt2060_config2,sizeof(mt2060_config2))) |
254 | return; | 248 | return; |
255 | 249 | ||
256 | do { | 250 | do { |
257 | b |= (1 << 6); // FM1SS; | 251 | b |= (1 << 6); // FM1SS; |
258 | mt2060_writereg(state, REG_LO2C1,b); | 252 | mt2060_writereg(priv, REG_LO2C1,b); |
259 | msleep(20); | 253 | msleep(20); |
260 | 254 | ||
261 | if (i == 0) { | 255 | if (i == 0) { |
262 | b |= (1 << 7); // FM1CA; | 256 | b |= (1 << 7); // FM1CA; |
263 | mt2060_writereg(state, REG_LO2C1,b); | 257 | mt2060_writereg(priv, REG_LO2C1,b); |
264 | b &= ~(1 << 7); // FM1CA; | 258 | b &= ~(1 << 7); // FM1CA; |
265 | msleep(20); | 259 | msleep(20); |
266 | } | 260 | } |
267 | 261 | ||
268 | b &= ~(1 << 6); // FM1SS | 262 | b &= ~(1 << 6); // FM1SS |
269 | mt2060_writereg(state, REG_LO2C1,b); | 263 | mt2060_writereg(priv, REG_LO2C1,b); |
270 | 264 | ||
271 | msleep(20); | 265 | msleep(20); |
272 | i++; | 266 | i++; |
273 | } while (i < 9); | 267 | } while (i < 9); |
274 | 268 | ||
275 | i = 0; | 269 | i = 0; |
276 | while (i++ < 10 && mt2060_readreg(state, REG_MISC_STAT, &b) == 0 && (b & (1 << 6)) == 0) | 270 | while (i++ < 10 && mt2060_readreg(priv, REG_MISC_STAT, &b) == 0 && (b & (1 << 6)) == 0) |
277 | msleep(20); | 271 | msleep(20); |
278 | 272 | ||
279 | if (i < 10) { | 273 | if (i < 10) { |
280 | mt2060_readreg(state, REG_FM_FREQ, &state->fmfreq); // now find out, what is fmreq used for :) | 274 | mt2060_readreg(priv, REG_FM_FREQ, &priv->fmfreq); // now find out, what is fmreq used for :) |
281 | dprintk("calibration was successful: %d", state->fmfreq); | 275 | dprintk("calibration was successful: %d", (int)priv->fmfreq); |
282 | } else | 276 | } else |
283 | dprintk("FMCAL timed out"); | 277 | dprintk("FMCAL timed out"); |
284 | } | 278 | } |
285 | 279 | ||
280 | static int mt2060_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8 *buf, int buf_len) | ||
281 | { | ||
282 | return -ENODEV; | ||
283 | } | ||
284 | |||
285 | static int mt2060_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
286 | { | ||
287 | struct mt2060_priv *priv = fe->tuner_priv; | ||
288 | *frequency = priv->frequency; | ||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static int mt2060_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | ||
293 | { | ||
294 | struct mt2060_priv *priv = fe->tuner_priv; | ||
295 | *bandwidth = priv->bandwidth; | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static int mt2060_sleep(struct dvb_frontend *fe) | ||
300 | { | ||
301 | struct mt2060_priv *priv = fe->tuner_priv; | ||
302 | return mt2060_writereg(priv, REG_VGAG,0x30); | ||
303 | } | ||
304 | |||
305 | static int mt2060_release(struct dvb_frontend *fe) | ||
306 | { | ||
307 | kfree(fe->tuner_priv); | ||
308 | fe->tuner_priv = NULL; | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static const struct dvb_tuner_ops mt2060_tuner_ops = { | ||
313 | .info = { | ||
314 | .name = "Microtune MT2060", | ||
315 | .frequency_min = 48000000, | ||
316 | .frequency_max = 860000000, | ||
317 | .frequency_step = 50000, | ||
318 | }, | ||
319 | |||
320 | .release = mt2060_release, | ||
321 | |||
322 | .sleep = mt2060_sleep, | ||
323 | |||
324 | .set_params = mt2060_set_params, | ||
325 | .calc_regs = mt2060_calc_regs, | ||
326 | .get_frequency = mt2060_get_frequency, | ||
327 | .get_bandwidth = mt2060_get_bandwidth | ||
328 | }; | ||
329 | |||
286 | /* This functions tries to identify a MT2060 tuner by reading the PART/REV register. This is hasty. */ | 330 | /* This functions tries to identify a MT2060 tuner by reading the PART/REV register. This is hasty. */ |
287 | int mt2060_attach(struct mt2060_state *state, struct mt2060_config *config, struct i2c_adapter *i2c,u16 if1) | 331 | int mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1) |
288 | { | 332 | { |
333 | struct mt2060_priv *priv = NULL; | ||
289 | u8 id = 0; | 334 | u8 id = 0; |
290 | memset(state,0,sizeof(struct mt2060_state)); | ||
291 | 335 | ||
292 | state->config = config; | 336 | priv = kzalloc(sizeof(struct mt2060_priv), GFP_KERNEL); |
293 | state->i2c = i2c; | 337 | if (priv == NULL) |
294 | state->if1_freq = if1; | 338 | return -ENOMEM; |
295 | 339 | ||
296 | if (mt2060_readreg(state,REG_PART_REV,&id) != 0) | 340 | priv->cfg = cfg; |
297 | return -ENODEV; | 341 | priv->i2c = i2c; |
342 | priv->if1_freq = if1; | ||
298 | 343 | ||
299 | if (id != PART_REV) | 344 | if (mt2060_readreg(priv,REG_PART_REV,&id) != 0) { |
345 | kfree(priv); | ||
300 | return -ENODEV; | 346 | return -ENODEV; |
347 | } | ||
301 | 348 | ||
349 | if (id != PART_REV) { | ||
350 | kfree(priv); | ||
351 | return -ENODEV; | ||
352 | } | ||
302 | printk(KERN_INFO "MT2060: successfully identified\n"); | 353 | printk(KERN_INFO "MT2060: successfully identified\n"); |
354 | memcpy(&fe->ops.tuner_ops, &mt2060_tuner_ops, sizeof(struct dvb_tuner_ops)); | ||
355 | |||
356 | fe->tuner_priv = priv; | ||
303 | 357 | ||
304 | mt2060_calibrate(state); | 358 | mt2060_calibrate(priv); |
305 | 359 | ||
306 | return 0; | 360 | return 0; |
307 | } | 361 | } |
diff --git a/drivers/media/dvb/frontends/mt2060.h b/drivers/media/dvb/frontends/mt2060.h index d5dae102f96f..c58b03e82345 100644 --- a/drivers/media/dvb/frontends/mt2060.h +++ b/drivers/media/dvb/frontends/mt2060.h | |||
@@ -22,23 +22,14 @@ | |||
22 | #ifndef MT2060_H | 22 | #ifndef MT2060_H |
23 | #define MT2060_H | 23 | #define MT2060_H |
24 | 24 | ||
25 | #include <linux/i2c.h> | 25 | struct dvb_frontend; |
26 | #include <linux/dvb/frontend.h> | 26 | struct i2c_adapter; |
27 | 27 | ||
28 | struct mt2060_config { | 28 | struct mt2060_config { |
29 | u8 i2c_address; | 29 | u8 i2c_address; |
30 | /* Shall we add settings for the discrete outputs ? */ | 30 | /* Shall we add settings for the discrete outputs ? */ |
31 | }; | 31 | }; |
32 | 32 | ||
33 | struct mt2060_state { | 33 | extern int mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1); |
34 | struct mt2060_config *config; | ||
35 | struct i2c_adapter *i2c; | ||
36 | u16 if1_freq; | ||
37 | u8 fmfreq; | ||
38 | }; | ||
39 | |||
40 | extern int mt2060_init(struct mt2060_state *state); | ||
41 | extern int mt2060_set(struct mt2060_state *state, struct dvb_frontend_parameters *fep); | ||
42 | extern int mt2060_attach(struct mt2060_state *state, struct mt2060_config *config, struct i2c_adapter *i2c,u16 if1); | ||
43 | 34 | ||
44 | #endif | 35 | #endif |
diff --git a/drivers/media/dvb/frontends/mt2060_priv.h b/drivers/media/dvb/frontends/mt2060_priv.h index 47e691e44b7b..5eaccdefd0b0 100644 --- a/drivers/media/dvb/frontends/mt2060_priv.h +++ b/drivers/media/dvb/frontends/mt2060_priv.h | |||
@@ -92,4 +92,14 @@ | |||
92 | 92 | ||
93 | #define PART_REV 0x63 // The current driver works only with PART=6 and REV=3 chips | 93 | #define PART_REV 0x63 // The current driver works only with PART=6 and REV=3 chips |
94 | 94 | ||
95 | struct mt2060_priv { | ||
96 | struct mt2060_config *cfg; | ||
97 | struct i2c_adapter *i2c; | ||
98 | |||
99 | u32 frequency; | ||
100 | u32 bandwidth; | ||
101 | u16 if1_freq; | ||
102 | u8 fmfreq; | ||
103 | }; | ||
104 | |||
95 | #endif | 105 | #endif |