diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-24 13:21:51 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-24 13:21:51 -0400 |
commit | ab11ca34eea8fda7a1a9302d86f6ef6108ffd68f (patch) | |
tree | 987ec6c263f3dfa4a7a6f9ce4d5ece47cbc12e29 /drivers/media/video/omap3isp/ispccdc.c | |
parent | f9369910a6225b8d4892c3f20ae740a711cd5ace (diff) | |
parent | 71006fb22b0f5a2045605b3887ee99a0e9adafe4 (diff) |
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- some V4L2 API updates needed by embedded devices
- DVB API extensions for ATSC-MH delivery system, used in US for mobile
TV
- new tuners for fc0011/0012/0013 and tua9001
- a new dvb driver for af9033/9035
- a new ATSC-MH frontend (lg2160)
- new remote controller keymaps
- Removal of a few legacy webcam driver that got replaced by gspca on
several kernel versions ago
- a new driver for Exynos 4/5 webcams(s5pp fimc-lite)
- a new webcam sensor driver (smiapp)
- a new video input driver for embedded (sta2x1xx)
- several improvements, fixes, cleanups, etc inside the drivers.
Manually fix up conflicts due to err() -> dev_err() conversion in
drivers/staging/media/easycap/easycap_main.c
* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (484 commits)
[media] saa7134-cards: Remove a PCI entry added by mistake
[media] radio-sf16fmi: add support for SF16-FMD
[media] rc-loopback: remove duplicate line
[media] patch for Asus My Cinema PS3-100 (1043:48cd)
[media] au0828: Move the Kconfig knob under V4L_USB_DRIVERS
[media] em28xx: simple comment fix
[media] [resend] radio-sf16fmr2: add PnP support for SF16-FMD2
[media] smiapp: Use v4l2_ctrl_new_int_menu() instead of v4l2_ctrl_new_custom()
[media] smiapp: Add support for 8-bit uncompressed formats
[media] smiapp: Allow generic quirk registers
[media] smiapp: Use non-binning limits if the binning limit is zero
[media] smiapp: Initialise rval in smiapp_read_nvm()
[media] smiapp: Round minimum pre_pll up rather than down in ip_clk_freq check
[media] smiapp: Use 8-bit reads only before identifying the sensor
[media] smiapp: Quirk for sensors that only do 8-bit reads
[media] smiapp: Pass struct sensor to register writing commands instead of i2c_client
[media] smiapp: Allow using external clock from the clock framework
[media] zl10353: change .read_snr() to report SNR as a 0.1 dB
[media] media: add support to gspca/pac7302.c for 093a:2627 (Genius FaceCam 300)
[media] m88rs2000 - only flip bit 2 on reg 0x70 on 16th try
...
Diffstat (limited to 'drivers/media/video/omap3isp/ispccdc.c')
-rw-r--r-- | drivers/media/video/omap3isp/ispccdc.c | 256 |
1 files changed, 238 insertions, 18 deletions
diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index eaabc27f0fa2..7e32331b60fb 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c | |||
@@ -38,6 +38,9 @@ | |||
38 | #include "ispreg.h" | 38 | #include "ispreg.h" |
39 | #include "ispccdc.h" | 39 | #include "ispccdc.h" |
40 | 40 | ||
41 | #define CCDC_MIN_WIDTH 32 | ||
42 | #define CCDC_MIN_HEIGHT 32 | ||
43 | |||
41 | static struct v4l2_mbus_framefmt * | 44 | static struct v4l2_mbus_framefmt * |
42 | __ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, | 45 | __ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, |
43 | unsigned int pad, enum v4l2_subdev_format_whence which); | 46 | unsigned int pad, enum v4l2_subdev_format_whence which); |
@@ -836,8 +839,8 @@ static void ccdc_config_vp(struct isp_ccdc_device *ccdc) | |||
836 | 839 | ||
837 | if (pipe->input) | 840 | if (pipe->input) |
838 | div = DIV_ROUND_UP(l3_ick, pipe->max_rate); | 841 | div = DIV_ROUND_UP(l3_ick, pipe->max_rate); |
839 | else if (ccdc->vpcfg.pixelclk) | 842 | else if (pipe->external_rate) |
840 | div = l3_ick / ccdc->vpcfg.pixelclk; | 843 | div = l3_ick / pipe->external_rate; |
841 | 844 | ||
842 | div = clamp(div, 2U, max_div); | 845 | div = clamp(div, 2U, max_div); |
843 | fmtcfg_vp |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT; | 846 | fmtcfg_vp |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT; |
@@ -1118,6 +1121,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) | |||
1118 | struct isp_parallel_platform_data *pdata = NULL; | 1121 | struct isp_parallel_platform_data *pdata = NULL; |
1119 | struct v4l2_subdev *sensor; | 1122 | struct v4l2_subdev *sensor; |
1120 | struct v4l2_mbus_framefmt *format; | 1123 | struct v4l2_mbus_framefmt *format; |
1124 | const struct v4l2_rect *crop; | ||
1121 | const struct isp_format_info *fmt_info; | 1125 | const struct isp_format_info *fmt_info; |
1122 | struct v4l2_subdev_format fmt_src; | 1126 | struct v4l2_subdev_format fmt_src; |
1123 | unsigned int depth_out; | 1127 | unsigned int depth_out; |
@@ -1211,14 +1215,14 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) | |||
1211 | OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VDINT); | 1215 | OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VDINT); |
1212 | 1216 | ||
1213 | /* CCDC_PAD_SOURCE_OF */ | 1217 | /* CCDC_PAD_SOURCE_OF */ |
1214 | format = &ccdc->formats[CCDC_PAD_SOURCE_OF]; | 1218 | crop = &ccdc->crop; |
1215 | 1219 | ||
1216 | isp_reg_writel(isp, (0 << ISPCCDC_HORZ_INFO_SPH_SHIFT) | | 1220 | isp_reg_writel(isp, (crop->left << ISPCCDC_HORZ_INFO_SPH_SHIFT) | |
1217 | ((format->width - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT), | 1221 | ((crop->width - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT), |
1218 | OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO); | 1222 | OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO); |
1219 | isp_reg_writel(isp, 0 << ISPCCDC_VERT_START_SLV0_SHIFT, | 1223 | isp_reg_writel(isp, crop->top << ISPCCDC_VERT_START_SLV0_SHIFT, |
1220 | OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_START); | 1224 | OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_START); |
1221 | isp_reg_writel(isp, (format->height - 1) | 1225 | isp_reg_writel(isp, (crop->height - 1) |
1222 | << ISPCCDC_VERT_LINES_NLV_SHIFT, | 1226 | << ISPCCDC_VERT_LINES_NLV_SHIFT, |
1223 | OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_LINES); | 1227 | OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_LINES); |
1224 | 1228 | ||
@@ -1410,6 +1414,9 @@ static void ccdc_hs_vs_isr(struct isp_ccdc_device *ccdc) | |||
1410 | struct video_device *vdev = ccdc->subdev.devnode; | 1414 | struct video_device *vdev = ccdc->subdev.devnode; |
1411 | struct v4l2_event event; | 1415 | struct v4l2_event event; |
1412 | 1416 | ||
1417 | /* Frame number propagation */ | ||
1418 | atomic_inc(&pipe->frame_number); | ||
1419 | |||
1413 | memset(&event, 0, sizeof(event)); | 1420 | memset(&event, 0, sizeof(event)); |
1414 | event.type = V4L2_EVENT_FRAME_SYNC; | 1421 | event.type = V4L2_EVENT_FRAME_SYNC; |
1415 | event.u.frame_sync.frame_sequence = atomic_read(&pipe->frame_number); | 1422 | event.u.frame_sync.frame_sequence = atomic_read(&pipe->frame_number); |
@@ -1703,7 +1710,7 @@ static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, | |||
1703 | if (sub->id != 0) | 1710 | if (sub->id != 0) |
1704 | return -EINVAL; | 1711 | return -EINVAL; |
1705 | 1712 | ||
1706 | return v4l2_event_subscribe(fh, sub, OMAP3ISP_CCDC_NEVENTS); | 1713 | return v4l2_event_subscribe(fh, sub, OMAP3ISP_CCDC_NEVENTS, NULL); |
1707 | } | 1714 | } |
1708 | 1715 | ||
1709 | static int ccdc_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, | 1716 | static int ccdc_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, |
@@ -1790,6 +1797,16 @@ __ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, | |||
1790 | return &ccdc->formats[pad]; | 1797 | return &ccdc->formats[pad]; |
1791 | } | 1798 | } |
1792 | 1799 | ||
1800 | static struct v4l2_rect * | ||
1801 | __ccdc_get_crop(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, | ||
1802 | enum v4l2_subdev_format_whence which) | ||
1803 | { | ||
1804 | if (which == V4L2_SUBDEV_FORMAT_TRY) | ||
1805 | return v4l2_subdev_get_try_crop(fh, CCDC_PAD_SOURCE_OF); | ||
1806 | else | ||
1807 | return &ccdc->crop; | ||
1808 | } | ||
1809 | |||
1793 | /* | 1810 | /* |
1794 | * ccdc_try_format - Try video format on a pad | 1811 | * ccdc_try_format - Try video format on a pad |
1795 | * @ccdc: ISP CCDC device | 1812 | * @ccdc: ISP CCDC device |
@@ -1806,6 +1823,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, | |||
1806 | const struct isp_format_info *info; | 1823 | const struct isp_format_info *info; |
1807 | unsigned int width = fmt->width; | 1824 | unsigned int width = fmt->width; |
1808 | unsigned int height = fmt->height; | 1825 | unsigned int height = fmt->height; |
1826 | struct v4l2_rect *crop; | ||
1809 | unsigned int i; | 1827 | unsigned int i; |
1810 | 1828 | ||
1811 | switch (pad) { | 1829 | switch (pad) { |
@@ -1831,14 +1849,10 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, | |||
1831 | format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which); | 1849 | format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which); |
1832 | memcpy(fmt, format, sizeof(*fmt)); | 1850 | memcpy(fmt, format, sizeof(*fmt)); |
1833 | 1851 | ||
1834 | /* The data formatter truncates the number of horizontal output | 1852 | /* Hardcode the output size to the crop rectangle size. */ |
1835 | * pixels to a multiple of 16. To avoid clipping data, allow | 1853 | crop = __ccdc_get_crop(ccdc, fh, which); |
1836 | * callers to request an output size bigger than the input size | 1854 | fmt->width = crop->width; |
1837 | * up to the nearest multiple of 16. | 1855 | fmt->height = crop->height; |
1838 | */ | ||
1839 | fmt->width = clamp_t(u32, width, 32, fmt->width + 15); | ||
1840 | fmt->width &= ~15; | ||
1841 | fmt->height = clamp_t(u32, height, 32, fmt->height); | ||
1842 | break; | 1856 | break; |
1843 | 1857 | ||
1844 | case CCDC_PAD_SOURCE_VP: | 1858 | case CCDC_PAD_SOURCE_VP: |
@@ -1866,6 +1880,49 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, | |||
1866 | } | 1880 | } |
1867 | 1881 | ||
1868 | /* | 1882 | /* |
1883 | * ccdc_try_crop - Validate a crop rectangle | ||
1884 | * @ccdc: ISP CCDC device | ||
1885 | * @sink: format on the sink pad | ||
1886 | * @crop: crop rectangle to be validated | ||
1887 | */ | ||
1888 | static void ccdc_try_crop(struct isp_ccdc_device *ccdc, | ||
1889 | const struct v4l2_mbus_framefmt *sink, | ||
1890 | struct v4l2_rect *crop) | ||
1891 | { | ||
1892 | const struct isp_format_info *info; | ||
1893 | unsigned int max_width; | ||
1894 | |||
1895 | /* For Bayer formats, restrict left/top and width/height to even values | ||
1896 | * to keep the Bayer pattern. | ||
1897 | */ | ||
1898 | info = omap3isp_video_format_info(sink->code); | ||
1899 | if (info->flavor != V4L2_MBUS_FMT_Y8_1X8) { | ||
1900 | crop->left &= ~1; | ||
1901 | crop->top &= ~1; | ||
1902 | } | ||
1903 | |||
1904 | crop->left = clamp_t(u32, crop->left, 0, sink->width - CCDC_MIN_WIDTH); | ||
1905 | crop->top = clamp_t(u32, crop->top, 0, sink->height - CCDC_MIN_HEIGHT); | ||
1906 | |||
1907 | /* The data formatter truncates the number of horizontal output pixels | ||
1908 | * to a multiple of 16. To avoid clipping data, allow callers to request | ||
1909 | * an output size bigger than the input size up to the nearest multiple | ||
1910 | * of 16. | ||
1911 | */ | ||
1912 | max_width = (sink->width - crop->left + 15) & ~15; | ||
1913 | crop->width = clamp_t(u32, crop->width, CCDC_MIN_WIDTH, max_width) | ||
1914 | & ~15; | ||
1915 | crop->height = clamp_t(u32, crop->height, CCDC_MIN_HEIGHT, | ||
1916 | sink->height - crop->top); | ||
1917 | |||
1918 | /* Odd width/height values don't make sense for Bayer formats. */ | ||
1919 | if (info->flavor != V4L2_MBUS_FMT_Y8_1X8) { | ||
1920 | crop->width &= ~1; | ||
1921 | crop->height &= ~1; | ||
1922 | } | ||
1923 | } | ||
1924 | |||
1925 | /* | ||
1869 | * ccdc_enum_mbus_code - Handle pixel format enumeration | 1926 | * ccdc_enum_mbus_code - Handle pixel format enumeration |
1870 | * @sd : pointer to v4l2 subdev structure | 1927 | * @sd : pointer to v4l2 subdev structure |
1871 | * @fh : V4L2 subdev file handle | 1928 | * @fh : V4L2 subdev file handle |
@@ -1937,6 +1994,93 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd, | |||
1937 | } | 1994 | } |
1938 | 1995 | ||
1939 | /* | 1996 | /* |
1997 | * ccdc_get_selection - Retrieve a selection rectangle on a pad | ||
1998 | * @sd: ISP CCDC V4L2 subdevice | ||
1999 | * @fh: V4L2 subdev file handle | ||
2000 | * @sel: Selection rectangle | ||
2001 | * | ||
2002 | * The only supported rectangles are the crop rectangles on the output formatter | ||
2003 | * source pad. | ||
2004 | * | ||
2005 | * Return 0 on success or a negative error code otherwise. | ||
2006 | */ | ||
2007 | static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
2008 | struct v4l2_subdev_selection *sel) | ||
2009 | { | ||
2010 | struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); | ||
2011 | struct v4l2_mbus_framefmt *format; | ||
2012 | |||
2013 | if (sel->pad != CCDC_PAD_SOURCE_OF) | ||
2014 | return -EINVAL; | ||
2015 | |||
2016 | switch (sel->target) { | ||
2017 | case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS: | ||
2018 | sel->r.left = 0; | ||
2019 | sel->r.top = 0; | ||
2020 | sel->r.width = INT_MAX; | ||
2021 | sel->r.height = INT_MAX; | ||
2022 | |||
2023 | format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, sel->which); | ||
2024 | ccdc_try_crop(ccdc, format, &sel->r); | ||
2025 | break; | ||
2026 | |||
2027 | case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL: | ||
2028 | sel->r = *__ccdc_get_crop(ccdc, fh, sel->which); | ||
2029 | break; | ||
2030 | |||
2031 | default: | ||
2032 | return -EINVAL; | ||
2033 | } | ||
2034 | |||
2035 | return 0; | ||
2036 | } | ||
2037 | |||
2038 | /* | ||
2039 | * ccdc_set_selection - Set a selection rectangle on a pad | ||
2040 | * @sd: ISP CCDC V4L2 subdevice | ||
2041 | * @fh: V4L2 subdev file handle | ||
2042 | * @sel: Selection rectangle | ||
2043 | * | ||
2044 | * The only supported rectangle is the actual crop rectangle on the output | ||
2045 | * formatter source pad. | ||
2046 | * | ||
2047 | * Return 0 on success or a negative error code otherwise. | ||
2048 | */ | ||
2049 | static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
2050 | struct v4l2_subdev_selection *sel) | ||
2051 | { | ||
2052 | struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); | ||
2053 | struct v4l2_mbus_framefmt *format; | ||
2054 | |||
2055 | if (sel->target != V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL || | ||
2056 | sel->pad != CCDC_PAD_SOURCE_OF) | ||
2057 | return -EINVAL; | ||
2058 | |||
2059 | /* The crop rectangle can't be changed while streaming. */ | ||
2060 | if (ccdc->state != ISP_PIPELINE_STREAM_STOPPED) | ||
2061 | return -EBUSY; | ||
2062 | |||
2063 | /* Modifying the crop rectangle always changes the format on the source | ||
2064 | * pad. If the KEEP_CONFIG flag is set, just return the current crop | ||
2065 | * rectangle. | ||
2066 | */ | ||
2067 | if (sel->flags & V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG) { | ||
2068 | sel->r = *__ccdc_get_crop(ccdc, fh, sel->which); | ||
2069 | return 0; | ||
2070 | } | ||
2071 | |||
2072 | format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, sel->which); | ||
2073 | ccdc_try_crop(ccdc, format, &sel->r); | ||
2074 | *__ccdc_get_crop(ccdc, fh, sel->which) = sel->r; | ||
2075 | |||
2076 | /* Update the source format. */ | ||
2077 | format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF, sel->which); | ||
2078 | ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_OF, format, sel->which); | ||
2079 | |||
2080 | return 0; | ||
2081 | } | ||
2082 | |||
2083 | /* | ||
1940 | * ccdc_get_format - Retrieve the video format on a pad | 2084 | * ccdc_get_format - Retrieve the video format on a pad |
1941 | * @sd : ISP CCDC V4L2 subdevice | 2085 | * @sd : ISP CCDC V4L2 subdevice |
1942 | * @fh : V4L2 subdev file handle | 2086 | * @fh : V4L2 subdev file handle |
@@ -1973,6 +2117,7 @@ static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
1973 | { | 2117 | { |
1974 | struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); | 2118 | struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); |
1975 | struct v4l2_mbus_framefmt *format; | 2119 | struct v4l2_mbus_framefmt *format; |
2120 | struct v4l2_rect *crop; | ||
1976 | 2121 | ||
1977 | format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which); | 2122 | format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which); |
1978 | if (format == NULL) | 2123 | if (format == NULL) |
@@ -1983,6 +2128,16 @@ static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
1983 | 2128 | ||
1984 | /* Propagate the format from sink to source */ | 2129 | /* Propagate the format from sink to source */ |
1985 | if (fmt->pad == CCDC_PAD_SINK) { | 2130 | if (fmt->pad == CCDC_PAD_SINK) { |
2131 | /* Reset the crop rectangle. */ | ||
2132 | crop = __ccdc_get_crop(ccdc, fh, fmt->which); | ||
2133 | crop->left = 0; | ||
2134 | crop->top = 0; | ||
2135 | crop->width = fmt->format.width; | ||
2136 | crop->height = fmt->format.height; | ||
2137 | |||
2138 | ccdc_try_crop(ccdc, &fmt->format, crop); | ||
2139 | |||
2140 | /* Update the source formats. */ | ||
1986 | format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF, | 2141 | format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF, |
1987 | fmt->which); | 2142 | fmt->which); |
1988 | *format = fmt->format; | 2143 | *format = fmt->format; |
@@ -2000,6 +2155,69 @@ static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
2000 | } | 2155 | } |
2001 | 2156 | ||
2002 | /* | 2157 | /* |
2158 | * Decide whether desired output pixel code can be obtained with | ||
2159 | * the lane shifter by shifting the input pixel code. | ||
2160 | * @in: input pixelcode to shifter | ||
2161 | * @out: output pixelcode from shifter | ||
2162 | * @additional_shift: # of bits the sensor's LSB is offset from CAMEXT[0] | ||
2163 | * | ||
2164 | * return true if the combination is possible | ||
2165 | * return false otherwise | ||
2166 | */ | ||
2167 | static bool ccdc_is_shiftable(enum v4l2_mbus_pixelcode in, | ||
2168 | enum v4l2_mbus_pixelcode out, | ||
2169 | unsigned int additional_shift) | ||
2170 | { | ||
2171 | const struct isp_format_info *in_info, *out_info; | ||
2172 | |||
2173 | if (in == out) | ||
2174 | return true; | ||
2175 | |||
2176 | in_info = omap3isp_video_format_info(in); | ||
2177 | out_info = omap3isp_video_format_info(out); | ||
2178 | |||
2179 | if ((in_info->flavor == 0) || (out_info->flavor == 0)) | ||
2180 | return false; | ||
2181 | |||
2182 | if (in_info->flavor != out_info->flavor) | ||
2183 | return false; | ||
2184 | |||
2185 | return in_info->bpp - out_info->bpp + additional_shift <= 6; | ||
2186 | } | ||
2187 | |||
2188 | static int ccdc_link_validate(struct v4l2_subdev *sd, | ||
2189 | struct media_link *link, | ||
2190 | struct v4l2_subdev_format *source_fmt, | ||
2191 | struct v4l2_subdev_format *sink_fmt) | ||
2192 | { | ||
2193 | struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); | ||
2194 | unsigned long parallel_shift; | ||
2195 | |||
2196 | /* Check if the two ends match */ | ||
2197 | if (source_fmt->format.width != sink_fmt->format.width || | ||
2198 | source_fmt->format.height != sink_fmt->format.height) | ||
2199 | return -EPIPE; | ||
2200 | |||
2201 | /* We've got a parallel sensor here. */ | ||
2202 | if (ccdc->input == CCDC_INPUT_PARALLEL) { | ||
2203 | struct isp_parallel_platform_data *pdata = | ||
2204 | &((struct isp_v4l2_subdevs_group *) | ||
2205 | media_entity_to_v4l2_subdev(link->source->entity) | ||
2206 | ->host_priv)->bus.parallel; | ||
2207 | parallel_shift = pdata->data_lane_shift * 2; | ||
2208 | } else { | ||
2209 | parallel_shift = 0; | ||
2210 | } | ||
2211 | |||
2212 | /* Lane shifter may be used to drop bits on CCDC sink pad */ | ||
2213 | if (!ccdc_is_shiftable(source_fmt->format.code, | ||
2214 | sink_fmt->format.code, parallel_shift)) | ||
2215 | return -EPIPE; | ||
2216 | |||
2217 | return 0; | ||
2218 | } | ||
2219 | |||
2220 | /* | ||
2003 | * ccdc_init_formats - Initialize formats on all pads | 2221 | * ccdc_init_formats - Initialize formats on all pads |
2004 | * @sd: ISP CCDC V4L2 subdevice | 2222 | * @sd: ISP CCDC V4L2 subdevice |
2005 | * @fh: V4L2 subdev file handle | 2223 | * @fh: V4L2 subdev file handle |
@@ -2041,6 +2259,9 @@ static const struct v4l2_subdev_pad_ops ccdc_v4l2_pad_ops = { | |||
2041 | .enum_frame_size = ccdc_enum_frame_size, | 2259 | .enum_frame_size = ccdc_enum_frame_size, |
2042 | .get_fmt = ccdc_get_format, | 2260 | .get_fmt = ccdc_get_format, |
2043 | .set_fmt = ccdc_set_format, | 2261 | .set_fmt = ccdc_set_format, |
2262 | .get_selection = ccdc_get_selection, | ||
2263 | .set_selection = ccdc_set_selection, | ||
2264 | .link_validate = ccdc_link_validate, | ||
2044 | }; | 2265 | }; |
2045 | 2266 | ||
2046 | /* V4L2 subdev operations */ | 2267 | /* V4L2 subdev operations */ |
@@ -2150,6 +2371,7 @@ static int ccdc_link_setup(struct media_entity *entity, | |||
2150 | /* media operations */ | 2371 | /* media operations */ |
2151 | static const struct media_entity_operations ccdc_media_ops = { | 2372 | static const struct media_entity_operations ccdc_media_ops = { |
2152 | .link_setup = ccdc_link_setup, | 2373 | .link_setup = ccdc_link_setup, |
2374 | .link_validate = v4l2_subdev_link_validate, | ||
2153 | }; | 2375 | }; |
2154 | 2376 | ||
2155 | void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc) | 2377 | void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc) |
@@ -2276,8 +2498,6 @@ int omap3isp_ccdc_init(struct isp_device *isp) | |||
2276 | ccdc->clamp.oblen = 0; | 2498 | ccdc->clamp.oblen = 0; |
2277 | ccdc->clamp.dcsubval = 0; | 2499 | ccdc->clamp.dcsubval = 0; |
2278 | 2500 | ||
2279 | ccdc->vpcfg.pixelclk = 0; | ||
2280 | |||
2281 | ccdc->update = OMAP3ISP_CCDC_BLCLAMP; | 2501 | ccdc->update = OMAP3ISP_CCDC_BLCLAMP; |
2282 | ccdc_apply_controls(ccdc); | 2502 | ccdc_apply_controls(ccdc); |
2283 | 2503 | ||