diff options
author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2009-12-11 09:46:49 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-12-16 06:27:29 -0500 |
commit | 760697beca338599a65484389c7abbe54aedb664 (patch) | |
tree | 515735429d2240629a6f048ab1a7fefaf5299e46 /drivers/media/video/rj54n1cb0c.c | |
parent | 9a74251d8bee7a25fee89a0be3ccea73e01c1a05 (diff) |
V4L/DVB (13659): soc-camera: convert to the new mediabus API
Convert soc-camera core and all soc-camera drivers to the new mediabus
API. This also takes soc-camera client drivers one step closer to also be
usable with generic v4l2-subdev host drivers.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Acked-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/rj54n1cb0c.c')
-rw-r--r-- | drivers/media/video/rj54n1cb0c.c | 201 |
1 files changed, 149 insertions, 52 deletions
diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c index 373f2a30a677..7b08bff443f5 100644 --- a/drivers/media/video/rj54n1cb0c.c +++ b/drivers/media/video/rj54n1cb0c.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <media/v4l2-subdev.h> | 16 | #include <media/v4l2-subdev.h> |
17 | #include <media/v4l2-chip-ident.h> | 17 | #include <media/v4l2-chip-ident.h> |
18 | #include <media/soc_camera.h> | 18 | #include <media/soc_camera.h> |
19 | #include <media/soc_mediabus.h> | ||
19 | 20 | ||
20 | #define RJ54N1_DEV_CODE 0x0400 | 21 | #define RJ54N1_DEV_CODE 0x0400 |
21 | #define RJ54N1_DEV_CODE2 0x0401 | 22 | #define RJ54N1_DEV_CODE2 0x0401 |
@@ -85,18 +86,35 @@ | |||
85 | 86 | ||
86 | /* I2C addresses: 0x50, 0x51, 0x60, 0x61 */ | 87 | /* I2C addresses: 0x50, 0x51, 0x60, 0x61 */ |
87 | 88 | ||
88 | static const struct soc_camera_data_format rj54n1_colour_formats[] = { | 89 | /* RJ54N1CB0C has only one fixed colorspace per pixelcode */ |
89 | { | 90 | struct rj54n1_datafmt { |
90 | .name = "YUYV", | 91 | enum v4l2_mbus_pixelcode code; |
91 | .depth = 16, | 92 | enum v4l2_colorspace colorspace; |
92 | .fourcc = V4L2_PIX_FMT_YUYV, | 93 | }; |
93 | .colorspace = V4L2_COLORSPACE_JPEG, | 94 | |
94 | }, { | 95 | /* Find a data format by a pixel code in an array */ |
95 | .name = "RGB565", | 96 | static const struct rj54n1_datafmt *rj54n1_find_datafmt( |
96 | .depth = 16, | 97 | enum v4l2_mbus_pixelcode code, const struct rj54n1_datafmt *fmt, |
97 | .fourcc = V4L2_PIX_FMT_RGB565, | 98 | int n) |
98 | .colorspace = V4L2_COLORSPACE_SRGB, | 99 | { |
99 | } | 100 | int i; |
101 | for (i = 0; i < n; i++) | ||
102 | if (fmt[i].code == code) | ||
103 | return fmt + i; | ||
104 | |||
105 | return NULL; | ||
106 | } | ||
107 | |||
108 | static const struct rj54n1_datafmt rj54n1_colour_fmts[] = { | ||
109 | {V4L2_MBUS_FMT_YUYV8_2X8_LE, V4L2_COLORSPACE_JPEG}, | ||
110 | {V4L2_MBUS_FMT_YVYU8_2X8_LE, V4L2_COLORSPACE_JPEG}, | ||
111 | {V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB}, | ||
112 | {V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB}, | ||
113 | {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB}, | ||
114 | {V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE, V4L2_COLORSPACE_SRGB}, | ||
115 | {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB}, | ||
116 | {V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE, V4L2_COLORSPACE_SRGB}, | ||
117 | {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB}, | ||
100 | }; | 118 | }; |
101 | 119 | ||
102 | struct rj54n1_clock_div { | 120 | struct rj54n1_clock_div { |
@@ -109,12 +127,12 @@ struct rj54n1_clock_div { | |||
109 | 127 | ||
110 | struct rj54n1 { | 128 | struct rj54n1 { |
111 | struct v4l2_subdev subdev; | 129 | struct v4l2_subdev subdev; |
130 | const struct rj54n1_datafmt *fmt; | ||
112 | struct v4l2_rect rect; /* Sensor window */ | 131 | struct v4l2_rect rect; /* Sensor window */ |
113 | unsigned short width; /* Output window */ | 132 | unsigned short width; /* Output window */ |
114 | unsigned short height; | 133 | unsigned short height; |
115 | unsigned short resize; /* Sensor * 1024 / resize = Output */ | 134 | unsigned short resize; /* Sensor * 1024 / resize = Output */ |
116 | struct rj54n1_clock_div clk_div; | 135 | struct rj54n1_clock_div clk_div; |
117 | u32 fourcc; | ||
118 | unsigned short scale; | 136 | unsigned short scale; |
119 | u8 bank; | 137 | u8 bank; |
120 | }; | 138 | }; |
@@ -440,6 +458,16 @@ static int reg_write_multiple(struct i2c_client *client, | |||
440 | return 0; | 458 | return 0; |
441 | } | 459 | } |
442 | 460 | ||
461 | static int rj54n1_enum_fmt(struct v4l2_subdev *sd, int index, | ||
462 | enum v4l2_mbus_pixelcode *code) | ||
463 | { | ||
464 | if ((unsigned int)index >= ARRAY_SIZE(rj54n1_colour_fmts)) | ||
465 | return -EINVAL; | ||
466 | |||
467 | *code = rj54n1_colour_fmts[index].code; | ||
468 | return 0; | ||
469 | } | ||
470 | |||
443 | static int rj54n1_s_stream(struct v4l2_subdev *sd, int enable) | 471 | static int rj54n1_s_stream(struct v4l2_subdev *sd, int enable) |
444 | { | 472 | { |
445 | /* TODO: start / stop streaming */ | 473 | /* TODO: start / stop streaming */ |
@@ -527,16 +555,17 @@ static int rj54n1_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
527 | return 0; | 555 | return 0; |
528 | } | 556 | } |
529 | 557 | ||
530 | static int rj54n1_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 558 | static int rj54n1_g_fmt(struct v4l2_subdev *sd, |
559 | struct v4l2_mbus_framefmt *mf) | ||
531 | { | 560 | { |
532 | struct i2c_client *client = sd->priv; | 561 | struct i2c_client *client = sd->priv; |
533 | struct rj54n1 *rj54n1 = to_rj54n1(client); | 562 | struct rj54n1 *rj54n1 = to_rj54n1(client); |
534 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
535 | 563 | ||
536 | pix->pixelformat = rj54n1->fourcc; | 564 | mf->code = rj54n1->fmt->code; |
537 | pix->field = V4L2_FIELD_NONE; | 565 | mf->colorspace = rj54n1->fmt->colorspace; |
538 | pix->width = rj54n1->width; | 566 | mf->field = V4L2_FIELD_NONE; |
539 | pix->height = rj54n1->height; | 567 | mf->width = rj54n1->width; |
568 | mf->height = rj54n1->height; | ||
540 | 569 | ||
541 | return 0; | 570 | return 0; |
542 | } | 571 | } |
@@ -787,26 +816,44 @@ static int rj54n1_reg_init(struct i2c_client *client) | |||
787 | } | 816 | } |
788 | 817 | ||
789 | /* FIXME: streaming output only up to 800x600 is functional */ | 818 | /* FIXME: streaming output only up to 800x600 is functional */ |
790 | static int rj54n1_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 819 | static int rj54n1_try_fmt(struct v4l2_subdev *sd, |
820 | struct v4l2_mbus_framefmt *mf) | ||
791 | { | 821 | { |
792 | struct v4l2_pix_format *pix = &f->fmt.pix; | 822 | struct i2c_client *client = sd->priv; |
823 | struct rj54n1 *rj54n1 = to_rj54n1(client); | ||
824 | const struct rj54n1_datafmt *fmt; | ||
825 | int align = mf->code == V4L2_MBUS_FMT_SBGGR10_1X10 || | ||
826 | mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE || | ||
827 | mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE || | ||
828 | mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE || | ||
829 | mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE; | ||
830 | |||
831 | dev_dbg(&client->dev, "%s: code = %d, width = %u, height = %u\n", | ||
832 | __func__, mf->code, mf->width, mf->height); | ||
833 | |||
834 | fmt = rj54n1_find_datafmt(mf->code, rj54n1_colour_fmts, | ||
835 | ARRAY_SIZE(rj54n1_colour_fmts)); | ||
836 | if (!fmt) { | ||
837 | fmt = rj54n1->fmt; | ||
838 | mf->code = fmt->code; | ||
839 | } | ||
793 | 840 | ||
794 | pix->field = V4L2_FIELD_NONE; | 841 | mf->field = V4L2_FIELD_NONE; |
842 | mf->colorspace = fmt->colorspace; | ||
795 | 843 | ||
796 | if (pix->width > 800) | 844 | v4l_bound_align_image(&mf->width, 112, RJ54N1_MAX_WIDTH, align, |
797 | pix->width = 800; | 845 | &mf->height, 84, RJ54N1_MAX_HEIGHT, align, 0); |
798 | if (pix->height > 600) | ||
799 | pix->height = 600; | ||
800 | 846 | ||
801 | return 0; | 847 | return 0; |
802 | } | 848 | } |
803 | 849 | ||
804 | static int rj54n1_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 850 | static int rj54n1_s_fmt(struct v4l2_subdev *sd, |
851 | struct v4l2_mbus_framefmt *mf) | ||
805 | { | 852 | { |
806 | struct i2c_client *client = sd->priv; | 853 | struct i2c_client *client = sd->priv; |
807 | struct rj54n1 *rj54n1 = to_rj54n1(client); | 854 | struct rj54n1 *rj54n1 = to_rj54n1(client); |
808 | struct v4l2_pix_format *pix = &f->fmt.pix; | 855 | const struct rj54n1_datafmt *fmt; |
809 | unsigned int output_w, output_h, | 856 | unsigned int output_w, output_h, max_w, max_h, |
810 | input_w = rj54n1->rect.width, input_h = rj54n1->rect.height; | 857 | input_w = rj54n1->rect.width, input_h = rj54n1->rect.height; |
811 | int ret; | 858 | int ret; |
812 | 859 | ||
@@ -814,7 +861,7 @@ static int rj54n1_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | |||
814 | * The host driver can call us without .try_fmt(), so, we have to take | 861 | * The host driver can call us without .try_fmt(), so, we have to take |
815 | * care ourseleves | 862 | * care ourseleves |
816 | */ | 863 | */ |
817 | ret = rj54n1_try_fmt(sd, f); | 864 | ret = rj54n1_try_fmt(sd, mf); |
818 | 865 | ||
819 | /* | 866 | /* |
820 | * Verify if the sensor has just been powered on. TODO: replace this | 867 | * Verify if the sensor has just been powered on. TODO: replace this |
@@ -832,49 +879,101 @@ static int rj54n1_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | |||
832 | } | 879 | } |
833 | 880 | ||
834 | /* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */ | 881 | /* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */ |
835 | switch (pix->pixelformat) { | 882 | switch (mf->code) { |
836 | case V4L2_PIX_FMT_YUYV: | 883 | case V4L2_MBUS_FMT_YUYV8_2X8_LE: |
837 | ret = reg_write(client, RJ54N1_OUT_SEL, 0); | 884 | ret = reg_write(client, RJ54N1_OUT_SEL, 0); |
838 | if (!ret) | 885 | if (!ret) |
839 | ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); | 886 | ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); |
840 | break; | 887 | break; |
841 | case V4L2_PIX_FMT_RGB565: | 888 | case V4L2_MBUS_FMT_YVYU8_2X8_LE: |
889 | ret = reg_write(client, RJ54N1_OUT_SEL, 0); | ||
890 | if (!ret) | ||
891 | ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8); | ||
892 | break; | ||
893 | case V4L2_MBUS_FMT_RGB565_2X8_LE: | ||
842 | ret = reg_write(client, RJ54N1_OUT_SEL, 0x11); | 894 | ret = reg_write(client, RJ54N1_OUT_SEL, 0x11); |
843 | if (!ret) | 895 | if (!ret) |
844 | ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); | 896 | ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); |
845 | break; | 897 | break; |
898 | case V4L2_MBUS_FMT_RGB565_2X8_BE: | ||
899 | ret = reg_write(client, RJ54N1_OUT_SEL, 0x11); | ||
900 | if (!ret) | ||
901 | ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8); | ||
902 | break; | ||
903 | case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE: | ||
904 | ret = reg_write(client, RJ54N1_OUT_SEL, 4); | ||
905 | if (!ret) | ||
906 | ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); | ||
907 | if (!ret) | ||
908 | ret = reg_write(client, RJ54N1_RA_SEL_UL, 0); | ||
909 | break; | ||
910 | case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE: | ||
911 | ret = reg_write(client, RJ54N1_OUT_SEL, 4); | ||
912 | if (!ret) | ||
913 | ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); | ||
914 | if (!ret) | ||
915 | ret = reg_write(client, RJ54N1_RA_SEL_UL, 8); | ||
916 | break; | ||
917 | case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE: | ||
918 | ret = reg_write(client, RJ54N1_OUT_SEL, 4); | ||
919 | if (!ret) | ||
920 | ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8); | ||
921 | if (!ret) | ||
922 | ret = reg_write(client, RJ54N1_RA_SEL_UL, 0); | ||
923 | break; | ||
924 | case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE: | ||
925 | ret = reg_write(client, RJ54N1_OUT_SEL, 4); | ||
926 | if (!ret) | ||
927 | ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8); | ||
928 | if (!ret) | ||
929 | ret = reg_write(client, RJ54N1_RA_SEL_UL, 8); | ||
930 | break; | ||
931 | case V4L2_MBUS_FMT_SBGGR10_1X10: | ||
932 | ret = reg_write(client, RJ54N1_OUT_SEL, 5); | ||
933 | break; | ||
846 | default: | 934 | default: |
847 | ret = -EINVAL; | 935 | ret = -EINVAL; |
848 | } | 936 | } |
849 | 937 | ||
938 | /* Special case: a raw mode with 10 bits of data per clock tick */ | ||
939 | if (!ret) | ||
940 | ret = reg_set(client, RJ54N1_OCLK_SEL_EN, | ||
941 | (mf->code == V4L2_MBUS_FMT_SBGGR10_1X10) << 1, 2); | ||
942 | |||
850 | if (ret < 0) | 943 | if (ret < 0) |
851 | return ret; | 944 | return ret; |
852 | 945 | ||
853 | /* Supported scales 1:1 - 1:16 */ | 946 | /* Supported scales 1:1 >= scale > 1:16 */ |
854 | if (pix->width < input_w / 16) | 947 | max_w = mf->width * (16 * 1024 - 1) / 1024; |
855 | pix->width = input_w / 16; | 948 | if (input_w > max_w) |
856 | if (pix->height < input_h / 16) | 949 | input_w = max_w; |
857 | pix->height = input_h / 16; | 950 | max_h = mf->height * (16 * 1024 - 1) / 1024; |
951 | if (input_h > max_h) | ||
952 | input_h = max_h; | ||
858 | 953 | ||
859 | output_w = pix->width; | 954 | output_w = mf->width; |
860 | output_h = pix->height; | 955 | output_h = mf->height; |
861 | 956 | ||
862 | ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h); | 957 | ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h); |
863 | if (ret < 0) | 958 | if (ret < 0) |
864 | return ret; | 959 | return ret; |
865 | 960 | ||
866 | rj54n1->fourcc = pix->pixelformat; | 961 | fmt = rj54n1_find_datafmt(mf->code, rj54n1_colour_fmts, |
962 | ARRAY_SIZE(rj54n1_colour_fmts)); | ||
963 | |||
964 | rj54n1->fmt = fmt; | ||
867 | rj54n1->resize = ret; | 965 | rj54n1->resize = ret; |
868 | rj54n1->rect.width = input_w; | 966 | rj54n1->rect.width = input_w; |
869 | rj54n1->rect.height = input_h; | 967 | rj54n1->rect.height = input_h; |
870 | rj54n1->width = output_w; | 968 | rj54n1->width = output_w; |
871 | rj54n1->height = output_h; | 969 | rj54n1->height = output_h; |
872 | 970 | ||
873 | pix->width = output_w; | 971 | mf->width = output_w; |
874 | pix->height = output_h; | 972 | mf->height = output_h; |
875 | pix->field = V4L2_FIELD_NONE; | 973 | mf->field = V4L2_FIELD_NONE; |
974 | mf->colorspace = fmt->colorspace; | ||
876 | 975 | ||
877 | return ret; | 976 | return 0; |
878 | } | 977 | } |
879 | 978 | ||
880 | static int rj54n1_g_chip_ident(struct v4l2_subdev *sd, | 979 | static int rj54n1_g_chip_ident(struct v4l2_subdev *sd, |
@@ -1054,9 +1153,10 @@ static struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = { | |||
1054 | 1153 | ||
1055 | static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { | 1154 | static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { |
1056 | .s_stream = rj54n1_s_stream, | 1155 | .s_stream = rj54n1_s_stream, |
1057 | .s_fmt = rj54n1_s_fmt, | 1156 | .s_mbus_fmt = rj54n1_s_fmt, |
1058 | .g_fmt = rj54n1_g_fmt, | 1157 | .g_mbus_fmt = rj54n1_g_fmt, |
1059 | .try_fmt = rj54n1_try_fmt, | 1158 | .try_mbus_fmt = rj54n1_try_fmt, |
1159 | .enum_mbus_fmt = rj54n1_enum_fmt, | ||
1060 | .g_crop = rj54n1_g_crop, | 1160 | .g_crop = rj54n1_g_crop, |
1061 | .cropcap = rj54n1_cropcap, | 1161 | .cropcap = rj54n1_cropcap, |
1062 | }; | 1162 | }; |
@@ -1153,7 +1253,7 @@ static int rj54n1_probe(struct i2c_client *client, | |||
1153 | rj54n1->rect.height = RJ54N1_MAX_HEIGHT; | 1253 | rj54n1->rect.height = RJ54N1_MAX_HEIGHT; |
1154 | rj54n1->width = RJ54N1_MAX_WIDTH; | 1254 | rj54n1->width = RJ54N1_MAX_WIDTH; |
1155 | rj54n1->height = RJ54N1_MAX_HEIGHT; | 1255 | rj54n1->height = RJ54N1_MAX_HEIGHT; |
1156 | rj54n1->fourcc = V4L2_PIX_FMT_YUYV; | 1256 | rj54n1->fmt = &rj54n1_colour_fmts[0]; |
1157 | rj54n1->resize = 1024; | 1257 | rj54n1->resize = 1024; |
1158 | 1258 | ||
1159 | ret = rj54n1_video_probe(icd, client); | 1259 | ret = rj54n1_video_probe(icd, client); |
@@ -1164,9 +1264,6 @@ static int rj54n1_probe(struct i2c_client *client, | |||
1164 | return ret; | 1264 | return ret; |
1165 | } | 1265 | } |
1166 | 1266 | ||
1167 | icd->formats = rj54n1_colour_formats; | ||
1168 | icd->num_formats = ARRAY_SIZE(rj54n1_colour_formats); | ||
1169 | |||
1170 | return ret; | 1267 | return ret; |
1171 | } | 1268 | } |
1172 | 1269 | ||