aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
authorPrashant Laddha <prladdha@cisco.com>2015-02-04 04:07:31 -0500
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>2015-03-02 12:51:32 -0500
commit4e30a37345e6f723553d457becc423efa4bf2703 (patch)
treeee35f58a991571ddfc59179ff395d6c9f8c9f37c /drivers/media
parent559addc25b00ff3a40eff03a0b3873c2b6d726f8 (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.c66
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 */
430static 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
449static inline s32 fixp_sin(unsigned int x)
450{
451 return -fixp_cos(x + (FIXP_PI / 2));
452}
453 430
454void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) 431void 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] */