diff options
-rw-r--r-- | drivers/media/dvb-frontends/cxd2820r_c.c | 104 |
1 files changed, 102 insertions, 2 deletions
diff --git a/drivers/media/dvb-frontends/cxd2820r_c.c b/drivers/media/dvb-frontends/cxd2820r_c.c index 957ec94c7243..7cdcd5535d06 100644 --- a/drivers/media/dvb-frontends/cxd2820r_c.c +++ b/drivers/media/dvb-frontends/cxd2820r_c.c | |||
@@ -260,11 +260,13 @@ int cxd2820r_read_ucblocks_c(struct dvb_frontend *fe, u32 *ucblocks) | |||
260 | int cxd2820r_read_status_c(struct dvb_frontend *fe, enum fe_status *status) | 260 | int cxd2820r_read_status_c(struct dvb_frontend *fe, enum fe_status *status) |
261 | { | 261 | { |
262 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 262 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
263 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
263 | int ret; | 264 | int ret; |
264 | u8 buf[2]; | 265 | unsigned int utmp; |
266 | u8 buf[3]; | ||
265 | *status = 0; | 267 | *status = 0; |
266 | 268 | ||
267 | ret = cxd2820r_rd_regs(priv, 0x10088, buf, sizeof(buf)); | 269 | ret = cxd2820r_rd_regs(priv, 0x10088, buf, 2); |
268 | if (ret) | 270 | if (ret) |
269 | goto error; | 271 | goto error; |
270 | 272 | ||
@@ -281,6 +283,104 @@ int cxd2820r_read_status_c(struct dvb_frontend *fe, enum fe_status *status) | |||
281 | dev_dbg(&priv->i2c->dev, "%s: lock=%02x %02x\n", __func__, buf[0], | 283 | dev_dbg(&priv->i2c->dev, "%s: lock=%02x %02x\n", __func__, buf[0], |
282 | buf[1]); | 284 | buf[1]); |
283 | 285 | ||
286 | /* Signal strength */ | ||
287 | if (*status & FE_HAS_SIGNAL) { | ||
288 | unsigned int strength; | ||
289 | |||
290 | ret = cxd2820r_rd_regs(priv, 0x10049, buf, 2); | ||
291 | if (ret) | ||
292 | goto error; | ||
293 | |||
294 | utmp = buf[0] << 8 | buf[1] << 0; | ||
295 | utmp = 511 - sign_extend32(utmp, 9); | ||
296 | /* Scale value to 0x0000-0xffff */ | ||
297 | strength = utmp << 6 | utmp >> 4; | ||
298 | |||
299 | c->strength.len = 1; | ||
300 | c->strength.stat[0].scale = FE_SCALE_RELATIVE; | ||
301 | c->strength.stat[0].uvalue = strength; | ||
302 | } else { | ||
303 | c->strength.len = 1; | ||
304 | c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
305 | } | ||
306 | |||
307 | /* CNR */ | ||
308 | if (*status & FE_HAS_VITERBI) { | ||
309 | unsigned int cnr, const_a, const_b; | ||
310 | |||
311 | ret = cxd2820r_rd_reg(priv, 0x10019, &buf[0]); | ||
312 | if (ret) | ||
313 | goto error; | ||
314 | |||
315 | if (((buf[0] >> 0) & 0x03) % 2) { | ||
316 | const_a = 8750; | ||
317 | const_b = 650; | ||
318 | } else { | ||
319 | const_a = 9500; | ||
320 | const_b = 760; | ||
321 | } | ||
322 | |||
323 | ret = cxd2820r_rd_reg(priv, 0x1004d, &buf[0]); | ||
324 | if (ret) | ||
325 | goto error; | ||
326 | |||
327 | utmp = buf[0] << 0; | ||
328 | #define CXD2820R_LOG2_E_24 24204406 /* log2(e) << 24 */ | ||
329 | if (utmp) | ||
330 | cnr = div_u64((u64)(intlog2(const_b) - intlog2(utmp)) | ||
331 | * const_a, CXD2820R_LOG2_E_24); | ||
332 | else | ||
333 | cnr = 0; | ||
334 | |||
335 | c->cnr.len = 1; | ||
336 | c->cnr.stat[0].scale = FE_SCALE_DECIBEL; | ||
337 | c->cnr.stat[0].svalue = cnr; | ||
338 | } else { | ||
339 | c->cnr.len = 1; | ||
340 | c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
341 | } | ||
342 | |||
343 | /* BER */ | ||
344 | if (*status & FE_HAS_SYNC) { | ||
345 | unsigned int post_bit_error; | ||
346 | bool start_ber; | ||
347 | |||
348 | if (priv->ber_running) { | ||
349 | ret = cxd2820r_rd_regs(priv, 0x10076, buf, 3); | ||
350 | if (ret) | ||
351 | goto error; | ||
352 | |||
353 | if ((buf[2] >> 7) & 0x01) { | ||
354 | post_bit_error = buf[2] << 16 | buf[1] << 8 | | ||
355 | buf[0] << 0; | ||
356 | post_bit_error &= 0x0fffff; | ||
357 | start_ber = true; | ||
358 | } else { | ||
359 | post_bit_error = 0; | ||
360 | start_ber = false; | ||
361 | } | ||
362 | } else { | ||
363 | post_bit_error = 0; | ||
364 | start_ber = true; | ||
365 | } | ||
366 | |||
367 | if (start_ber) { | ||
368 | ret = cxd2820r_wr_reg(priv, 0x10079, 0x01); | ||
369 | if (ret) | ||
370 | goto error; | ||
371 | priv->ber_running = true; | ||
372 | } | ||
373 | |||
374 | priv->post_bit_error += post_bit_error; | ||
375 | |||
376 | c->post_bit_error.len = 1; | ||
377 | c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; | ||
378 | c->post_bit_error.stat[0].uvalue = priv->post_bit_error; | ||
379 | } else { | ||
380 | c->post_bit_error.len = 1; | ||
381 | c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
382 | } | ||
383 | |||
284 | return ret; | 384 | return ret; |
285 | error: | 385 | error: |
286 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | 386 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); |