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