/*****************************************************************************/
/* 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.                                                                      */
/*                                                                           */
/*****************************************************************************/

/**
    This is the HDMI Component.


Rev Date        Author      Comments
--------------------------------------------------------------------------------
  1 20081002    estarkie    Original
  2 20081119    estarkie    Add mode_option module param for initial display modes
  3 20081120    estarkie    Use "\n" for printk's instead of "\n\r"
  4 20081211    batelaan    Fix build error if CONFIG_PM (power management) is undefined.
  5 20090121    batelaan    Update author/license.
  6 20090217    batelaan    Add various public functions.
  7 20090325    amccurdy    Sync with San Jose, add additional kernel API functions
  8 20090329    amccurdy    Simplify phStbHdmi_RegisterStatusCallback callback arg
  9 20090402    amccurdy    Minor cleanup of startup debug
--------------------------------------------------------------------------------
    For consistency and standardisation retain the Section Separators.
*/

/***********************************************
 * INCLUDE FILES                                *
 ************************************************/

#include "phStbHdmi.h"

#include <linux/module.h>
#include <linux/videodenc.h>

/***********************************************
 * LOCAL MACROS                                *
 ***********************************************/

/**
 * @brief Debug Macro.
 */
#define dprintk(num, format...) \
    do { \
        if (debug >= (num)) \
            printk(format); \
    } while (0)

#define mode_matches(v, __xres, __yres, __refresh, __scantype, __signal_type) \
    ((v).xres == (__xres) && \
     (v).yres == (__yres) && \
     (v).refresh == (__refresh) && \
     (v).scantype == (__scantype) && \
     (v).output_signal == (__signal_type))

#define mode_matches_exact(v, __xres, __yres, __refresh, __scantype, __signal_type, __bpp, __tv_standard) \
     (mode_matches(v, __xres, __yres, __refresh, __scantype, __signal_type) && \
      ((v).bits_per_pixel == (__bpp)) && \
      ((v).tv_standard == (__tv_standard)))

/******************************************************************
 * LOCAL TYPEDEFS                                                 *
 * recommendation only:                [p]phStbHdmi_<Word>+_t     *
 ******************************************************************/

/**
 * Here we define the default videodenc_fix_screeninfo
 * We do use modedb to get a videodenc_var_screeninfo.
 */
static struct videodenc_fix_screeninfo gHdmiVdenc_fix =
{
    .id =       "STB225 HDMI Vdenc",
    .type =     VIDEODENC_TYPE_HDMI,
    .features = VIDEODENC_FEATURE_INTERLACED |
                VIDEODENC_FEATURE_PROGRESSIVE |
                VIDEODENC_FEATURE_TESTPATTERN,
    .all_connectors = {{1, VIDEODENC_CONNECTOR_HDMI, 0},
                       {0, VIDEODENC_CONNECTOR_NONE, 0}
                      },
    .sout_signals   = VIDEODENC_OUTSIGNAL_DIGITAL
};

/**
 *  Local structure holding all fb info.
 */
struct videodenc_info_phStbHdmi
{
    /* Standard Videodenc info structure*/
    struct videodenc_info *pvdenc_info;

    /* STB225 implementation specific details*/
    struct platform_driver platform_driver_info;
    struct platform_device platform_device_info;
    struct videodenc_sysfs_attrs sysfs_attrs;
};

/******************************************************************
 * STATIC DATA                  g[k|p|kp|pk|kpk]phStbHdmi_<Word>+   *
 ******************************************************************/

static uint debug = 0;

struct platform_device* gp_dev;

static char display_mode[256];
static char* mode_option = NULL;

/* Internal flag to show that an HDMI device has registered with phStbHdmi */
static bool devRegistered = false;

/* Internal phStbHdmi data structure */
static struct videodenc_info_phStbHdmi gphStbHdmi_info;

static phStbHdmi_Ops_t phStbHdmi_funcs;

/* Copy of the current video denc info to allow us to detect "no-change situation". */
static struct videodenc_info old_videodenc_info;

/**
 * @brief A structure of the video modes we support in the form of:
 * struct videodenc_videomode
 * {
 *  const char *name;   //OPTIONAL
 *  u32 refresh;
 *  u32 xres;
 *  u32 yres;
 *  u8  bits_per_pixel; //OPTIONAL
 *  videodenc_scantype_t      scantype; // Chosen Scantype
 *  videodenc_output_signal_t output_signal; // Chosen output signal
 *  videodenc_tv_standard_t   tv_standard; // Chosen TV Output Signal Type. OPTIONAL
 *  videodenc_outputconnector supported_connectors[VIDEODENC_CONNECTORS_MAX]; //Supported connectors
 * };
 */
