Commit | Line | Data |
---|---|---|
c942fddf | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
395d00d1 | 2 | /* |
7978b8a1 | 3 | * Montage Technology M88DS3103/M88RS6000 demodulator driver |
395d00d1 AP |
4 | * |
5 | * Copyright (C) 2013 Antti Palosaari <crope@iki.fi> | |
395d00d1 AP |
6 | */ |
7 | ||
8 | #include "m88ds3103_priv.h" | |
9 | ||
bd336e63 | 10 | static const struct dvb_frontend_ops m88ds3103_ops; |
395d00d1 | 11 | |
56ea37da AP |
12 | /* write single register with mask */ |
13 | static int m88ds3103_update_bits(struct m88ds3103_dev *dev, | |
14 | u8 reg, u8 mask, u8 val) | |
15 | { | |
16 | int ret; | |
17 | u8 tmp; | |
18 | ||
19 | /* no need for read if whole reg is written */ | |
20 | if (mask != 0xff) { | |
21 | ret = regmap_bulk_read(dev->regmap, reg, &tmp, 1); | |
22 | if (ret) | |
23 | return ret; | |
24 | ||
25 | val &= mask; | |
26 | tmp &= ~mask; | |
27 | val |= tmp; | |
28 | } | |
29 | ||
30 | return regmap_bulk_write(dev->regmap, reg, &val, 1); | |
31 | } | |
32 | ||
06487dee | 33 | /* write reg val table using reg addr auto increment */ |
7978b8a1 | 34 | static int m88ds3103_wr_reg_val_tab(struct m88ds3103_dev *dev, |
06487dee AP |
35 | const struct m88ds3103_reg_val *tab, int tab_len) |
36 | { | |
7978b8a1 | 37 | struct i2c_client *client = dev->client; |
06487dee AP |
38 | int ret, i, j; |
39 | u8 buf[83]; | |
41b9aa00 | 40 | |
7978b8a1 | 41 | dev_dbg(&client->dev, "tab_len=%d\n", tab_len); |
06487dee | 42 | |
f4df95bc | 43 | if (tab_len > 86) { |
06487dee AP |
44 | ret = -EINVAL; |
45 | goto err; | |
46 | } | |
47 | ||
48 | for (i = 0, j = 0; i < tab_len; i++, j++) { | |
49 | buf[j] = tab[i].val; | |
50 | ||
51 | if (i == tab_len - 1 || tab[i].reg != tab[i + 1].reg - 1 || | |
7978b8a1 | 52 | !((j + 1) % (dev->cfg->i2c_wr_max - 1))) { |
478932b1 | 53 | ret = regmap_bulk_write(dev->regmap, tab[i].reg - j, buf, j + 1); |
06487dee AP |
54 | if (ret) |
55 | goto err; | |
56 | ||
57 | j = -1; | |
58 | } | |
59 | } | |
60 | ||
61 | return 0; | |
62 | err: | |
7978b8a1 | 63 | dev_dbg(&client->dev, "failed=%d\n", ret); |
06487dee AP |
64 | return ret; |
65 | } | |
66 | ||
0f91c9d6 DH |
67 | /* |
68 | * Get the demodulator AGC PWM voltage setting supplied to the tuner. | |
69 | */ | |
70 | int m88ds3103_get_agc_pwm(struct dvb_frontend *fe, u8 *_agc_pwm) | |
71 | { | |
72 | struct m88ds3103_dev *dev = fe->demodulator_priv; | |
73 | unsigned tmp; | |
74 | int ret; | |
75 | ||
76 | ret = regmap_read(dev->regmap, 0x3f, &tmp); | |
77 | if (ret == 0) | |
78 | *_agc_pwm = tmp; | |
79 | return ret; | |
80 | } | |
81 | EXPORT_SYMBOL(m88ds3103_get_agc_pwm); | |
82 | ||
0df289a2 MCC |
83 | static int m88ds3103_read_status(struct dvb_frontend *fe, |
84 | enum fe_status *status) | |
395d00d1 | 85 | { |
7978b8a1 AP |
86 | struct m88ds3103_dev *dev = fe->demodulator_priv; |
87 | struct i2c_client *client = dev->client; | |
395d00d1 | 88 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
c1daf651 | 89 | int ret, i, itmp; |
478932b1 | 90 | unsigned int utmp; |
c1daf651 | 91 | u8 buf[3]; |
395d00d1 AP |
92 | |
93 | *status = 0; | |
94 | ||
7978b8a1 | 95 | if (!dev->warm) { |
395d00d1 AP |
96 | ret = -EAGAIN; |
97 | goto err; | |
98 | } | |
99 | ||
100 | switch (c->delivery_system) { | |
101 | case SYS_DVBS: | |
478932b1 | 102 | ret = regmap_read(dev->regmap, 0xd1, &utmp); |
395d00d1 AP |
103 | if (ret) |
104 | goto err; | |
105 | ||
478932b1 | 106 | if ((utmp & 0x07) == 0x07) |
395d00d1 AP |
107 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | |
108 | FE_HAS_VITERBI | FE_HAS_SYNC | | |
109 | FE_HAS_LOCK; | |
110 | break; | |
111 | case SYS_DVBS2: | |
478932b1 | 112 | ret = regmap_read(dev->regmap, 0x0d, &utmp); |
395d00d1 AP |
113 | if (ret) |
114 | goto err; | |
115 | ||
478932b1 | 116 | if ((utmp & 0x8f) == 0x8f) |
395d00d1 AP |
117 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | |
118 | FE_HAS_VITERBI | FE_HAS_SYNC | | |
119 | FE_HAS_LOCK; | |
120 | break; | |
121 | default: | |
7978b8a1 | 122 | dev_dbg(&client->dev, "invalid delivery_system\n"); |
395d00d1 AP |
123 | ret = -EINVAL; |
124 | goto err; | |
125 | } | |
126 | ||
7978b8a1 | 127 | dev->fe_status = *status; |
478932b1 | 128 | dev_dbg(&client->dev, "lock=%02x status=%02x\n", utmp, *status); |
395d00d1 | 129 | |
c1daf651 | 130 | /* CNR */ |
7978b8a1 | 131 | if (dev->fe_status & FE_HAS_VITERBI) { |
c1daf651 AP |
132 | unsigned int cnr, noise, signal, noise_tot, signal_tot; |
133 | ||
134 | cnr = 0; | |
135 | /* more iterations for more accurate estimation */ | |
136 | #define M88DS3103_SNR_ITERATIONS 3 | |
137 | ||
138 | switch (c->delivery_system) { | |
139 | case SYS_DVBS: | |
140 | itmp = 0; | |
141 | ||
142 | for (i = 0; i < M88DS3103_SNR_ITERATIONS; i++) { | |
478932b1 | 143 | ret = regmap_read(dev->regmap, 0xff, &utmp); |
c1daf651 AP |
144 | if (ret) |
145 | goto err; | |
146 | ||
478932b1 | 147 | itmp += utmp; |
c1daf651 AP |
148 | } |
149 | ||
150 | /* use of single register limits max value to 15 dB */ | |
151 | /* SNR(X) dB = 10 * ln(X) / ln(10) dB */ | |
152 | itmp = DIV_ROUND_CLOSEST(itmp, 8 * M88DS3103_SNR_ITERATIONS); | |
153 | if (itmp) | |
154 | cnr = div_u64((u64) 10000 * intlog2(itmp), intlog2(10)); | |
155 | break; | |
156 | case SYS_DVBS2: | |
157 | noise_tot = 0; | |
158 | signal_tot = 0; | |
159 | ||
160 | for (i = 0; i < M88DS3103_SNR_ITERATIONS; i++) { | |
478932b1 | 161 | ret = regmap_bulk_read(dev->regmap, 0x8c, buf, 3); |
c1daf651 AP |
162 | if (ret) |
163 | goto err; | |
164 | ||
165 | noise = buf[1] << 6; /* [13:6] */ | |
166 | noise |= buf[0] & 0x3f; /* [5:0] */ | |
167 | noise >>= 2; | |
168 | signal = buf[2] * buf[2]; | |
169 | signal >>= 1; | |
170 | ||
171 | noise_tot += noise; | |
172 | signal_tot += signal; | |
173 | } | |
174 | ||
175 | noise = noise_tot / M88DS3103_SNR_ITERATIONS; | |
176 | signal = signal_tot / M88DS3103_SNR_ITERATIONS; | |
177 | ||
178 | /* SNR(X) dB = 10 * log10(X) dB */ | |
179 | if (signal > noise) { | |
180 | itmp = signal / noise; | |
181 | cnr = div_u64((u64) 10000 * intlog10(itmp), (1 << 24)); | |
182 | } | |
183 | break; | |
184 | default: | |
7978b8a1 | 185 | dev_dbg(&client->dev, "invalid delivery_system\n"); |
c1daf651 AP |
186 | ret = -EINVAL; |
187 | goto err; | |
188 | } | |
189 | ||
190 | if (cnr) { | |
191 | c->cnr.stat[0].scale = FE_SCALE_DECIBEL; | |
192 | c->cnr.stat[0].svalue = cnr; | |
193 | } else { | |
194 | c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
195 | } | |
196 | } else { | |
197 | c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
198 | } | |
199 | ||
ce80d713 | 200 | /* BER */ |
7978b8a1 | 201 | if (dev->fe_status & FE_HAS_LOCK) { |
ce80d713 AP |
202 | unsigned int utmp, post_bit_error, post_bit_count; |
203 | ||
204 | switch (c->delivery_system) { | |
205 | case SYS_DVBS: | |
478932b1 | 206 | ret = regmap_write(dev->regmap, 0xf9, 0x04); |
ce80d713 AP |
207 | if (ret) |
208 | goto err; | |
209 | ||
478932b1 | 210 | ret = regmap_read(dev->regmap, 0xf8, &utmp); |
ce80d713 AP |
211 | if (ret) |
212 | goto err; | |
213 | ||
214 | /* measurement ready? */ | |
478932b1 AP |
215 | if (!(utmp & 0x10)) { |
216 | ret = regmap_bulk_read(dev->regmap, 0xf6, buf, 2); | |
ce80d713 AP |
217 | if (ret) |
218 | goto err; | |
219 | ||
220 | post_bit_error = buf[1] << 8 | buf[0] << 0; | |
221 | post_bit_count = 0x800000; | |
7978b8a1 AP |
222 | dev->post_bit_error += post_bit_error; |
223 | dev->post_bit_count += post_bit_count; | |
224 | dev->dvbv3_ber = post_bit_error; | |
ce80d713 AP |
225 | |
226 | /* restart measurement */ | |
478932b1 AP |
227 | utmp |= 0x10; |
228 | ret = regmap_write(dev->regmap, 0xf8, utmp); | |
ce80d713 AP |
229 | if (ret) |
230 | goto err; | |
231 | } | |
232 | break; | |
233 | case SYS_DVBS2: | |
478932b1 | 234 | ret = regmap_bulk_read(dev->regmap, 0xd5, buf, 3); |
ce80d713 AP |
235 | if (ret) |
236 | goto err; | |
237 | ||
238 | utmp = buf[2] << 16 | buf[1] << 8 | buf[0] << 0; | |
239 | ||
240 | /* enough data? */ | |
241 | if (utmp > 4000) { | |
478932b1 | 242 | ret = regmap_bulk_read(dev->regmap, 0xf7, buf, 2); |
ce80d713 AP |
243 | if (ret) |
244 | goto err; | |
245 | ||
246 | post_bit_error = buf[1] << 8 | buf[0] << 0; | |
247 | post_bit_count = 32 * utmp; /* TODO: FEC */ | |
7978b8a1 AP |
248 | dev->post_bit_error += post_bit_error; |
249 | dev->post_bit_count += post_bit_count; | |
250 | dev->dvbv3_ber = post_bit_error; | |
ce80d713 AP |
251 | |
252 | /* restart measurement */ | |
478932b1 | 253 | ret = regmap_write(dev->regmap, 0xd1, 0x01); |
ce80d713 AP |
254 | if (ret) |
255 | goto err; | |
256 | ||
478932b1 | 257 | ret = regmap_write(dev->regmap, 0xf9, 0x01); |
ce80d713 AP |
258 | if (ret) |
259 | goto err; | |
260 | ||
478932b1 | 261 | ret = regmap_write(dev->regmap, 0xf9, 0x00); |
ce80d713 AP |
262 | if (ret) |
263 | goto err; | |
264 | ||
478932b1 | 265 | ret = regmap_write(dev->regmap, 0xd1, 0x00); |
ce80d713 AP |
266 | if (ret) |
267 | goto err; | |
268 | } | |
269 | break; | |
270 | default: | |
7978b8a1 | 271 | dev_dbg(&client->dev, "invalid delivery_system\n"); |
ce80d713 AP |
272 | ret = -EINVAL; |
273 | goto err; | |
274 | } | |
275 | ||
276 | c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; | |
7978b8a1 | 277 | c->post_bit_error.stat[0].uvalue = dev->post_bit_error; |
ce80d713 | 278 | c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; |
7978b8a1 | 279 | c->post_bit_count.stat[0].uvalue = dev->post_bit_count; |
ce80d713 AP |
280 | } else { |
281 | c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
282 | c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
283 | } | |
284 | ||
395d00d1 AP |
285 | return 0; |
286 | err: | |
7978b8a1 | 287 | dev_dbg(&client->dev, "failed=%d\n", ret); |
395d00d1 AP |
288 | return ret; |
289 | } | |
290 | ||
291 | static int m88ds3103_set_frontend(struct dvb_frontend *fe) | |
292 | { | |
7978b8a1 AP |
293 | struct m88ds3103_dev *dev = fe->demodulator_priv; |
294 | struct i2c_client *client = dev->client; | |
395d00d1 | 295 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
06487dee | 296 | int ret, len; |
395d00d1 | 297 | const struct m88ds3103_reg_val *init; |
b6851419 | 298 | u8 u8tmp, u8tmp1 = 0, u8tmp2 = 0; /* silence compiler warning */ |
f4df95bc | 299 | u8 buf[3]; |
334ef18e | 300 | u16 u16tmp; |
f5d9b88d | 301 | u32 tuner_frequency_khz, target_mclk; |
395d00d1 | 302 | s32 s32tmp; |
981fbe3d JH |
303 | static const struct reg_sequence reset_buf[] = { |
304 | {0x07, 0x80}, {0x07, 0x00} | |
305 | }; | |
41b9aa00 | 306 | |
7978b8a1 AP |
307 | dev_dbg(&client->dev, |
308 | "delivery_system=%d modulation=%d frequency=%u symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n", | |
309 | c->delivery_system, c->modulation, c->frequency, c->symbol_rate, | |
310 | c->inversion, c->pilot, c->rolloff); | |
395d00d1 | 311 | |
7978b8a1 | 312 | if (!dev->warm) { |
395d00d1 AP |
313 | ret = -EAGAIN; |
314 | goto err; | |
315 | } | |
316 | ||
f4df95bc | 317 | /* reset */ |
981fbe3d | 318 | ret = regmap_multi_reg_write(dev->regmap, reset_buf, 2); |
f4df95bc | 319 | if (ret) |
320 | goto err; | |
321 | ||
322 | /* Disable demod clock path */ | |
7978b8a1 | 323 | if (dev->chip_id == M88RS6000_CHIP_ID) { |
478932b1 | 324 | ret = regmap_write(dev->regmap, 0x06, 0xe0); |
f4df95bc | 325 | if (ret) |
326 | goto err; | |
327 | } | |
328 | ||
395d00d1 AP |
329 | /* program tuner */ |
330 | if (fe->ops.tuner_ops.set_params) { | |
331 | ret = fe->ops.tuner_ops.set_params(fe); | |
332 | if (ret) | |
333 | goto err; | |
334 | } | |
335 | ||
336 | if (fe->ops.tuner_ops.get_frequency) { | |
f5d9b88d | 337 | ret = fe->ops.tuner_ops.get_frequency(fe, &tuner_frequency_khz); |
395d00d1 AP |
338 | if (ret) |
339 | goto err; | |
2f9dff3f AP |
340 | } else { |
341 | /* | |
342 | * Use nominal target frequency as tuner driver does not provide | |
343 | * actual frequency used. Carrier offset calculation is not | |
344 | * valid. | |
345 | */ | |
f5d9b88d | 346 | tuner_frequency_khz = c->frequency; |
395d00d1 AP |
347 | } |
348 | ||
f4df95bc | 349 | /* select M88RS6000 demod main mclk and ts mclk from tuner die. */ |
7978b8a1 | 350 | if (dev->chip_id == M88RS6000_CHIP_ID) { |
f4df95bc | 351 | if (c->symbol_rate > 45010000) |
f5d9b88d | 352 | dev->mclk = 110250000; |
f4df95bc | 353 | else |
f5d9b88d | 354 | dev->mclk = 96000000; |
395d00d1 | 355 | |
f4df95bc | 356 | if (c->delivery_system == SYS_DVBS) |
f5d9b88d | 357 | target_mclk = 96000000; |
f4df95bc | 358 | else |
f5d9b88d | 359 | target_mclk = 144000000; |
f4df95bc | 360 | |
361 | /* Enable demod clock path */ | |
478932b1 | 362 | ret = regmap_write(dev->regmap, 0x06, 0x00); |
f4df95bc | 363 | if (ret) |
364 | goto err; | |
365 | usleep_range(10000, 20000); | |
366 | } else { | |
367 | /* set M88DS3103 mclk and ts mclk. */ | |
f5d9b88d | 368 | dev->mclk = 96000000; |
f4df95bc | 369 | |
7978b8a1 | 370 | switch (dev->cfg->ts_mode) { |
b6851419 | 371 | case M88DS3103_TS_SERIAL: |
372 | case M88DS3103_TS_SERIAL_D7: | |
7978b8a1 | 373 | target_mclk = dev->cfg->ts_clk; |
b6851419 | 374 | break; |
375 | case M88DS3103_TS_PARALLEL: | |
376 | case M88DS3103_TS_CI: | |
377 | if (c->delivery_system == SYS_DVBS) | |
f5d9b88d | 378 | target_mclk = 96000000; |
b6851419 | 379 | else { |
f4df95bc | 380 | if (c->symbol_rate < 18000000) |
f5d9b88d | 381 | target_mclk = 96000000; |
f4df95bc | 382 | else if (c->symbol_rate < 28000000) |
f5d9b88d | 383 | target_mclk = 144000000; |
f4df95bc | 384 | else |
f5d9b88d | 385 | target_mclk = 192000000; |
f4df95bc | 386 | } |
b6851419 | 387 | break; |
388 | default: | |
7978b8a1 | 389 | dev_dbg(&client->dev, "invalid ts_mode\n"); |
b6851419 | 390 | ret = -EINVAL; |
391 | goto err; | |
f4df95bc | 392 | } |
393 | ||
394 | switch (target_mclk) { | |
f5d9b88d | 395 | case 96000000: |
f4df95bc | 396 | u8tmp1 = 0x02; /* 0b10 */ |
397 | u8tmp2 = 0x01; /* 0b01 */ | |
398 | break; | |
f5d9b88d | 399 | case 144000000: |
f4df95bc | 400 | u8tmp1 = 0x00; /* 0b00 */ |
401 | u8tmp2 = 0x01; /* 0b01 */ | |
402 | break; | |
f5d9b88d | 403 | case 192000000: |
f4df95bc | 404 | u8tmp1 = 0x03; /* 0b11 */ |
405 | u8tmp2 = 0x00; /* 0b00 */ | |
406 | break; | |
407 | } | |
56ea37da | 408 | ret = m88ds3103_update_bits(dev, 0x22, 0xc0, u8tmp1 << 6); |
f4df95bc | 409 | if (ret) |
410 | goto err; | |
56ea37da | 411 | ret = m88ds3103_update_bits(dev, 0x24, 0xc0, u8tmp2 << 6); |
f4df95bc | 412 | if (ret) |
413 | goto err; | |
414 | } | |
395d00d1 | 415 | |
478932b1 | 416 | ret = regmap_write(dev->regmap, 0xb2, 0x01); |
395d00d1 AP |
417 | if (ret) |
418 | goto err; | |
419 | ||
478932b1 | 420 | ret = regmap_write(dev->regmap, 0x00, 0x01); |
395d00d1 AP |
421 | if (ret) |
422 | goto err; | |
423 | ||
424 | switch (c->delivery_system) { | |
425 | case SYS_DVBS: | |
7978b8a1 | 426 | if (dev->chip_id == M88RS6000_CHIP_ID) { |
f4df95bc | 427 | len = ARRAY_SIZE(m88rs6000_dvbs_init_reg_vals); |
428 | init = m88rs6000_dvbs_init_reg_vals; | |
429 | } else { | |
430 | len = ARRAY_SIZE(m88ds3103_dvbs_init_reg_vals); | |
431 | init = m88ds3103_dvbs_init_reg_vals; | |
432 | } | |
395d00d1 AP |
433 | break; |
434 | case SYS_DVBS2: | |
7978b8a1 | 435 | if (dev->chip_id == M88RS6000_CHIP_ID) { |
f4df95bc | 436 | len = ARRAY_SIZE(m88rs6000_dvbs2_init_reg_vals); |
437 | init = m88rs6000_dvbs2_init_reg_vals; | |
438 | } else { | |
439 | len = ARRAY_SIZE(m88ds3103_dvbs2_init_reg_vals); | |
440 | init = m88ds3103_dvbs2_init_reg_vals; | |
395d00d1 AP |
441 | } |
442 | break; | |
443 | default: | |
7978b8a1 | 444 | dev_dbg(&client->dev, "invalid delivery_system\n"); |
395d00d1 AP |
445 | ret = -EINVAL; |
446 | goto err; | |
447 | } | |
448 | ||
449 | /* program init table */ | |
7978b8a1 AP |
450 | if (c->delivery_system != dev->delivery_system) { |
451 | ret = m88ds3103_wr_reg_val_tab(dev, init, len); | |
06487dee AP |
452 | if (ret) |
453 | goto err; | |
395d00d1 AP |
454 | } |
455 | ||
7978b8a1 | 456 | if (dev->chip_id == M88RS6000_CHIP_ID) { |
f5d9b88d AP |
457 | if (c->delivery_system == SYS_DVBS2 && |
458 | c->symbol_rate <= 5000000) { | |
478932b1 | 459 | ret = regmap_write(dev->regmap, 0xc0, 0x04); |
f4df95bc | 460 | if (ret) |
461 | goto err; | |
462 | buf[0] = 0x09; | |
463 | buf[1] = 0x22; | |
464 | buf[2] = 0x88; | |
478932b1 | 465 | ret = regmap_bulk_write(dev->regmap, 0x8a, buf, 3); |
f4df95bc | 466 | if (ret) |
467 | goto err; | |
468 | } | |
56ea37da | 469 | ret = m88ds3103_update_bits(dev, 0x9d, 0x08, 0x08); |
f4df95bc | 470 | if (ret) |
471 | goto err; | |
478932b1 | 472 | ret = regmap_write(dev->regmap, 0xf1, 0x01); |
f4df95bc | 473 | if (ret) |
474 | goto err; | |
56ea37da | 475 | ret = m88ds3103_update_bits(dev, 0x30, 0x80, 0x80); |
f4df95bc | 476 | if (ret) |
477 | goto err; | |
478 | } | |
479 | ||
7978b8a1 | 480 | switch (dev->cfg->ts_mode) { |
395d00d1 AP |
481 | case M88DS3103_TS_SERIAL: |
482 | u8tmp1 = 0x00; | |
79d09330 | 483 | u8tmp = 0x06; |
395d00d1 AP |
484 | break; |
485 | case M88DS3103_TS_SERIAL_D7: | |
486 | u8tmp1 = 0x20; | |
79d09330 | 487 | u8tmp = 0x06; |
395d00d1 AP |
488 | break; |
489 | case M88DS3103_TS_PARALLEL: | |
79d09330 | 490 | u8tmp = 0x02; |
395d00d1 AP |
491 | break; |
492 | case M88DS3103_TS_CI: | |
79d09330 | 493 | u8tmp = 0x03; |
395d00d1 AP |
494 | break; |
495 | default: | |
7978b8a1 | 496 | dev_dbg(&client->dev, "invalid ts_mode\n"); |
395d00d1 AP |
497 | ret = -EINVAL; |
498 | goto err; | |
499 | } | |
500 | ||
7978b8a1 | 501 | if (dev->cfg->ts_clk_pol) |
79d09330 | 502 | u8tmp |= 0x40; |
503 | ||
395d00d1 | 504 | /* TS mode */ |
478932b1 | 505 | ret = regmap_write(dev->regmap, 0xfd, u8tmp); |
395d00d1 AP |
506 | if (ret) |
507 | goto err; | |
508 | ||
7978b8a1 | 509 | switch (dev->cfg->ts_mode) { |
395d00d1 AP |
510 | case M88DS3103_TS_SERIAL: |
511 | case M88DS3103_TS_SERIAL_D7: | |
56ea37da | 512 | ret = m88ds3103_update_bits(dev, 0x29, 0x20, u8tmp1); |
395d00d1 AP |
513 | if (ret) |
514 | goto err; | |
334ef18e AP |
515 | u16tmp = 0; |
516 | u8tmp1 = 0x3f; | |
517 | u8tmp2 = 0x3f; | |
b6851419 | 518 | break; |
519 | default: | |
334ef18e AP |
520 | u16tmp = DIV_ROUND_UP(target_mclk, dev->cfg->ts_clk); |
521 | u8tmp1 = u16tmp / 2 - 1; | |
522 | u8tmp2 = DIV_ROUND_UP(u16tmp, 2) - 1; | |
395d00d1 AP |
523 | } |
524 | ||
f5d9b88d | 525 | dev_dbg(&client->dev, "target_mclk=%u ts_clk=%u ts_clk_divide_ratio=%u\n", |
334ef18e | 526 | target_mclk, dev->cfg->ts_clk, u16tmp); |
395d00d1 | 527 | |
395d00d1 | 528 | /* u8tmp1[5:2] => fe[3:0], u8tmp1[1:0] => ea[7:6] */ |
395d00d1 | 529 | /* u8tmp2[5:0] => ea[5:0] */ |
334ef18e AP |
530 | u8tmp = (u8tmp1 >> 2) & 0x0f; |
531 | ret = regmap_update_bits(dev->regmap, 0xfe, 0x0f, u8tmp); | |
395d00d1 AP |
532 | if (ret) |
533 | goto err; | |
395d00d1 | 534 | u8tmp = ((u8tmp1 & 0x03) << 6) | u8tmp2 >> 0; |
478932b1 | 535 | ret = regmap_write(dev->regmap, 0xea, u8tmp); |
395d00d1 AP |
536 | if (ret) |
537 | goto err; | |
538 | ||
395d00d1 AP |
539 | if (c->symbol_rate <= 3000000) |
540 | u8tmp = 0x20; | |
541 | else if (c->symbol_rate <= 10000000) | |
542 | u8tmp = 0x10; | |
543 | else | |
544 | u8tmp = 0x06; | |
545 | ||
478932b1 | 546 | ret = regmap_write(dev->regmap, 0xc3, 0x08); |
395d00d1 AP |
547 | if (ret) |
548 | goto err; | |
549 | ||
478932b1 | 550 | ret = regmap_write(dev->regmap, 0xc8, u8tmp); |
395d00d1 AP |
551 | if (ret) |
552 | goto err; | |
553 | ||
478932b1 | 554 | ret = regmap_write(dev->regmap, 0xc4, 0x08); |
395d00d1 AP |
555 | if (ret) |
556 | goto err; | |
557 | ||
478932b1 | 558 | ret = regmap_write(dev->regmap, 0xc7, 0x00); |
395d00d1 AP |
559 | if (ret) |
560 | goto err; | |
561 | ||
f5d9b88d | 562 | u16tmp = DIV_ROUND_CLOSEST_ULL((u64)c->symbol_rate * 0x10000, dev->mclk); |
395d00d1 AP |
563 | buf[0] = (u16tmp >> 0) & 0xff; |
564 | buf[1] = (u16tmp >> 8) & 0xff; | |
478932b1 | 565 | ret = regmap_bulk_write(dev->regmap, 0x61, buf, 2); |
395d00d1 AP |
566 | if (ret) |
567 | goto err; | |
568 | ||
56ea37da | 569 | ret = m88ds3103_update_bits(dev, 0x4d, 0x02, dev->cfg->spec_inv << 1); |
395d00d1 AP |
570 | if (ret) |
571 | goto err; | |
572 | ||
56ea37da | 573 | ret = m88ds3103_update_bits(dev, 0x30, 0x10, dev->cfg->agc_inv << 4); |
395d00d1 AP |
574 | if (ret) |
575 | goto err; | |
576 | ||
478932b1 | 577 | ret = regmap_write(dev->regmap, 0x33, dev->cfg->agc); |
395d00d1 AP |
578 | if (ret) |
579 | goto err; | |
580 | ||
7978b8a1 | 581 | dev_dbg(&client->dev, "carrier offset=%d\n", |
f5d9b88d | 582 | (tuner_frequency_khz - c->frequency)); |
395d00d1 | 583 | |
f5d9b88d AP |
584 | /* Use 32-bit calc as there is no s64 version of DIV_ROUND_CLOSEST() */ |
585 | s32tmp = 0x10000 * (tuner_frequency_khz - c->frequency); | |
586 | s32tmp = DIV_ROUND_CLOSEST(s32tmp, dev->mclk / 1000); | |
395d00d1 AP |
587 | buf[0] = (s32tmp >> 0) & 0xff; |
588 | buf[1] = (s32tmp >> 8) & 0xff; | |
478932b1 | 589 | ret = regmap_bulk_write(dev->regmap, 0x5e, buf, 2); |
395d00d1 AP |
590 | if (ret) |
591 | goto err; | |
592 | ||
478932b1 | 593 | ret = regmap_write(dev->regmap, 0x00, 0x00); |
395d00d1 AP |
594 | if (ret) |
595 | goto err; | |
596 | ||
478932b1 | 597 | ret = regmap_write(dev->regmap, 0xb2, 0x00); |
395d00d1 AP |
598 | if (ret) |
599 | goto err; | |
600 | ||
7978b8a1 | 601 | dev->delivery_system = c->delivery_system; |
395d00d1 AP |
602 | |
603 | return 0; | |
604 | err: | |
7978b8a1 | 605 | dev_dbg(&client->dev, "failed=%d\n", ret); |
395d00d1 AP |
606 | return ret; |
607 | } | |
608 | ||
609 | static int m88ds3103_init(struct dvb_frontend *fe) | |
610 | { | |
7978b8a1 AP |
611 | struct m88ds3103_dev *dev = fe->demodulator_priv; |
612 | struct i2c_client *client = dev->client; | |
c1daf651 | 613 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
60701d5f | 614 | int ret, len, rem; |
478932b1 | 615 | unsigned int utmp; |
60701d5f AP |
616 | const struct firmware *firmware; |
617 | const char *name; | |
41b9aa00 | 618 | |
7978b8a1 | 619 | dev_dbg(&client->dev, "\n"); |
395d00d1 AP |
620 | |
621 | /* set cold state by default */ | |
7978b8a1 | 622 | dev->warm = false; |
395d00d1 AP |
623 | |
624 | /* wake up device from sleep */ | |
56ea37da | 625 | ret = m88ds3103_update_bits(dev, 0x08, 0x01, 0x01); |
395d00d1 AP |
626 | if (ret) |
627 | goto err; | |
56ea37da | 628 | ret = m88ds3103_update_bits(dev, 0x04, 0x01, 0x00); |
395d00d1 AP |
629 | if (ret) |
630 | goto err; | |
56ea37da | 631 | ret = m88ds3103_update_bits(dev, 0x23, 0x10, 0x00); |
395d00d1 AP |
632 | if (ret) |
633 | goto err; | |
634 | ||
395d00d1 | 635 | /* firmware status */ |
478932b1 | 636 | ret = regmap_read(dev->regmap, 0xb9, &utmp); |
395d00d1 AP |
637 | if (ret) |
638 | goto err; | |
639 | ||
478932b1 | 640 | dev_dbg(&client->dev, "firmware=%02x\n", utmp); |
395d00d1 | 641 | |
478932b1 | 642 | if (utmp) |
60701d5f | 643 | goto warm; |
395d00d1 | 644 | |
f4df95bc | 645 | /* global reset, global diseqc reset, golbal fec reset */ |
478932b1 | 646 | ret = regmap_write(dev->regmap, 0x07, 0xe0); |
f4df95bc | 647 | if (ret) |
648 | goto err; | |
478932b1 | 649 | ret = regmap_write(dev->regmap, 0x07, 0x00); |
f4df95bc | 650 | if (ret) |
651 | goto err; | |
652 | ||
395d00d1 | 653 | /* cold state - try to download firmware */ |
7978b8a1 AP |
654 | dev_info(&client->dev, "found a '%s' in cold state\n", |
655 | m88ds3103_ops.info.name); | |
395d00d1 | 656 | |
7978b8a1 | 657 | if (dev->chip_id == M88RS6000_CHIP_ID) |
60701d5f | 658 | name = M88RS6000_FIRMWARE; |
f4df95bc | 659 | else |
60701d5f | 660 | name = M88DS3103_FIRMWARE; |
395d00d1 | 661 | /* request the firmware, this will block and timeout */ |
60701d5f | 662 | ret = request_firmware(&firmware, name, &client->dev); |
395d00d1 | 663 | if (ret) { |
60701d5f | 664 | dev_err(&client->dev, "firmware file '%s' not found\n", name); |
395d00d1 AP |
665 | goto err; |
666 | } | |
667 | ||
60701d5f | 668 | dev_info(&client->dev, "downloading firmware from file '%s'\n", name); |
395d00d1 | 669 | |
478932b1 | 670 | ret = regmap_write(dev->regmap, 0xb2, 0x01); |
395d00d1 | 671 | if (ret) |
60701d5f | 672 | goto err_release_firmware; |
395d00d1 | 673 | |
60701d5f AP |
674 | for (rem = firmware->size; rem > 0; rem -= (dev->cfg->i2c_wr_max - 1)) { |
675 | len = min(dev->cfg->i2c_wr_max - 1, rem); | |
478932b1 | 676 | ret = regmap_bulk_write(dev->regmap, 0xb0, |
60701d5f AP |
677 | &firmware->data[firmware->size - rem], |
678 | len); | |
395d00d1 | 679 | if (ret) { |
60701d5f | 680 | dev_err(&client->dev, "firmware download failed %d\n", |
7978b8a1 | 681 | ret); |
60701d5f | 682 | goto err_release_firmware; |
395d00d1 AP |
683 | } |
684 | } | |
685 | ||
478932b1 | 686 | ret = regmap_write(dev->regmap, 0xb2, 0x00); |
395d00d1 | 687 | if (ret) |
60701d5f | 688 | goto err_release_firmware; |
395d00d1 | 689 | |
60701d5f | 690 | release_firmware(firmware); |
395d00d1 | 691 | |
478932b1 | 692 | ret = regmap_read(dev->regmap, 0xb9, &utmp); |
395d00d1 AP |
693 | if (ret) |
694 | goto err; | |
695 | ||
478932b1 | 696 | if (!utmp) { |
60701d5f | 697 | ret = -EINVAL; |
7978b8a1 | 698 | dev_info(&client->dev, "firmware did not run\n"); |
395d00d1 AP |
699 | goto err; |
700 | } | |
701 | ||
7978b8a1 AP |
702 | dev_info(&client->dev, "found a '%s' in warm state\n", |
703 | m88ds3103_ops.info.name); | |
704 | dev_info(&client->dev, "firmware version: %X.%X\n", | |
478932b1 | 705 | (utmp >> 4) & 0xf, (utmp >> 0 & 0xf)); |
395d00d1 | 706 | |
60701d5f | 707 | warm: |
395d00d1 | 708 | /* warm state */ |
7978b8a1 AP |
709 | dev->warm = true; |
710 | ||
c1daf651 AP |
711 | /* init stats here in order signal app which stats are supported */ |
712 | c->cnr.len = 1; | |
713 | c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
ce80d713 AP |
714 | c->post_bit_error.len = 1; |
715 | c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
716 | c->post_bit_count.len = 1; | |
717 | c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
395d00d1 | 718 | |
7978b8a1 | 719 | return 0; |
60701d5f AP |
720 | err_release_firmware: |
721 | release_firmware(firmware); | |
5ed0cf88 | 722 | err: |
7978b8a1 | 723 | dev_dbg(&client->dev, "failed=%d\n", ret); |
395d00d1 AP |
724 | return ret; |
725 | } | |
726 | ||
727 | static int m88ds3103_sleep(struct dvb_frontend *fe) | |
728 | { | |
7978b8a1 AP |
729 | struct m88ds3103_dev *dev = fe->demodulator_priv; |
730 | struct i2c_client *client = dev->client; | |
395d00d1 | 731 | int ret; |
478932b1 | 732 | unsigned int utmp; |
41b9aa00 | 733 | |
7978b8a1 | 734 | dev_dbg(&client->dev, "\n"); |
395d00d1 | 735 | |
7978b8a1 AP |
736 | dev->fe_status = 0; |
737 | dev->delivery_system = SYS_UNDEFINED; | |
395d00d1 AP |
738 | |
739 | /* TS Hi-Z */ | |
7978b8a1 | 740 | if (dev->chip_id == M88RS6000_CHIP_ID) |
478932b1 | 741 | utmp = 0x29; |
f4df95bc | 742 | else |
478932b1 | 743 | utmp = 0x27; |
56ea37da | 744 | ret = m88ds3103_update_bits(dev, utmp, 0x01, 0x00); |
395d00d1 AP |
745 | if (ret) |
746 | goto err; | |
747 | ||
748 | /* sleep */ | |
56ea37da | 749 | ret = m88ds3103_update_bits(dev, 0x08, 0x01, 0x00); |
395d00d1 AP |
750 | if (ret) |
751 | goto err; | |
56ea37da | 752 | ret = m88ds3103_update_bits(dev, 0x04, 0x01, 0x01); |
395d00d1 AP |
753 | if (ret) |
754 | goto err; | |
56ea37da | 755 | ret = m88ds3103_update_bits(dev, 0x23, 0x10, 0x10); |
395d00d1 AP |
756 | if (ret) |
757 | goto err; | |
758 | ||
759 | return 0; | |
760 | err: | |
7978b8a1 | 761 | dev_dbg(&client->dev, "failed=%d\n", ret); |
395d00d1 AP |
762 | return ret; |
763 | } | |
764 | ||
7e3e68bc MCC |
765 | static int m88ds3103_get_frontend(struct dvb_frontend *fe, |
766 | struct dtv_frontend_properties *c) | |
395d00d1 | 767 | { |
7978b8a1 AP |
768 | struct m88ds3103_dev *dev = fe->demodulator_priv; |
769 | struct i2c_client *client = dev->client; | |
395d00d1 AP |
770 | int ret; |
771 | u8 buf[3]; | |
41b9aa00 | 772 | |
7978b8a1 | 773 | dev_dbg(&client->dev, "\n"); |
395d00d1 | 774 | |
7978b8a1 | 775 | if (!dev->warm || !(dev->fe_status & FE_HAS_LOCK)) { |
9240c384 | 776 | ret = 0; |
395d00d1 AP |
777 | goto err; |
778 | } | |
779 | ||
780 | switch (c->delivery_system) { | |
781 | case SYS_DVBS: | |
478932b1 | 782 | ret = regmap_bulk_read(dev->regmap, 0xe0, &buf[0], 1); |
395d00d1 AP |
783 | if (ret) |
784 | goto err; | |
785 | ||
478932b1 | 786 | ret = regmap_bulk_read(dev->regmap, 0xe6, &buf[1], 1); |
395d00d1 AP |
787 | if (ret) |
788 | goto err; | |
789 | ||
790 | switch ((buf[0] >> 2) & 0x01) { | |
791 | case 0: | |
792 | c->inversion = INVERSION_OFF; | |
793 | break; | |
794 | case 1: | |
795 | c->inversion = INVERSION_ON; | |
796 | break; | |
395d00d1 AP |
797 | } |
798 | ||
799 | switch ((buf[1] >> 5) & 0x07) { | |
800 | case 0: | |
801 | c->fec_inner = FEC_7_8; | |
802 | break; | |
803 | case 1: | |
804 | c->fec_inner = FEC_5_6; | |
805 | break; | |
806 | case 2: | |
807 | c->fec_inner = FEC_3_4; | |
808 | break; | |
809 | case 3: | |
810 | c->fec_inner = FEC_2_3; | |
811 | break; | |
812 | case 4: | |
813 | c->fec_inner = FEC_1_2; | |
814 | break; | |
815 | default: | |
7978b8a1 | 816 | dev_dbg(&client->dev, "invalid fec_inner\n"); |
395d00d1 AP |
817 | } |
818 | ||
819 | c->modulation = QPSK; | |
820 | ||
821 | break; | |
822 | case SYS_DVBS2: | |
478932b1 | 823 | ret = regmap_bulk_read(dev->regmap, 0x7e, &buf[0], 1); |
395d00d1 AP |
824 | if (ret) |
825 | goto err; | |
826 | ||
478932b1 | 827 | ret = regmap_bulk_read(dev->regmap, 0x89, &buf[1], 1); |
395d00d1 AP |
828 | if (ret) |
829 | goto err; | |
830 | ||
478932b1 | 831 | ret = regmap_bulk_read(dev->regmap, 0xf2, &buf[2], 1); |
395d00d1 AP |
832 | if (ret) |
833 | goto err; | |
834 | ||
835 | switch ((buf[0] >> 0) & 0x0f) { | |
836 | case 2: | |
837 | c->fec_inner = FEC_2_5; | |
838 | break; | |
839 | case 3: | |
840 | c->fec_inner = FEC_1_2; | |
841 | break; | |
842 | case 4: | |
843 | c->fec_inner = FEC_3_5; | |
844 | break; | |
845 | case 5: | |
846 | c->fec_inner = FEC_2_3; | |
847 | break; | |
848 | case 6: | |
849 | c->fec_inner = FEC_3_4; | |
850 | break; | |
851 | case 7: | |
852 | c->fec_inner = FEC_4_5; | |
853 | break; | |
854 | case 8: | |
855 | c->fec_inner = FEC_5_6; | |
856 | break; | |
857 | case 9: | |
858 | c->fec_inner = FEC_8_9; | |
859 | break; | |
860 | case 10: | |
861 | c->fec_inner = FEC_9_10; | |
862 | break; | |
863 | default: | |
7978b8a1 | 864 | dev_dbg(&client->dev, "invalid fec_inner\n"); |
395d00d1 AP |
865 | } |
866 | ||
867 | switch ((buf[0] >> 5) & 0x01) { | |
868 | case 0: | |
869 | c->pilot = PILOT_OFF; | |
870 | break; | |
871 | case 1: | |
872 | c->pilot = PILOT_ON; | |
873 | break; | |
395d00d1 AP |
874 | } |
875 | ||
876 | switch ((buf[0] >> 6) & 0x07) { | |
877 | case 0: | |
878 | c->modulation = QPSK; | |
879 | break; | |
880 | case 1: | |
881 | c->modulation = PSK_8; | |
882 | break; | |
883 | case 2: | |
884 | c->modulation = APSK_16; | |
885 | break; | |
886 | case 3: | |
887 | c->modulation = APSK_32; | |
888 | break; | |
889 | default: | |
7978b8a1 | 890 | dev_dbg(&client->dev, "invalid modulation\n"); |
395d00d1 AP |
891 | } |
892 | ||
893 | switch ((buf[1] >> 7) & 0x01) { | |
894 | case 0: | |
895 | c->inversion = INVERSION_OFF; | |
896 | break; | |
897 | case 1: | |
898 | c->inversion = INVERSION_ON; | |
899 | break; | |
395d00d1 AP |
900 | } |
901 | ||
902 | switch ((buf[2] >> 0) & 0x03) { | |
903 | case 0: | |
904 | c->rolloff = ROLLOFF_35; | |
905 | break; | |
906 | case 1: | |
907 | c->rolloff = ROLLOFF_25; | |
908 | break; | |
909 | case 2: | |
910 | c->rolloff = ROLLOFF_20; | |
911 | break; | |
912 | default: | |
7978b8a1 | 913 | dev_dbg(&client->dev, "invalid rolloff\n"); |
395d00d1 AP |
914 | } |
915 | break; | |
916 | default: | |
7978b8a1 | 917 | dev_dbg(&client->dev, "invalid delivery_system\n"); |
395d00d1 AP |
918 | ret = -EINVAL; |
919 | goto err; | |
920 | } | |
921 | ||
478932b1 | 922 | ret = regmap_bulk_read(dev->regmap, 0x6d, buf, 2); |
395d00d1 AP |
923 | if (ret) |
924 | goto err; | |
925 | ||
f5d9b88d | 926 | c->symbol_rate = DIV_ROUND_CLOSEST_ULL((u64)(buf[1] << 8 | buf[0] << 0) * dev->mclk, 0x10000); |
395d00d1 AP |
927 | |
928 | return 0; | |
929 | err: | |
7978b8a1 | 930 | dev_dbg(&client->dev, "failed=%d\n", ret); |
395d00d1 AP |
931 | return ret; |
932 | } | |
933 | ||
934 | static int m88ds3103_read_snr(struct dvb_frontend *fe, u16 *snr) | |
935 | { | |
395d00d1 | 936 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
41b9aa00 | 937 | |
c1daf651 AP |
938 | if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL) |
939 | *snr = div_s64(c->cnr.stat[0].svalue, 100); | |
940 | else | |
941 | *snr = 0; | |
395d00d1 AP |
942 | |
943 | return 0; | |
395d00d1 AP |
944 | } |
945 | ||
4423a2ba AP |
946 | static int m88ds3103_read_ber(struct dvb_frontend *fe, u32 *ber) |
947 | { | |
7978b8a1 | 948 | struct m88ds3103_dev *dev = fe->demodulator_priv; |
41b9aa00 | 949 | |
7978b8a1 | 950 | *ber = dev->dvbv3_ber; |
4423a2ba AP |
951 | |
952 | return 0; | |
4423a2ba | 953 | } |
395d00d1 AP |
954 | |
955 | static int m88ds3103_set_tone(struct dvb_frontend *fe, | |
0df289a2 | 956 | enum fe_sec_tone_mode fe_sec_tone_mode) |
395d00d1 | 957 | { |
7978b8a1 AP |
958 | struct m88ds3103_dev *dev = fe->demodulator_priv; |
959 | struct i2c_client *client = dev->client; | |
395d00d1 | 960 | int ret; |
478932b1 | 961 | unsigned int utmp, tone, reg_a1_mask; |
41b9aa00 | 962 | |
7978b8a1 | 963 | dev_dbg(&client->dev, "fe_sec_tone_mode=%d\n", fe_sec_tone_mode); |
395d00d1 | 964 | |
7978b8a1 | 965 | if (!dev->warm) { |
395d00d1 AP |
966 | ret = -EAGAIN; |
967 | goto err; | |
968 | } | |
969 | ||
970 | switch (fe_sec_tone_mode) { | |
971 | case SEC_TONE_ON: | |
972 | tone = 0; | |
418a97cb | 973 | reg_a1_mask = 0x47; |
395d00d1 AP |
974 | break; |
975 | case SEC_TONE_OFF: | |
976 | tone = 1; | |
977 | reg_a1_mask = 0x00; | |
978 | break; | |
979 | default: | |
7978b8a1 | 980 | dev_dbg(&client->dev, "invalid fe_sec_tone_mode\n"); |
395d00d1 AP |
981 | ret = -EINVAL; |
982 | goto err; | |
983 | } | |
984 | ||
478932b1 | 985 | utmp = tone << 7 | dev->cfg->envelope_mode << 5; |
56ea37da | 986 | ret = m88ds3103_update_bits(dev, 0xa2, 0xe0, utmp); |
395d00d1 AP |
987 | if (ret) |
988 | goto err; | |
989 | ||
478932b1 | 990 | utmp = 1 << 2; |
56ea37da | 991 | ret = m88ds3103_update_bits(dev, 0xa1, reg_a1_mask, utmp); |
395d00d1 AP |
992 | if (ret) |
993 | goto err; | |
994 | ||
995 | return 0; | |
996 | err: | |
7978b8a1 | 997 | dev_dbg(&client->dev, "failed=%d\n", ret); |
395d00d1 AP |
998 | return ret; |
999 | } | |
1000 | ||
79d09330 | 1001 | static int m88ds3103_set_voltage(struct dvb_frontend *fe, |
0df289a2 | 1002 | enum fe_sec_voltage fe_sec_voltage) |
79d09330 | 1003 | { |
7978b8a1 AP |
1004 | struct m88ds3103_dev *dev = fe->demodulator_priv; |
1005 | struct i2c_client *client = dev->client; | |
d28677ff | 1006 | int ret; |
478932b1 | 1007 | unsigned int utmp; |
d28677ff | 1008 | bool voltage_sel, voltage_dis; |
79d09330 | 1009 | |
7978b8a1 | 1010 | dev_dbg(&client->dev, "fe_sec_voltage=%d\n", fe_sec_voltage); |
79d09330 | 1011 | |
7978b8a1 | 1012 | if (!dev->warm) { |
d28677ff AP |
1013 | ret = -EAGAIN; |
1014 | goto err; | |
1015 | } | |
79d09330 | 1016 | |
d28677ff | 1017 | switch (fe_sec_voltage) { |
79d09330 | 1018 | case SEC_VOLTAGE_18: |
afbd6eb4 MCC |
1019 | voltage_sel = true; |
1020 | voltage_dis = false; | |
79d09330 | 1021 | break; |
1022 | case SEC_VOLTAGE_13: | |
afbd6eb4 MCC |
1023 | voltage_sel = false; |
1024 | voltage_dis = false; | |
79d09330 | 1025 | break; |
1026 | case SEC_VOLTAGE_OFF: | |
afbd6eb4 MCC |
1027 | voltage_sel = false; |
1028 | voltage_dis = true; | |
79d09330 | 1029 | break; |
d28677ff | 1030 | default: |
7978b8a1 | 1031 | dev_dbg(&client->dev, "invalid fe_sec_voltage\n"); |
d28677ff AP |
1032 | ret = -EINVAL; |
1033 | goto err; | |
79d09330 | 1034 | } |
d28677ff AP |
1035 | |
1036 | /* output pin polarity */ | |
7978b8a1 AP |
1037 | voltage_sel ^= dev->cfg->lnb_hv_pol; |
1038 | voltage_dis ^= dev->cfg->lnb_en_pol; | |
d28677ff | 1039 | |
478932b1 | 1040 | utmp = voltage_dis << 1 | voltage_sel << 0; |
56ea37da | 1041 | ret = m88ds3103_update_bits(dev, 0xa2, 0x03, utmp); |
d28677ff AP |
1042 | if (ret) |
1043 | goto err; | |
79d09330 | 1044 | |
1045 | return 0; | |
d28677ff | 1046 | err: |
7978b8a1 | 1047 | dev_dbg(&client->dev, "failed=%d\n", ret); |
d28677ff | 1048 | return ret; |
79d09330 | 1049 | } |
1050 | ||
395d00d1 AP |
1051 | static int m88ds3103_diseqc_send_master_cmd(struct dvb_frontend *fe, |
1052 | struct dvb_diseqc_master_cmd *diseqc_cmd) | |
1053 | { | |
7978b8a1 AP |
1054 | struct m88ds3103_dev *dev = fe->demodulator_priv; |
1055 | struct i2c_client *client = dev->client; | |
befa0cc1 | 1056 | int ret; |
478932b1 | 1057 | unsigned int utmp; |
befa0cc1 | 1058 | unsigned long timeout; |
41b9aa00 | 1059 | |
7978b8a1 AP |
1060 | dev_dbg(&client->dev, "msg=%*ph\n", |
1061 | diseqc_cmd->msg_len, diseqc_cmd->msg); | |
395d00d1 | 1062 | |
7978b8a1 | 1063 | if (!dev->warm) { |
395d00d1 AP |
1064 | ret = -EAGAIN; |
1065 | goto err; | |
1066 | } | |
1067 | ||
1068 | if (diseqc_cmd->msg_len < 3 || diseqc_cmd->msg_len > 6) { | |
1069 | ret = -EINVAL; | |
1070 | goto err; | |
1071 | } | |
1072 | ||
478932b1 | 1073 | utmp = dev->cfg->envelope_mode << 5; |
56ea37da | 1074 | ret = m88ds3103_update_bits(dev, 0xa2, 0xe0, utmp); |
395d00d1 AP |
1075 | if (ret) |
1076 | goto err; | |
1077 | ||
478932b1 | 1078 | ret = regmap_bulk_write(dev->regmap, 0xa3, diseqc_cmd->msg, |
395d00d1 AP |
1079 | diseqc_cmd->msg_len); |
1080 | if (ret) | |
1081 | goto err; | |
1082 | ||
478932b1 | 1083 | ret = regmap_write(dev->regmap, 0xa1, |
395d00d1 AP |
1084 | (diseqc_cmd->msg_len - 1) << 3 | 0x07); |
1085 | if (ret) | |
1086 | goto err; | |
1087 | ||
395d00d1 | 1088 | /* wait DiSEqC TX ready */ |
befa0cc1 AP |
1089 | #define SEND_MASTER_CMD_TIMEOUT 120 |
1090 | timeout = jiffies + msecs_to_jiffies(SEND_MASTER_CMD_TIMEOUT); | |
1091 | ||
9ef3cdc1 AP |
1092 | /* DiSEqC message period is 13.5 ms per byte */ |
1093 | utmp = diseqc_cmd->msg_len * 13500; | |
1094 | usleep_range(utmp - 4000, utmp); | |
395d00d1 | 1095 | |
478932b1 AP |
1096 | for (utmp = 1; !time_after(jiffies, timeout) && utmp;) { |
1097 | ret = regmap_read(dev->regmap, 0xa1, &utmp); | |
395d00d1 AP |
1098 | if (ret) |
1099 | goto err; | |
478932b1 | 1100 | utmp = (utmp >> 6) & 0x1; |
395d00d1 AP |
1101 | } |
1102 | ||
478932b1 | 1103 | if (utmp == 0) { |
7978b8a1 | 1104 | dev_dbg(&client->dev, "diseqc tx took %u ms\n", |
befa0cc1 AP |
1105 | jiffies_to_msecs(jiffies) - |
1106 | (jiffies_to_msecs(timeout) - SEND_MASTER_CMD_TIMEOUT)); | |
1107 | } else { | |
7978b8a1 | 1108 | dev_dbg(&client->dev, "diseqc tx timeout\n"); |
395d00d1 | 1109 | |
56ea37da | 1110 | ret = m88ds3103_update_bits(dev, 0xa1, 0xc0, 0x40); |
395d00d1 AP |
1111 | if (ret) |
1112 | goto err; | |
1113 | } | |
1114 | ||
56ea37da | 1115 | ret = m88ds3103_update_bits(dev, 0xa2, 0xc0, 0x80); |
395d00d1 AP |
1116 | if (ret) |
1117 | goto err; | |
1118 | ||
478932b1 | 1119 | if (utmp == 1) { |
395d00d1 AP |
1120 | ret = -ETIMEDOUT; |
1121 | goto err; | |
1122 | } | |
1123 | ||
1124 | return 0; | |
1125 | err: | |
7978b8a1 | 1126 | dev_dbg(&client->dev, "failed=%d\n", ret); |
395d00d1 AP |
1127 | return ret; |
1128 | } | |
1129 | ||
1130 | static int m88ds3103_diseqc_send_burst(struct dvb_frontend *fe, | |
0df289a2 | 1131 | enum fe_sec_mini_cmd fe_sec_mini_cmd) |
395d00d1 | 1132 | { |
7978b8a1 AP |
1133 | struct m88ds3103_dev *dev = fe->demodulator_priv; |
1134 | struct i2c_client *client = dev->client; | |
befa0cc1 | 1135 | int ret; |
478932b1 | 1136 | unsigned int utmp, burst; |
befa0cc1 | 1137 | unsigned long timeout; |
41b9aa00 | 1138 | |
7978b8a1 | 1139 | dev_dbg(&client->dev, "fe_sec_mini_cmd=%d\n", fe_sec_mini_cmd); |
395d00d1 | 1140 | |
7978b8a1 | 1141 | if (!dev->warm) { |
395d00d1 AP |
1142 | ret = -EAGAIN; |
1143 | goto err; | |
1144 | } | |
1145 | ||
478932b1 | 1146 | utmp = dev->cfg->envelope_mode << 5; |
56ea37da | 1147 | ret = m88ds3103_update_bits(dev, 0xa2, 0xe0, utmp); |
395d00d1 AP |
1148 | if (ret) |
1149 | goto err; | |
1150 | ||
1151 | switch (fe_sec_mini_cmd) { | |
1152 | case SEC_MINI_A: | |
1153 | burst = 0x02; | |
1154 | break; | |
1155 | case SEC_MINI_B: | |
1156 | burst = 0x01; | |
1157 | break; | |
1158 | default: | |
7978b8a1 | 1159 | dev_dbg(&client->dev, "invalid fe_sec_mini_cmd\n"); |
395d00d1 AP |
1160 | ret = -EINVAL; |
1161 | goto err; | |
1162 | } | |
1163 | ||
478932b1 | 1164 | ret = regmap_write(dev->regmap, 0xa1, burst); |
395d00d1 AP |
1165 | if (ret) |
1166 | goto err; | |
1167 | ||
395d00d1 | 1168 | /* wait DiSEqC TX ready */ |
befa0cc1 AP |
1169 | #define SEND_BURST_TIMEOUT 40 |
1170 | timeout = jiffies + msecs_to_jiffies(SEND_BURST_TIMEOUT); | |
1171 | ||
1172 | /* DiSEqC ToneBurst period is 12.5 ms */ | |
1173 | usleep_range(8500, 12500); | |
395d00d1 | 1174 | |
478932b1 AP |
1175 | for (utmp = 1; !time_after(jiffies, timeout) && utmp;) { |
1176 | ret = regmap_read(dev->regmap, 0xa1, &utmp); | |
395d00d1 AP |
1177 | if (ret) |
1178 | goto err; | |
478932b1 | 1179 | utmp = (utmp >> 6) & 0x1; |
395d00d1 AP |
1180 | } |
1181 | ||
478932b1 | 1182 | if (utmp == 0) { |
7978b8a1 | 1183 | dev_dbg(&client->dev, "diseqc tx took %u ms\n", |
befa0cc1 AP |
1184 | jiffies_to_msecs(jiffies) - |
1185 | (jiffies_to_msecs(timeout) - SEND_BURST_TIMEOUT)); | |
1186 | } else { | |
7978b8a1 | 1187 | dev_dbg(&client->dev, "diseqc tx timeout\n"); |
befa0cc1 | 1188 | |
56ea37da | 1189 | ret = m88ds3103_update_bits(dev, 0xa1, 0xc0, 0x40); |
befa0cc1 AP |
1190 | if (ret) |
1191 | goto err; | |
1192 | } | |
395d00d1 | 1193 | |
56ea37da | 1194 | ret = m88ds3103_update_bits(dev, 0xa2, 0xc0, 0x80); |
395d00d1 AP |
1195 | if (ret) |
1196 | goto err; | |
1197 | ||
478932b1 | 1198 | if (utmp == 1) { |
395d00d1 AP |
1199 | ret = -ETIMEDOUT; |
1200 | goto err; | |
1201 | } | |
1202 | ||
1203 | return 0; | |
1204 | err: | |
7978b8a1 | 1205 | dev_dbg(&client->dev, "failed=%d\n", ret); |
395d00d1 AP |
1206 | return ret; |
1207 | } | |
1208 | ||
1209 | static int m88ds3103_get_tune_settings(struct dvb_frontend *fe, | |
1210 | struct dvb_frontend_tune_settings *s) | |
1211 | { | |
1212 | s->min_delay_ms = 3000; | |
1213 | ||
1214 | return 0; | |
1215 | } | |
1216 | ||
44b9055b | 1217 | static void m88ds3103_release(struct dvb_frontend *fe) |
395d00d1 | 1218 | { |
7978b8a1 AP |
1219 | struct m88ds3103_dev *dev = fe->demodulator_priv; |
1220 | struct i2c_client *client = dev->client; | |
41b9aa00 | 1221 | |
f01919e8 | 1222 | i2c_unregister_device(client); |
395d00d1 AP |
1223 | } |
1224 | ||
e00fed40 | 1225 | static int m88ds3103_select(struct i2c_mux_core *muxc, u32 chan) |
395d00d1 | 1226 | { |
e00fed40 | 1227 | struct m88ds3103_dev *dev = i2c_mux_priv(muxc); |
7978b8a1 | 1228 | struct i2c_client *client = dev->client; |
395d00d1 | 1229 | int ret; |
478932b1 AP |
1230 | struct i2c_msg msg = { |
1231 | .addr = client->addr, | |
1232 | .flags = 0, | |
1233 | .len = 2, | |
1234 | .buf = "\x03\x11", | |
395d00d1 | 1235 | }; |
395d00d1 | 1236 | |
478932b1 AP |
1237 | /* Open tuner I2C repeater for 1 xfer, closes automatically */ |
1238 | ret = __i2c_transfer(client->adapter, &msg, 1); | |
395d00d1 | 1239 | if (ret != 1) { |
7978b8a1 | 1240 | dev_warn(&client->dev, "i2c wr failed=%d\n", ret); |
44b9055b AP |
1241 | if (ret >= 0) |
1242 | ret = -EREMOTEIO; | |
44b9055b AP |
1243 | return ret; |
1244 | } | |
395d00d1 | 1245 | |
44b9055b | 1246 | return 0; |
395d00d1 AP |
1247 | } |
1248 | ||
f01919e8 AP |
1249 | /* |
1250 | * XXX: That is wrapper to m88ds3103_probe() via driver core in order to provide | |
1251 | * proper I2C client for legacy media attach binding. | |
1252 | * New users must use I2C client binding directly! | |
1253 | */ | |
395d00d1 | 1254 | struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg, |
b9c97c67 MCC |
1255 | struct i2c_adapter *i2c, |
1256 | struct i2c_adapter **tuner_i2c_adapter) | |
395d00d1 | 1257 | { |
f01919e8 AP |
1258 | struct i2c_client *client; |
1259 | struct i2c_board_info board_info; | |
b9c97c67 | 1260 | struct m88ds3103_platform_data pdata = {}; |
f01919e8 AP |
1261 | |
1262 | pdata.clk = cfg->clock; | |
1263 | pdata.i2c_wr_max = cfg->i2c_wr_max; | |
1264 | pdata.ts_mode = cfg->ts_mode; | |
1265 | pdata.ts_clk = cfg->ts_clk; | |
1266 | pdata.ts_clk_pol = cfg->ts_clk_pol; | |
1267 | pdata.spec_inv = cfg->spec_inv; | |
1268 | pdata.agc = cfg->agc; | |
1269 | pdata.agc_inv = cfg->agc_inv; | |
1270 | pdata.clk_out = cfg->clock_out; | |
1271 | pdata.envelope_mode = cfg->envelope_mode; | |
1272 | pdata.lnb_hv_pol = cfg->lnb_hv_pol; | |
1273 | pdata.lnb_en_pol = cfg->lnb_en_pol; | |
1274 | pdata.attach_in_use = true; | |
1275 | ||
1276 | memset(&board_info, 0, sizeof(board_info)); | |
c0decac1 | 1277 | strscpy(board_info.type, "m88ds3103", I2C_NAME_SIZE); |
f01919e8 AP |
1278 | board_info.addr = cfg->i2c_addr; |
1279 | board_info.platform_data = &pdata; | |
aace5926 WS |
1280 | client = i2c_new_client_device(i2c, &board_info); |
1281 | if (!i2c_client_has_driver(client)) | |
f01919e8 AP |
1282 | return NULL; |
1283 | ||
1284 | *tuner_i2c_adapter = pdata.get_i2c_adapter(client); | |
1285 | return pdata.get_dvb_frontend(client); | |
1286 | } | |
1287 | EXPORT_SYMBOL(m88ds3103_attach); | |
1288 | ||
bd336e63 | 1289 | static const struct dvb_frontend_ops m88ds3103_ops = { |
7978b8a1 | 1290 | .delsys = {SYS_DVBS, SYS_DVBS2}, |
f01919e8 | 1291 | .info = { |
7978b8a1 | 1292 | .name = "Montage Technology M88DS3103", |
f1b1eabf MCC |
1293 | .frequency_min_hz = 950 * MHz, |
1294 | .frequency_max_hz = 2150 * MHz, | |
1295 | .frequency_tolerance_hz = 5 * MHz, | |
f01919e8 AP |
1296 | .symbol_rate_min = 1000000, |
1297 | .symbol_rate_max = 45000000, | |
1298 | .caps = FE_CAN_INVERSION_AUTO | | |
1299 | FE_CAN_FEC_1_2 | | |
1300 | FE_CAN_FEC_2_3 | | |
1301 | FE_CAN_FEC_3_4 | | |
1302 | FE_CAN_FEC_4_5 | | |
1303 | FE_CAN_FEC_5_6 | | |
1304 | FE_CAN_FEC_6_7 | | |
1305 | FE_CAN_FEC_7_8 | | |
1306 | FE_CAN_FEC_8_9 | | |
1307 | FE_CAN_FEC_AUTO | | |
1308 | FE_CAN_QPSK | | |
1309 | FE_CAN_RECOVER | | |
1310 | FE_CAN_2G_MODULATION | |
1311 | }, | |
1312 | ||
1313 | .release = m88ds3103_release, | |
1314 | ||
1315 | .get_tune_settings = m88ds3103_get_tune_settings, | |
1316 | ||
1317 | .init = m88ds3103_init, | |
1318 | .sleep = m88ds3103_sleep, | |
1319 | ||
1320 | .set_frontend = m88ds3103_set_frontend, | |
1321 | .get_frontend = m88ds3103_get_frontend, | |
1322 | ||
1323 | .read_status = m88ds3103_read_status, | |
1324 | .read_snr = m88ds3103_read_snr, | |
1325 | .read_ber = m88ds3103_read_ber, | |
1326 | ||
1327 | .diseqc_send_master_cmd = m88ds3103_diseqc_send_master_cmd, | |
1328 | .diseqc_send_burst = m88ds3103_diseqc_send_burst, | |
1329 | ||
1330 | .set_tone = m88ds3103_set_tone, | |
1331 | .set_voltage = m88ds3103_set_voltage, | |
1332 | }; | |
1333 | ||
1334 | static struct dvb_frontend *m88ds3103_get_dvb_frontend(struct i2c_client *client) | |
1335 | { | |
7978b8a1 | 1336 | struct m88ds3103_dev *dev = i2c_get_clientdata(client); |
f01919e8 AP |
1337 | |
1338 | dev_dbg(&client->dev, "\n"); | |
1339 | ||
1340 | return &dev->fe; | |
1341 | } | |
1342 | ||
1343 | static struct i2c_adapter *m88ds3103_get_i2c_adapter(struct i2c_client *client) | |
1344 | { | |
7978b8a1 | 1345 | struct m88ds3103_dev *dev = i2c_get_clientdata(client); |
f01919e8 AP |
1346 | |
1347 | dev_dbg(&client->dev, "\n"); | |
1348 | ||
e00fed40 | 1349 | return dev->muxc->adapter[0]; |
f01919e8 AP |
1350 | } |
1351 | ||
1352 | static int m88ds3103_probe(struct i2c_client *client, | |
1353 | const struct i2c_device_id *id) | |
1354 | { | |
7978b8a1 | 1355 | struct m88ds3103_dev *dev; |
f01919e8 | 1356 | struct m88ds3103_platform_data *pdata = client->dev.platform_data; |
395d00d1 | 1357 | int ret; |
478932b1 | 1358 | unsigned int utmp; |
395d00d1 | 1359 | |
f01919e8 AP |
1360 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
1361 | if (!dev) { | |
395d00d1 | 1362 | ret = -ENOMEM; |
395d00d1 AP |
1363 | goto err; |
1364 | } | |
1365 | ||
f01919e8 | 1366 | dev->client = client; |
f01919e8 AP |
1367 | dev->config.clock = pdata->clk; |
1368 | dev->config.i2c_wr_max = pdata->i2c_wr_max; | |
1369 | dev->config.ts_mode = pdata->ts_mode; | |
f5d9b88d | 1370 | dev->config.ts_clk = pdata->ts_clk * 1000; |
f01919e8 AP |
1371 | dev->config.ts_clk_pol = pdata->ts_clk_pol; |
1372 | dev->config.spec_inv = pdata->spec_inv; | |
1373 | dev->config.agc_inv = pdata->agc_inv; | |
1374 | dev->config.clock_out = pdata->clk_out; | |
1375 | dev->config.envelope_mode = pdata->envelope_mode; | |
1376 | dev->config.agc = pdata->agc; | |
1377 | dev->config.lnb_hv_pol = pdata->lnb_hv_pol; | |
1378 | dev->config.lnb_en_pol = pdata->lnb_en_pol; | |
1379 | dev->cfg = &dev->config; | |
478932b1 AP |
1380 | /* create regmap */ |
1381 | dev->regmap_config.reg_bits = 8, | |
1382 | dev->regmap_config.val_bits = 8, | |
1383 | dev->regmap_config.lock_arg = dev, | |
1384 | dev->regmap = devm_regmap_init_i2c(client, &dev->regmap_config); | |
1385 | if (IS_ERR(dev->regmap)) { | |
1386 | ret = PTR_ERR(dev->regmap); | |
1387 | goto err_kfree; | |
1388 | } | |
395d00d1 | 1389 | |
f4df95bc | 1390 | /* 0x00: chip id[6:0], 0x01: chip ver[7:0], 0x02: chip ver[15:8] */ |
478932b1 | 1391 | ret = regmap_read(dev->regmap, 0x00, &utmp); |
395d00d1 | 1392 | if (ret) |
f01919e8 | 1393 | goto err_kfree; |
395d00d1 | 1394 | |
478932b1 AP |
1395 | dev->chip_id = utmp >> 1; |
1396 | dev_dbg(&client->dev, "chip_id=%02x\n", dev->chip_id); | |
395d00d1 | 1397 | |
478932b1 | 1398 | switch (dev->chip_id) { |
f4df95bc | 1399 | case M88RS6000_CHIP_ID: |
1400 | case M88DS3103_CHIP_ID: | |
395d00d1 AP |
1401 | break; |
1402 | default: | |
b9c97c67 MCC |
1403 | ret = -ENODEV; |
1404 | dev_err(&client->dev, "Unknown device. Chip_id=%02x\n", dev->chip_id); | |
f01919e8 | 1405 | goto err_kfree; |
395d00d1 AP |
1406 | } |
1407 | ||
f01919e8 | 1408 | switch (dev->cfg->clock_out) { |
395d00d1 | 1409 | case M88DS3103_CLOCK_OUT_DISABLED: |
478932b1 | 1410 | utmp = 0x80; |
395d00d1 AP |
1411 | break; |
1412 | case M88DS3103_CLOCK_OUT_ENABLED: | |
478932b1 | 1413 | utmp = 0x00; |
395d00d1 AP |
1414 | break; |
1415 | case M88DS3103_CLOCK_OUT_ENABLED_DIV2: | |
478932b1 | 1416 | utmp = 0x10; |
395d00d1 AP |
1417 | break; |
1418 | default: | |
4347df6a | 1419 | ret = -EINVAL; |
f01919e8 | 1420 | goto err_kfree; |
395d00d1 AP |
1421 | } |
1422 | ||
334ef18e AP |
1423 | if (!pdata->ts_clk) { |
1424 | ret = -EINVAL; | |
1425 | goto err_kfree; | |
1426 | } | |
1427 | ||
f4df95bc | 1428 | /* 0x29 register is defined differently for m88rs6000. */ |
1429 | /* set internal tuner address to 0x21 */ | |
478932b1 AP |
1430 | if (dev->chip_id == M88RS6000_CHIP_ID) |
1431 | utmp = 0x00; | |
f4df95bc | 1432 | |
478932b1 | 1433 | ret = regmap_write(dev->regmap, 0x29, utmp); |
395d00d1 | 1434 | if (ret) |
f01919e8 | 1435 | goto err_kfree; |
395d00d1 AP |
1436 | |
1437 | /* sleep */ | |
56ea37da | 1438 | ret = m88ds3103_update_bits(dev, 0x08, 0x01, 0x00); |
395d00d1 | 1439 | if (ret) |
f01919e8 | 1440 | goto err_kfree; |
56ea37da | 1441 | ret = m88ds3103_update_bits(dev, 0x04, 0x01, 0x01); |
395d00d1 | 1442 | if (ret) |
f01919e8 | 1443 | goto err_kfree; |
56ea37da | 1444 | ret = m88ds3103_update_bits(dev, 0x23, 0x10, 0x10); |
395d00d1 | 1445 | if (ret) |
f01919e8 | 1446 | goto err_kfree; |
395d00d1 | 1447 | |
44b9055b | 1448 | /* create mux i2c adapter for tuner */ |
e00fed40 PR |
1449 | dev->muxc = i2c_mux_alloc(client->adapter, &client->dev, 1, 0, 0, |
1450 | m88ds3103_select, NULL); | |
1451 | if (!dev->muxc) { | |
4347df6a | 1452 | ret = -ENOMEM; |
f01919e8 | 1453 | goto err_kfree; |
4347df6a | 1454 | } |
e00fed40 PR |
1455 | dev->muxc->priv = dev; |
1456 | ret = i2c_mux_add_adapter(dev->muxc, 0, 0, 0); | |
1457 | if (ret) | |
1458 | goto err_kfree; | |
44b9055b | 1459 | |
395d00d1 | 1460 | /* create dvb_frontend */ |
f01919e8 AP |
1461 | memcpy(&dev->fe.ops, &m88ds3103_ops, sizeof(struct dvb_frontend_ops)); |
1462 | if (dev->chip_id == M88RS6000_CHIP_ID) | |
85709cbf | 1463 | strscpy(dev->fe.ops.info.name, "Montage Technology M88RS6000", |
7978b8a1 | 1464 | sizeof(dev->fe.ops.info.name)); |
f01919e8 AP |
1465 | if (!pdata->attach_in_use) |
1466 | dev->fe.ops.release = NULL; | |
1467 | dev->fe.demodulator_priv = dev; | |
1468 | i2c_set_clientdata(client, dev); | |
1469 | ||
1470 | /* setup callbacks */ | |
1471 | pdata->get_dvb_frontend = m88ds3103_get_dvb_frontend; | |
1472 | pdata->get_i2c_adapter = m88ds3103_get_i2c_adapter; | |
1473 | return 0; | |
1474 | err_kfree: | |
1475 | kfree(dev); | |
395d00d1 | 1476 | err: |
f01919e8 AP |
1477 | dev_dbg(&client->dev, "failed=%d\n", ret); |
1478 | return ret; | |
395d00d1 | 1479 | } |
395d00d1 | 1480 | |
f01919e8 AP |
1481 | static int m88ds3103_remove(struct i2c_client *client) |
1482 | { | |
7978b8a1 | 1483 | struct m88ds3103_dev *dev = i2c_get_clientdata(client); |
395d00d1 | 1484 | |
f01919e8 | 1485 | dev_dbg(&client->dev, "\n"); |
395d00d1 | 1486 | |
e00fed40 | 1487 | i2c_mux_del_adapters(dev->muxc); |
395d00d1 | 1488 | |
f01919e8 AP |
1489 | kfree(dev); |
1490 | return 0; | |
1491 | } | |
395d00d1 | 1492 | |
f01919e8 AP |
1493 | static const struct i2c_device_id m88ds3103_id_table[] = { |
1494 | {"m88ds3103", 0}, | |
1495 | {} | |
1496 | }; | |
1497 | MODULE_DEVICE_TABLE(i2c, m88ds3103_id_table); | |
395d00d1 | 1498 | |
f01919e8 AP |
1499 | static struct i2c_driver m88ds3103_driver = { |
1500 | .driver = { | |
f01919e8 AP |
1501 | .name = "m88ds3103", |
1502 | .suppress_bind_attrs = true, | |
1503 | }, | |
1504 | .probe = m88ds3103_probe, | |
1505 | .remove = m88ds3103_remove, | |
1506 | .id_table = m88ds3103_id_table, | |
395d00d1 AP |
1507 | }; |
1508 | ||
f01919e8 AP |
1509 | module_i2c_driver(m88ds3103_driver); |
1510 | ||
395d00d1 | 1511 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); |
7978b8a1 | 1512 | MODULE_DESCRIPTION("Montage Technology M88DS3103 DVB-S/S2 demodulator driver"); |
395d00d1 AP |
1513 | MODULE_LICENSE("GPL"); |
1514 | MODULE_FIRMWARE(M88DS3103_FIRMWARE); | |
f4df95bc | 1515 | MODULE_FIRMWARE(M88RS6000_FIRMWARE); |