Merge tag 'docs-5.15' of git://git.lwn.net/linux
[linux-2.6-microblaze.git] / drivers / media / dvb-frontends / cx24113.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  Driver for Conexant CX24113/CX24128 Tuner (Satellite)
4  *
5  *  Copyright (C) 2007-8 Patrick Boettcher <pb@linuxtv.org>
6  *
7  *  Developed for BBTI / Technisat
8  */
9
10 #include <linux/slab.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/init.h>
14
15 #include <media/dvb_frontend.h>
16 #include "cx24113.h"
17
18 static int debug;
19
20 #define cx_info(args...) do { printk(KERN_INFO "CX24113: " args); } while (0)
21 #define cx_err(args...)  do { printk(KERN_ERR  "CX24113: " args); } while (0)
22
23 #define dprintk(args...) \
24         do { \
25                 if (debug) { \
26                         printk(KERN_DEBUG "CX24113: %s: ", __func__); \
27                         printk(args); \
28                 } \
29         } while (0)
30
31 struct cx24113_state {
32         struct i2c_adapter *i2c;
33         const struct cx24113_config *config;
34
35 #define REV_CX24113 0x23
36         u8 rev;
37         u8 ver;
38
39         u8 icp_mode:1;
40
41 #define ICP_LEVEL1 0
42 #define ICP_LEVEL2 1
43 #define ICP_LEVEL3 2
44 #define ICP_LEVEL4 3
45         u8 icp_man:2;
46         u8 icp_auto_low:2;
47         u8 icp_auto_mlow:2;
48         u8 icp_auto_mhi:2;
49         u8 icp_auto_hi:2;
50         u8 icp_dig;
51
52 #define LNA_MIN_GAIN 0
53 #define LNA_MID_GAIN 1
54 #define LNA_MAX_GAIN 2
55         u8 lna_gain:2;
56
57         u8 acp_on:1;
58
59         u8 vco_mode:2;
60         u8 vco_shift:1;
61 #define VCOBANDSEL_6 0x80
62 #define VCOBANDSEL_5 0x01
63 #define VCOBANDSEL_4 0x02
64 #define VCOBANDSEL_3 0x04
65 #define VCOBANDSEL_2 0x08
66 #define VCOBANDSEL_1 0x10
67         u8 vco_band;
68
69 #define VCODIV4 4
70 #define VCODIV2 2
71         u8 vcodiv;
72
73         u8 bs_delay:4;
74         u16 bs_freqcnt:13;
75         u16 bs_rdiv;
76         u8 prescaler_mode:1;
77
78         u8 rfvga_bias_ctrl;
79
80         s16 tuner_gain_thres;
81         u8  gain_level;
82
83         u32 frequency;
84
85         u8 refdiv;
86
87         u8 Fwindow_enabled;
88 };
89
90 static int cx24113_writereg(struct cx24113_state *state, int reg, int data)
91 {
92         u8 buf[] = { reg, data };
93         struct i2c_msg msg = { .addr = state->config->i2c_addr,
94                 .flags = 0, .buf = buf, .len = 2 };
95         int err = i2c_transfer(state->i2c, &msg, 1);
96         if (err != 1) {
97                 printk(KERN_DEBUG "%s: writereg error(err == %i, reg == 0x%02x, data == 0x%02x)\n",
98                        __func__, err, reg, data);
99                 return err;
100         }
101
102         return 0;
103 }
104
105 static int cx24113_readreg(struct cx24113_state *state, u8 reg)
106 {
107         int ret;
108         u8 b;
109         struct i2c_msg msg[] = {
110                 { .addr = state->config->i2c_addr,
111                         .flags = 0, .buf = &reg, .len = 1 },
112                 { .addr = state->config->i2c_addr,
113                         .flags = I2C_M_RD, .buf = &b, .len = 1 }
114         };
115
116         ret = i2c_transfer(state->i2c, msg, 2);
117
118         if (ret != 2) {
119                 printk(KERN_DEBUG "%s: reg=0x%x (error=%d)\n",
120                         __func__, reg, ret);
121                 return ret;
122         }
123
124         return b;
125 }
126
127 static void cx24113_set_parameters(struct cx24113_state *state)
128 {
129         u8 r;
130
131         r = cx24113_readreg(state, 0x10) & 0x82;
132         r |= state->icp_mode;
133         r |= state->icp_man << 4;
134         r |= state->icp_dig << 2;
135         r |= state->prescaler_mode << 5;
136         cx24113_writereg(state, 0x10, r);
137
138         r = (state->icp_auto_low  << 0) | (state->icp_auto_mlow << 2)
139                 | (state->icp_auto_mhi << 4) | (state->icp_auto_hi << 6);
140         cx24113_writereg(state, 0x11, r);
141
142         if (state->rev == REV_CX24113) {
143                 r = cx24113_readreg(state, 0x20) & 0xec;
144                 r |= state->lna_gain;
145                 r |= state->rfvga_bias_ctrl << 4;
146                 cx24113_writereg(state, 0x20, r);
147         }
148
149         r = cx24113_readreg(state, 0x12) & 0x03;
150         r |= state->acp_on << 2;
151         r |= state->bs_delay << 4;
152         cx24113_writereg(state, 0x12, r);
153
154         r = cx24113_readreg(state, 0x18) & 0x40;
155         r |= state->vco_shift;
156         if (state->vco_band == VCOBANDSEL_6)
157                 r |= (1 << 7);
158         else
159                 r |= (state->vco_band << 1);
160         cx24113_writereg(state, 0x18, r);
161
162         r  = cx24113_readreg(state, 0x14) & 0x20;
163         r |= (state->vco_mode << 6) | ((state->bs_freqcnt >> 8) & 0x1f);
164         cx24113_writereg(state, 0x14, r);
165         cx24113_writereg(state, 0x15, (state->bs_freqcnt        & 0xff));
166
167         cx24113_writereg(state, 0x16, (state->bs_rdiv >> 4) & 0xff);
168         r = (cx24113_readreg(state, 0x17) & 0x0f) |
169                 ((state->bs_rdiv & 0x0f) << 4);
170         cx24113_writereg(state, 0x17, r);
171 }
172
173 #define VGA_0 0x00
174 #define VGA_1 0x04
175 #define VGA_2 0x02
176 #define VGA_3 0x06
177 #define VGA_4 0x01
178 #define VGA_5 0x05
179 #define VGA_6 0x03
180 #define VGA_7 0x07
181
182 #define RFVGA_0 0x00
183 #define RFVGA_1 0x01
184 #define RFVGA_2 0x02
185 #define RFVGA_3 0x03
186
187 static int cx24113_set_gain_settings(struct cx24113_state *state,
188                 s16 power_estimation)
189 {
190         u8 ampout = cx24113_readreg(state, 0x1d) & 0xf0,
191            vga    = cx24113_readreg(state, 0x1f) & 0x3f,
192            rfvga  = cx24113_readreg(state, 0x20) & 0xf3;
193         u8 gain_level = power_estimation >= state->tuner_gain_thres;
194
195         dprintk("power estimation: %d, thres: %d, gain_level: %d/%d\n",
196                         power_estimation, state->tuner_gain_thres,
197                         state->gain_level, gain_level);
198
199         if (gain_level == state->gain_level)
200                 return 0; /* nothing to be done */
201
202         ampout |= 0xf;
203
204         if (gain_level) {
205                 rfvga |= RFVGA_0 << 2;
206                 vga   |= (VGA_7 << 3) | VGA_7;
207         } else {
208                 rfvga |= RFVGA_2 << 2;
209                 vga  |= (VGA_6 << 3) | VGA_2;
210         }
211         state->gain_level = gain_level;
212
213         cx24113_writereg(state, 0x1d, ampout);
214         cx24113_writereg(state, 0x1f, vga);
215         cx24113_writereg(state, 0x20, rfvga);
216
217         return 1; /* did something */
218 }
219
220 static int cx24113_set_Fref(struct cx24113_state *state, u8 high)
221 {
222         u8 xtal = cx24113_readreg(state, 0x02);
223         if (state->rev == 0x43 && state->vcodiv == VCODIV4)
224                 high = 1;
225
226         xtal &= ~0x2;
227         if (high)
228                 xtal |= high << 1;
229         return cx24113_writereg(state, 0x02, xtal);
230 }
231
232 static int cx24113_enable(struct cx24113_state *state, u8 enable)
233 {
234         u8 r21 = (cx24113_readreg(state, 0x21) & 0xc0) | enable;
235         if (state->rev == REV_CX24113)
236                 r21 |= (1 << 1);
237         return cx24113_writereg(state, 0x21, r21);
238 }
239
240 static int cx24113_set_bandwidth(struct cx24113_state *state, u32 bandwidth_khz)
241 {
242         u8 r;
243
244         if (bandwidth_khz <= 19000)
245                 r = 0x03 << 6;
246         else if (bandwidth_khz <= 25000)
247                 r = 0x02 << 6;
248         else
249                 r = 0x01 << 6;
250
251         dprintk("bandwidth to be set: %d\n", bandwidth_khz);
252         bandwidth_khz *= 10;
253         bandwidth_khz -= 10000;
254         bandwidth_khz /= 1000;
255         bandwidth_khz += 5;
256         bandwidth_khz /= 10;
257
258         dprintk("bandwidth: %d %d\n", r >> 6, bandwidth_khz);
259
260         r |= bandwidth_khz & 0x3f;
261
262         return cx24113_writereg(state, 0x1e, r);
263 }
264
265 static int cx24113_set_clk_inversion(struct cx24113_state *state, u8 on)
266 {
267         u8 r = (cx24113_readreg(state, 0x10) & 0x7f) | ((on & 0x1) << 7);
268         return cx24113_writereg(state, 0x10, r);
269 }
270
271 static int cx24113_get_status(struct dvb_frontend *fe, u32 *status)
272 {
273         struct cx24113_state *state = fe->tuner_priv;
274         u8 r = (cx24113_readreg(state, 0x10) & 0x02) >> 1;
275         if (r)
276                 *status |= TUNER_STATUS_LOCKED;
277         dprintk("PLL locked: %d\n", r);
278         return 0;
279 }
280
281 static u8 cx24113_set_ref_div(struct cx24113_state *state, u8 refdiv)
282 {
283         if (state->rev == 0x43 && state->vcodiv == VCODIV4)
284                 refdiv = 2;
285         return state->refdiv = refdiv;
286 }
287
288 static void cx24113_calc_pll_nf(struct cx24113_state *state, u16 *n, s32 *f)
289 {
290         s32 N;
291         s64 F;
292         u64 dividend;
293         u8 R, r;
294         u8 vcodiv;
295         u8 factor;
296         s32 freq_hz = state->frequency * 1000;
297
298         if (state->config->xtal_khz < 20000)
299                 factor = 1;
300         else
301                 factor = 2;
302
303         if (state->rev == REV_CX24113) {
304                 if (state->frequency >= 1100000)
305                         vcodiv = VCODIV2;
306                 else
307                         vcodiv = VCODIV4;
308         } else {
309                 if (state->frequency >= 1165000)
310                         vcodiv = VCODIV2;
311                 else
312                         vcodiv = VCODIV4;
313         }
314         state->vcodiv = vcodiv;
315
316         dprintk("calculating N/F for %dHz with vcodiv %d\n", freq_hz, vcodiv);
317         R = 0;
318         do {
319                 R = cx24113_set_ref_div(state, R + 1);
320
321                 /* calculate tuner PLL settings: */
322                 N =  (freq_hz / 100 * vcodiv) * R;
323                 N /= (state->config->xtal_khz) * factor * 2;
324                 N += 5;     /* For round up. */
325                 N /= 10;
326                 N -= 32;
327         } while (N < 6 && R < 3);
328
329         if (N < 6) {
330                 cx_err("strange frequency: N < 6\n");
331                 return;
332         }
333         F = freq_hz;
334         F *= (u64) (R * vcodiv * 262144);
335         dprintk("1 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
336         /* do_div needs an u64 as first argument */
337         dividend = F;
338         do_div(dividend, state->config->xtal_khz * 1000 * factor * 2);
339         F = dividend;
340         dprintk("2 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
341         F -= (N + 32) * 262144;
342
343         dprintk("3 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
344
345         if (state->Fwindow_enabled) {
346                 if (F > (262144 / 2 - 1638))
347                         F = 262144 / 2 - 1638;
348                 if (F < (-262144 / 2 + 1638))
349                         F = -262144 / 2 + 1638;
350                 if ((F < 3277 && F > 0) || (F > -3277 && F < 0)) {
351                         F = 0;
352                         r = cx24113_readreg(state, 0x10);
353                         cx24113_writereg(state, 0x10, r | (1 << 6));
354                 }
355         }
356         dprintk("4 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
357
358         *n = (u16) N;
359         *f = (s32) F;
360 }
361
362
363 static void cx24113_set_nfr(struct cx24113_state *state, u16 n, s32 f, u8 r)
364 {
365         u8 reg;
366         cx24113_writereg(state, 0x19, (n >> 1) & 0xff);
367
368         reg = ((n & 0x1) << 7) | ((f >> 11) & 0x7f);
369         cx24113_writereg(state, 0x1a, reg);
370
371         cx24113_writereg(state, 0x1b, (f >> 3) & 0xff);
372
373         reg = cx24113_readreg(state, 0x1c) & 0x1f;
374         cx24113_writereg(state, 0x1c, reg | ((f & 0x7) << 5));
375
376         cx24113_set_Fref(state, r - 1);
377 }
378
379 static int cx24113_set_frequency(struct cx24113_state *state, u32 frequency)
380 {
381         u8 r = 1; /* or 2 */
382         u16 n = 6;
383         s32 f = 0;
384
385         r = cx24113_readreg(state, 0x14);
386         cx24113_writereg(state, 0x14, r & 0x3f);
387
388         r = cx24113_readreg(state, 0x10);
389         cx24113_writereg(state, 0x10, r & 0xbf);
390
391         state->frequency = frequency;
392
393         dprintk("tuning to frequency: %d\n", frequency);
394
395         cx24113_calc_pll_nf(state, &n, &f);
396         cx24113_set_nfr(state, n, f, state->refdiv);
397
398         r = cx24113_readreg(state, 0x18) & 0xbf;
399         if (state->vcodiv != VCODIV2)
400                 r |= 1 << 6;
401         cx24113_writereg(state, 0x18, r);
402
403         /* The need for this sleep is not clear. But helps in some cases */
404         msleep(5);
405
406         r = cx24113_readreg(state, 0x1c) & 0xef;
407         cx24113_writereg(state, 0x1c, r | (1 << 4));
408         return 0;
409 }
410
411 static int cx24113_init(struct dvb_frontend *fe)
412 {
413         struct cx24113_state *state = fe->tuner_priv;
414         int ret;
415
416         state->tuner_gain_thres = -50;
417         state->gain_level = 255; /* to force a gain-setting initialization */
418         state->icp_mode = 0;
419
420         if (state->config->xtal_khz < 11000) {
421                 state->icp_auto_hi  = ICP_LEVEL4;
422                 state->icp_auto_mhi  = ICP_LEVEL4;
423                 state->icp_auto_mlow = ICP_LEVEL3;
424                 state->icp_auto_low = ICP_LEVEL3;
425         } else {
426                 state->icp_auto_hi  = ICP_LEVEL4;
427                 state->icp_auto_mhi  = ICP_LEVEL4;
428                 state->icp_auto_mlow = ICP_LEVEL3;
429                 state->icp_auto_low = ICP_LEVEL2;
430         }
431
432         state->icp_dig = ICP_LEVEL3;
433         state->icp_man = ICP_LEVEL1;
434         state->acp_on  = 1;
435         state->vco_mode = 0;
436         state->vco_shift = 0;
437         state->vco_band = VCOBANDSEL_1;
438         state->bs_delay = 8;
439         state->bs_freqcnt = 0x0fff;
440         state->bs_rdiv = 0x0fff;
441         state->prescaler_mode = 0;
442         state->lna_gain = LNA_MAX_GAIN;
443         state->rfvga_bias_ctrl = 1;
444         state->Fwindow_enabled = 1;
445
446         cx24113_set_Fref(state, 0);
447         cx24113_enable(state, 0x3d);
448         cx24113_set_parameters(state);
449
450         cx24113_set_gain_settings(state, -30);
451
452         cx24113_set_bandwidth(state, 18025);
453         cx24113_set_clk_inversion(state, 1);
454
455         if (state->config->xtal_khz >= 40000)
456                 ret = cx24113_writereg(state, 0x02,
457                         (cx24113_readreg(state, 0x02) & 0xfb) | (1 << 2));
458         else
459                 ret = cx24113_writereg(state, 0x02,
460                         (cx24113_readreg(state, 0x02) & 0xfb) | (0 << 2));
461
462         return ret;
463 }
464
465 static int cx24113_set_params(struct dvb_frontend *fe)
466 {
467         struct dtv_frontend_properties *c = &fe->dtv_property_cache;
468         struct cx24113_state *state = fe->tuner_priv;
469         /* for a ROLL-OFF factor of 0.35, 0.2: 600, 0.25: 625 */
470         u32 roll_off = 675;
471         u32 bw;
472
473         bw  = ((c->symbol_rate/100) * roll_off) / 1000;
474         bw += (10000000/100) + 5;
475         bw /= 10;
476         bw += 1000;
477         cx24113_set_bandwidth(state, bw);
478
479         cx24113_set_frequency(state, c->frequency);
480         msleep(5);
481         return cx24113_get_status(fe, &bw);
482 }
483
484 static s8 cx24113_agc_table[2][10] = {
485         {-54, -41, -35, -30, -25, -21, -16, -10,  -6,  -2},
486         {-39, -35, -30, -25, -19, -15, -11,  -5,   1,   9},
487 };
488
489 void cx24113_agc_callback(struct dvb_frontend *fe)
490 {
491         struct cx24113_state *state = fe->tuner_priv;
492         s16 s, i;
493         if (!fe->ops.read_signal_strength)
494                 return;
495
496         do {
497                 /* this only works with the current CX24123 implementation */
498                 fe->ops.read_signal_strength(fe, (u16 *) &s);
499                 s >>= 8;
500                 dprintk("signal strength: %d\n", s);
501                 for (i = 0; i < sizeof(cx24113_agc_table[0]); i++)
502                         if (cx24113_agc_table[state->gain_level][i] > s)
503                                 break;
504                 s = -25 - i*5;
505         } while (cx24113_set_gain_settings(state, s));
506 }
507 EXPORT_SYMBOL(cx24113_agc_callback);
508
509 static int cx24113_get_frequency(struct dvb_frontend *fe, u32 *frequency)
510 {
511         struct cx24113_state *state = fe->tuner_priv;
512         *frequency = state->frequency;
513         return 0;
514 }
515
516 static void cx24113_release(struct dvb_frontend *fe)
517 {
518         struct cx24113_state *state = fe->tuner_priv;
519         dprintk("\n");
520         fe->tuner_priv = NULL;
521         kfree(state);
522 }
523
524 static const struct dvb_tuner_ops cx24113_tuner_ops = {
525         .info = {
526                 .name              = "Conexant CX24113",
527                 .frequency_min_hz  =  950 * MHz,
528                 .frequency_max_hz  = 2150 * MHz,
529                 .frequency_step_hz =  125 * kHz,
530         },
531
532         .release       = cx24113_release,
533
534         .init          = cx24113_init,
535
536         .set_params    = cx24113_set_params,
537         .get_frequency = cx24113_get_frequency,
538         .get_status    = cx24113_get_status,
539 };
540
541 struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
542                 const struct cx24113_config *config, struct i2c_adapter *i2c)
543 {
544         /* allocate memory for the internal state */
545         struct cx24113_state *state = kzalloc(sizeof(*state), GFP_KERNEL);
546         int rc;
547
548         if (!state)
549                 return NULL;
550
551         /* setup the state */
552         state->config = config;
553         state->i2c = i2c;
554
555         cx_info("trying to detect myself\n");
556
557         /* making a dummy read, because of some expected troubles
558          * after power on */
559         cx24113_readreg(state, 0x00);
560
561         rc = cx24113_readreg(state, 0x00);
562         if (rc < 0) {
563                 cx_info("CX24113 not found.\n");
564                 goto error;
565         }
566         state->rev = rc;
567
568         switch (rc) {
569         case 0x43:
570                 cx_info("detected CX24113 variant\n");
571                 break;
572         case REV_CX24113:
573                 cx_info("successfully detected\n");
574                 break;
575         default:
576                 cx_err("unsupported device id: %x\n", state->rev);
577                 goto error;
578         }
579         state->ver = cx24113_readreg(state, 0x01);
580         cx_info("version: %x\n", state->ver);
581
582         /* create dvb_frontend */
583         memcpy(&fe->ops.tuner_ops, &cx24113_tuner_ops,
584                         sizeof(struct dvb_tuner_ops));
585         fe->tuner_priv = state;
586         return fe;
587
588 error:
589         kfree(state);
590
591         return NULL;
592 }
593 EXPORT_SYMBOL(cx24113_attach);
594
595 module_param(debug, int, 0644);
596 MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
597
598 MODULE_AUTHOR("Patrick Boettcher <pb@linuxtv.org>");
599 MODULE_DESCRIPTION("DVB Frontend module for Conexant CX24113/CX24128hardware");
600 MODULE_LICENSE("GPL");
601