/*
* ImgTec IR Hardware Decoder found in PowerDown Controller.
*
* Copyright 2010-2014 Imagination Technologies Ltd.
*
* This ties into the input subsystem using the RC-core. Protocol support is
* provided in separate modules which provide the parameters and scancode
* translation functions to set up the hardware decoder and interpret the
* resulting input.
*/
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <media/rc-core.h>
#include "img-ir.h"
/* Decoders lock (only modified to preprocess them) */
static DEFINE_SPINLOCK(img_ir_decoders_lock);
extern struct img_ir_decoder img_ir_nec;
extern struct img_ir_decoder img_ir_jvc;
extern struct img_ir_decoder img_ir_sony;
extern struct img_ir_decoder img_ir_sharp;
extern struct img_ir_decoder img_ir_sanyo;
static bool img_ir_decoders_preprocessed;
static struct img_ir_decoder *img_ir_decoders[] = {
#ifdef CONFIG_IR_IMG_NEC
&img_ir_nec,
#endif
#ifdef CONFIG_IR_IMG_JVC
&img_ir_jvc,
#endif
#ifdef CONFIG_IR_IMG_SONY
&img_ir_sony,
#endif
#ifdef CONFIG_IR_IMG_SHARP
&img_ir_sharp,
#endif
#ifdef CONFIG_IR_IMG_SANYO
&img_ir_sanyo,
#endif
NULL
};
#define IMG_IR_F_FILTER BIT(RC_FILTER_NORMAL) /* enable filtering */
#define IMG_IR_F_WAKE BIT(RC_FILTER_WAKEUP) /* enable waking */
/* code type quirks */
#define IMG_IR_QUIRK_CODE_BROKEN 0x1 /* Decode is broken */
#define IMG_IR_QUIRK_CODE_LEN_INCR 0x2 /* Bit length needs increment */
/* functions for preprocessing timings, ensuring max is set */
static void img_ir_timing_preprocess(struct img_ir_timing_range *range,
unsigned int unit)
{
if (range->max < range->min)
range->max = range->min;
if (unit) {
/* multiply by unit and convert to microseconds */
range->min = (range->min*unit)/1000;
range->max = (range->max*unit + 999)/1000; /* round up */
}
}
static void img_ir_symbol_timing_preprocess(struct img_ir_symbol_timing *timing,
unsigned int unit)
{
img_ir_timing_preprocess(&timing->pulse, unit);
img_ir_timing_preprocess(&timing->space, unit);
}
static void img_ir_timings_preprocess(struct img_ir_timings *timings,
unsigned int unit)
{
img_ir_symbol_timing_preprocess(&timings->ldr, unit);
img_ir_symbol_timing_preprocess(&timings->s00, unit);
img_ir_symbol_timing_preprocess(&timings->s01, unit);
img_ir_symbol_timing_preprocess(&timings->s10, unit);
img_ir_symbol_timing_preprocess(&timings->s11, unit);
/* default s10 and s11 to s00 and s01 if no leader */
if (unit)
/* multiply by unit and convert to microseconds (round up) */
timings->ft.ft_min = (timings->ft.ft_min*unit + 999)/1000;
}
/* functions for filling empty fields with defaults */
static void img_ir_timing_defaults(struct img_ir_timing_range *range,
struct img_ir_timing_range *defaults)
{
if (!range->min)
range->min = defaults->min;
if (!range->max)
range->max = defaults->max;
}
static void img_ir_symbol_timing_defaults(struct img_ir_symbol_timing *timing,
struct img_ir_symbol_timing *defaults)
{
img_ir_timing_defaults(&timing->pulse, &defaults->pulse);
img_ir_timing_defaults(&timing->space, &defaults->space);
}
static void img_ir_timings_defaults(struct img_ir_timings *timings,
struct img_ir_timings *defaults)
{
img_ir_symbol_timing_defaults(&timings->ldr, &defaults->ldr);
img_ir_symbol_timing_defaults(&timings->s00, &defaults->s00);
img_ir_symbol_timing_defaults(&timings->s01, &defaults->s01);
img_ir_symbol_timing_defaults(&timings->s10, &defaults->s10);
img_ir_symbol_timing_defaults(&timings->s11, &defaults->s11);
if (!timings->ft.ft_min)
timings->ft.ft_min = defaults->ft.ft_min;
}
/* functions for converting timings to register values */
/**
* img_ir_control() - Convert control struct to control register value.
* @control: Control data
*
* Returns: The control register value equivalent of @control.
*/
static u32 img_ir_control(const struct img_ir_control *control)
{
u32 ctrl = control->code_type << IMG_IR_CODETYPE_SHIFT;
if (control->decoden)
ctrl |= IMG_IR_DECODEN;
if (control->hdrtog)
ctrl |= IMG_IR_HDRTOG;
if (control->ldrdec)
ctrl |= IMG_IR_LDRDEC;
if (control->dec