.. | .. |
---|
14 | 14 | #include <linux/of_graph.h> |
---|
15 | 15 | #include <linux/platform_device.h> |
---|
16 | 16 | #include <linux/pm_runtime.h> |
---|
| 17 | +#include <linux/reset.h> |
---|
17 | 18 | #include <linux/sys_soc.h> |
---|
18 | 19 | |
---|
19 | 20 | #include <media/v4l2-ctrls.h> |
---|
.. | .. |
---|
51 | 52 | |
---|
52 | 53 | /* |
---|
53 | 54 | * Channel Data Type Select |
---|
54 | | - * VCDT[0-15]: Channel 1 VCDT[16-31]: Channel 2 |
---|
55 | | - * VCDT2[0-15]: Channel 3 VCDT2[16-31]: Channel 4 |
---|
| 55 | + * VCDT[0-15]: Channel 0 VCDT[16-31]: Channel 1 |
---|
| 56 | + * VCDT2[0-15]: Channel 2 VCDT2[16-31]: Channel 3 |
---|
56 | 57 | */ |
---|
57 | 58 | #define VCDT_REG 0x10 |
---|
58 | 59 | #define VCDT2_REG 0x14 |
---|
.. | .. |
---|
67 | 68 | /* Field Detection Control */ |
---|
68 | 69 | #define FLD_REG 0x1c |
---|
69 | 70 | #define FLD_FLD_NUM(n) (((n) & 0xff) << 16) |
---|
| 71 | +#define FLD_DET_SEL(n) (((n) & 0x3) << 4) |
---|
70 | 72 | #define FLD_FLD_EN4 BIT(3) |
---|
71 | 73 | #define FLD_FLD_EN3 BIT(2) |
---|
72 | 74 | #define FLD_FLD_EN2 BIT(1) |
---|
.. | .. |
---|
83 | 85 | |
---|
84 | 86 | /* Interrupt Enable */ |
---|
85 | 87 | #define INTEN_REG 0x30 |
---|
| 88 | +#define INTEN_INT_AFIFO_OF BIT(27) |
---|
| 89 | +#define INTEN_INT_ERRSOTHS BIT(4) |
---|
| 90 | +#define INTEN_INT_ERRSOTSYNCHS BIT(3) |
---|
86 | 91 | |
---|
87 | 92 | /* Interrupt Source Mask */ |
---|
88 | 93 | #define INTCLOSE_REG 0x34 |
---|
.. | .. |
---|
315 | 320 | { .code = MEDIA_BUS_FMT_YUYV8_1X16, .datatype = 0x1e, .bpp = 16 }, |
---|
316 | 321 | { .code = MEDIA_BUS_FMT_UYVY8_2X8, .datatype = 0x1e, .bpp = 16 }, |
---|
317 | 322 | { .code = MEDIA_BUS_FMT_YUYV10_2X10, .datatype = 0x1e, .bpp = 20 }, |
---|
| 323 | + { .code = MEDIA_BUS_FMT_SBGGR8_1X8, .datatype = 0x2a, .bpp = 8 }, |
---|
| 324 | + { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .datatype = 0x2a, .bpp = 8 }, |
---|
| 325 | + { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .datatype = 0x2a, .bpp = 8 }, |
---|
| 326 | + { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .datatype = 0x2a, .bpp = 8 }, |
---|
318 | 327 | }; |
---|
319 | 328 | |
---|
320 | 329 | static const struct rcar_csi2_format *rcsi2_code_to_fmt(unsigned int code) |
---|
.. | .. |
---|
339 | 348 | |
---|
340 | 349 | struct rcar_csi2_info { |
---|
341 | 350 | int (*init_phtw)(struct rcar_csi2 *priv, unsigned int mbps); |
---|
342 | | - int (*confirm_start)(struct rcar_csi2 *priv); |
---|
| 351 | + int (*phy_post_init)(struct rcar_csi2 *priv); |
---|
343 | 352 | const struct rcsi2_mbps_reg *hsfreqrange; |
---|
344 | 353 | unsigned int csi0clkfreqrange; |
---|
| 354 | + unsigned int num_channels; |
---|
345 | 355 | bool clear_ulps; |
---|
346 | 356 | }; |
---|
347 | 357 | |
---|
.. | .. |
---|
349 | 359 | struct device *dev; |
---|
350 | 360 | void __iomem *base; |
---|
351 | 361 | const struct rcar_csi2_info *info; |
---|
| 362 | + struct reset_control *rstc; |
---|
352 | 363 | |
---|
353 | 364 | struct v4l2_subdev subdev; |
---|
354 | 365 | struct media_pad pads[NR_OF_RCAR_CSI2_PAD]; |
---|
355 | 366 | |
---|
356 | 367 | struct v4l2_async_notifier notifier; |
---|
357 | | - struct v4l2_async_subdev asd; |
---|
358 | 368 | struct v4l2_subdev *remote; |
---|
| 369 | + unsigned int remote_pad; |
---|
359 | 370 | |
---|
360 | 371 | struct v4l2_mbus_framefmt mf; |
---|
361 | 372 | |
---|
.. | .. |
---|
386 | 397 | iowrite32(data, priv->base + reg); |
---|
387 | 398 | } |
---|
388 | 399 | |
---|
389 | | -static void rcsi2_reset(struct rcar_csi2 *priv) |
---|
| 400 | +static void rcsi2_enter_standby(struct rcar_csi2 *priv) |
---|
390 | 401 | { |
---|
391 | | - rcsi2_write(priv, SRST_REG, SRST_SRST); |
---|
| 402 | + rcsi2_write(priv, PHYCNT_REG, 0); |
---|
| 403 | + rcsi2_write(priv, PHTC_REG, PHTC_TESTCLR); |
---|
| 404 | + reset_control_assert(priv->rstc); |
---|
392 | 405 | usleep_range(100, 150); |
---|
393 | | - rcsi2_write(priv, SRST_REG, 0); |
---|
| 406 | + pm_runtime_put(priv->dev); |
---|
394 | 407 | } |
---|
395 | 408 | |
---|
396 | | -static int rcsi2_wait_phy_start(struct rcar_csi2 *priv) |
---|
| 409 | +static void rcsi2_exit_standby(struct rcar_csi2 *priv) |
---|
| 410 | +{ |
---|
| 411 | + pm_runtime_get_sync(priv->dev); |
---|
| 412 | + reset_control_deassert(priv->rstc); |
---|
| 413 | +} |
---|
| 414 | + |
---|
| 415 | +static int rcsi2_wait_phy_start(struct rcar_csi2 *priv, |
---|
| 416 | + unsigned int lanes) |
---|
397 | 417 | { |
---|
398 | 418 | unsigned int timeout; |
---|
399 | 419 | |
---|
400 | 420 | /* Wait for the clock and data lanes to enter LP-11 state. */ |
---|
401 | 421 | for (timeout = 0; timeout <= 20; timeout++) { |
---|
402 | | - const u32 lane_mask = (1 << priv->lanes) - 1; |
---|
| 422 | + const u32 lane_mask = (1 << lanes) - 1; |
---|
403 | 423 | |
---|
404 | 424 | if ((rcsi2_read(priv, PHCLM_REG) & PHCLM_STOPSTATECKL) && |
---|
405 | 425 | (rcsi2_read(priv, PHDLM_REG) & lane_mask) == lane_mask) |
---|
.. | .. |
---|
438 | 458 | return 0; |
---|
439 | 459 | } |
---|
440 | 460 | |
---|
441 | | -static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp) |
---|
| 461 | +static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp, |
---|
| 462 | + unsigned int lanes) |
---|
442 | 463 | { |
---|
443 | 464 | struct v4l2_subdev *source; |
---|
444 | 465 | struct v4l2_ctrl *ctrl; |
---|
.. | .. |
---|
463 | 484 | * bps = link_freq * 2 |
---|
464 | 485 | */ |
---|
465 | 486 | mbps = v4l2_ctrl_g_ctrl_int64(ctrl) * bpp; |
---|
466 | | - do_div(mbps, priv->lanes * 1000000); |
---|
| 487 | + do_div(mbps, lanes * 1000000); |
---|
467 | 488 | |
---|
468 | 489 | return mbps; |
---|
469 | 490 | } |
---|
470 | 491 | |
---|
471 | | -static int rcsi2_start(struct rcar_csi2 *priv) |
---|
| 492 | +static int rcsi2_get_active_lanes(struct rcar_csi2 *priv, |
---|
| 493 | + unsigned int *lanes) |
---|
| 494 | +{ |
---|
| 495 | + struct v4l2_mbus_config mbus_config = { 0 }; |
---|
| 496 | + unsigned int num_lanes = UINT_MAX; |
---|
| 497 | + int ret; |
---|
| 498 | + |
---|
| 499 | + *lanes = priv->lanes; |
---|
| 500 | + |
---|
| 501 | + ret = v4l2_subdev_call(priv->remote, pad, get_mbus_config, |
---|
| 502 | + priv->remote_pad, &mbus_config); |
---|
| 503 | + if (ret == -ENOIOCTLCMD) { |
---|
| 504 | + dev_dbg(priv->dev, "No remote mbus configuration available\n"); |
---|
| 505 | + return 0; |
---|
| 506 | + } |
---|
| 507 | + |
---|
| 508 | + if (ret) { |
---|
| 509 | + dev_err(priv->dev, "Failed to get remote mbus configuration\n"); |
---|
| 510 | + return ret; |
---|
| 511 | + } |
---|
| 512 | + |
---|
| 513 | + if (mbus_config.type != V4L2_MBUS_CSI2_DPHY) { |
---|
| 514 | + dev_err(priv->dev, "Unsupported media bus type %u\n", |
---|
| 515 | + mbus_config.type); |
---|
| 516 | + return -EINVAL; |
---|
| 517 | + } |
---|
| 518 | + |
---|
| 519 | + if (mbus_config.flags & V4L2_MBUS_CSI2_1_LANE) |
---|
| 520 | + num_lanes = 1; |
---|
| 521 | + else if (mbus_config.flags & V4L2_MBUS_CSI2_2_LANE) |
---|
| 522 | + num_lanes = 2; |
---|
| 523 | + else if (mbus_config.flags & V4L2_MBUS_CSI2_3_LANE) |
---|
| 524 | + num_lanes = 3; |
---|
| 525 | + else if (mbus_config.flags & V4L2_MBUS_CSI2_4_LANE) |
---|
| 526 | + num_lanes = 4; |
---|
| 527 | + |
---|
| 528 | + if (num_lanes > priv->lanes) { |
---|
| 529 | + dev_err(priv->dev, |
---|
| 530 | + "Unsupported mbus config: too many data lanes %u\n", |
---|
| 531 | + num_lanes); |
---|
| 532 | + return -EINVAL; |
---|
| 533 | + } |
---|
| 534 | + |
---|
| 535 | + *lanes = num_lanes; |
---|
| 536 | + |
---|
| 537 | + return 0; |
---|
| 538 | +} |
---|
| 539 | + |
---|
| 540 | +static int rcsi2_start_receiver(struct rcar_csi2 *priv) |
---|
472 | 541 | { |
---|
473 | 542 | const struct rcar_csi2_format *format; |
---|
474 | | - u32 phycnt, vcdt = 0, vcdt2 = 0; |
---|
| 543 | + u32 phycnt, vcdt = 0, vcdt2 = 0, fld = 0; |
---|
| 544 | + unsigned int lanes; |
---|
475 | 545 | unsigned int i; |
---|
476 | 546 | int mbps, ret; |
---|
477 | 547 | |
---|
.. | .. |
---|
485 | 555 | return -EINVAL; |
---|
486 | 556 | |
---|
487 | 557 | /* |
---|
488 | | - * Enable all Virtual Channels. |
---|
| 558 | + * Enable all supported CSI-2 channels with virtual channel and |
---|
| 559 | + * data type matching. |
---|
489 | 560 | * |
---|
490 | 561 | * NOTE: It's not possible to get individual datatype for each |
---|
491 | 562 | * source virtual channel. Once this is possible in V4L2 |
---|
492 | 563 | * it should be used here. |
---|
493 | 564 | */ |
---|
494 | | - for (i = 0; i < 4; i++) { |
---|
| 565 | + for (i = 0; i < priv->info->num_channels; i++) { |
---|
495 | 566 | u32 vcdt_part; |
---|
496 | 567 | |
---|
497 | 568 | vcdt_part = VCDT_SEL_VC(i) | VCDT_VCDTN_EN | VCDT_SEL_DTN_ON | |
---|
.. | .. |
---|
504 | 575 | vcdt2 |= vcdt_part << ((i % 2) * 16); |
---|
505 | 576 | } |
---|
506 | 577 | |
---|
507 | | - phycnt = PHYCNT_ENABLECLK; |
---|
508 | | - phycnt |= (1 << priv->lanes) - 1; |
---|
| 578 | + if (priv->mf.field == V4L2_FIELD_ALTERNATE) { |
---|
| 579 | + fld = FLD_DET_SEL(1) | FLD_FLD_EN4 | FLD_FLD_EN3 | FLD_FLD_EN2 |
---|
| 580 | + | FLD_FLD_EN; |
---|
509 | 581 | |
---|
510 | | - mbps = rcsi2_calc_mbps(priv, format->bpp); |
---|
| 582 | + if (priv->mf.height == 240) |
---|
| 583 | + fld |= FLD_FLD_NUM(0); |
---|
| 584 | + else |
---|
| 585 | + fld |= FLD_FLD_NUM(1); |
---|
| 586 | + } |
---|
| 587 | + |
---|
| 588 | + /* |
---|
| 589 | + * Get the number of active data lanes inspecting the remote mbus |
---|
| 590 | + * configuration. |
---|
| 591 | + */ |
---|
| 592 | + ret = rcsi2_get_active_lanes(priv, &lanes); |
---|
| 593 | + if (ret) |
---|
| 594 | + return ret; |
---|
| 595 | + |
---|
| 596 | + phycnt = PHYCNT_ENABLECLK; |
---|
| 597 | + phycnt |= (1 << lanes) - 1; |
---|
| 598 | + |
---|
| 599 | + mbps = rcsi2_calc_mbps(priv, format->bpp, lanes); |
---|
511 | 600 | if (mbps < 0) |
---|
512 | 601 | return mbps; |
---|
513 | 602 | |
---|
| 603 | + /* Enable interrupts. */ |
---|
| 604 | + rcsi2_write(priv, INTEN_REG, INTEN_INT_AFIFO_OF | INTEN_INT_ERRSOTHS |
---|
| 605 | + | INTEN_INT_ERRSOTSYNCHS); |
---|
| 606 | + |
---|
514 | 607 | /* Init */ |
---|
515 | 608 | rcsi2_write(priv, TREF_REG, TREF_TREF); |
---|
516 | | - rcsi2_reset(priv); |
---|
517 | 609 | rcsi2_write(priv, PHTC_REG, 0); |
---|
518 | 610 | |
---|
519 | 611 | /* Configure */ |
---|
520 | | - rcsi2_write(priv, FLD_REG, FLD_FLD_NUM(2) | FLD_FLD_EN4 | |
---|
521 | | - FLD_FLD_EN3 | FLD_FLD_EN2 | FLD_FLD_EN); |
---|
522 | 612 | rcsi2_write(priv, VCDT_REG, vcdt); |
---|
523 | | - rcsi2_write(priv, VCDT2_REG, vcdt2); |
---|
| 613 | + if (vcdt2) |
---|
| 614 | + rcsi2_write(priv, VCDT2_REG, vcdt2); |
---|
524 | 615 | /* Lanes are zero indexed. */ |
---|
525 | 616 | rcsi2_write(priv, LSWAP_REG, |
---|
526 | 617 | LSWAP_L0SEL(priv->lane_swap[0] - 1) | |
---|
.. | .. |
---|
548 | 639 | rcsi2_write(priv, PHYCNT_REG, phycnt); |
---|
549 | 640 | rcsi2_write(priv, LINKCNT_REG, LINKCNT_MONITOR_EN | |
---|
550 | 641 | LINKCNT_REG_MONI_PACT_EN | LINKCNT_ICLK_NONSTOP); |
---|
| 642 | + rcsi2_write(priv, FLD_REG, fld); |
---|
551 | 643 | rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ); |
---|
552 | 644 | rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ | PHYCNT_RSTZ); |
---|
553 | 645 | |
---|
554 | | - ret = rcsi2_wait_phy_start(priv); |
---|
| 646 | + ret = rcsi2_wait_phy_start(priv, lanes); |
---|
555 | 647 | if (ret) |
---|
556 | 648 | return ret; |
---|
557 | 649 | |
---|
558 | | - /* Confirm start */ |
---|
559 | | - if (priv->info->confirm_start) { |
---|
560 | | - ret = priv->info->confirm_start(priv); |
---|
| 650 | + /* Run post PHY start initialization, if needed. */ |
---|
| 651 | + if (priv->info->phy_post_init) { |
---|
| 652 | + ret = priv->info->phy_post_init(priv); |
---|
561 | 653 | if (ret) |
---|
562 | 654 | return ret; |
---|
563 | 655 | } |
---|
.. | .. |
---|
570 | 662 | return 0; |
---|
571 | 663 | } |
---|
572 | 664 | |
---|
| 665 | +static int rcsi2_start(struct rcar_csi2 *priv) |
---|
| 666 | +{ |
---|
| 667 | + int ret; |
---|
| 668 | + |
---|
| 669 | + rcsi2_exit_standby(priv); |
---|
| 670 | + |
---|
| 671 | + ret = rcsi2_start_receiver(priv); |
---|
| 672 | + if (ret) { |
---|
| 673 | + rcsi2_enter_standby(priv); |
---|
| 674 | + return ret; |
---|
| 675 | + } |
---|
| 676 | + |
---|
| 677 | + ret = v4l2_subdev_call(priv->remote, video, s_stream, 1); |
---|
| 678 | + if (ret) { |
---|
| 679 | + rcsi2_enter_standby(priv); |
---|
| 680 | + return ret; |
---|
| 681 | + } |
---|
| 682 | + |
---|
| 683 | + return 0; |
---|
| 684 | +} |
---|
| 685 | + |
---|
573 | 686 | static void rcsi2_stop(struct rcar_csi2 *priv) |
---|
574 | 687 | { |
---|
575 | | - rcsi2_write(priv, PHYCNT_REG, 0); |
---|
576 | | - |
---|
577 | | - rcsi2_reset(priv); |
---|
578 | | - |
---|
579 | | - rcsi2_write(priv, PHTC_REG, PHTC_TESTCLR); |
---|
| 688 | + rcsi2_enter_standby(priv); |
---|
| 689 | + v4l2_subdev_call(priv->remote, video, s_stream, 0); |
---|
580 | 690 | } |
---|
581 | 691 | |
---|
582 | 692 | static int rcsi2_s_stream(struct v4l2_subdev *sd, int enable) |
---|
583 | 693 | { |
---|
584 | 694 | struct rcar_csi2 *priv = sd_to_csi2(sd); |
---|
585 | | - struct v4l2_subdev *nextsd; |
---|
586 | 695 | int ret = 0; |
---|
587 | 696 | |
---|
588 | 697 | mutex_lock(&priv->lock); |
---|
.. | .. |
---|
592 | 701 | goto out; |
---|
593 | 702 | } |
---|
594 | 703 | |
---|
595 | | - nextsd = priv->remote; |
---|
596 | | - |
---|
597 | 704 | if (enable && priv->stream_count == 0) { |
---|
598 | | - pm_runtime_get_sync(priv->dev); |
---|
599 | | - |
---|
600 | 705 | ret = rcsi2_start(priv); |
---|
601 | | - if (ret) { |
---|
602 | | - pm_runtime_put(priv->dev); |
---|
| 706 | + if (ret) |
---|
603 | 707 | goto out; |
---|
604 | | - } |
---|
605 | | - |
---|
606 | | - ret = v4l2_subdev_call(nextsd, video, s_stream, 1); |
---|
607 | | - if (ret) { |
---|
608 | | - rcsi2_stop(priv); |
---|
609 | | - pm_runtime_put(priv->dev); |
---|
610 | | - goto out; |
---|
611 | | - } |
---|
612 | 708 | } else if (!enable && priv->stream_count == 1) { |
---|
613 | 709 | rcsi2_stop(priv); |
---|
614 | | - v4l2_subdev_call(nextsd, video, s_stream, 0); |
---|
615 | | - pm_runtime_put(priv->dev); |
---|
616 | 710 | } |
---|
617 | 711 | |
---|
618 | 712 | priv->stream_count += enable ? 1 : -1; |
---|
.. | .. |
---|
670 | 764 | .pad = &rcar_csi2_pad_ops, |
---|
671 | 765 | }; |
---|
672 | 766 | |
---|
| 767 | +static irqreturn_t rcsi2_irq(int irq, void *data) |
---|
| 768 | +{ |
---|
| 769 | + struct rcar_csi2 *priv = data; |
---|
| 770 | + u32 status, err_status; |
---|
| 771 | + |
---|
| 772 | + status = rcsi2_read(priv, INTSTATE_REG); |
---|
| 773 | + err_status = rcsi2_read(priv, INTERRSTATE_REG); |
---|
| 774 | + |
---|
| 775 | + if (!status) |
---|
| 776 | + return IRQ_HANDLED; |
---|
| 777 | + |
---|
| 778 | + rcsi2_write(priv, INTSTATE_REG, status); |
---|
| 779 | + |
---|
| 780 | + if (!err_status) |
---|
| 781 | + return IRQ_HANDLED; |
---|
| 782 | + |
---|
| 783 | + rcsi2_write(priv, INTERRSTATE_REG, err_status); |
---|
| 784 | + |
---|
| 785 | + dev_info(priv->dev, "Transfer error, restarting CSI-2 receiver\n"); |
---|
| 786 | + |
---|
| 787 | + return IRQ_WAKE_THREAD; |
---|
| 788 | +} |
---|
| 789 | + |
---|
| 790 | +static irqreturn_t rcsi2_irq_thread(int irq, void *data) |
---|
| 791 | +{ |
---|
| 792 | + struct rcar_csi2 *priv = data; |
---|
| 793 | + |
---|
| 794 | + mutex_lock(&priv->lock); |
---|
| 795 | + rcsi2_stop(priv); |
---|
| 796 | + usleep_range(1000, 2000); |
---|
| 797 | + if (rcsi2_start(priv)) |
---|
| 798 | + dev_warn(priv->dev, "Failed to restart CSI-2 receiver\n"); |
---|
| 799 | + mutex_unlock(&priv->lock); |
---|
| 800 | + |
---|
| 801 | + return IRQ_HANDLED; |
---|
| 802 | +} |
---|
| 803 | + |
---|
673 | 804 | /* ----------------------------------------------------------------------------- |
---|
674 | 805 | * Async handling and registration of subdevices and links. |
---|
675 | 806 | */ |
---|
.. | .. |
---|
689 | 820 | } |
---|
690 | 821 | |
---|
691 | 822 | priv->remote = subdev; |
---|
| 823 | + priv->remote_pad = pad; |
---|
692 | 824 | |
---|
693 | 825 | dev_dbg(priv->dev, "Bound %s pad: %d\n", subdev->name, pad); |
---|
694 | 826 | |
---|
.. | .. |
---|
723 | 855 | if (vep->base.port || vep->base.id) |
---|
724 | 856 | return -ENOTCONN; |
---|
725 | 857 | |
---|
726 | | - if (vep->bus_type != V4L2_MBUS_CSI2) { |
---|
| 858 | + if (vep->bus_type != V4L2_MBUS_CSI2_DPHY) { |
---|
727 | 859 | dev_err(priv->dev, "Unsupported bus: %u\n", vep->bus_type); |
---|
728 | 860 | return -EINVAL; |
---|
729 | 861 | } |
---|
.. | .. |
---|
751 | 883 | |
---|
752 | 884 | static int rcsi2_parse_dt(struct rcar_csi2 *priv) |
---|
753 | 885 | { |
---|
| 886 | + struct v4l2_async_subdev *asd; |
---|
| 887 | + struct fwnode_handle *fwnode; |
---|
754 | 888 | struct device_node *ep; |
---|
755 | | - struct v4l2_fwnode_endpoint v4l2_ep; |
---|
| 889 | + struct v4l2_fwnode_endpoint v4l2_ep = { .bus_type = 0 }; |
---|
756 | 890 | int ret; |
---|
757 | 891 | |
---|
758 | 892 | ep = of_graph_get_endpoint_by_regs(priv->dev->of_node, 0, 0); |
---|
.. | .. |
---|
774 | 908 | return ret; |
---|
775 | 909 | } |
---|
776 | 910 | |
---|
777 | | - priv->asd.match.fwnode = |
---|
778 | | - fwnode_graph_get_remote_endpoint(of_fwnode_handle(ep)); |
---|
779 | | - priv->asd.match_type = V4L2_ASYNC_MATCH_FWNODE; |
---|
780 | | - |
---|
| 911 | + fwnode = fwnode_graph_get_remote_endpoint(of_fwnode_handle(ep)); |
---|
781 | 912 | of_node_put(ep); |
---|
782 | 913 | |
---|
783 | | - priv->notifier.subdevs = devm_kzalloc(priv->dev, |
---|
784 | | - sizeof(*priv->notifier.subdevs), |
---|
785 | | - GFP_KERNEL); |
---|
786 | | - if (!priv->notifier.subdevs) |
---|
787 | | - return -ENOMEM; |
---|
| 914 | + dev_dbg(priv->dev, "Found '%pOF'\n", to_of_node(fwnode)); |
---|
788 | 915 | |
---|
789 | | - priv->notifier.num_subdevs = 1; |
---|
790 | | - priv->notifier.subdevs[0] = &priv->asd; |
---|
| 916 | + v4l2_async_notifier_init(&priv->notifier); |
---|
791 | 917 | priv->notifier.ops = &rcar_csi2_notify_ops; |
---|
792 | 918 | |
---|
793 | | - dev_dbg(priv->dev, "Found '%pOF'\n", |
---|
794 | | - to_of_node(priv->asd.match.fwnode)); |
---|
| 919 | + asd = v4l2_async_notifier_add_fwnode_subdev(&priv->notifier, fwnode, |
---|
| 920 | + sizeof(*asd)); |
---|
| 921 | + fwnode_handle_put(fwnode); |
---|
| 922 | + if (IS_ERR(asd)) |
---|
| 923 | + return PTR_ERR(asd); |
---|
795 | 924 | |
---|
796 | | - return v4l2_async_subdev_notifier_register(&priv->subdev, |
---|
797 | | - &priv->notifier); |
---|
| 925 | + ret = v4l2_async_subdev_notifier_register(&priv->subdev, |
---|
| 926 | + &priv->notifier); |
---|
| 927 | + if (ret) |
---|
| 928 | + v4l2_async_notifier_cleanup(&priv->notifier); |
---|
| 929 | + |
---|
| 930 | + return ret; |
---|
798 | 931 | } |
---|
799 | 932 | |
---|
800 | 933 | /* ----------------------------------------------------------------------------- |
---|
.. | .. |
---|
863 | 996 | return rcsi2_phtw_write(priv, value->reg, code); |
---|
864 | 997 | } |
---|
865 | 998 | |
---|
866 | | -static int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps) |
---|
| 999 | +static int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, |
---|
| 1000 | + unsigned int mbps) |
---|
867 | 1001 | { |
---|
868 | 1002 | static const struct phtw_value step1[] = { |
---|
869 | 1003 | { .data = 0xcc, .code = 0xe2 }, |
---|
.. | .. |
---|
889 | 1023 | if (ret) |
---|
890 | 1024 | return ret; |
---|
891 | 1025 | |
---|
892 | | - if (mbps <= 250) { |
---|
| 1026 | + if (mbps != 0 && mbps <= 250) { |
---|
893 | 1027 | ret = rcsi2_phtw_write(priv, 0x39, 0x05); |
---|
894 | 1028 | if (ret) |
---|
895 | 1029 | return ret; |
---|
.. | .. |
---|
903 | 1037 | return rcsi2_phtw_write_array(priv, step2); |
---|
904 | 1038 | } |
---|
905 | 1039 | |
---|
| 1040 | +static int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps) |
---|
| 1041 | +{ |
---|
| 1042 | + return __rcsi2_init_phtw_h3_v3h_m3n(priv, mbps); |
---|
| 1043 | +} |
---|
| 1044 | + |
---|
| 1045 | +static int rcsi2_init_phtw_h3es2(struct rcar_csi2 *priv, unsigned int mbps) |
---|
| 1046 | +{ |
---|
| 1047 | + return __rcsi2_init_phtw_h3_v3h_m3n(priv, 0); |
---|
| 1048 | +} |
---|
| 1049 | + |
---|
906 | 1050 | static int rcsi2_init_phtw_v3m_e3(struct rcar_csi2 *priv, unsigned int mbps) |
---|
907 | 1051 | { |
---|
908 | 1052 | return rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_v3m_e3, 0x44); |
---|
909 | 1053 | } |
---|
910 | 1054 | |
---|
911 | | -static int rcsi2_confirm_start_v3m_e3(struct rcar_csi2 *priv) |
---|
| 1055 | +static int rcsi2_phy_post_init_v3m_e3(struct rcar_csi2 *priv) |
---|
912 | 1056 | { |
---|
913 | 1057 | static const struct phtw_value step1[] = { |
---|
914 | | - { .data = 0xed, .code = 0x34 }, |
---|
915 | | - { .data = 0xed, .code = 0x44 }, |
---|
916 | | - { .data = 0xed, .code = 0x54 }, |
---|
917 | | - { .data = 0xed, .code = 0x84 }, |
---|
918 | | - { .data = 0xed, .code = 0x94 }, |
---|
| 1058 | + { .data = 0xee, .code = 0x34 }, |
---|
| 1059 | + { .data = 0xee, .code = 0x44 }, |
---|
| 1060 | + { .data = 0xee, .code = 0x54 }, |
---|
| 1061 | + { .data = 0xee, .code = 0x84 }, |
---|
| 1062 | + { .data = 0xee, .code = 0x94 }, |
---|
919 | 1063 | { /* sentinel */ }, |
---|
920 | 1064 | }; |
---|
921 | 1065 | |
---|
.. | .. |
---|
934 | 1078 | struct platform_device *pdev) |
---|
935 | 1079 | { |
---|
936 | 1080 | struct resource *res; |
---|
937 | | - int irq; |
---|
| 1081 | + int irq, ret; |
---|
938 | 1082 | |
---|
939 | 1083 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
940 | 1084 | priv->base = devm_ioremap_resource(&pdev->dev, res); |
---|
.. | .. |
---|
945 | 1089 | if (irq < 0) |
---|
946 | 1090 | return irq; |
---|
947 | 1091 | |
---|
948 | | - return 0; |
---|
| 1092 | + ret = devm_request_threaded_irq(&pdev->dev, irq, rcsi2_irq, |
---|
| 1093 | + rcsi2_irq_thread, IRQF_SHARED, |
---|
| 1094 | + KBUILD_MODNAME, priv); |
---|
| 1095 | + if (ret) |
---|
| 1096 | + return ret; |
---|
| 1097 | + |
---|
| 1098 | + priv->rstc = devm_reset_control_get(&pdev->dev, NULL); |
---|
| 1099 | + |
---|
| 1100 | + return PTR_ERR_OR_ZERO(priv->rstc); |
---|
949 | 1101 | } |
---|
950 | 1102 | |
---|
951 | 1103 | static const struct rcar_csi2_info rcar_csi2_info_r8a7795 = { |
---|
952 | 1104 | .init_phtw = rcsi2_init_phtw_h3_v3h_m3n, |
---|
953 | 1105 | .hsfreqrange = hsfreqrange_h3_v3h_m3n, |
---|
954 | 1106 | .csi0clkfreqrange = 0x20, |
---|
| 1107 | + .num_channels = 4, |
---|
955 | 1108 | .clear_ulps = true, |
---|
956 | 1109 | }; |
---|
957 | 1110 | |
---|
958 | 1111 | static const struct rcar_csi2_info rcar_csi2_info_r8a7795es1 = { |
---|
959 | 1112 | .hsfreqrange = hsfreqrange_m3w_h3es1, |
---|
| 1113 | + .num_channels = 4, |
---|
| 1114 | +}; |
---|
| 1115 | + |
---|
| 1116 | +static const struct rcar_csi2_info rcar_csi2_info_r8a7795es2 = { |
---|
| 1117 | + .init_phtw = rcsi2_init_phtw_h3es2, |
---|
| 1118 | + .hsfreqrange = hsfreqrange_h3_v3h_m3n, |
---|
| 1119 | + .csi0clkfreqrange = 0x20, |
---|
| 1120 | + .num_channels = 4, |
---|
| 1121 | + .clear_ulps = true, |
---|
960 | 1122 | }; |
---|
961 | 1123 | |
---|
962 | 1124 | static const struct rcar_csi2_info rcar_csi2_info_r8a7796 = { |
---|
963 | 1125 | .hsfreqrange = hsfreqrange_m3w_h3es1, |
---|
| 1126 | + .num_channels = 4, |
---|
964 | 1127 | }; |
---|
965 | 1128 | |
---|
966 | 1129 | static const struct rcar_csi2_info rcar_csi2_info_r8a77965 = { |
---|
967 | 1130 | .init_phtw = rcsi2_init_phtw_h3_v3h_m3n, |
---|
968 | 1131 | .hsfreqrange = hsfreqrange_h3_v3h_m3n, |
---|
969 | 1132 | .csi0clkfreqrange = 0x20, |
---|
| 1133 | + .num_channels = 4, |
---|
970 | 1134 | .clear_ulps = true, |
---|
971 | 1135 | }; |
---|
972 | 1136 | |
---|
973 | 1137 | static const struct rcar_csi2_info rcar_csi2_info_r8a77970 = { |
---|
974 | 1138 | .init_phtw = rcsi2_init_phtw_v3m_e3, |
---|
975 | | - .confirm_start = rcsi2_confirm_start_v3m_e3, |
---|
| 1139 | + .phy_post_init = rcsi2_phy_post_init_v3m_e3, |
---|
| 1140 | + .num_channels = 4, |
---|
| 1141 | +}; |
---|
| 1142 | + |
---|
| 1143 | +static const struct rcar_csi2_info rcar_csi2_info_r8a77980 = { |
---|
| 1144 | + .init_phtw = rcsi2_init_phtw_h3_v3h_m3n, |
---|
| 1145 | + .hsfreqrange = hsfreqrange_h3_v3h_m3n, |
---|
| 1146 | + .csi0clkfreqrange = 0x20, |
---|
| 1147 | + .clear_ulps = true, |
---|
| 1148 | +}; |
---|
| 1149 | + |
---|
| 1150 | +static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = { |
---|
| 1151 | + .init_phtw = rcsi2_init_phtw_v3m_e3, |
---|
| 1152 | + .phy_post_init = rcsi2_phy_post_init_v3m_e3, |
---|
| 1153 | + .num_channels = 2, |
---|
976 | 1154 | }; |
---|
977 | 1155 | |
---|
978 | 1156 | static const struct of_device_id rcar_csi2_of_table[] = { |
---|
| 1157 | + { |
---|
| 1158 | + .compatible = "renesas,r8a774a1-csi2", |
---|
| 1159 | + .data = &rcar_csi2_info_r8a7796, |
---|
| 1160 | + }, |
---|
| 1161 | + { |
---|
| 1162 | + .compatible = "renesas,r8a774b1-csi2", |
---|
| 1163 | + .data = &rcar_csi2_info_r8a77965, |
---|
| 1164 | + }, |
---|
| 1165 | + { |
---|
| 1166 | + .compatible = "renesas,r8a774c0-csi2", |
---|
| 1167 | + .data = &rcar_csi2_info_r8a77990, |
---|
| 1168 | + }, |
---|
| 1169 | + { |
---|
| 1170 | + .compatible = "renesas,r8a774e1-csi2", |
---|
| 1171 | + .data = &rcar_csi2_info_r8a7795, |
---|
| 1172 | + }, |
---|
979 | 1173 | { |
---|
980 | 1174 | .compatible = "renesas,r8a7795-csi2", |
---|
981 | 1175 | .data = &rcar_csi2_info_r8a7795, |
---|
.. | .. |
---|
992 | 1186 | .compatible = "renesas,r8a77970-csi2", |
---|
993 | 1187 | .data = &rcar_csi2_info_r8a77970, |
---|
994 | 1188 | }, |
---|
| 1189 | + { |
---|
| 1190 | + .compatible = "renesas,r8a77980-csi2", |
---|
| 1191 | + .data = &rcar_csi2_info_r8a77980, |
---|
| 1192 | + }, |
---|
| 1193 | + { |
---|
| 1194 | + .compatible = "renesas,r8a77990-csi2", |
---|
| 1195 | + .data = &rcar_csi2_info_r8a77990, |
---|
| 1196 | + }, |
---|
995 | 1197 | { /* sentinel */ }, |
---|
996 | 1198 | }; |
---|
997 | 1199 | MODULE_DEVICE_TABLE(of, rcar_csi2_of_table); |
---|
998 | 1200 | |
---|
999 | | -static const struct soc_device_attribute r8a7795es1[] = { |
---|
| 1201 | +static const struct soc_device_attribute r8a7795[] = { |
---|
1000 | 1202 | { |
---|
1001 | 1203 | .soc_id = "r8a7795", .revision = "ES1.*", |
---|
1002 | 1204 | .data = &rcar_csi2_info_r8a7795es1, |
---|
| 1205 | + }, |
---|
| 1206 | + { |
---|
| 1207 | + .soc_id = "r8a7795", .revision = "ES2.*", |
---|
| 1208 | + .data = &rcar_csi2_info_r8a7795es2, |
---|
1003 | 1209 | }, |
---|
1004 | 1210 | { /* sentinel */ }, |
---|
1005 | 1211 | }; |
---|
.. | .. |
---|
1018 | 1224 | priv->info = of_device_get_match_data(&pdev->dev); |
---|
1019 | 1225 | |
---|
1020 | 1226 | /* |
---|
1021 | | - * r8a7795 ES1.x behaves differently than the ES2.0+ but doesn't |
---|
1022 | | - * have it's own compatible string. |
---|
| 1227 | + * The different ES versions of r8a7795 (H3) behave differently but |
---|
| 1228 | + * share the same compatible string. |
---|
1023 | 1229 | */ |
---|
1024 | | - attr = soc_device_match(r8a7795es1); |
---|
| 1230 | + attr = soc_device_match(r8a7795); |
---|
1025 | 1231 | if (attr) |
---|
1026 | 1232 | priv->info = attr->data; |
---|
1027 | 1233 | |
---|