1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" |
4 | * |
5 | * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> |
6 | */ |
7 | |
8 | #include <linux/module.h> |
9 | #include <linux/delay.h> |
10 | #include <linux/dvb/frontend.h> |
11 | #include <linux/i2c.h> |
12 | #include <linux/slab.h> |
13 | |
14 | #include <media/dvb_frontend.h> |
15 | |
16 | #include "mt2131.h" |
17 | #include "mt2131_priv.h" |
18 | |
19 | static int debug; |
20 | module_param(debug, int, 0644); |
21 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)." ); |
22 | |
23 | #define dprintk(level,fmt, arg...) if (debug >= level) \ |
24 | printk(KERN_INFO "%s: " fmt, "mt2131", ## arg) |
25 | |
26 | static u8 mt2131_config1[] = { |
27 | 0x01, |
28 | 0x50, 0x00, 0x50, 0x80, 0x00, 0x49, 0xfa, 0x88, |
29 | 0x08, 0x77, 0x41, 0x04, 0x00, 0x00, 0x00, 0x32, |
30 | 0x7f, 0xda, 0x4c, 0x00, 0x10, 0xaa, 0x78, 0x80, |
31 | 0xff, 0x68, 0xa0, 0xff, 0xdd, 0x00, 0x00 |
32 | }; |
33 | |
34 | static u8 mt2131_config2[] = { |
35 | 0x10, |
36 | 0x7f, 0xc8, 0x0a, 0x5f, 0x00, 0x04 |
37 | }; |
38 | |
39 | static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val) |
40 | { |
41 | struct i2c_msg msg[2] = { |
42 | { .addr = priv->cfg->i2c_address, .flags = 0, |
43 | .buf = ®, .len = 1 }, |
44 | { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, |
45 | .buf = val, .len = 1 }, |
46 | }; |
47 | |
48 | if (i2c_transfer(adap: priv->i2c, msgs: msg, num: 2) != 2) { |
49 | printk(KERN_WARNING "mt2131 I2C read failed\n" ); |
50 | return -EREMOTEIO; |
51 | } |
52 | return 0; |
53 | } |
54 | |
55 | static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val) |
56 | { |
57 | u8 buf[2] = { reg, val }; |
58 | struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, |
59 | .buf = buf, .len = 2 }; |
60 | |
61 | if (i2c_transfer(adap: priv->i2c, msgs: &msg, num: 1) != 1) { |
62 | printk(KERN_WARNING "mt2131 I2C write failed\n" ); |
63 | return -EREMOTEIO; |
64 | } |
65 | return 0; |
66 | } |
67 | |
68 | static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len) |
69 | { |
70 | struct i2c_msg msg = { .addr = priv->cfg->i2c_address, |
71 | .flags = 0, .buf = buf, .len = len }; |
72 | |
73 | if (i2c_transfer(adap: priv->i2c, msgs: &msg, num: 1) != 1) { |
74 | printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n" , |
75 | (int)len); |
76 | return -EREMOTEIO; |
77 | } |
78 | return 0; |
79 | } |
80 | |
81 | static int mt2131_set_params(struct dvb_frontend *fe) |
82 | { |
83 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
84 | struct mt2131_priv *priv; |
85 | int ret=0, i; |
86 | u32 freq; |
87 | u8 if_band_center; |
88 | u32 f_lo1, f_lo2; |
89 | u32 div1, num1, div2, num2; |
90 | u8 b[8]; |
91 | u8 lockval = 0; |
92 | |
93 | priv = fe->tuner_priv; |
94 | |
95 | freq = c->frequency / 1000; /* Hz -> kHz */ |
96 | dprintk(1, "%s() freq=%d\n" , __func__, freq); |
97 | |
98 | f_lo1 = freq + MT2131_IF1 * 1000; |
99 | f_lo1 = (f_lo1 / 250) * 250; |
100 | f_lo2 = f_lo1 - freq - MT2131_IF2; |
101 | |
102 | priv->frequency = (f_lo1 - f_lo2 - MT2131_IF2) * 1000; |
103 | |
104 | /* Frequency LO1 = 16MHz * (DIV1 + NUM1/8192 ) */ |
105 | num1 = f_lo1 * 64 / (MT2131_FREF / 128); |
106 | div1 = num1 / 8192; |
107 | num1 &= 0x1fff; |
108 | |
109 | /* Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) */ |
110 | num2 = f_lo2 * 64 / (MT2131_FREF / 128); |
111 | div2 = num2 / 8192; |
112 | num2 &= 0x1fff; |
113 | |
114 | if (freq <= 82500) if_band_center = 0x00; else |
115 | if (freq <= 137500) if_band_center = 0x01; else |
116 | if (freq <= 192500) if_band_center = 0x02; else |
117 | if (freq <= 247500) if_band_center = 0x03; else |
118 | if (freq <= 302500) if_band_center = 0x04; else |
119 | if (freq <= 357500) if_band_center = 0x05; else |
120 | if (freq <= 412500) if_band_center = 0x06; else |
121 | if (freq <= 467500) if_band_center = 0x07; else |
122 | if (freq <= 522500) if_band_center = 0x08; else |
123 | if (freq <= 577500) if_band_center = 0x09; else |
124 | if (freq <= 632500) if_band_center = 0x0A; else |
125 | if (freq <= 687500) if_band_center = 0x0B; else |
126 | if (freq <= 742500) if_band_center = 0x0C; else |
127 | if (freq <= 797500) if_band_center = 0x0D; else |
128 | if (freq <= 852500) if_band_center = 0x0E; else |
129 | if (freq <= 907500) if_band_center = 0x0F; else |
130 | if (freq <= 962500) if_band_center = 0x10; else |
131 | if (freq <= 1017500) if_band_center = 0x11; else |
132 | if (freq <= 1072500) if_band_center = 0x12; else if_band_center = 0x13; |
133 | |
134 | b[0] = 1; |
135 | b[1] = (num1 >> 5) & 0xFF; |
136 | b[2] = (num1 & 0x1F); |
137 | b[3] = div1; |
138 | b[4] = (num2 >> 5) & 0xFF; |
139 | b[5] = num2 & 0x1F; |
140 | b[6] = div2; |
141 | |
142 | dprintk(1, "IF1: %dMHz IF2: %dMHz\n" , MT2131_IF1, MT2131_IF2); |
143 | dprintk(1, "PLL freq=%dkHz band=%d\n" , (int)freq, (int)if_band_center); |
144 | dprintk(1, "PLL f_lo1=%dkHz f_lo2=%dkHz\n" , (int)f_lo1, (int)f_lo2); |
145 | dprintk(1, "PLL div1=%d num1=%d div2=%d num2=%d\n" , |
146 | (int)div1, (int)num1, (int)div2, (int)num2); |
147 | dprintk(1, "PLL [1..6]: %2x %2x %2x %2x %2x %2x\n" , |
148 | (int)b[1], (int)b[2], (int)b[3], (int)b[4], (int)b[5], |
149 | (int)b[6]); |
150 | |
151 | ret = mt2131_writeregs(priv,buf: b,len: 7); |
152 | if (ret < 0) |
153 | return ret; |
154 | |
155 | mt2131_writereg(priv, reg: 0x0b, val: if_band_center); |
156 | |
157 | /* Wait for lock */ |
158 | i = 0; |
159 | do { |
160 | mt2131_readreg(priv, reg: 0x08, val: &lockval); |
161 | if ((lockval & 0x88) == 0x88) |
162 | break; |
163 | msleep(msecs: 4); |
164 | i++; |
165 | } while (i < 10); |
166 | |
167 | return ret; |
168 | } |
169 | |
170 | static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency) |
171 | { |
172 | struct mt2131_priv *priv = fe->tuner_priv; |
173 | dprintk(1, "%s()\n" , __func__); |
174 | *frequency = priv->frequency; |
175 | return 0; |
176 | } |
177 | |
178 | static int mt2131_get_status(struct dvb_frontend *fe, u32 *status) |
179 | { |
180 | struct mt2131_priv *priv = fe->tuner_priv; |
181 | u8 lock_status = 0; |
182 | u8 afc_status = 0; |
183 | |
184 | *status = 0; |
185 | |
186 | mt2131_readreg(priv, reg: 0x08, val: &lock_status); |
187 | if ((lock_status & 0x88) == 0x88) |
188 | *status = TUNER_STATUS_LOCKED; |
189 | |
190 | mt2131_readreg(priv, reg: 0x09, val: &afc_status); |
191 | dprintk(1, "%s() - LO Status = 0x%x, AFC Status = 0x%x\n" , |
192 | __func__, lock_status, afc_status); |
193 | |
194 | return 0; |
195 | } |
196 | |
197 | static int mt2131_init(struct dvb_frontend *fe) |
198 | { |
199 | struct mt2131_priv *priv = fe->tuner_priv; |
200 | int ret; |
201 | dprintk(1, "%s()\n" , __func__); |
202 | |
203 | if ((ret = mt2131_writeregs(priv, buf: mt2131_config1, |
204 | len: sizeof(mt2131_config1))) < 0) |
205 | return ret; |
206 | |
207 | mt2131_writereg(priv, reg: 0x0b, val: 0x09); |
208 | mt2131_writereg(priv, reg: 0x15, val: 0x47); |
209 | mt2131_writereg(priv, reg: 0x07, val: 0xf2); |
210 | mt2131_writereg(priv, reg: 0x0b, val: 0x01); |
211 | |
212 | if ((ret = mt2131_writeregs(priv, buf: mt2131_config2, |
213 | len: sizeof(mt2131_config2))) < 0) |
214 | return ret; |
215 | |
216 | return ret; |
217 | } |
218 | |
219 | static void mt2131_release(struct dvb_frontend *fe) |
220 | { |
221 | dprintk(1, "%s()\n" , __func__); |
222 | kfree(objp: fe->tuner_priv); |
223 | fe->tuner_priv = NULL; |
224 | } |
225 | |
226 | static const struct dvb_tuner_ops mt2131_tuner_ops = { |
227 | .info = { |
228 | .name = "Microtune MT2131" , |
229 | .frequency_min_hz = 48 * MHz, |
230 | .frequency_max_hz = 860 * MHz, |
231 | .frequency_step_hz = 50 * kHz, |
232 | }, |
233 | |
234 | .release = mt2131_release, |
235 | .init = mt2131_init, |
236 | |
237 | .set_params = mt2131_set_params, |
238 | .get_frequency = mt2131_get_frequency, |
239 | .get_status = mt2131_get_status |
240 | }; |
241 | |
242 | struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, |
243 | struct i2c_adapter *i2c, |
244 | struct mt2131_config *cfg, u16 if1) |
245 | { |
246 | struct mt2131_priv *priv = NULL; |
247 | u8 id = 0; |
248 | |
249 | dprintk(1, "%s()\n" , __func__); |
250 | |
251 | priv = kzalloc(size: sizeof(struct mt2131_priv), GFP_KERNEL); |
252 | if (priv == NULL) |
253 | return NULL; |
254 | |
255 | priv->cfg = cfg; |
256 | priv->i2c = i2c; |
257 | |
258 | if (mt2131_readreg(priv, reg: 0, val: &id) != 0) { |
259 | kfree(objp: priv); |
260 | return NULL; |
261 | } |
262 | if ( (id != 0x3E) && (id != 0x3F) ) { |
263 | printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n" , |
264 | cfg->i2c_address); |
265 | kfree(objp: priv); |
266 | return NULL; |
267 | } |
268 | |
269 | printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n" , |
270 | cfg->i2c_address); |
271 | memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops, |
272 | sizeof(struct dvb_tuner_ops)); |
273 | |
274 | fe->tuner_priv = priv; |
275 | return fe; |
276 | } |
277 | EXPORT_SYMBOL_GPL(mt2131_attach); |
278 | |
279 | MODULE_AUTHOR("Steven Toth" ); |
280 | MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver" ); |
281 | MODULE_LICENSE("GPL" ); |
282 | |