[media] drx-j: put under 3-clause BSD license
[deliverable/linux.git] / drivers / media / dvb-frontends / drx39xyj / drx39xxj.c
1 /*
2 * Driver for Micronas DRX39xx family (drx3933j)
3 *
4 * Written by Devin Heitmueller <devin.heitmueller@kernellabs.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 *
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
20 */
21
22 #include <linux/module.h>
23 #include <linux/init.h>
24 #include <linux/string.h>
25 #include <linux/slab.h>
26
27 #include "dvb_frontend.h"
28 #include "drx39xxj.h"
29 #include "drx_driver.h"
30 #include "bsp_types.h"
31 #include "bsp_tuner.h"
32 #include "drxj_mc.h"
33 #include "drxj.h"
34
35 static int drx39xxj_set_powerstate(struct dvb_frontend* fe, int enable)
36 {
37 struct drx39xxj_state *state = fe->demodulator_priv;
38 DRXDemodInstance_t *demod = state->demod;
39 DRXStatus_t result;
40 DRXPowerMode_t powerMode;
41
42 if (enable)
43 powerMode = DRX_POWER_UP;
44 else
45 powerMode = DRX_POWER_DOWN;
46
47 result = DRX_Ctrl(demod, DRX_CTRL_POWER_MODE, &powerMode);
48 if (result != DRX_STS_OK) {
49 printk("Power state change failed\n");
50 return 0;
51 }
52
53 state->powered_up = enable;
54 return 0;
55 }
56
57 static int drx39xxj_read_status(struct dvb_frontend* fe, fe_status_t* status)
58 {
59 struct drx39xxj_state* state = fe->demodulator_priv;
60 DRXDemodInstance_t *demod = state->demod;
61 DRXStatus_t result;
62 DRXLockStatus_t lock_status;
63
64 *status = 0;
65
66 result = DRX_Ctrl(demod, DRX_CTRL_LOCK_STATUS, &lock_status);
67 if (result != DRX_STS_OK) {
68 printk("drx39xxj: could not get lock status!\n");
69 *status = 0;
70 }
71
72 switch (lock_status) {
73 case DRX_NEVER_LOCK:
74 *status = 0;
75 printk("drx says NEVER_LOCK\n");
76 break;
77 case DRX_NOT_LOCKED:
78 *status = 0;
79 break;
80 case DRX_LOCK_STATE_1:
81 case DRX_LOCK_STATE_2:
82 case DRX_LOCK_STATE_3:
83 case DRX_LOCK_STATE_4:
84 case DRX_LOCK_STATE_5:
85 case DRX_LOCK_STATE_6:
86 case DRX_LOCK_STATE_7:
87 case DRX_LOCK_STATE_8:
88 case DRX_LOCK_STATE_9:
89 *status = FE_HAS_SIGNAL
90 | FE_HAS_CARRIER
91 | FE_HAS_VITERBI
92 | FE_HAS_SYNC;
93 break;
94 case DRX_LOCKED:
95 *status = FE_HAS_SIGNAL
96 | FE_HAS_CARRIER
97 | FE_HAS_VITERBI
98 | FE_HAS_SYNC
99 | FE_HAS_LOCK;
100 break;
101 default:
102 printk("Lock state unknown %d\n", lock_status);
103 }
104
105 return 0;
106 }
107
108 static int drx39xxj_read_ber(struct dvb_frontend* fe, u32* ber)
109 {
110 struct drx39xxj_state* state = fe->demodulator_priv;
111 DRXDemodInstance_t *demod = state->demod;
112 DRXStatus_t result;
113 DRXSigQuality_t sig_quality;
114
115 result = DRX_Ctrl(demod, DRX_CTRL_SIG_QUALITY, &sig_quality);
116 if (result != DRX_STS_OK) {
117 printk("drx39xxj: could not get ber!\n");
118 *ber = 0;
119 return 0;
120 }
121
122 *ber = sig_quality.postReedSolomonBER;
123 return 0;
124 }
125
126 static int drx39xxj_read_signal_strength(struct dvb_frontend* fe, u16* strength)
127 {
128 struct drx39xxj_state* state = fe->demodulator_priv;
129 DRXDemodInstance_t *demod = state->demod;
130 DRXStatus_t result;
131 DRXSigQuality_t sig_quality;
132
133 result = DRX_Ctrl(demod, DRX_CTRL_SIG_QUALITY, &sig_quality);
134 if (result != DRX_STS_OK) {
135 printk("drx39xxj: could not get signal strength!\n");
136 *strength = 0;
137 return 0;
138 }
139
140 /* 1-100% scaled to 0-65535 */
141 *strength = (sig_quality.indicator * 65535 / 100);
142 return 0;
143 }
144
145 static int drx39xxj_read_snr(struct dvb_frontend* fe, u16* snr)
146 {
147 struct drx39xxj_state* state = fe->demodulator_priv;
148 DRXDemodInstance_t *demod = state->demod;
149 DRXStatus_t result;
150 DRXSigQuality_t sig_quality;
151
152 result = DRX_Ctrl(demod, DRX_CTRL_SIG_QUALITY, &sig_quality);
153 if (result != DRX_STS_OK) {
154 printk("drx39xxj: could not read snr!\n");
155 *snr = 0;
156 return 0;
157 }
158
159 *snr = sig_quality.MER;
160 return 0;
161 }
162
163 static int drx39xxj_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
164 {
165 struct drx39xxj_state* state = fe->demodulator_priv;
166 DRXDemodInstance_t *demod = state->demod;
167 DRXStatus_t result;
168 DRXSigQuality_t sig_quality;
169
170 result = DRX_Ctrl(demod, DRX_CTRL_SIG_QUALITY, &sig_quality);
171 if (result != DRX_STS_OK) {
172 printk("drx39xxj: could not get uc blocks!\n");
173 *ucblocks = 0;
174 return 0;
175 }
176
177 *ucblocks = sig_quality.packetError;
178 return 0;
179 }
180
181 static int drx39xxj_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
182 {
183 return 0;
184 }
185
186 static int drx39xxj_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
187 {
188 #ifdef DJH_DEBUG
189 int i;
190 #endif
191 struct drx39xxj_state* state = fe->demodulator_priv;
192 DRXDemodInstance_t *demod = state->demod;
193 DRXStandard_t standard = DRX_STANDARD_8VSB;
194 DRXChannel_t channel;
195 DRXStatus_t result;
196 DRXUIOData_t uioData;
197 DRXChannel_t defChannel = {/* frequency */ 0,
198 /* bandwidth */ DRX_BANDWIDTH_6MHZ,
199 /* mirror */ DRX_MIRROR_NO,
200 /* constellation */ DRX_CONSTELLATION_AUTO,
201 /* hierarchy */ DRX_HIERARCHY_UNKNOWN,
202 /* priority */ DRX_PRIORITY_UNKNOWN,
203 /* coderate */ DRX_CODERATE_UNKNOWN,
204 /* guard */ DRX_GUARD_UNKNOWN,
205 /* fftmode */ DRX_FFTMODE_UNKNOWN,
206 /* classification */ DRX_CLASSIFICATION_AUTO,
207 /* symbolrate */ 5057000,
208 /* interleavemode */ DRX_INTERLEAVEMODE_UNKNOWN,
209 /* ldpc */ DRX_LDPC_UNKNOWN,
210 /* carrier */ DRX_CARRIER_UNKNOWN,
211 /* frame mode */ DRX_FRAMEMODE_UNKNOWN
212 };
213
214 /* Bring the demod out of sleep */
215 drx39xxj_set_powerstate(fe, 1);
216
217 /* Now make the tuner do it's thing... */
218 if (fe->ops.tuner_ops.set_params) {
219 if (fe->ops.i2c_gate_ctrl)
220 fe->ops.i2c_gate_ctrl(fe, 1);
221 fe->ops.tuner_ops.set_params(fe, p);
222 if (fe->ops.i2c_gate_ctrl)
223 fe->ops.i2c_gate_ctrl(fe, 0);
224 }
225
226 if (standard != state->current_standard || state->powered_up == 0) {
227 /* Set the standard (will be powered up if necessary */
228 result = DRX_Ctrl(demod, DRX_CTRL_SET_STANDARD, &standard);
229 if (result != DRX_STS_OK) {
230 printk("Failed to set standard! result=%02x\n", result);
231 return -EINVAL;
232 }
233 state->powered_up = 1;
234 state->current_standard = standard;
235 }
236
237 /* set channel parameters */
238 channel = defChannel;
239 channel.frequency = p->frequency / 1000;
240 channel.bandwidth = DRX_BANDWIDTH_6MHZ;
241 channel.constellation = DRX_CONSTELLATION_AUTO;
242
243 /* program channel */
244 result = DRX_Ctrl(demod, DRX_CTRL_SET_CHANNEL, &channel);
245 if (result != DRX_STS_OK) {
246 printk("Failed to set channel!\n");
247 return -EINVAL;
248 }
249
250 // Just for giggles, let's shut off the LNA again....
251 uioData.uio = DRX_UIO1;
252 uioData.value = FALSE;
253 result = DRX_Ctrl(demod, DRX_CTRL_UIO_WRITE, &uioData);
254 if (result != DRX_STS_OK) {
255 printk("Failed to disable LNA!\n");
256 return 0;
257 }
258
259 #ifdef DJH_DEBUG
260 for(i = 0; i < 2000; i++) {
261 fe_status_t status;
262 drx39xxj_read_status(fe, &status);
263 printk("i=%d status=%d\n", i, status);
264 msleep(100);
265 i += 100;
266 }
267 #endif
268
269 return 0;
270 }
271
272
273 static int drx39xxj_sleep(struct dvb_frontend* fe)
274 {
275 /* power-down the demodulator */
276 return drx39xxj_set_powerstate(fe, 0);
277 }
278
279 static int drx39xxj_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
280 {
281 struct drx39xxj_state *state = fe->demodulator_priv;
282 DRXDemodInstance_t *demod = state->demod;
283 Bool_t i2c_gate_state;
284 DRXStatus_t result;
285
286 #ifdef DJH_DEBUG
287 printk("i2c gate call: enable=%d state=%d\n", enable,
288 state->i2c_gate_open);
289 #endif
290
291 if (enable)
292 i2c_gate_state = TRUE;
293 else
294 i2c_gate_state = FALSE;
295
296 if (state->i2c_gate_open == enable) {
297 /* We're already in the desired state */
298 return 0;
299 }
300
301 result = DRX_Ctrl(demod, DRX_CTRL_I2C_BRIDGE, &i2c_gate_state);
302 if (result != DRX_STS_OK) {
303 printk("drx39xxj: could not open i2c gate [%d]\n", result);
304 dump_stack();
305 } else {
306 state->i2c_gate_open = enable;
307 }
308 return 0;
309 }
310
311
312 static int drx39xxj_init(struct dvb_frontend* fe)
313 {
314 /* Bring the demod out of sleep */
315 drx39xxj_set_powerstate(fe, 1);
316
317 return 0;
318 }
319
320 static int drx39xxj_get_tune_settings(struct dvb_frontend *fe,
321 struct dvb_frontend_tune_settings *tune)
322 {
323 tune->min_delay_ms = 1000;
324 return 0;
325 }
326
327 static void drx39xxj_release(struct dvb_frontend* fe)
328 {
329 struct drx39xxj_state* state = fe->demodulator_priv;
330 kfree(state);
331 }
332
333 static struct dvb_frontend_ops drx39xxj_ops;
334
335 struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c)
336 {
337 struct drx39xxj_state* state = NULL;
338
339 I2CDeviceAddr_t *demodAddr = NULL;
340 DRXCommonAttr_t *demodCommAttr = NULL;
341 DRXJData_t *demodExtAttr = NULL;
342 DRXDemodInstance_t *demod = NULL;
343 DRXUIOCfg_t uioCfg;
344 DRXUIOData_t uioData;
345 DRXStatus_t result;
346
347 /* allocate memory for the internal state */
348 state = kmalloc(sizeof(struct drx39xxj_state), GFP_KERNEL);
349 if (state == NULL) goto error;
350
351 demod = kmalloc(sizeof(DRXDemodInstance_t), GFP_KERNEL);
352 if (demod == NULL) goto error;
353
354 demodAddr = kmalloc(sizeof(I2CDeviceAddr_t), GFP_KERNEL);
355 if (demodAddr == NULL) goto error;
356
357 demodCommAttr = kmalloc(sizeof(DRXCommonAttr_t), GFP_KERNEL);
358 if (demodCommAttr == NULL) goto error;
359
360 demodExtAttr = kmalloc(sizeof(DRXJData_t), GFP_KERNEL);
361 if (demodExtAttr == NULL) goto error;
362
363 /* setup the state */
364 state->i2c = i2c;
365 state->demod = demod;
366
367 memcpy(demod, &DRXJDefaultDemod_g, sizeof(DRXDemodInstance_t));
368
369 demod->myI2CDevAddr = demodAddr;
370 memcpy(demod->myI2CDevAddr, &DRXJDefaultAddr_g,
371 sizeof(I2CDeviceAddr_t));
372 demod->myI2CDevAddr->userData = state;
373 demod->myCommonAttr = demodCommAttr;
374 memcpy(demod->myCommonAttr, &DRXJDefaultCommAttr_g,
375 sizeof(DRXCommonAttr_t));
376 demod->myCommonAttr->microcode = DRXJ_MC_MAIN;
377 // demod->myCommonAttr->verifyMicrocode = FALSE;
378 demod->myCommonAttr->verifyMicrocode = TRUE;
379 demod->myCommonAttr->intermediateFreq = 5000;
380
381 demod->myExtAttr = demodExtAttr;
382 memcpy(demod->myExtAttr, &DRXJData_g, sizeof(DRXJData_t));
383 ((DRXJData_t *) demod->myExtAttr)->uioSmaTxMode = DRX_UIO_MODE_READWRITE;
384
385 demod->myTuner = NULL;
386
387 result = DRX_Open(demod);
388 if (result != DRX_STS_OK) {
389 printk("DRX open failed! Aborting\n");
390 kfree(state);
391 return NULL;
392 }
393
394 /* Turn off the LNA */
395 uioCfg.uio = DRX_UIO1;
396 uioCfg.mode = DRX_UIO_MODE_READWRITE;
397 /* Configure user-I/O #3: enable read/write */
398 result = DRX_Ctrl(demod, DRX_CTRL_UIO_CFG, &uioCfg);
399 if (result != DRX_STS_OK) {
400 printk("Failed to setup LNA GPIO!\n");
401 return NULL;
402 }
403
404 uioData.uio = DRX_UIO1;
405 uioData.value = FALSE;
406 result = DRX_Ctrl(demod, DRX_CTRL_UIO_WRITE, &uioData);
407 if (result != DRX_STS_OK) {
408 printk("Failed to disable LNA!\n");
409 return NULL;
410 }
411
412 /* create dvb_frontend */
413 memcpy(&state->frontend.ops, &drx39xxj_ops,
414 sizeof(struct dvb_frontend_ops));
415
416 state->frontend.demodulator_priv = state;
417 return &state->frontend;
418
419 error:
420 if (state != NULL)
421 kfree(state);
422 if (demod != NULL)
423 kfree(demod);
424 return NULL;
425 }
426
427 static struct dvb_frontend_ops drx39xxj_ops = {
428
429 .info = {
430 .name = "Micronas DRX39xxj family Frontend",
431 .type = FE_ATSC | FE_QAM,
432 .frequency_stepsize = 62500,
433 .frequency_min = 51000000,
434 .frequency_max = 858000000,
435 .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
436 },
437
438 .init = drx39xxj_init,
439 .i2c_gate_ctrl = drx39xxj_i2c_gate_ctrl,
440 .sleep = drx39xxj_sleep,
441 .set_frontend = drx39xxj_set_frontend,
442 .get_frontend = drx39xxj_get_frontend,
443 .get_tune_settings = drx39xxj_get_tune_settings,
444 .read_status = drx39xxj_read_status,
445 .read_ber = drx39xxj_read_ber,
446 .read_signal_strength = drx39xxj_read_signal_strength,
447 .read_snr = drx39xxj_read_snr,
448 .read_ucblocks = drx39xxj_read_ucblocks,
449 .release = drx39xxj_release,
450 };
451
452 MODULE_DESCRIPTION("Micronas DRX39xxj Frontend");
453 MODULE_AUTHOR("Devin Heitmueller");
454 MODULE_LICENSE("GPL");
455
456 EXPORT_SYMBOL(drx39xxj_attach);
This page took 0.040728 seconds and 5 git commands to generate.