static struct videodenc_videomode phStbHdmi_modedb[] =
{
    {
        /* PAL-BG*/
        "PAL-BG", VIDEODENC_REFRESH_RATE_50HZ, 720, 576, 32,
        VIDEODENC_SCANTYPE_INTERLACED, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_PAL_BG,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* PAL-I*/
        "PAL-I", VIDEODENC_REFRESH_RATE_50HZ, 720, 576, 32,
        VIDEODENC_SCANTYPE_INTERLACED, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_PAL_I,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* PAL-M*/
        "PAL-M", VIDEODENC_REFRESH_RATE_60HZ, 720, 480, 32,
        VIDEODENC_SCANTYPE_INTERLACED, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_PAL_M,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* PAL-N*/
        "PAL-N", VIDEODENC_REFRESH_RATE_50HZ, 720, 576, 32,
        VIDEODENC_SCANTYPE_INTERLACED, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_PAL_N,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* PAL-NC*/
        "PAL-NC", VIDEODENC_REFRESH_RATE_50HZ, 720, 576, 32,
        VIDEODENC_SCANTYPE_INTERLACED, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_PAL_NC,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* SECAM */
        "SECAM", VIDEODENC_REFRESH_RATE_50HZ, 720, 576, 32,
        VIDEODENC_SCANTYPE_INTERLACED, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_SECAM,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* NTSC-M */
        "NTSC-M", VIDEODENC_REFRESH_RATE_60HZ, 720, 480, 32,
        VIDEODENC_SCANTYPE_INTERLACED, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_NTSC_M,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* NTSC-M-JPN */
        "NTSC-M-JPN", VIDEODENC_REFRESH_RATE_60HZ, 720, 480, 32,
        VIDEODENC_SCANTYPE_INTERLACED, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_NTSC_M_JPN,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* 720x576x50p */
        "720x576x50p", VIDEODENC_REFRESH_RATE_50HZ, 720, 576, 32,
        VIDEODENC_SCANTYPE_PROGRESSIVE, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_DIGITAL,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* 720x480x60p */
        "720x480x60p", VIDEODENC_REFRESH_RATE_60HZ, 720, 480, 32,
        VIDEODENC_SCANTYPE_PROGRESSIVE, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_DIGITAL,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* 720x480x59.94p */
        "720x480x59.94p", VIDEODENC_REFRESH_RATE_59_94HZ, 720, 480, 32,
        VIDEODENC_SCANTYPE_PROGRESSIVE, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_DIGITAL,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* 640x480x60p */
        "640x480x60p", VIDEODENC_REFRESH_RATE_60HZ, 640, 480, 32,
        VIDEODENC_SCANTYPE_PROGRESSIVE, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_DIGITAL,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* 800x600x75p */
        "800x600x75p", VIDEODENC_REFRESH_RATE_75HZ, 800, 600, 32,
        VIDEODENC_SCANTYPE_PROGRESSIVE, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_DIGITAL,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* 1024x768x75p */
        "1024x768x75p", VIDEODENC_REFRESH_RATE_75HZ, 1024, 768, 32,
        VIDEODENC_SCANTYPE_PROGRESSIVE, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_DIGITAL,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* 1280x768x60p */
        "1280x768x60p", VIDEODENC_REFRESH_RATE_60HZ, 1280, 768, 32,
        VIDEODENC_SCANTYPE_PROGRESSIVE, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_DIGITAL,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* 1280x800x60p */
        "1280x800x60p", VIDEODENC_REFRESH_RATE_60HZ, 1280, 800, 32,
        VIDEODENC_SCANTYPE_PROGRESSIVE, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_DIGITAL,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* 1360x768x60p */
        "1360x768x60p", VIDEODENC_REFRESH_RATE_60HZ, 1360, 768, 32,
        VIDEODENC_SCANTYPE_PROGRESSIVE, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_DIGITAL,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* 1920x1080x60i */
        "1920x1080x60i", VIDEODENC_REFRESH_RATE_60HZ, 1920, 1080, 32,
        VIDEODENC_SCANTYPE_INTERLACED, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_DIGITAL,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* 1920x1080x59.94i */
        "1920x1080x59.94i", VIDEODENC_REFRESH_RATE_59_94HZ, 1920, 1080, 32,
        VIDEODENC_SCANTYPE_INTERLACED, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_DIGITAL,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* 1920x1080x60p */
        "1920x1080x60p", VIDEODENC_REFRESH_RATE_60HZ, 1920, 1080, 32,
        VIDEODENC_SCANTYPE_PROGRESSIVE, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_DIGITAL,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* 1920x1080x59.94p */
        "1920x1080x59.94p", VIDEODENC_REFRESH_RATE_59_94HZ, 1920, 1080, 32,
        VIDEODENC_SCANTYPE_PROGRESSIVE, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_DIGITAL,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* 1920x1080x29.97p */
        "1920x1080x29.97p", VIDEODENC_REFRESH_RATE_29_97HZ, 1920, 1080, 32,
        VIDEODENC_SCANTYPE_PROGRESSIVE, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_DIGITAL,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* 1280x720x60p */
        "1280x720x60p", VIDEODENC_REFRESH_RATE_60HZ, 1280, 720, 32,
        VIDEODENC_SCANTYPE_PROGRESSIVE, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_DIGITAL,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* 1280x720x59.94p */
        "1280x720x59.94p", VIDEODENC_REFRESH_RATE_59_94HZ, 1280, 720, 32,
        VIDEODENC_SCANTYPE_PROGRESSIVE, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_DIGITAL,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* 1920x1080x50i */
        "1920x1080x50i", VIDEODENC_REFRESH_RATE_50HZ, 1920, 1080, 32,
        VIDEODENC_SCANTYPE_INTERLACED, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_DIGITAL,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* 1920x1080x50p */
        "1920x1080x50p", VIDEODENC_REFRESH_RATE_50HZ, 1920, 1080, 32,
        VIDEODENC_SCANTYPE_PROGRESSIVE, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_DIGITAL,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    },
    {
        /* 1280x720x50p */
        "1280x720x50p", VIDEODENC_REFRESH_RATE_50HZ, 1280, 720, 32,
        VIDEODENC_SCANTYPE_PROGRESSIVE, VIDEODENC_OUTSIGNAL_DIGITAL, VIDEODENC_TV_STANDARD_DIGITAL,
        {{1, VIDEODENC_CONNECTOR_HDMI, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0},
         {0, VIDEODENC_CONNECTOR_NONE, 0}}
    }
};

