diff options
author | Prashant Laddha <prladdha@cisco.com> | 2015-02-04 04:07:31 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-03-02 12:51:32 -0500 |
commit | 4e30a37345e6f723553d457becc423efa4bf2703 (patch) | |
tree | ee35f58a991571ddfc59179ff395d6c9f8c9f37c /drivers/media | |
parent | 559addc25b00ff3a40eff03a0b3873c2b6d726f8 (diff) |
[media] vivid sdr: Use LUT based implementation for sin/cos()
The common implementation for sin/cos in include/linux/fixp-arith.h
has been improved recently to provide higher precision.
Replacing native implementation of sin/cos in vivid sdr with common
implementation. This serves two purposes:
1. Improved accuracy: the native implementation based on the Taylor
series is more prone to rounding errors.
2. Reuse of common function: this is better compared to maintaining
native versions for each driver.
Suggested by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Cc: Antti Palosaari <crope@iki.fi>
Signed-off-by: Prashant Laddha <prladdha@cisco.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/platform/vivid/vivid-sdr-cap.c | 66 |
1 files changed, 27 insertions, 39 deletions
diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c index 4af55f18829f..5e089cb58a38 100644 --- a/drivers/media/platform/vivid/vivid-sdr-cap.c +++ b/drivers/media/platform/vivid/vivid-sdr-cap.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <media/v4l2-common.h> | 27 | #include <media/v4l2-common.h> |
28 | #include <media/v4l2-event.h> | 28 | #include <media/v4l2-event.h> |
29 | #include <media/v4l2-dv-timings.h> | 29 | #include <media/v4l2-dv-timings.h> |
30 | #include <linux/fixp-arith.h> | ||
30 | 31 | ||
31 | #include "vivid-core.h" | 32 | #include "vivid-core.h" |
32 | #include "vivid-ctrls.h" | 33 | #include "vivid-ctrls.h" |
@@ -423,40 +424,19 @@ int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) | |||
423 | return 0; | 424 | return 0; |
424 | } | 425 | } |
425 | 426 | ||
426 | #define FIXP_FRAC (1 << 15) | 427 | #define FIXP_N (15) |
427 | #define FIXP_PI ((int)(FIXP_FRAC * 3.141592653589)) | 428 | #define FIXP_FRAC (1 << FIXP_N) |
428 | 429 | #define FIXP_2PI ((int)(2 * 3.141592653589 * FIXP_FRAC)) | |
429 | /* cos() from cx88 driver: cx88-dsp.c */ | ||
430 | static s32 fixp_cos(unsigned int x) | ||
431 | { | ||
432 | u32 t2, t4, t6, t8; | ||
433 | u16 period = x / FIXP_PI; | ||
434 | |||
435 | if (period % 2) | ||
436 | return -fixp_cos(x - FIXP_PI); | ||
437 | x = x % FIXP_PI; | ||
438 | if (x > FIXP_PI/2) | ||
439 | return -fixp_cos(FIXP_PI/2 - (x % (FIXP_PI/2))); | ||
440 | /* Now x is between 0 and FIXP_PI/2. | ||
441 | * To calculate cos(x) we use it's Taylor polinom. */ | ||
442 | t2 = x*x/FIXP_FRAC/2; | ||
443 | t4 = t2*x/FIXP_FRAC*x/FIXP_FRAC/3/4; | ||
444 | t6 = t4*x/FIXP_FRAC*x/FIXP_FRAC/5/6; | ||
445 | t8 = t6*x/FIXP_FRAC*x/FIXP_FRAC/7/8; | ||
446 | return FIXP_FRAC-t2+t4-t6+t8; | ||
447 | } | ||
448 | |||
449 | static inline s32 fixp_sin(unsigned int x) | ||
450 | { | ||
451 | return -fixp_cos(x + (FIXP_PI / 2)); | ||
452 | } | ||
453 | 430 | ||
454 | void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) | 431 | void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) |
455 | { | 432 | { |
456 | u8 *vbuf = vb2_plane_vaddr(&buf->vb, 0); | 433 | u8 *vbuf = vb2_plane_vaddr(&buf->vb, 0); |
457 | unsigned long i; | 434 | unsigned long i; |
458 | unsigned long plane_size = vb2_plane_size(&buf->vb, 0); | 435 | unsigned long plane_size = vb2_plane_size(&buf->vb, 0); |
459 | int fixp_src_phase_step, fixp_i, fixp_q; | 436 | s32 src_phase_step; |
437 | s32 mod_phase_step; | ||
438 | s32 fixp_i; | ||
439 | s32 fixp_q; | ||
460 | 440 | ||
461 | /* | 441 | /* |
462 | * TODO: Generated beep tone goes very crackly when sample rate is | 442 | * TODO: Generated beep tone goes very crackly when sample rate is |
@@ -466,28 +446,36 @@ void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) | |||
466 | 446 | ||
467 | /* calculate phase step */ | 447 | /* calculate phase step */ |
468 | #define BEEP_FREQ 1000 /* 1kHz beep */ | 448 | #define BEEP_FREQ 1000 /* 1kHz beep */ |
469 | fixp_src_phase_step = DIV_ROUND_CLOSEST(2 * FIXP_PI * BEEP_FREQ, | 449 | src_phase_step = DIV_ROUND_CLOSEST(FIXP_2PI * BEEP_FREQ, |
470 | dev->sdr_adc_freq); | 450 | dev->sdr_adc_freq); |
471 | 451 | ||
472 | for (i = 0; i < plane_size; i += 2) { | 452 | for (i = 0; i < plane_size; i += 2) { |
473 | dev->sdr_fixp_mod_phase += fixp_cos(dev->sdr_fixp_src_phase); | 453 | mod_phase_step = fixp_cos32_rad(dev->sdr_fixp_src_phase, |
474 | dev->sdr_fixp_src_phase += fixp_src_phase_step; | 454 | FIXP_2PI) >> (31 - FIXP_N); |
455 | |||
456 | dev->sdr_fixp_src_phase += src_phase_step; | ||
457 | dev->sdr_fixp_mod_phase += mod_phase_step; | ||
475 | 458 | ||
476 | /* | 459 | /* |
477 | * Transfer phases to [0 / 2xPI] in order to avoid variable | 460 | * Transfer phases to [0 / 2xPI] in order to avoid variable |
478 | * overflow and make it suitable for cosine implementation | 461 | * overflow and make it suitable for cosine implementation |
479 | * used, which does not support negative angles. | 462 | * used, which does not support negative angles. |
480 | */ | 463 | */ |
481 | while (dev->sdr_fixp_mod_phase < (0 * FIXP_PI)) | 464 | while (dev->sdr_fixp_mod_phase < FIXP_2PI) |
482 | dev->sdr_fixp_mod_phase += (2 * FIXP_PI); | 465 | dev->sdr_fixp_mod_phase += FIXP_2PI; |
483 | while (dev->sdr_fixp_mod_phase > (2 * FIXP_PI)) | 466 | while (dev->sdr_fixp_mod_phase > FIXP_2PI) |
484 | dev->sdr_fixp_mod_phase -= (2 * FIXP_PI); | 467 | dev->sdr_fixp_mod_phase -= FIXP_2PI; |
468 | |||
469 | while (dev->sdr_fixp_src_phase > FIXP_2PI) | ||
470 | dev->sdr_fixp_src_phase -= FIXP_2PI; | ||
485 | 471 | ||
486 | while (dev->sdr_fixp_src_phase > (2 * FIXP_PI)) | 472 | fixp_i = fixp_cos32_rad(dev->sdr_fixp_mod_phase, FIXP_2PI); |
487 | dev->sdr_fixp_src_phase -= (2 * FIXP_PI); | 473 | fixp_q = fixp_sin32_rad(dev->sdr_fixp_mod_phase, FIXP_2PI); |
488 | 474 | ||
489 | fixp_i = fixp_cos(dev->sdr_fixp_mod_phase); | 475 | /* Normalize fraction values represented with 32 bit precision |
490 | fixp_q = fixp_sin(dev->sdr_fixp_mod_phase); | 476 | * to fixed point representation with FIXP_N bits */ |
477 | fixp_i >>= (31 - FIXP_N); | ||
478 | fixp_q >>= (31 - FIXP_N); | ||
491 | 479 | ||
492 | /* convert 'fixp float' to u8 */ | 480 | /* convert 'fixp float' to u8 */ |
493 | /* u8 = X * 127.5f + 127.5f; where X is float [-1.0 / +1.0] */ | 481 | /* u8 = X * 127.5f + 127.5f; where X is float [-1.0 / +1.0] */ |