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