/**
 * sysfs entries
 */
static ssize_t phStbHdmi_show_rev(struct device *device, struct device_attribute *attr, char *buf)
{
    return snprintf(buf, PAGE_SIZE, "%d\n", 0);
}
static DEVICE_ATTR(revision, S_IRUGO, &phStbHdmi_show_rev, NULL);

static ssize_t phStbHdmi_show_vendor(struct device *dev, struct device_attribute *attr, char *buf)
{
    return snprintf(buf, PAGE_SIZE, "0x%04x\n", 0xDEAF);
}
static DEVICE_ATTR(vendor, S_IRUGO, &phStbHdmi_show_vendor, NULL);

static ssize_t phStbHdmi_show_device_name(struct device *dev, struct device_attribute *attr, char *buf)
{
    return snprintf(buf, PAGE_SIZE, "%s\n", "STB225 HDMI Denc");
}
static DEVICE_ATTR(device_name, S_IRUGO, &phStbHdmi_show_device_name, NULL);

/**************************************************************************
* EXPORTED DATA                     g[k|p|kp|pk|kpk]phStbHdmi_<Word>+ *
***************************************************************************/


/*******************************************************************************
* FUNCTION IMPLEMENTATION  <Module>[_<Word>+] for static functions             *
*                          ph[<layer>]<Module>[_<Word>+] for exported functions*
********************************************************************************/


static int phStbHdmi_check_mode(struct videodenc_var_screeninfo *var, struct videodenc_info *info)
{
    uint32_t changed = 0;
    uint32_t index = 0;
    uint32_t modeIndex = 0;
    uint32_t foundMatch = 1;
    static uint32_t firstcall = 1;
    changed = ((info->var.xres != var->xres) ||
               (info->var.yres != var->yres) ||
               (info->var.bits_per_pixel != var->bits_per_pixel) ||
               (info->var.refresh != var->refresh) ||
               (info->var.subcarrier_freq != var->subcarrier_freq) ||
               (info->var.scantype != var->scantype) ||
               (info->var.output_signal != var->output_signal) ||
               (info->var.tv_standard != var->tv_standard) ||
               (info->var.macro_type != var->macro_type) ||
               ((var->xres == 720) && (firstcall == 0)));//Temporarily allow 480p setting to go through to use Alt480P
    /* Need to also detect if connectors have been changed this is a simple test and presumes that they will not have
       changed the order but kept overall connectors the same.*/
    for (index =0; index < VIDEODENC_CONNECTORS_MAX; index++)
    {
        if ((info->var.chosen_connectors[index].in_use != var->chosen_connectors[index].in_use) ||
                (info->var.chosen_connectors[index].type != var->chosen_connectors[index].type) ||
                (info->var.chosen_connectors[index].connector_id != var->chosen_connectors[index].connector_id))
        {
            foundMatch = 0;
            break;
        }
    }

    firstcall = 0;
    /*If something has changed look at values*/
    if (changed || !foundMatch )
    {
        for (modeIndex = 0; modeIndex < ARRAY_SIZE(phStbHdmi_modedb); modeIndex++)
        {
            /*Check if we support the mode that has changed to*/
            if (mode_matches_exact(phStbHdmi_modedb[modeIndex],
                                   var->xres,
                                   var->yres,
                                   var->refresh,
                                   var->scantype,
                                   var->output_signal,
                                   var->bits_per_pixel,
                                   var->tv_standard))

            {
                /*we have checked all requested connectors and all seems ok and the mode is valid.*/
                dprintk(1, "Found a match %d\n", modeIndex);
                return 1;
            }
        }
        return -EINVAL;
    }

	// We're happy with this, but lets make sure that we do force the change
	if(var->activate == VIDEODENC_ACTIVATE_NOW)
		return 1;
		
    return 0;
}

static int phStbHdmi_set_mode(struct videodenc_info * info)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_set_mode)
    {
        err = phStbHdmi_funcs.phStbHdmi_set_mode(info);
    }
    else
    {
        dprintk(1,"No pointer found for Set Mode function. Has HDMI device registered?\n");
    }

    return err;
}

static int phStbHdmi_blank(struct videodenc_info *info, int blank)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_blank)
    {
        err = phStbHdmi_funcs.phStbHdmi_blank(info, blank);
    }
    else
    {
        dprintk(1,"No pointer found for Blank function. Has HDMI device registered?\n");
    }

    return err;
}

static int phStbHdmi_test_pattern(struct videodenc_info *info, int test_pattern)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_test_pattern)
    {
        err = phStbHdmi_funcs.phStbHdmi_test_pattern(info, test_pattern);
    }
    else
    {
        dprintk(1,"No pointer found for Test Pattern function. Has HDMI device registered?\n");
    }

    return err;
}

