1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Elonics E4000 silicon tuner driver |
4 | * |
5 | * Copyright (C) 2012 Antti Palosaari <crope@iki.fi> |
6 | */ |
7 | |
8 | #include "e4000_priv.h" |
9 | |
10 | static int e4000_init(struct e4000_dev *dev) |
11 | { |
12 | struct i2c_client *client = dev->client; |
13 | int ret; |
14 | |
15 | dev_dbg(&client->dev, "\n" ); |
16 | |
17 | /* reset */ |
18 | ret = regmap_write(map: dev->regmap, reg: 0x00, val: 0x01); |
19 | if (ret) |
20 | goto err; |
21 | |
22 | /* disable output clock */ |
23 | ret = regmap_write(map: dev->regmap, reg: 0x06, val: 0x00); |
24 | if (ret) |
25 | goto err; |
26 | |
27 | ret = regmap_write(map: dev->regmap, reg: 0x7a, val: 0x96); |
28 | if (ret) |
29 | goto err; |
30 | |
31 | /* configure gains */ |
32 | ret = regmap_bulk_write(map: dev->regmap, reg: 0x7e, val: "\x01\xfe" , val_count: 2); |
33 | if (ret) |
34 | goto err; |
35 | |
36 | ret = regmap_write(map: dev->regmap, reg: 0x82, val: 0x00); |
37 | if (ret) |
38 | goto err; |
39 | |
40 | ret = regmap_write(map: dev->regmap, reg: 0x24, val: 0x05); |
41 | if (ret) |
42 | goto err; |
43 | |
44 | ret = regmap_bulk_write(map: dev->regmap, reg: 0x87, val: "\x20\x01" , val_count: 2); |
45 | if (ret) |
46 | goto err; |
47 | |
48 | ret = regmap_bulk_write(map: dev->regmap, reg: 0x9f, val: "\x7f\x07" , val_count: 2); |
49 | if (ret) |
50 | goto err; |
51 | |
52 | /* DC offset control */ |
53 | ret = regmap_write(map: dev->regmap, reg: 0x2d, val: 0x1f); |
54 | if (ret) |
55 | goto err; |
56 | |
57 | ret = regmap_bulk_write(map: dev->regmap, reg: 0x70, val: "\x01\x01" , val_count: 2); |
58 | if (ret) |
59 | goto err; |
60 | |
61 | /* gain control */ |
62 | ret = regmap_write(map: dev->regmap, reg: 0x1a, val: 0x17); |
63 | if (ret) |
64 | goto err; |
65 | |
66 | ret = regmap_write(map: dev->regmap, reg: 0x1f, val: 0x1a); |
67 | if (ret) |
68 | goto err; |
69 | |
70 | dev->active = true; |
71 | |
72 | return 0; |
73 | err: |
74 | dev_dbg(&client->dev, "failed=%d\n" , ret); |
75 | return ret; |
76 | } |
77 | |
78 | static int e4000_sleep(struct e4000_dev *dev) |
79 | { |
80 | struct i2c_client *client = dev->client; |
81 | int ret; |
82 | |
83 | dev_dbg(&client->dev, "\n" ); |
84 | |
85 | dev->active = false; |
86 | |
87 | ret = regmap_write(map: dev->regmap, reg: 0x00, val: 0x00); |
88 | if (ret) |
89 | goto err; |
90 | |
91 | return 0; |
92 | err: |
93 | dev_dbg(&client->dev, "failed=%d\n" , ret); |
94 | return ret; |
95 | } |
96 | |
97 | static int e4000_set_params(struct e4000_dev *dev) |
98 | { |
99 | struct i2c_client *client = dev->client; |
100 | int ret, i; |
101 | unsigned int div_n, k, k_cw, div_out; |
102 | u64 f_vco; |
103 | u8 buf[5], i_data[4], q_data[4]; |
104 | |
105 | if (!dev->active) { |
106 | dev_dbg(&client->dev, "tuner is sleeping\n" ); |
107 | return 0; |
108 | } |
109 | |
110 | /* gain control manual */ |
111 | ret = regmap_write(map: dev->regmap, reg: 0x1a, val: 0x00); |
112 | if (ret) |
113 | goto err; |
114 | |
115 | /* |
116 | * Fractional-N synthesizer |
117 | * |
118 | * +----------------------------+ |
119 | * v | |
120 | * Fref +----+ +-------+ +------+ +---+ |
121 | * ------> | PD | --> | VCO | ------> | /N.F | <-- | K | |
122 | * +----+ +-------+ +------+ +---+ |
123 | * | |
124 | * | |
125 | * v |
126 | * +-------+ Fout |
127 | * | /Rout | ------> |
128 | * +-------+ |
129 | */ |
130 | for (i = 0; i < ARRAY_SIZE(e4000_pll_lut); i++) { |
131 | if (dev->f_frequency <= e4000_pll_lut[i].freq) |
132 | break; |
133 | } |
134 | if (i == ARRAY_SIZE(e4000_pll_lut)) { |
135 | ret = -EINVAL; |
136 | goto err; |
137 | } |
138 | |
139 | #define F_REF dev->clk |
140 | div_out = e4000_pll_lut[i].div_out; |
141 | f_vco = (u64) dev->f_frequency * div_out; |
142 | /* calculate PLL integer and fractional control word */ |
143 | div_n = div_u64_rem(dividend: f_vco, F_REF, remainder: &k); |
144 | k_cw = div_u64(dividend: (u64) k * 0x10000, F_REF); |
145 | |
146 | dev_dbg(&client->dev, |
147 | "frequency=%u bandwidth=%u f_vco=%llu F_REF=%u div_n=%u k=%u k_cw=%04x div_out=%u\n" , |
148 | dev->f_frequency, dev->f_bandwidth, f_vco, F_REF, div_n, k, |
149 | k_cw, div_out); |
150 | |
151 | buf[0] = div_n; |
152 | buf[1] = (k_cw >> 0) & 0xff; |
153 | buf[2] = (k_cw >> 8) & 0xff; |
154 | buf[3] = 0x00; |
155 | buf[4] = e4000_pll_lut[i].div_out_reg; |
156 | ret = regmap_bulk_write(map: dev->regmap, reg: 0x09, val: buf, val_count: 5); |
157 | if (ret) |
158 | goto err; |
159 | |
160 | /* LNA filter (RF filter) */ |
161 | for (i = 0; i < ARRAY_SIZE(e400_lna_filter_lut); i++) { |
162 | if (dev->f_frequency <= e400_lna_filter_lut[i].freq) |
163 | break; |
164 | } |
165 | if (i == ARRAY_SIZE(e400_lna_filter_lut)) { |
166 | ret = -EINVAL; |
167 | goto err; |
168 | } |
169 | |
170 | ret = regmap_write(map: dev->regmap, reg: 0x10, val: e400_lna_filter_lut[i].val); |
171 | if (ret) |
172 | goto err; |
173 | |
174 | /* IF filters */ |
175 | for (i = 0; i < ARRAY_SIZE(e4000_if_filter_lut); i++) { |
176 | if (dev->f_bandwidth <= e4000_if_filter_lut[i].freq) |
177 | break; |
178 | } |
179 | if (i == ARRAY_SIZE(e4000_if_filter_lut)) { |
180 | ret = -EINVAL; |
181 | goto err; |
182 | } |
183 | |
184 | buf[0] = e4000_if_filter_lut[i].reg11_val; |
185 | buf[1] = e4000_if_filter_lut[i].reg12_val; |
186 | |
187 | ret = regmap_bulk_write(map: dev->regmap, reg: 0x11, val: buf, val_count: 2); |
188 | if (ret) |
189 | goto err; |
190 | |
191 | /* frequency band */ |
192 | for (i = 0; i < ARRAY_SIZE(e4000_band_lut); i++) { |
193 | if (dev->f_frequency <= e4000_band_lut[i].freq) |
194 | break; |
195 | } |
196 | if (i == ARRAY_SIZE(e4000_band_lut)) { |
197 | ret = -EINVAL; |
198 | goto err; |
199 | } |
200 | |
201 | ret = regmap_write(map: dev->regmap, reg: 0x07, val: e4000_band_lut[i].reg07_val); |
202 | if (ret) |
203 | goto err; |
204 | |
205 | ret = regmap_write(map: dev->regmap, reg: 0x78, val: e4000_band_lut[i].reg78_val); |
206 | if (ret) |
207 | goto err; |
208 | |
209 | /* DC offset */ |
210 | for (i = 0; i < 4; i++) { |
211 | if (i == 0) |
212 | ret = regmap_bulk_write(map: dev->regmap, reg: 0x15, val: "\x00\x7e\x24" , val_count: 3); |
213 | else if (i == 1) |
214 | ret = regmap_bulk_write(map: dev->regmap, reg: 0x15, val: "\x00\x7f" , val_count: 2); |
215 | else if (i == 2) |
216 | ret = regmap_bulk_write(map: dev->regmap, reg: 0x15, val: "\x01" , val_count: 1); |
217 | else |
218 | ret = regmap_bulk_write(map: dev->regmap, reg: 0x16, val: "\x7e" , val_count: 1); |
219 | |
220 | if (ret) |
221 | goto err; |
222 | |
223 | ret = regmap_write(map: dev->regmap, reg: 0x29, val: 0x01); |
224 | if (ret) |
225 | goto err; |
226 | |
227 | ret = regmap_bulk_read(map: dev->regmap, reg: 0x2a, val: buf, val_count: 3); |
228 | if (ret) |
229 | goto err; |
230 | |
231 | i_data[i] = (((buf[2] >> 0) & 0x3) << 6) | (buf[0] & 0x3f); |
232 | q_data[i] = (((buf[2] >> 4) & 0x3) << 6) | (buf[1] & 0x3f); |
233 | } |
234 | |
235 | swap(q_data[2], q_data[3]); |
236 | swap(i_data[2], i_data[3]); |
237 | |
238 | ret = regmap_bulk_write(map: dev->regmap, reg: 0x50, val: q_data, val_count: 4); |
239 | if (ret) |
240 | goto err; |
241 | |
242 | ret = regmap_bulk_write(map: dev->regmap, reg: 0x60, val: i_data, val_count: 4); |
243 | if (ret) |
244 | goto err; |
245 | |
246 | /* gain control auto */ |
247 | ret = regmap_write(map: dev->regmap, reg: 0x1a, val: 0x17); |
248 | if (ret) |
249 | goto err; |
250 | |
251 | return 0; |
252 | err: |
253 | dev_dbg(&client->dev, "failed=%d\n" , ret); |
254 | return ret; |
255 | } |
256 | |
257 | /* |
258 | * V4L2 API |
259 | */ |
260 | #if IS_ENABLED(CONFIG_VIDEO_DEV) |
261 | static const struct v4l2_frequency_band bands[] = { |
262 | { |
263 | .type = V4L2_TUNER_RF, |
264 | .index = 0, |
265 | .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, |
266 | .rangelow = 59000000, |
267 | .rangehigh = 1105000000, |
268 | }, |
269 | { |
270 | .type = V4L2_TUNER_RF, |
271 | .index = 1, |
272 | .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, |
273 | .rangelow = 1249000000, |
274 | .rangehigh = 2208000000UL, |
275 | }, |
276 | }; |
277 | |
278 | static inline struct e4000_dev *e4000_subdev_to_dev(struct v4l2_subdev *sd) |
279 | { |
280 | return container_of(sd, struct e4000_dev, sd); |
281 | } |
282 | |
283 | static int e4000_standby(struct v4l2_subdev *sd) |
284 | { |
285 | struct e4000_dev *dev = e4000_subdev_to_dev(sd); |
286 | int ret; |
287 | |
288 | ret = e4000_sleep(dev); |
289 | if (ret) |
290 | return ret; |
291 | |
292 | return e4000_set_params(dev); |
293 | } |
294 | |
295 | static int e4000_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) |
296 | { |
297 | struct e4000_dev *dev = e4000_subdev_to_dev(sd); |
298 | struct i2c_client *client = dev->client; |
299 | |
300 | dev_dbg(&client->dev, "index=%d\n" , v->index); |
301 | |
302 | strscpy(p: v->name, q: "Elonics E4000" , size: sizeof(v->name)); |
303 | v->type = V4L2_TUNER_RF; |
304 | v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; |
305 | v->rangelow = bands[0].rangelow; |
306 | v->rangehigh = bands[1].rangehigh; |
307 | return 0; |
308 | } |
309 | |
310 | static int e4000_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *v) |
311 | { |
312 | struct e4000_dev *dev = e4000_subdev_to_dev(sd); |
313 | struct i2c_client *client = dev->client; |
314 | |
315 | dev_dbg(&client->dev, "index=%d\n" , v->index); |
316 | return 0; |
317 | } |
318 | |
319 | static int e4000_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) |
320 | { |
321 | struct e4000_dev *dev = e4000_subdev_to_dev(sd); |
322 | struct i2c_client *client = dev->client; |
323 | |
324 | dev_dbg(&client->dev, "tuner=%d\n" , f->tuner); |
325 | f->frequency = dev->f_frequency; |
326 | return 0; |
327 | } |
328 | |
329 | static int e4000_s_frequency(struct v4l2_subdev *sd, |
330 | const struct v4l2_frequency *f) |
331 | { |
332 | struct e4000_dev *dev = e4000_subdev_to_dev(sd); |
333 | struct i2c_client *client = dev->client; |
334 | |
335 | dev_dbg(&client->dev, "tuner=%d type=%d frequency=%u\n" , |
336 | f->tuner, f->type, f->frequency); |
337 | |
338 | dev->f_frequency = clamp_t(unsigned int, f->frequency, |
339 | bands[0].rangelow, bands[1].rangehigh); |
340 | return e4000_set_params(dev); |
341 | } |
342 | |
343 | static int e4000_enum_freq_bands(struct v4l2_subdev *sd, |
344 | struct v4l2_frequency_band *band) |
345 | { |
346 | struct e4000_dev *dev = e4000_subdev_to_dev(sd); |
347 | struct i2c_client *client = dev->client; |
348 | |
349 | dev_dbg(&client->dev, "tuner=%d type=%d index=%d\n" , |
350 | band->tuner, band->type, band->index); |
351 | |
352 | if (band->index >= ARRAY_SIZE(bands)) |
353 | return -EINVAL; |
354 | |
355 | band->capability = bands[band->index].capability; |
356 | band->rangelow = bands[band->index].rangelow; |
357 | band->rangehigh = bands[band->index].rangehigh; |
358 | return 0; |
359 | } |
360 | |
361 | static const struct v4l2_subdev_tuner_ops e4000_subdev_tuner_ops = { |
362 | .standby = e4000_standby, |
363 | .g_tuner = e4000_g_tuner, |
364 | .s_tuner = e4000_s_tuner, |
365 | .g_frequency = e4000_g_frequency, |
366 | .s_frequency = e4000_s_frequency, |
367 | .enum_freq_bands = e4000_enum_freq_bands, |
368 | }; |
369 | |
370 | static const struct v4l2_subdev_ops e4000_subdev_ops = { |
371 | .tuner = &e4000_subdev_tuner_ops, |
372 | }; |
373 | |
374 | static int e4000_set_lna_gain(struct dvb_frontend *fe) |
375 | { |
376 | struct e4000_dev *dev = fe->tuner_priv; |
377 | struct i2c_client *client = dev->client; |
378 | int ret; |
379 | u8 u8tmp; |
380 | |
381 | dev_dbg(&client->dev, "lna auto=%d->%d val=%d->%d\n" , |
382 | dev->lna_gain_auto->cur.val, dev->lna_gain_auto->val, |
383 | dev->lna_gain->cur.val, dev->lna_gain->val); |
384 | |
385 | if (dev->lna_gain_auto->val && dev->if_gain_auto->cur.val) |
386 | u8tmp = 0x17; |
387 | else if (dev->lna_gain_auto->val) |
388 | u8tmp = 0x19; |
389 | else if (dev->if_gain_auto->cur.val) |
390 | u8tmp = 0x16; |
391 | else |
392 | u8tmp = 0x10; |
393 | |
394 | ret = regmap_write(map: dev->regmap, reg: 0x1a, val: u8tmp); |
395 | if (ret) |
396 | goto err; |
397 | |
398 | if (dev->lna_gain_auto->val == false) { |
399 | ret = regmap_write(map: dev->regmap, reg: 0x14, val: dev->lna_gain->val); |
400 | if (ret) |
401 | goto err; |
402 | } |
403 | |
404 | return 0; |
405 | err: |
406 | dev_dbg(&client->dev, "failed=%d\n" , ret); |
407 | return ret; |
408 | } |
409 | |
410 | static int e4000_set_mixer_gain(struct dvb_frontend *fe) |
411 | { |
412 | struct e4000_dev *dev = fe->tuner_priv; |
413 | struct i2c_client *client = dev->client; |
414 | int ret; |
415 | u8 u8tmp; |
416 | |
417 | dev_dbg(&client->dev, "mixer auto=%d->%d val=%d->%d\n" , |
418 | dev->mixer_gain_auto->cur.val, dev->mixer_gain_auto->val, |
419 | dev->mixer_gain->cur.val, dev->mixer_gain->val); |
420 | |
421 | if (dev->mixer_gain_auto->val) |
422 | u8tmp = 0x15; |
423 | else |
424 | u8tmp = 0x14; |
425 | |
426 | ret = regmap_write(map: dev->regmap, reg: 0x20, val: u8tmp); |
427 | if (ret) |
428 | goto err; |
429 | |
430 | if (dev->mixer_gain_auto->val == false) { |
431 | ret = regmap_write(map: dev->regmap, reg: 0x15, val: dev->mixer_gain->val); |
432 | if (ret) |
433 | goto err; |
434 | } |
435 | |
436 | return 0; |
437 | err: |
438 | dev_dbg(&client->dev, "failed=%d\n" , ret); |
439 | return ret; |
440 | } |
441 | |
442 | static int e4000_set_if_gain(struct dvb_frontend *fe) |
443 | { |
444 | struct e4000_dev *dev = fe->tuner_priv; |
445 | struct i2c_client *client = dev->client; |
446 | int ret; |
447 | u8 buf[2]; |
448 | u8 u8tmp; |
449 | |
450 | dev_dbg(&client->dev, "if auto=%d->%d val=%d->%d\n" , |
451 | dev->if_gain_auto->cur.val, dev->if_gain_auto->val, |
452 | dev->if_gain->cur.val, dev->if_gain->val); |
453 | |
454 | if (dev->if_gain_auto->val && dev->lna_gain_auto->cur.val) |
455 | u8tmp = 0x17; |
456 | else if (dev->lna_gain_auto->cur.val) |
457 | u8tmp = 0x19; |
458 | else if (dev->if_gain_auto->val) |
459 | u8tmp = 0x16; |
460 | else |
461 | u8tmp = 0x10; |
462 | |
463 | ret = regmap_write(map: dev->regmap, reg: 0x1a, val: u8tmp); |
464 | if (ret) |
465 | goto err; |
466 | |
467 | if (dev->if_gain_auto->val == false) { |
468 | buf[0] = e4000_if_gain_lut[dev->if_gain->val].reg16_val; |
469 | buf[1] = e4000_if_gain_lut[dev->if_gain->val].reg17_val; |
470 | ret = regmap_bulk_write(map: dev->regmap, reg: 0x16, val: buf, val_count: 2); |
471 | if (ret) |
472 | goto err; |
473 | } |
474 | |
475 | return 0; |
476 | err: |
477 | dev_dbg(&client->dev, "failed=%d\n" , ret); |
478 | return ret; |
479 | } |
480 | |
481 | static int e4000_pll_lock(struct dvb_frontend *fe) |
482 | { |
483 | struct e4000_dev *dev = fe->tuner_priv; |
484 | struct i2c_client *client = dev->client; |
485 | int ret; |
486 | unsigned int uitmp; |
487 | |
488 | ret = regmap_read(map: dev->regmap, reg: 0x07, val: &uitmp); |
489 | if (ret) |
490 | goto err; |
491 | |
492 | dev->pll_lock->val = (uitmp & 0x01); |
493 | |
494 | return 0; |
495 | err: |
496 | dev_dbg(&client->dev, "failed=%d\n" , ret); |
497 | return ret; |
498 | } |
499 | |
500 | static int e4000_g_volatile_ctrl(struct v4l2_ctrl *ctrl) |
501 | { |
502 | struct e4000_dev *dev = container_of(ctrl->handler, struct e4000_dev, hdl); |
503 | struct i2c_client *client = dev->client; |
504 | int ret; |
505 | |
506 | if (!dev->active) |
507 | return 0; |
508 | |
509 | switch (ctrl->id) { |
510 | case V4L2_CID_RF_TUNER_PLL_LOCK: |
511 | ret = e4000_pll_lock(fe: dev->fe); |
512 | break; |
513 | default: |
514 | dev_dbg(&client->dev, "unknown ctrl: id=%d name=%s\n" , |
515 | ctrl->id, ctrl->name); |
516 | ret = -EINVAL; |
517 | } |
518 | |
519 | return ret; |
520 | } |
521 | |
522 | static int e4000_s_ctrl(struct v4l2_ctrl *ctrl) |
523 | { |
524 | struct e4000_dev *dev = container_of(ctrl->handler, struct e4000_dev, hdl); |
525 | struct i2c_client *client = dev->client; |
526 | int ret; |
527 | |
528 | if (!dev->active) |
529 | return 0; |
530 | |
531 | switch (ctrl->id) { |
532 | case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: |
533 | case V4L2_CID_RF_TUNER_BANDWIDTH: |
534 | /* |
535 | * TODO: Auto logic does not work 100% correctly as tuner driver |
536 | * do not have information to calculate maximum suitable |
537 | * bandwidth. Calculating it is responsible of master driver. |
538 | */ |
539 | dev->f_bandwidth = dev->bandwidth->val; |
540 | ret = e4000_set_params(dev); |
541 | break; |
542 | case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO: |
543 | case V4L2_CID_RF_TUNER_LNA_GAIN: |
544 | ret = e4000_set_lna_gain(fe: dev->fe); |
545 | break; |
546 | case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO: |
547 | case V4L2_CID_RF_TUNER_MIXER_GAIN: |
548 | ret = e4000_set_mixer_gain(fe: dev->fe); |
549 | break; |
550 | case V4L2_CID_RF_TUNER_IF_GAIN_AUTO: |
551 | case V4L2_CID_RF_TUNER_IF_GAIN: |
552 | ret = e4000_set_if_gain(fe: dev->fe); |
553 | break; |
554 | default: |
555 | dev_dbg(&client->dev, "unknown ctrl: id=%d name=%s\n" , |
556 | ctrl->id, ctrl->name); |
557 | ret = -EINVAL; |
558 | } |
559 | |
560 | return ret; |
561 | } |
562 | |
563 | static const struct v4l2_ctrl_ops e4000_ctrl_ops = { |
564 | .g_volatile_ctrl = e4000_g_volatile_ctrl, |
565 | .s_ctrl = e4000_s_ctrl, |
566 | }; |
567 | #endif |
568 | |
569 | /* |
570 | * DVB API |
571 | */ |
572 | static int e4000_dvb_set_params(struct dvb_frontend *fe) |
573 | { |
574 | struct e4000_dev *dev = fe->tuner_priv; |
575 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
576 | |
577 | dev->f_frequency = c->frequency; |
578 | dev->f_bandwidth = c->bandwidth_hz; |
579 | return e4000_set_params(dev); |
580 | } |
581 | |
582 | static int e4000_dvb_init(struct dvb_frontend *fe) |
583 | { |
584 | return e4000_init(dev: fe->tuner_priv); |
585 | } |
586 | |
587 | static int e4000_dvb_sleep(struct dvb_frontend *fe) |
588 | { |
589 | return e4000_sleep(dev: fe->tuner_priv); |
590 | } |
591 | |
592 | static int e4000_dvb_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) |
593 | { |
594 | *frequency = 0; /* Zero-IF */ |
595 | return 0; |
596 | } |
597 | |
598 | static const struct dvb_tuner_ops e4000_dvb_tuner_ops = { |
599 | .info = { |
600 | .name = "Elonics E4000" , |
601 | .frequency_min_hz = 174 * MHz, |
602 | .frequency_max_hz = 862 * MHz, |
603 | }, |
604 | |
605 | .init = e4000_dvb_init, |
606 | .sleep = e4000_dvb_sleep, |
607 | .set_params = e4000_dvb_set_params, |
608 | |
609 | .get_if_frequency = e4000_dvb_get_if_frequency, |
610 | }; |
611 | |
612 | static int e4000_probe(struct i2c_client *client) |
613 | { |
614 | struct e4000_dev *dev; |
615 | struct e4000_config *cfg = client->dev.platform_data; |
616 | struct dvb_frontend *fe = cfg->fe; |
617 | int ret; |
618 | unsigned int uitmp; |
619 | static const struct regmap_config regmap_config = { |
620 | .reg_bits = 8, |
621 | .val_bits = 8, |
622 | }; |
623 | |
624 | dev = kzalloc(size: sizeof(*dev), GFP_KERNEL); |
625 | if (!dev) { |
626 | ret = -ENOMEM; |
627 | goto err; |
628 | } |
629 | |
630 | dev->clk = cfg->clock; |
631 | dev->client = client; |
632 | dev->fe = cfg->fe; |
633 | dev->regmap = devm_regmap_init_i2c(client, ®map_config); |
634 | if (IS_ERR(ptr: dev->regmap)) { |
635 | ret = PTR_ERR(ptr: dev->regmap); |
636 | goto err_kfree; |
637 | } |
638 | |
639 | /* check if the tuner is there */ |
640 | ret = regmap_read(map: dev->regmap, reg: 0x02, val: &uitmp); |
641 | if (ret) |
642 | goto err_kfree; |
643 | |
644 | dev_dbg(&client->dev, "chip id=%02x\n" , uitmp); |
645 | |
646 | if (uitmp != 0x40) { |
647 | ret = -ENODEV; |
648 | goto err_kfree; |
649 | } |
650 | |
651 | /* put sleep as chip seems to be in normal mode by default */ |
652 | ret = regmap_write(map: dev->regmap, reg: 0x00, val: 0x00); |
653 | if (ret) |
654 | goto err_kfree; |
655 | |
656 | #if IS_ENABLED(CONFIG_VIDEO_DEV) |
657 | /* Register controls */ |
658 | v4l2_ctrl_handler_init(&dev->hdl, 9); |
659 | dev->bandwidth_auto = v4l2_ctrl_new_std(hdl: &dev->hdl, ops: &e4000_ctrl_ops, |
660 | V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, min: 0, max: 1, step: 1, def: 1); |
661 | dev->bandwidth = v4l2_ctrl_new_std(hdl: &dev->hdl, ops: &e4000_ctrl_ops, |
662 | V4L2_CID_RF_TUNER_BANDWIDTH, min: 4300000, max: 11000000, step: 100000, def: 4300000); |
663 | v4l2_ctrl_auto_cluster(ncontrols: 2, controls: &dev->bandwidth_auto, manual_val: 0, set_volatile: false); |
664 | dev->lna_gain_auto = v4l2_ctrl_new_std(hdl: &dev->hdl, ops: &e4000_ctrl_ops, |
665 | V4L2_CID_RF_TUNER_LNA_GAIN_AUTO, min: 0, max: 1, step: 1, def: 1); |
666 | dev->lna_gain = v4l2_ctrl_new_std(hdl: &dev->hdl, ops: &e4000_ctrl_ops, |
667 | V4L2_CID_RF_TUNER_LNA_GAIN, min: 0, max: 15, step: 1, def: 10); |
668 | v4l2_ctrl_auto_cluster(ncontrols: 2, controls: &dev->lna_gain_auto, manual_val: 0, set_volatile: false); |
669 | dev->mixer_gain_auto = v4l2_ctrl_new_std(hdl: &dev->hdl, ops: &e4000_ctrl_ops, |
670 | V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO, min: 0, max: 1, step: 1, def: 1); |
671 | dev->mixer_gain = v4l2_ctrl_new_std(hdl: &dev->hdl, ops: &e4000_ctrl_ops, |
672 | V4L2_CID_RF_TUNER_MIXER_GAIN, min: 0, max: 1, step: 1, def: 1); |
673 | v4l2_ctrl_auto_cluster(ncontrols: 2, controls: &dev->mixer_gain_auto, manual_val: 0, set_volatile: false); |
674 | dev->if_gain_auto = v4l2_ctrl_new_std(hdl: &dev->hdl, ops: &e4000_ctrl_ops, |
675 | V4L2_CID_RF_TUNER_IF_GAIN_AUTO, min: 0, max: 1, step: 1, def: 1); |
676 | dev->if_gain = v4l2_ctrl_new_std(hdl: &dev->hdl, ops: &e4000_ctrl_ops, |
677 | V4L2_CID_RF_TUNER_IF_GAIN, min: 0, max: 54, step: 1, def: 0); |
678 | v4l2_ctrl_auto_cluster(ncontrols: 2, controls: &dev->if_gain_auto, manual_val: 0, set_volatile: false); |
679 | dev->pll_lock = v4l2_ctrl_new_std(hdl: &dev->hdl, ops: &e4000_ctrl_ops, |
680 | V4L2_CID_RF_TUNER_PLL_LOCK, min: 0, max: 1, step: 1, def: 0); |
681 | if (dev->hdl.error) { |
682 | ret = dev->hdl.error; |
683 | dev_err(&client->dev, "Could not initialize controls\n" ); |
684 | v4l2_ctrl_handler_free(hdl: &dev->hdl); |
685 | goto err_kfree; |
686 | } |
687 | |
688 | dev->sd.ctrl_handler = &dev->hdl; |
689 | dev->f_frequency = bands[0].rangelow; |
690 | dev->f_bandwidth = dev->bandwidth->val; |
691 | v4l2_i2c_subdev_init(sd: &dev->sd, client, ops: &e4000_subdev_ops); |
692 | #endif |
693 | fe->tuner_priv = dev; |
694 | memcpy(&fe->ops.tuner_ops, &e4000_dvb_tuner_ops, |
695 | sizeof(fe->ops.tuner_ops)); |
696 | v4l2_set_subdevdata(sd: &dev->sd, p: client); |
697 | i2c_set_clientdata(client, data: &dev->sd); |
698 | |
699 | dev_info(&client->dev, "Elonics E4000 successfully identified\n" ); |
700 | return 0; |
701 | err_kfree: |
702 | kfree(objp: dev); |
703 | err: |
704 | dev_dbg(&client->dev, "failed=%d\n" , ret); |
705 | return ret; |
706 | } |
707 | |
708 | static void e4000_remove(struct i2c_client *client) |
709 | { |
710 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
711 | struct e4000_dev *dev = container_of(sd, struct e4000_dev, sd); |
712 | |
713 | dev_dbg(&client->dev, "\n" ); |
714 | |
715 | #if IS_ENABLED(CONFIG_VIDEO_DEV) |
716 | v4l2_ctrl_handler_free(hdl: &dev->hdl); |
717 | #endif |
718 | kfree(objp: dev); |
719 | } |
720 | |
721 | static const struct i2c_device_id e4000_id_table[] = { |
722 | {"e4000" , 0}, |
723 | {} |
724 | }; |
725 | MODULE_DEVICE_TABLE(i2c, e4000_id_table); |
726 | |
727 | static struct i2c_driver e4000_driver = { |
728 | .driver = { |
729 | .name = "e4000" , |
730 | .suppress_bind_attrs = true, |
731 | }, |
732 | .probe = e4000_probe, |
733 | .remove = e4000_remove, |
734 | .id_table = e4000_id_table, |
735 | }; |
736 | |
737 | module_i2c_driver(e4000_driver); |
738 | |
739 | MODULE_DESCRIPTION("Elonics E4000 silicon tuner driver" ); |
740 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>" ); |
741 | MODULE_LICENSE("GPL" ); |
742 | |