diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/media/video/davinci/vpbe_venc.c | |
parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) |
Diffstat (limited to 'drivers/media/video/davinci/vpbe_venc.c')
-rw-r--r-- | drivers/media/video/davinci/vpbe_venc.c | 566 |
1 files changed, 566 insertions, 0 deletions
diff --git a/drivers/media/video/davinci/vpbe_venc.c b/drivers/media/video/davinci/vpbe_venc.c new file mode 100644 index 00000000000..03a3e5c65ee --- /dev/null +++ b/drivers/media/video/davinci/vpbe_venc.c | |||
@@ -0,0 +1,566 @@ | |||
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/io.h> | ||
31 | #include <mach/i2c.h> | ||
32 | |||
33 | #include <linux/io.h> | ||
34 | |||
35 | #include <media/davinci/vpbe_types.h> | ||
36 | #include <media/davinci/vpbe_venc.h> | ||
37 | #include <media/davinci/vpss.h> | ||
38 | #include <media/v4l2-device.h> | ||
39 | |||
40 | #include "vpbe_venc_regs.h" | ||
41 | |||
42 | #define MODULE_NAME VPBE_VENC_SUBDEV_NAME | ||
43 | |||
44 | static int debug = 2; | ||
45 | module_param(debug, int, 0644); | ||
46 | MODULE_PARM_DESC(debug, "Debug level 0-2"); | ||
47 | |||
48 | struct venc_state { | ||
49 | struct v4l2_subdev sd; | ||
50 | struct venc_callback *callback; | ||
51 | struct venc_platform_data *pdata; | ||
52 | struct device *pdev; | ||
53 | u32 output; | ||
54 | v4l2_std_id std; | ||
55 | spinlock_t lock; | ||
56 | void __iomem *venc_base; | ||
57 | void __iomem *vdaccfg_reg; | ||
58 | }; | ||
59 | |||
60 | static inline struct venc_state *to_state(struct v4l2_subdev *sd) | ||
61 | { | ||
62 | return container_of(sd, struct venc_state, sd); | ||
63 | } | ||
64 | |||
65 | static inline u32 venc_read(struct v4l2_subdev *sd, u32 offset) | ||
66 | { | ||
67 | struct venc_state *venc = to_state(sd); | ||
68 | |||
69 | return readl(venc->venc_base + offset); | ||
70 | } | ||
71 | |||
72 | static inline u32 venc_write(struct v4l2_subdev *sd, u32 offset, u32 val) | ||
73 | { | ||
74 | struct venc_state *venc = to_state(sd); | ||
75 | |||
76 | writel(val, (venc->venc_base + offset)); | ||
77 | |||
78 | return val; | ||
79 | } | ||
80 | |||
81 | static inline u32 venc_modify(struct v4l2_subdev *sd, u32 offset, | ||
82 | u32 val, u32 mask) | ||
83 | { | ||
84 | u32 new_val = (venc_read(sd, offset) & ~mask) | (val & mask); | ||
85 | |||
86 | venc_write(sd, offset, new_val); | ||
87 | |||
88 | return new_val; | ||
89 | } | ||
90 | |||
91 | static inline u32 vdaccfg_write(struct v4l2_subdev *sd, u32 val) | ||
92 | { | ||
93 | struct venc_state *venc = to_state(sd); | ||
94 | |||
95 | writel(val, venc->vdaccfg_reg); | ||
96 | |||
97 | val = readl(venc->vdaccfg_reg); | ||
98 | |||
99 | return val; | ||
100 | } | ||
101 | |||
102 | /* This function sets the dac of the VPBE for various outputs | ||
103 | */ | ||
104 | static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index) | ||
105 | { | ||
106 | switch (out_index) { | ||
107 | case 0: | ||
108 | v4l2_dbg(debug, 1, sd, "Setting output to Composite\n"); | ||
109 | venc_write(sd, VENC_DACSEL, 0); | ||
110 | break; | ||
111 | case 1: | ||
112 | v4l2_dbg(debug, 1, sd, "Setting output to S-Video\n"); | ||
113 | venc_write(sd, VENC_DACSEL, 0x210); | ||
114 | break; | ||
115 | case 2: | ||
116 | venc_write(sd, VENC_DACSEL, 0x543); | ||
117 | break; | ||
118 | default: | ||
119 | return -EINVAL; | ||
120 | } | ||
121 | |||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable) | ||
126 | { | ||
127 | v4l2_dbg(debug, 2, sd, "venc_enabledigitaloutput\n"); | ||
128 | |||
129 | if (benable) { | ||
130 | venc_write(sd, VENC_VMOD, 0); | ||
131 | venc_write(sd, VENC_CVBS, 0); | ||
132 | venc_write(sd, VENC_LCDOUT, 0); | ||
133 | venc_write(sd, VENC_HSPLS, 0); | ||
134 | venc_write(sd, VENC_HSTART, 0); | ||
135 | venc_write(sd, VENC_HVALID, 0); | ||
136 | venc_write(sd, VENC_HINT, 0); | ||
137 | venc_write(sd, VENC_VSPLS, 0); | ||
138 | venc_write(sd, VENC_VSTART, 0); | ||
139 | venc_write(sd, VENC_VVALID, 0); | ||
140 | venc_write(sd, VENC_VINT, 0); | ||
141 | venc_write(sd, VENC_YCCCTL, 0); | ||
142 | venc_write(sd, VENC_DACSEL, 0); | ||
143 | |||
144 | } else { | ||
145 | venc_write(sd, VENC_VMOD, 0); | ||
146 | /* disable VCLK output pin enable */ | ||
147 | venc_write(sd, VENC_VIDCTL, 0x141); | ||
148 | |||
149 | /* Disable output sync pins */ | ||
150 | venc_write(sd, VENC_SYNCCTL, 0); | ||
151 | |||
152 | /* Disable DCLOCK */ | ||
153 | venc_write(sd, VENC_DCLKCTL, 0); | ||
154 | venc_write(sd, VENC_DRGBX1, 0x0000057C); | ||
155 | |||
156 | /* Disable LCD output control (accepting default polarity) */ | ||
157 | venc_write(sd, VENC_LCDOUT, 0); | ||
158 | venc_write(sd, VENC_CMPNT, 0x100); | ||
159 | venc_write(sd, VENC_HSPLS, 0); | ||
160 | venc_write(sd, VENC_HINT, 0); | ||
161 | venc_write(sd, VENC_HSTART, 0); | ||
162 | venc_write(sd, VENC_HVALID, 0); | ||
163 | |||
164 | venc_write(sd, VENC_VSPLS, 0); | ||
165 | venc_write(sd, VENC_VINT, 0); | ||
166 | venc_write(sd, VENC_VSTART, 0); | ||
167 | venc_write(sd, VENC_VVALID, 0); | ||
168 | |||
169 | venc_write(sd, VENC_HSDLY, 0); | ||
170 | venc_write(sd, VENC_VSDLY, 0); | ||
171 | |||
172 | venc_write(sd, VENC_YCCCTL, 0); | ||
173 | venc_write(sd, VENC_VSTARTA, 0); | ||
174 | |||
175 | /* Set OSD clock and OSD Sync Adavance registers */ | ||
176 | venc_write(sd, VENC_OSDCLK0, 1); | ||
177 | venc_write(sd, VENC_OSDCLK1, 2); | ||
178 | } | ||
179 | } | ||
180 | |||
181 | /* | ||
182 | * setting NTSC mode | ||
183 | */ | ||
184 | static int venc_set_ntsc(struct v4l2_subdev *sd) | ||
185 | { | ||
186 | struct venc_state *venc = to_state(sd); | ||
187 | struct venc_platform_data *pdata = venc->pdata; | ||
188 | |||
189 | v4l2_dbg(debug, 2, sd, "venc_set_ntsc\n"); | ||
190 | |||
191 | /* Setup clock at VPSS & VENC for SD */ | ||
192 | vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1); | ||
193 | if (pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_525_60) < 0) | ||
194 | return -EINVAL; | ||
195 | |||
196 | venc_enabledigitaloutput(sd, 0); | ||
197 | |||
198 | /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ | ||
199 | venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); | ||
200 | /* Set REC656 Mode */ | ||
201 | venc_write(sd, VENC_YCCCTL, 0x1); | ||
202 | venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAFRQ); | ||
203 | venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAUPS); | ||
204 | |||
205 | venc_write(sd, VENC_VMOD, 0); | ||
206 | venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), | ||
207 | VENC_VMOD_VIE); | ||
208 | venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_VMD), VENC_VMOD_VMD); | ||
209 | venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_TVTYP_SHIFT), | ||
210 | VENC_VMOD_TVTYP); | ||
211 | venc_write(sd, VENC_DACTST, 0x0); | ||
212 | venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | /* | ||
218 | * setting PAL mode | ||
219 | */ | ||
220 | static int venc_set_pal(struct v4l2_subdev *sd) | ||
221 | { | ||
222 | struct venc_state *venc = to_state(sd); | ||
223 | |||
224 | v4l2_dbg(debug, 2, sd, "venc_set_pal\n"); | ||
225 | |||
226 | /* Setup clock at VPSS & VENC for SD */ | ||
227 | vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1); | ||
228 | if (venc->pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_625_50) < 0) | ||
229 | return -EINVAL; | ||
230 | |||
231 | venc_enabledigitaloutput(sd, 0); | ||
232 | |||
233 | /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ | ||
234 | venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); | ||
235 | /* Set REC656 Mode */ | ||
236 | venc_write(sd, VENC_YCCCTL, 0x1); | ||
237 | |||
238 | venc_modify(sd, VENC_SYNCCTL, 1 << VENC_SYNCCTL_OVD_SHIFT, | ||
239 | VENC_SYNCCTL_OVD); | ||
240 | venc_write(sd, VENC_VMOD, 0); | ||
241 | venc_modify(sd, VENC_VMOD, | ||
242 | (1 << VENC_VMOD_VIE_SHIFT), | ||
243 | VENC_VMOD_VIE); | ||
244 | venc_modify(sd, VENC_VMOD, | ||
245 | (0 << VENC_VMOD_VMD), VENC_VMOD_VMD); | ||
246 | venc_modify(sd, VENC_VMOD, | ||
247 | (1 << VENC_VMOD_TVTYP_SHIFT), | ||
248 | VENC_VMOD_TVTYP); | ||
249 | venc_write(sd, VENC_DACTST, 0x0); | ||
250 | venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | /* | ||
256 | * venc_set_480p59_94 | ||
257 | * | ||
258 | * This function configures the video encoder to EDTV(525p) component setting. | ||
259 | */ | ||
260 | static int venc_set_480p59_94(struct v4l2_subdev *sd) | ||
261 | { | ||
262 | struct venc_state *venc = to_state(sd); | ||
263 | struct venc_platform_data *pdata = venc->pdata; | ||
264 | |||
265 | v4l2_dbg(debug, 2, sd, "venc_set_480p59_94\n"); | ||
266 | |||
267 | /* Setup clock at VPSS & VENC for SD */ | ||
268 | if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_480P59_94) < 0) | ||
269 | return -EINVAL; | ||
270 | |||
271 | venc_enabledigitaloutput(sd, 0); | ||
272 | |||
273 | venc_write(sd, VENC_OSDCLK0, 0); | ||
274 | venc_write(sd, VENC_OSDCLK1, 1); | ||
275 | venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, | ||
276 | VENC_VDPRO_DAFRQ); | ||
277 | venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, | ||
278 | VENC_VDPRO_DAUPS); | ||
279 | venc_write(sd, VENC_VMOD, 0); | ||
280 | venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), | ||
281 | VENC_VMOD_VIE); | ||
282 | venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); | ||
283 | venc_modify(sd, VENC_VMOD, (HDTV_525P << VENC_VMOD_TVTYP_SHIFT), | ||
284 | VENC_VMOD_TVTYP); | ||
285 | venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 << | ||
286 | VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD); | ||
287 | |||
288 | venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); | ||
289 | |||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | /* | ||
294 | * venc_set_625p | ||
295 | * | ||
296 | * This function configures the video encoder to HDTV(625p) component setting | ||
297 | */ | ||
298 | static int venc_set_576p50(struct v4l2_subdev *sd) | ||
299 | { | ||
300 | struct venc_state *venc = to_state(sd); | ||
301 | struct venc_platform_data *pdata = venc->pdata; | ||
302 | |||
303 | v4l2_dbg(debug, 2, sd, "venc_set_576p50\n"); | ||
304 | |||
305 | /* Setup clock at VPSS & VENC for SD */ | ||
306 | if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_576P50) < 0) | ||
307 | return -EINVAL; | ||
308 | |||
309 | venc_enabledigitaloutput(sd, 0); | ||
310 | |||
311 | venc_write(sd, VENC_OSDCLK0, 0); | ||
312 | venc_write(sd, VENC_OSDCLK1, 1); | ||
313 | |||
314 | venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, | ||
315 | VENC_VDPRO_DAFRQ); | ||
316 | venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, | ||
317 | VENC_VDPRO_DAUPS); | ||
318 | |||
319 | venc_write(sd, VENC_VMOD, 0); | ||
320 | venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), | ||
321 | VENC_VMOD_VIE); | ||
322 | venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); | ||
323 | venc_modify(sd, VENC_VMOD, (HDTV_625P << VENC_VMOD_TVTYP_SHIFT), | ||
324 | VENC_VMOD_TVTYP); | ||
325 | |||
326 | venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 << | ||
327 | VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD); | ||
328 | venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); | ||
329 | |||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) | ||
334 | { | ||
335 | v4l2_dbg(debug, 1, sd, "venc_s_std_output\n"); | ||
336 | |||
337 | if (norm & V4L2_STD_525_60) | ||
338 | return venc_set_ntsc(sd); | ||
339 | else if (norm & V4L2_STD_625_50) | ||
340 | return venc_set_pal(sd); | ||
341 | |||
342 | return -EINVAL; | ||
343 | } | ||
344 | |||
345 | static int venc_s_dv_preset(struct v4l2_subdev *sd, | ||
346 | struct v4l2_dv_preset *dv_preset) | ||
347 | { | ||
348 | v4l2_dbg(debug, 1, sd, "venc_s_dv_preset\n"); | ||
349 | |||
350 | if (dv_preset->preset == V4L2_DV_576P50) | ||
351 | return venc_set_576p50(sd); | ||
352 | else if (dv_preset->preset == V4L2_DV_480P59_94) | ||
353 | return venc_set_480p59_94(sd); | ||
354 | |||
355 | return -EINVAL; | ||
356 | } | ||
357 | |||
358 | static int venc_s_routing(struct v4l2_subdev *sd, u32 input, u32 output, | ||
359 | u32 config) | ||
360 | { | ||
361 | struct venc_state *venc = to_state(sd); | ||
362 | int ret; | ||
363 | |||
364 | v4l2_dbg(debug, 1, sd, "venc_s_routing\n"); | ||
365 | |||
366 | ret = venc_set_dac(sd, output); | ||
367 | if (!ret) | ||
368 | venc->output = output; | ||
369 | |||
370 | return ret; | ||
371 | } | ||
372 | |||
373 | static long venc_ioctl(struct v4l2_subdev *sd, | ||
374 | unsigned int cmd, | ||
375 | void *arg) | ||
376 | { | ||
377 | u32 val; | ||
378 | |||
379 | switch (cmd) { | ||
380 | case VENC_GET_FLD: | ||
381 | val = venc_read(sd, VENC_VSTAT); | ||
382 | *((int *)arg) = ((val & VENC_VSTAT_FIDST) == | ||
383 | VENC_VSTAT_FIDST); | ||
384 | break; | ||
385 | default: | ||
386 | v4l2_err(sd, "Wrong IOCTL cmd\n"); | ||
387 | break; | ||
388 | } | ||
389 | |||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | static const struct v4l2_subdev_core_ops venc_core_ops = { | ||
394 | .ioctl = venc_ioctl, | ||
395 | }; | ||
396 | |||
397 | static const struct v4l2_subdev_video_ops venc_video_ops = { | ||
398 | .s_routing = venc_s_routing, | ||
399 | .s_std_output = venc_s_std_output, | ||
400 | .s_dv_preset = venc_s_dv_preset, | ||
401 | }; | ||
402 | |||
403 | static const struct v4l2_subdev_ops venc_ops = { | ||
404 | .core = &venc_core_ops, | ||
405 | .video = &venc_video_ops, | ||
406 | }; | ||
407 | |||
408 | static int venc_initialize(struct v4l2_subdev *sd) | ||
409 | { | ||
410 | struct venc_state *venc = to_state(sd); | ||
411 | int ret; | ||
412 | |||
413 | /* Set default to output to composite and std to NTSC */ | ||
414 | venc->output = 0; | ||
415 | venc->std = V4L2_STD_525_60; | ||
416 | |||
417 | ret = venc_s_routing(sd, 0, venc->output, 0); | ||
418 | if (ret < 0) { | ||
419 | v4l2_err(sd, "Error setting output during init\n"); | ||
420 | return -EINVAL; | ||
421 | } | ||
422 | |||
423 | ret = venc_s_std_output(sd, venc->std); | ||
424 | if (ret < 0) { | ||
425 | v4l2_err(sd, "Error setting std during init\n"); | ||
426 | return -EINVAL; | ||
427 | } | ||
428 | |||
429 | return ret; | ||
430 | } | ||
431 | |||
432 | static int venc_device_get(struct device *dev, void *data) | ||
433 | { | ||
434 | struct platform_device *pdev = to_platform_device(dev); | ||
435 | struct venc_state **venc = data; | ||
436 | |||
437 | if (strcmp(MODULE_NAME, pdev->name) == 0) | ||
438 | *venc = platform_get_drvdata(pdev); | ||
439 | |||
440 | return 0; | ||
441 | } | ||
442 | |||
443 | struct v4l2_subdev *venc_sub_dev_init(struct v4l2_device *v4l2_dev, | ||
444 | const char *venc_name) | ||
445 | { | ||
446 | struct venc_state *venc; | ||
447 | int err; | ||
448 | |||
449 | err = bus_for_each_dev(&platform_bus_type, NULL, &venc, | ||
450 | venc_device_get); | ||
451 | if (venc == NULL) | ||
452 | return NULL; | ||
453 | |||
454 | v4l2_subdev_init(&venc->sd, &venc_ops); | ||
455 | |||
456 | strcpy(venc->sd.name, venc_name); | ||
457 | if (v4l2_device_register_subdev(v4l2_dev, &venc->sd) < 0) { | ||
458 | v4l2_err(v4l2_dev, | ||
459 | "vpbe unable to register venc sub device\n"); | ||
460 | return NULL; | ||
461 | } | ||
462 | if (venc_initialize(&venc->sd)) { | ||
463 | v4l2_err(v4l2_dev, | ||
464 | "vpbe venc initialization failed\n"); | ||
465 | return NULL; | ||
466 | } | ||
467 | |||
468 | return &venc->sd; | ||
469 | } | ||
470 | EXPORT_SYMBOL(venc_sub_dev_init); | ||
471 | |||
472 | static int venc_probe(struct platform_device *pdev) | ||
473 | { | ||
474 | struct venc_state *venc; | ||
475 | struct resource *res; | ||
476 | int ret; | ||
477 | |||
478 | venc = kzalloc(sizeof(struct venc_state), GFP_KERNEL); | ||
479 | if (venc == NULL) | ||
480 | return -ENOMEM; | ||
481 | |||
482 | venc->pdev = &pdev->dev; | ||
483 | venc->pdata = pdev->dev.platform_data; | ||
484 | if (NULL == venc->pdata) { | ||
485 | dev_err(venc->pdev, "Unable to get platform data for" | ||
486 | " VENC sub device"); | ||
487 | ret = -ENOENT; | ||
488 | goto free_mem; | ||
489 | } | ||
490 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
491 | if (!res) { | ||
492 | dev_err(venc->pdev, | ||
493 | "Unable to get VENC register address map\n"); | ||
494 | ret = -ENODEV; | ||
495 | goto free_mem; | ||
496 | } | ||
497 | |||
498 | if (!request_mem_region(res->start, resource_size(res), "venc")) { | ||
499 | dev_err(venc->pdev, "Unable to reserve VENC MMIO region\n"); | ||
500 | ret = -ENODEV; | ||
501 | goto free_mem; | ||
502 | } | ||
503 | |||
504 | venc->venc_base = ioremap_nocache(res->start, resource_size(res)); | ||
505 | if (!venc->venc_base) { | ||
506 | dev_err(venc->pdev, "Unable to map VENC IO space\n"); | ||
507 | ret = -ENODEV; | ||
508 | goto release_venc_mem_region; | ||
509 | } | ||
510 | |||
511 | spin_lock_init(&venc->lock); | ||
512 | platform_set_drvdata(pdev, venc); | ||
513 | dev_notice(venc->pdev, "VENC sub device probe success\n"); | ||
514 | return 0; | ||
515 | |||
516 | release_venc_mem_region: | ||
517 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
518 | release_mem_region(res->start, resource_size(res)); | ||
519 | free_mem: | ||
520 | kfree(venc); | ||
521 | return ret; | ||
522 | } | ||
523 | |||
524 | static int venc_remove(struct platform_device *pdev) | ||
525 | { | ||
526 | struct venc_state *venc = platform_get_drvdata(pdev); | ||
527 | struct resource *res; | ||
528 | |||
529 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
530 | iounmap((void *)venc->venc_base); | ||
531 | release_mem_region(res->start, resource_size(res)); | ||
532 | kfree(venc); | ||
533 | |||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | static struct platform_driver venc_driver = { | ||
538 | .probe = venc_probe, | ||
539 | .remove = venc_remove, | ||
540 | .driver = { | ||
541 | .name = MODULE_NAME, | ||
542 | .owner = THIS_MODULE, | ||
543 | }, | ||
544 | }; | ||
545 | |||
546 | static int venc_init(void) | ||
547 | { | ||
548 | if (platform_driver_register(&venc_driver)) { | ||
549 | printk(KERN_ERR "Unable to register venc driver\n"); | ||
550 | return -ENODEV; | ||
551 | } | ||
552 | return 0; | ||
553 | } | ||
554 | |||
555 | static void venc_exit(void) | ||
556 | { | ||
557 | platform_driver_unregister(&venc_driver); | ||
558 | return; | ||
559 | } | ||
560 | |||
561 | module_init(venc_init); | ||
562 | module_exit(venc_exit); | ||
563 | |||
564 | MODULE_LICENSE("GPL"); | ||
565 | MODULE_DESCRIPTION("VPBE VENC Driver"); | ||
566 | MODULE_AUTHOR("Texas Instruments"); | ||