[media] media: use macros to check for V4L2 subdev entities
[deliverable/linux.git] / drivers / staging / media / omap4iss / iss.c
CommitLineData
59f0ad80
SA
1/*
2 * TI OMAP4 ISS V4L2 Driver
3 *
4 * Copyright (C) 2012, Texas Instruments
5 *
6 * Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
14#include <linux/clk.h>
15#include <linux/delay.h>
16#include <linux/device.h>
17#include <linux/dma-mapping.h>
18#include <linux/i2c.h>
19#include <linux/interrupt.h>
fefad2d5 20#include <linux/mfd/syscon.h>
59f0ad80
SA
21#include <linux/module.h>
22#include <linux/platform_device.h>
23#include <linux/slab.h>
24#include <linux/sched.h>
25#include <linux/vmalloc.h>
26
27#include <media/v4l2-common.h>
28#include <media/v4l2-device.h>
29#include <media/v4l2-ctrls.h>
30
31#include "iss.h"
32#include "iss_regs.h"
33
34#define ISS_PRINT_REGISTER(iss, name)\
35 dev_dbg(iss->dev, "###ISS " #name "=0x%08x\n", \
11abbfd3 36 iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_##name))
59f0ad80
SA
37
38static void iss_print_status(struct iss_device *iss)
39{
40 dev_dbg(iss->dev, "-------------ISS HL Register dump-------------\n");
41
42 ISS_PRINT_REGISTER(iss, HL_REVISION);
43 ISS_PRINT_REGISTER(iss, HL_SYSCONFIG);
ade1ec37
LP
44 ISS_PRINT_REGISTER(iss, HL_IRQSTATUS(5));
45 ISS_PRINT_REGISTER(iss, HL_IRQENABLE_SET(5));
46 ISS_PRINT_REGISTER(iss, HL_IRQENABLE_CLR(5));
59f0ad80
SA
47 ISS_PRINT_REGISTER(iss, CTRL);
48 ISS_PRINT_REGISTER(iss, CLKCTRL);
49 ISS_PRINT_REGISTER(iss, CLKSTAT);
50
51 dev_dbg(iss->dev, "-----------------------------------------------\n");
52}
53
54/*
55 * omap4iss_flush - Post pending L3 bus writes by doing a register readback
56 * @iss: OMAP4 ISS device
57 *
58 * In order to force posting of pending writes, we need to write and
59 * readback the same register, in this case the revision register.
60 *
61 * See this link for reference:
62 * http://www.mail-archive.com/linux-omap@vger.kernel.org/msg08149.html
63 */
64void omap4iss_flush(struct iss_device *iss)
65{
11abbfd3
LP
66 iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_HL_REVISION, 0);
67 iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_HL_REVISION);
59f0ad80
SA
68}
69
70/*
af15d025 71 * iss_isp_enable_interrupts - Enable ISS ISP interrupts.
59f0ad80
SA
72 * @iss: OMAP4 ISS device
73 */
af15d025 74static void omap4iss_isp_enable_interrupts(struct iss_device *iss)
59f0ad80 75{
af15d025
LP
76 static const u32 isp_irq = ISP5_IRQ_OCP_ERR |
77 ISP5_IRQ_RSZ_FIFO_IN_BLK_ERR |
78 ISP5_IRQ_RSZ_FIFO_OVF |
79 ISP5_IRQ_RSZ_INT_DMA |
80 ISP5_IRQ_ISIF_INT(0);
59f0ad80 81
af15d025
LP
82 /* Enable ISP interrupts */
83 iss_reg_write(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_IRQSTATUS(0), isp_irq);
84 iss_reg_write(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_IRQENABLE_SET(0),
85 isp_irq);
59f0ad80
SA
86}
87
88/*
af15d025 89 * iss_isp_disable_interrupts - Disable ISS interrupts.
59f0ad80
SA
90 * @iss: OMAP4 ISS device
91 */
af15d025 92static void omap4iss_isp_disable_interrupts(struct iss_device *iss)
59f0ad80 93{
af15d025 94 iss_reg_write(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_IRQENABLE_CLR(0), ~0);
59f0ad80
SA
95}
96
97/*
af15d025 98 * iss_enable_interrupts - Enable ISS interrupts.
59f0ad80
SA
99 * @iss: OMAP4 ISS device
100 */
af15d025 101static void iss_enable_interrupts(struct iss_device *iss)
59f0ad80 102{
af15d025
LP
103 static const u32 hl_irq = ISS_HL_IRQ_CSIA | ISS_HL_IRQ_CSIB
104 | ISS_HL_IRQ_ISP(0);
59f0ad80 105
af15d025
LP
106 /* Enable HL interrupts */
107 iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_HL_IRQSTATUS(5), hl_irq);
108 iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_HL_IRQENABLE_SET(5), hl_irq);
109
110 if (iss->regs[OMAP4_ISS_MEM_ISP_SYS1])
111 omap4iss_isp_enable_interrupts(iss);
59f0ad80
SA
112}
113
114/*
af15d025 115 * iss_disable_interrupts - Disable ISS interrupts.
59f0ad80
SA
116 * @iss: OMAP4 ISS device
117 */
af15d025 118static void iss_disable_interrupts(struct iss_device *iss)
59f0ad80 119{
af15d025
LP
120 if (iss->regs[OMAP4_ISS_MEM_ISP_SYS1])
121 omap4iss_isp_disable_interrupts(iss);
122
123 iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_HL_IRQENABLE_CLR(5), ~0);
59f0ad80
SA
124}
125
126int omap4iss_get_external_info(struct iss_pipeline *pipe,
127 struct media_link *link)
128{
129 struct iss_device *iss =
130 container_of(pipe, struct iss_video, pipe)->iss;
131 struct v4l2_subdev_format fmt;
ea72717e 132 struct v4l2_ctrl *ctrl;
59f0ad80
SA
133 int ret;
134
135 if (!pipe->external)
136 return 0;
137
138 if (pipe->external_rate)
139 return 0;
140
141 memset(&fmt, 0, sizeof(fmt));
142
143 fmt.pad = link->source->index;
144 fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
145 ret = v4l2_subdev_call(media_entity_to_v4l2_subdev(link->sink->entity),
146 pad, get_fmt, NULL, &fmt);
147 if (ret < 0)
148 return -EPIPE;
149
150 pipe->external_bpp = omap4iss_video_format_info(fmt.format.code)->bpp;
151
ea72717e
LP
152 ctrl = v4l2_ctrl_find(pipe->external->ctrl_handler,
153 V4L2_CID_PIXEL_RATE);
9058fc92 154 if (!ctrl) {
59f0ad80
SA
155 dev_warn(iss->dev, "no pixel rate control in subdev %s\n",
156 pipe->external->name);
ea72717e 157 return -EPIPE;
59f0ad80
SA
158 }
159
ea72717e 160 pipe->external_rate = v4l2_ctrl_g_ctrl_int64(ctrl);
59f0ad80
SA
161
162 return 0;
163}
164
165/*
166 * Configure the bridge. Valid inputs are
167 *
168 * IPIPEIF_INPUT_CSI2A: CSI2a receiver
169 * IPIPEIF_INPUT_CSI2B: CSI2b receiver
170 *
171 * The bridge and lane shifter are configured according to the selected input
172 * and the ISP platform data.
173 */
174void omap4iss_configure_bridge(struct iss_device *iss,
175 enum ipipeif_input_entity input)
176{
177 u32 issctrl_val;
178 u32 isp5ctrl_val;
179
11abbfd3 180 issctrl_val = iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_CTRL);
59f0ad80
SA
181 issctrl_val &= ~ISS_CTRL_INPUT_SEL_MASK;
182 issctrl_val &= ~ISS_CTRL_CLK_DIV_MASK;
183
11abbfd3 184 isp5ctrl_val = iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL);
59f0ad80
SA
185
186 switch (input) {
187 case IPIPEIF_INPUT_CSI2A:
188 issctrl_val |= ISS_CTRL_INPUT_SEL_CSI2A;
59f0ad80
SA
189 break;
190
191 case IPIPEIF_INPUT_CSI2B:
192 issctrl_val |= ISS_CTRL_INPUT_SEL_CSI2B;
59f0ad80
SA
193 break;
194
195 default:
196 return;
197 }
198
199 issctrl_val |= ISS_CTRL_SYNC_DETECT_VS_RAISING;
200
cce093ee
LP
201 isp5ctrl_val |= ISP5_CTRL_VD_PULSE_EXT | ISP5_CTRL_PSYNC_CLK_SEL |
202 ISP5_CTRL_SYNC_ENABLE;
59f0ad80 203
11abbfd3
LP
204 iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_CTRL, issctrl_val);
205 iss_reg_write(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL, isp5ctrl_val);
59f0ad80
SA
206}
207
d14cb130 208#ifdef ISS_ISR_DEBUG
380df42b 209static void iss_isr_dbg(struct iss_device *iss, u32 irqstatus)
59f0ad80 210{
5122f6a2
LP
211 static const char * const name[] = {
212 "ISP_0",
213 "ISP_1",
214 "ISP_2",
215 "ISP_3",
216 "CSIA",
217 "CSIB",
218 "CCP2_0",
219 "CCP2_1",
220 "CCP2_2",
221 "CCP2_3",
222 "CBUFF",
223 "BTE",
224 "SIMCOP_0",
225 "SIMCOP_1",
226 "SIMCOP_2",
227 "SIMCOP_3",
228 "CCP2_8",
229 "HS_VS",
230 "18",
231 "19",
232 "20",
233 "21",
234 "22",
235 "23",
236 "24",
237 "25",
238 "26",
239 "27",
240 "28",
241 "29",
242 "30",
243 "31",
59f0ad80 244 };
5122f6a2 245 unsigned int i;
59f0ad80
SA
246
247 dev_dbg(iss->dev, "ISS IRQ: ");
248
249 for (i = 0; i < ARRAY_SIZE(name); i++) {
250 if ((1 << i) & irqstatus)
251 pr_cont("%s ", name[i]);
252 }
253 pr_cont("\n");
254}
255
380df42b 256static void iss_isp_isr_dbg(struct iss_device *iss, u32 irqstatus)
5122f6a2
LP
257{
258 static const char * const name[] = {
259 "ISIF_0",
260 "ISIF_1",
261 "ISIF_2",
262 "ISIF_3",
263 "IPIPEREQ",
264 "IPIPELAST_PIX",
265 "IPIPEDMA",
266 "IPIPEBSC",
267 "IPIPEHST",
268 "IPIPEIF",
269 "AEW",
270 "AF",
271 "H3A",
272 "RSZ_REG",
273 "RSZ_LAST_PIX",
274 "RSZ_DMA",
275 "RSZ_CYC_RZA",
276 "RSZ_CYC_RZB",
277 "RSZ_FIFO_OVF",
278 "RSZ_FIFO_IN_BLK_ERR",
279 "20",
280 "21",
281 "RSZ_EOF0",
282 "RSZ_EOF1",
283 "H3A_EOF",
284 "IPIPE_EOF",
285 "26",
286 "IPIPE_DPC_INI",
287 "IPIPE_DPC_RNEW0",
288 "IPIPE_DPC_RNEW1",
289 "30",
290 "OCP_ERR",
291 };
292 unsigned int i;
293
294 dev_dbg(iss->dev, "ISP IRQ: ");
295
296 for (i = 0; i < ARRAY_SIZE(name); i++) {
297 if ((1 << i) & irqstatus)
298 pr_cont("%s ", name[i]);
299 }
300 pr_cont("\n");
301}
302#endif
303
59f0ad80
SA
304/*
305 * iss_isr - Interrupt Service Routine for ISS module.
306 * @irq: Not used currently.
307 * @_iss: Pointer to the OMAP4 ISS device
308 *
309 * Handles the corresponding callback if plugged in.
310 *
311 * Returns IRQ_HANDLED when IRQ was correctly handled, or IRQ_NONE when the
312 * IRQ wasn't handled.
313 */
314static irqreturn_t iss_isr(int irq, void *_iss)
315{
ade1ec37
LP
316 static const u32 ipipeif_events = ISP5_IRQ_IPIPEIF_IRQ |
317 ISP5_IRQ_ISIF_INT(0);
318 static const u32 resizer_events = ISP5_IRQ_RSZ_FIFO_IN_BLK_ERR |
59f0ad80
SA
319 ISP5_IRQ_RSZ_FIFO_OVF |
320 ISP5_IRQ_RSZ_INT_DMA;
321 struct iss_device *iss = _iss;
322 u32 irqstatus;
323
11abbfd3
LP
324 irqstatus = iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_HL_IRQSTATUS(5));
325 iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_HL_IRQSTATUS(5), irqstatus);
59f0ad80
SA
326
327 if (irqstatus & ISS_HL_IRQ_CSIA)
328 omap4iss_csi2_isr(&iss->csi2a);
329
330 if (irqstatus & ISS_HL_IRQ_CSIB)
331 omap4iss_csi2_isr(&iss->csi2b);
332
333 if (irqstatus & ISS_HL_IRQ_ISP(0)) {
11abbfd3
LP
334 u32 isp_irqstatus = iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1,
335 ISP5_IRQSTATUS(0));
336 iss_reg_write(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_IRQSTATUS(0),
337 isp_irqstatus);
59f0ad80
SA
338
339 if (isp_irqstatus & ISP5_IRQ_OCP_ERR)
340 dev_dbg(iss->dev, "ISP5 OCP Error!\n");
341
342 if (isp_irqstatus & ipipeif_events) {
343 omap4iss_ipipeif_isr(&iss->ipipeif,
344 isp_irqstatus & ipipeif_events);
345 }
346
347 if (isp_irqstatus & resizer_events)
348 omap4iss_resizer_isr(&iss->resizer,
349 isp_irqstatus & resizer_events);
5122f6a2 350
d14cb130 351#ifdef ISS_ISR_DEBUG
5122f6a2
LP
352 iss_isp_isr_dbg(iss, isp_irqstatus);
353#endif
59f0ad80
SA
354 }
355
356 omap4iss_flush(iss);
357
d14cb130 358#ifdef ISS_ISR_DEBUG
59f0ad80
SA
359 iss_isr_dbg(iss, irqstatus);
360#endif
361
362 return IRQ_HANDLED;
363}
364
365/* -----------------------------------------------------------------------------
366 * Pipeline power management
367 *
368 * Entities must be powered up when part of a pipeline that contains at least
369 * one open video device node.
370 *
371 * To achieve this use the entity use_count field to track the number of users.
372 * For entities corresponding to video device nodes the use_count field stores
373 * the users count of the node. For entities corresponding to subdevs the
374 * use_count field stores the total number of users of all video device nodes
375 * in the pipeline.
376 *
377 * The omap4iss_pipeline_pm_use() function must be called in the open() and
378 * close() handlers of video device nodes. It increments or decrements the use
379 * count of all subdev entities in the pipeline.
380 *
381 * To react to link management on powered pipelines, the link setup notification
382 * callback updates the use count of all entities in the source and sink sides
383 * of the link.
384 */
385
386/*
387 * iss_pipeline_pm_use_count - Count the number of users of a pipeline
388 * @entity: The entity
389 *
390 * Return the total number of users of all video device nodes in the pipeline.
391 */
392static int iss_pipeline_pm_use_count(struct media_entity *entity)
393{
394 struct media_entity_graph graph;
395 int use = 0;
396
397 media_entity_graph_walk_start(&graph, entity);
398
399 while ((entity = media_entity_graph_walk_next(&graph))) {
3efdf62c 400 if (is_media_entity_v4l2_io(entity))
59f0ad80
SA
401 use += entity->use_count;
402 }
403
404 return use;
405}
406
407/*
408 * iss_pipeline_pm_power_one - Apply power change to an entity
409 * @entity: The entity
410 * @change: Use count change
411 *
412 * Change the entity use count by @change. If the entity is a subdev update its
413 * power state by calling the core::s_power operation when the use count goes
414 * from 0 to != 0 or from != 0 to 0.
415 *
416 * Return 0 on success or a negative error code on failure.
417 */
418static int iss_pipeline_pm_power_one(struct media_entity *entity, int change)
419{
420 struct v4l2_subdev *subdev;
421
3efdf62c 422 subdev = is_media_entity_v4l2_subdev(entity)
59f0ad80
SA
423 ? media_entity_to_v4l2_subdev(entity) : NULL;
424
9058fc92 425 if (entity->use_count == 0 && change > 0 && subdev) {
59f0ad80
SA
426 int ret;
427
428 ret = v4l2_subdev_call(subdev, core, s_power, 1);
429 if (ret < 0 && ret != -ENOIOCTLCMD)
430 return ret;
431 }
432
433 entity->use_count += change;
434 WARN_ON(entity->use_count < 0);
435
9058fc92 436 if (entity->use_count == 0 && change < 0 && subdev)
59f0ad80
SA
437 v4l2_subdev_call(subdev, core, s_power, 0);
438
439 return 0;
440}
441
442/*
443 * iss_pipeline_pm_power - Apply power change to all entities in a pipeline
444 * @entity: The entity
445 * @change: Use count change
446 *
447 * Walk the pipeline to update the use count and the power state of all non-node
448 * entities.
449 *
450 * Return 0 on success or a negative error code on failure.
451 */
452static int iss_pipeline_pm_power(struct media_entity *entity, int change)
453{
454 struct media_entity_graph graph;
455 struct media_entity *first = entity;
456 int ret = 0;
457
458 if (!change)
459 return 0;
460
461 media_entity_graph_walk_start(&graph, entity);
462
463 while (!ret && (entity = media_entity_graph_walk_next(&graph)))
3efdf62c 464 if (is_media_entity_v4l2_subdev(entity))
59f0ad80
SA
465 ret = iss_pipeline_pm_power_one(entity, change);
466
467 if (!ret)
468 return 0;
469
470 media_entity_graph_walk_start(&graph, first);
471
01afde85
AG
472 while ((first = media_entity_graph_walk_next(&graph)) &&
473 first != entity)
3efdf62c 474 if (is_media_entity_v4l2_subdev(first))
59f0ad80
SA
475 iss_pipeline_pm_power_one(first, -change);
476
477 return ret;
478}
479
480/*
481 * omap4iss_pipeline_pm_use - Update the use count of an entity
482 * @entity: The entity
483 * @use: Use (1) or stop using (0) the entity
484 *
485 * Update the use count of all entities in the pipeline and power entities on or
486 * off accordingly.
487 *
488 * Return 0 on success or a negative error code on failure. Powering entities
489 * off is assumed to never fail. No failure can occur when the use parameter is
490 * set to 0.
491 */
492int omap4iss_pipeline_pm_use(struct media_entity *entity, int use)
493{
494 int change = use ? 1 : -1;
495 int ret;
496
d10c9894 497 mutex_lock(&entity->graph_obj.mdev->graph_mutex);
59f0ad80
SA
498
499 /* Apply use count to node. */
500 entity->use_count += change;
501 WARN_ON(entity->use_count < 0);
502
503 /* Apply power change to connected non-nodes. */
504 ret = iss_pipeline_pm_power(entity, change);
505 if (ret < 0)
506 entity->use_count -= change;
507
d10c9894 508 mutex_unlock(&entity->graph_obj.mdev->graph_mutex);
59f0ad80
SA
509
510 return ret;
511}
512
513/*
514 * iss_pipeline_link_notify - Link management notification callback
515 * @link: The link
516 * @flags: New link flags that will be applied
517 *
518 * React to link management on powered pipelines by updating the use count of
519 * all entities in the source and sink sides of the link. Entities are powered
520 * on or off accordingly.
521 *
522 * Return 0 on success or a negative error code on failure. Powering entities
523 * off is assumed to never fail. This function will not fail for disconnection
524 * events.
525 */
526static int iss_pipeline_link_notify(struct media_link *link, u32 flags,
527 unsigned int notification)
528{
529 struct media_entity *source = link->source->entity;
530 struct media_entity *sink = link->sink->entity;
531 int source_use = iss_pipeline_pm_use_count(source);
532 int sink_use = iss_pipeline_pm_use_count(sink);
533 int ret;
534
535 if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
536 !(link->flags & MEDIA_LNK_FL_ENABLED)) {
537 /* Powering off entities is assumed to never fail. */
538 iss_pipeline_pm_power(source, -sink_use);
539 iss_pipeline_pm_power(sink, -source_use);
540 return 0;
541 }
542
543 if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
b9e50a06 544 (flags & MEDIA_LNK_FL_ENABLED)) {
59f0ad80
SA
545 ret = iss_pipeline_pm_power(source, sink_use);
546 if (ret < 0)
547 return ret;
548
549 ret = iss_pipeline_pm_power(sink, source_use);
550 if (ret < 0)
551 iss_pipeline_pm_power(source, -sink_use);
552
553 return ret;
554 }
555
556 return 0;
557}
558
559/* -----------------------------------------------------------------------------
560 * Pipeline stream management
561 */
562
9587a3fc
LP
563/*
564 * iss_pipeline_disable - Disable streaming on a pipeline
565 * @pipe: ISS pipeline
566 * @until: entity at which to stop pipeline walk
567 *
568 * Walk the entities chain starting at the pipeline output video node and stop
569 * all modules in the chain. Wait synchronously for the modules to be stopped if
570 * necessary.
571 *
572 * If the until argument isn't NULL, stop the pipeline walk when reaching the
573 * until entity. This is used to disable a partially started pipeline due to a
574 * subdev start error.
575 */
576static int iss_pipeline_disable(struct iss_pipeline *pipe,
577 struct media_entity *until)
578{
579 struct iss_device *iss = pipe->output->iss;
580 struct media_entity *entity;
581 struct media_pad *pad;
582 struct v4l2_subdev *subdev;
583 int failure = 0;
584 int ret;
585
586 entity = &pipe->output->video.entity;
587 while (1) {
588 pad = &entity->pads[0];
589 if (!(pad->flags & MEDIA_PAD_FL_SINK))
590 break;
591
592 pad = media_entity_remote_pad(pad);
3efdf62c 593 if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
9587a3fc
LP
594 break;
595
596 entity = pad->entity;
597 if (entity == until)
598 break;
599
600 subdev = media_entity_to_v4l2_subdev(entity);
601 ret = v4l2_subdev_call(subdev, video, s_stream, 0);
602 if (ret < 0) {
cd1e11be
LP
603 dev_warn(iss->dev, "%s: module stop timeout.\n",
604 subdev->name);
9587a3fc
LP
605 /* If the entity failed to stopped, assume it has
606 * crashed. Mark it as such, the ISS will be reset when
607 * applications will release it.
608 */
1302d39c 609 iss->crashed |= 1U << media_entity_id(&subdev->entity);
9587a3fc
LP
610 failure = -ETIMEDOUT;
611 }
612 }
613
614 return failure;
615}
616
59f0ad80
SA
617/*
618 * iss_pipeline_enable - Enable streaming on a pipeline
619 * @pipe: ISS pipeline
620 * @mode: Stream mode (single shot or continuous)
621 *
622 * Walk the entities chain starting at the pipeline output video node and start
623 * all modules in the chain in the given mode.
624 *
625 * Return 0 if successful, or the return value of the failed video::s_stream
626 * operation otherwise.
627 */
628static int iss_pipeline_enable(struct iss_pipeline *pipe,
629 enum iss_pipeline_stream_state mode)
630{
f3632ba8 631 struct iss_device *iss = pipe->output->iss;
59f0ad80
SA
632 struct media_entity *entity;
633 struct media_pad *pad;
634 struct v4l2_subdev *subdev;
635 unsigned long flags;
636 int ret;
637
f3632ba8
LP
638 /* If one of the entities in the pipeline has crashed it will not work
639 * properly. Refuse to start streaming in that case. This check must be
640 * performed before the loop below to avoid starting entities if the
641 * pipeline won't start anyway (those entities would then likely fail to
642 * stop, making the problem worse).
643 */
644 if (pipe->entities & iss->crashed)
645 return -EIO;
646
59f0ad80
SA
647 spin_lock_irqsave(&pipe->lock, flags);
648 pipe->state &= ~(ISS_PIPELINE_IDLE_INPUT | ISS_PIPELINE_IDLE_OUTPUT);
649 spin_unlock_irqrestore(&pipe->lock, flags);
650
651 pipe->do_propagation = false;
652
653 entity = &pipe->output->video.entity;
654 while (1) {
655 pad = &entity->pads[0];
656 if (!(pad->flags & MEDIA_PAD_FL_SINK))
657 break;
658
659 pad = media_entity_remote_pad(pad);
3efdf62c 660 if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
59f0ad80
SA
661 break;
662
663 entity = pad->entity;
664 subdev = media_entity_to_v4l2_subdev(entity);
665
666 ret = v4l2_subdev_call(subdev, video, s_stream, mode);
9587a3fc
LP
667 if (ret < 0 && ret != -ENOIOCTLCMD) {
668 iss_pipeline_disable(pipe, entity);
59f0ad80 669 return ret;
9587a3fc 670 }
707acfc0
LP
671
672 if (subdev == &iss->csi2a.subdev ||
673 subdev == &iss->csi2b.subdev)
674 pipe->do_propagation = true;
59f0ad80 675 }
707acfc0 676
59f0ad80
SA
677 iss_print_status(pipe->output->iss);
678 return 0;
679}
680
59f0ad80
SA
681/*
682 * omap4iss_pipeline_set_stream - Enable/disable streaming on a pipeline
683 * @pipe: ISS pipeline
684 * @state: Stream state (stopped, single shot or continuous)
685 *
686 * Set the pipeline to the given stream state. Pipelines can be started in
687 * single-shot or continuous mode.
688 *
689 * Return 0 if successful, or the return value of the failed video::s_stream
690 * operation otherwise. The pipeline state is not updated when the operation
691 * fails, except when stopping the pipeline.
692 */
693int omap4iss_pipeline_set_stream(struct iss_pipeline *pipe,
694 enum iss_pipeline_stream_state state)
695{
696 int ret;
697
698 if (state == ISS_PIPELINE_STREAM_STOPPED)
9587a3fc 699 ret = iss_pipeline_disable(pipe, NULL);
59f0ad80
SA
700 else
701 ret = iss_pipeline_enable(pipe, state);
702
703 if (ret == 0 || state == ISS_PIPELINE_STREAM_STOPPED)
704 pipe->stream_state = state;
705
706 return ret;
707}
708
112da085
LP
709/*
710 * omap4iss_pipeline_cancel_stream - Cancel stream on a pipeline
711 * @pipe: ISS pipeline
712 *
713 * Cancelling a stream mark all buffers on all video nodes in the pipeline as
714 * erroneous and makes sure no new buffer can be queued. This function is called
715 * when a fatal error that prevents any further operation on the pipeline
716 * occurs.
717 */
718void omap4iss_pipeline_cancel_stream(struct iss_pipeline *pipe)
719{
720 if (pipe->input)
721 omap4iss_video_cancel_stream(pipe->input);
722 if (pipe->output)
723 omap4iss_video_cancel_stream(pipe->output);
724}
725
59f0ad80
SA
726/*
727 * iss_pipeline_is_last - Verify if entity has an enabled link to the output
728 * video node
729 * @me: ISS module's media entity
730 *
731 * Returns 1 if the entity has an enabled link to the output video node or 0
732 * otherwise. It's true only while pipeline can have no more than one output
733 * node.
734 */
735static int iss_pipeline_is_last(struct media_entity *me)
736{
737 struct iss_pipeline *pipe;
738 struct media_pad *pad;
739
740 if (!me->pipe)
741 return 0;
742 pipe = to_iss_pipeline(me);
743 if (pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED)
744 return 0;
745 pad = media_entity_remote_pad(&pipe->output->pad);
746 return pad->entity == me;
747}
748
749static int iss_reset(struct iss_device *iss)
750{
05b1b986 751 unsigned int timeout;
59f0ad80 752
11abbfd3
LP
753 iss_reg_set(iss, OMAP4_ISS_MEM_TOP, ISS_HL_SYSCONFIG,
754 ISS_HL_SYSCONFIG_SOFTRESET);
59f0ad80 755
05b1b986
LP
756 timeout = iss_poll_condition_timeout(
757 !(iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_HL_SYSCONFIG) &
fa7014f5 758 ISS_HL_SYSCONFIG_SOFTRESET), 1000, 10, 100);
05b1b986
LP
759 if (timeout) {
760 dev_err(iss->dev, "ISS reset timeout\n");
761 return -ETIMEDOUT;
59f0ad80
SA
762 }
763
f3632ba8 764 iss->crashed = 0;
59f0ad80
SA
765 return 0;
766}
767
768static int iss_isp_reset(struct iss_device *iss)
769{
05b1b986 770 unsigned int timeout;
59f0ad80
SA
771
772 /* Fist, ensure that the ISP is IDLE (no transactions happening) */
11abbfd3
LP
773 iss_reg_update(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_SYSCONFIG,
774 ISP5_SYSCONFIG_STANDBYMODE_MASK,
775 ISP5_SYSCONFIG_STANDBYMODE_SMART);
59f0ad80 776
11abbfd3 777 iss_reg_set(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL, ISP5_CTRL_MSTANDBY);
59f0ad80 778
05b1b986
LP
779 timeout = iss_poll_condition_timeout(
780 iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL) &
781 ISP5_CTRL_MSTANDBY_WAIT, 1000000, 1000, 1500);
782 if (timeout) {
783 dev_err(iss->dev, "ISP5 standby timeout\n");
784 return -ETIMEDOUT;
59f0ad80
SA
785 }
786
787 /* Now finally, do the reset */
11abbfd3
LP
788 iss_reg_set(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_SYSCONFIG,
789 ISP5_SYSCONFIG_SOFTRESET);
59f0ad80 790
05b1b986
LP
791 timeout = iss_poll_condition_timeout(
792 !(iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_SYSCONFIG) &
793 ISP5_SYSCONFIG_SOFTRESET), 1000000, 1000, 1500);
794 if (timeout) {
795 dev_err(iss->dev, "ISP5 reset timeout\n");
796 return -ETIMEDOUT;
59f0ad80
SA
797 }
798
799 return 0;
800}
801
802/*
803 * iss_module_sync_idle - Helper to sync module with its idle state
804 * @me: ISS submodule's media entity
805 * @wait: ISS submodule's wait queue for streamoff/interrupt synchronization
806 * @stopping: flag which tells module wants to stop
807 *
808 * This function checks if ISS submodule needs to wait for next interrupt. If
809 * yes, makes the caller to sleep while waiting for such event.
810 */
811int omap4iss_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait,
812 atomic_t *stopping)
813{
814 struct iss_pipeline *pipe = to_iss_pipeline(me);
815 struct iss_video *video = pipe->output;
816 unsigned long flags;
817
818 if (pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED ||
819 (pipe->stream_state == ISS_PIPELINE_STREAM_SINGLESHOT &&
820 !iss_pipeline_ready(pipe)))
821 return 0;
822
823 /*
824 * atomic_set() doesn't include memory barrier on ARM platform for SMP
825 * scenario. We'll call it here to avoid race conditions.
826 */
827 atomic_set(stopping, 1);
828 smp_wmb();
829
830 /*
831 * If module is the last one, it's writing to memory. In this case,
832 * it's necessary to check if the module is already paused due to
833 * DMA queue underrun or if it has to wait for next interrupt to be
834 * idle.
835 * If it isn't the last one, the function won't sleep but *stopping
836 * will still be set to warn next submodule caller's interrupt the
837 * module wants to be idle.
838 */
839 if (!iss_pipeline_is_last(me))
840 return 0;
841
842 spin_lock_irqsave(&video->qlock, flags);
843 if (video->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_UNDERRUN) {
844 spin_unlock_irqrestore(&video->qlock, flags);
845 atomic_set(stopping, 0);
846 smp_wmb();
847 return 0;
848 }
849 spin_unlock_irqrestore(&video->qlock, flags);
850 if (!wait_event_timeout(*wait, !atomic_read(stopping),
851 msecs_to_jiffies(1000))) {
852 atomic_set(stopping, 0);
853 smp_wmb();
854 return -ETIMEDOUT;
855 }
856
857 return 0;
858}
859
860/*
861 * omap4iss_module_sync_is_stopped - Helper to verify if module was stopping
862 * @wait: ISS submodule's wait queue for streamoff/interrupt synchronization
863 * @stopping: flag which tells module wants to stop
864 *
865 * This function checks if ISS submodule was stopping. In case of yes, it
866 * notices the caller by setting stopping to 0 and waking up the wait queue.
867 * Returns 1 if it was stopping or 0 otherwise.
868 */
869int omap4iss_module_sync_is_stopping(wait_queue_head_t *wait,
870 atomic_t *stopping)
871{
872 if (atomic_cmpxchg(stopping, 1, 0)) {
873 wake_up(wait);
874 return 1;
875 }
876
877 return 0;
878}
879
880/* --------------------------------------------------------------------------
881 * Clock management
882 */
883
884#define ISS_CLKCTRL_MASK (ISS_CLKCTRL_CSI2_A |\
885 ISS_CLKCTRL_CSI2_B |\
886 ISS_CLKCTRL_ISP)
887
888static int __iss_subclk_update(struct iss_device *iss)
889{
890 u32 clk = 0;
891 int ret = 0, timeout = 1000;
892
893 if (iss->subclk_resources & OMAP4_ISS_SUBCLK_CSI2_A)
894 clk |= ISS_CLKCTRL_CSI2_A;
895
896 if (iss->subclk_resources & OMAP4_ISS_SUBCLK_CSI2_B)
897 clk |= ISS_CLKCTRL_CSI2_B;
898
899 if (iss->subclk_resources & OMAP4_ISS_SUBCLK_ISP)
900 clk |= ISS_CLKCTRL_ISP;
901
11abbfd3
LP
902 iss_reg_update(iss, OMAP4_ISS_MEM_TOP, ISS_CLKCTRL,
903 ISS_CLKCTRL_MASK, clk);
59f0ad80
SA
904
905 /* Wait for HW assertion */
906 while (--timeout > 0) {
907 udelay(1);
11abbfd3
LP
908 if ((iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_CLKSTAT) &
909 ISS_CLKCTRL_MASK) == clk)
59f0ad80
SA
910 break;
911 }
912
913 if (!timeout)
914 ret = -EBUSY;
915
916 return ret;
917}
918
919int omap4iss_subclk_enable(struct iss_device *iss,
b9e50a06 920 enum iss_subclk_resource res)
59f0ad80
SA
921{
922 iss->subclk_resources |= res;
923
924 return __iss_subclk_update(iss);
925}
926
927int omap4iss_subclk_disable(struct iss_device *iss,
b9e50a06 928 enum iss_subclk_resource res)
59f0ad80
SA
929{
930 iss->subclk_resources &= ~res;
931
932 return __iss_subclk_update(iss);
933}
934
935#define ISS_ISP5_CLKCTRL_MASK (ISP5_CTRL_BL_CLK_ENABLE |\
936 ISP5_CTRL_ISIF_CLK_ENABLE |\
937 ISP5_CTRL_H3A_CLK_ENABLE |\
938 ISP5_CTRL_RSZ_CLK_ENABLE |\
939 ISP5_CTRL_IPIPE_CLK_ENABLE |\
940 ISP5_CTRL_IPIPEIF_CLK_ENABLE)
941
68c03a66 942static void __iss_isp_subclk_update(struct iss_device *iss)
59f0ad80
SA
943{
944 u32 clk = 0;
945
946 if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_ISIF)
947 clk |= ISP5_CTRL_ISIF_CLK_ENABLE;
948
949 if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_H3A)
950 clk |= ISP5_CTRL_H3A_CLK_ENABLE;
951
952 if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_RSZ)
953 clk |= ISP5_CTRL_RSZ_CLK_ENABLE;
954
955 if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_IPIPE)
956 clk |= ISP5_CTRL_IPIPE_CLK_ENABLE;
957
958 if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_IPIPEIF)
959 clk |= ISP5_CTRL_IPIPEIF_CLK_ENABLE;
960
961 if (clk)
962 clk |= ISP5_CTRL_BL_CLK_ENABLE;
963
11abbfd3
LP
964 iss_reg_update(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL,
965 ISS_ISP5_CLKCTRL_MASK, clk);
59f0ad80
SA
966}
967
68c03a66 968void omap4iss_isp_subclk_enable(struct iss_device *iss,
59f0ad80
SA
969 enum iss_isp_subclk_resource res)
970{
971 iss->isp_subclk_resources |= res;
972
68c03a66 973 __iss_isp_subclk_update(iss);
59f0ad80
SA
974}
975
68c03a66
LP
976void omap4iss_isp_subclk_disable(struct iss_device *iss,
977 enum iss_isp_subclk_resource res)
59f0ad80
SA
978{
979 iss->isp_subclk_resources &= ~res;
980
68c03a66 981 __iss_isp_subclk_update(iss);
59f0ad80
SA
982}
983
984/*
985 * iss_enable_clocks - Enable ISS clocks
986 * @iss: OMAP4 ISS device
987 *
988 * Return 0 if successful, or clk_enable return value if any of tthem fails.
989 */
990static int iss_enable_clocks(struct iss_device *iss)
991{
2b16b44a 992 int ret;
59f0ad80 993
2b16b44a
LP
994 ret = clk_enable(iss->iss_fck);
995 if (ret) {
59f0ad80 996 dev_err(iss->dev, "clk_enable iss_fck failed\n");
2b16b44a 997 return ret;
59f0ad80
SA
998 }
999
2b16b44a
LP
1000 ret = clk_enable(iss->iss_ctrlclk);
1001 if (ret) {
59f0ad80 1002 dev_err(iss->dev, "clk_enable iss_ctrlclk failed\n");
2b16b44a
LP
1003 clk_disable(iss->iss_fck);
1004 return ret;
59f0ad80 1005 }
59f0ad80 1006
2b16b44a 1007 return 0;
59f0ad80
SA
1008}
1009
1010/*
1011 * iss_disable_clocks - Disable ISS clocks
1012 * @iss: OMAP4 ISS device
1013 */
1014static void iss_disable_clocks(struct iss_device *iss)
1015{
1016 clk_disable(iss->iss_ctrlclk);
1017 clk_disable(iss->iss_fck);
1018}
1019
59f0ad80
SA
1020static int iss_get_clocks(struct iss_device *iss)
1021{
1153be56 1022 iss->iss_fck = devm_clk_get(iss->dev, "iss_fck");
59f0ad80
SA
1023 if (IS_ERR(iss->iss_fck)) {
1024 dev_err(iss->dev, "Unable to get iss_fck clock info\n");
59f0ad80
SA
1025 return PTR_ERR(iss->iss_fck);
1026 }
1027
1153be56 1028 iss->iss_ctrlclk = devm_clk_get(iss->dev, "iss_ctrlclk");
59f0ad80
SA
1029 if (IS_ERR(iss->iss_ctrlclk)) {
1030 dev_err(iss->dev, "Unable to get iss_ctrlclk clock info\n");
057ef1e5 1031 return PTR_ERR(iss->iss_ctrlclk);
59f0ad80
SA
1032 }
1033
1034 return 0;
1035}
1036
1037/*
1038 * omap4iss_get - Acquire the ISS resource.
1039 *
1040 * Initializes the clocks for the first acquire.
1041 *
1042 * Increment the reference count on the ISS. If the first reference is taken,
1043 * enable clocks and power-up all submodules.
1044 *
1045 * Return a pointer to the ISS device structure, or NULL if an error occurred.
1046 */
1047struct iss_device *omap4iss_get(struct iss_device *iss)
1048{
1049 struct iss_device *__iss = iss;
1050
9058fc92 1051 if (!iss)
59f0ad80
SA
1052 return NULL;
1053
1054 mutex_lock(&iss->iss_mutex);
1055 if (iss->ref_count > 0)
1056 goto out;
1057
1058 if (iss_enable_clocks(iss) < 0) {
1059 __iss = NULL;
1060 goto out;
1061 }
1062
1063 iss_enable_interrupts(iss);
1064
1065out:
9058fc92 1066 if (__iss)
59f0ad80
SA
1067 iss->ref_count++;
1068 mutex_unlock(&iss->iss_mutex);
1069
1070 return __iss;
1071}
1072
1073/*
1074 * omap4iss_put - Release the ISS
1075 *
1076 * Decrement the reference count on the ISS. If the last reference is released,
1077 * power-down all submodules, disable clocks and free temporary buffers.
1078 */
1079void omap4iss_put(struct iss_device *iss)
1080{
9058fc92 1081 if (!iss)
59f0ad80
SA
1082 return;
1083
1084 mutex_lock(&iss->iss_mutex);
1085 BUG_ON(iss->ref_count == 0);
1086 if (--iss->ref_count == 0) {
1087 iss_disable_interrupts(iss);
f3632ba8
LP
1088 /* Reset the ISS if an entity has failed to stop. This is the
1089 * only way to recover from such conditions, although it would
1090 * be worth investigating whether resetting the ISP only can't
1091 * fix the problem in some cases.
1092 */
1093 if (iss->crashed)
1094 iss_reset(iss);
59f0ad80
SA
1095 iss_disable_clocks(iss);
1096 }
1097 mutex_unlock(&iss->iss_mutex);
1098}
1099
1100static int iss_map_mem_resource(struct platform_device *pdev,
1101 struct iss_device *iss,
1102 enum iss_mem_resources res)
1103{
1104 struct resource *mem;
1105
59f0ad80 1106 mem = platform_get_resource(pdev, IORESOURCE_MEM, res);
59f0ad80 1107
1153be56 1108 iss->regs[res] = devm_ioremap_resource(iss->dev, mem);
59f0ad80 1109
1153be56 1110 return PTR_ERR_OR_ZERO(iss->regs[res]);
59f0ad80
SA
1111}
1112
1113static void iss_unregister_entities(struct iss_device *iss)
1114{
1115 omap4iss_resizer_unregister_entities(&iss->resizer);
1116 omap4iss_ipipe_unregister_entities(&iss->ipipe);
1117 omap4iss_ipipeif_unregister_entities(&iss->ipipeif);
1118 omap4iss_csi2_unregister_entities(&iss->csi2a);
1119 omap4iss_csi2_unregister_entities(&iss->csi2b);
1120
1121 v4l2_device_unregister(&iss->v4l2_dev);
1122 media_device_unregister(&iss->media_dev);
1123}
1124
1125/*
1126 * iss_register_subdev_group - Register a group of subdevices
1127 * @iss: OMAP4 ISS device
1128 * @board_info: I2C subdevs board information array
1129 *
1130 * Register all I2C subdevices in the board_info array. The array must be
1131 * terminated by a NULL entry, and the first entry must be the sensor.
1132 *
1133 * Return a pointer to the sensor media entity if it has been successfully
1134 * registered, or NULL otherwise.
1135 */
1136static struct v4l2_subdev *
1137iss_register_subdev_group(struct iss_device *iss,
b9e50a06 1138 struct iss_subdev_i2c_board_info *board_info)
59f0ad80
SA
1139{
1140 struct v4l2_subdev *sensor = NULL;
1141 unsigned int first;
1142
9058fc92 1143 if (!board_info->board_info)
59f0ad80
SA
1144 return NULL;
1145
1146 for (first = 1; board_info->board_info; ++board_info, first = 0) {
1147 struct v4l2_subdev *subdev;
1148 struct i2c_adapter *adapter;
1149
1150 adapter = i2c_get_adapter(board_info->i2c_adapter_id);
9058fc92 1151 if (!adapter) {
499226fb
LP
1152 dev_err(iss->dev,
1153 "%s: Unable to get I2C adapter %d for device %s\n",
1154 __func__, board_info->i2c_adapter_id,
59f0ad80
SA
1155 board_info->board_info->type);
1156 continue;
1157 }
1158
1159 subdev = v4l2_i2c_new_subdev_board(&iss->v4l2_dev, adapter,
1160 board_info->board_info, NULL);
9058fc92 1161 if (!subdev) {
8c6ccbeb
HM
1162 dev_err(iss->dev, "Unable to register subdev %s\n",
1163 board_info->board_info->type);
59f0ad80
SA
1164 continue;
1165 }
1166
1167 if (first)
1168 sensor = subdev;
1169 }
1170
1171 return sensor;
1172}
1173
1174static int iss_register_entities(struct iss_device *iss)
1175{
1176 struct iss_platform_data *pdata = iss->pdata;
1177 struct iss_v4l2_subdevs_group *subdevs;
1178 int ret;
1179
1180 iss->media_dev.dev = iss->dev;
1181 strlcpy(iss->media_dev.model, "TI OMAP4 ISS",
1182 sizeof(iss->media_dev.model));
1183 iss->media_dev.hw_revision = iss->revision;
1184 iss->media_dev.link_notify = iss_pipeline_link_notify;
1185 ret = media_device_register(&iss->media_dev);
1186 if (ret < 0) {
8c6ccbeb
HM
1187 dev_err(iss->dev, "Media device registration failed (%d)\n",
1188 ret);
59f0ad80
SA
1189 return ret;
1190 }
1191
1192 iss->v4l2_dev.mdev = &iss->media_dev;
1193 ret = v4l2_device_register(iss->dev, &iss->v4l2_dev);
1194 if (ret < 0) {
8c6ccbeb
HM
1195 dev_err(iss->dev, "V4L2 device registration failed (%d)\n",
1196 ret);
59f0ad80
SA
1197 goto done;
1198 }
1199
1200 /* Register internal entities */
1201 ret = omap4iss_csi2_register_entities(&iss->csi2a, &iss->v4l2_dev);
1202 if (ret < 0)
1203 goto done;
1204
1205 ret = omap4iss_csi2_register_entities(&iss->csi2b, &iss->v4l2_dev);
1206 if (ret < 0)
1207 goto done;
1208
1209 ret = omap4iss_ipipeif_register_entities(&iss->ipipeif, &iss->v4l2_dev);
1210 if (ret < 0)
1211 goto done;
1212
1213 ret = omap4iss_ipipe_register_entities(&iss->ipipe, &iss->v4l2_dev);
1214 if (ret < 0)
1215 goto done;
1216
1217 ret = omap4iss_resizer_register_entities(&iss->resizer, &iss->v4l2_dev);
1218 if (ret < 0)
1219 goto done;
1220
1221 /* Register external entities */
1222 for (subdevs = pdata->subdevs; subdevs && subdevs->subdevs; ++subdevs) {
1223 struct v4l2_subdev *sensor;
1224 struct media_entity *input;
1225 unsigned int flags;
1226 unsigned int pad;
1227
1228 sensor = iss_register_subdev_group(iss, subdevs->subdevs);
9058fc92 1229 if (!sensor)
59f0ad80
SA
1230 continue;
1231
1232 sensor->host_priv = subdevs;
1233
1234 /* Connect the sensor to the correct interface module.
1235 * CSI2a receiver through CSIPHY1, or
1236 * CSI2b receiver through CSIPHY2
1237 */
1238 switch (subdevs->interface) {
1239 case ISS_INTERFACE_CSI2A_PHY1:
1240 input = &iss->csi2a.subdev.entity;
1241 pad = CSI2_PAD_SINK;
1242 flags = MEDIA_LNK_FL_IMMUTABLE
1243 | MEDIA_LNK_FL_ENABLED;
1244 break;
1245
1246 case ISS_INTERFACE_CSI2B_PHY2:
1247 input = &iss->csi2b.subdev.entity;
1248 pad = CSI2_PAD_SINK;
1249 flags = MEDIA_LNK_FL_IMMUTABLE
1250 | MEDIA_LNK_FL_ENABLED;
1251 break;
1252
1253 default:
8c6ccbeb
HM
1254 dev_err(iss->dev, "invalid interface type %u\n",
1255 subdevs->interface);
59f0ad80
SA
1256 ret = -EINVAL;
1257 goto done;
1258 }
1259
8df00a15 1260 ret = media_create_pad_link(&sensor->entity, 0, input, pad,
59f0ad80
SA
1261 flags);
1262 if (ret < 0)
1263 goto done;
1264 }
1265
1266 ret = v4l2_device_register_subdev_nodes(&iss->v4l2_dev);
1267
1268done:
1269 if (ret < 0)
1270 iss_unregister_entities(iss);
1271
1272 return ret;
1273}
1274
5837ceea
JMC
1275/*
1276 * iss_create_pads_links() - Pads links creation for the subdevices
1277 * @iss : Pointer to ISS device
1278 *
1279 * return negative error code or zero on success
1280 */
1281static int iss_create_pads_links(struct iss_device *iss)
1282{
1283 int ret;
1284
1285 ret = omap4iss_csi2_create_pads_links(iss);
1286 if (ret < 0) {
1287 dev_err(iss->dev, "CSI2 pads links creation failed\n");
1288 return ret;
1289 }
1290
1291 ret = omap4iss_ipipeif_create_pads_links(iss);
1292 if (ret < 0) {
1293 dev_err(iss->dev, "ISP IPIPEIF pads links creation failed\n");
1294 return ret;
1295 }
1296
1297 ret = omap4iss_resizer_create_pads_links(iss);
1298 if (ret < 0) {
1299 dev_err(iss->dev, "ISP RESIZER pads links creation failed\n");
1300 return ret;
1301 }
1302
1303 /* Connect the submodules. */
1304 ret = media_create_pad_link(
1305 &iss->csi2a.subdev.entity, CSI2_PAD_SOURCE,
1306 &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SINK, 0);
1307 if (ret < 0)
1308 return ret;
1309
1310 ret = media_create_pad_link(
1311 &iss->csi2b.subdev.entity, CSI2_PAD_SOURCE,
1312 &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SINK, 0);
1313 if (ret < 0)
1314 return ret;
1315
1316 ret = media_create_pad_link(
1317 &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SOURCE_VP,
1318 &iss->resizer.subdev.entity, RESIZER_PAD_SINK, 0);
1319 if (ret < 0)
1320 return ret;
1321
1322 ret = media_create_pad_link(
1323 &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SOURCE_VP,
1324 &iss->ipipe.subdev.entity, IPIPE_PAD_SINK, 0);
1325 if (ret < 0)
1326 return ret;
1327
1328 ret = media_create_pad_link(
1329 &iss->ipipe.subdev.entity, IPIPE_PAD_SOURCE_VP,
1330 &iss->resizer.subdev.entity, RESIZER_PAD_SINK, 0);
1331 if (ret < 0)
1332 return ret;
1333
1334 return 0;
1335};
1336
59f0ad80
SA
1337static void iss_cleanup_modules(struct iss_device *iss)
1338{
1339 omap4iss_csi2_cleanup(iss);
1340 omap4iss_ipipeif_cleanup(iss);
1341 omap4iss_ipipe_cleanup(iss);
1342 omap4iss_resizer_cleanup(iss);
1343}
1344
1345static int iss_initialize_modules(struct iss_device *iss)
1346{
1347 int ret;
1348
1349 ret = omap4iss_csiphy_init(iss);
1350 if (ret < 0) {
1351 dev_err(iss->dev, "CSI PHY initialization failed\n");
1352 goto error_csiphy;
1353 }
1354
1355 ret = omap4iss_csi2_init(iss);
1356 if (ret < 0) {
1357 dev_err(iss->dev, "CSI2 initialization failed\n");
1358 goto error_csi2;
1359 }
1360
1361 ret = omap4iss_ipipeif_init(iss);
1362 if (ret < 0) {
1363 dev_err(iss->dev, "ISP IPIPEIF initialization failed\n");
1364 goto error_ipipeif;
1365 }
1366
1367 ret = omap4iss_ipipe_init(iss);
1368 if (ret < 0) {
1369 dev_err(iss->dev, "ISP IPIPE initialization failed\n");
1370 goto error_ipipe;
1371 }
1372
1373 ret = omap4iss_resizer_init(iss);
1374 if (ret < 0) {
1375 dev_err(iss->dev, "ISP RESIZER initialization failed\n");
1376 goto error_resizer;
1377 }
1378
59f0ad80
SA
1379 return 0;
1380
59f0ad80
SA
1381error_resizer:
1382 omap4iss_ipipe_cleanup(iss);
1383error_ipipe:
1384 omap4iss_ipipeif_cleanup(iss);
1385error_ipipeif:
1386 omap4iss_csi2_cleanup(iss);
1387error_csi2:
1388error_csiphy:
1389 return ret;
1390}
1391
1392static int iss_probe(struct platform_device *pdev)
1393{
1394 struct iss_platform_data *pdata = pdev->dev.platform_data;
1395 struct iss_device *iss;
4334fd18
LP
1396 unsigned int i;
1397 int ret;
59f0ad80 1398
9058fc92 1399 if (!pdata)
59f0ad80
SA
1400 return -EINVAL;
1401
1153be56 1402 iss = devm_kzalloc(&pdev->dev, sizeof(*iss), GFP_KERNEL);
b717a65a 1403 if (!iss)
59f0ad80 1404 return -ENOMEM;
59f0ad80
SA
1405
1406 mutex_init(&iss->iss_mutex);
1407
1408 iss->dev = &pdev->dev;
1409 iss->pdata = pdata;
59f0ad80
SA
1410
1411 iss->raw_dmamask = DMA_BIT_MASK(32);
1412 iss->dev->dma_mask = &iss->raw_dmamask;
1413 iss->dev->coherent_dma_mask = DMA_BIT_MASK(32);
1414
1415 platform_set_drvdata(pdev, iss);
1416
fefad2d5
LP
1417 /*
1418 * TODO: When implementing DT support switch to syscon regmap lookup by
1419 * phandle.
1420 */
1421 iss->syscon = syscon_regmap_lookup_by_compatible("syscon");
1422 if (IS_ERR(iss->syscon)) {
1423 ret = PTR_ERR(iss->syscon);
1424 goto error;
1425 }
1426
59f0ad80
SA
1427 /* Clocks */
1428 ret = iss_map_mem_resource(pdev, iss, OMAP4_ISS_MEM_TOP);
1429 if (ret < 0)
1430 goto error;
1431
1432 ret = iss_get_clocks(iss);
1433 if (ret < 0)
1434 goto error;
1435
9058fc92 1436 if (!omap4iss_get(iss))
59f0ad80
SA
1437 goto error;
1438
1439 ret = iss_reset(iss);
1440 if (ret < 0)
1441 goto error_iss;
1442
11abbfd3 1443 iss->revision = iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_HL_REVISION);
59f0ad80
SA
1444 dev_info(iss->dev, "Revision %08x found\n", iss->revision);
1445
1446 for (i = 1; i < OMAP4_ISS_MEM_LAST; i++) {
1447 ret = iss_map_mem_resource(pdev, iss, i);
1448 if (ret)
1449 goto error_iss;
1450 }
1451
1452 /* Configure BTE BW_LIMITER field to max recommended value (1 GB) */
11abbfd3
LP
1453 iss_reg_update(iss, OMAP4_ISS_MEM_BTE, BTE_CTRL,
1454 BTE_CTRL_BW_LIMITER_MASK,
1455 18 << BTE_CTRL_BW_LIMITER_SHIFT);
59f0ad80
SA
1456
1457 /* Perform ISP reset */
1458 ret = omap4iss_subclk_enable(iss, OMAP4_ISS_SUBCLK_ISP);
1459 if (ret < 0)
1460 goto error_iss;
1461
1462 ret = iss_isp_reset(iss);
1463 if (ret < 0)
1464 goto error_iss;
1465
1466 dev_info(iss->dev, "ISP Revision %08x found\n",
11abbfd3 1467 iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_REVISION));
59f0ad80
SA
1468
1469 /* Interrupt */
08ed049a
AH
1470 ret = platform_get_irq(pdev, 0);
1471 if (ret <= 0) {
59f0ad80
SA
1472 dev_err(iss->dev, "No IRQ resource\n");
1473 ret = -ENODEV;
1474 goto error_iss;
1475 }
08ed049a 1476 iss->irq_num = ret;
59f0ad80 1477
1153be56
LP
1478 if (devm_request_irq(iss->dev, iss->irq_num, iss_isr, IRQF_SHARED,
1479 "OMAP4 ISS", iss)) {
59f0ad80
SA
1480 dev_err(iss->dev, "Unable to request IRQ\n");
1481 ret = -EINVAL;
1482 goto error_iss;
1483 }
1484
1485 /* Entities */
1486 ret = iss_initialize_modules(iss);
1487 if (ret < 0)
1153be56 1488 goto error_iss;
59f0ad80
SA
1489
1490 ret = iss_register_entities(iss);
1491 if (ret < 0)
1492 goto error_modules;
1493
5837ceea
JMC
1494 ret = iss_create_pads_links(iss);
1495 if (ret < 0)
1496 goto error_entities;
1497
59f0ad80
SA
1498 omap4iss_put(iss);
1499
1500 return 0;
1501
5837ceea
JMC
1502error_entities:
1503 iss_unregister_entities(iss);
59f0ad80
SA
1504error_modules:
1505 iss_cleanup_modules(iss);
59f0ad80
SA
1506error_iss:
1507 omap4iss_put(iss);
1508error:
59f0ad80
SA
1509 platform_set_drvdata(pdev, NULL);
1510
1511 mutex_destroy(&iss->iss_mutex);
59f0ad80
SA
1512
1513 return ret;
1514}
1515
1516static int iss_remove(struct platform_device *pdev)
1517{
1518 struct iss_device *iss = platform_get_drvdata(pdev);
59f0ad80
SA
1519
1520 iss_unregister_entities(iss);
1521 iss_cleanup_modules(iss);
1522
59f0ad80
SA
1523 return 0;
1524}
1525
44d6ac60 1526static const struct platform_device_id omap4iss_id_table[] = {
59f0ad80
SA
1527 { "omap4iss", 0 },
1528 { },
1529};
1530MODULE_DEVICE_TABLE(platform, omap4iss_id_table);
1531
1532static struct platform_driver iss_driver = {
1533 .probe = iss_probe,
1534 .remove = iss_remove,
1535 .id_table = omap4iss_id_table,
1536 .driver = {
59f0ad80
SA
1537 .name = "omap4iss",
1538 },
1539};
1540
1541module_platform_driver(iss_driver);
1542
1543MODULE_DESCRIPTION("TI OMAP4 ISS driver");
1544MODULE_AUTHOR("Sergio Aguirre <sergio.a.aguirre@gmail.com>");
1545MODULE_LICENSE("GPL");
1546MODULE_VERSION(ISS_VIDEO_DRIVER_VERSION);
This page took 0.279031 seconds and 5 git commands to generate.