int phStbHdmi_EnableAudio(void)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_enable_audio)
    {
        err = phStbHdmi_funcs.phStbHdmi_enable_audio();
    }
    else
    {
        dprintk(1,"No pointer found for Enable Audio function. Has HDMI device registered?\n");
    }

    return err;
}

int phStbHdmi_DisableAudio(void)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_disable_audio)
    {
        err = phStbHdmi_funcs.phStbHdmi_disable_audio();
    }
    else
    {
        dprintk(1,"No pointer found for Disable function. Has HDMI device registered?\n");
    }

    return err;
}

tmErrorCode_t phStbHdmi_SetAudioRate(phStbHdmi_afs_t audioRate)
{
    tmErrorCode_t err;

    if (phStbHdmi_funcs.phStbHdmi_setAudioRate)
    {
        err = phStbHdmi_funcs.phStbHdmi_setAudioRate(audioRate);
    }
    else
    {
        err = TM_ERR_NOT_SUPPORTED;
        dprintk(1,"No pointer found for SetAudioRate function. Has HDMI device registered?\n");
    }

    return err;
}

tmErrorCode_t phStbHdmi_GetAudioCap(phStbHdmi_audio_cap_t *pAudioCap)
{
    tmErrorCode_t err;

    if (phStbHdmi_funcs.phStbHdmi_getAudioCap)
    {
        err = phStbHdmi_funcs.phStbHdmi_getAudioCap(pAudioCap);
    }
    else
    {
        err = TM_ERR_NOT_SUPPORTED;
        dprintk(1,"No pointer found for GetAudioCap function. Has HDMI device registered?\n");
    }

    return err;
}

tmErrorCode_t phStbHdmi_SetAudio(phStbHdmi_aud_t *pStrAudio)
{
    tmErrorCode_t err;

    if (phStbHdmi_funcs.phStbHdmi_setAudio)
    {
        err = phStbHdmi_funcs.phStbHdmi_setAudio(pStrAudio);
    }
    else
    {
        err = TM_ERR_NOT_SUPPORTED;
        dprintk(1,"No pointer found for SetAudio function. Has HDMI device registered?\n");
    }

    return err;
}

tmErrorCode_t phStbHdmi_RegisterStatusCallback(void (*pCallback) (unsigned long status))
{
    tmErrorCode_t err;

    if (phStbHdmi_funcs.phStbHdmi_RegisterStatusCallback)
    {
        err = phStbHdmi_funcs.phStbHdmi_RegisterStatusCallback(pCallback);
    }
    else
    {
        err = TM_ERR_NOT_SUPPORTED;
        dprintk(1,"No pointer found for RegisterStatusCallback function. Has HDMI device registered?\n");
    }

    return err;
}

tmErrorCode_t phStbHdmi_UnRegisterStatusCallback(void)
{
    tmErrorCode_t err;

    if (phStbHdmi_funcs.phStbHdmi_UnRegisterStatusCallback)
    {
        err = phStbHdmi_funcs.phStbHdmi_UnRegisterStatusCallback();
    }
    else
    {
        err = TM_ERR_NOT_SUPPORTED;
        dprintk(1,"No pointer found for UnRegisterStatusCallback function. Has HDMI device registered?\n");
    }

    return err;
}

tmErrorCode_t phStbHdmi_InitializeHDMIDevice(void)
{
    tmErrorCode_t err;

    if (phStbHdmi_funcs.phStbHdmi_InitializeHDMIDevice)
    {
        err = phStbHdmi_funcs.phStbHdmi_InitializeHDMIDevice();
    }
    else
    {
        err = TM_ERR_NOT_SUPPORTED;
        dprintk(1,"No pointer found for InitializeHDMIDevice function. Has HDMI device registered?\n");
    }

    return err;
}

int phStbHdmi_MultiChannelPCMSupported(void)
{
    int result;

    if (phStbHdmi_funcs.phStbHdmi_MultiChannelPCMSupported)
    {
        result = phStbHdmi_funcs.phStbHdmi_MultiChannelPCMSupported();
    }
    else
    {
        result = false;
        dprintk(1,"No pointer found for MultiChannelPCMSupported function. Has HDMI device registered?\n");
    }

    return result;
}

/**
 * phStbHdmi_get_modes - Get the live mode database.
 *
 * @videoMode: Ptr to first entry in the database.
 * @dbSize:   Size of the database.
 *
 * Returns zero.
 */
static int phStbHdmi_get_modes(struct videodenc_videomode **ppVideoMode, int *dbSize)
{
    *ppVideoMode = phStbHdmi_modedb;
    *dbSize   = (sizeof(*phStbHdmi_modedb)) * ARRAY_SIZE(phStbHdmi_modedb);

    return 0;
}

/**
 * phStbHdmi_get_number_modes - Get the number of entries in the live modedb.
 *
 * @num_modes:   Size of the database.
 *
 * Returns zero.
 */
static int phStbHdmi_get_number_modes(int *num_modes)
{
    *num_modes   = ARRAY_SIZE(phStbHdmi_modedb);

    return 0;
}

/* Handle function pointers for the HDMI IOCTLs */

