Linux Audio

Check our new training course

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