cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vpbe_venc.c (17373B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2010 Texas Instruments Inc
      4 */
      5#include <linux/module.h>
      6#include <linux/mod_devicetable.h>
      7#include <linux/kernel.h>
      8#include <linux/init.h>
      9#include <linux/ctype.h>
     10#include <linux/delay.h>
     11#include <linux/device.h>
     12#include <linux/interrupt.h>
     13#include <linux/platform_device.h>
     14#include <linux/videodev2.h>
     15#include <linux/slab.h>
     16
     17#include <linux/platform_data/i2c-davinci.h>
     18
     19#include <linux/io.h>
     20
     21#include <media/davinci/vpbe_types.h>
     22#include <media/davinci/vpbe_venc.h>
     23#include <media/davinci/vpss.h>
     24#include <media/v4l2-device.h>
     25
     26#include "vpbe_venc_regs.h"
     27
     28#define MODULE_NAME	"davinci-vpbe-venc"
     29
     30static const struct platform_device_id vpbe_venc_devtype[] = {
     31	{
     32		.name = DM644X_VPBE_VENC_SUBDEV_NAME,
     33		.driver_data = VPBE_VERSION_1,
     34	}, {
     35		.name = DM365_VPBE_VENC_SUBDEV_NAME,
     36		.driver_data = VPBE_VERSION_2,
     37	}, {
     38		.name = DM355_VPBE_VENC_SUBDEV_NAME,
     39		.driver_data = VPBE_VERSION_3,
     40	},
     41	{
     42		/* sentinel */
     43	}
     44};
     45
     46MODULE_DEVICE_TABLE(platform, vpbe_venc_devtype);
     47
     48static int debug = 2;
     49module_param(debug, int, 0644);
     50MODULE_PARM_DESC(debug, "Debug level 0-2");
     51
     52struct venc_state {
     53	struct v4l2_subdev sd;
     54	struct venc_callback *callback;
     55	struct venc_platform_data *pdata;
     56	struct device *pdev;
     57	u32 output;
     58	v4l2_std_id std;
     59	spinlock_t lock;
     60	void __iomem *venc_base;
     61	void __iomem *vdaccfg_reg;
     62	enum vpbe_version venc_type;
     63};
     64
     65static inline struct venc_state *to_state(struct v4l2_subdev *sd)
     66{
     67	return container_of(sd, struct venc_state, sd);
     68}
     69
     70static inline u32 venc_read(struct v4l2_subdev *sd, u32 offset)
     71{
     72	struct venc_state *venc = to_state(sd);
     73
     74	return readl(venc->venc_base + offset);
     75}
     76
     77static inline u32 venc_write(struct v4l2_subdev *sd, u32 offset, u32 val)
     78{
     79	struct venc_state *venc = to_state(sd);
     80
     81	writel(val, (venc->venc_base + offset));
     82
     83	return val;
     84}
     85
     86static inline u32 venc_modify(struct v4l2_subdev *sd, u32 offset,
     87				 u32 val, u32 mask)
     88{
     89	u32 new_val = (venc_read(sd, offset) & ~mask) | (val & mask);
     90
     91	venc_write(sd, offset, new_val);
     92
     93	return new_val;
     94}
     95
     96static inline u32 vdaccfg_write(struct v4l2_subdev *sd, u32 val)
     97{
     98	struct venc_state *venc = to_state(sd);
     99
    100	writel(val, venc->vdaccfg_reg);
    101
    102	val = readl(venc->vdaccfg_reg);
    103
    104	return val;
    105}
    106
    107#define VDAC_COMPONENT	0x543
    108#define VDAC_S_VIDEO	0x210
    109/* This function sets the dac of the VPBE for various outputs
    110 */
    111static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index)
    112{
    113	switch (out_index) {
    114	case 0:
    115		v4l2_dbg(debug, 1, sd, "Setting output to Composite\n");
    116		venc_write(sd, VENC_DACSEL, 0);
    117		break;
    118	case 1:
    119		v4l2_dbg(debug, 1, sd, "Setting output to Component\n");
    120		venc_write(sd, VENC_DACSEL, VDAC_COMPONENT);
    121		break;
    122	case 2:
    123		v4l2_dbg(debug, 1, sd, "Setting output to S-video\n");
    124		venc_write(sd, VENC_DACSEL, VDAC_S_VIDEO);
    125		break;
    126	default:
    127		return -EINVAL;
    128	}
    129
    130	return 0;
    131}
    132
    133static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable)
    134{
    135	struct venc_state *venc = to_state(sd);
    136
    137	v4l2_dbg(debug, 2, sd, "venc_enabledigitaloutput\n");
    138
    139	if (benable) {
    140		venc_write(sd, VENC_VMOD, 0);
    141		venc_write(sd, VENC_CVBS, 0);
    142		venc_write(sd, VENC_LCDOUT, 0);
    143		venc_write(sd, VENC_HSPLS, 0);
    144		venc_write(sd, VENC_HSTART, 0);
    145		venc_write(sd, VENC_HVALID, 0);
    146		venc_write(sd, VENC_HINT, 0);
    147		venc_write(sd, VENC_VSPLS, 0);
    148		venc_write(sd, VENC_VSTART, 0);
    149		venc_write(sd, VENC_VVALID, 0);
    150		venc_write(sd, VENC_VINT, 0);
    151		venc_write(sd, VENC_YCCCTL, 0);
    152		venc_write(sd, VENC_DACSEL, 0);
    153
    154	} else {
    155		venc_write(sd, VENC_VMOD, 0);
    156		/* disable VCLK output pin enable */
    157		venc_write(sd, VENC_VIDCTL, 0x141);
    158
    159		/* Disable output sync pins */
    160		venc_write(sd, VENC_SYNCCTL, 0);
    161
    162		/* Disable DCLOCK */
    163		venc_write(sd, VENC_DCLKCTL, 0);
    164		venc_write(sd, VENC_DRGBX1, 0x0000057C);
    165
    166		/* Disable LCD output control (accepting default polarity) */
    167		venc_write(sd, VENC_LCDOUT, 0);
    168		if (venc->venc_type != VPBE_VERSION_3)
    169			venc_write(sd, VENC_CMPNT, 0x100);
    170		venc_write(sd, VENC_HSPLS, 0);
    171		venc_write(sd, VENC_HINT, 0);
    172		venc_write(sd, VENC_HSTART, 0);
    173		venc_write(sd, VENC_HVALID, 0);
    174
    175		venc_write(sd, VENC_VSPLS, 0);
    176		venc_write(sd, VENC_VINT, 0);
    177		venc_write(sd, VENC_VSTART, 0);
    178		venc_write(sd, VENC_VVALID, 0);
    179
    180		venc_write(sd, VENC_HSDLY, 0);
    181		venc_write(sd, VENC_VSDLY, 0);
    182
    183		venc_write(sd, VENC_YCCCTL, 0);
    184		venc_write(sd, VENC_VSTARTA, 0);
    185
    186		/* Set OSD clock and OSD Sync Adavance registers */
    187		venc_write(sd, VENC_OSDCLK0, 1);
    188		venc_write(sd, VENC_OSDCLK1, 2);
    189	}
    190}
    191
    192static void
    193venc_enable_vpss_clock(int venc_type,
    194		       enum vpbe_enc_timings_type type,
    195		       unsigned int pclock)
    196{
    197	if (venc_type == VPBE_VERSION_1)
    198		return;
    199
    200	if (venc_type == VPBE_VERSION_2 && (type == VPBE_ENC_STD || (type ==
    201	    VPBE_ENC_DV_TIMINGS && pclock <= 27000000))) {
    202		vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1);
    203		vpss_enable_clock(VPSS_VPBE_CLOCK, 1);
    204		return;
    205	}
    206
    207	if (venc_type == VPBE_VERSION_3 && type == VPBE_ENC_STD)
    208		vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 0);
    209}
    210
    211#define VDAC_CONFIG_SD_V3	0x0E21A6B6
    212#define VDAC_CONFIG_SD_V2	0x081141CF
    213/*
    214 * setting NTSC mode
    215 */
    216static int venc_set_ntsc(struct v4l2_subdev *sd)
    217{
    218	struct venc_state *venc = to_state(sd);
    219	struct venc_platform_data *pdata = venc->pdata;
    220
    221	v4l2_dbg(debug, 2, sd, "venc_set_ntsc\n");
    222
    223	/* Setup clock at VPSS & VENC for SD */
    224	vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1);
    225	if (pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_525_60) < 0)
    226		return -EINVAL;
    227
    228	venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_STD, V4L2_STD_525_60);
    229	venc_enabledigitaloutput(sd, 0);
    230
    231	if (venc->venc_type == VPBE_VERSION_3) {
    232		venc_write(sd, VENC_CLKCTL, 0x01);
    233		venc_write(sd, VENC_VIDCTL, 0);
    234		vdaccfg_write(sd, VDAC_CONFIG_SD_V3);
    235	} else if (venc->venc_type == VPBE_VERSION_2) {
    236		venc_write(sd, VENC_CLKCTL, 0x01);
    237		venc_write(sd, VENC_VIDCTL, 0);
    238		vdaccfg_write(sd, VDAC_CONFIG_SD_V2);
    239	} else {
    240		/* to set VENC CLK DIV to 1 - final clock is 54 MHz */
    241		venc_modify(sd, VENC_VIDCTL, 0, 1 << 1);
    242		/* Set REC656 Mode */
    243		venc_write(sd, VENC_YCCCTL, 0x1);
    244		venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAFRQ);
    245		venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAUPS);
    246	}
    247
    248	venc_write(sd, VENC_VMOD, 0);
    249	venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
    250			VENC_VMOD_VIE);
    251	venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_VMD), VENC_VMOD_VMD);
    252	venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_TVTYP_SHIFT),
    253			VENC_VMOD_TVTYP);
    254	venc_write(sd, VENC_DACTST, 0x0);
    255	venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
    256
    257	return 0;
    258}
    259
    260/*
    261 * setting PAL mode
    262 */
    263static int venc_set_pal(struct v4l2_subdev *sd)
    264{
    265	struct venc_state *venc = to_state(sd);
    266
    267	v4l2_dbg(debug, 2, sd, "venc_set_pal\n");
    268
    269	/* Setup clock at VPSS & VENC for SD */
    270	vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1);
    271	if (venc->pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_625_50) < 0)
    272		return -EINVAL;
    273
    274	venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_STD, V4L2_STD_625_50);
    275	venc_enabledigitaloutput(sd, 0);
    276
    277	if (venc->venc_type == VPBE_VERSION_3) {
    278		venc_write(sd, VENC_CLKCTL, 0x1);
    279		venc_write(sd, VENC_VIDCTL, 0);
    280		vdaccfg_write(sd, VDAC_CONFIG_SD_V3);
    281	} else if (venc->venc_type == VPBE_VERSION_2) {
    282		venc_write(sd, VENC_CLKCTL, 0x1);
    283		venc_write(sd, VENC_VIDCTL, 0);
    284		vdaccfg_write(sd, VDAC_CONFIG_SD_V2);
    285	} else {
    286		/* to set VENC CLK DIV to 1 - final clock is 54 MHz */
    287		venc_modify(sd, VENC_VIDCTL, 0, 1 << 1);
    288		/* Set REC656 Mode */
    289		venc_write(sd, VENC_YCCCTL, 0x1);
    290	}
    291
    292	venc_modify(sd, VENC_SYNCCTL, 1 << VENC_SYNCCTL_OVD_SHIFT,
    293			VENC_SYNCCTL_OVD);
    294	venc_write(sd, VENC_VMOD, 0);
    295	venc_modify(sd, VENC_VMOD,
    296			(1 << VENC_VMOD_VIE_SHIFT),
    297			VENC_VMOD_VIE);
    298	venc_modify(sd, VENC_VMOD,
    299			(0 << VENC_VMOD_VMD), VENC_VMOD_VMD);
    300	venc_modify(sd, VENC_VMOD,
    301			(1 << VENC_VMOD_TVTYP_SHIFT),
    302			VENC_VMOD_TVTYP);
    303	venc_write(sd, VENC_DACTST, 0x0);
    304	venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
    305
    306	return 0;
    307}
    308
    309#define VDAC_CONFIG_HD_V2	0x081141EF
    310/*
    311 * venc_set_480p59_94
    312 *
    313 * This function configures the video encoder to EDTV(525p) component setting.
    314 */
    315static int venc_set_480p59_94(struct v4l2_subdev *sd)
    316{
    317	struct venc_state *venc = to_state(sd);
    318	struct venc_platform_data *pdata = venc->pdata;
    319
    320	v4l2_dbg(debug, 2, sd, "venc_set_480p59_94\n");
    321	if (venc->venc_type != VPBE_VERSION_1 &&
    322	    venc->venc_type != VPBE_VERSION_2)
    323		return -EINVAL;
    324
    325	/* Setup clock at VPSS & VENC for SD */
    326	if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 27000000) < 0)
    327		return -EINVAL;
    328
    329	venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 27000000);
    330	venc_enabledigitaloutput(sd, 0);
    331
    332	if (venc->venc_type == VPBE_VERSION_2)
    333		vdaccfg_write(sd, VDAC_CONFIG_HD_V2);
    334	venc_write(sd, VENC_OSDCLK0, 0);
    335	venc_write(sd, VENC_OSDCLK1, 1);
    336
    337	if (venc->venc_type == VPBE_VERSION_1) {
    338		venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ,
    339			    VENC_VDPRO_DAFRQ);
    340		venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS,
    341			    VENC_VDPRO_DAUPS);
    342	}
    343
    344	venc_write(sd, VENC_VMOD, 0);
    345	venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
    346		    VENC_VMOD_VIE);
    347	venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD);
    348	venc_modify(sd, VENC_VMOD, (HDTV_525P << VENC_VMOD_TVTYP_SHIFT),
    349		    VENC_VMOD_TVTYP);
    350	venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 <<
    351		    VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD);
    352
    353	venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
    354
    355	return 0;
    356}
    357
    358/*
    359 * venc_set_625p
    360 *
    361 * This function configures the video encoder to HDTV(625p) component setting
    362 */
    363static int venc_set_576p50(struct v4l2_subdev *sd)
    364{
    365	struct venc_state *venc = to_state(sd);
    366	struct venc_platform_data *pdata = venc->pdata;
    367
    368	v4l2_dbg(debug, 2, sd, "venc_set_576p50\n");
    369
    370	if (venc->venc_type != VPBE_VERSION_1 &&
    371	    venc->venc_type != VPBE_VERSION_2)
    372		return -EINVAL;
    373	/* Setup clock at VPSS & VENC for SD */
    374	if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 27000000) < 0)
    375		return -EINVAL;
    376
    377	venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 27000000);
    378	venc_enabledigitaloutput(sd, 0);
    379
    380	if (venc->venc_type == VPBE_VERSION_2)
    381		vdaccfg_write(sd, VDAC_CONFIG_HD_V2);
    382
    383	venc_write(sd, VENC_OSDCLK0, 0);
    384	venc_write(sd, VENC_OSDCLK1, 1);
    385
    386	if (venc->venc_type == VPBE_VERSION_1) {
    387		venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ,
    388			    VENC_VDPRO_DAFRQ);
    389		venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS,
    390			    VENC_VDPRO_DAUPS);
    391	}
    392
    393	venc_write(sd, VENC_VMOD, 0);
    394	venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
    395		    VENC_VMOD_VIE);
    396	venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD);
    397	venc_modify(sd, VENC_VMOD, (HDTV_625P << VENC_VMOD_TVTYP_SHIFT),
    398		    VENC_VMOD_TVTYP);
    399
    400	venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 <<
    401		    VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD);
    402	venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
    403
    404	return 0;
    405}
    406
    407/*
    408 * venc_set_720p60_internal - Setup 720p60 in venc for dm365 only
    409 */
    410static int venc_set_720p60_internal(struct v4l2_subdev *sd)
    411{
    412	struct venc_state *venc = to_state(sd);
    413	struct venc_platform_data *pdata = venc->pdata;
    414
    415	if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 74250000) < 0)
    416		return -EINVAL;
    417
    418	venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 74250000);
    419	venc_enabledigitaloutput(sd, 0);
    420
    421	venc_write(sd, VENC_OSDCLK0, 0);
    422	venc_write(sd, VENC_OSDCLK1, 1);
    423
    424	venc_write(sd, VENC_VMOD, 0);
    425	/* DM365 component HD mode */
    426	venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
    427	    VENC_VMOD_VIE);
    428	venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD);
    429	venc_modify(sd, VENC_VMOD, (HDTV_720P << VENC_VMOD_TVTYP_SHIFT),
    430		    VENC_VMOD_TVTYP);
    431	venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
    432	venc_write(sd, VENC_XHINTVL, 0);
    433	return 0;
    434}
    435
    436/*
    437 * venc_set_1080i30_internal - Setup 1080i30 in venc for dm365 only
    438 */
    439static int venc_set_1080i30_internal(struct v4l2_subdev *sd)
    440{
    441	struct venc_state *venc = to_state(sd);
    442	struct venc_platform_data *pdata = venc->pdata;
    443
    444	if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 74250000) < 0)
    445		return -EINVAL;
    446
    447	venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 74250000);
    448	venc_enabledigitaloutput(sd, 0);
    449
    450	venc_write(sd, VENC_OSDCLK0, 0);
    451	venc_write(sd, VENC_OSDCLK1, 1);
    452
    453
    454	venc_write(sd, VENC_VMOD, 0);
    455	/* DM365 component HD mode */
    456	venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
    457		    VENC_VMOD_VIE);
    458	venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD);
    459	venc_modify(sd, VENC_VMOD, (HDTV_1080I << VENC_VMOD_TVTYP_SHIFT),
    460		    VENC_VMOD_TVTYP);
    461	venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
    462	venc_write(sd, VENC_XHINTVL, 0);
    463	return 0;
    464}
    465
    466static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm)
    467{
    468	v4l2_dbg(debug, 1, sd, "venc_s_std_output\n");
    469
    470	if (norm & V4L2_STD_525_60)
    471		return venc_set_ntsc(sd);
    472	else if (norm & V4L2_STD_625_50)
    473		return venc_set_pal(sd);
    474
    475	return -EINVAL;
    476}
    477
    478static int venc_s_dv_timings(struct v4l2_subdev *sd,
    479			    struct v4l2_dv_timings *dv_timings)
    480{
    481	struct venc_state *venc = to_state(sd);
    482	u32 height = dv_timings->bt.height;
    483	int ret;
    484
    485	v4l2_dbg(debug, 1, sd, "venc_s_dv_timings\n");
    486
    487	if (height == 576)
    488		return venc_set_576p50(sd);
    489	else if (height == 480)
    490		return venc_set_480p59_94(sd);
    491	else if ((height == 720) &&
    492			(venc->venc_type == VPBE_VERSION_2)) {
    493		/* TBD setup internal 720p mode here */
    494		ret = venc_set_720p60_internal(sd);
    495		/* for DM365 VPBE, there is DAC inside */
    496		vdaccfg_write(sd, VDAC_CONFIG_HD_V2);
    497		return ret;
    498	} else if ((height == 1080) &&
    499		(venc->venc_type == VPBE_VERSION_2)) {
    500		/* TBD setup internal 1080i mode here */
    501		ret = venc_set_1080i30_internal(sd);
    502		/* for DM365 VPBE, there is DAC inside */
    503		vdaccfg_write(sd, VDAC_CONFIG_HD_V2);
    504		return ret;
    505	}
    506	return -EINVAL;
    507}
    508
    509static int venc_s_routing(struct v4l2_subdev *sd, u32 input, u32 output,
    510			  u32 config)
    511{
    512	struct venc_state *venc = to_state(sd);
    513	int ret;
    514
    515	v4l2_dbg(debug, 1, sd, "venc_s_routing\n");
    516
    517	ret = venc_set_dac(sd, output);
    518	if (!ret)
    519		venc->output = output;
    520
    521	return ret;
    522}
    523
    524static long venc_command(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
    525{
    526	u32 val;
    527
    528	switch (cmd) {
    529	case VENC_GET_FLD:
    530		val = venc_read(sd, VENC_VSTAT);
    531		*((int *)arg) = ((val & VENC_VSTAT_FIDST) ==
    532		VENC_VSTAT_FIDST);
    533		break;
    534	default:
    535		v4l2_err(sd, "Wrong IOCTL cmd\n");
    536		break;
    537	}
    538
    539	return 0;
    540}
    541
    542static const struct v4l2_subdev_core_ops venc_core_ops = {
    543	.command      = venc_command,
    544};
    545
    546static const struct v4l2_subdev_video_ops venc_video_ops = {
    547	.s_routing = venc_s_routing,
    548	.s_std_output = venc_s_std_output,
    549	.s_dv_timings = venc_s_dv_timings,
    550};
    551
    552static const struct v4l2_subdev_ops venc_ops = {
    553	.core = &venc_core_ops,
    554	.video = &venc_video_ops,
    555};
    556
    557static int venc_initialize(struct v4l2_subdev *sd)
    558{
    559	struct venc_state *venc = to_state(sd);
    560	int ret;
    561
    562	/* Set default to output to composite and std to NTSC */
    563	venc->output = 0;
    564	venc->std = V4L2_STD_525_60;
    565
    566	ret = venc_s_routing(sd, 0, venc->output, 0);
    567	if (ret < 0) {
    568		v4l2_err(sd, "Error setting output during init\n");
    569		return -EINVAL;
    570	}
    571
    572	ret = venc_s_std_output(sd, venc->std);
    573	if (ret < 0) {
    574		v4l2_err(sd, "Error setting std during init\n");
    575		return -EINVAL;
    576	}
    577
    578	return ret;
    579}
    580
    581static int venc_device_get(struct device *dev, void *data)
    582{
    583	struct platform_device *pdev = to_platform_device(dev);
    584	struct venc_state **venc = data;
    585
    586	if (strstr(pdev->name, "vpbe-venc") != NULL)
    587		*venc = platform_get_drvdata(pdev);
    588
    589	return 0;
    590}
    591
    592struct v4l2_subdev *venc_sub_dev_init(struct v4l2_device *v4l2_dev,
    593		const char *venc_name)
    594{
    595	struct venc_state *venc = NULL;
    596
    597	bus_for_each_dev(&platform_bus_type, NULL, &venc,
    598			venc_device_get);
    599	if (venc == NULL)
    600		return NULL;
    601
    602	v4l2_subdev_init(&venc->sd, &venc_ops);
    603
    604	strscpy(venc->sd.name, venc_name, sizeof(venc->sd.name));
    605	if (v4l2_device_register_subdev(v4l2_dev, &venc->sd) < 0) {
    606		v4l2_err(v4l2_dev,
    607			"vpbe unable to register venc sub device\n");
    608		return NULL;
    609	}
    610	if (venc_initialize(&venc->sd)) {
    611		v4l2_err(v4l2_dev,
    612			"vpbe venc initialization failed\n");
    613		return NULL;
    614	}
    615
    616	return &venc->sd;
    617}
    618EXPORT_SYMBOL(venc_sub_dev_init);
    619
    620static int venc_probe(struct platform_device *pdev)
    621{
    622	const struct platform_device_id *pdev_id;
    623	struct venc_state *venc;
    624
    625	if (!pdev->dev.platform_data) {
    626		dev_err(&pdev->dev, "No platform data for VENC sub device");
    627		return -EINVAL;
    628	}
    629
    630	pdev_id = platform_get_device_id(pdev);
    631	if (!pdev_id)
    632		return -EINVAL;
    633
    634	venc = devm_kzalloc(&pdev->dev, sizeof(struct venc_state), GFP_KERNEL);
    635	if (venc == NULL)
    636		return -ENOMEM;
    637
    638	venc->venc_type = pdev_id->driver_data;
    639	venc->pdev = &pdev->dev;
    640	venc->pdata = pdev->dev.platform_data;
    641
    642	venc->venc_base = devm_platform_ioremap_resource(pdev, 0);
    643	if (IS_ERR(venc->venc_base))
    644		return PTR_ERR(venc->venc_base);
    645
    646	if (venc->venc_type != VPBE_VERSION_1) {
    647		venc->vdaccfg_reg = devm_platform_ioremap_resource(pdev, 1);
    648		if (IS_ERR(venc->vdaccfg_reg))
    649			return PTR_ERR(venc->vdaccfg_reg);
    650	}
    651	spin_lock_init(&venc->lock);
    652	platform_set_drvdata(pdev, venc);
    653	dev_notice(venc->pdev, "VENC sub device probe success\n");
    654
    655	return 0;
    656}
    657
    658static int venc_remove(struct platform_device *pdev)
    659{
    660	return 0;
    661}
    662
    663static struct platform_driver venc_driver = {
    664	.probe		= venc_probe,
    665	.remove		= venc_remove,
    666	.driver		= {
    667		.name	= MODULE_NAME,
    668	},
    669	.id_table	= vpbe_venc_devtype
    670};
    671
    672module_platform_driver(venc_driver);
    673
    674MODULE_LICENSE("GPL");
    675MODULE_DESCRIPTION("VPBE VENC Driver");
    676MODULE_AUTHOR("Texas Instruments");