static int phStbHdmi_ioctlSetAudioRate(unsigned long arg)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_ioctlSetAudioRate)
    {
        err = phStbHdmi_funcs.phStbHdmi_ioctlSetAudioRate(arg);
    }
    else
    {
        dprintk(1,"No pointer found for phStbHdmi_ioctlSetAudioRate. Has HDMI device registered?\n");
    }

    return err;
}

static int phStbHdmi_ioctlGetEdidBlkCnt(tmUnitSelect_t txUnit, unsigned long arg)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_ioctlGetEdidBlkCnt)
    {
        err = phStbHdmi_funcs.phStbHdmi_ioctlGetEdidBlkCnt(txUnit, arg);
    }
    else
    {
        dprintk(1,"No pointer found for phStbHdmi_ioctlGetEdidBlkCnt. Has HDMI device registered?\n");
    }

    return err;
}

static int phStbHdmi_ioctlGetEdidData(tmUnitSelect_t txUnit, unsigned long arg)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_ioctlGetEdidData)
    {
        err = phStbHdmi_funcs.phStbHdmi_ioctlGetEdidData(txUnit, arg);
    }
    else
    {
        dprintk(1,"No pointer found for phStbHdmi_ioctlGetEdidData. Has HDMI device registered?\n");
    }

    return err;
}

static int phStbHdmi_ioctlEnableDisableHdmi(tmUnitSelect_t txUnit, int disable)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_ioctlEnableDisableHdmi)
    {
        err = phStbHdmi_funcs.phStbHdmi_ioctlEnableDisableHdmi(txUnit, disable);
    }
    else
    {
        dprintk(1,"No pointer found for phStbHdmi_ioctlEnableDisableHdmi. Has HDMI device registered?\n");
    }

    return err;
}

static int phStbHdmi_ioctlGetAudioCap(tmUnitSelect_t txUnit, unsigned long arg)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_ioctlGetAudioCap)
    {
        err = phStbHdmi_funcs.phStbHdmi_ioctlGetAudioCap(txUnit, arg);
    }
    else
    {
        dprintk(1,"No pointer found for phStbHdmi_ioctlGetAudioCap. Has HDMI device registered?\n");
    }

    return err;
}

static int phStbHdmi_ioctlGetVideoCap(tmUnitSelect_t txUnit, unsigned long arg)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_ioctlGetVideoCap)
    {
        err = phStbHdmi_funcs.phStbHdmi_ioctlGetVideoCap(txUnit, arg);
    }
    else
    {
        dprintk(1,"No pointer found for phStbHdmi_ioctlGetVideoCap. Has HDMI device registered?\n");
    }

    return err;
}

static int phStbHdmi_ioctlGetHotplugStatus(tmUnitSelect_t txUnit, unsigned long arg)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_ioctlGetHotplugStatus)
    {
        err = phStbHdmi_funcs.phStbHdmi_ioctlGetHotplugStatus(txUnit, arg);
    }
    else
    {
        dprintk(1,"No pointer found for phStbHdmi_ioctlGetHotplugStatus. Has HDMI device registered?\n");
    }

    return err;
}

static int phStbHdmi_ioctlGetSinkType(tmUnitSelect_t txUnit, unsigned long arg)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_ioctlGetSinkType)
    {
        err = phStbHdmi_funcs.phStbHdmi_ioctlGetSinkType(txUnit, arg);
    }
    else
    {
        dprintk(1,"No pointer found for phStbHdmi_ioctlGetSinkType. Has HDMI device registered?\n");
    }

    return err;
}

static int phStbHdmi_ioctlGetRxSenseStatus(tmUnitSelect_t txUnit, unsigned long arg)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_ioctlGetRxSenseStatus)
    {
        err = phStbHdmi_funcs.phStbHdmi_ioctlGetRxSenseStatus(txUnit, arg);
    }
    else
    {
        dprintk(1,"No pointer found for phStbHdmi_ioctlGetRxSenseStatus. Has HDMI device registered?\n");
    }

    return err;
}

static int phStbHdmi_ioctlWaitCallbackStatus(tmUnitSelect_t txUnit, unsigned long arg)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_ioctlWaitCallbackStatus)
    {
        err = phStbHdmi_funcs.phStbHdmi_ioctlWaitCallbackStatus(txUnit, arg);
    }
    else
    {
        dprintk(1,"No pointer found for phStbHdmi_ioctlWaitCallbackStatus. Has HDMI device registered?\n");
    }

    return err;
}

static int phStbHdmi_ioctlUserUnblockWaitStatus(void)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_ioctlUserUnblockWaitStatus)
    {
        err = phStbHdmi_funcs.phStbHdmi_ioctlUserUnblockWaitStatus();
    }
    else
    {
        dprintk(1,"No pointer found for phStbHdmi_ioctlUserUnblockWaitStatus. Has HDMI device registered?\n");
    }

    return err;
}

static int phStbHdmi_ioctlEnableDisableAudio(tmUnitSelect_t txUnit, int disable)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_ioctlEnableDisableAudio)
    {
        err = phStbHdmi_funcs.phStbHdmi_ioctlEnableDisableAudio(txUnit, disable);
    }
    else
    {
        dprintk(1,"No pointer found for phStbHdmi_ioctlEnableDisableAudio. Has HDMI device registered?\n");
    }

    return err;
}

