#include <linux/kernel.h>
#include <media/saa7146_vv.h>
static void calculate_output_format_register(struct saa7146_dev* saa, u32 palette, u32* clip_format)
{
/* clear out the necessary bits */
*clip_format &= 0x0000ffff;
/* set these bits new */
*clip_format |= (( ((palette&0xf00)>>8) << 30) | ((palette&0x00f) << 24) | (((palette&0x0f0)>>4) << 16));
}
static void calculate_hps_source_and_sync(struct saa7146_dev *dev, int source, int sync, u32* hps_ctrl)
{
*hps_ctrl &= ~(MASK_30 | MASK_31 | MASK_28);
*hps_ctrl |= (source << 30) | (sync << 28);
}
static void calculate_hxo_and_hyo(struct saa7146_vv *vv, u32* hps_h_scale, u32* hps_ctrl)
{
int hyo = 0, hxo = 0;
hyo = vv->standard->v_offset;
hxo = vv->standard->h_offset;
*hps_h_scale &= ~(MASK_B0 | 0xf00);
*hps_h_scale |= (hxo << 0);
*hps_ctrl &= ~(MASK_W0 | MASK_B2);
*hps_ctrl |= (hyo << 12);
}
/* helper functions for the calculation of the horizontal- and vertical
scaling registers, clip-format-register etc ...
these functions take pointers to the (most-likely read-out
original-values) and manipulate them according to the requested
changes.
*/
/* hps_coeff used for CXY and CXUV; scale 1/1 -> scale 1/64 */
static struct {
u16 hps_coeff;
u16 weight_sum;
} hps_h_coeff_tab [] = {
{0x00, 2}, {0x02, 4}, {0x00, 4}, {0x06, 8}, {0x02, 8},
{0x08, 8}, {0x00, 8}, {0x1E, 16}, {0x0E, 8}, {0x26, 8},
{0x06, 8}, {0x42, 8}, {0x02, 8}, {0x80, 8}, {0x00, 8},
{0xFE, 16}, {0xFE, 8}, {0x7E, 8}, {0x7E, 8}, {0x3E, 8},
{0x3E, 8}, {0x1E, 8}, {0x1E, 8}, {0x0E, 8}, {0x0E, 8},
{0x06, 8}, {0x06, 8}, {0x02, 8}, {0x02, 8}, {0x00, 8},
{0x00, 8}, {0xFE, 16}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8},
{0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8},
{0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8},
{0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0x7E, 8},
{0x7E, 8}, {0x3E, 8}, {0x3E, 8}, {0x1E, 8}, {0x1E, 8},
{0x0E, 8}, {0x0E, 8}, {0x06, 8}, {0x06, 8}, {0x02, 8},
{0x02, 8}, {0x00, 8}, {0x00, 8}, {0xFE, 16}
};
/* table of attenuation values for horizontal scaling */
static u8 h_attenuation[] = { 1, 2, 4, 8, 2, 4, 8, 16, 0};
/* calculate horizontal scale registers */
static int calculate_h_scale_registers(struct saa7146_dev *dev,
int in_x, int out_x, int flip_lr,
u32* hps_ctrl, u32* hps_v_gain, u32* hps_h_prescale, u32* hps_h_scale)
{
/* horizontal prescaler */
u32 dcgx = 0, xpsc = 0, xacm = 0, cxy = 0, cxuv = 0;
/* horizontal scaler */
u32 xim = 0, xp = 0, xsci =0;
/* vertical scale & gain */
u32 pfuv = 0;
/* helper variables */
u32 h_atten = 0, i = 0;
if ( 0 == out_x ) {
return -EINVAL;
}
/* mask out vanity-bit */
*hps_ctrl &= ~MASK_29;
/* calculate prescale-(xspc)-value: [n .. 1/2) : 1
[1/2 .. 1/3) : 2
[1/3 .. 1/4) : 3
... */
if (in_x > out_x) {
xpsc = in_x / out_x;
}
else {
/* zooming */
xpsc = 1;
}
/* if flip_lr-bit is set, number of pixels after
horizontal prescaling must be < 384 */
if ( 0 != flip_lr ) {
/* set vanity bit */
*hps_ctrl |= MASK_29;
while (in_x / xpsc >= 384 )
xpsc++;
}
/* if zooming is wanted, number of pixels after
horizontal prescaling must be < 768 */
else {
while ( in_x / xpsc >= 768 )
xpsc++;
}
/* maximum prescale is 64 (p.69) */
if ( xpsc >