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