diff options
Diffstat (limited to 'drivers/media/video/davinci/vpbe.c')
-rw-r--r-- | drivers/media/video/davinci/vpbe.c | 886 |
1 files changed, 0 insertions, 886 deletions
diff --git a/drivers/media/video/davinci/vpbe.c b/drivers/media/video/davinci/vpbe.c deleted file mode 100644 index c4a82a1a8a97..000000000000 --- a/drivers/media/video/davinci/vpbe.c +++ /dev/null | |||
@@ -1,886 +0,0 @@ | |||
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/kernel.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/fs.h> | ||
22 | #include <linux/string.h> | ||
23 | #include <linux/wait.h> | ||
24 | #include <linux/time.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/clk.h> | ||
29 | #include <linux/err.h> | ||
30 | |||
31 | #include <media/v4l2-device.h> | ||
32 | #include <media/davinci/vpbe_types.h> | ||
33 | #include <media/davinci/vpbe.h> | ||
34 | #include <media/davinci/vpss.h> | ||
35 | #include <media/davinci/vpbe_venc.h> | ||
36 | |||
37 | #define VPBE_DEFAULT_OUTPUT "Composite" | ||
38 | #define VPBE_DEFAULT_MODE "ntsc" | ||
39 | |||
40 | static char *def_output = VPBE_DEFAULT_OUTPUT; | ||
41 | static char *def_mode = VPBE_DEFAULT_MODE; | ||
42 | static int debug; | ||
43 | |||
44 | module_param(def_output, charp, S_IRUGO); | ||
45 | module_param(def_mode, charp, S_IRUGO); | ||
46 | module_param(debug, int, 0644); | ||
47 | |||
48 | MODULE_PARM_DESC(def_output, "vpbe output name (default:Composite)"); | ||
49 | MODULE_PARM_DESC(def_mode, "vpbe output mode name (default:ntsc"); | ||
50 | MODULE_PARM_DESC(debug, "Debug level 0-1"); | ||
51 | |||
52 | MODULE_DESCRIPTION("TI DMXXX VPBE Display controller"); | ||
53 | MODULE_LICENSE("GPL"); | ||
54 | MODULE_AUTHOR("Texas Instruments"); | ||
55 | |||
56 | /** | ||
57 | * vpbe_current_encoder_info - Get config info for current encoder | ||
58 | * @vpbe_dev - vpbe device ptr | ||
59 | * | ||
60 | * Return ptr to current encoder config info | ||
61 | */ | ||
62 | static struct encoder_config_info* | ||
63 | vpbe_current_encoder_info(struct vpbe_device *vpbe_dev) | ||
64 | { | ||
65 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
66 | int index = vpbe_dev->current_sd_index; | ||
67 | |||
68 | return ((index == 0) ? &cfg->venc : | ||
69 | &cfg->ext_encoders[index-1]); | ||
70 | } | ||
71 | |||
72 | /** | ||
73 | * vpbe_find_encoder_sd_index - Given a name find encoder sd index | ||
74 | * | ||
75 | * @vpbe_config - ptr to vpbe cfg | ||
76 | * @output_index - index used by application | ||
77 | * | ||
78 | * Return sd index of the encoder | ||
79 | */ | ||
80 | static int vpbe_find_encoder_sd_index(struct vpbe_config *cfg, | ||
81 | int index) | ||
82 | { | ||
83 | char *encoder_name = cfg->outputs[index].subdev_name; | ||
84 | int i; | ||
85 | |||
86 | /* Venc is always first */ | ||
87 | if (!strcmp(encoder_name, cfg->venc.module_name)) | ||
88 | return 0; | ||
89 | |||
90 | for (i = 0; i < cfg->num_ext_encoders; i++) { | ||
91 | if (!strcmp(encoder_name, | ||
92 | cfg->ext_encoders[i].module_name)) | ||
93 | return i+1; | ||
94 | } | ||
95 | |||
96 | return -EINVAL; | ||
97 | } | ||
98 | |||
99 | /** | ||
100 | * vpbe_g_cropcap - Get crop capabilities of the display | ||
101 | * @vpbe_dev - vpbe device ptr | ||
102 | * @cropcap - cropcap is a ptr to struct v4l2_cropcap | ||
103 | * | ||
104 | * Update the crop capabilities in crop cap for current | ||
105 | * mode | ||
106 | */ | ||
107 | static int vpbe_g_cropcap(struct vpbe_device *vpbe_dev, | ||
108 | struct v4l2_cropcap *cropcap) | ||
109 | { | ||
110 | if (NULL == cropcap) | ||
111 | return -EINVAL; | ||
112 | cropcap->bounds.left = 0; | ||
113 | cropcap->bounds.top = 0; | ||
114 | cropcap->bounds.width = vpbe_dev->current_timings.xres; | ||
115 | cropcap->bounds.height = vpbe_dev->current_timings.yres; | ||
116 | cropcap->defrect = cropcap->bounds; | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | /** | ||
122 | * vpbe_enum_outputs - enumerate outputs | ||
123 | * @vpbe_dev - vpbe device ptr | ||
124 | * @output - ptr to v4l2_output structure | ||
125 | * | ||
126 | * Enumerates the outputs available at the vpbe display | ||
127 | * returns the status, -EINVAL if end of output list | ||
128 | */ | ||
129 | static int vpbe_enum_outputs(struct vpbe_device *vpbe_dev, | ||
130 | struct v4l2_output *output) | ||
131 | { | ||
132 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
133 | int temp_index = output->index; | ||
134 | |||
135 | if (temp_index >= cfg->num_outputs) | ||
136 | return -EINVAL; | ||
137 | |||
138 | *output = cfg->outputs[temp_index].output; | ||
139 | output->index = temp_index; | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int vpbe_get_mode_info(struct vpbe_device *vpbe_dev, char *mode, | ||
145 | int output_index) | ||
146 | { | ||
147 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
148 | struct vpbe_enc_mode_info var; | ||
149 | int curr_output = output_index; | ||
150 | int i; | ||
151 | |||
152 | if (NULL == mode) | ||
153 | return -EINVAL; | ||
154 | |||
155 | for (i = 0; i < cfg->outputs[curr_output].num_modes; i++) { | ||
156 | var = cfg->outputs[curr_output].modes[i]; | ||
157 | if (!strcmp(mode, var.name)) { | ||
158 | vpbe_dev->current_timings = var; | ||
159 | return 0; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | return -EINVAL; | ||
164 | } | ||
165 | |||
166 | static int vpbe_get_current_mode_info(struct vpbe_device *vpbe_dev, | ||
167 | struct vpbe_enc_mode_info *mode_info) | ||
168 | { | ||
169 | if (NULL == mode_info) | ||
170 | return -EINVAL; | ||
171 | |||
172 | *mode_info = vpbe_dev->current_timings; | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static int vpbe_get_dv_preset_info(struct vpbe_device *vpbe_dev, | ||
178 | unsigned int dv_preset) | ||
179 | { | ||
180 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
181 | struct vpbe_enc_mode_info var; | ||
182 | int curr_output = vpbe_dev->current_out_index; | ||
183 | int i; | ||
184 | |||
185 | for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { | ||
186 | var = cfg->outputs[curr_output].modes[i]; | ||
187 | if ((var.timings_type & VPBE_ENC_DV_PRESET) && | ||
188 | (var.timings.dv_preset == dv_preset)) { | ||
189 | vpbe_dev->current_timings = var; | ||
190 | return 0; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | return -EINVAL; | ||
195 | } | ||
196 | |||
197 | /* Get std by std id */ | ||
198 | static int vpbe_get_std_info(struct vpbe_device *vpbe_dev, | ||
199 | v4l2_std_id std_id) | ||
200 | { | ||
201 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
202 | struct vpbe_enc_mode_info var; | ||
203 | int curr_output = vpbe_dev->current_out_index; | ||
204 | int i; | ||
205 | |||
206 | for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { | ||
207 | var = cfg->outputs[curr_output].modes[i]; | ||
208 | if ((var.timings_type & VPBE_ENC_STD) && | ||
209 | (var.timings.std_id & std_id)) { | ||
210 | vpbe_dev->current_timings = var; | ||
211 | return 0; | ||
212 | } | ||
213 | } | ||
214 | |||
215 | return -EINVAL; | ||
216 | } | ||
217 | |||
218 | static int vpbe_get_std_info_by_name(struct vpbe_device *vpbe_dev, | ||
219 | char *std_name) | ||
220 | { | ||
221 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
222 | struct vpbe_enc_mode_info var; | ||
223 | int curr_output = vpbe_dev->current_out_index; | ||
224 | int i; | ||
225 | |||
226 | for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { | ||
227 | var = cfg->outputs[curr_output].modes[i]; | ||
228 | if (!strcmp(var.name, std_name)) { | ||
229 | vpbe_dev->current_timings = var; | ||
230 | return 0; | ||
231 | } | ||
232 | } | ||
233 | |||
234 | return -EINVAL; | ||
235 | } | ||
236 | |||
237 | /** | ||
238 | * vpbe_set_output - Set output | ||
239 | * @vpbe_dev - vpbe device ptr | ||
240 | * @index - index of output | ||
241 | * | ||
242 | * Set vpbe output to the output specified by the index | ||
243 | */ | ||
244 | static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index) | ||
245 | { | ||
246 | struct encoder_config_info *curr_enc_info = | ||
247 | vpbe_current_encoder_info(vpbe_dev); | ||
248 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
249 | struct venc_platform_data *venc_device = vpbe_dev->venc_device; | ||
250 | enum v4l2_mbus_pixelcode if_params; | ||
251 | int enc_out_index; | ||
252 | int sd_index; | ||
253 | int ret = 0; | ||
254 | |||
255 | if (index >= cfg->num_outputs) | ||
256 | return -EINVAL; | ||
257 | |||
258 | mutex_lock(&vpbe_dev->lock); | ||
259 | |||
260 | sd_index = vpbe_dev->current_sd_index; | ||
261 | enc_out_index = cfg->outputs[index].output.index; | ||
262 | /* | ||
263 | * Currently we switch the encoder based on output selected | ||
264 | * by the application. If media controller is implemented later | ||
265 | * there is will be an API added to setup_link between venc | ||
266 | * and external encoder. So in that case below comparison always | ||
267 | * match and encoder will not be switched. But if application | ||
268 | * chose not to use media controller, then this provides current | ||
269 | * way of switching encoder at the venc output. | ||
270 | */ | ||
271 | if (strcmp(curr_enc_info->module_name, | ||
272 | cfg->outputs[index].subdev_name)) { | ||
273 | /* Need to switch the encoder at the output */ | ||
274 | sd_index = vpbe_find_encoder_sd_index(cfg, index); | ||
275 | if (sd_index < 0) { | ||
276 | ret = -EINVAL; | ||
277 | goto out; | ||
278 | } | ||
279 | |||
280 | if_params = cfg->outputs[index].if_params; | ||
281 | venc_device->setup_if_config(if_params); | ||
282 | if (ret) | ||
283 | goto out; | ||
284 | } | ||
285 | |||
286 | /* Set output at the encoder */ | ||
287 | ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, | ||
288 | s_routing, 0, enc_out_index, 0); | ||
289 | if (ret) | ||
290 | goto out; | ||
291 | |||
292 | /* | ||
293 | * It is assumed that venc or extenal encoder will set a default | ||
294 | * mode in the sub device. For external encoder or LCD pannel output, | ||
295 | * we also need to set up the lcd port for the required mode. So setup | ||
296 | * the lcd port for the default mode that is configured in the board | ||
297 | * arch/arm/mach-davinci/board-dm355-evm.setup file for the external | ||
298 | * encoder. | ||
299 | */ | ||
300 | ret = vpbe_get_mode_info(vpbe_dev, | ||
301 | cfg->outputs[index].default_mode, index); | ||
302 | if (!ret) { | ||
303 | struct osd_state *osd_device = vpbe_dev->osd_device; | ||
304 | |||
305 | osd_device->ops.set_left_margin(osd_device, | ||
306 | vpbe_dev->current_timings.left_margin); | ||
307 | osd_device->ops.set_top_margin(osd_device, | ||
308 | vpbe_dev->current_timings.upper_margin); | ||
309 | vpbe_dev->current_sd_index = sd_index; | ||
310 | vpbe_dev->current_out_index = index; | ||
311 | } | ||
312 | out: | ||
313 | mutex_unlock(&vpbe_dev->lock); | ||
314 | return ret; | ||
315 | } | ||
316 | |||
317 | static int vpbe_set_default_output(struct vpbe_device *vpbe_dev) | ||
318 | { | ||
319 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
320 | int ret = 0; | ||
321 | int i; | ||
322 | |||
323 | for (i = 0; i < cfg->num_outputs; i++) { | ||
324 | if (!strcmp(def_output, | ||
325 | cfg->outputs[i].output.name)) { | ||
326 | ret = vpbe_set_output(vpbe_dev, i); | ||
327 | if (!ret) | ||
328 | vpbe_dev->current_out_index = i; | ||
329 | return ret; | ||
330 | } | ||
331 | } | ||
332 | return ret; | ||
333 | } | ||
334 | |||
335 | /** | ||
336 | * vpbe_get_output - Get output | ||
337 | * @vpbe_dev - vpbe device ptr | ||
338 | * | ||
339 | * return current vpbe output to the the index | ||
340 | */ | ||
341 | static unsigned int vpbe_get_output(struct vpbe_device *vpbe_dev) | ||
342 | { | ||
343 | return vpbe_dev->current_out_index; | ||
344 | } | ||
345 | |||
346 | /** | ||
347 | * vpbe_s_dv_preset - Set the given preset timings in the encoder | ||
348 | * | ||
349 | * Sets the preset if supported by the current encoder. Return the status. | ||
350 | * 0 - success & -EINVAL on error | ||
351 | */ | ||
352 | static int vpbe_s_dv_preset(struct vpbe_device *vpbe_dev, | ||
353 | struct v4l2_dv_preset *dv_preset) | ||
354 | { | ||
355 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
356 | int out_index = vpbe_dev->current_out_index; | ||
357 | int sd_index = vpbe_dev->current_sd_index; | ||
358 | int ret; | ||
359 | |||
360 | |||
361 | if (!(cfg->outputs[out_index].output.capabilities & | ||
362 | V4L2_OUT_CAP_PRESETS)) | ||
363 | return -EINVAL; | ||
364 | |||
365 | ret = vpbe_get_dv_preset_info(vpbe_dev, dv_preset->preset); | ||
366 | |||
367 | if (ret) | ||
368 | return ret; | ||
369 | |||
370 | mutex_lock(&vpbe_dev->lock); | ||
371 | |||
372 | |||
373 | ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, | ||
374 | s_dv_preset, dv_preset); | ||
375 | if (!ret && (vpbe_dev->amp != NULL)) { | ||
376 | /* Call amplifier subdevice */ | ||
377 | ret = v4l2_subdev_call(vpbe_dev->amp, video, | ||
378 | s_dv_preset, dv_preset); | ||
379 | } | ||
380 | /* set the lcd controller output for the given mode */ | ||
381 | if (!ret) { | ||
382 | struct osd_state *osd_device = vpbe_dev->osd_device; | ||
383 | |||
384 | osd_device->ops.set_left_margin(osd_device, | ||
385 | vpbe_dev->current_timings.left_margin); | ||
386 | osd_device->ops.set_top_margin(osd_device, | ||
387 | vpbe_dev->current_timings.upper_margin); | ||
388 | } | ||
389 | mutex_unlock(&vpbe_dev->lock); | ||
390 | |||
391 | return ret; | ||
392 | } | ||
393 | |||
394 | /** | ||
395 | * vpbe_g_dv_preset - Get the preset in the current encoder | ||
396 | * | ||
397 | * Get the preset in the current encoder. Return the status. 0 - success | ||
398 | * -EINVAL on error | ||
399 | */ | ||
400 | static int vpbe_g_dv_preset(struct vpbe_device *vpbe_dev, | ||
401 | struct v4l2_dv_preset *dv_preset) | ||
402 | { | ||
403 | if (vpbe_dev->current_timings.timings_type & | ||
404 | VPBE_ENC_DV_PRESET) { | ||
405 | dv_preset->preset = vpbe_dev->current_timings.timings.dv_preset; | ||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | return -EINVAL; | ||
410 | } | ||
411 | |||
412 | /** | ||
413 | * vpbe_enum_dv_presets - Enumerate the dv presets in the current encoder | ||
414 | * | ||
415 | * Get the preset in the current encoder. Return the status. 0 - success | ||
416 | * -EINVAL on error | ||
417 | */ | ||
418 | static int vpbe_enum_dv_presets(struct vpbe_device *vpbe_dev, | ||
419 | struct v4l2_dv_enum_preset *preset_info) | ||
420 | { | ||
421 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
422 | int out_index = vpbe_dev->current_out_index; | ||
423 | struct vpbe_output *output = &cfg->outputs[out_index]; | ||
424 | int j = 0; | ||
425 | int i; | ||
426 | |||
427 | if (!(output->output.capabilities & V4L2_OUT_CAP_PRESETS)) | ||
428 | return -EINVAL; | ||
429 | |||
430 | for (i = 0; i < output->num_modes; i++) { | ||
431 | if (output->modes[i].timings_type == VPBE_ENC_DV_PRESET) { | ||
432 | if (j == preset_info->index) | ||
433 | break; | ||
434 | j++; | ||
435 | } | ||
436 | } | ||
437 | |||
438 | if (i == output->num_modes) | ||
439 | return -EINVAL; | ||
440 | |||
441 | return v4l_fill_dv_preset_info(output->modes[i].timings.dv_preset, | ||
442 | preset_info); | ||
443 | } | ||
444 | |||
445 | /** | ||
446 | * vpbe_s_std - Set the given standard in the encoder | ||
447 | * | ||
448 | * Sets the standard if supported by the current encoder. Return the status. | ||
449 | * 0 - success & -EINVAL on error | ||
450 | */ | ||
451 | static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) | ||
452 | { | ||
453 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
454 | int out_index = vpbe_dev->current_out_index; | ||
455 | int sd_index = vpbe_dev->current_sd_index; | ||
456 | int ret; | ||
457 | |||
458 | if (!(cfg->outputs[out_index].output.capabilities & | ||
459 | V4L2_OUT_CAP_STD)) | ||
460 | return -EINVAL; | ||
461 | |||
462 | ret = vpbe_get_std_info(vpbe_dev, *std_id); | ||
463 | if (ret) | ||
464 | return ret; | ||
465 | |||
466 | mutex_lock(&vpbe_dev->lock); | ||
467 | |||
468 | ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, | ||
469 | s_std_output, *std_id); | ||
470 | /* set the lcd controller output for the given mode */ | ||
471 | if (!ret) { | ||
472 | struct osd_state *osd_device = vpbe_dev->osd_device; | ||
473 | |||
474 | osd_device->ops.set_left_margin(osd_device, | ||
475 | vpbe_dev->current_timings.left_margin); | ||
476 | osd_device->ops.set_top_margin(osd_device, | ||
477 | vpbe_dev->current_timings.upper_margin); | ||
478 | } | ||
479 | mutex_unlock(&vpbe_dev->lock); | ||
480 | |||
481 | return ret; | ||
482 | } | ||
483 | |||
484 | /** | ||
485 | * vpbe_g_std - Get the standard in the current encoder | ||
486 | * | ||
487 | * Get the standard in the current encoder. Return the status. 0 - success | ||
488 | * -EINVAL on error | ||
489 | */ | ||
490 | static int vpbe_g_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) | ||
491 | { | ||
492 | struct vpbe_enc_mode_info cur_timings = vpbe_dev->current_timings; | ||
493 | |||
494 | if (cur_timings.timings_type & VPBE_ENC_STD) { | ||
495 | *std_id = cur_timings.timings.std_id; | ||
496 | return 0; | ||
497 | } | ||
498 | |||
499 | return -EINVAL; | ||
500 | } | ||
501 | |||
502 | /** | ||
503 | * vpbe_set_mode - Set mode in the current encoder using mode info | ||
504 | * | ||
505 | * Use the mode string to decide what timings to set in the encoder | ||
506 | * This is typically useful when fbset command is used to change the current | ||
507 | * timings by specifying a string to indicate the timings. | ||
508 | */ | ||
509 | static int vpbe_set_mode(struct vpbe_device *vpbe_dev, | ||
510 | struct vpbe_enc_mode_info *mode_info) | ||
511 | { | ||
512 | struct vpbe_enc_mode_info *preset_mode = NULL; | ||
513 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
514 | struct v4l2_dv_preset dv_preset; | ||
515 | struct osd_state *osd_device; | ||
516 | int out_index = vpbe_dev->current_out_index; | ||
517 | int ret = 0; | ||
518 | int i; | ||
519 | |||
520 | if ((NULL == mode_info) || (NULL == mode_info->name)) | ||
521 | return -EINVAL; | ||
522 | |||
523 | for (i = 0; i < cfg->outputs[out_index].num_modes; i++) { | ||
524 | if (!strcmp(mode_info->name, | ||
525 | cfg->outputs[out_index].modes[i].name)) { | ||
526 | preset_mode = &cfg->outputs[out_index].modes[i]; | ||
527 | /* | ||
528 | * it may be one of the 3 timings type. Check and | ||
529 | * invoke right API | ||
530 | */ | ||
531 | if (preset_mode->timings_type & VPBE_ENC_STD) | ||
532 | return vpbe_s_std(vpbe_dev, | ||
533 | &preset_mode->timings.std_id); | ||
534 | if (preset_mode->timings_type & VPBE_ENC_DV_PRESET) { | ||
535 | dv_preset.preset = | ||
536 | preset_mode->timings.dv_preset; | ||
537 | return vpbe_s_dv_preset(vpbe_dev, &dv_preset); | ||
538 | } | ||
539 | } | ||
540 | } | ||
541 | |||
542 | /* Only custom timing should reach here */ | ||
543 | if (preset_mode == NULL) | ||
544 | return -EINVAL; | ||
545 | |||
546 | mutex_lock(&vpbe_dev->lock); | ||
547 | |||
548 | osd_device = vpbe_dev->osd_device; | ||
549 | vpbe_dev->current_timings = *preset_mode; | ||
550 | osd_device->ops.set_left_margin(osd_device, | ||
551 | vpbe_dev->current_timings.left_margin); | ||
552 | osd_device->ops.set_top_margin(osd_device, | ||
553 | vpbe_dev->current_timings.upper_margin); | ||
554 | |||
555 | mutex_unlock(&vpbe_dev->lock); | ||
556 | |||
557 | return ret; | ||
558 | } | ||
559 | |||
560 | static int vpbe_set_default_mode(struct vpbe_device *vpbe_dev) | ||
561 | { | ||
562 | int ret; | ||
563 | |||
564 | ret = vpbe_get_std_info_by_name(vpbe_dev, def_mode); | ||
565 | if (ret) | ||
566 | return ret; | ||
567 | |||
568 | /* set the default mode in the encoder */ | ||
569 | return vpbe_set_mode(vpbe_dev, &vpbe_dev->current_timings); | ||
570 | } | ||
571 | |||
572 | static int platform_device_get(struct device *dev, void *data) | ||
573 | { | ||
574 | struct platform_device *pdev = to_platform_device(dev); | ||
575 | struct vpbe_device *vpbe_dev = data; | ||
576 | |||
577 | if (strcmp("vpbe-osd", pdev->name) == 0) | ||
578 | vpbe_dev->osd_device = platform_get_drvdata(pdev); | ||
579 | if (strcmp("vpbe-venc", pdev->name) == 0) | ||
580 | vpbe_dev->venc_device = dev_get_platdata(&pdev->dev); | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | /** | ||
586 | * vpbe_initialize() - Initialize the vpbe display controller | ||
587 | * @vpbe_dev - vpbe device ptr | ||
588 | * | ||
589 | * Master frame buffer device drivers calls this to initialize vpbe | ||
590 | * display controller. This will then registers v4l2 device and the sub | ||
591 | * devices and sets a current encoder sub device for display. v4l2 display | ||
592 | * device driver is the master and frame buffer display device driver is | ||
593 | * the slave. Frame buffer display driver checks the initialized during | ||
594 | * probe and exit if not initialized. Returns status. | ||
595 | */ | ||
596 | static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) | ||
597 | { | ||
598 | struct encoder_config_info *enc_info; | ||
599 | struct amp_config_info *amp_info; | ||
600 | struct v4l2_subdev **enc_subdev; | ||
601 | struct osd_state *osd_device; | ||
602 | struct i2c_adapter *i2c_adap; | ||
603 | int output_index; | ||
604 | int num_encoders; | ||
605 | int ret = 0; | ||
606 | int err; | ||
607 | int i; | ||
608 | |||
609 | /* | ||
610 | * v4l2 abd FBDev frame buffer devices will get the vpbe_dev pointer | ||
611 | * from the platform device by iteration of platform drivers and | ||
612 | * matching with device name | ||
613 | */ | ||
614 | if (NULL == vpbe_dev || NULL == dev) { | ||
615 | printk(KERN_ERR "Null device pointers.\n"); | ||
616 | return -ENODEV; | ||
617 | } | ||
618 | |||
619 | if (vpbe_dev->initialized) | ||
620 | return 0; | ||
621 | |||
622 | mutex_lock(&vpbe_dev->lock); | ||
623 | |||
624 | if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) { | ||
625 | /* We have dac clock available for platform */ | ||
626 | vpbe_dev->dac_clk = clk_get(vpbe_dev->pdev, "vpss_dac"); | ||
627 | if (IS_ERR(vpbe_dev->dac_clk)) { | ||
628 | ret = PTR_ERR(vpbe_dev->dac_clk); | ||
629 | goto vpbe_unlock; | ||
630 | } | ||
631 | if (clk_enable(vpbe_dev->dac_clk)) { | ||
632 | ret = -ENODEV; | ||
633 | goto vpbe_unlock; | ||
634 | } | ||
635 | } | ||
636 | |||
637 | /* first enable vpss clocks */ | ||
638 | vpss_enable_clock(VPSS_VPBE_CLOCK, 1); | ||
639 | |||
640 | /* First register a v4l2 device */ | ||
641 | ret = v4l2_device_register(dev, &vpbe_dev->v4l2_dev); | ||
642 | if (ret) { | ||
643 | v4l2_err(dev->driver, | ||
644 | "Unable to register v4l2 device.\n"); | ||
645 | goto vpbe_fail_clock; | ||
646 | } | ||
647 | v4l2_info(&vpbe_dev->v4l2_dev, "vpbe v4l2 device registered\n"); | ||
648 | |||
649 | err = bus_for_each_dev(&platform_bus_type, NULL, vpbe_dev, | ||
650 | platform_device_get); | ||
651 | if (err < 0) | ||
652 | return err; | ||
653 | |||
654 | vpbe_dev->venc = venc_sub_dev_init(&vpbe_dev->v4l2_dev, | ||
655 | vpbe_dev->cfg->venc.module_name); | ||
656 | /* register venc sub device */ | ||
657 | if (vpbe_dev->venc == NULL) { | ||
658 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
659 | "vpbe unable to init venc sub device\n"); | ||
660 | ret = -ENODEV; | ||
661 | goto vpbe_fail_v4l2_device; | ||
662 | } | ||
663 | /* initialize osd device */ | ||
664 | osd_device = vpbe_dev->osd_device; | ||
665 | |||
666 | if (NULL != osd_device->ops.initialize) { | ||
667 | err = osd_device->ops.initialize(osd_device); | ||
668 | if (err) { | ||
669 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
670 | "unable to initialize the OSD device"); | ||
671 | err = -ENOMEM; | ||
672 | goto vpbe_fail_v4l2_device; | ||
673 | } | ||
674 | } | ||
675 | |||
676 | /* | ||
677 | * Register any external encoders that are configured. At index 0 we | ||
678 | * store venc sd index. | ||
679 | */ | ||
680 | num_encoders = vpbe_dev->cfg->num_ext_encoders + 1; | ||
681 | vpbe_dev->encoders = kmalloc( | ||
682 | sizeof(struct v4l2_subdev *)*num_encoders, | ||
683 | GFP_KERNEL); | ||
684 | if (NULL == vpbe_dev->encoders) { | ||
685 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
686 | "unable to allocate memory for encoders sub devices"); | ||
687 | ret = -ENOMEM; | ||
688 | goto vpbe_fail_v4l2_device; | ||
689 | } | ||
690 | |||
691 | i2c_adap = i2c_get_adapter(vpbe_dev->cfg->i2c_adapter_id); | ||
692 | for (i = 0; i < (vpbe_dev->cfg->num_ext_encoders + 1); i++) { | ||
693 | if (i == 0) { | ||
694 | /* venc is at index 0 */ | ||
695 | enc_subdev = &vpbe_dev->encoders[i]; | ||
696 | *enc_subdev = vpbe_dev->venc; | ||
697 | continue; | ||
698 | } | ||
699 | enc_info = &vpbe_dev->cfg->ext_encoders[i]; | ||
700 | if (enc_info->is_i2c) { | ||
701 | enc_subdev = &vpbe_dev->encoders[i]; | ||
702 | *enc_subdev = v4l2_i2c_new_subdev_board( | ||
703 | &vpbe_dev->v4l2_dev, i2c_adap, | ||
704 | &enc_info->board_info, NULL); | ||
705 | if (*enc_subdev) | ||
706 | v4l2_info(&vpbe_dev->v4l2_dev, | ||
707 | "v4l2 sub device %s registered\n", | ||
708 | enc_info->module_name); | ||
709 | else { | ||
710 | v4l2_err(&vpbe_dev->v4l2_dev, "encoder %s" | ||
711 | " failed to register", | ||
712 | enc_info->module_name); | ||
713 | ret = -ENODEV; | ||
714 | goto vpbe_fail_sd_register; | ||
715 | } | ||
716 | } else | ||
717 | v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c encoders" | ||
718 | " currently not supported"); | ||
719 | } | ||
720 | /* Add amplifier subdevice for dm365 */ | ||
721 | if ((strcmp(vpbe_dev->cfg->module_name, "dm365-vpbe-display") == 0) && | ||
722 | vpbe_dev->cfg->amp != NULL) { | ||
723 | amp_info = vpbe_dev->cfg->amp; | ||
724 | if (amp_info->is_i2c) { | ||
725 | vpbe_dev->amp = v4l2_i2c_new_subdev_board( | ||
726 | &vpbe_dev->v4l2_dev, i2c_adap, | ||
727 | &_info->board_info, NULL); | ||
728 | if (!vpbe_dev->amp) { | ||
729 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
730 | "amplifier %s failed to register", | ||
731 | amp_info->module_name); | ||
732 | ret = -ENODEV; | ||
733 | goto vpbe_fail_amp_register; | ||
734 | } | ||
735 | v4l2_info(&vpbe_dev->v4l2_dev, | ||
736 | "v4l2 sub device %s registered\n", | ||
737 | amp_info->module_name); | ||
738 | } else { | ||
739 | vpbe_dev->amp = NULL; | ||
740 | v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c amplifiers" | ||
741 | " currently not supported"); | ||
742 | } | ||
743 | } else { | ||
744 | vpbe_dev->amp = NULL; | ||
745 | } | ||
746 | |||
747 | /* set the current encoder and output to that of venc by default */ | ||
748 | vpbe_dev->current_sd_index = 0; | ||
749 | vpbe_dev->current_out_index = 0; | ||
750 | output_index = 0; | ||
751 | |||
752 | mutex_unlock(&vpbe_dev->lock); | ||
753 | |||
754 | printk(KERN_NOTICE "Setting default output to %s\n", def_output); | ||
755 | ret = vpbe_set_default_output(vpbe_dev); | ||
756 | if (ret) { | ||
757 | v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default output %s", | ||
758 | def_output); | ||
759 | return ret; | ||
760 | } | ||
761 | |||
762 | printk(KERN_NOTICE "Setting default mode to %s\n", def_mode); | ||
763 | ret = vpbe_set_default_mode(vpbe_dev); | ||
764 | if (ret) { | ||
765 | v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default mode %s", | ||
766 | def_mode); | ||
767 | return ret; | ||
768 | } | ||
769 | vpbe_dev->initialized = 1; | ||
770 | /* TBD handling of bootargs for default output and mode */ | ||
771 | return 0; | ||
772 | |||
773 | vpbe_fail_amp_register: | ||
774 | kfree(vpbe_dev->amp); | ||
775 | vpbe_fail_sd_register: | ||
776 | kfree(vpbe_dev->encoders); | ||
777 | vpbe_fail_v4l2_device: | ||
778 | v4l2_device_unregister(&vpbe_dev->v4l2_dev); | ||
779 | vpbe_fail_clock: | ||
780 | if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) | ||
781 | clk_put(vpbe_dev->dac_clk); | ||
782 | vpbe_unlock: | ||
783 | mutex_unlock(&vpbe_dev->lock); | ||
784 | return ret; | ||
785 | } | ||
786 | |||
787 | /** | ||
788 | * vpbe_deinitialize() - de-initialize the vpbe display controller | ||
789 | * @dev - Master and slave device ptr | ||
790 | * | ||
791 | * vpbe_master and slave frame buffer devices calls this to de-initialize | ||
792 | * the display controller. It is called when master and slave device | ||
793 | * driver modules are removed and no longer requires the display controller. | ||
794 | */ | ||
795 | static void vpbe_deinitialize(struct device *dev, struct vpbe_device *vpbe_dev) | ||
796 | { | ||
797 | v4l2_device_unregister(&vpbe_dev->v4l2_dev); | ||
798 | if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) | ||
799 | clk_put(vpbe_dev->dac_clk); | ||
800 | |||
801 | kfree(vpbe_dev->amp); | ||
802 | kfree(vpbe_dev->encoders); | ||
803 | vpbe_dev->initialized = 0; | ||
804 | /* disable vpss clocks */ | ||
805 | vpss_enable_clock(VPSS_VPBE_CLOCK, 0); | ||
806 | } | ||
807 | |||
808 | static struct vpbe_device_ops vpbe_dev_ops = { | ||
809 | .g_cropcap = vpbe_g_cropcap, | ||
810 | .enum_outputs = vpbe_enum_outputs, | ||
811 | .set_output = vpbe_set_output, | ||
812 | .get_output = vpbe_get_output, | ||
813 | .s_dv_preset = vpbe_s_dv_preset, | ||
814 | .g_dv_preset = vpbe_g_dv_preset, | ||
815 | .enum_dv_presets = vpbe_enum_dv_presets, | ||
816 | .s_std = vpbe_s_std, | ||
817 | .g_std = vpbe_g_std, | ||
818 | .initialize = vpbe_initialize, | ||
819 | .deinitialize = vpbe_deinitialize, | ||
820 | .get_mode_info = vpbe_get_current_mode_info, | ||
821 | .set_mode = vpbe_set_mode, | ||
822 | }; | ||
823 | |||
824 | static __devinit int vpbe_probe(struct platform_device *pdev) | ||
825 | { | ||
826 | struct vpbe_device *vpbe_dev; | ||
827 | struct vpbe_config *cfg; | ||
828 | int ret = -EINVAL; | ||
829 | |||
830 | if (pdev->dev.platform_data == NULL) { | ||
831 | v4l2_err(pdev->dev.driver, "No platform data\n"); | ||
832 | return -ENODEV; | ||
833 | } | ||
834 | cfg = pdev->dev.platform_data; | ||
835 | |||
836 | if (!cfg->module_name[0] || | ||
837 | !cfg->osd.module_name[0] || | ||
838 | !cfg->venc.module_name[0]) { | ||
839 | v4l2_err(pdev->dev.driver, "vpbe display module names not" | ||
840 | " defined\n"); | ||
841 | return ret; | ||
842 | } | ||
843 | |||
844 | vpbe_dev = kzalloc(sizeof(*vpbe_dev), GFP_KERNEL); | ||
845 | if (vpbe_dev == NULL) { | ||
846 | v4l2_err(pdev->dev.driver, "Unable to allocate memory" | ||
847 | " for vpbe_device\n"); | ||
848 | return -ENOMEM; | ||
849 | } | ||
850 | vpbe_dev->cfg = cfg; | ||
851 | vpbe_dev->ops = vpbe_dev_ops; | ||
852 | vpbe_dev->pdev = &pdev->dev; | ||
853 | |||
854 | if (cfg->outputs->num_modes > 0) | ||
855 | vpbe_dev->current_timings = vpbe_dev->cfg->outputs[0].modes[0]; | ||
856 | else { | ||
857 | kfree(vpbe_dev); | ||
858 | return -ENODEV; | ||
859 | } | ||
860 | |||
861 | /* set the driver data in platform device */ | ||
862 | platform_set_drvdata(pdev, vpbe_dev); | ||
863 | mutex_init(&vpbe_dev->lock); | ||
864 | |||
865 | return 0; | ||
866 | } | ||
867 | |||
868 | static int vpbe_remove(struct platform_device *device) | ||
869 | { | ||
870 | struct vpbe_device *vpbe_dev = platform_get_drvdata(device); | ||
871 | |||
872 | kfree(vpbe_dev); | ||
873 | |||
874 | return 0; | ||
875 | } | ||
876 | |||
877 | static struct platform_driver vpbe_driver = { | ||
878 | .driver = { | ||
879 | .name = "vpbe_controller", | ||
880 | .owner = THIS_MODULE, | ||
881 | }, | ||
882 | .probe = vpbe_probe, | ||
883 | .remove = vpbe_remove, | ||
884 | }; | ||
885 | |||
886 | module_platform_driver(vpbe_driver); | ||