static int phStbHdmi_ioctlStartHdcp(tmUnitSelect_t txUnit, unsigned long arg)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_ioctlStartHdcp)
    {
        err = phStbHdmi_funcs.phStbHdmi_ioctlStartHdcp(txUnit, arg);
    }
    else
    {
        dprintk(1,"No pointer found for phStbHdmi_ioctlStartHdcp. Has HDMI device registered?\n");
    }

    return err;
}

static int phStbHdmi_ioctlStopHdcp(tmUnitSelect_t txUnit, unsigned long arg)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_ioctlStopHdcp)
    {
        err = phStbHdmi_funcs.phStbHdmi_ioctlStopHdcp(txUnit, arg);
    }
    else
    {
        dprintk(1,"No pointer found for phStbHdmi_ioctlStopHdcp. Has HDMI device registered?\n");
    }

    return err;
}

static int phStbHdmi_ioctlGetHdcpStatus(tmUnitSelect_t txUnit, unsigned long arg)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_ioctlGetHdcpStatus)
    {
        err = phStbHdmi_funcs.phStbHdmi_ioctlGetHdcpStatus(txUnit, arg);
    }
    else
    {
        dprintk(1,"No pointer found for phStbHdmi_ioctlGetHdcpStatus. Has HDMI device registered?\n");
    }

    return err;
}

static int phStbHdmi_ioctl_test_pattern(struct videodenc_info *info, int test_pattern)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_ioctl_test_pattern)
    {
        err = phStbHdmi_funcs.phStbHdmi_ioctl_test_pattern(info, test_pattern);
    }
    else
    {
        dprintk(1,"No pointer found for phStbHdmi_ioctl_test_pattern. Has HDMI device registered?\n");
    }

    return err;
}

static int phStbHdmi_ioctlGetTmHdmiTxobject(tmUnitSelect_t txUnit, unsigned long arg)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_ioctlGetTmHdmiTxobject)
    {
        err = phStbHdmi_funcs.phStbHdmi_ioctlGetTmHdmiTxobject(txUnit, arg);
    }
    else
    {
        dprintk(1,"No pointer found for phStbHdmi_ioctlGetTmHdmiTxobject. Has HDMI device registered?\n");
    }

    return err;
}

static int phStbHdmi_ioctlExtended(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg, struct videodenc_info *info)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_ioctlExtended)
    {
        err = phStbHdmi_funcs.phStbHdmi_ioctlExtended(inode, file, cmd, arg, info);
    }
    else
    {
        dprintk(1,"No pointer found for phStbHdmi_ioctlExtended. Has HDMI device registered?\n");
    }

    return err;
}

/* Handle all HDMI ioctls supported by the device */
static int phStbHdmi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg, struct videodenc_info *info)
{
    tmUnitSelect_t  txUnit = 0; //Always 0 for STB225
    int result;

    switch (cmd)
    {
    case PH_STBHDMI_IOCTL_SET_AUDIO_RATE :
        result = phStbHdmi_ioctlSetAudioRate(arg);
        break;
    case PH_STBHDMI_IOCTL_SET_VIDEO_MODE:
    {
        struct videodenc_info kVidInfo;
        if (copy_from_user((char *)&kVidInfo.var, (char *)arg,
                           sizeof(struct videodenc_var_screeninfo)))
        {
            dprintk(1,"PH_STBHDMI_IOCTL_SET_VIDEO_MODE<ERR>cannot copy from user\n");
            result = -EFAULT;
            break;
        }
        result = phStbHdmi_set_mode(&kVidInfo);
        break;
    }
    case PH_STBHDMI_IOCTL_GET_EDID_BLKCNT:
        result = phStbHdmi_ioctlGetEdidBlkCnt(txUnit, arg);
        break;
    case PH_STBHDMI_IOCTL_GET_EDID_DATA:
        result = phStbHdmi_ioctlGetEdidData(txUnit, arg);
        break;
    case PH_STBHDMI_IOCTL_DISABLE_HDMI_OUTPUT:
        result = phStbHdmi_ioctlEnableDisableHdmi(txUnit, 1);
        break;
    case PH_STBHDMI_IOCTL_ENABLE_HDMI_OUTPUT:
        result = phStbHdmi_ioctlEnableDisableHdmi(txUnit, 0);
        break;
    case PH_STBHDMI_IOCTL_GET_AUDIO_CAP:
        result = phStbHdmi_ioctlGetAudioCap(txUnit, arg);
        break;
    case PH_STBHDMI_IOCTL_GET_VIDEO_CAP:
        result = phStbHdmi_ioctlGetVideoCap(txUnit, arg);
        break;
    case PH_STBHDMI_IOCTL_GET_HOTPLUG_STATUS:
        result = phStbHdmi_ioctlGetHotplugStatus(txUnit, arg);
        break;
    case PH_STBHDMI_IOCTL_GET_SINK_TYPE:
        result = phStbHdmi_ioctlGetSinkType(txUnit, arg);
        break;
    case PH_STBHDMI_IOCTL_GET_RXSENSE_STATUS:
        result = phStbHdmi_ioctlGetRxSenseStatus(txUnit, arg);
        break;
    case PH_STBHDMI_IOCTL_WAIT_CALLBACK_STATUS:
        result = phStbHdmi_ioctlWaitCallbackStatus(txUnit, arg);
        break;
    case PH_STBHDMI_IOCTL_UNBLOCK_CALLBACK:
        result = phStbHdmi_ioctlUserUnblockWaitStatus();
        break;
    case PH_STBHDMI_IOCTL_DISABLE_AUDIO_OUTPUT:
        result = phStbHdmi_ioctlEnableDisableAudio(txUnit, 1);
        break;
    case PH_STBHDMI_IOCTL_ENABLE_AUDIO_OUTPUT:
        result = phStbHdmi_ioctlEnableDisableAudio(txUnit, 0);
        break;
    case PH_STBHDMI_IOCTL_START_HDCP:
        result = phStbHdmi_ioctlStartHdcp(txUnit, arg);
        break;
    case PH_STBHDMI_IOCTL_STOP_HDCP:
        result = phStbHdmi_ioctlStopHdcp(txUnit, arg);
        break;
    case PH_STBHDMI_IOCTL_GET_HDCP_STATUS:
        result = phStbHdmi_ioctlGetHdcpStatus(txUnit, arg);
        break;
    case PH_STBHDMI_IOCTL_SET_TEST_PATTERN:
    {
        int test_pattern;
        if (copy_from_user(&test_pattern, (char *)arg, sizeof(int)))
        {
            dprintk(1,"PH_STBHDMI_IOCTL_SET_TEST_PATTERN<ERR>cannot copy from user\n");
            result = -EFAULT;
            break;
        }
        result = phStbHdmi_ioctl_test_pattern(NULL, test_pattern);
        break;
    }
    case PH_STBHDMI_IOCTL_GET_TX_OBJECT:
        result = phStbHdmi_ioctlGetTmHdmiTxobject(txUnit, arg);
        break;
    default:
        result = phStbHdmi_ioctlExtended(inode, file, cmd, arg, info);
        break;
    }

    return result;
}

