.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * V4L2 subdevice driver for OmniVision OV6650 Camera Sensor |
---|
3 | 4 | * |
---|
.. | .. |
---|
15 | 16 | * Copyright (C) 2008 Magnus Damm |
---|
16 | 17 | * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> |
---|
17 | 18 | * |
---|
18 | | - * Hardware specific bits initialy based on former work by Matt Callow |
---|
| 19 | + * Hardware specific bits initially based on former work by Matt Callow |
---|
19 | 20 | * drivers/media/video/omap/sensor_ov6650.c |
---|
20 | 21 | * Copyright (C) 2006 Matt Callow |
---|
21 | | - * |
---|
22 | | - * This program is free software; you can redistribute it and/or modify |
---|
23 | | - * it under the terms of the GNU General Public License version 2 as |
---|
24 | | - * published by the Free Software Foundation. |
---|
25 | 22 | */ |
---|
26 | 23 | |
---|
27 | 24 | #include <linux/bitops.h> |
---|
.. | .. |
---|
127 | 124 | |
---|
128 | 125 | #define DEF_AECH 0x4D |
---|
129 | 126 | |
---|
130 | | -#define CLKRC_6MHz 0x00 |
---|
| 127 | +#define CLKRC_8MHz 0x00 |
---|
131 | 128 | #define CLKRC_12MHz 0x40 |
---|
132 | 129 | #define CLKRC_16MHz 0x80 |
---|
133 | 130 | #define CLKRC_24MHz 0xc0 |
---|
134 | 131 | #define CLKRC_DIV_MASK 0x3f |
---|
135 | 132 | #define GET_CLKRC_DIV(x) (((x) & CLKRC_DIV_MASK) + 1) |
---|
| 133 | +#define DEF_CLKRC 0x00 |
---|
136 | 134 | |
---|
137 | 135 | #define COMA_RESET BIT(7) |
---|
138 | 136 | #define COMA_QCIF BIT(5) |
---|
.. | .. |
---|
199 | 197 | struct v4l2_clk *clk; |
---|
200 | 198 | bool half_scale; /* scale down output by 2 */ |
---|
201 | 199 | struct v4l2_rect rect; /* sensor cropping window */ |
---|
202 | | - unsigned long pclk_limit; /* from host */ |
---|
203 | | - unsigned long pclk_max; /* from resolution and format */ |
---|
204 | 200 | struct v4l2_fract tpf; /* as requested with s_frame_interval */ |
---|
205 | 201 | u32 code; |
---|
206 | 202 | }; |
---|
207 | 203 | |
---|
| 204 | +struct ov6650_xclk { |
---|
| 205 | + unsigned long rate; |
---|
| 206 | + u8 clkrc; |
---|
| 207 | +}; |
---|
| 208 | + |
---|
| 209 | +static const struct ov6650_xclk ov6650_xclk[] = { |
---|
| 210 | +{ |
---|
| 211 | + .rate = 8000000, |
---|
| 212 | + .clkrc = CLKRC_8MHz, |
---|
| 213 | +}, |
---|
| 214 | +{ |
---|
| 215 | + .rate = 12000000, |
---|
| 216 | + .clkrc = CLKRC_12MHz, |
---|
| 217 | +}, |
---|
| 218 | +{ |
---|
| 219 | + .rate = 16000000, |
---|
| 220 | + .clkrc = CLKRC_16MHz, |
---|
| 221 | +}, |
---|
| 222 | +{ |
---|
| 223 | + .rate = 24000000, |
---|
| 224 | + .clkrc = CLKRC_24MHz, |
---|
| 225 | +}, |
---|
| 226 | +}; |
---|
208 | 227 | |
---|
209 | 228 | static u32 ov6650_codes[] = { |
---|
210 | 229 | MEDIA_BUS_FMT_YUYV8_2X8, |
---|
.. | .. |
---|
459 | 478 | |
---|
460 | 479 | switch (sel->target) { |
---|
461 | 480 | case V4L2_SEL_TGT_CROP_BOUNDS: |
---|
462 | | - case V4L2_SEL_TGT_CROP_DEFAULT: |
---|
463 | 481 | sel->r.left = DEF_HSTRT << 1; |
---|
464 | 482 | sel->r.top = DEF_VSTRT << 1; |
---|
465 | 483 | sel->r.width = W_CIF; |
---|
.. | .. |
---|
549 | 567 | return width > rect->width >> 1 || height > rect->height >> 1; |
---|
550 | 568 | } |
---|
551 | 569 | |
---|
552 | | -static u8 to_clkrc(struct v4l2_fract *timeperframe, |
---|
553 | | - unsigned long pclk_limit, unsigned long pclk_max) |
---|
554 | | -{ |
---|
555 | | - unsigned long pclk; |
---|
556 | | - |
---|
557 | | - if (timeperframe->numerator && timeperframe->denominator) |
---|
558 | | - pclk = pclk_max * timeperframe->denominator / |
---|
559 | | - (FRAME_RATE_MAX * timeperframe->numerator); |
---|
560 | | - else |
---|
561 | | - pclk = pclk_max; |
---|
562 | | - |
---|
563 | | - if (pclk_limit && pclk_limit < pclk) |
---|
564 | | - pclk = pclk_limit; |
---|
565 | | - |
---|
566 | | - return (pclk_max - 1) / pclk; |
---|
567 | | -} |
---|
| 570 | +#define to_clkrc(div) ((div) - 1) |
---|
568 | 571 | |
---|
569 | 572 | /* set the format we will capture in */ |
---|
570 | 573 | static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) |
---|
.. | .. |
---|
583 | 586 | .r.height = mf->height << half_scale, |
---|
584 | 587 | }; |
---|
585 | 588 | u32 code = mf->code; |
---|
586 | | - unsigned long mclk, pclk; |
---|
587 | | - u8 coma_set = 0, coma_mask = 0, coml_set, coml_mask, clkrc; |
---|
| 589 | + u8 coma_set = 0, coma_mask = 0, coml_set, coml_mask; |
---|
588 | 590 | int ret; |
---|
589 | 591 | |
---|
590 | 592 | /* select color matrix configuration for given color encoding */ |
---|
.. | .. |
---|
638 | 640 | code == MEDIA_BUS_FMT_SBGGR8_1X8) { |
---|
639 | 641 | coml_mask = COML_ONE_CHANNEL; |
---|
640 | 642 | coml_set = 0; |
---|
641 | | - priv->pclk_max = 4000000; |
---|
642 | 643 | } else { |
---|
643 | 644 | coml_mask = 0; |
---|
644 | 645 | coml_set = COML_ONE_CHANNEL; |
---|
645 | | - priv->pclk_max = 8000000; |
---|
646 | 646 | } |
---|
647 | 647 | |
---|
648 | 648 | if (half_scale) { |
---|
649 | 649 | dev_dbg(&client->dev, "max resolution: QCIF\n"); |
---|
650 | 650 | coma_set |= COMA_QCIF; |
---|
651 | | - priv->pclk_max /= 2; |
---|
652 | 651 | } else { |
---|
653 | 652 | dev_dbg(&client->dev, "max resolution: CIF\n"); |
---|
654 | 653 | coma_mask |= COMA_QCIF; |
---|
655 | 654 | } |
---|
656 | 655 | |
---|
657 | | - clkrc = CLKRC_12MHz; |
---|
658 | | - mclk = 12000000; |
---|
659 | | - priv->pclk_limit = 1334000; |
---|
660 | | - dev_dbg(&client->dev, "using 12MHz input clock\n"); |
---|
661 | | - |
---|
662 | | - clkrc |= to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max); |
---|
663 | | - |
---|
664 | | - pclk = priv->pclk_max / GET_CLKRC_DIV(clkrc); |
---|
665 | | - dev_dbg(&client->dev, "pixel clock divider: %ld.%ld\n", |
---|
666 | | - mclk / pclk, 10 * mclk % pclk / pclk); |
---|
667 | | - |
---|
668 | 656 | ret = ov6650_set_selection(sd, NULL, &sel); |
---|
669 | 657 | if (!ret) |
---|
670 | 658 | ret = ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask); |
---|
671 | | - if (!ret) |
---|
672 | | - ret = ov6650_reg_write(client, REG_CLKRC, clkrc); |
---|
673 | 659 | if (!ret) { |
---|
674 | 660 | priv->half_scale = half_scale; |
---|
675 | 661 | |
---|
.. | .. |
---|
699 | 685 | switch (mf->code) { |
---|
700 | 686 | case MEDIA_BUS_FMT_Y10_1X10: |
---|
701 | 687 | mf->code = MEDIA_BUS_FMT_Y8_1X8; |
---|
702 | | - /* fall through */ |
---|
| 688 | + fallthrough; |
---|
703 | 689 | case MEDIA_BUS_FMT_Y8_1X8: |
---|
704 | 690 | case MEDIA_BUS_FMT_YVYU8_2X8: |
---|
705 | 691 | case MEDIA_BUS_FMT_YUYV8_2X8: |
---|
.. | .. |
---|
708 | 694 | break; |
---|
709 | 695 | default: |
---|
710 | 696 | mf->code = MEDIA_BUS_FMT_SBGGR8_1X8; |
---|
711 | | - /* fall through */ |
---|
| 697 | + fallthrough; |
---|
712 | 698 | case MEDIA_BUS_FMT_SBGGR8_1X8: |
---|
713 | 699 | break; |
---|
714 | 700 | } |
---|
.. | .. |
---|
758 | 744 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
---|
759 | 745 | struct ov6650 *priv = to_ov6650(client); |
---|
760 | 746 | |
---|
761 | | - ival->interval.numerator = GET_CLKRC_DIV(to_clkrc(&priv->tpf, |
---|
762 | | - priv->pclk_limit, priv->pclk_max)); |
---|
763 | | - ival->interval.denominator = FRAME_RATE_MAX; |
---|
| 747 | + ival->interval = priv->tpf; |
---|
764 | 748 | |
---|
765 | 749 | dev_dbg(&client->dev, "Frame interval: %u/%u s\n", |
---|
766 | 750 | ival->interval.numerator, ival->interval.denominator); |
---|
.. | .. |
---|
775 | 759 | struct ov6650 *priv = to_ov6650(client); |
---|
776 | 760 | struct v4l2_fract *tpf = &ival->interval; |
---|
777 | 761 | int div, ret; |
---|
778 | | - u8 clkrc; |
---|
779 | 762 | |
---|
780 | 763 | if (tpf->numerator == 0 || tpf->denominator == 0) |
---|
781 | 764 | div = 1; /* Reset to full rate */ |
---|
.. | .. |
---|
787 | 770 | else if (div > GET_CLKRC_DIV(CLKRC_DIV_MASK)) |
---|
788 | 771 | div = GET_CLKRC_DIV(CLKRC_DIV_MASK); |
---|
789 | 772 | |
---|
790 | | - /* |
---|
791 | | - * Keep result to be used as tpf limit |
---|
792 | | - * for subseqent clock divider calculations |
---|
793 | | - */ |
---|
794 | | - priv->tpf.numerator = div; |
---|
795 | | - priv->tpf.denominator = FRAME_RATE_MAX; |
---|
796 | | - |
---|
797 | | - clkrc = to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max); |
---|
798 | | - |
---|
799 | | - ret = ov6650_reg_rmw(client, REG_CLKRC, clkrc, CLKRC_DIV_MASK); |
---|
| 773 | + ret = ov6650_reg_rmw(client, REG_CLKRC, to_clkrc(div), CLKRC_DIV_MASK); |
---|
800 | 774 | if (!ret) { |
---|
801 | | - tpf->numerator = GET_CLKRC_DIV(clkrc); |
---|
802 | | - tpf->denominator = FRAME_RATE_MAX; |
---|
| 775 | + priv->tpf.numerator = div; |
---|
| 776 | + priv->tpf.denominator = FRAME_RATE_MAX; |
---|
| 777 | + |
---|
| 778 | + *tpf = priv->tpf; |
---|
803 | 779 | } |
---|
804 | 780 | |
---|
805 | 781 | return ret; |
---|
.. | .. |
---|
821 | 797 | } |
---|
822 | 798 | |
---|
823 | 799 | /* program default register values */ |
---|
824 | | -static int ov6650_prog_dflt(struct i2c_client *client) |
---|
| 800 | +static int ov6650_prog_dflt(struct i2c_client *client, u8 clkrc) |
---|
825 | 801 | { |
---|
826 | 802 | int ret; |
---|
827 | 803 | |
---|
.. | .. |
---|
829 | 805 | |
---|
830 | 806 | ret = ov6650_reg_write(client, REG_COMA, 0); /* ~COMA_RESET */ |
---|
831 | 807 | if (!ret) |
---|
| 808 | + ret = ov6650_reg_write(client, REG_CLKRC, clkrc); |
---|
| 809 | + if (!ret) |
---|
832 | 810 | ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_BAND_FILTER); |
---|
833 | 811 | |
---|
834 | 812 | return ret; |
---|
835 | 813 | } |
---|
836 | 814 | |
---|
837 | | -static int ov6650_video_probe(struct i2c_client *client) |
---|
| 815 | +static int ov6650_video_probe(struct v4l2_subdev *sd) |
---|
838 | 816 | { |
---|
| 817 | + struct i2c_client *client = v4l2_get_subdevdata(sd); |
---|
839 | 818 | struct ov6650 *priv = to_ov6650(client); |
---|
840 | | - u8 pidh, pidl, midh, midl; |
---|
841 | | - int ret; |
---|
| 819 | + const struct ov6650_xclk *xclk = NULL; |
---|
| 820 | + unsigned long rate; |
---|
| 821 | + u8 pidh, pidl, midh, midl; |
---|
| 822 | + int i, ret = 0; |
---|
842 | 823 | |
---|
843 | 824 | priv->clk = v4l2_clk_get(&client->dev, NULL); |
---|
844 | 825 | if (IS_ERR(priv->clk)) { |
---|
.. | .. |
---|
847 | 828 | return ret; |
---|
848 | 829 | } |
---|
849 | 830 | |
---|
850 | | - ret = ov6650_s_power(&priv->subdev, 1); |
---|
| 831 | + rate = v4l2_clk_get_rate(priv->clk); |
---|
| 832 | + for (i = 0; rate && i < ARRAY_SIZE(ov6650_xclk); i++) { |
---|
| 833 | + if (rate != ov6650_xclk[i].rate) |
---|
| 834 | + continue; |
---|
| 835 | + |
---|
| 836 | + xclk = &ov6650_xclk[i]; |
---|
| 837 | + dev_info(&client->dev, "using host default clock rate %lukHz\n", |
---|
| 838 | + rate / 1000); |
---|
| 839 | + break; |
---|
| 840 | + } |
---|
| 841 | + for (i = 0; !xclk && i < ARRAY_SIZE(ov6650_xclk); i++) { |
---|
| 842 | + ret = v4l2_clk_set_rate(priv->clk, ov6650_xclk[i].rate); |
---|
| 843 | + if (ret || v4l2_clk_get_rate(priv->clk) != ov6650_xclk[i].rate) |
---|
| 844 | + continue; |
---|
| 845 | + |
---|
| 846 | + xclk = &ov6650_xclk[i]; |
---|
| 847 | + dev_info(&client->dev, "using negotiated clock rate %lukHz\n", |
---|
| 848 | + xclk->rate / 1000); |
---|
| 849 | + break; |
---|
| 850 | + } |
---|
| 851 | + if (!xclk) { |
---|
| 852 | + dev_err(&client->dev, "unable to get supported clock rate\n"); |
---|
| 853 | + if (!ret) |
---|
| 854 | + ret = -EINVAL; |
---|
| 855 | + goto eclkput; |
---|
| 856 | + } |
---|
| 857 | + |
---|
| 858 | + ret = ov6650_s_power(sd, 1); |
---|
851 | 859 | if (ret < 0) |
---|
852 | 860 | goto eclkput; |
---|
853 | 861 | |
---|
.. | .. |
---|
880 | 888 | |
---|
881 | 889 | ret = ov6650_reset(client); |
---|
882 | 890 | if (!ret) |
---|
883 | | - ret = ov6650_prog_dflt(client); |
---|
| 891 | + ret = ov6650_prog_dflt(client, xclk->clkrc); |
---|
| 892 | + if (!ret) { |
---|
| 893 | + struct v4l2_mbus_framefmt mf = ov6650_def_fmt; |
---|
| 894 | + |
---|
| 895 | + ret = ov6650_s_fmt(sd, &mf); |
---|
| 896 | + } |
---|
884 | 897 | if (!ret) |
---|
885 | 898 | ret = v4l2_ctrl_handler_setup(&priv->hdl); |
---|
886 | 899 | |
---|
887 | 900 | done: |
---|
888 | | - ov6650_s_power(&priv->subdev, 0); |
---|
| 901 | + ov6650_s_power(sd, 0); |
---|
889 | 902 | if (!ret) |
---|
890 | 903 | return 0; |
---|
891 | 904 | eclkput: |
---|
.. | .. |
---|
908 | 921 | }; |
---|
909 | 922 | |
---|
910 | 923 | /* Request bus settings on camera side */ |
---|
911 | | -static int ov6650_g_mbus_config(struct v4l2_subdev *sd, |
---|
912 | | - struct v4l2_mbus_config *cfg) |
---|
| 924 | +static int ov6650_get_mbus_config(struct v4l2_subdev *sd, |
---|
| 925 | + unsigned int pad, |
---|
| 926 | + struct v4l2_mbus_config *cfg) |
---|
913 | 927 | { |
---|
| 928 | + struct i2c_client *client = v4l2_get_subdevdata(sd); |
---|
| 929 | + u8 comj, comf; |
---|
| 930 | + int ret; |
---|
914 | 931 | |
---|
915 | | - cfg->flags = V4L2_MBUS_MASTER | |
---|
916 | | - V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | |
---|
917 | | - V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW | |
---|
918 | | - V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | |
---|
919 | | - V4L2_MBUS_DATA_ACTIVE_HIGH; |
---|
| 932 | + ret = ov6650_reg_read(client, REG_COMJ, &comj); |
---|
| 933 | + if (ret) |
---|
| 934 | + return ret; |
---|
| 935 | + |
---|
| 936 | + ret = ov6650_reg_read(client, REG_COMF, &comf); |
---|
| 937 | + if (ret) |
---|
| 938 | + return ret; |
---|
| 939 | + |
---|
| 940 | + cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH |
---|
| 941 | + | ((comj & COMJ_VSYNC_HIGH) ? V4L2_MBUS_VSYNC_ACTIVE_HIGH |
---|
| 942 | + : V4L2_MBUS_VSYNC_ACTIVE_LOW) |
---|
| 943 | + | ((comf & COMF_HREF_LOW) ? V4L2_MBUS_HSYNC_ACTIVE_LOW |
---|
| 944 | + : V4L2_MBUS_HSYNC_ACTIVE_HIGH) |
---|
| 945 | + | ((comj & COMJ_PCLK_RISING) ? V4L2_MBUS_PCLK_SAMPLE_RISING |
---|
| 946 | + : V4L2_MBUS_PCLK_SAMPLE_FALLING); |
---|
920 | 947 | cfg->type = V4L2_MBUS_PARALLEL; |
---|
921 | 948 | |
---|
922 | 949 | return 0; |
---|
923 | 950 | } |
---|
924 | 951 | |
---|
925 | 952 | /* Alter bus settings on camera side */ |
---|
926 | | -static int ov6650_s_mbus_config(struct v4l2_subdev *sd, |
---|
927 | | - const struct v4l2_mbus_config *cfg) |
---|
| 953 | +static int ov6650_set_mbus_config(struct v4l2_subdev *sd, |
---|
| 954 | + unsigned int pad, |
---|
| 955 | + struct v4l2_mbus_config *cfg) |
---|
928 | 956 | { |
---|
929 | 957 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
---|
930 | | - int ret; |
---|
| 958 | + int ret = 0; |
---|
931 | 959 | |
---|
932 | 960 | if (cfg->flags & V4L2_MBUS_PCLK_SAMPLE_RISING) |
---|
933 | 961 | ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_PCLK_RISING, 0); |
---|
934 | | - else |
---|
| 962 | + else if (cfg->flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) |
---|
935 | 963 | ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_PCLK_RISING); |
---|
936 | 964 | if (ret) |
---|
937 | 965 | return ret; |
---|
938 | 966 | |
---|
939 | 967 | if (cfg->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) |
---|
940 | 968 | ret = ov6650_reg_rmw(client, REG_COMF, COMF_HREF_LOW, 0); |
---|
941 | | - else |
---|
| 969 | + else if (cfg->flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) |
---|
942 | 970 | ret = ov6650_reg_rmw(client, REG_COMF, 0, COMF_HREF_LOW); |
---|
943 | 971 | if (ret) |
---|
944 | 972 | return ret; |
---|
945 | 973 | |
---|
946 | 974 | if (cfg->flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) |
---|
947 | 975 | ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_VSYNC_HIGH, 0); |
---|
948 | | - else |
---|
| 976 | + else if (cfg->flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) |
---|
949 | 977 | ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_VSYNC_HIGH); |
---|
| 978 | + if (ret) |
---|
| 979 | + return ret; |
---|
950 | 980 | |
---|
951 | | - return ret; |
---|
| 981 | + /* |
---|
| 982 | + * Update the configuration to report what is actually applied to |
---|
| 983 | + * the hardware. |
---|
| 984 | + */ |
---|
| 985 | + return ov6650_get_mbus_config(sd, pad, cfg); |
---|
952 | 986 | } |
---|
953 | 987 | |
---|
954 | 988 | static const struct v4l2_subdev_video_ops ov6650_video_ops = { |
---|
955 | 989 | .s_stream = ov6650_s_stream, |
---|
956 | 990 | .g_frame_interval = ov6650_g_frame_interval, |
---|
957 | 991 | .s_frame_interval = ov6650_s_frame_interval, |
---|
958 | | - .g_mbus_config = ov6650_g_mbus_config, |
---|
959 | | - .s_mbus_config = ov6650_s_mbus_config, |
---|
960 | 992 | }; |
---|
961 | 993 | |
---|
962 | 994 | static const struct v4l2_subdev_pad_ops ov6650_pad_ops = { |
---|
.. | .. |
---|
965 | 997 | .set_selection = ov6650_set_selection, |
---|
966 | 998 | .get_fmt = ov6650_get_fmt, |
---|
967 | 999 | .set_fmt = ov6650_set_fmt, |
---|
| 1000 | + .get_mbus_config = ov6650_get_mbus_config, |
---|
| 1001 | + .set_mbus_config = ov6650_set_mbus_config, |
---|
968 | 1002 | }; |
---|
969 | 1003 | |
---|
970 | 1004 | static const struct v4l2_subdev_ops ov6650_subdev_ops = { |
---|
971 | 1005 | .core = &ov6650_core_ops, |
---|
972 | 1006 | .video = &ov6650_video_ops, |
---|
973 | 1007 | .pad = &ov6650_pad_ops, |
---|
| 1008 | +}; |
---|
| 1009 | + |
---|
| 1010 | +static const struct v4l2_subdev_internal_ops ov6650_internal_ops = { |
---|
| 1011 | + .registered = ov6650_video_probe, |
---|
974 | 1012 | }; |
---|
975 | 1013 | |
---|
976 | 1014 | /* |
---|
.. | .. |
---|
1017 | 1055 | V4L2_CID_GAMMA, 0, 0xff, 1, 0x12); |
---|
1018 | 1056 | |
---|
1019 | 1057 | priv->subdev.ctrl_handler = &priv->hdl; |
---|
1020 | | - if (priv->hdl.error) |
---|
1021 | | - return priv->hdl.error; |
---|
| 1058 | + if (priv->hdl.error) { |
---|
| 1059 | + ret = priv->hdl.error; |
---|
| 1060 | + goto ectlhdlfree; |
---|
| 1061 | + } |
---|
1022 | 1062 | |
---|
1023 | 1063 | v4l2_ctrl_auto_cluster(2, &priv->autogain, 0, true); |
---|
1024 | 1064 | v4l2_ctrl_auto_cluster(3, &priv->autowb, 0, true); |
---|
.. | .. |
---|
1029 | 1069 | priv->rect.top = DEF_VSTRT << 1; |
---|
1030 | 1070 | priv->rect.width = W_CIF; |
---|
1031 | 1071 | priv->rect.height = H_CIF; |
---|
1032 | | - priv->half_scale = false; |
---|
1033 | | - priv->code = MEDIA_BUS_FMT_YUYV8_2X8; |
---|
1034 | 1072 | |
---|
1035 | | - ret = ov6650_video_probe(client); |
---|
1036 | | - if (ret) |
---|
1037 | | - v4l2_ctrl_handler_free(&priv->hdl); |
---|
| 1073 | + /* Hardware default frame interval */ |
---|
| 1074 | + priv->tpf.numerator = GET_CLKRC_DIV(DEF_CLKRC); |
---|
| 1075 | + priv->tpf.denominator = FRAME_RATE_MAX; |
---|
| 1076 | + |
---|
| 1077 | + priv->subdev.internal_ops = &ov6650_internal_ops; |
---|
| 1078 | + |
---|
| 1079 | + ret = v4l2_async_register_subdev(&priv->subdev); |
---|
| 1080 | + if (!ret) |
---|
| 1081 | + return 0; |
---|
| 1082 | +ectlhdlfree: |
---|
| 1083 | + v4l2_ctrl_handler_free(&priv->hdl); |
---|
1038 | 1084 | |
---|
1039 | 1085 | return ret; |
---|
1040 | 1086 | } |
---|
.. | .. |
---|
1044 | 1090 | struct ov6650 *priv = to_ov6650(client); |
---|
1045 | 1091 | |
---|
1046 | 1092 | v4l2_clk_put(priv->clk); |
---|
1047 | | - v4l2_device_unregister_subdev(&priv->subdev); |
---|
| 1093 | + v4l2_async_unregister_subdev(&priv->subdev); |
---|
1048 | 1094 | v4l2_ctrl_handler_free(&priv->hdl); |
---|
1049 | 1095 | return 0; |
---|
1050 | 1096 | } |
---|
.. | .. |
---|
1066 | 1112 | |
---|
1067 | 1113 | module_i2c_driver(ov6650_i2c_driver); |
---|
1068 | 1114 | |
---|
1069 | | -MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV6650"); |
---|
1070 | | -MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>"); |
---|
| 1115 | +MODULE_DESCRIPTION("V4L2 subdevice driver for OmniVision OV6650 camera sensor"); |
---|
| 1116 | +MODULE_AUTHOR("Janusz Krzysztofik <jmkrzyszt@gmail.com"); |
---|
1071 | 1117 | MODULE_LICENSE("GPL v2"); |
---|