/*****************************************************************************/
/* Copyright (c) 2009 NXP B.V.                                               */
/*                                                                           */
/* This program is free software; you can redistribute it and/or modify      */
/* it under the terms of the GNU General Public License as published by      */
/* the Free Software Foundation, using version 2 of the License.             */
/*                                                                           */
/* This program is distributed in the hope that it will be useful,           */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the              */
/* GNU General Public License for more details.                              */
/*                                                                           */
/* You should have received a copy of the GNU General Public License         */
/* along with this program; if not, write to the Free Software               */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307       */
/* USA.                                                                      */
/*                                                                           */
/*****************************************************************************/
/**
    @file   phStbScartSwitchUda.c
    @brief  Linux implementation of the UDA3000 (AV Scart switch) driver.

    @b  Module:  UDA3000 (AV Scart switch) driver.

*//*

Rev Date        Author      Comments
--------------------------------------------------------------------------------
    20061009    frq06781    Creation.
    20061218    frq06781    - Modified to use the full range of audio values
                            - Added GetVolume ioctl.
    20061221    frq06781    Changed to allow CVBS and RGB mode simultaneously.
    20070130    frq06781    Modify to externalize API (for ALSA).
    20081015    frq06751    Import component into stb225 database
  3 20090121    batelaan    Update license header
  4 20090126    Jiang Qian  Set default TV video format as cvbs, as HD have no RGB
  5 20090226    boudy       Add Get/Set IOCTL to control slow blanking and video format
                            with one IOCTL and one associated data structure
  6 20090325    boudy       Add enable/disable output (shadow of PR SHZ_STB2#251)
  7 20090407    ocourson    Compiling issue
  8 20090407    ocourson    VCR output loses fidelity (shadow of PR SHZ_STB2#372)
                            Remove unused code
--------------------------------------------------------------------------------
    For consistency and standardisation retain the Section Separators.
*/


/*============================================================================*/
/*                   STANDARD INCLUDE FILES                                   */
/*============================================================================*/
#include <tmtypes.h>                    // DVP standard types/defines/enums
#include <tmosal.h>                     // DVP Operating System Adaptaion Layer

#include <linux/init.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/fs.h>

#include <linux/i2c.h>
#include <linux/i2c-dev.h>

/*============================================================================*/
/*                   PROJECT INCLUDE FILES                                    */
/*============================================================================*/
#include "tmdlPio.h"
#include "phStbScartSwitch.h"

/*============================================================================*/
/*                   MACRO DEFINITION                                         */
/*============================================================================*/
#define REPORT_BUG()  printk("BUG in %s:: %s::%i\n", __FILE__, __FUNCTION__, \
        __LINE__)

/* I2C constants */
#define I2C_UDA3000    0x22
#define I2C_NAME(s) (s)->name
#define BUFFER_LENGTH  10

/* Notification task */
#define INT_PIO_TASK_PRIORITY     (tmosalTaskPriority_t)30
#define INT_PIO_TASK_STACK_SIZE   (uint32_t)8000
#define INT_PIO_TASK_NAME         "P15T"

/* Notification queue */
#define INT_PIO_QUEUE_MAX_PACKETS      (uint32_t)40
#define INT_PIO_QUEUE_MAX_PACKETS_SIZE (uint32_t)4
#define INT_PIO_SEND_TIMEOUT           1000
#define INT_PIO_MSG_CLOSE              (uint32_t)0xFFFFFFFE
#define INT_PIO_MSG_STATE_CHANGE       (uint32_t)0xFFFFFFFD

/* Number of registers in UDA3000 */
#define UDA3000_NR_REG 12

/* Number of config registers (read/write) */
#define NB_CONFIG_REG 10

/* Number of status registers (read only) */
#define NB_STATE_REG  2

/* Address of status registers (read only) */
#define ADR_STATE_REG 10

/* IO lines used for scart switch */
#define PHSTBSCARTSWITCH_UDA_INT_PIO_BIT   TMDL_PIO_PIN11_EVENT      /* Pio 11 */

/*============================================================================*/
/*                   TYPE DEFINITION                                          */
/*============================================================================*/

typedef struct
{
	UInt32 IntPioBit;
} phStbScartSwitchCfgUDA_t;

static const uint8_t gcRegInit[] =
{ //val    reg
    0x00, //0 I2S DAC CONTROL MUTE
    0x0, //1 loopthrough on audio
    0x1f, //2 tv audio volume
    0x1f, //3 vcr audio volume
    0x0, //4 no standby and interrupt on all events
    0x9, //5 loopthrough on video
    0x1f, //6 activation of outputs
    0xa0, //7 clamp and source for DC restore (must be updated after stabilisation)
    0x0, //8 video ident is invcr
    0x3c  //9 loopthrough on blankings 	
		/* change from 0x3d => 0x3c, 
		because on HD mode, will not output rgb, FBTV should set to 0V
		on SD mode, application will set to its preferred mode, so default value means nothing.*/
    //0x00 //A status
    //0x00 //B status
};

static const uint8_t gcAudioValues[] =
{ /* audio levels */
     0, /* -62 db */
    12, /* -38 db */
    13, /* -36 db */
    14, /* -34 db */
    15, /* -32 db */
    16, /* -30 db */
    17, /* -28 db */
    18, /* -26 db */
    19, /* -24 db */
    20, /* -22 db */
    21, /* -20 db */
    22, /* -18 db */
    23, /* -16 db */
    24, /* -14 db */
    25, /* -12 db */
    26, /* -10 db */
    27, /*  -8 db */
    28, /*  -6 db */
    29, /*  -4 db */
    30, /*  -2 db */
    31, /*   0 db */
    32, /*  +2 db */
    33, /*  +4 db */
    34  /*  +6 db */
};


/*============================================================================*/
/*                   PUBLIC VARIABLES DEFINITION                              */
/*============================================================================*/

/*============================================================================*/
/*                   STATIC VARIABLES DECLARATIONS                            */
/*============================================================================*/
//static tmInstance_t                  gI2cInstance = 0;

static phStbScartSwitchOutputMode_t  gTVOutputMode;
static phStbScartSwitchVideoFormat_t gTVVideoFormat;
static phStbScartSwitchSBMode_t      gTVSBMode;
static phStbScartSwitchSBValue_t     gTVSBValue;
static phStbScartSwitchFBMode_t      gTVFBMode;

static phStbScartSwitchOutputMode_t  gVCROutputMode;
static phStbScartSwitchVideoFormat_t gVCRVideoFormat;
static phStbScartSwitchSBMode_t      gVCRSBMode;
static phStbScartSwitchSBValue_t     gVCRSBValue;
static phStbScartSwitchFBMode_t      gVCRFBMode;

static uint8_t gRegisters[12];

/* management of PIO task */
static tmosalQueueHandle_t           gIntPioMsgQueueHandle;
#ifdef AUTO_LOOPTHROUGH_ENABLE
static tmosalTaskHandle_t            gTaskHandle;
static tmInstance_t                  gPioInstance;
#endif

static pScartSwitchCallback_t        gVCRSBCallbackFunc = Null;

static phStbScartSwitchCfgUDA_t      gScartSwitchCfg;

static int                           loopthrough = 1;

/* I2C Support Structures */
/* Generic i2c probe ... addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */
static unsigned short normal_i2c      [ ] =   { I2C_UDA3000 >> 1, I2C_CLIENT_END };
static unsigned short probe           [2] =   { I2C_CLIENT_END  , I2C_CLIENT_END };
static unsigned short ignore          [2] =   { I2C_CLIENT_END  , I2C_CLIENT_END };

static struct i2c_client_address_data dataAddress =
{
    .normal_i2c         =   normal_i2c,
    .probe              =   probe,
    .ignore             =   ignore
};

static struct i2c_client *udaClient = NULL;


/*============================================================================*/
/*                   STATIC FUNCTIONS DECLARATIONS                            */
/*============================================================================*/
#ifdef AUTO_LOOPTHROUGH_ENABLE
static void PioTask(void *pvoid_dummy);
#endif
static int32_t I2cInit(void);
static int32_t I2cTerminate(void);
static int32_t I2cRead(uint32_t kByteCount, uint8_t kSubAdr, uint8_t* pData);
static int32_t I2cWrite(uint32_t kByteCount, uint8_t kSubAdr, uint8_t* pData);
static int     I2cDetectUdaClient(struct i2c_adapter *adapter, int address, int kind);
static int     I2cAttachUdaAdapter(struct i2c_adapter *adapter);
static int     I2cDetachUdaClient(struct i2c_client *client);
static uint32_t SetTvVideoFormat(phStbScartSwitchVideoFormat_t kFormat);
static uint32_t SetVcrVideoFormat(phStbScartSwitchVideoFormat_t kFormat);
static uint32_t SetVcrVideoFormatForExtDenc(phStbScartSwitchVideoFormat_t kFormat);
static uint32_t SetTVSBValue(phStbScartSwitchSBValue_t kValue);
static uint32_t SetVCRSBValue(phStbScartSwitchSBValue_t kValue);