/* ------------------------------------------------------------------------- */
/*
 * Video denc operations that we have implemented and support.
 */
static struct videodenc_ops gHdmiVdenc_ops =
{
    .owner                      = THIS_MODULE,
    .videodenc_check_mode       = &phStbHdmi_check_mode,
    .videodenc_set_mode         = &phStbHdmi_set_mode,
    .videodenc_test_pattern     = &phStbHdmi_test_pattern,
    .videodenc_blank            = &phStbHdmi_blank,
    .videodenc_get_modes        = &phStbHdmi_get_modes,
    .videodenc_get_number_modes = &phStbHdmi_get_number_modes,
    .videodenc_ioctl            = &phStbHdmi_ioctl
};

/*
 *  Initialization of the Video Denc.
 */
static int phStbHdmi_probe(struct platform_device *p_dev)
{
    int retval = 0;
    uint32_t modeIndex = 0;
    uint32_t index = 0;
#ifndef MODULE
    char *option = NULL;
#endif

    /* Initialise the old video denc info structure to ensure the first call to */
    /* phStbHdmi_set_mode succeeds by using a guard value for one of the members. */
    old_videodenc_info.var.output_signal = VIDEODENC_OUTSIGNAL_MAX_ENTRIES;

    /*
     * Set up the default display mode
     */
    strcpy(display_mode, "1280x720x60p");

#ifdef MODULE
    if (mode_option)
    {
        strcpy(display_mode, mode_option);
    }
#else
    /*
    *  For kernel boot options (in 'videodenc=phStbHdmi:<option>:<option>...' format)
    */
    if (videodenc_get_options("phStbHdmi", &option))
    {
        printk(KERN_WARNING "Failed to parse specified options\n");
        return -ENODEV;
    }

#endif

    gphStbHdmi_info.pvdenc_info = videodenc_alloc(0, &p_dev->dev);
    if (gphStbHdmi_info.pvdenc_info == NULL)
    {
        printk(KERN_ERR "Error videodenc_alloc\n");
        return -ENOMEM;
    }

    /*
     * Function pointers and fixed values filled in here.
     */
    gphStbHdmi_info.pvdenc_info->videodenc_ops = &gHdmiVdenc_ops;
    gphStbHdmi_info.pvdenc_info->fix = gHdmiVdenc_fix;

    printk(KERN_INFO "phStbHdmi: vdenc%d: %s video denc device\n",
           gphStbHdmi_info.pvdenc_info->node,
           gphStbHdmi_info.pvdenc_info->fix.id);

    /*
     * This should give a reasonable default video mode.
     */
    retval = videodenc_find_mode(&gphStbHdmi_info.pvdenc_info->var,
                                 gphStbHdmi_info.pvdenc_info,
                                 display_mode,
                                 phStbHdmi_modedb,
                                 ARRAY_SIZE(phStbHdmi_modedb),
                                 NULL);

    if (!retval || retval == 4)
    {
        printk(KERN_ERR "phStbHdmi: Unable to find a video denc video mode.(Format: XxY-Bpp@Hz)\n");
        return -EINVAL;
    }
    else
    {
        printk(KERN_INFO "phStbHdmi: Using specified video mode (%s)\n", display_mode);
    }

    for (modeIndex = 0; modeIndex < ARRAY_SIZE(phStbHdmi_modedb); modeIndex++)
    {
        /*Check if we support the mode that has changed to*/
        if (mode_matches_exact(phStbHdmi_modedb[modeIndex],
                               gphStbHdmi_info.pvdenc_info->var.xres,
                               gphStbHdmi_info.pvdenc_info->var.yres,
                               gphStbHdmi_info.pvdenc_info->var.refresh,
                               gphStbHdmi_info.pvdenc_info->var.scantype,
                               gphStbHdmi_info.pvdenc_info->var.output_signal,
                               gphStbHdmi_info.pvdenc_info->var.bits_per_pixel,
                               gphStbHdmi_info.pvdenc_info->var.tv_standard))
        {
            break;
        }
    }

    /*We now know the index to our mode database so can add the first supported connector.*/
    if ((phStbHdmi_modedb[modeIndex].supported_connectors[0].in_use) &&
            (phStbHdmi_modedb[modeIndex].supported_connectors[0].type != VIDEODENC_CONNECTOR_SCART) &&
            (phStbHdmi_modedb[modeIndex].supported_connectors[0].connector_id != 1))
    {
        gphStbHdmi_info.pvdenc_info->var.chosen_connectors[index++] = phStbHdmi_modedb[modeIndex].supported_connectors[0];
    }

    /*Registering the video denc is delayed until some HDMI driver calls phStbHdmi_Register. */
    gp_dev = p_dev;

    return 0;
}

