.. | .. |
---|
8 | 8 | * V0.0X01.0X01 fix set vflip/hflip failed bug. |
---|
9 | 9 | */ |
---|
10 | 10 | |
---|
| 11 | +//#define DEBUG |
---|
11 | 12 | #include <linux/clk.h> |
---|
12 | 13 | #include <linux/device.h> |
---|
13 | 14 | #include <linux/delay.h> |
---|
.. | .. |
---|
42 | 43 | #include <linux/printk.h> |
---|
43 | 44 | |
---|
44 | 45 | #include <linux/rk-camera-module.h> |
---|
| 46 | +#include "../platform/rockchip/isp/rkisp_tb_helper.h" |
---|
45 | 47 | #define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x01) |
---|
46 | 48 | |
---|
47 | 49 | #ifndef V4L2_CID_DIGITAL_GAIN |
---|
.. | .. |
---|
51 | 53 | #define SC530AI_LINK_FREQ_396M 198000000 // 396Mbps |
---|
52 | 54 | #define SC530AI_LINK_FREQ_792M 396000000 // 792Mbps |
---|
53 | 55 | #define SC530AI_LINK_FREQ_792M_2LANE 396000000 // 792Mbps |
---|
| 56 | +#define SC530AI_LINK_FREQ_936M_2LANE 468000000 // 936Mbps |
---|
54 | 57 | |
---|
55 | 58 | #define SC530AI_LINEAR_PIXEL_RATES (SC530AI_LINK_FREQ_396M / 10 * 2 * 4) |
---|
56 | 59 | #define SC530AI_HDR_PIXEL_RATES (SC530AI_LINK_FREQ_792M / 10 * 2 * 4) |
---|
.. | .. |
---|
59 | 62 | |
---|
60 | 63 | #define SC530AI_XVCLK_FREQ 27000000 |
---|
61 | 64 | |
---|
62 | | -#define SC530AI_CHIP_ID 0x9e39 |
---|
| 65 | +#define SC530AI_CHIP_ID 0x8e39 |
---|
63 | 66 | #define SC530AI_REG_CHIP_ID 0x3107 |
---|
64 | 67 | |
---|
65 | 68 | #define SC530AI_REG_CTRL_MODE 0x0100 |
---|
.. | .. |
---|
77 | 80 | #define SC530AI_REG_DIG_FINE_GAIN 0x3e07 |
---|
78 | 81 | #define SC530AI_REG_ANA_GAIN 0x3e09 |
---|
79 | 82 | |
---|
80 | | -#define SC530AI_GAIN_MIN 0x800 |
---|
81 | | -#define SC530AI_GAIN_MAX 0xa3300 |
---|
| 83 | +#define SC530AI_GAIN_MIN 0x20 |
---|
| 84 | +#define SC530AI_GAIN_MAX (32 * 326) |
---|
82 | 85 | #define SC530AI_GAIN_STEP 1 |
---|
83 | | -#define SC530AI_GAIN_DEFAULT 0x800 |
---|
| 86 | +#define SC530AI_GAIN_DEFAULT 0x20 |
---|
84 | 87 | |
---|
85 | 88 | #define SC530AI_REG_VTS_H 0x320e |
---|
86 | 89 | #define SC530AI_REG_VTS_L 0x320f |
---|
.. | .. |
---|
139 | 142 | |
---|
140 | 143 | #define sc530ai_NUM_SUPPLIES ARRAY_SIZE(sc530ai_supply_names) |
---|
141 | 144 | |
---|
142 | | -enum sc530ai_max_pad { |
---|
143 | | - PAD0, /* link to isp */ |
---|
144 | | - PAD1, /* link to csi wr0 | hdr x2:L x3:M */ |
---|
145 | | - PAD2, /* link to csi wr1 | hdr x3:L */ |
---|
146 | | - PAD3, /* link to csi wr2 | hdr x2:M x3:S */ |
---|
147 | | - PAD_MAX, |
---|
148 | | -}; |
---|
149 | | - |
---|
150 | 145 | struct regval { |
---|
151 | 146 | u16 addr; |
---|
152 | 147 | u8 val; |
---|
.. | .. |
---|
177 | 172 | struct pinctrl *pinctrl; |
---|
178 | 173 | struct pinctrl_state *pins_default; |
---|
179 | 174 | struct pinctrl_state *pins_sleep; |
---|
180 | | - |
---|
| 175 | + struct v4l2_fract cur_fps; |
---|
| 176 | + u32 cur_vts; |
---|
181 | 177 | struct v4l2_subdev subdev; |
---|
182 | 178 | struct media_pad pad; |
---|
183 | 179 | struct v4l2_ctrl_handler ctrl_handler; |
---|
.. | .. |
---|
191 | 187 | struct mutex mutex; |
---|
192 | 188 | bool streaming; |
---|
193 | 189 | bool power_on; |
---|
| 190 | + const struct sc530ai_mode *support_modes; |
---|
194 | 191 | const struct sc530ai_mode *cur_mode; |
---|
| 192 | + u32 support_modes_num; |
---|
195 | 193 | unsigned int lane_num; |
---|
196 | 194 | u32 module_index; |
---|
197 | 195 | const char *module_facing; |
---|
198 | 196 | const char *module_name; |
---|
199 | 197 | const char *len_name; |
---|
200 | 198 | bool has_init_exp; |
---|
| 199 | + bool is_thunderboot; |
---|
| 200 | + bool is_first_streamoff; |
---|
201 | 201 | struct preisp_hdrae_exp_s init_hdrae_exp; |
---|
202 | 202 | }; |
---|
203 | 203 | |
---|
.. | .. |
---|
208 | 208 | * max_framerate 30fps |
---|
209 | 209 | * mipi_datarate per lane 1008Mbps, 4lane |
---|
210 | 210 | */ |
---|
211 | | -static const struct regval sc530ai_linear_10_30fps_2880x1620_regs[] = { |
---|
| 211 | +static const struct regval sc530ai_linear_10_30fps_2880x1620_4lane_regs[] = { |
---|
212 | 212 | {0x0103, 0x01}, |
---|
213 | 213 | {0x0100, 0x00}, |
---|
214 | 214 | {0x36e9, 0x80}, |
---|
.. | .. |
---|
317 | 317 | {0x3e02, 0xa0}, |
---|
318 | 318 | {0x440e, 0x02}, |
---|
319 | 319 | {0x4509, 0x20}, |
---|
| 320 | + {0x4800, 0x04}, |
---|
320 | 321 | {0x4837, 0x28}, |
---|
321 | 322 | {0x5010, 0x10}, |
---|
322 | 323 | {0x5799, 0x06}, |
---|
.. | .. |
---|
356 | 357 | {REG_NULL, 0x00}, |
---|
357 | 358 | }; |
---|
358 | 359 | |
---|
359 | | -static const struct regval sc530ai_hdr_10_30fps_2880x1620_regs[] = { |
---|
| 360 | +static const struct regval sc530ai_hdr_10_30fps_2880x1620_4lane_regs[] = { |
---|
360 | 361 | {0x0103, 0x01}, |
---|
361 | 362 | {0x0100, 0x00}, |
---|
362 | 363 | {0x36e9, 0x80}, |
---|
.. | .. |
---|
471 | 472 | {0x3e24, 0xc8}, |
---|
472 | 473 | {0x440e, 0x02}, |
---|
473 | 474 | {0x4509, 0x20}, |
---|
| 475 | + {0x4800, 0x04}, |
---|
474 | 476 | {0x4816, 0x11}, |
---|
475 | 477 | {0x5010, 0x10}, |
---|
476 | 478 | {0x5799, 0x06}, |
---|
.. | .. |
---|
522 | 524 | {0x37f9, 0x80}, |
---|
523 | 525 | {0x3018, 0x32}, |
---|
524 | 526 | {0x3019, 0x0c}, |
---|
525 | | - {0x301f, 0x18}, |
---|
| 527 | + {0x301f, 0x42}, |
---|
| 528 | + {0x320c, 0x06}, |
---|
| 529 | + {0x320d, 0x27}, |
---|
| 530 | + {0x320e, 0x07}, |
---|
| 531 | + {0x320f, 0xbc}, |
---|
526 | 532 | {0x3250, 0x40}, |
---|
527 | 533 | {0x3251, 0x98}, |
---|
528 | 534 | {0x3253, 0x0c}, |
---|
529 | 535 | {0x325f, 0x20}, |
---|
530 | 536 | {0x3301, 0x08}, |
---|
531 | 537 | {0x3304, 0x50}, |
---|
532 | | - {0x3306, 0x78}, |
---|
| 538 | + {0x3306, 0x88}, |
---|
533 | 539 | {0x3308, 0x14}, |
---|
534 | 540 | {0x3309, 0x70}, |
---|
535 | 541 | {0x330a, 0x00}, |
---|
536 | | - {0x330b, 0xd8}, |
---|
| 542 | + {0x330b, 0xf8}, |
---|
537 | 543 | {0x330d, 0x10}, |
---|
538 | 544 | {0x331e, 0x41}, |
---|
539 | 545 | {0x331f, 0x61}, |
---|
.. | .. |
---|
562 | 568 | {0x33ae, 0x30}, |
---|
563 | 569 | {0x33af, 0x50}, |
---|
564 | 570 | {0x33b1, 0x80}, |
---|
565 | | - {0x33b2, 0x80}, |
---|
566 | | - {0x33b3, 0x40}, |
---|
| 571 | + {0x33b2, 0x48}, |
---|
| 572 | + {0x33b3, 0x30}, |
---|
567 | 573 | {0x349f, 0x02}, |
---|
568 | 574 | {0x34a6, 0x48}, |
---|
569 | | - {0x34a7, 0x49}, |
---|
570 | | - {0x34a8, 0x40}, |
---|
571 | | - {0x34a9, 0x30}, |
---|
572 | | - {0x34f8, 0x4b}, |
---|
573 | | - {0x34f9, 0x30}, |
---|
| 575 | + {0x34a7, 0x4b}, |
---|
| 576 | + {0x34a8, 0x30}, |
---|
| 577 | + {0x34a9, 0x18}, |
---|
| 578 | + {0x34f8, 0x5f}, |
---|
| 579 | + {0x34f9, 0x08}, |
---|
574 | 580 | {0x3632, 0x48}, |
---|
575 | 581 | {0x3633, 0x32}, |
---|
576 | | - {0x3637, 0x2b}, |
---|
| 582 | + {0x3637, 0x29}, |
---|
577 | 583 | {0x3638, 0xc1}, |
---|
578 | 584 | {0x363b, 0x20}, |
---|
579 | 585 | {0x363d, 0x02}, |
---|
.. | .. |
---|
584 | 590 | {0x367c, 0x40}, |
---|
585 | 591 | {0x367d, 0x48}, |
---|
586 | 592 | {0x3690, 0x32}, |
---|
587 | | - {0x3691, 0x32}, |
---|
| 593 | + {0x3691, 0x43}, |
---|
588 | 594 | {0x3692, 0x33}, |
---|
589 | 595 | {0x3693, 0x40}, |
---|
590 | 596 | {0x3694, 0x4b}, |
---|
.. | .. |
---|
596 | 602 | {0x36a3, 0x4b}, |
---|
597 | 603 | {0x36a4, 0x4f}, |
---|
598 | 604 | {0x36d0, 0x01}, |
---|
| 605 | + {0x36ea, 0x0d}, |
---|
| 606 | + {0x36eb, 0x04}, |
---|
599 | 607 | {0x36ec, 0x03}, |
---|
| 608 | + {0x36ed, 0x14}, |
---|
600 | 609 | {0x370f, 0x01}, |
---|
601 | 610 | {0x3722, 0x00}, |
---|
602 | 611 | {0x3728, 0x10}, |
---|
.. | .. |
---|
605 | 614 | {0x37b2, 0x83}, |
---|
606 | 615 | {0x37b3, 0x48}, |
---|
607 | 616 | {0x37b4, 0x49}, |
---|
608 | | - {0x37fb, 0x25}, |
---|
| 617 | + {0x37fa, 0x0d}, |
---|
| 618 | + {0x37fb, 0x24}, |
---|
609 | 619 | {0x37fc, 0x01}, |
---|
| 620 | + {0x37fd, 0x14}, |
---|
610 | 621 | {0x3901, 0x00}, |
---|
611 | 622 | {0x3902, 0xc5}, |
---|
612 | 623 | {0x3904, 0x08}, |
---|
.. | .. |
---|
616 | 627 | {0x391f, 0x44}, |
---|
617 | 628 | {0x3926, 0x21}, |
---|
618 | 629 | {0x3929, 0x18}, |
---|
619 | | - {0x3933, 0x81}, |
---|
620 | | - {0x3934, 0x81}, |
---|
621 | | - {0x3937, 0x69}, |
---|
| 630 | + {0x3933, 0x82}, |
---|
| 631 | + {0x3934, 0x0a}, |
---|
| 632 | + {0x3937, 0x5f}, |
---|
622 | 633 | {0x3939, 0x00}, |
---|
623 | 634 | {0x393a, 0x00}, |
---|
624 | 635 | {0x39dc, 0x02}, |
---|
625 | | - {0x3e01, 0xcd}, |
---|
626 | | - {0x3e02, 0xa0}, |
---|
| 636 | + {0x3e01, 0xf6}, |
---|
| 637 | + {0x3e02, 0xe0}, |
---|
627 | 638 | {0x440e, 0x02}, |
---|
628 | 639 | {0x4509, 0x20}, |
---|
629 | | - {0x4837, 0x14}, |
---|
| 640 | + {0x4837, 0x22}, |
---|
630 | 641 | {0x5010, 0x10}, |
---|
| 642 | + {0x5780, 0x66}, |
---|
| 643 | + {0x578d, 0x40}, |
---|
631 | 644 | {0x5799, 0x06}, |
---|
632 | 645 | {0x57ad, 0x00}, |
---|
633 | 646 | {0x5ae0, 0xfe}, |
---|
.. | .. |
---|
659 | 672 | {0x5afe, 0x30}, |
---|
660 | 673 | {0x5aff, 0x28}, |
---|
661 | 674 | {0x36e9, 0x44}, |
---|
662 | | - {0x37f9, 0x34}, |
---|
663 | | -// {0x0100, 0x01}, |
---|
| 675 | + {0x37f9, 0x44}, |
---|
664 | 676 | {REG_NULL, 0x00}, |
---|
665 | 677 | }; |
---|
666 | 678 | |
---|
667 | | -static const struct sc530ai_mode supported_modes[] = { |
---|
| 679 | +static const struct sc530ai_mode supported_modes_4lane[] = { |
---|
668 | 680 | { |
---|
669 | 681 | .width = 2880, |
---|
670 | 682 | .height = 1620, |
---|
.. | .. |
---|
676 | 688 | .hts_def = 0xb40, |
---|
677 | 689 | .vts_def = 0x0672, |
---|
678 | 690 | .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, |
---|
679 | | - .reg_list = sc530ai_linear_10_30fps_2880x1620_regs, |
---|
| 691 | + .reg_list = sc530ai_linear_10_30fps_2880x1620_4lane_regs, |
---|
680 | 692 | .mipi_freq_idx = 0, |
---|
681 | 693 | .bpp = 10, |
---|
682 | 694 | .hdr_mode = NO_HDR, |
---|
.. | .. |
---|
693 | 705 | .hts_def = 0xb40, |
---|
694 | 706 | .vts_def = 0x0ce4, |
---|
695 | 707 | .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, |
---|
696 | | - .reg_list = sc530ai_hdr_10_30fps_2880x1620_regs, |
---|
| 708 | + .reg_list = sc530ai_hdr_10_30fps_2880x1620_4lane_regs, |
---|
697 | 709 | .mipi_freq_idx = 1, |
---|
698 | 710 | .bpp = 10, |
---|
699 | 711 | .hdr_mode = HDR_X2, |
---|
.. | .. |
---|
702 | 714 | .vc[PAD2] = V4L2_MBUS_CSI2_CHANNEL_1, |
---|
703 | 715 | .vc[PAD3] = V4L2_MBUS_CSI2_CHANNEL_1,//M->csi wr2 |
---|
704 | 716 | }, |
---|
705 | | - { |
---|
| 717 | +}; |
---|
| 718 | + |
---|
| 719 | +static const struct sc530ai_mode supported_modes_2lane[] = { |
---|
| 720 | +{ |
---|
706 | 721 | .width = 2880, |
---|
707 | 722 | .height = 1620, |
---|
708 | 723 | .max_fps = { |
---|
.. | .. |
---|
711 | 726 | }, |
---|
712 | 727 | .exp_def = 0xcda / 2, |
---|
713 | 728 | .hts_def = 0xb40, |
---|
714 | | - .vts_def = 0x0672, |
---|
| 729 | + .vts_def = 0x07bc, |
---|
715 | 730 | .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, |
---|
716 | 731 | .reg_list = sc530ai_10_30fps_2880x1620_2lane_regs, |
---|
717 | | - .mipi_freq_idx = 2, |
---|
| 732 | + .mipi_freq_idx = 3, |
---|
718 | 733 | .bpp = 10, |
---|
719 | 734 | .hdr_mode = NO_HDR, |
---|
720 | 735 | .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, |
---|
.. | .. |
---|
725 | 740 | SC530AI_LINK_FREQ_396M, |
---|
726 | 741 | SC530AI_LINK_FREQ_792M, |
---|
727 | 742 | SC530AI_LINK_FREQ_792M_2LANE, |
---|
| 743 | + SC530AI_LINK_FREQ_936M_2LANE, |
---|
728 | 744 | }; |
---|
729 | 745 | |
---|
730 | 746 | /* Write registers up to 4 at a time */ |
---|
.. | .. |
---|
812 | 828 | } |
---|
813 | 829 | |
---|
814 | 830 | static const struct sc530ai_mode * |
---|
815 | | -sc530ai_find_best_fit(struct v4l2_subdev_format *fmt) |
---|
| 831 | +sc530ai_find_best_fit(struct sc530ai *sc530ai, struct v4l2_subdev_format *fmt) |
---|
816 | 832 | { |
---|
817 | 833 | struct v4l2_mbus_framefmt *framefmt = &fmt->format; |
---|
818 | 834 | int dist; |
---|
.. | .. |
---|
820 | 836 | int cur_best_fit_dist = -1; |
---|
821 | 837 | unsigned int i; |
---|
822 | 838 | |
---|
823 | | - for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { |
---|
824 | | - dist = sc530ai_get_reso_dist(&supported_modes[i], framefmt); |
---|
| 839 | + for (i = 0; i < sc530ai->support_modes_num; i++) { |
---|
| 840 | + dist = sc530ai_get_reso_dist(&sc530ai->support_modes[i], framefmt); |
---|
825 | 841 | if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) { |
---|
826 | 842 | cur_best_fit_dist = dist; |
---|
827 | 843 | cur_best_fit = i; |
---|
828 | 844 | } |
---|
829 | 845 | } |
---|
830 | 846 | |
---|
831 | | - return &supported_modes[cur_best_fit]; |
---|
| 847 | + return &sc530ai->support_modes[cur_best_fit]; |
---|
832 | 848 | } |
---|
833 | 849 | |
---|
834 | 850 | static int sc530ai_set_fmt(struct v4l2_subdev *sd, |
---|
.. | .. |
---|
842 | 858 | |
---|
843 | 859 | mutex_lock(&sc530ai->mutex); |
---|
844 | 860 | |
---|
845 | | - mode = sc530ai_find_best_fit(fmt); |
---|
| 861 | + mode = sc530ai_find_best_fit(sc530ai, fmt); |
---|
846 | 862 | fmt->format.code = mode->bus_fmt; |
---|
847 | 863 | fmt->format.width = mode->width; |
---|
848 | 864 | fmt->format.height = mode->height; |
---|
.. | .. |
---|
869 | 885 | pixel_rate = (u32)link_freq_items[mode->mipi_freq_idx] / |
---|
870 | 886 | mode->bpp * 2 * sc530ai->lane_num; |
---|
871 | 887 | __v4l2_ctrl_s_ctrl_int64(sc530ai->pixel_rate, pixel_rate); |
---|
| 888 | + sc530ai->cur_vts = mode->vts_def; |
---|
| 889 | + sc530ai->cur_fps = mode->max_fps; |
---|
872 | 890 | } |
---|
873 | 891 | |
---|
874 | 892 | mutex_unlock(&sc530ai->mutex); |
---|
.. | .. |
---|
924 | 942 | struct v4l2_subdev_pad_config *cfg, |
---|
925 | 943 | struct v4l2_subdev_frame_size_enum *fse) |
---|
926 | 944 | { |
---|
927 | | - if (fse->index >= ARRAY_SIZE(supported_modes)) |
---|
| 945 | + struct sc530ai *sc530ai = to_sc530ai(sd); |
---|
| 946 | + |
---|
| 947 | + if (fse->index >= sc530ai->support_modes_num) |
---|
928 | 948 | return -EINVAL; |
---|
929 | 949 | |
---|
930 | | - if (fse->code != supported_modes[0].bus_fmt) |
---|
| 950 | + if (fse->code != sc530ai->support_modes[fse->index].bus_fmt) |
---|
931 | 951 | return -EINVAL; |
---|
932 | 952 | |
---|
933 | | - fse->min_width = supported_modes[fse->index].width; |
---|
934 | | - fse->max_width = supported_modes[fse->index].width; |
---|
935 | | - fse->max_height = supported_modes[fse->index].height; |
---|
936 | | - fse->min_height = supported_modes[fse->index].height; |
---|
| 953 | + fse->min_width = sc530ai->support_modes[fse->index].width; |
---|
| 954 | + fse->max_width = sc530ai->support_modes[fse->index].width; |
---|
| 955 | + fse->max_height = sc530ai->support_modes[fse->index].height; |
---|
| 956 | + fse->min_height = sc530ai->support_modes[fse->index].height; |
---|
937 | 957 | |
---|
938 | 958 | return 0; |
---|
939 | 959 | } |
---|
.. | .. |
---|
944 | 964 | struct sc530ai *sc530ai = to_sc530ai(sd); |
---|
945 | 965 | const struct sc530ai_mode *mode = sc530ai->cur_mode; |
---|
946 | 966 | |
---|
947 | | - mutex_lock(&sc530ai->mutex); |
---|
948 | | - fi->interval = mode->max_fps; |
---|
949 | | - mutex_unlock(&sc530ai->mutex); |
---|
| 967 | + if (sc530ai->streaming) |
---|
| 968 | + fi->interval = sc530ai->cur_fps; |
---|
| 969 | + else |
---|
| 970 | + fi->interval = mode->max_fps; |
---|
950 | 971 | |
---|
951 | 972 | return 0; |
---|
952 | 973 | } |
---|
953 | 974 | |
---|
954 | | -static int sc530ai_g_mbus_config(struct v4l2_subdev *sd, |
---|
| 975 | +static int sc530ai_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id, |
---|
955 | 976 | struct v4l2_mbus_config *config) |
---|
956 | 977 | { |
---|
957 | 978 | struct sc530ai *sc530ai = to_sc530ai(sd); |
---|
.. | .. |
---|
965 | 986 | if (mode->hdr_mode == HDR_X3) |
---|
966 | 987 | val |= V4L2_MBUS_CSI2_CHANNEL_2; |
---|
967 | 988 | |
---|
968 | | - config->type = V4L2_MBUS_CSI2; |
---|
| 989 | + config->type = V4L2_MBUS_CSI2_DPHY; |
---|
969 | 990 | config->flags = val; |
---|
970 | 991 | |
---|
971 | 992 | return 0; |
---|
.. | .. |
---|
984 | 1005 | static void sc530ai_get_gain_reg(u32 total_gain, u32 *again, u32 *dgain, |
---|
985 | 1006 | u32 *dgain_fine) |
---|
986 | 1007 | { |
---|
987 | | - if (total_gain < 0x1000) { /* 1 - 2x gain */ |
---|
| 1008 | + u32 gain_factor = 0; |
---|
| 1009 | + |
---|
| 1010 | + if (total_gain < SC530AI_GAIN_MIN) |
---|
| 1011 | + total_gain = SC530AI_GAIN_MIN; |
---|
| 1012 | + else if (total_gain > SC530AI_GAIN_MAX) |
---|
| 1013 | + total_gain = SC530AI_GAIN_MAX; |
---|
| 1014 | + |
---|
| 1015 | + gain_factor = total_gain * 1000 / 32; |
---|
| 1016 | + if (gain_factor < 2000) { /* 1 - 2x gain */ |
---|
988 | 1017 | *again = 0x00; |
---|
989 | 1018 | *dgain = 0x00; |
---|
990 | | - *dgain_fine = total_gain >> 4; |
---|
991 | | - } else if (total_gain < 0x1466) { /* 2x - 2.55x gain */ |
---|
| 1019 | + *dgain_fine = gain_factor * 128 / 1000; |
---|
| 1020 | + } else if (gain_factor < 2550) { /* 2x - 2.55x gain */ |
---|
992 | 1021 | *again = 0x01; |
---|
993 | 1022 | *dgain = 0x00; |
---|
994 | | - *dgain_fine = total_gain >> 5; |
---|
995 | | - } else if (total_gain < 0x28cc) { /* 2.55x - 5.1x gain */ |
---|
| 1023 | + *dgain_fine = gain_factor * 128 / 2000; |
---|
| 1024 | + } else if (gain_factor < 2550 * 2) { /* 2.55x - 5.1x gain */ |
---|
996 | 1025 | *again = 0x40; |
---|
997 | 1026 | *dgain = 0x00; |
---|
998 | | - *dgain_fine = total_gain * 0x80 / 0x1466; |
---|
999 | | - } else if (total_gain < 0x5198) { /* 5.1x - 10.2x gain */ |
---|
| 1027 | + *dgain_fine = gain_factor * 128 / 2550; |
---|
| 1028 | + } else if (gain_factor < 2550 * 4) { /* 5.1x - 10.2x gain */ |
---|
1000 | 1029 | *again = 0x48; |
---|
1001 | 1030 | *dgain = 0x00; |
---|
1002 | | - *dgain_fine = (total_gain * 0x80 / 0x1466) >> 1; |
---|
1003 | | - } else if (total_gain < 0xa330) { /* 10.2x - 20.4x gain */ |
---|
| 1031 | + *dgain_fine = gain_factor * 128 / 5110; |
---|
| 1032 | + } else if (gain_factor < 2550 * 8) { /* 10.2x - 20.4x gain */ |
---|
1004 | 1033 | *again = 0x49; |
---|
1005 | 1034 | *dgain = 0x00; |
---|
1006 | | - *dgain_fine = (total_gain * 0x80 / 0x1466) >> 2; |
---|
1007 | | - } else if (total_gain < 0x14660) { /* 20.4x - 40.8x gain */ |
---|
| 1035 | + *dgain_fine = gain_factor * 128 / 10200; |
---|
| 1036 | + } else if (gain_factor < 2550 * 16) { /* 20.4x - 40.8x gain */ |
---|
1008 | 1037 | *again = 0x4B; |
---|
1009 | 1038 | *dgain = 0x00; |
---|
1010 | | - *dgain_fine = (total_gain * 0x80 / 0x1466) >> 3; |
---|
1011 | | - } else if (total_gain < 0x28cc0) { /* 40.8x - 81.6x gain */ |
---|
| 1039 | + *dgain_fine = gain_factor * 128 / 20400; |
---|
| 1040 | + } else if (gain_factor < 2550 * 32) { /* 40.8x - 81.6x gain */ |
---|
1012 | 1041 | *again = 0x4f; |
---|
1013 | 1042 | *dgain = 0x00; |
---|
1014 | | - *dgain_fine = (total_gain * 0x80 / 0x1466) >> 4; |
---|
1015 | | - } else if (total_gain < 0x51980) { /* 81.6x - 163.2x gain */ |
---|
| 1043 | + *dgain_fine = gain_factor * 128 / 40800; |
---|
| 1044 | + } else if (gain_factor < 2550 * 64) { /* 81.6x - 163.2x gain */ |
---|
1016 | 1045 | *again = 0x5f; |
---|
1017 | 1046 | *dgain = 0x00; |
---|
1018 | | - *dgain_fine = (total_gain * 0x80 / 0x1466) >> 5; |
---|
1019 | | - } else if (total_gain < 0xa3300) { /* 163.2x - 326.4x gain */ |
---|
| 1047 | + *dgain_fine = gain_factor * 128 / 40800 / 2; |
---|
| 1048 | + } else if (gain_factor < 2550 * 128) { /* 163.2x - 326.4x gain */ |
---|
1020 | 1049 | *again = 0x5f; |
---|
1021 | 1050 | *dgain = 0x01; |
---|
1022 | | - *dgain_fine = (total_gain * 0x80 / 0x1466) >> 6; |
---|
| 1051 | + *dgain_fine = gain_factor * 128 / 40800 / 4; |
---|
1023 | 1052 | } |
---|
1024 | 1053 | } |
---|
1025 | 1054 | |
---|
.. | .. |
---|
1114 | 1143 | return ret; |
---|
1115 | 1144 | } |
---|
1116 | 1145 | |
---|
| 1146 | +static int sc530ai_get_channel_info(struct sc530ai *sc530ai, struct rkmodule_channel_info *ch_info) |
---|
| 1147 | +{ |
---|
| 1148 | + if (ch_info->index < PAD0 || ch_info->index >= PAD_MAX) |
---|
| 1149 | + return -EINVAL; |
---|
| 1150 | + ch_info->vc = sc530ai->cur_mode->vc[ch_info->index]; |
---|
| 1151 | + ch_info->width = sc530ai->cur_mode->width; |
---|
| 1152 | + ch_info->height = sc530ai->cur_mode->height; |
---|
| 1153 | + ch_info->bus_fmt = sc530ai->cur_mode->bus_fmt; |
---|
| 1154 | + return 0; |
---|
| 1155 | +} |
---|
| 1156 | + |
---|
1117 | 1157 | static long sc530ai_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) |
---|
1118 | 1158 | { |
---|
1119 | 1159 | struct sc530ai *sc530ai = to_sc530ai(sd); |
---|
1120 | 1160 | struct rkmodule_hdr_cfg *hdr; |
---|
1121 | 1161 | const struct sc530ai_mode *mode; |
---|
| 1162 | + struct rkmodule_channel_info *ch_info; |
---|
1122 | 1163 | |
---|
1123 | 1164 | long ret = 0; |
---|
1124 | 1165 | u32 i, h = 0, w; |
---|
.. | .. |
---|
1136 | 1177 | break; |
---|
1137 | 1178 | case RKMODULE_SET_HDR_CFG: |
---|
1138 | 1179 | hdr = (struct rkmodule_hdr_cfg *)arg; |
---|
1139 | | - w = sc530ai->cur_mode->mipi_freq_idx; |
---|
1140 | | - for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { |
---|
1141 | | - if (w == supported_modes[i].mipi_freq_idx && |
---|
1142 | | - supported_modes[i].hdr_mode == hdr->hdr_mode) { |
---|
1143 | | - sc530ai->cur_mode = &supported_modes[i]; |
---|
| 1180 | + w = sc530ai->cur_mode->width; |
---|
| 1181 | + h = sc530ai->cur_mode->height; |
---|
| 1182 | + for (i = 0; i < sc530ai->support_modes_num; i++) { |
---|
| 1183 | + if (w == sc530ai->support_modes[i].width && |
---|
| 1184 | + h == sc530ai->support_modes[i].height && |
---|
| 1185 | + sc530ai->support_modes[i].hdr_mode == hdr->hdr_mode) { |
---|
| 1186 | + sc530ai->cur_mode = &sc530ai->support_modes[i]; |
---|
1144 | 1187 | break; |
---|
1145 | 1188 | } |
---|
1146 | 1189 | } |
---|
1147 | | - if (i == ARRAY_SIZE(supported_modes)) { |
---|
| 1190 | + if (i == sc530ai->support_modes_num) { |
---|
1148 | 1191 | dev_err(&sc530ai->client->dev, |
---|
1149 | 1192 | "not find hdr mode:%d %dx%d config\n", |
---|
1150 | 1193 | hdr->hdr_mode, w, h); |
---|
.. | .. |
---|
1169 | 1212 | |
---|
1170 | 1213 | __v4l2_ctrl_s_ctrl_int64(sc530ai->pixel_rate, |
---|
1171 | 1214 | pixel_rate); |
---|
1172 | | - |
---|
| 1215 | + sc530ai->cur_vts = mode->vts_def; |
---|
| 1216 | + sc530ai->cur_fps = mode->max_fps; |
---|
1173 | 1217 | dev_info(&sc530ai->client->dev, "sensor mode: %d\n", |
---|
1174 | 1218 | sc530ai->cur_mode->hdr_mode); |
---|
1175 | 1219 | } |
---|
.. | .. |
---|
1191 | 1235 | SC530AI_REG_VALUE_08BIT, |
---|
1192 | 1236 | SC530AI_MODE_SW_STANDBY); |
---|
1193 | 1237 | break; |
---|
| 1238 | + case RKMODULE_GET_CHANNEL_INFO: |
---|
| 1239 | + ch_info = (struct rkmodule_channel_info *)arg; |
---|
| 1240 | + ret = sc530ai_get_channel_info(sc530ai, ch_info); |
---|
| 1241 | + break; |
---|
1194 | 1242 | default: |
---|
1195 | 1243 | ret = -ENOIOCTLCMD; |
---|
1196 | 1244 | break; |
---|
.. | .. |
---|
1207 | 1255 | struct rkmodule_inf *inf; |
---|
1208 | 1256 | struct rkmodule_hdr_cfg *hdr; |
---|
1209 | 1257 | struct preisp_hdrae_exp_s *hdrae; |
---|
| 1258 | + struct rkmodule_channel_info *ch_info; |
---|
1210 | 1259 | long ret = 0; |
---|
1211 | 1260 | u32 stream = 0; |
---|
1212 | 1261 | |
---|
.. | .. |
---|
1277 | 1326 | |
---|
1278 | 1327 | ret = sc530ai_ioctl(sd, cmd, &stream); |
---|
1279 | 1328 | break; |
---|
| 1329 | + case RKMODULE_GET_CHANNEL_INFO: |
---|
| 1330 | + ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL); |
---|
| 1331 | + if (!ch_info) { |
---|
| 1332 | + ret = -ENOMEM; |
---|
| 1333 | + return ret; |
---|
| 1334 | + } |
---|
| 1335 | + |
---|
| 1336 | + ret = sc530ai_ioctl(sd, cmd, ch_info); |
---|
| 1337 | + if (!ret) { |
---|
| 1338 | + ret = copy_to_user(up, ch_info, sizeof(*ch_info)); |
---|
| 1339 | + if (ret) |
---|
| 1340 | + ret = -EFAULT; |
---|
| 1341 | + } |
---|
| 1342 | + kfree(ch_info); |
---|
| 1343 | + break; |
---|
1280 | 1344 | default: |
---|
1281 | 1345 | ret = -ENOIOCTLCMD; |
---|
1282 | 1346 | break; |
---|
.. | .. |
---|
1290 | 1354 | { |
---|
1291 | 1355 | int ret; |
---|
1292 | 1356 | |
---|
1293 | | - ret = sc530ai_write_array(sc530ai->client, sc530ai->cur_mode->reg_list); |
---|
1294 | | - if (ret) |
---|
1295 | | - return ret; |
---|
1296 | | - |
---|
1297 | | - /* In case these controls are set before streaming */ |
---|
1298 | | - ret = __v4l2_ctrl_handler_setup(&sc530ai->ctrl_handler); |
---|
1299 | | - if (ret) |
---|
1300 | | - return ret; |
---|
1301 | | - if (sc530ai->has_init_exp && sc530ai->cur_mode->hdr_mode != NO_HDR) { |
---|
1302 | | - ret = sc530ai_ioctl(&sc530ai->subdev, PREISP_CMD_SET_HDRAE_EXP, |
---|
1303 | | - &sc530ai->init_hdrae_exp); |
---|
1304 | | - if (ret) { |
---|
1305 | | - dev_err(&sc530ai->client->dev, |
---|
1306 | | - "init exp fail in hdr mode\n"); |
---|
| 1357 | + if (!sc530ai->is_thunderboot) { |
---|
| 1358 | + ret = sc530ai_write_array(sc530ai->client, sc530ai->cur_mode->reg_list); |
---|
| 1359 | + if (ret) |
---|
1307 | 1360 | return ret; |
---|
| 1361 | + |
---|
| 1362 | + /* In case these controls are set before streaming */ |
---|
| 1363 | + ret = __v4l2_ctrl_handler_setup(&sc530ai->ctrl_handler); |
---|
| 1364 | + if (ret) |
---|
| 1365 | + return ret; |
---|
| 1366 | + if (sc530ai->has_init_exp && sc530ai->cur_mode->hdr_mode != NO_HDR) { |
---|
| 1367 | + ret = sc530ai_ioctl(&sc530ai->subdev, PREISP_CMD_SET_HDRAE_EXP, |
---|
| 1368 | + &sc530ai->init_hdrae_exp); |
---|
| 1369 | + if (ret) { |
---|
| 1370 | + dev_err(&sc530ai->client->dev, |
---|
| 1371 | + "init exp fail in hdr mode\n"); |
---|
| 1372 | + return ret; |
---|
| 1373 | + } |
---|
1308 | 1374 | } |
---|
1309 | 1375 | } |
---|
1310 | 1376 | return sc530ai_write_reg(sc530ai->client, SC530AI_REG_CTRL_MODE, |
---|
.. | .. |
---|
1315 | 1381 | static int __sc530ai_stop_stream(struct sc530ai *sc530ai) |
---|
1316 | 1382 | { |
---|
1317 | 1383 | sc530ai->has_init_exp = false; |
---|
| 1384 | + if (sc530ai->is_thunderboot) { |
---|
| 1385 | + sc530ai->is_first_streamoff = true; |
---|
| 1386 | + pm_runtime_put(&sc530ai->client->dev); |
---|
| 1387 | + } |
---|
1318 | 1388 | return sc530ai_write_reg(sc530ai->client, SC530AI_REG_CTRL_MODE, |
---|
1319 | 1389 | SC530AI_REG_VALUE_08BIT, |
---|
1320 | 1390 | SC530AI_MODE_SW_STANDBY); |
---|
1321 | 1391 | } |
---|
1322 | 1392 | |
---|
| 1393 | +static int __sc530ai_power_on(struct sc530ai *sc530ai); |
---|
1323 | 1394 | static int sc530ai_s_stream(struct v4l2_subdev *sd, int on) |
---|
1324 | 1395 | { |
---|
1325 | 1396 | struct sc530ai *sc530ai = to_sc530ai(sd); |
---|
.. | .. |
---|
1331 | 1402 | if (on == sc530ai->streaming) |
---|
1332 | 1403 | goto unlock_and_return; |
---|
1333 | 1404 | if (on) { |
---|
| 1405 | + if (sc530ai->is_thunderboot && rkisp_tb_get_state() == RKISP_TB_NG) { |
---|
| 1406 | + sc530ai->is_thunderboot = false; |
---|
| 1407 | + __sc530ai_power_on(sc530ai); |
---|
| 1408 | + } |
---|
1334 | 1409 | ret = pm_runtime_get_sync(&client->dev); |
---|
1335 | 1410 | if (ret < 0) { |
---|
1336 | 1411 | pm_runtime_put_noidle(&client->dev); |
---|
.. | .. |
---|
1373 | 1448 | pm_runtime_put_noidle(&client->dev); |
---|
1374 | 1449 | goto unlock_and_return; |
---|
1375 | 1450 | } |
---|
1376 | | - |
---|
1377 | | - ret |= sc530ai_write_reg(sc530ai->client, |
---|
1378 | | - SC530AI_SOFTWARE_RESET_REG, |
---|
1379 | | - SC530AI_REG_VALUE_08BIT, |
---|
1380 | | - 0x01); |
---|
1381 | | - usleep_range(100, 200); |
---|
1382 | | - |
---|
| 1451 | + if (!sc530ai->is_thunderboot) { |
---|
| 1452 | + ret |= sc530ai_write_reg(sc530ai->client, |
---|
| 1453 | + SC530AI_SOFTWARE_RESET_REG, |
---|
| 1454 | + SC530AI_REG_VALUE_08BIT, |
---|
| 1455 | + 0x01); |
---|
| 1456 | + if (ret) { |
---|
| 1457 | + v4l2_err(sd, "could not set init registers\n"); |
---|
| 1458 | + pm_runtime_put_noidle(&client->dev); |
---|
| 1459 | + goto unlock_and_return; |
---|
| 1460 | + } |
---|
| 1461 | + usleep_range(100, 200); |
---|
| 1462 | + } |
---|
1383 | 1463 | sc530ai->power_on = true; |
---|
1384 | 1464 | } else { |
---|
1385 | 1465 | pm_runtime_put(&client->dev); |
---|
.. | .. |
---|
1413 | 1493 | dev_err(dev, "Failed to enable xvclk\n"); |
---|
1414 | 1494 | return ret; |
---|
1415 | 1495 | } |
---|
| 1496 | + |
---|
| 1497 | + if (sc530ai->is_thunderboot) |
---|
| 1498 | + return 0; |
---|
| 1499 | + |
---|
1416 | 1500 | if (!IS_ERR(sc530ai->reset_gpio)) |
---|
1417 | 1501 | gpiod_set_value_cansleep(sc530ai->reset_gpio, 0); |
---|
1418 | 1502 | |
---|
.. | .. |
---|
1443 | 1527 | int ret; |
---|
1444 | 1528 | struct device *dev = &sc530ai->client->dev; |
---|
1445 | 1529 | |
---|
| 1530 | + if (sc530ai->is_thunderboot) { |
---|
| 1531 | + if (sc530ai->is_first_streamoff) { |
---|
| 1532 | + sc530ai->is_thunderboot = false; |
---|
| 1533 | + sc530ai->is_first_streamoff = false; |
---|
| 1534 | + } else { |
---|
| 1535 | + return; |
---|
| 1536 | + } |
---|
| 1537 | + } |
---|
| 1538 | + |
---|
1446 | 1539 | if (!IS_ERR(sc530ai->pwdn_gpio)) |
---|
1447 | 1540 | gpiod_set_value_cansleep(sc530ai->pwdn_gpio, 0); |
---|
1448 | 1541 | clk_disable_unprepare(sc530ai->xvclk); |
---|
.. | .. |
---|
1457 | 1550 | regulator_bulk_disable(sc530ai_NUM_SUPPLIES, sc530ai->supplies); |
---|
1458 | 1551 | } |
---|
1459 | 1552 | |
---|
1460 | | -static int sc530ai_runtime_resume(struct device *dev) |
---|
| 1553 | +static int __maybe_unused sc530ai_runtime_resume(struct device *dev) |
---|
1461 | 1554 | { |
---|
1462 | 1555 | struct i2c_client *client = to_i2c_client(dev); |
---|
1463 | 1556 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
---|
.. | .. |
---|
1466 | 1559 | return __sc530ai_power_on(sc530ai); |
---|
1467 | 1560 | } |
---|
1468 | 1561 | |
---|
1469 | | -static int sc530ai_runtime_suspend(struct device *dev) |
---|
| 1562 | +static int __maybe_unused sc530ai_runtime_suspend(struct device *dev) |
---|
1470 | 1563 | { |
---|
1471 | 1564 | struct i2c_client *client = to_i2c_client(dev); |
---|
1472 | 1565 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
---|
.. | .. |
---|
1483 | 1576 | struct sc530ai *sc530ai = to_sc530ai(sd); |
---|
1484 | 1577 | struct v4l2_mbus_framefmt *try_fmt = |
---|
1485 | 1578 | v4l2_subdev_get_try_format(sd, fh->pad, 0); |
---|
1486 | | - const struct sc530ai_mode *def_mode = &supported_modes[0]; |
---|
| 1579 | + const struct sc530ai_mode *def_mode = &sc530ai->support_modes[0]; |
---|
1487 | 1580 | |
---|
1488 | 1581 | mutex_lock(&sc530ai->mutex); |
---|
1489 | 1582 | /* Initialize try_fmt */ |
---|
.. | .. |
---|
1529 | 1622 | struct v4l2_subdev_pad_config *cfg, |
---|
1530 | 1623 | struct v4l2_subdev_frame_interval_enum *fie) |
---|
1531 | 1624 | { |
---|
1532 | | - if (fie->index >= ARRAY_SIZE(supported_modes)) |
---|
| 1625 | + struct sc530ai *sc530ai = to_sc530ai(sd); |
---|
| 1626 | + |
---|
| 1627 | + if (fie->index >= sc530ai->support_modes_num) |
---|
1533 | 1628 | return -EINVAL; |
---|
1534 | 1629 | |
---|
1535 | | - fie->code = supported_modes[fie->index].bus_fmt; |
---|
1536 | | - fie->width = supported_modes[fie->index].width; |
---|
1537 | | - fie->height = supported_modes[fie->index].height; |
---|
1538 | | - fie->interval = supported_modes[fie->index].max_fps; |
---|
1539 | | - fie->reserved[0] = supported_modes[fie->index].hdr_mode; |
---|
| 1630 | + fie->code = sc530ai->support_modes[fie->index].bus_fmt; |
---|
| 1631 | + fie->width = sc530ai->support_modes[fie->index].width; |
---|
| 1632 | + fie->height = sc530ai->support_modes[fie->index].height; |
---|
| 1633 | + fie->interval = sc530ai->support_modes[fie->index].max_fps; |
---|
| 1634 | + fie->reserved[0] = sc530ai->support_modes[fie->index].hdr_mode; |
---|
1540 | 1635 | return 0; |
---|
1541 | 1636 | } |
---|
1542 | 1637 | |
---|
.. | .. |
---|
1562 | 1657 | static const struct v4l2_subdev_video_ops sc530ai_video_ops = { |
---|
1563 | 1658 | .s_stream = sc530ai_s_stream, |
---|
1564 | 1659 | .g_frame_interval = sc530ai_g_frame_interval, |
---|
1565 | | - .g_mbus_config = sc530ai_g_mbus_config, |
---|
1566 | 1660 | }; |
---|
1567 | 1661 | |
---|
1568 | 1662 | static const struct v4l2_subdev_pad_ops sc530ai_pad_ops = { |
---|
.. | .. |
---|
1572 | 1666 | .get_fmt = sc530ai_get_fmt, |
---|
1573 | 1667 | .set_fmt = sc530ai_set_fmt, |
---|
1574 | 1668 | .get_selection = sc530ai_get_selection, |
---|
| 1669 | + .get_mbus_config = sc530ai_g_mbus_config, |
---|
1575 | 1670 | }; |
---|
1576 | 1671 | |
---|
1577 | 1672 | static const struct v4l2_subdev_ops sc530ai_subdev_ops = { |
---|
.. | .. |
---|
1579 | 1674 | .video = &sc530ai_video_ops, |
---|
1580 | 1675 | .pad = &sc530ai_pad_ops, |
---|
1581 | 1676 | }; |
---|
| 1677 | + |
---|
| 1678 | +static void sc530ai_modify_fps_info(struct sc530ai *sc5330ai) |
---|
| 1679 | +{ |
---|
| 1680 | + const struct sc530ai_mode *mode = sc5330ai->cur_mode; |
---|
| 1681 | + |
---|
| 1682 | + sc5330ai->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / |
---|
| 1683 | + sc5330ai->cur_vts; |
---|
| 1684 | +} |
---|
1582 | 1685 | |
---|
1583 | 1686 | static int sc530ai_set_ctrl(struct v4l2_ctrl *ctrl) |
---|
1584 | 1687 | { |
---|
.. | .. |
---|
1608 | 1711 | switch (ctrl->id) { |
---|
1609 | 1712 | case V4L2_CID_EXPOSURE: |
---|
1610 | 1713 | if (sc530ai->cur_mode->hdr_mode != NO_HDR) |
---|
1611 | | - return ret; |
---|
| 1714 | + goto ctrl_end; |
---|
1612 | 1715 | val = ctrl->val << 1; |
---|
1613 | 1716 | ret = sc530ai_write_reg(sc530ai->client, |
---|
1614 | 1717 | SC530AI_REG_EXPOSURE_H, |
---|
.. | .. |
---|
1627 | 1730 | break; |
---|
1628 | 1731 | case V4L2_CID_ANALOGUE_GAIN: |
---|
1629 | 1732 | if (sc530ai->cur_mode->hdr_mode != NO_HDR) |
---|
1630 | | - return ret; |
---|
| 1733 | + goto ctrl_end; |
---|
1631 | 1734 | |
---|
1632 | 1735 | sc530ai_get_gain_reg(ctrl->val, &again, &dgain, &dgain_fine); |
---|
1633 | 1736 | ret = sc530ai_write_reg(sc530ai->client, |
---|
.. | .. |
---|
1642 | 1745 | SC530AI_REG_ANA_GAIN, |
---|
1643 | 1746 | SC530AI_REG_VALUE_08BIT, |
---|
1644 | 1747 | again); |
---|
1645 | | - |
---|
| 1748 | + dev_dbg(&client->dev, "set gain 0x%x\n", ctrl->val); |
---|
1646 | 1749 | break; |
---|
1647 | 1750 | case V4L2_CID_VBLANK: |
---|
1648 | 1751 | vts = ctrl->val + sc530ai->cur_mode->height; |
---|
.. | .. |
---|
1654 | 1757 | SC530AI_REG_VTS_L, |
---|
1655 | 1758 | SC530AI_REG_VALUE_08BIT, |
---|
1656 | 1759 | vts & 0xff); |
---|
| 1760 | + if (!ret) |
---|
| 1761 | + sc530ai->cur_vts = vts; |
---|
| 1762 | + sc530ai_modify_fps_info(sc530ai); |
---|
| 1763 | + dev_dbg(&client->dev, "set vblank 0x%x\n", ctrl->val); |
---|
1657 | 1764 | break; |
---|
1658 | 1765 | case V4L2_CID_HFLIP: |
---|
1659 | 1766 | ret = sc530ai_read_reg(sc530ai->client, SC530AI_FLIP_MIRROR_REG, |
---|
.. | .. |
---|
1691 | 1798 | break; |
---|
1692 | 1799 | } |
---|
1693 | 1800 | |
---|
| 1801 | +ctrl_end: |
---|
1694 | 1802 | pm_runtime_put(&client->dev); |
---|
1695 | 1803 | |
---|
1696 | 1804 | return ret; |
---|
.. | .. |
---|
1715 | 1823 | fwnode = of_fwnode_handle(endpoint); |
---|
1716 | 1824 | rval = fwnode_property_read_u32_array(fwnode, "data-lanes", NULL, 0); |
---|
1717 | 1825 | if (rval <= 0) { |
---|
1718 | | - dev_warn(dev, " Get mipi lane num failed!\n"); |
---|
1719 | | - return -1; |
---|
| 1826 | + dev_err(dev, " Get mipi lane num failed!\n"); |
---|
| 1827 | + return -EINVAL; |
---|
1720 | 1828 | } |
---|
1721 | 1829 | |
---|
1722 | 1830 | sc530ai->lane_num = rval; |
---|
| 1831 | + dev_info(dev, "lane_num = %d\n", sc530ai->lane_num); |
---|
1723 | 1832 | |
---|
1724 | 1833 | if (sc530ai->lane_num == 2) { |
---|
1725 | | - sc530ai->cur_mode = &supported_modes[2]; |
---|
1726 | | - dev_info(dev, "lane_num(%d)\n", sc530ai->lane_num); |
---|
1727 | | - } else if (sc530ai->lane_num == 2) { |
---|
1728 | | - sc530ai->cur_mode = &supported_modes[0]; |
---|
1729 | | - dev_info(dev, "lane_num(%d)\n", sc530ai->lane_num); |
---|
1730 | | - } else { |
---|
1731 | | - dev_err(dev, "unsupported lane_num(%d)\n", sc530ai->lane_num); |
---|
1732 | | - return -1; |
---|
| 1834 | + sc530ai->support_modes = supported_modes_2lane; |
---|
| 1835 | + sc530ai->support_modes_num = ARRAY_SIZE(supported_modes_2lane); |
---|
| 1836 | + } else if (sc530ai->lane_num == 4) { |
---|
| 1837 | + sc530ai->support_modes = supported_modes_4lane; |
---|
| 1838 | + sc530ai->support_modes_num = ARRAY_SIZE(supported_modes_4lane); |
---|
1733 | 1839 | } |
---|
| 1840 | + |
---|
| 1841 | + sc530ai->cur_mode = &sc530ai->support_modes[0]; |
---|
| 1842 | + |
---|
1734 | 1843 | return 0; |
---|
1735 | 1844 | } |
---|
1736 | 1845 | |
---|
.. | .. |
---|
1809 | 1918 | } |
---|
1810 | 1919 | sc530ai->subdev.ctrl_handler = handler; |
---|
1811 | 1920 | sc530ai->has_init_exp = false; |
---|
| 1921 | + sc530ai->cur_vts = mode->vts_def; |
---|
| 1922 | + sc530ai->cur_fps = mode->max_fps; |
---|
1812 | 1923 | |
---|
1813 | 1924 | return 0; |
---|
1814 | 1925 | |
---|
.. | .. |
---|
1824 | 1935 | u32 id = 0; |
---|
1825 | 1936 | int ret; |
---|
1826 | 1937 | |
---|
| 1938 | + if (sc530ai->is_thunderboot) { |
---|
| 1939 | + dev_info(dev, "Enable thunderboot mode, skip sensor id check\n"); |
---|
| 1940 | + return 0; |
---|
| 1941 | + } |
---|
1827 | 1942 | ret = sc530ai_read_reg(client, SC530AI_REG_CHIP_ID, |
---|
1828 | 1943 | SC530AI_REG_VALUE_16BIT, &id); |
---|
1829 | 1944 | if (id != SC530AI_CHIP_ID) { |
---|
.. | .. |
---|
1857 | 1972 | struct v4l2_subdev *sd; |
---|
1858 | 1973 | char facing[2]; |
---|
1859 | 1974 | int ret; |
---|
1860 | | - u32 i, hdr_mode = 0; |
---|
| 1975 | + u32 hdr_mode = 0; |
---|
1861 | 1976 | |
---|
1862 | 1977 | dev_info(dev, "driver version: %02x.%02x.%02x", |
---|
1863 | 1978 | DRIVER_VERSION >> 16, |
---|
.. | .. |
---|
1882 | 1997 | return -EINVAL; |
---|
1883 | 1998 | } |
---|
1884 | 1999 | |
---|
| 2000 | + sc530ai->is_thunderboot = IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP); |
---|
1885 | 2001 | sc530ai->client = client; |
---|
1886 | | - for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { |
---|
1887 | | - if (hdr_mode == supported_modes[i].hdr_mode) { |
---|
1888 | | - sc530ai->cur_mode = &supported_modes[i]; |
---|
1889 | | - break; |
---|
1890 | | - } |
---|
1891 | | - } |
---|
1892 | | - if (i == ARRAY_SIZE(supported_modes)) |
---|
1893 | | - sc530ai->cur_mode = &supported_modes[0]; |
---|
| 2002 | + |
---|
| 2003 | + ret = sc530ai_parse_of(sc530ai); |
---|
| 2004 | + if (ret) |
---|
| 2005 | + return -EINVAL; |
---|
1894 | 2006 | |
---|
1895 | 2007 | sc530ai->xvclk = devm_clk_get(dev, "xvclk"); |
---|
1896 | 2008 | if (IS_ERR(sc530ai->xvclk)) { |
---|
.. | .. |
---|
1898 | 2010 | return -EINVAL; |
---|
1899 | 2011 | } |
---|
1900 | 2012 | |
---|
1901 | | - sc530ai->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); |
---|
| 2013 | + sc530ai->reset_gpio = devm_gpiod_get(dev, "reset", |
---|
| 2014 | + sc530ai->is_thunderboot ? GPIOD_ASIS : GPIOD_OUT_LOW); |
---|
1902 | 2015 | if (IS_ERR(sc530ai->reset_gpio)) |
---|
1903 | 2016 | dev_warn(dev, "Failed to get reset-gpios\n"); |
---|
1904 | 2017 | |
---|
1905 | | - sc530ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW); |
---|
| 2018 | + sc530ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", |
---|
| 2019 | + sc530ai->is_thunderboot ? GPIOD_ASIS : GPIOD_OUT_LOW); |
---|
1906 | 2020 | if (IS_ERR(sc530ai->pwdn_gpio)) |
---|
1907 | 2021 | dev_warn(dev, "Failed to get pwdn-gpios\n"); |
---|
1908 | 2022 | |
---|
.. | .. |
---|
1928 | 2042 | dev_err(dev, "Failed to get power regulators\n"); |
---|
1929 | 2043 | return ret; |
---|
1930 | 2044 | } |
---|
1931 | | - |
---|
1932 | | - ret = sc530ai_parse_of(sc530ai); |
---|
1933 | | - if (ret != 0) |
---|
1934 | | - return -EINVAL; |
---|
1935 | 2045 | |
---|
1936 | 2046 | mutex_init(&sc530ai->mutex); |
---|
1937 | 2047 | |
---|
.. | .. |
---|
1980 | 2090 | |
---|
1981 | 2091 | pm_runtime_set_active(dev); |
---|
1982 | 2092 | pm_runtime_enable(dev); |
---|
1983 | | - pm_runtime_idle(dev); |
---|
| 2093 | + if (sc530ai->is_thunderboot) |
---|
| 2094 | + pm_runtime_get_sync(dev); |
---|
| 2095 | + else |
---|
| 2096 | + pm_runtime_idle(dev); |
---|
1984 | 2097 | |
---|
1985 | 2098 | return 0; |
---|
1986 | 2099 | |
---|