/* Local functions to configure registers */
static int32_t phStbScartSwitchUDAInit(               void                                                                               );
static int32_t phStbScartSwitchUDATerminate(          void                                                                               );
static int32_t phStbScartSwitchUDASetVolume(          phStbScartSwitchScartId_t kScartNumber, uint8_t kVolume                            );
static int32_t phStbScartSwitchUDAGetVolume(          phStbScartSwitchScartId_t kScartNumber, uint8_t *kVolume                           );
static int32_t phStbScartSwitchUDASetOutputMode(      phStbScartSwitchScartId_t kScartNumber, phStbScartSwitchOutputMode_t kMode         );
static int32_t phStbScartSwitchUDASetVideoFormat(     phStbScartSwitchScartId_t kScartNumber, phStbScartSwitchVideoFormat_t kFormat      );
static int32_t phStbScartSwitchUDAGetVideoFormat(     phStbScartSwitchScartId_t kScartNumber, phStbScartSwitchVideoFormat_t* pFormat     );
static int32_t phStbScartSwitchUDASetSBMode(          phStbScartSwitchScartId_t kScartNumber, phStbScartSwitchSBMode_t kMode             );
static int32_t phStbScartSwitchUDASetSBValue(         phStbScartSwitchScartId_t kScartNumber, phStbScartSwitchSBValue_t kValue           );
static int32_t phStbScartSwitchUDAGetSBValue(         phStbScartSwitchScartId_t kScartNumber, phStbScartSwitchSBValue_t* pValue          );
static int32_t phStbScartSwitchUDAInstallSBCallback(  phStbScartSwitchScartId_t kScartNumber, pScartSwitchCallback_t pFunc               );
static int32_t phStbScartSwitchUDASetFBMode(          phStbScartSwitchScartId_t kScartNumber, phStbScartSwitchFBMode_t kFBMode           );
static int32_t phStbScartSwitchUDASetAudioSource(     phStbScartSwitchScartId_t kScartNumber, phStbScartSwitchAudioSource_t kAudioSource );
static int32_t phStbScartSwitchUDASetAudioCommonMute( phStbScartSwitchAudioCommonMute_t kMute                                            );

static struct i2c_driver i2cDriverUda =
{
    .driver = {
        .name = PH_STB_SCART_SWITCH_DEVNAME,
    },
    .id = I2C_DRIVERID_AK470X,
    .attach_adapter = I2cAttachUdaAdapter,
    .detach_client = I2cDetachUdaClient,
};

/* -------------------------------------------------------------------------- */
/* FUNCTION:    PioTask                                                       */
/*                                                                            */
/* DESCRIPTION: This function un-initialise the avswitch.                     */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
#ifdef AUTO_LOOPTHROUGH_ENABLE
static void PioTask(void *pvoid_dummy)
{
    uint32_t          eventMsg;
    uint32_t          eventMsgSize;
    uint32_t          ret;
    uint8_t           OldRegA;
    uint8_t           OldRegB;

    if (pvoid_dummy); /* to avoid a warning */

    while(1)
    {
        tmosalQueueReceive(gIntPioMsgQueueHandle, &eventMsg,
                           &eventMsgSize, Null, tmosalQueueReceiveFlagNone);

        switch (eventMsg)
        {
            case INT_PIO_MSG_CLOSE:
            {
                tmosalQueueDestroy(gIntPioMsgQueueHandle);
                tmosalTaskExit();
            }
            break;

            case INT_PIO_MSG_STATE_CHANGE:
            {
                /* WARNING : if there is fast change on fast blanking         */
                /* it may overload soft by generating lots of interruptions   */
                /* save current state of the 2 state registers */
                OldRegA = gRegisters[0xA];
                OldRegB = gRegisters[0xB];
                ret = I2cRead(NB_STATE_REG, ADR_STATE_REG, &gRegisters[ADR_STATE_REG]); /* Read status registers */

                if (ret == TM_OK)
                {
                    /* check for video detection change */
                    if ( (OldRegB & 0x80) != (gRegisters[0xB] & 0x80) )
                    {
                        /* check if a signal is detected */
                        if (gRegisters[0xB] & 0x80)
                        {
                            /* a signal is present              */
                            /* look for the video ident source  */
                            if ( ( (gRegisters[0x8]) & 0x07) == 1 )
                            {
                                /* source is DECV */
                                /* set DC Restore source Control to DECV */
                                gRegisters[0x7] &= ~0x60; /* -00----- */
                            }
                            else
                            if ( ( (gRegisters[0x8]) & 0x07) == 2 )
                            {
                                /* source is DECY */
                                /* set DC Restore source Control to DECY */
                                gRegisters[0x7] &= ~0x40; /* -01----- */
                                gRegisters[0x7] |= 0x20;
                            }
                            else
                            if ( ( (gRegisters[0x8]) & 0x07) == 3 )
                            {
                                /* source is INVCR */
                                /* set DC Restore source Control to INVCR */
                                gRegisters[7] &= ~0x20; /* -10----- */
                                gRegisters[7] |= 0x40;
                            }
                        }
                        else
                        {
                            /* we lost the signal */
                            /* set DC Restore source Control to "no source selected" */
                            gRegisters[0x7] |= 0x60; /* -11----- */
                        }
                        I2cWrite(1, 7, &gRegisters[7]);
                    }

                    /* This is only in loopthrough on video signals with loopthrough on FB */
                    if (   (gTVOutputMode == PHSTB_SCART_SWITCH_OUTPUT_LOOP_OTHER)
                        && (gTVFBMode == PHSTB_SCART_SWITCH_FB_OUT_LOOP)
                        && (gVCRFBMode == PHSTB_SCART_SWITCH_FB_IN) )
                    {
                        /* check Fast Blanking state on vcr */
                        if (gRegisters[0xA] & 0x4)
                        {
                            /* signal is RGB */
                            gRegisters[6] = 0xDF; /* 11011111 need to be more accurate */
                            gRegisters[7] |= 0x80;/* activate all*/
                            /* activate DC restore */
                            gRegisters[7] &= ~0x04;
                        }
                        else
                        {
                            /* Signal is CVBS (or Y/C ?) */
                            gRegisters[6] = 0xDF; /* 11011111 need to be more accurate */
                            /* activate clamping */
                            gRegisters[7] |= 0x04;
                        }
                        I2cWrite(2, 6, &gRegisters[6]);
                    }

                    /* Lauch user callback if defined */
                    if (gVCRSBCallbackFunc != Null)
                    {
                        /* Check if slow blanking is defined as an input */
                        if (gRegisters[9] & 0x80)
                        {
                            /* have to be called only on slow blanking change */
                            if ( ((gRegisters[0xA]) & 0x3) != (OldRegA & 0x3) )
                            {
                                if ( ( (gRegisters[0xA]) & 0x3) == 0 )
                                {
                                    gVCRSBCallbackFunc(0, Null, 0); // SB = 0
                                }
                                else
                                {
                                    gVCRSBCallbackFunc(1, Null, 0); // SB = 6 or 12V
                                }
                            }
                        }
                    }
                }
            }
            break;

            default:
                REPORT_BUG();
            break;
        }
    }
}
#endif


