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