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