/* -------------------------------------------------------------------------- */
/* FUNCTION:    I2cInit                                                       */
/*                                                                            */
/* DESCRIPTION: Initialize I2C functionalities                                */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
static int32_t I2cInit(void)
{
    int32_t ret;

    ret = i2c_add_driver(&i2cDriverUda);
    if (ret == 0)
    {
        dprintk("%s (%s-%s) - Loopthrough %s\n",
                "Scart Switch driver (UDA3000)",
                __DATE__,
                __TIME__,
                loopthrough ? "enabled" : "disabled");
    }
    return ret;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    I2cTerminate                                                  */
/*                                                                            */
/* DESCRIPTION: This function un-initialise the avswitch.                     */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
static int32_t I2cTerminate(void)
{
    int32_t ret = 0;

    /* Active loopthrough */
    loopthrough = 1;
    i2c_del_driver(&i2cDriverUda);

    return ret;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    I2cRead                                                       */
/*                                                                            */
/* DESCRIPTION: I2C Read API function.                                        */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
static int32_t I2cRead(uint32_t kByteCount, uint8_t kSubAdr, uint8_t *pData)
{
    int32_t ret = 0;
    int i;
    int byteRead;

    if (udaClient == NULL)
    {
        dprintk("%s :I2C read -> no I2C bus registered\n", PH_STB_SCART_SWITCH_DESCRIPTION);
        ret = -EIO;
        goto I2cRead_error;
    }

    /* Write requested sub-address on I2C bus */
    if ( (ret = i2c_smbus_write_byte(udaClient, kSubAdr)) < 0 )
    {
        dprintk("%s : I2C read error -> i2c_smbus_write_byte has returned an error (%d)\n", PH_STB_SCART_SWITCH_DESCRIPTION, ret);
        goto I2cRead_error;
    }

    /* Read the requested number of bytes */
    for (i = 0; i < kByteCount; i++)
    {
        /* Read one byte on I2C bus */
        byteRead = i2c_smbus_read_byte(udaClient);

        /* Copy byte to output buffer if no error */
        if (byteRead < 0)
        {
            /* Read error */
            dprintk("%s : I2C read error\n", PH_STB_SCART_SWITCH_DESCRIPTION);
            ret = byteRead;
            goto I2cRead_error;
        }
        else
        {
            /* Read Ok -> copy byte to output buffer */
            *pData++ = byteRead;
        }
    }
    return 0;

I2cRead_error:
    return ret;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    I2cWrite                                                      */
/*                                                                            */
/* DESCRIPTION: I2C Write API function.                                       */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
static int32_t I2cWrite(uint32_t kByteCount, uint8_t kSubAdr, uint8_t *pData)
{
    int32_t ret = 0;
    struct i2c_msg msg;
    uint8_t reg;
    uint32_t i = 0;
    uint8_t localData[11];
    uint8_t *pLocalData = NULL;

    /* Sanity check */
    if (kSubAdr + (kByteCount - 1) > NB_CONFIG_REG)
    {
        dprintk("%s :I2C write -> incorrect parameters\n", PH_STB_SCART_SWITCH_DESCRIPTION);
        ret = -EIO;
        goto I2cWrite_error;
    }

    if (udaClient == NULL)
    {
        dprintk("%s :I2C write -> no I2C bus registered\n", PH_STB_SCART_SWITCH_DESCRIPTION);
        ret = -EIO;
        goto I2cWrite_error;
    }

    /* The uda3000 has an autoincrement function, use it if */
    /* The adapter understands raw I2C                      */
    if (i2c_check_functionality(udaClient->adapter, I2C_FUNC_I2C))
    {
        /* Prepare data for I2C data transfer */
        localData[0] = kSubAdr; /* Set MSB to 0 for autoincrement mode */
        /* Insert subaddress before data to write */
        for (i = 0; i < kByteCount; i++)
            localData[i + 1] = *(pData + i);
        pLocalData = localData;

        msg.len = (kByteCount + 1); /* nb bytes + sub address */
        msg.buf = (char*)pLocalData;
        msg.addr = (udaClient->addr);
        msg.flags = 0;

        ret = i2c_transfer(udaClient->adapter, &msg, 1);
        if (ret < 0)
        {
            dprintk("%s :I2C write error (autoincrement mode)\n", PH_STB_SCART_SWITCH_DESCRIPTION);
            goto I2cWrite_error;
        }
    }
    else
    {
        /* Prepare data for I2C data transfer */
        localData[0] = (kSubAdr | 0x80); /* Set MSB to 1 for non-autoincrement mode */

        /* Insert subaddress before data to write */
        for (i = 0; i < kByteCount; i++)
            localData[i + 1] = *(pData + i);

        for (i = 1, reg = localData[0]; i < (kByteCount + 1); i++, reg++)
        {
            if ((ret = i2c_smbus_write_byte_data(udaClient, reg, localData[i])) < 0)
            {
                dprintk("%s :I2C write error\n", PH_STB_SCART_SWITCH_DESCRIPTION);
                goto I2cWrite_error;
            }
        }
    }
    return 0;

I2cWrite_error:
    return ret;
}


static int I2cDetectUdaClient(struct i2c_adapter *adapter, int address, int kind)
{
    int ret = 0;

    dprintk("%s :Detect I2C client\n", PH_STB_SCART_SWITCH_DESCRIPTION);
    dprintk("%s :Detecting uda3000 client on address 0x%x\n", PH_STB_SCART_SWITCH_DESCRIPTION, address << 1);

    /* Check if the adapter supports the needed features */
    if (!i2c_check_functionality(adapter, (I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA) ))
    {
        dprintk("%s :Detect client -> ERROR function not supported\n", PH_STB_SCART_SWITCH_DESCRIPTION);
        return -ENXIO;
    }

    /* Create the I2C client data structure */
    udaClient = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
    if (udaClient == 0)
    {
        return -ENOMEM;
    }
    memset(udaClient, 0, sizeof(struct i2c_client));
    udaClient->addr = address;
    udaClient->adapter = adapter;
    udaClient->driver = &i2cDriverUda;
    snprintf(I2C_NAME(udaClient), (sizeof(I2C_NAME(udaClient))) - 1, "uda3000");

    /* Attach the AV switch to the I2C adapter */
    ret = i2c_attach_client(udaClient);
    if (ret)
    {
        dprintk("%s :Failed to attach to I2C client on adapter %s (0x%x) - 0x%02X\n",
                PH_STB_SCART_SWITCH_DESCRIPTION, I2C_NAME(adapter), adapter->id, ret);

        kfree(udaClient);
        return -EINVAL;
    }

    dprintk("%s :found device on I2C adapter %s (0x%x) - 0x%02X\n",
            PH_STB_SCART_SWITCH_DESCRIPTION, I2C_NAME(adapter), (adapter->id), ret);

    return 0;
}


static int I2cAttachUdaAdapter(struct i2c_adapter *adapter)
{
    uint32_t ret = 0;

    dprintk("%s :Attach UDA3000\n", PH_STB_SCART_SWITCH_DESCRIPTION);
    ret = i2c_probe(adapter, &dataAddress, &I2cDetectUdaClient);

    return ret;
}


static int I2cDetachUdaClient(struct i2c_client *client)
{
    int ret = 0;

    dprintk("%s :De-Attach I2C client (UDA3000)\n", PH_STB_SCART_SWITCH_DESCRIPTION);
    ret = i2c_detach_client(client);
    if (ret)
    {
        dprintk("%s :De-Attach I2C client failed (UDA3000)\n", PH_STB_SCART_SWITCH_DESCRIPTION);
        return ret;
    }
    kfree(client);

    return ret;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    SetTvVideoFormat                                              */
/*                                                                            */
/* DESCRIPTION: Set the TV video format (cvbs/rgb/yc) and activate the        */
/*              corresponding output.                                         */
/*              This function only affect the local copy of register          */
/*              (no write on i2c)                                             */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
static uint32_t SetTvVideoFormat(phStbScartSwitchVideoFormat_t kFormat)
{
	switch (kFormat)
	{
        case PHSTB_SCART_SWITCH_RGB:
        case (PHSTB_SCART_SWITCH_RGB | PHSTB_SCART_SWITCH_CVBS): /* Mode RGB allow also CVBS mode */
        {
            /* video format to CVBS or RGB : PTV2..0=001 */
            gRegisters[5] &= ~0x06; /* -----001 */
            gRegisters[5] |= 0x1;

            /* set clamp control to DC restore clamp active : CLMP1=0 */
            gRegisters[7] &= ~0x08; /* ----0---	*/

            /* activate : BTV, GTV, RCTV */
            gRegisters[6] |= 0x07;  /* -----111 */

            /* activate : OTV */
            gRegisters[7] |= 0x80;  /* 1------- */
        }
        break;

        case PHSTB_SCART_SWITCH_CVBS:
        {
            /* video format to CVBS or RGB : PTV2..0=001 */
            gRegisters[5] &= ~0x06; /* -----001 */
            gRegisters[5] |= 0x1;

            /* set clamp control to DC restore clamp active : CLMP1=0 */
            gRegisters[7] &= ~0x08; /* ----0--- */				

            /* unactivate : BTV, GTV, RCTV */
            gRegisters[6] &= ~0x07; /* -----000 */

            /* activate : OTV */
            gRegisters[7] |= 0x80;  /* 1------- */
        }
        break;

        case PHSTB_SCART_SWITCH_YC:
        {
            /* PNX denc must be reconfigured */
            /* video format to YC : PTV2..0=010 */
            gRegisters[5] &= ~0x05; /* -----010 */
            gRegisters[5] |= 0x2;

            /* set the clamp control to biased for chroma : CLMP1=1 */
            gRegisters[7] |= 0x08;  /* ----1--- */

            /* unactivate : BTV, GTV and activate : RCTV */
            gRegisters[6] &= ~0x06; /* -----001 */
            gRegisters[6] |= 0x01;
            /* activate : OTV */
            gRegisters[7] |= 0x80;  /* 1------- */
        }
        break;

        default:
            dprintk("%s :SetTvVideoFormat does not support these parameters (UDA3000)\n", PH_STB_SCART_SWITCH_DESCRIPTION);
        break;
	}

    return 0;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    SetVcrVideoFormat                                             */
/*                                                                            */
/* DESCRIPTION: Set the VCR video format (cvbs/rgb/yc) when video come from   */
/*              pnx internal denc activate the corresponding outputs.         */
/*              This function only affect the local copy of register          */
/*              (no write on i2c)                                             */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
static uint32_t SetVcrVideoFormat(phStbScartSwitchVideoFormat_t kFormat )
{
    switch (kFormat)
    {
        case PHSTB_SCART_SWITCH_RGB: /* To put something but not supported from internal denc */
        case PHSTB_SCART_SWITCH_CVBS:
        {
            /* sources are DECV and DECRC : PVCR2..0=001 */
            gRegisters[5] &= ~0x30; /* --001--- */
            gRegisters[5] |= 0x08;

            /* enable VVCR and set VCR chominance output to GND : VCIO=1 */
            gRegisters[6] |= 0x48;  /* -1--1--- */
        }
        break;

        case PHSTB_SCART_SWITCH_YC:
        {
            /* PNX must be reconfigured */
            /* sources are DECV and DECRC : PVCR2..0=001 */
            gRegisters[5] &= ~0x30; /* --001--- */
            gRegisters[5] |= 0x08;

            /* enable VVCR and enable the VCR chominance output : VCIO=0 ; CVCR=1 */
            gRegisters[6] &= ~0x40; /* -01-1--- */
            gRegisters[6] |= 0x28;
        }
        break;

        default:
        break;
    }
    return 0;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    SetVcrVideoFormatForExtDenc                                   */
/*                                                                            */
/* DESCRIPTION: Set the VCR video format (cvbs/rgb/yc) when video come from   */
/*              pnx internal denc activate the corresponding outputs.         */
/*              This function only affect the local copy of register          */
/*              (no write on i2c)                                             */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
static uint32_t SetVcrVideoFormatForExtDenc(phStbScartSwitchVideoFormat_t kFormat)
{
    switch (kFormat)
    {
        case PHSTB_SCART_SWITCH_RGB: /* only cvbs signal go through avswitch */
        case PHSTB_SCART_SWITCH_CVBS:
        {
            /* sources are DECY and DECC : PVCR2..0=010 */
            gRegisters[5] &= 0xc7; /* --010--- */
            gRegisters[5] |= 0x10;

            /* enable VVCR and set VCR chominance output to GND : VCIO=1 */
            gRegisters[6] |= 0x48; /* -1--1--- */
        }
        break;

        case PHSTB_SCART_SWITCH_YC:
        {
            /* sources are DECY and DECC : PVCR2..0=010 */
            gRegisters[5] &= 0xc7; /* --010--- */
            gRegisters[5] |= 0x10;

            /* enable VVCR and enable the VCR chominance output : VCIO=0 ; CVCR=1 */
            gRegisters[6] &= ~0x40; /* -01-1--- */
            gRegisters[6] |= 0x28;
        }
        break;

        default:
        break;
    }
    return 0;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    SetTVSBValue                                                  */
/*                                                                            */
/* DESCRIPTION: Change the TV Slow Blanking level.                            */
/*              This function may be called only if SB is an output           */
/*              This function only affect the local copy of register          */
/*              (no write on i2c)                                             */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
static uint32_t SetTVSBValue(phStbScartSwitchSBValue_t kValue)
{
    switch (kValue)
    {
        case PHSTB_SCART_SWITCH_SB_4_3:
        {
            gRegisters[9] |= 0x0C;  /* ----11-- */
        }
        break;

        case PHSTB_SCART_SWITCH_SB_16_9:
        {
            gRegisters[9] &= ~0x08; /* ----01-- */
            gRegisters[9] |= 0x04;
        }
        break;

        case PHSTB_SCART_SWITCH_SB_LOW:
        {
            gRegisters[9] &= ~0x0C; /* ----00-- */
        }
        break;

        default:
        break;
    }
    return 0;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    SetVCRSBValue                                                 */
/*                                                                            */
/* DESCRIPTION: Change the VCR Slow Blanking level.                           */
/*              This function may be called only if SB is an output           */
/*              This function only affect the local copy of register          */
/*              (no write on i2c)                                             */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
static uint32_t SetVCRSBValue(phStbScartSwitchSBValue_t kValue)
{
    switch (kValue)
    {
        case PHSTB_SCART_SWITCH_SB_4_3:
        {
            gRegisters[9] |= 0x30;  /* --11---- */
        }
        break;

        case PHSTB_SCART_SWITCH_SB_16_9:
        {
            gRegisters[9] &= ~0x20; /* --01---- */
            gRegisters[9] |= 0x10;
        }
        break;

        case PHSTB_SCART_SWITCH_SB_LOW:
        {
            gRegisters[9] &= ~0x30; /* --00---- */
        }
        break;

        default:
        break;
    }
    return 0;
}

/* -------------------------------------------------------------------------- */
/* FUNCTION:    phStbScartSwitchCfgUDAGetConfig                               */
/*                                                                            */
/* DESCRIPTION: Specific config function for UDA driver.                      */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
uint32_t phStbScartSwitchCfgUDAGetConfig(phStbScartSwitchCfgUDA_t *pCfg)
{
    pCfg->IntPioBit = PHSTBSCARTSWITCH_UDA_INT_PIO_BIT;

    return 0;
}

/*============================================================================*/
/*                   PUBLIC FUNCTIONS DEFINITIONS                             */
/*============================================================================*/


/* -------------------------------------------------------------------------- */
/* FUNCTION:    phStbScartSwitchUDAInit                                       */
/*                                                                            */
/* DESCRIPTION: This function initialise the External Video Denc.             */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
static int32_t phStbScartSwitchUDAInit(void)
{
    int32_t ret;
#ifdef AUTO_LOOPTHROUGH_ENABLE
    tmdlPioInstanceSetup_t  tempioInstanceSetUp;
    tmdlPioInstanceSetup_t  *pioInstanceSetUp = &tempioInstanceSetUp;
    tmdlPioLines_t          ioLineSelInput;
    tmdlPioLines_t          ioLineSelOutput;
    tmdlPioLines_t          ioLineSelPeriph;
#endif
    uint8_t                 i;

    /* Retreive configuration */
    ret = phStbScartSwitchCfgUDAGetConfig(&gScartSwitchCfg);

    if (ret != 0)
        return ret;

    ret = I2cInit();

    if (ret != 0)
        return ret;

    for (i = 0; i < (sizeof(gcRegInit)); i++)
        gRegisters[i] = gcRegInit[i];

    ret = I2cWrite(NB_CONFIG_REG, 0, &gRegisters[0]);

    /* Init default values */
    gTVOutputMode = PHSTB_SCART_SWITCH_OUTPUT_LOOP_OTHER;
    gTVVideoFormat = PHSTB_SCART_SWITCH_RGB;
    gTVSBMode = PHSTB_SCART_SWITCH_SB_OUT_LOOP;
    gTVSBValue = PHSTB_SCART_SWITCH_SB_4_3;
    gTVFBMode = PHSTB_SCART_SWITCH_FB_OUT_LOOP;

    gVCROutputMode = PHSTB_SCART_SWITCH_OUTPUT_LOOP_OTHER;
    gVCRVideoFormat = PHSTB_SCART_SWITCH_CVBS;
    gVCRSBMode = PHSTB_SCART_SWITCH_SB_IN;
    gVCRSBValue = PHSTB_SCART_SWITCH_SB_4_3;
    gVCRSBCallbackFunc = Null;
    gVCRFBMode = PHSTB_SCART_SWITCH_FB_IN;

    tmosalTaskSleep(20);

    gRegisters[7]=0x80;
    ret = I2cWrite(NB_CONFIG_REG, 0, &gRegisters[0]);

    if (ret != 0)
        return ret;

    /* wait update of status according to new config */
    tmosalTaskSleep(20);

    if (ret != 0)
        return ret;

#ifdef AUTO_LOOPTHROUGH_ENABLE
    /* Setup UDA_INT_PIO msg to set the path in the task */
    ret = tmosalQueueCreate( INT_PIO_QUEUE_MAX_PACKETS,
                             INT_PIO_QUEUE_MAX_PACKETS_SIZE,
                             &gIntPioMsgQueueHandle,
                             tmosalQueueCreateFlagNone);
    if (ret != 0)
    {
        dprintk("%s : phStbScartSwitchUDAInit() -> tmosalQueueCreate failed\n", PH_STB_SCART_SWITCH_DESCRIPTION);
        return ret;
    }

    /* Setup UDA_INT_PIO task to set the path via i2c */
    /* waiting the above msg */
    ret = tmosalTaskCreate( PioTask, Null,
                            INT_PIO_TASK_PRIORITY,
                            INT_PIO_TASK_STACK_SIZE,
                            &gTaskHandle,
                            INT_PIO_TASK_NAME,
                            tmosalTaskStarted );
    if (ret != 0)
    {
        dprintk("%s :phStbScartSwitchUDAInit() -> tmosalTaskCreate failed\n", PH_STB_SCART_SWITCH_DESCRIPTION);
        return ret;
    }

    /* open GPIO devlib */
    ret = tmdlPioOpen(&gPioInstance);

    if (ret != 0)
    {
        dprintk("%s :phStbScartSwitchUDAInit() -> tmdlPioOpen() failed\n", PH_STB_SCART_SWITCH_DESCRIPTION);
        return ret;
    }

    /* get the instance setup */
    ret = tmdlPioGetInstanceSetup(gPioInstance, &pioInstanceSetUp);

    if (ret != 0)
    {
        dprintk("%s :phStbScartSwitchUDAInit() -> tmdlPioGetInstanceSetup failed\n", PH_STB_SCART_SWITCH_DESCRIPTION);
        return ret;
    }

    /* Config the lines which wanted UDA_INT_PIO */
    (pioInstanceSetUp->lineSelect) = (gScartSwitchCfg.IntPioBit);

    ret = tmdlPioInstanceSetup(gPioInstance, pioInstanceSetUp);

    if(ret != 0)
    {
        dprintk("%s :phStbScartSwitchUDAInit() -> tmdlPioInstanceSetup() failed\n", PH_STB_SCART_SWITCH_DESCRIPTION);
        return ret;
    }

    ret = tmdlPioGetMode( gPioInstance,
                          &ioLineSelInput,
                          &ioLineSelOutput,
                          &ioLineSelPeriph );
    if (ret != 0)
    {
        dprintk("%s :phStbScartSwitchUDAInit() -> tmdlPioGetMode() failed\n", PH_STB_SCART_SWITCH_DESCRIPTION);
        return ret;
    }

    (ioLineSelInput) |= (gScartSwitchCfg.IntPioBit);

    /* Set PIO to I/O mode */
    ioLineSelPeriph = ( ioLineSelPeriph & (~(gScartSwitchCfg.IntPioBit))   );

    ret = tmdlPioSetMode( gPioInstance,
                          ioLineSelInput,
                          ioLineSelOutput,
                          ioLineSelPeriph );
    if (ret != 0)
    {
        dprintk("%s :phStbScartSwitchUDAInit() -> tmdlPioSetMode() failed\n", PH_STB_SCART_SWITCH_DESCRIPTION);
        return ret;
    }
#endif

    return 0;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    phStbScartSwitchUDATerminate                                  */
/*                                                                            */
/* DESCRIPTION: This function un-initialise the External Video Denc.          */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
static int32_t phStbScartSwitchUDATerminate(void)
{
    int32_t ret;
    uint32_t eventMsg = INT_PIO_MSG_CLOSE;
    uint32_t IntPioTimeout = INT_PIO_SEND_TIMEOUT;

    gVCRSBCallbackFunc = Null;

    ret = I2cTerminate();

    if (ret != 0)
        return ret;

    ret = tmosalQueueSend( (const tmosalQueueHandle_t)gIntPioMsgQueueHandle,
                           (const Pointer)&eventMsg,
                           (const uint32_t)INT_PIO_QUEUE_MAX_PACKETS_SIZE,
                           (const pUInt32)&IntPioTimeout,
                           (const tmosalQueueSendFlags_t)tmosalQueueSendFlagNone );

    if (ret != 0)
    {
        dprintk("%s :phStbScartSwitchUDATerminate() -> tmosalQueueSend() failed\n", PH_STB_SCART_SWITCH_DESCRIPTION);
        return ret;
    }

    return 0;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    phStbScartSwitchUDASetVolume                                  */
/*                                                                            */
/* DESCRIPTION: Modify the volume level on TV or VCR scart.                   */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
static int32_t phStbScartSwitchUDASetVolume(phStbScartSwitchScartId_t kScartNumber,
                                            uint8_t kVolume)
{
    int32_t ret = 0;
    uint8_t Vol;

    Vol = (kVolume >= 115) ?
    (gcAudioValues[(sizeof(gcAudioValues))-1]) : /* Too high ! set it to max value   */
    (gcAudioValues[(kVolume / 5)]); /* Ok. Retreive value in table.     */

    switch (kScartNumber)
    {
        case PHSTB_SCART_SWITCH_SCART_TV:
        {
            gRegisters[2] = Vol; /* let upper bits to 0 */
            ret = I2cWrite(1, 2, &gRegisters[2]);
        }
        break;

        case PHSTB_SCART_SWITCH_SCART_VCR:
        {
            gRegisters[3] = Vol; /* let upper bits to 0 */
            ret = I2cWrite(1, 3, &gRegisters[3]);
        }
        break;

        default:
        {
            dprintk("%s :phStbScartSwitchUDASetVolume error\n", PH_STB_SCART_SWITCH_DESCRIPTION);
            ret = -EINVAL;
        }
        break;
    }
    return ret;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    phStbScartSwitchUDAGetVolume                                  */
/*                                                                            */
/* DESCRIPTION: Get the volume level on TV or VCR scart.                      */
/*                                                                            */
/* RETURN:      uint32_t                                                      */
/* -------------------------------------------------------------------------- */
static int32_t phStbScartSwitchUDAGetVolume(phStbScartSwitchScartId_t kScartNumber,
                                            uint8_t *pVolume)
{
    int32_t ret = 0;
    uint8_t i;
    uint8_t Vol;
    uint8_t currentVolume = 0;

    switch (kScartNumber)
    {
        case PHSTB_SCART_SWITCH_SCART_TV:
        {
            /* Read audio level of TV scart */
            Vol = ( (gRegisters[2]) & 0x3F );
        }
        break;

        case PHSTB_SCART_SWITCH_SCART_VCR:
        {
            /* Read audio level of VCR scart */
            Vol = ( (gRegisters[3]) & 0x3F );
        }
        break;

        default:
        {
            dprintk("%s :phStbScartSwitchUDAGetVolume error -> unknown scart device\n", PH_STB_SCART_SWITCH_DESCRIPTION);
            ret = -EINVAL;
            goto phStbScartSwitchUDAGetVolume_error;
        }
        break;
    }

    /* Return volume level on range 0 -> 115 */
    for (i = 0; i < (sizeof(gcAudioValues)); i++)
    {
        if (gcAudioValues[i] == Vol)
        {
            currentVolume = (i * 5);
            break;
        }
        /* TODO : What if Vol is not in the table gcAudioValues */
    }

    /* Returns current audio value on range 0 -> 115 (percentage) */
    *pVolume = currentVolume;

    return 0;

phStbScartSwitchUDAGetVolume_error:
    return ret;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    phStbScartSwitchUDASetOutputMode                              */
/*                                                                            */
/* DESCRIPTION: Change VCR or TV scart output mode                            */
/*              (source, on, off, loopthrough). In case of activation of one  */
/*              scart, the previous format is used.                           */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
static int32_t phStbScartSwitchUDASetOutputMode(phStbScartSwitchScartId_t kScartNumber,
                                                phStbScartSwitchOutputMode_t kMode)
{
    int32_t ret = 0;

    switch (kScartNumber)
    {
        case PHSTB_SCART_SWITCH_SCART_TV:
        {
            gTVOutputMode = kMode;
            switch (kMode)
            {
                case PHSTB_SCART_SWITCH_OUTPUT_FROM_INT_DENC:
                {
                    gRegisters[1] &= ~0x06; /* -----00- */
                    /* DC restore source control, select source from DECV : VCLMP1..0=00 */
                    gRegisters[7] &= ~0x60; /* -00----- */
                    /* Video ident to DECV : SD2..0=001 */
                    gRegisters[8] &= ~0x06; /* -----001 */
                    gRegisters[8] |= 0x01;

                    SetTvVideoFormat(gTVVideoFormat);
                }
                break;

                /* Not supported for this scart */
                case PHSTB_SCART_SWITCH_OUTPUT_FROM_EXT_DENC:
                break;

                case PHSTB_SCART_SWITCH_OUTPUT_DISABLE:
                {
                    /* High Impedance of BTV,GTV,RCTV=-----000 */
                    gRegisters[6] &= ~0x07;
                    /* set DC Restore Source Control as no source:VCLMP1 VCLMP0 = -11----- */
                    gRegisters[7] |= 0x60;
                }
                break;

                case PHSTB_SCART_SWITCH_OUTPUT_ENABLE:
                {
                    /* Active of BTV, GTV, RCTV=-----111 */
                    gRegisters[6] |= 0x07;
                    /* set DC Restore source control as DECV:VCLMP1 VCLMP0 = -00----- */
                    gRegisters[7] &= ~0x60;
                }
                break;

                case PHSTB_SCART_SWITCH_OUTPUT_OFF:
                {
                    /* Mute the tv audio out : ATV1..0=11 */
                    gRegisters[1] |= 0x06; /* -----11- */

                    /* Unactivate tv output : PTV2..0 = 000 */
                    gRegisters[5] &= ~0x07;/* -----000 */

                    /* Unactivate : RFVID, BTV, GTV, RCTV */
                    gRegisters[6] &= ~0x87;/* 0----000 */

                    /* Unactivate : OTV */
                    gRegisters[7] &= ~0x80;/* 0------- */
                }
                break;

                case PHSTB_SCART_SWITCH_OUTPUT_LOOP_OTHER:
                {
                    /* Source of video ident=INVCR */
                    gRegisters[8] &= ~0x04;/* -----011 */
                    gRegisters[8] |= 0x03;

                    /* Set source for DC restore to "no source" */
                    gRegisters[7] |= 0x60; /* -11----- */

                    I2cWrite(2, 7, &gRegisters[7]);

                    /* Wait for correct status bit (video ident) */
                    tmosalTaskSleep(20); /* 10ms is working but... */

                    /* done in the task phStbScartSwitchI2cRead() */
                    /* Set source of audio tv out to vcr : ATV1..0=01 */
                    gRegisters[1] &= ~0x04; /* -----01- */
                    gRegisters[1] |= 0x02;

                    /* Set TV scart source to VCR scart : PTV2..0=100 */
                    gRegisters[5] &= ~0x03; /* -----100 */
                    gRegisters[5] |= 0x04;
					
#ifndef AUTO_LOOPTHROUGH_ENABLE
		    /* Read status registers */
                    /* Not necessary for auto loopthrough case, as it can be done by task */
                    I2cRead(NB_STATE_REG, ADR_STATE_REG, &gRegisters[ADR_STATE_REG]);
#endif
                    /* Check if there is a signal on VCR scart */
                    if (gRegisters[0xB] & 0x80)
                    {
                        /* May be possible to replace this code */
                        /* by a send message to the task */

                        /* Source of the synchro clamping to VCR */
                        gRegisters[7] &= ~0x20; /* -10----- */
                        gRegisters[7] |= 0x40;

                        /* To be correct, if a pio is used to set the fast blanking,  */
                        /* on vcr scart it must be "released"                         */
                        /* check if signal from VCR is CVBS or RGB with fast blanking */
                        if (gRegisters[0xA] & 0x4)
                        {
                            /* Signal is RGB */
                            /* DC restore */
                            gRegisters[7] &= ~0x04;
                        }
                        else
                        {
                            /* Signal is CVBS (or Y/C ?) */
                            /* Active bias for chroma signal */
                            gRegisters[7] |= 0x04;
                        }
                    }
                    else
                    {
                        /* No signal : updated will be done by the task */
                    }

                    /* Set the CVRC output selection to Gnd to be able  */
                    /* to handle something on VCR scart                 */
                    gRegisters[6] |= 0x60; /* -11----- */

                    /* Activate : BTV, GTV, RCTV */
                    gRegisters[6] |= 0x17; /* 1----111 */
                    /* activate : OTV */
                    gRegisters[7] |= 0x80; /* 1------- */
                }
                break;

                case PHSTB_SCART_SWITCH_OUTPUT_LOOP_SELF:
                {
                    /* What about audio ? */
                    /* Set tv cvbs as video out signal : PTV2..0=101 */
                    gRegisters[5] &= ~0x02; /* -----101 */
                    gRegisters[5] |= 0x05;

                    /* Unactivate : BTV, GTV, RCTV */
                    gRegisters[6] &= ~0x07; /* -----000 */

                    /* Activate : OTV */
                    gRegisters[7] |= 0x80;  /* 1------- */
                }
                break;

                default:
                break;
            }
        }
        break;

        case PHSTB_SCART_SWITCH_SCART_VCR:
        {
            gVCROutputMode = kMode;
            switch (kMode)
            {
                case PHSTB_SCART_SWITCH_OUTPUT_FROM_INT_DENC:
                {
                    /* Set VCR audio output to DAC : AVCR1..0=00 */
                    gRegisters[1] &= ~0x60; /* -00----- */

                    /* Done in set format function */
                    /* Activate CVRC and VCROUT outputs */
                    SetVcrVideoFormat(gVCRVideoFormat);
                }
                break;

                case PHSTB_SCART_SWITCH_OUTPUT_FROM_EXT_DENC:
                {
                    /* Mute VCR audio output */
                    gRegisters[1] |= 0x60; /* -11----- */

                    /* Something else to do ? */
                    /* Set format and activate outputs */
                    SetVcrVideoFormatForExtDenc(gVCRVideoFormat);
                }
                break;

                case PHSTB_SCART_SWITCH_OUTPUT_OFF:
                {
                    /* Mute vcr audio output */
                    gRegisters[1] |= 0x60; /* -11----- */

                    /* Set VCR video out to Hi-Z : PVCR2..0=000 */
                    gRegisters[5] &= ~0x38;/* --000--- */

                    /* Unactivate VCRC and VCRC outputs (CVRC to ground to enable input function) */
                    gRegisters[6] &= ~0x28;/* -10-0--- */
                    gRegisters[6] |= 0x40;
                }
                break;

                case PHSTB_SCART_SWITCH_OUTPUT_LOOP_OTHER:
                {
                    /* Set VCR audio output to TV */
                    gRegisters[1] &= ~0x40; /* -01----- */
                    gRegisters[1] |= 0x20;

                    /* Set VCR video out to TV : PVCR2..0=011 */
                    gRegisters[5] &= ~0x20; /* --011--- */
                    gRegisters[5] |= 0x18;

                    /* Activate VVCR output */
                    gRegisters[6] |= 0x08;  /* ----1--- */
                }
                break;

                case PHSTB_SCART_SWITCH_OUTPUT_LOOP_SELF:
                {
                    /* Set vcr video output to vcr video input ! */
                    gRegisters[5] &= ~0x18; /* --100--- */
                    gRegisters[5] |= 0x20;

                    /* What about audio */

                    /* Activate CVRC and VCROUT outputs */
                    gRegisters[6] |= 0x28;  /* -01-1--- */
                    gRegisters[6] &= ~0x40;
                }
                break;

                default:
                break;
            }
        }
        break;

        default:
        break;
    }

    /* Many things may have change then write all registers */
    ret = I2cWrite(NB_CONFIG_REG, 0, &gRegisters[0]);

    return ret;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    phStbScartSwitchUDASetVideoFormat                             */
/*                                                                            */
/* DESCRIPTION: Change video format (cvbs/rgb/yc)                             */
/*              If corresponding scart is off, only save the format           */
/*              else write the new format on i2c.                             */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
static int32_t phStbScartSwitchUDASetVideoFormat(phStbScartSwitchScartId_t kScartNumber,
                                                 phStbScartSwitchVideoFormat_t kFormat)
{
    int32_t ret = 0;
    uint8_t writereg = 0;

    switch (kScartNumber)
    {
        case PHSTB_SCART_SWITCH_SCART_TV:
        {
            gTVVideoFormat = kFormat;
            /* If the scart is currently used, we need to update device */
            if (gTVOutputMode == PHSTB_SCART_SWITCH_OUTPUT_FROM_INT_DENC)
            {
                SetTvVideoFormat(gTVVideoFormat);
                writereg = 1;
            }
        }
        break;

        case PHSTB_SCART_SWITCH_SCART_VCR:
        {
            gVCRVideoFormat = kFormat;
            /* If the scart is currently used, we need to update device */
            if (gVCROutputMode == PHSTB_SCART_SWITCH_OUTPUT_FROM_INT_DENC)
            {
                SetVcrVideoFormat(gVCRVideoFormat);
                writereg = 1;
            }
            else
            if (gVCROutputMode == PHSTB_SCART_SWITCH_OUTPUT_FROM_EXT_DENC)
            {
                SetVcrVideoFormatForExtDenc(gVCRVideoFormat);
                writereg = 1;
            }
        }
        break;

        default:
        break;
    }

    if (writereg)
    {
        /* Many things may have change then write all registers */
        ret = I2cWrite(NB_CONFIG_REG, 0, &gRegisters[0]);
    }

    return ret;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    phStbScartSwitchUDAGetVideoFormat                             */
/*                                                                            */
/* DESCRIPTION: Get video format (cvbs/rgb/yc)                                */
/*              Retrieve current output video format.                         */
/*                                                                            */
/* RETURN:      int32_t                                                       */
/* -------------------------------------------------------------------------- */
static int32_t phStbScartSwitchUDAGetVideoFormat(phStbScartSwitchScartId_t kScartNumber,
                                                 phStbScartSwitchVideoFormat_t *pFormat)
{
    int32_t ret = 0;

    switch (kScartNumber)
    {
        case PHSTB_SCART_SWITCH_SCART_TV:
        {
            /* TV scart video format */
            *pFormat = gTVVideoFormat;
        }
        break;

        case PHSTB_SCART_SWITCH_SCART_VCR:
        {
            /* VCR scart video format */
            *pFormat = gVCRVideoFormat;
        }
        break;

        default:
        {
            /* Unknown scart number */
            ret = -EINVAL;
        }
        break;
    }
    return ret;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    phStbScartSwitchUDASetSBMode                                  */
/*                                                                            */
/* DESCRIPTION: Change the behaviour of Slow Blanking (in/out/loopthrough)    */
/*              In this function, not all the conbination TV and VCR          */
/*              are allowed then TV will be "master".                         */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
static int32_t phStbScartSwitchUDASetSBMode(phStbScartSwitchScartId_t kScartNumber,
                                            phStbScartSwitchSBMode_t kMode)
{
    uint32_t ret = 0;

    switch (kScartNumber)
    {
        case PHSTB_SCART_SWITCH_SCART_TV:
        {
            gTVSBMode = kMode;
            switch (kMode)
            {
                case PHSTB_SCART_SWITCH_SB_IN: /* Not supported on UDA */
                break;

                case PHSTB_SCART_SWITCH_SB_OUT:
                {
                    if (gVCRSBMode == PHSTB_SCART_SWITCH_SB_IN)
                    {
                        /* TVSB out ; VCRSB in */
                        gRegisters[9] |= 0x80; /* 10------ */
                        gRegisters[9] &= ~0x40;
                    }
                    else /* SB_OUT == gVCRSBMode */
                    {
                        /* SB_OUT_LOOP is treated like SB_OUT */
                        /* TVSB out ; VCRSB out */
                        gRegisters[9] &= ~0xC0;/* 00------ */
                    }
                    SetTVSBValue(gTVSBValue);  /* reg9 ----xx-- */
                }
                break;

                case PHSTB_SCART_SWITCH_SB_OUT_LOOP:
                {
                    /* Loopthrough of VCRSB to TVSB */
                    gRegisters[9] |= 0xC0; /* 11------ */
                }
                break;

                default:
                break;
            }
        }
        break;

        case PHSTB_SCART_SWITCH_SCART_VCR:
        {
            gVCRSBMode = kMode;
            switch (kMode)
            {
                case PHSTB_SCART_SWITCH_SB_IN:
                {
                    if (gTVSBMode == PHSTB_SCART_SWITCH_SB_OUT)
                    {
                        /* TVSB out ; VCRSB in */
                        gRegisters[9] |= 0x80; /* 10------ */
                        gRegisters[9] &= ~0x40;
                    }
                    else
                    if (gTVSBMode == PHSTB_SCART_SWITCH_SB_OUT_LOOP)
                    {
                        /* Loopthrough from VCRSB to TV SB */
                        gRegisters[9] |= 0xC0; /* 11------ */
                    }
                }
                break;

                case PHSTB_SCART_SWITCH_SB_OUT:
                {
                    /* TVSB out ; VCRSB out */
                    gRegisters[9] &= ~0xC0;    /* 00------ */
                    SetVCRSBValue(gVCRSBValue);/* reg9 --xx---- */
                }
                break;

                case PHSTB_SCART_SWITCH_SB_OUT_LOOP: /* Not supported on UDA */
                break;

                default:
                break;
            }
        }
        break;

        default:
        break;
    }

    /* Write new register value */
    ret = I2cWrite(1, 9, &gRegisters[9]);

    return ret;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    phStbScartSwitchUDASetSBMode                                  */
/*                                                                            */
/* DESCRIPTION: Change the level of Slow Blanking on one scart                */
/*              If corresponding Slow Blanking is not an output, only save    */
/*              the value else write the new value on I2C.                    */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
static int32_t phStbScartSwitchUDASetSBValue(phStbScartSwitchScartId_t kScartNumber,
                                             phStbScartSwitchSBValue_t kValue)
{
    uint32_t ret = 0;

    switch (kScartNumber)
    {
        case PHSTB_SCART_SWITCH_SCART_TV:
        {
            gTVSBValue = kValue;
            if (gTVSBMode == PHSTB_SCART_SWITCH_SB_OUT)
            {
                SetTVSBValue(gTVSBValue); /* reg9 --xx---- */
                ret = I2cWrite(1, 9, &gRegisters[9]);
            }
        }
        break;

        case PHSTB_SCART_SWITCH_SCART_VCR:
        {
            gVCRSBValue = kValue;
            if (gVCRSBMode == PHSTB_SCART_SWITCH_SB_OUT)
            {
                SetVCRSBValue(gVCRSBValue); /* reg9 --xx---- */
                ret = I2cWrite(1, 9, &gRegisters[9]);
            }
        }
        break;

        default:
        break;
    }
    return ret;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    phStbScartSwitchUDAGetSBValue                                  */
/*                                                                            */
/* DESCRIPTION: Read the level of Slow Blanking on one scart.                 */
/*              If the corresponding SB is not an input, it return "low".     */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
static int32_t phStbScartSwitchUDAGetSBValue(phStbScartSwitchScartId_t kScartNumber,
                                             phStbScartSwitchSBValue_t *pValue)
{
    uint32_t ret = 0;

    switch (kScartNumber)
    {
        case PHSTB_SCART_SWITCH_SCART_TV: /* not supported on UDA chip */
            /* the status register is updated in the task after an interrupt ! */
            switch ((gRegisters[0x9] >> 2) & 0x3)
            {
                case 3: /* ------11 */
                {
                    *pValue = PHSTB_SCART_SWITCH_SB_4_3;
                }
                break;

                case 1: /* ------01 */
                {
                    *pValue = PHSTB_SCART_SWITCH_SB_16_9;
                }
                break;

                case 0: /* ------00 */
                {
                    *pValue = PHSTB_SCART_SWITCH_SB_LOW;
                }
                break;

                default:
                {
                    *pValue = PHSTB_SCART_SWITCH_SB_LOW;
                }
                break;
            }
        break;

        case PHSTB_SCART_SWITCH_SCART_VCR:
        {
            /* this function make sense only if vcr sb is an input */
            if (gVCRSBMode == PHSTB_SCART_SWITCH_SB_IN)
            {
                /* the status register is updated in the task after an interrupt ! */
                switch ((gRegisters[0xA]) & 3)
                {
                    case 3: /* ------11 */
                    {
                        *pValue = PHSTB_SCART_SWITCH_SB_4_3;
                    }
                    break;

                    case 1: /* ------01 */
                    {
                        *pValue = PHSTB_SCART_SWITCH_SB_16_9;
                    }
                    break;

                    case 0: /* ------00 */
                    {
                        *pValue = PHSTB_SCART_SWITCH_SB_LOW;
                    }
                    break;

                    default:
                    {
                        *pValue = PHSTB_SCART_SWITCH_SB_LOW;
                    }
                    break;
                }
            }
            else
            {
                *pValue = PHSTB_SCART_SWITCH_SB_LOW;
            }
        }
        break;

        default:
        {
            /* Unknown scart number */
            ret = -EINVAL;
        }
        break;
    }
    return ret;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    phStbScartSwitchUDASetSBMode                                  */
/*                                                                            */
/* DESCRIPTION: Install a callback.                                           */
/*              This callback will be called when a change will occur         */
/*              on Slow Blanking.                                             */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
static int32_t phStbScartSwitchUDAInstallSBCallback(phStbScartSwitchScartId_t kScartNumber,
                                                    pScartSwitchCallback_t pFunc)
{
    int32_t ret = 0;

    if (pFunc == Null)
    {
        /* No callback passed */
        ret = -EINVAL;
    }
    else
    {
        switch (kScartNumber)
        {
            case PHSTB_SCART_SWITCH_SCART_TV:
            {
                /* tv sb can't be an input then a callback can't be used ! */
            }
            break;

            case PHSTB_SCART_SWITCH_SCART_VCR:
            {
                gVCRSBCallbackFunc = pFunc;
                /* There, it may be usefull to call the callback function */
                /* (to be in a know situation)                            */
            }
            break;

            default:
            break;
        }
    }
    return ret;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    phStbScartSwitchUdaSetFBMode                                  */
/*                                                                            */
/* DESCRIPTION: This function get the value of the specified register.        */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
static int32_t phStbScartSwitchUDASetFBMode(phStbScartSwitchScartId_t kScartNumber,
                                            phStbScartSwitchFBMode_t kFBMode)
{
    int32_t ret = 0;

    switch (kScartNumber)
    {
        case PHSTB_SCART_SWITCH_SCART_TV:
        {
            gTVFBMode = kFBMode;

            switch(kFBMode)
            {
                case PHSTB_SCART_SWITCH_FB_OUT_0V:
                {
                    /* set tv fast blanking to 0v */
                    gRegisters[9] &= ~0x03; /* ------00 */
                }
                break;

                case PHSTB_SCART_SWITCH_FB_OUT_4V:
                {
                    gRegisters[9] |= 0x01; /* ------01 */
                    gRegisters[9] &= ~0x02;
                }
                break;

                case PHSTB_SCART_SWITCH_FB_OUT_LOOP:
                {
                    gRegisters[9] |= 0x02; /* ------10 */
                    gRegisters[9] &= ~0x01;
                }
                break;

                case PHSTB_SCART_SWITCH_FB_IN: /* not possible on UDA */
                break;

                default:
                break;
            }
            ret = I2cWrite(1, 9, &gRegisters[9]);
        }
        break;

        case PHSTB_SCART_SWITCH_SCART_VCR:
        {
            gVCRFBMode = kFBMode;
            switch (kFBMode)
            {
                case PHSTB_SCART_SWITCH_FB_OUT_0V:
                {
                    /* TODO */
                }
                break;

                case PHSTB_SCART_SWITCH_FB_OUT_4V:
                {
                    /* TODO */
                }
                break;

                case PHSTB_SCART_SWITCH_FB_OUT_LOOP: /* not possible on UDA */
                break;

                case PHSTB_SCART_SWITCH_FB_IN:
                {
                    /* TODO */
                }
                break;

                default:
                break;
            }
            break;
        }

        default:
        break;
    }
    return ret;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    phStbScartSwitchUDASetAudioCommonMute                         */
/*                                                                            */
/* DESCRIPTION: This function mute on/off all audio output.                   */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
int32_t phStbScartSwitchUDASetAudioCommonMute(phStbScartSwitchAudioCommonMute_t kMute)
{
    int32_t ret = 0;

    switch(kMute)
    {
        case PHSTB_SCART_SWITCH_MUTE_OFF:
        {
            /* Mute off all audio output */
            gRegisters[0] &= 0x02;
        }
        break;

        case PHSTB_SCART_SWITCH_MUTE_ON:
        {
            /* Mute on all audio output */
            gRegisters[0] |= 0x02;
        }
        break;

        default:
        break;
    }

    /* Write new register value */
    ret = I2cWrite(1, 0, &gRegisters[0]);

    return ret;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    phStbScartSwitchUDASetAudioMute                               */
/*                                                                            */
/* DESCRIPTION: This function set TV/VCR audio source.                        */
/*                                                                            */
/* RETURN:      tmErrorCode_t                                                 */
/* -------------------------------------------------------------------------- */
int32_t phStbScartSwitchUDASetAudioSource(phStbScartSwitchScartId_t kScartNumber,
                                          phStbScartSwitchAudioSource_t kAudioSource)
{
    int32_t ret = 0;

    switch(kScartNumber)
    {
        /* Set audio source for TV output */
        case PHSTB_SCART_SWITCH_SCART_TV:
        {
            switch(kAudioSource)
            {
                case PHSTB_SCART_SWITCH_AUDIO_SOURCE_DAC:
                {
                    /* Select DAC source for TV output */
                    gRegisters[1] &= (~0x06);
                }
                break;

                case PHSTB_SCART_SWITCH_AUDIO_SOURCE_TVIN:
                {
                    /* Not possible */
                }
                break;

                case PHSTB_SCART_SWITCH_AUDIO_SOURCE_VCRIN:
                {
                    /* Select VCR IN for TV output */
                    gRegisters[1] &= (~0x04);
                    gRegisters[1] |= ( 0x02);
                }
                break;

                case PHSTB_SCART_SWITCH_AUDIO_SOURCE_MUTE:
                {
                    gRegisters[1] |= ( 0x04);
                }
                break;

                default:
                break;

            }
        }
        break;

        case PHSTB_SCART_SWITCH_SCART_VCR:
        {
            switch(kAudioSource)
            {
                case PHSTB_SCART_SWITCH_AUDIO_SOURCE_DAC:
                {
                    /* Select DAC source for TV output */
                    gRegisters[1] &= (~0x60);
                }
                break;

                case PHSTB_SCART_SWITCH_AUDIO_SOURCE_TVIN:
                {
                    /* Select VCR IN for TV output */
                    gRegisters[1] &= (~0x40);
                    gRegisters[1] |= ( 0x20);
                }
                break;

                case PHSTB_SCART_SWITCH_AUDIO_SOURCE_VCRIN:
                {
                    /* Not possible */
                }
                break;

                case PHSTB_SCART_SWITCH_AUDIO_SOURCE_MUTE:
                {
                    gRegisters[1] |= ( 0x40);
                }
                break;

                default:
                break;
            }
        }
        break;

        default:
        break;
    }

    /* Write new register value */
    ret = I2cWrite(1, 1, &gRegisters[1]);

    return ret;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    phStbScartSwitchUDAGetSwitchSettings                          */
/*                                                                            */
/* DESCRIPTION: This function get current slow blanking and output mode       */
/*                                                                            */
/* RETURN:      int32_t                                                       */
/* -------------------------------------------------------------------------- */
int32_t phStbScartSwitchUDAGetSwitchSettings(phStbScartSwitch_data_t *pScartSwitchData)
{
    int32_t ret = 0;
    phStbScartSwitchVideoFormat_t lVideoFormat;
    phStbScartSwitchSBValue_t     lSBValue;

    /* Get video format for TV SCART */
    ret = phStbScartSwitchUDAGetVideoFormat(PHSTB_SCART_SWITCH_SCART_TV,
                                            &lVideoFormat);

    pScartSwitchData->attribute[PHSTB_SCART_SWITCH_SCART_TV].display_mode = lVideoFormat;

    if (ret != 0)
    {
        dprintk("%s :GetSwitchSettings error %d -> phStbScartSwitchUDAGetVideoFormat() failed for TV SCART\n", ret, PH_STB_SCART_SWITCH_DESCRIPTION);
        goto GetSwitchSettings_error;
    }

    /* Get slow blanking for TV SCART */
    ret = phStbScartSwitchUDAGetSBValue(PHSTB_SCART_SWITCH_SCART_TV,
                                        &lSBValue);

    pScartSwitchData->attribute[PHSTB_SCART_SWITCH_SCART_TV].slow_blanking = lSBValue;

    if (ret != 0)
    {
        dprintk("%s :GetSwitchSettings error %d -> phStbScartSwitchUDAGetSBValue() failed for TV SCART\n", ret, PH_STB_SCART_SWITCH_DESCRIPTION);
        goto GetSwitchSettings_error;
    }

    /* Get video format for VCR SCART */
    ret = phStbScartSwitchUDAGetVideoFormat(PHSTB_SCART_SWITCH_SCART_VCR,
                                            &lVideoFormat);

    pScartSwitchData->attribute[PHSTB_SCART_SWITCH_SCART_VCR].display_mode = lVideoFormat;

    if (ret != 0)
    {
        dprintk("%s :GetSwitchSettings error %d -> phStbScartSwitchUDAGetVideoFormat() failed for VCR SCART\n", ret, PH_STB_SCART_SWITCH_DESCRIPTION);
        goto GetSwitchSettings_error;
    }

    /* Get slow blanking for VCR SCART */
    ret = phStbScartSwitchUDAGetSBValue(PHSTB_SCART_SWITCH_SCART_VCR,
                                        &lSBValue);

    pScartSwitchData->attribute[PHSTB_SCART_SWITCH_SCART_VCR].slow_blanking = lSBValue;

    if (ret != 0)
    {
        dprintk("%s :GetSwitchSettings error %d -> phStbScartSwitchUDAGetSBValue() failed for VCR SCART\n", ret, PH_STB_SCART_SWITCH_DESCRIPTION);
        goto GetSwitchSettings_error;
    }

GetSwitchSettings_error:
    return ret;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    phStbScartSwitchUDASetSwitchSettings                          */
/*                                                                            */
/* DESCRIPTION: This function set slow blanking and output mode               */
/*                                                                            */
/* RETURN:      int32_t                                                       */
/* -------------------------------------------------------------------------- */
int32_t phStbScartSwitchUDASetSwitchSettings(phStbScartSwitch_data_t *pScartSwitchData)
{
    int32_t ret = 0;

    /* Set video format for TV SCART */
    ret = phStbScartSwitchUDASetVideoFormat(PHSTB_SCART_SWITCH_SCART_TV,
                                            pScartSwitchData->attribute[PHSTB_SCART_SWITCH_SCART_TV].display_mode);
    if (ret != 0)
    {
        dprintk("%s :SetSwitchSettings error %d -> phStbScartSwitchUDASetVideoFormat() failed for TV SCART\n", ret, PH_STB_SCART_SWITCH_DESCRIPTION);
        goto SetSwitchSettings_error;
    }

    /* Set slow blanking for TV SCART */
    ret = phStbScartSwitchUDASetSBValue(PHSTB_SCART_SWITCH_SCART_TV,
                                        pScartSwitchData->attribute[PHSTB_SCART_SWITCH_SCART_TV].slow_blanking);
    if (ret != 0)
    {
        dprintk("%s :SetSwitchSettings error %d -> phStbScartSwitchUDASetSBValue() failed for TV SCART\n", ret, PH_STB_SCART_SWITCH_DESCRIPTION);
        goto SetSwitchSettings_error;
    }

    /* Set video format for VCR SCART */
    ret = phStbScartSwitchUDASetVideoFormat(PHSTB_SCART_SWITCH_SCART_VCR,
                                            pScartSwitchData->attribute[PHSTB_SCART_SWITCH_SCART_VCR].display_mode);
    if (ret != 0)
    {
        dprintk("%s :SetSwitchSettings error %d -> phStbScartSwitchUDASetVideoFormat() failed for VCR SCART\n", ret, PH_STB_SCART_SWITCH_DESCRIPTION);
        goto SetSwitchSettings_error;
    }

    /* Set slow blanking for VCR SCART */
    ret = phStbScartSwitchUDASetSBValue(PHSTB_SCART_SWITCH_SCART_VCR,
                                        pScartSwitchData->attribute[PHSTB_SCART_SWITCH_SCART_VCR].slow_blanking);
    if (ret != 0)
    {
        dprintk("%s :SetSwitchSettings error %d -> phStbScartSwitchUDASetSBValue() failed for VCR SCART\n", ret, PH_STB_SCART_SWITCH_DESCRIPTION);
        goto SetSwitchSettings_error;
    }

SetSwitchSettings_error:
    return ret;
}


/* -------------------------------------------------------------------------- */
/* FUNCTION:    phStbScartSwitchUDASetInterface                               */
/*                                                                            */
/* DESCRIPTION: This function set the interface to use.                       */
/*                                                                            */
/* RETURN:      int32_t                                                       */
/* -------------------------------------------------------------------------- */
int32_t phStbScartSwitchUDASetInterface(phStbScartSwitchFunctionList_t *pFunctionList,
                                        uint8_t Id)
{
    int32_t ret = 0;

    if (Id == PHSTB_SCART_SWITCH_UDA)
    {
        /* Function from the UDA driver */
        pFunctionList->Init =               phStbScartSwitchUDAInit;
        pFunctionList->Terminate =          phStbScartSwitchUDATerminate;
        pFunctionList->SetVolume =          phStbScartSwitchUDASetVolume;
        pFunctionList->GetVolume =          phStbScartSwitchUDAGetVolume;
        pFunctionList->SetOutputMode =      phStbScartSwitchUDASetOutputMode;
        pFunctionList->SetVideoFormat =     phStbScartSwitchUDASetVideoFormat;
        pFunctionList->SetSBMode =          phStbScartSwitchUDASetSBMode;
        pFunctionList->SetSBValue =         phStbScartSwitchUDASetSBValue;
        pFunctionList->GetSBValue =         phStbScartSwitchUDAGetSBValue;
        pFunctionList->InstallSBCallback =  phStbScartSwitchUDAInstallSBCallback;
        pFunctionList->SetFBMode =          phStbScartSwitchUDASetFBMode;
        pFunctionList->SetAudioSource =     phStbScartSwitchUDASetAudioSource;
        pFunctionList->SetAudioCommonMute = phStbScartSwitchUDASetAudioCommonMute;
        pFunctionList->GetSwitchSettings =  phStbScartSwitchUDAGetSwitchSettings;
        pFunctionList->SetSwitchSettings =  phStbScartSwitchUDASetSwitchSettings;
    }
    else
    {
        /* Invalid device ID */
        ret = -EINVAL;
    }
    return ret;
}


/*============================================================================*/
/*                     END OF FILE                                            */
/*============================================================================*/
