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 *   https://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        mutex_lock(&iss->media_dev.graph_mutex);
 460
 461        entity = &pipe->output->video.entity;
 462        while (1) {
 463                pad = &entity->pads[0];
 464                if (!(pad->flags & MEDIA_PAD_FL_SINK))
 465                        break;
 466
 467                pad = media_entity_remote_pad(pad);
 468                if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
 469                        break;
 470
 471                entity = pad->entity;
 472                subdev = media_entity_to_v4l2_subdev(entity);
 473
 474                ret = v4l2_subdev_call(subdev, video, s_stream, mode);
 475                if (ret < 0 && ret != -ENOIOCTLCMD) {
 476                        iss_pipeline_disable(pipe, entity);
 477                        mutex_unlock(&iss->media_dev.graph_mutex);
 478                        return ret;
 479                }
 480
 481                if (subdev == &iss->csi2a.subdev ||
 482                    subdev == &iss->csi2b.subdev)
 483                        pipe->do_propagation = true;
 484        }
 485
 486        mutex_unlock(&iss->media_dev.graph_mutex);
 487        iss_print_status(pipe->output->iss);
 488
 489        return 0;
 490}
 491
 492/*
 493 * omap4iss_pipeline_set_stream - Enable/disable streaming on a pipeline
 494 * @pipe: ISS pipeline
 495 * @state: Stream state (stopped, single shot or continuous)
 496 *
 497 * Set the pipeline to the given stream state. Pipelines can be started in
 498 * single-shot or continuous mode.
 499 *
 500 * Return 0 if successful, or the return value of the failed video::s_stream
 501 * operation otherwise. The pipeline state is not updated when the operation
 502 * fails, except when stopping the pipeline.
 503 */
 504int omap4iss_pipeline_set_stream(struct iss_pipeline *pipe,
 505                                 enum iss_pipeline_stream_state state)
 506{
 507        int ret;
 508
 509        if (state == ISS_PIPELINE_STREAM_STOPPED)
 510                ret = iss_pipeline_disable(pipe, NULL);
 511        else
 512                ret = iss_pipeline_enable(pipe, state);
 513
 514        if (ret == 0 || state == ISS_PIPELINE_STREAM_STOPPED)
 515                pipe->stream_state = state;
 516
 517        return ret;
 518}
 519
 520/*
 521 * omap4iss_pipeline_cancel_stream - Cancel stream on a pipeline
 522 * @pipe: ISS pipeline
 523 *
 524 * Cancelling a stream mark all buffers on all video nodes in the pipeline as
 525 * erroneous and makes sure no new buffer can be queued. This function is called
 526 * when a fatal error that prevents any further operation on the pipeline
 527 * occurs.
 528 */
 529void omap4iss_pipeline_cancel_stream(struct iss_pipeline *pipe)
 530{
 531        if (pipe->input)
 532                omap4iss_video_cancel_stream(pipe->input);
 533        if (pipe->output)
 534                omap4iss_video_cancel_stream(pipe->output);
 535}
 536
 537/*
 538 * iss_pipeline_is_last - Verify if entity has an enabled link to the output
 539 *                        video node
 540 * @me: ISS module's media entity
 541 *
 542 * Returns 1 if the entity has an enabled link to the output video node or 0
 543 * otherwise. It's true only while pipeline can have no more than one output
 544 * node.
 545 */
 546static int iss_pipeline_is_last(struct media_entity *me)
 547{
 548        struct iss_pipeline *pipe;
 549        struct media_pad *pad;
 550
 551        if (!me->pipe)
 552                return 0;
 553        pipe = to_iss_pipeline(me);
 554        if (pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED)
 555                return 0;
 556        pad = media_entity_remote_pad(&pipe->output->pad);
 557        return pad->entity == me;
 558}
 559
 560static int iss_reset(struct iss_device *iss)
 561{
 562        unsigned int timeout;
 563
 564        iss_reg_set(iss, OMAP4_ISS_MEM_TOP, ISS_HL_SYSCONFIG,
 565                    ISS_HL_SYSCONFIG_SOFTRESET);
 566
 567        timeout = iss_poll_condition_timeout(
 568                !(iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_HL_SYSCONFIG) &
 569                ISS_HL_SYSCONFIG_SOFTRESET), 1000, 10, 100);
 570        if (timeout) {
 571                dev_err(iss->dev, "ISS reset timeout\n");
 572                return -ETIMEDOUT;
 573        }
 574
 575        media_entity_enum_zero(&iss->crashed);
 576
 577        return 0;
 578}
 579
 580static int iss_isp_reset(struct iss_device *iss)
 581{
 582        unsigned int timeout;
 583
 584        /* Fist, ensure that the ISP is IDLE (no transactions happening) */
 585        iss_reg_update(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_SYSCONFIG,
 586                       ISP5_SYSCONFIG_STANDBYMODE_MASK,
 587                       ISP5_SYSCONFIG_STANDBYMODE_SMART);
 588
 589        iss_reg_set(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL, ISP5_CTRL_MSTANDBY);
 590
 591        timeout = iss_poll_condition_timeout(
 592                iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL) &
 593                ISP5_CTRL_MSTANDBY_WAIT, 1000000, 1000, 1500);
 594        if (timeout) {
 595                dev_err(iss->dev, "ISP5 standby timeout\n");
 596                return -ETIMEDOUT;
 597        }
 598
 599        /* Now finally, do the reset */
 600        iss_reg_set(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_SYSCONFIG,
 601                    ISP5_SYSCONFIG_SOFTRESET);
 602
 603        timeout = iss_poll_condition_timeout(
 604                !(iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_SYSCONFIG) &
 605                ISP5_SYSCONFIG_SOFTRESET), 1000000, 1000, 1500);
 606        if (timeout) {
 607                dev_err(iss->dev, "ISP5 reset timeout\n");
 608                return -ETIMEDOUT;
 609        }
 610
 611        return 0;
 612}
 613
 614/*
 615 * iss_module_sync_idle - Helper to sync module with its idle state
 616 * @me: ISS submodule's media entity
 617 * @wait: ISS submodule's wait queue for streamoff/interrupt synchronization
 618 * @stopping: flag which tells module wants to stop
 619 *
 620 * This function checks if ISS submodule needs to wait for next interrupt. If
 621 * yes, makes the caller to sleep while waiting for such event.
 622 */
 623int omap4iss_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait,
 624                              atomic_t *stopping)
 625{
 626        struct iss_pipeline *pipe = to_iss_pipeline(me);
 627        struct iss_video *video = pipe->output;
 628        unsigned long flags;
 629
 630        if (pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED ||
 631            (pipe->stream_state == ISS_PIPELINE_STREAM_SINGLESHOT &&
 632             !iss_pipeline_ready(pipe)))
 633                return 0;
 634
 635        /*
 636         * atomic_set() doesn't include memory barrier on ARM platform for SMP
 637         * scenario. We'll call it here to avoid race conditions.
 638         */
 639        atomic_set(stopping, 1);
 640        smp_wmb();
 641
 642        /*
 643         * If module is the last one, it's writing to memory. In this case,
 644         * it's necessary to check if the module is already paused due to
 645         * DMA queue underrun or if it has to wait for next interrupt to be
 646         * idle.
 647         * If it isn't the last one, the function won't sleep but *stopping
 648         * will still be set to warn next submodule caller's interrupt the
 649         * module wants to be idle.
 650         */
 651        if (!iss_pipeline_is_last(me))
 652                return 0;
 653
 654        spin_lock_irqsave(&video->qlock, flags);
 655        if (video->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_UNDERRUN) {
 656                spin_unlock_irqrestore(&video->qlock, flags);
 657                atomic_set(stopping, 0);
 658                smp_wmb();
 659                return 0;
 660        }
 661        spin_unlock_irqrestore(&video->qlock, flags);
 662        if (!wait_event_timeout(*wait, !atomic_read(stopping),
 663                                msecs_to_jiffies(1000))) {
 664                atomic_set(stopping, 0);
 665                smp_wmb();
 666                return -ETIMEDOUT;
 667        }
 668
 669        return 0;
 670}
 671
 672/*
 673 * omap4iss_module_sync_is_stopped - Helper to verify if module was stopping
 674 * @wait: ISS submodule's wait queue for streamoff/interrupt synchronization
 675 * @stopping: flag which tells module wants to stop
 676 *
 677 * This function checks if ISS submodule was stopping. In case of yes, it
 678 * notices the caller by setting stopping to 0 and waking up the wait queue.
 679 * Returns 1 if it was stopping or 0 otherwise.
 680 */
 681int omap4iss_module_sync_is_stopping(wait_queue_head_t *wait,
 682                                     atomic_t *stopping)
 683{
 684        if (atomic_cmpxchg(stopping, 1, 0)) {
 685                wake_up(wait);
 686                return 1;
 687        }
 688
 689        return 0;
 690}
 691
 692/* --------------------------------------------------------------------------
 693 * Clock management
 694 */
 695
 696#define ISS_CLKCTRL_MASK        (ISS_CLKCTRL_CSI2_A |\
 697                                 ISS_CLKCTRL_CSI2_B |\
 698                                 ISS_CLKCTRL_ISP)
 699
 700static int __iss_subclk_update(struct iss_device *iss)
 701{
 702        u32 clk = 0;
 703        int ret = 0, timeout = 1000;
 704
 705        if (iss->subclk_resources & OMAP4_ISS_SUBCLK_CSI2_A)
 706                clk |= ISS_CLKCTRL_CSI2_A;
 707
 708        if (iss->subclk_resources & OMAP4_ISS_SUBCLK_CSI2_B)
 709                clk |= ISS_CLKCTRL_CSI2_B;
 710
 711        if (iss->subclk_resources & OMAP4_ISS_SUBCLK_ISP)
 712                clk |= ISS_CLKCTRL_ISP;
 713
 714        iss_reg_update(iss, OMAP4_ISS_MEM_TOP, ISS_CLKCTRL,
 715                       ISS_CLKCTRL_MASK, clk);
 716
 717        /* Wait for HW assertion */
 718        while (--timeout > 0) {
 719                udelay(1);
 720                if ((iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_CLKSTAT) &
 721                    ISS_CLKCTRL_MASK) == clk)
 722                        break;
 723        }
 724
 725        if (!timeout)
 726                ret = -EBUSY;
 727
 728        return ret;
 729}
 730
 731int omap4iss_subclk_enable(struct iss_device *iss,
 732                           enum iss_subclk_resource res)
 733{
 734        iss->subclk_resources |= res;
 735
 736        return __iss_subclk_update(iss);
 737}
 738
 739int omap4iss_subclk_disable(struct iss_device *iss,
 740                            enum iss_subclk_resource res)
 741{
 742        iss->subclk_resources &= ~res;
 743
 744        return __iss_subclk_update(iss);
 745}
 746
 747#define ISS_ISP5_CLKCTRL_MASK   (ISP5_CTRL_BL_CLK_ENABLE |\
 748                                 ISP5_CTRL_ISIF_CLK_ENABLE |\
 749                                 ISP5_CTRL_H3A_CLK_ENABLE |\
 750                                 ISP5_CTRL_RSZ_CLK_ENABLE |\
 751                                 ISP5_CTRL_IPIPE_CLK_ENABLE |\
 752                                 ISP5_CTRL_IPIPEIF_CLK_ENABLE)
 753
 754static void __iss_isp_subclk_update(struct iss_device *iss)
 755{
 756        u32 clk = 0;
 757
 758        if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_ISIF)
 759                clk |= ISP5_CTRL_ISIF_CLK_ENABLE;
 760
 761        if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_H3A)
 762                clk |= ISP5_CTRL_H3A_CLK_ENABLE;
 763
 764        if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_RSZ)
 765                clk |= ISP5_CTRL_RSZ_CLK_ENABLE;
 766
 767        if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_IPIPE)
 768                clk |= ISP5_CTRL_IPIPE_CLK_ENABLE;
 769
 770        if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_IPIPEIF)
 771                clk |= ISP5_CTRL_IPIPEIF_CLK_ENABLE;
 772
 773        if (clk)
 774                clk |= ISP5_CTRL_BL_CLK_ENABLE;
 775
 776        iss_reg_update(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL,
 777                       ISS_ISP5_CLKCTRL_MASK, clk);
 778}
 779
 780void omap4iss_isp_subclk_enable(struct iss_device *iss,
 781                                enum iss_isp_subclk_resource res)
 782{
 783        iss->isp_subclk_resources |= res;
 784
 785        __iss_isp_subclk_update(iss);
 786}
 787
 788void omap4iss_isp_subclk_disable(struct iss_device *iss,
 789                                 enum iss_isp_subclk_resource res)
 790{
 791        iss->isp_subclk_resources &= ~res;
 792
 793        __iss_isp_subclk_update(iss);
 794}
 795
 796/*
 797 * iss_enable_clocks - Enable ISS clocks
 798 * @iss: OMAP4 ISS device
 799 *
 800 * Return 0 if successful, or clk_enable return value if any of tthem fails.
 801 */
 802static int iss_enable_clocks(struct iss_device *iss)
 803{
 804        int ret;
 805
 806        ret = clk_enable(iss->iss_fck);
 807        if (ret) {
 808                dev_err(iss->dev, "clk_enable iss_fck failed\n");
 809                return ret;
 810        }
 811
 812        ret = clk_enable(iss->iss_ctrlclk);
 813        if (ret) {
 814                dev_err(iss->dev, "clk_enable iss_ctrlclk failed\n");
 815                clk_disable(iss->iss_fck);
 816                return ret;
 817        }
 818
 819        return 0;
 820}
 821
 822/*
 823 * iss_disable_clocks - Disable ISS clocks
 824 * @iss: OMAP4 ISS device
 825 */
 826static void iss_disable_clocks(struct iss_device *iss)
 827{
 828        clk_disable(iss->iss_ctrlclk);
 829        clk_disable(iss->iss_fck);
 830}
 831
 832static int iss_get_clocks(struct iss_device *iss)
 833{
 834        iss->iss_fck = devm_clk_get(iss->dev, "iss_fck");
 835        if (IS_ERR(iss->iss_fck)) {
 836                dev_err(iss->dev, "Unable to get iss_fck clock info\n");
 837                return PTR_ERR(iss->iss_fck);
 838        }
 839
 840        iss->iss_ctrlclk = devm_clk_get(iss->dev, "iss_ctrlclk");
 841        if (IS_ERR(iss->iss_ctrlclk)) {
 842                dev_err(iss->dev, "Unable to get iss_ctrlclk clock info\n");
 843                return PTR_ERR(iss->iss_ctrlclk);
 844        }
 845
 846        return 0;
 847}
 848
 849/*
 850 * omap4iss_get - Acquire the ISS resource.
 851 *
 852 * Initializes the clocks for the first acquire.
 853 *
 854 * Increment the reference count on the ISS. If the first reference is taken,
 855 * enable clocks and power-up all submodules.
 856 *
 857 * Return a pointer to the ISS device structure, or NULL if an error occurred.
 858 */
 859struct iss_device *omap4iss_get(struct iss_device *iss)
 860{
 861        struct iss_device *__iss = iss;
 862
 863        if (!iss)
 864                return NULL;
 865
 866        mutex_lock(&iss->iss_mutex);
 867        if (iss->ref_count > 0)
 868                goto out;
 869
 870        if (iss_enable_clocks(iss) < 0) {
 871                __iss = NULL;
 872                goto out;
 873        }
 874
 875        iss_enable_interrupts(iss);
 876
 877out:
 878        if (__iss)
 879                iss->ref_count++;
 880        mutex_unlock(&iss->iss_mutex);
 881
 882        return __iss;
 883}
 884
 885/*
 886 * omap4iss_put - Release the ISS
 887 *
 888 * Decrement the reference count on the ISS. If the last reference is released,
 889 * power-down all submodules, disable clocks and free temporary buffers.
 890 */
 891void omap4iss_put(struct iss_device *iss)
 892{
 893        if (!iss)
 894                return;
 895
 896        mutex_lock(&iss->iss_mutex);
 897        WARN_ON(iss->ref_count == 0);
 898        if (--iss->ref_count == 0) {
 899                iss_disable_interrupts(iss);
 900                /* Reset the ISS if an entity has failed to stop. This is the
 901                 * only way to recover from such conditions, although it would
 902                 * be worth investigating whether resetting the ISP only can't
 903                 * fix the problem in some cases.
 904                 */
 905                if (!media_entity_enum_empty(&iss->crashed))
 906                        iss_reset(iss);
 907                iss_disable_clocks(iss);
 908        }
 909        mutex_unlock(&iss->iss_mutex);
 910}
 911
 912static int iss_map_mem_resource(struct platform_device *pdev,
 913                                struct iss_device *iss,
 914                                enum iss_mem_resources res)
 915{
 916        iss->regs[res] = devm_platform_ioremap_resource(pdev, res);
 917
 918        return PTR_ERR_OR_ZERO(iss->regs[res]);
 919}
 920
 921static void iss_unregister_entities(struct iss_device *iss)
 922{
 923        omap4iss_resizer_unregister_entities(&iss->resizer);
 924        omap4iss_ipipe_unregister_entities(&iss->ipipe);
 925        omap4iss_ipipeif_unregister_entities(&iss->ipipeif);
 926        omap4iss_csi2_unregister_entities(&iss->csi2a);
 927        omap4iss_csi2_unregister_entities(&iss->csi2b);
 928
 929        v4l2_device_unregister(&iss->v4l2_dev);
 930        media_device_unregister(&iss->media_dev);
 931}
 932
 933/*
 934 * iss_register_subdev_group - Register a group of subdevices
 935 * @iss: OMAP4 ISS device
 936 * @board_info: I2C subdevs board information array
 937 *
 938 * Register all I2C subdevices in the board_info array. The array must be
 939 * terminated by a NULL entry, and the first entry must be the sensor.
 940 *
 941 * Return a pointer to the sensor media entity if it has been successfully
 942 * registered, or NULL otherwise.
 943 */
 944static struct v4l2_subdev *
 945iss_register_subdev_group(struct iss_device *iss,
 946                          struct iss_subdev_i2c_board_info *board_info)
 947{
 948        struct v4l2_subdev *sensor = NULL;
 949        unsigned int first;
 950
 951        if (!board_info->board_info)
 952                return NULL;
 953
 954        for (first = 1; board_info->board_info; ++board_info, first = 0) {
 955                struct v4l2_subdev *subdev;
 956                struct i2c_adapter *adapter;
 957
 958                adapter = i2c_get_adapter(board_info->i2c_adapter_id);
 959                if (!adapter) {
 960                        dev_err(iss->dev,
 961                                "%s: Unable to get I2C adapter %d for device %s\n",
 962                                __func__, board_info->i2c_adapter_id,
 963                                board_info->board_info->type);
 964                        continue;
 965                }
 966
 967                subdev = v4l2_i2c_new_subdev_board(&iss->v4l2_dev, adapter,
 968                                                   board_info->board_info, NULL);
 969                if (!subdev) {
 970                        dev_err(iss->dev, "Unable to register subdev %s\n",
 971                                board_info->board_info->type);
 972                        continue;
 973                }
 974
 975                if (first)
 976                        sensor = subdev;
 977        }
 978
 979        return sensor;
 980}
 981
 982static int iss_register_entities(struct iss_device *iss)
 983{
 984        struct iss_platform_data *pdata = iss->pdata;
 985        struct iss_v4l2_subdevs_group *subdevs;
 986        int ret;
 987
 988        iss->media_dev.dev = iss->dev;
 989        strscpy(iss->media_dev.model, "TI OMAP4 ISS",
 990                sizeof(iss->media_dev.model));
 991        iss->media_dev.hw_revision = iss->revision;
 992        iss->media_dev.ops = &iss_media_ops;
 993        ret = media_device_register(&iss->media_dev);
 994        if (ret < 0) {
 995                dev_err(iss->dev, "Media device registration failed (%d)\n",
 996                        ret);
 997                return ret;
 998        }
 999
1000        iss->v4l2_dev.mdev = &iss->media_dev;
1001        ret = v4l2_device_register(iss->dev, &iss->v4l2_dev);
1002        if (ret < 0) {
1003                dev_err(iss->dev, "V4L2 device registration failed (%d)\n",
1004                        ret);
1005                goto done;
1006        }
1007
1008        /* Register internal entities */
1009        ret = omap4iss_csi2_register_entities(&iss->csi2a, &iss->v4l2_dev);
1010        if (ret < 0)
1011                goto done;
1012
1013        ret = omap4iss_csi2_register_entities(&iss->csi2b, &iss->v4l2_dev);
1014        if (ret < 0)
1015                goto done;
1016
1017        ret = omap4iss_ipipeif_register_entities(&iss->ipipeif, &iss->v4l2_dev);
1018        if (ret < 0)
1019                goto done;
1020
1021        ret = omap4iss_ipipe_register_entities(&iss->ipipe, &iss->v4l2_dev);
1022        if (ret < 0)
1023                goto done;
1024
1025        ret = omap4iss_resizer_register_entities(&iss->resizer, &iss->v4l2_dev);
1026        if (ret < 0)
1027                goto done;
1028
1029        /* Register external entities */
1030        for (subdevs = pdata->subdevs; subdevs && subdevs->subdevs; ++subdevs) {
1031                struct v4l2_subdev *sensor;
1032                struct media_entity *input;
1033                unsigned int flags;
1034                unsigned int pad;
1035
1036                sensor = iss_register_subdev_group(iss, subdevs->subdevs);
1037                if (!sensor)
1038                        continue;
1039
1040                sensor->host_priv = subdevs;
1041
1042                /* Connect the sensor to the correct interface module.
1043                 * CSI2a receiver through CSIPHY1, or
1044                 * CSI2b receiver through CSIPHY2
1045                 */
1046                switch (subdevs->interface) {
1047                case ISS_INTERFACE_CSI2A_PHY1:
1048                        input = &iss->csi2a.subdev.entity;
1049                        pad = CSI2_PAD_SINK;
1050                        flags = MEDIA_LNK_FL_IMMUTABLE
1051                              | MEDIA_LNK_FL_ENABLED;
1052                        break;
1053
1054                case ISS_INTERFACE_CSI2B_PHY2:
1055                        input = &iss->csi2b.subdev.entity;
1056                        pad = CSI2_PAD_SINK;
1057                        flags = MEDIA_LNK_FL_IMMUTABLE
1058                              | MEDIA_LNK_FL_ENABLED;
1059                        break;
1060
1061                default:
1062                        dev_err(iss->dev, "invalid interface type %u\n",
1063                                subdevs->interface);
1064                        ret = -EINVAL;
1065                        goto done;
1066                }
1067
1068                ret = media_create_pad_link(&sensor->entity, 0, input, pad,
1069                                            flags);
1070                if (ret < 0)
1071                        goto done;
1072        }
1073
1074        ret = v4l2_device_register_subdev_nodes(&iss->v4l2_dev);
1075
1076done:
1077        if (ret < 0)
1078                iss_unregister_entities(iss);
1079
1080        return ret;
1081}
1082
1083/*
1084 * iss_create_links() - Pads links creation for the subdevices
1085 * @iss : Pointer to ISS device
1086 *
1087 * return negative error code or zero on success
1088 */
1089static int iss_create_links(struct iss_device *iss)
1090{
1091        int ret;
1092
1093        ret = omap4iss_csi2_create_links(iss);
1094        if (ret < 0) {
1095                dev_err(iss->dev, "CSI2 pads links creation failed\n");
1096                return ret;
1097        }
1098
1099        ret = omap4iss_ipipeif_create_links(iss);
1100        if (ret < 0) {
1101                dev_err(iss->dev, "ISP IPIPEIF pads links creation failed\n");
1102                return ret;
1103        }
1104
1105        ret = omap4iss_resizer_create_links(iss);
1106        if (ret < 0) {
1107                dev_err(iss->dev, "ISP RESIZER pads links creation failed\n");
1108                return ret;
1109        }
1110
1111        /* Connect the submodules. */
1112        ret = media_create_pad_link(
1113                        &iss->csi2a.subdev.entity, CSI2_PAD_SOURCE,
1114                        &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SINK, 0);
1115        if (ret < 0)
1116                return ret;
1117
1118        ret = media_create_pad_link(
1119                        &iss->csi2b.subdev.entity, CSI2_PAD_SOURCE,
1120                        &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SINK, 0);
1121        if (ret < 0)
1122                return ret;
1123
1124        ret = media_create_pad_link(
1125                        &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SOURCE_VP,
1126                        &iss->resizer.subdev.entity, RESIZER_PAD_SINK, 0);
1127        if (ret < 0)
1128                return ret;
1129
1130        ret = media_create_pad_link(
1131                        &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SOURCE_VP,
1132                        &iss->ipipe.subdev.entity, IPIPE_PAD_SINK, 0);
1133        if (ret < 0)
1134                return ret;
1135
1136        ret = media_create_pad_link(
1137                        &iss->ipipe.subdev.entity, IPIPE_PAD_SOURCE_VP,
1138                        &iss->resizer.subdev.entity, RESIZER_PAD_SINK, 0);
1139        if (ret < 0)
1140                return ret;
1141
1142        return 0;
1143};
1144
1145static void iss_cleanup_modules(struct iss_device *iss)
1146{
1147        omap4iss_csi2_cleanup(iss);
1148        omap4iss_ipipeif_cleanup(iss);
1149        omap4iss_ipipe_cleanup(iss);
1150        omap4iss_resizer_cleanup(iss);
1151}
1152
1153static int iss_initialize_modules(struct iss_device *iss)
1154{
1155        int ret;
1156
1157        ret = omap4iss_csiphy_init(iss);
1158        if (ret < 0) {
1159                dev_err(iss->dev, "CSI PHY initialization failed\n");
1160                goto error_csiphy;
1161        }
1162
1163        ret = omap4iss_csi2_init(iss);
1164        if (ret < 0) {
1165                dev_err(iss->dev, "CSI2 initialization failed\n");
1166                goto error_csi2;
1167        }
1168
1169        ret = omap4iss_ipipeif_init(iss);
1170        if (ret < 0) {
1171                dev_err(iss->dev, "ISP IPIPEIF initialization failed\n");
1172                goto error_ipipeif;
1173        }
1174
1175        ret = omap4iss_ipipe_init(iss);
1176        if (ret < 0) {
1177                dev_err(iss->dev, "ISP IPIPE initialization failed\n");
1178                goto error_ipipe;
1179        }
1180
1181        ret = omap4iss_resizer_init(iss);
1182        if (ret < 0) {
1183                dev_err(iss->dev, "ISP RESIZER initialization failed\n");
1184                goto error_resizer;
1185        }
1186
1187        return 0;
1188
1189error_resizer:
1190        omap4iss_ipipe_cleanup(iss);
1191error_ipipe:
1192        omap4iss_ipipeif_cleanup(iss);
1193error_ipipeif:
1194        omap4iss_csi2_cleanup(iss);
1195error_csi2:
1196error_csiphy:
1197        return ret;
1198}
1199
1200static int iss_probe(struct platform_device *pdev)
1201{
1202        struct iss_platform_data *pdata = pdev->dev.platform_data;
1203        struct iss_device *iss;
1204        unsigned int i;
1205        int ret;
1206
1207        if (!pdata)
1208                return -EINVAL;
1209
1210        iss = devm_kzalloc(&pdev->dev, sizeof(*iss), GFP_KERNEL);
1211        if (!iss)
1212                return -ENOMEM;
1213
1214        mutex_init(&iss->iss_mutex);
1215
1216        iss->dev = &pdev->dev;
1217        iss->pdata = pdata;
1218
1219        iss->raw_dmamask = DMA_BIT_MASK(32);
1220        iss->dev->dma_mask = &iss->raw_dmamask;
1221        iss->dev->coherent_dma_mask = DMA_BIT_MASK(32);
1222
1223        platform_set_drvdata(pdev, iss);
1224
1225        /*
1226         * TODO: When implementing DT support switch to syscon regmap lookup by
1227         * phandle.
1228         */
1229        iss->syscon = syscon_regmap_lookup_by_compatible("syscon");
1230        if (IS_ERR(iss->syscon)) {
1231                ret = PTR_ERR(iss->syscon);
1232                goto error;
1233        }
1234
1235        /* Clocks */
1236        ret = iss_map_mem_resource(pdev, iss, OMAP4_ISS_MEM_TOP);
1237        if (ret < 0)
1238                goto error;
1239
1240        ret = iss_get_clocks(iss);
1241        if (ret < 0)
1242                goto error;
1243
1244        if (!omap4iss_get(iss)) {
1245                ret = -EINVAL;
1246                goto error;
1247        }
1248
1249        ret = iss_reset(iss);
1250        if (ret < 0)
1251                goto error_iss;
1252
1253        iss->revision = iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_HL_REVISION);
1254        dev_info(iss->dev, "Revision %08x found\n", iss->revision);
1255
1256        for (i = 1; i < OMAP4_ISS_MEM_LAST; i++) {
1257                ret = iss_map_mem_resource(pdev, iss, i);
1258                if (ret)
1259                        goto error_iss;
1260        }
1261
1262        /* Configure BTE BW_LIMITER field to max recommended value (1 GB) */
1263        iss_reg_update(iss, OMAP4_ISS_MEM_BTE, BTE_CTRL,
1264                       BTE_CTRL_BW_LIMITER_MASK,
1265                       18 << BTE_CTRL_BW_LIMITER_SHIFT);
1266
1267        /* Perform ISP reset */
1268        ret = omap4iss_subclk_enable(iss, OMAP4_ISS_SUBCLK_ISP);
1269        if (ret < 0)
1270                goto error_iss;
1271
1272        ret = iss_isp_reset(iss);
1273        if (ret < 0)
1274                goto error_iss;
1275
1276        dev_info(iss->dev, "ISP Revision %08x found\n",
1277                 iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_REVISION));
1278
1279        /* Interrupt */
1280        ret = platform_get_irq(pdev, 0);
1281        if (ret <= 0) {
1282                ret = -ENODEV;
1283                goto error_iss;
1284        }
1285        iss->irq_num = ret;
1286
1287        if (devm_request_irq(iss->dev, iss->irq_num, iss_isr, IRQF_SHARED,
1288                             "OMAP4 ISS", iss)) {
1289                dev_err(iss->dev, "Unable to request IRQ\n");
1290                ret = -EINVAL;
1291                goto error_iss;
1292        }
1293
1294        /* Entities */
1295        ret = iss_initialize_modules(iss);
1296        if (ret < 0)
1297                goto error_iss;
1298
1299        ret = iss_register_entities(iss);
1300        if (ret < 0)
1301                goto error_modules;
1302
1303        ret = media_entity_enum_init(&iss->crashed, &iss->media_dev);
1304        if (ret)
1305                goto error_entities;
1306
1307        ret = iss_create_links(iss);
1308        if (ret < 0)
1309                goto error_entities;
1310
1311        omap4iss_put(iss);
1312
1313        return 0;
1314
1315error_entities:
1316        iss_unregister_entities(iss);
1317        media_entity_enum_cleanup(&iss->crashed);
1318error_modules:
1319        iss_cleanup_modules(iss);
1320error_iss:
1321        omap4iss_put(iss);
1322error:
1323        mutex_destroy(&iss->iss_mutex);
1324
1325        return ret;
1326}
1327
1328static int iss_remove(struct platform_device *pdev)
1329{
1330        struct iss_device *iss = platform_get_drvdata(pdev);
1331
1332        iss_unregister_entities(iss);
1333        media_entity_enum_cleanup(&iss->crashed);
1334        iss_cleanup_modules(iss);
1335
1336        return 0;
1337}
1338
1339static const struct platform_device_id omap4iss_id_table[] = {
1340        { "omap4iss", 0 },
1341        { },
1342};
1343MODULE_DEVICE_TABLE(platform, omap4iss_id_table);
1344
1345static struct platform_driver iss_driver = {
1346        .probe          = iss_probe,
1347        .remove         = iss_remove,
1348        .id_table       = omap4iss_id_table,
1349        .driver = {
1350                .name   = "omap4iss",
1351        },
1352};
1353
1354module_platform_driver(iss_driver);
1355
1356MODULE_DESCRIPTION("TI OMAP4 ISS driver");
1357MODULE_AUTHOR("Sergio Aguirre <sergio.a.aguirre@gmail.com>");
1358MODULE_LICENSE("GPL");
1359