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