/*
 *  Cleanup
 */
static int phStbHdmi_remove(struct platform_device* p_dev)
{
    /* Unregister the video denc */
    unregister_videodenc(gphStbHdmi_info.pvdenc_info);

    /* Remove sysfs entries */
    videodenc_unregister_sysfs_entries(&p_dev->dev, &gphStbHdmi_info.sysfs_attrs);

    return 0;
}

#ifdef CONFIG_PM
static int phStbHdmi_suspend(struct platform_device* p_dev, pm_message_t event)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_suspend)
    {
        err = phStbHdmi_funcs.phStbHdmi_suspend(p_dev,event);
    }
    else
    {
        dprintk(1,"No pointer found for phStbHdmi_suspend. Has HDMI device registered?\n");
    }
    return err;
}

static int phStbHdmi_resume(struct platform_device* p_dev)
{
    int err = -ENOSYS;

    if (phStbHdmi_funcs.phStbHdmi_resume)
    {
        err = phStbHdmi_funcs.phStbHdmi_resume(p_dev);
    }
    else
    {
        dprintk(1,"No pointer found for phStbHdmi_resume. Has HDMI device registered?\n");
    }
    return err;
}
#endif // #ifdef CONFIG_PM

int phStbHdmi_Register(phStbHdmi_Ops_t Hdmi_funcs)
{
    int retVal = 0;

    if(devRegistered)
    {
        retVal= -EPERM;
        printk(KERN_WARNING "phStbHdmi: Error 0x%X, a device has already registered with phStbHdmi\n", retVal);
        return retVal;
    }

    /* Fill in the function pointers */
    phStbHdmi_funcs = Hdmi_funcs;

    /*Now register the video Denc*/
    if (register_videodenc(gphStbHdmi_info.pvdenc_info, 0) < 0)
    {
        printk(KERN_WARNING "Unable to Register Video Denc\n");
        return -EINVAL;
    }

    /*Now do sysfs stuff*/
    platform_set_drvdata(gp_dev, gphStbHdmi_info.pvdenc_info);
    videodenc_register_sysfs_entries(&gp_dev->dev, &gphStbHdmi_info.sysfs_attrs);

    /* An HDMI device has registered itself, so set the initial display mode */
    retVal = phStbHdmi_set_mode(gphStbHdmi_info.pvdenc_info);
    if (retVal)
    {
        printk(KERN_WARNING "phStbHdmi: Error 0x%X setting up initial video mode\n", retVal);
    }

    /* An HDMI device has registered itself with phStbHdmi */
    devRegistered = true;

    return retVal;
}

static int __init phStbHdmi_Init (void)
{
    int retValue;

    memset(&phStbHdmi_funcs, 0, sizeof( phStbHdmi_funcs ));

    /* Fill these in before calling videodenc_register_driver as they are used!!*/
    gphStbHdmi_info.sysfs_attrs.attr_vendor = dev_attr_vendor;
    gphStbHdmi_info.sysfs_attrs.attr_revision = dev_attr_revision;
    gphStbHdmi_info.sysfs_attrs.attr_device_name = dev_attr_device_name;

#ifdef CONFIG_PM
    gphStbHdmi_info.platform_driver_info.suspend = &phStbHdmi_suspend;
    gphStbHdmi_info.platform_driver_info.resume = &phStbHdmi_resume;
#endif

    /* Register the new video denc */
    retValue = videodenc_register_driver("hdmi-",
                                         0,
                                         &gphStbHdmi_info.platform_driver_info,
                                         &gphStbHdmi_info.platform_device_info,
                                         &phStbHdmi_probe,
                                         &phStbHdmi_remove);

    return retValue;
}

static void __exit phStbHdmi_Exit (void)
{
    dprintk(1,"phStbHdmi Exit \n");
}

module_init(phStbHdmi_Init);
module_exit(phStbHdmi_Exit);

module_param(debug, uint, 0);
MODULE_PARM_DESC(debug, "Debug level (0-1)");

module_param(mode_option, charp, 0644);
MODULE_PARM_DESC(mode_option, "Use a specifed video mode as default\n");

MODULE_DESCRIPTION("HDMI Component");
MODULE_AUTHOR("NXP B.V.");
MODULE_LICENSE("GPL v2");
