2 * Driver for Micronas DRX39xx family (drx3933j)
4 * Written by Devin Heitmueller <devin.heitmueller@kernellabs.com>
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.
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
15 * GNU General Public License for more details.
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.=
22 #include <linux/module.h>
23 #include <linux/init.h>
24 #include <linux/string.h>
25 #include <linux/slab.h>
27 #include "dvb_frontend.h"
29 #include "drx_driver.h"
30 #include "bsp_types.h"
31 #include "bsp_tuner.h"
35 static int drx39xxj_set_powerstate(struct dvb_frontend
* fe
, int enable
)
37 struct drx39xxj_state
*state
= fe
->demodulator_priv
;
38 DRXDemodInstance_t
*demod
= state
->demod
;
40 DRXPowerMode_t powerMode
;
43 powerMode
= DRX_POWER_UP
;
45 powerMode
= DRX_POWER_DOWN
;
47 result
= DRX_Ctrl(demod
, DRX_CTRL_POWER_MODE
, &powerMode
);
48 if (result
!= DRX_STS_OK
) {
49 printk("Power state change failed\n");
53 state
->powered_up
= enable
;
57 static int drx39xxj_read_status(struct dvb_frontend
* fe
, fe_status_t
* status
)
59 struct drx39xxj_state
* state
= fe
->demodulator_priv
;
60 DRXDemodInstance_t
*demod
= state
->demod
;
62 DRXLockStatus_t lock_status
;
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");
72 switch (lock_status
) {
75 printk("drx says NEVER_LOCK\n");
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
95 *status
= FE_HAS_SIGNAL
102 printk("Lock state unknown %d\n", lock_status
);
108 static int drx39xxj_read_ber(struct dvb_frontend
* fe
, u32
* ber
)
110 struct drx39xxj_state
* state
= fe
->demodulator_priv
;
111 DRXDemodInstance_t
*demod
= state
->demod
;
113 DRXSigQuality_t sig_quality
;
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");
122 *ber
= sig_quality
.postReedSolomonBER
;
126 static int drx39xxj_read_signal_strength(struct dvb_frontend
* fe
, u16
* strength
)
128 struct drx39xxj_state
* state
= fe
->demodulator_priv
;
129 DRXDemodInstance_t
*demod
= state
->demod
;
131 DRXSigQuality_t sig_quality
;
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");
140 /* 1-100% scaled to 0-65535 */
141 *strength
= (sig_quality
.indicator
* 65535 / 100);
145 static int drx39xxj_read_snr(struct dvb_frontend
* fe
, u16
* snr
)
147 struct drx39xxj_state
* state
= fe
->demodulator_priv
;
148 DRXDemodInstance_t
*demod
= state
->demod
;
150 DRXSigQuality_t sig_quality
;
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");
159 *snr
= sig_quality
.MER
;
163 static int drx39xxj_read_ucblocks(struct dvb_frontend
* fe
, u32
* ucblocks
)
165 struct drx39xxj_state
* state
= fe
->demodulator_priv
;
166 DRXDemodInstance_t
*demod
= state
->demod
;
168 DRXSigQuality_t sig_quality
;
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");
177 *ucblocks
= sig_quality
.packetError
;
181 static int drx39xxj_get_frontend(struct dvb_frontend
* fe
, struct dvb_frontend_parameters
*p
)
186 static int drx39xxj_set_frontend(struct dvb_frontend
* fe
, struct dvb_frontend_parameters
*p
)
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
;
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
214 /* Bring the demod out of sleep */
215 drx39xxj_set_powerstate(fe
, 1);
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);
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
);
233 state
->powered_up
= 1;
234 state
->current_standard
= standard
;
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
;
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");
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");
260 for(i
= 0; i
< 2000; i
++) {
262 drx39xxj_read_status(fe
, &status
);
263 printk("i=%d status=%d\n", i
, status
);
273 static int drx39xxj_sleep(struct dvb_frontend
* fe
)
275 /* power-down the demodulator */
276 return drx39xxj_set_powerstate(fe
, 0);
279 static int drx39xxj_i2c_gate_ctrl(struct dvb_frontend
*fe
, int enable
)
281 struct drx39xxj_state
*state
= fe
->demodulator_priv
;
282 DRXDemodInstance_t
*demod
= state
->demod
;
283 Bool_t i2c_gate_state
;
287 printk("i2c gate call: enable=%d state=%d\n", enable
,
288 state
->i2c_gate_open
);
292 i2c_gate_state
= TRUE
;
294 i2c_gate_state
= FALSE
;
296 if (state
->i2c_gate_open
== enable
) {
297 /* We're already in the desired state */
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
);
306 state
->i2c_gate_open
= enable
;
312 static int drx39xxj_init(struct dvb_frontend
* fe
)
314 /* Bring the demod out of sleep */
315 drx39xxj_set_powerstate(fe
, 1);
320 static int drx39xxj_get_tune_settings(struct dvb_frontend
*fe
,
321 struct dvb_frontend_tune_settings
*tune
)
323 tune
->min_delay_ms
= 1000;
327 static void drx39xxj_release(struct dvb_frontend
* fe
)
329 struct drx39xxj_state
* state
= fe
->demodulator_priv
;
333 static struct dvb_frontend_ops drx39xxj_ops
;
335 struct dvb_frontend
*drx39xxj_attach(struct i2c_adapter
*i2c
)
337 struct drx39xxj_state
* state
= NULL
;
339 I2CDeviceAddr_t
*demodAddr
= NULL
;
340 DRXCommonAttr_t
*demodCommAttr
= NULL
;
341 DRXJData_t
*demodExtAttr
= NULL
;
342 DRXDemodInstance_t
*demod
= NULL
;
344 DRXUIOData_t uioData
;
347 /* allocate memory for the internal state */
348 state
= kmalloc(sizeof(struct drx39xxj_state
), GFP_KERNEL
);
349 if (state
== NULL
) goto error
;
351 demod
= kmalloc(sizeof(DRXDemodInstance_t
), GFP_KERNEL
);
352 if (demod
== NULL
) goto error
;
354 demodAddr
= kmalloc(sizeof(I2CDeviceAddr_t
), GFP_KERNEL
);
355 if (demodAddr
== NULL
) goto error
;
357 demodCommAttr
= kmalloc(sizeof(DRXCommonAttr_t
), GFP_KERNEL
);
358 if (demodCommAttr
== NULL
) goto error
;
360 demodExtAttr
= kmalloc(sizeof(DRXJData_t
), GFP_KERNEL
);
361 if (demodExtAttr
== NULL
) goto error
;
363 /* setup the state */
365 state
->demod
= demod
;
367 memcpy(demod
, &DRXJDefaultDemod_g
, sizeof(DRXDemodInstance_t
));
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;
381 demod
->myExtAttr
= demodExtAttr
;
382 memcpy(demod
->myExtAttr
, &DRXJData_g
, sizeof(DRXJData_t
));
383 ((DRXJData_t
*) demod
->myExtAttr
)->uioSmaTxMode
= DRX_UIO_MODE_READWRITE
;
385 demod
->myTuner
= NULL
;
387 result
= DRX_Open(demod
);
388 if (result
!= DRX_STS_OK
) {
389 printk("DRX open failed! Aborting\n");
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");
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");
412 /* create dvb_frontend */
413 memcpy(&state
->frontend
.ops
, &drx39xxj_ops
,
414 sizeof(struct dvb_frontend_ops
));
416 state
->frontend
.demodulator_priv
= state
;
417 return &state
->frontend
;
427 static struct dvb_frontend_ops drx39xxj_ops
= {
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
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
,
452 MODULE_DESCRIPTION("Micronas DRX39xxj Frontend");
453 MODULE_AUTHOR("Devin Heitmueller");
454 MODULE_LICENSE("GPL");
456 EXPORT_SYMBOL(drx39xxj_attach
);