| @@ -22,6 +22,7 @@ · 21 unmodified lines |
| 22 | 22 | #include <linux/pm_runtime.h> |
| 23 | 23 | #include <linux/regmap.h> |
| 24 | 24 | #include <linux/videodev2.h> |
| 25 | +#include <linux/atmel-isc-media.h> |
| 25 | 26 | |
| 26 | 27 | #include <media/v4l2-ctrls.h> |
| 27 | 28 | #include <media/v4l2-device.h> |
| @@ -224,10 +225,35 @@ const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = { · 196 unmodified lines |
| 224 | 225 | (((mbus_code) == MEDIA_BUS_FMT_Y10_1X10) | \ |
| 225 | 226 | (((mbus_code) == MEDIA_BUS_FMT_Y8_1X8))) |
| 226 | 227 | |
| 228 | +#define ISC_CTRL_ISC_TO_V4L2(x) ((x) == ISC_WB_O_ZERO_VAL ? 0 : (x)) |
| 229 | +#define ISC_CTRL_V4L2_TO_ISC(x) ((x) ? (x) : ISC_WB_O_ZERO_VAL) |
| 230 | + |
| 231 | +static inline void isc_update_v4l2_ctrls(struct isc_device *isc) |
| 232 | +{ |
| 233 | + struct isc_ctrls *ctrls = &isc->ctrls; |
| 234 | + |
| 235 | + /* In here we set the v4l2 controls w.r.t. our pipeline config */ |
| 236 | + v4l2_ctrl_s_ctrl(isc->r_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_R]); |
| 237 | + v4l2_ctrl_s_ctrl(isc->b_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_B]); |
| 238 | + v4l2_ctrl_s_ctrl(isc->gr_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_GR]); |
| 239 | + v4l2_ctrl_s_ctrl(isc->gb_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_GB]); |
| 240 | + |
| 241 | + v4l2_ctrl_s_ctrl(isc->r_off_ctrl, |
| 242 | + ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_R])); |
| 243 | + v4l2_ctrl_s_ctrl(isc->b_off_ctrl, |
| 244 | + ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_B])); |
| 245 | + v4l2_ctrl_s_ctrl(isc->gr_off_ctrl, |
| 246 | + ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_GR])); |
| 247 | + v4l2_ctrl_s_ctrl(isc->gb_off_ctrl, |
| 248 | + ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_GB])); |
| 249 | +} |
| 250 | + |
| 227 | 251 | static inline void isc_update_awb_ctrls(struct isc_device *isc) |
| 228 | 252 | { |
| 229 | 253 | struct isc_ctrls *ctrls = &isc->ctrls; |
| 230 | 254 | |
| 255 | + /* In here we set our actual hw pipeline config */ |
| 256 | + |
| 231 | 257 | regmap_write(isc->regmap, ISC_WB_O_RGR, |
| 232 | 258 | (ISC_WB_O_ZERO_VAL - (ctrls->offset[ISC_HIS_CFG_MODE_R])) | |
| 233 | 259 | ((ISC_WB_O_ZERO_VAL - ctrls->offset[ISC_HIS_CFG_MODE_GR]) << 16)); |
| @@ -662,11 +688,9 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) · 428 unmodified lines |
| 662 | 688 | |
| 663 | 689 | bay_cfg = isc->config.sd_format->cfa_baycfg; |
| 664 | 690 | |
| 665 | | − if (ctrls->awb == ISC_WB_NONE) |
| 666 | | − isc_reset_awb_ctrls(isc); |
| 667 | | − |
| 668 | 691 | regmap_write(regmap, ISC_WB_CFG, bay_cfg); |
| 669 | 692 | isc_update_awb_ctrls(isc); |
| 693 | + isc_update_v4l2_ctrls(isc); |
| 670 | 694 | |
| 671 | 695 | regmap_write(regmap, ISC_CFA_CFG, bay_cfg | ISC_CFA_CFG_EITPOL); |
| 672 | 696 | |
| @@ -1396,6 +1420,7 @@ static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f) · 723 unmodified lines |
| 1396 | 1420 | isc->try_config.sd_format != isc->config.sd_format) { |
| 1397 | 1421 | isc->ctrls.hist_stat = HIST_INIT; |
| 1398 | 1422 | isc_reset_awb_ctrls(isc); |
| 1423 | + isc_update_v4l2_ctrls(isc); |
| 1399 | 1424 | } |
| 1400 | 1425 | /* make the try configuration active */ |
| 1401 | 1426 | isc->config = isc->try_config; |
| @@ -1814,10 +1839,6 @@ static void isc_awb_work(struct work_struct *w) · 412 unmodified lines |
| 1814 | 1839 | ctrls->hist_id = hist_id; |
| 1815 | 1840 | baysel = isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT; |
| 1816 | 1841 | |
| 1817 | | − /* if no more auto white balance, reset controls. */ |
| 1818 | | − if (ctrls->awb == ISC_WB_NONE) |
| 1819 | | − isc_reset_awb_ctrls(isc); |
| 1820 | | − |
| 1821 | 1842 | pm_runtime_get_sync(isc->dev); |
| 1822 | 1843 | |
| 1823 | 1844 | /* |
| @@ -1842,6 +1863,8 @@ static void isc_awb_work(struct work_struct *w) · 18 unmodified lines |
| 1842 | 1863 | if (ctrls->awb == ISC_WB_ONETIME) { |
| 1843 | 1864 | v4l2_info(&isc->v4l2_dev, |
| 1844 | 1865 | "Completed one time white-balance adjustment.\n"); |
| 1866 | + /* update the v4l2 controls values */ |
| 1867 | + isc_update_v4l2_ctrls(isc); |
| 1845 | 1868 | ctrls->awb = ISC_WB_NONE; |
| 1846 | 1869 | } |
| 1847 | 1870 | } |
| @@ -1873,6 +1896,27 @@ static int isc_s_ctrl(struct v4l2_ctrl *ctrl) · 25 unmodified lines |
| 1873 | 1896 | case V4L2_CID_GAMMA: |
| 1874 | 1897 | ctrls->gamma_index = ctrl->val; |
| 1875 | 1898 | break; |
| 1899 | + default: |
| 1900 | + return -EINVAL; |
| 1901 | + } |
| 1902 | + |
| 1903 | + return 0; |
| 1904 | +} |
| 1905 | + |
| 1906 | +static const struct v4l2_ctrl_ops isc_ctrl_ops = { |
| 1907 | + .s_ctrl = isc_s_ctrl, |
| 1908 | +}; |
| 1909 | + |
| 1910 | +static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl) |
| 1911 | +{ |
| 1912 | + struct isc_device *isc = container_of(ctrl->handler, |
| 1913 | + struct isc_device, ctrls.handler); |
| 1914 | + struct isc_ctrls *ctrls = &isc->ctrls; |
| 1915 | + |
| 1916 | + if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) |
| 1917 | + return 0; |
| 1918 | + |
| 1919 | + switch (ctrl->id) { |
| 1876 | 1920 | case V4L2_CID_AUTO_WHITE_BALANCE: |
| 1877 | 1921 | if (ctrl->val == 1) |
| 1878 | 1922 | ctrls->awb = ISC_WB_AUTO; |
| @@ -1883,36 +1927,142 @@ static int isc_s_ctrl(struct v4l2_ctrl *ctrl) · 4 unmodified lines |
| 1883 | 1927 | if (!isc->config.sd_format) |
| 1884 | 1928 | break; |
| 1885 | 1929 | |
| 1886 | | − if (ctrls->hist_stat != HIST_ENABLED) |
| 1887 | | − isc_reset_awb_ctrls(isc); |
| 1930 | + /* configure the controls with new values from v4l2 */ |
| 1931 | + if (ctrl->cluster[ISC_CTRL_R_GAIN]->is_new) |
| 1932 | + ctrls->gain[ISC_HIS_CFG_MODE_R] = isc->r_gain_ctrl->val; |
| 1933 | + if (ctrl->cluster[ISC_CTRL_B_GAIN]->is_new) |
| 1934 | + ctrls->gain[ISC_HIS_CFG_MODE_B] = isc->b_gain_ctrl->val; |
| 1935 | + if (ctrl->cluster[ISC_CTRL_GR_GAIN]->is_new) |
| 1936 | + ctrls->gain[ISC_HIS_CFG_MODE_GR] = isc->gr_gain_ctrl->val; |
| 1937 | + if (ctrl->cluster[ISC_CTRL_GB_GAIN]->is_new) |
| 1938 | + ctrls->gain[ISC_HIS_CFG_MODE_GB] = isc->gb_gain_ctrl->val; |
| 1939 | + |
| 1940 | + if (ctrl->cluster[ISC_CTRL_R_OFF]->is_new) |
| 1941 | + ctrls->offset[ISC_HIS_CFG_MODE_R] = |
| 1942 | + ISC_CTRL_V4L2_TO_ISC(isc->r_off_ctrl->val); |
| 1943 | + if (ctrl->cluster[ISC_CTRL_B_OFF]->is_new) |
| 1944 | + ctrls->offset[ISC_HIS_CFG_MODE_B] = |
| 1945 | + ISC_CTRL_V4L2_TO_ISC(isc->b_off_ctrl->val); |
| 1946 | + if (ctrl->cluster[ISC_CTRL_GR_OFF]->is_new) |
| 1947 | + ctrls->offset[ISC_HIS_CFG_MODE_GR] = |
| 1948 | + ISC_CTRL_V4L2_TO_ISC(isc->gr_off_ctrl->val); |
| 1949 | + if (ctrl->cluster[ISC_CTRL_GB_OFF]->is_new) |
| 1950 | + ctrls->offset[ISC_HIS_CFG_MODE_GB] = |
| 1951 | + ISC_CTRL_V4L2_TO_ISC(isc->gb_off_ctrl->val); |
| 1888 | 1952 | |
| 1889 | | − if (isc->ctrls.awb == ISC_WB_AUTO && |
| 1953 | + isc_update_awb_ctrls(isc); |
| 1954 | + |
| 1955 | + if (vb2_is_streaming(&isc->vb2_vidq)) { |
| 1956 | + /* |
| 1957 | + * If we are streaming, we can update profile to |
| 1958 | + * have the new settings in place. |
| 1959 | + */ |
| 1960 | + isc_update_profile(isc); |
| 1961 | + } else { |
| 1962 | + /* |
| 1963 | + * The auto cluster will activate automatically this |
| 1964 | + * control. This has to be deactivated when not |
| 1965 | + * streaming. |
| 1966 | + */ |
| 1967 | + v4l2_ctrl_activate(isc->do_wb_ctrl, false); |
| 1968 | + } |
| 1969 | + |
| 1970 | + /* if we have autowhitebalance on, start histogram procedure */ |
| 1971 | + if (ctrls->awb == ISC_WB_AUTO && |
| 1890 | 1972 | vb2_is_streaming(&isc->vb2_vidq) && |
| 1891 | 1973 | ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) |
| 1892 | 1974 | isc_set_histogram(isc, true); |
| 1893 | 1975 | |
| 1894 | | − break; |
| 1895 | | − case V4L2_CID_DO_WHITE_BALANCE: |
| 1896 | | − /* if AWB is enabled, do nothing */ |
| 1897 | | − if (ctrls->awb == ISC_WB_AUTO) |
| 1898 | | − return 0; |
| 1976 | + /* |
| 1977 | + * for one time whitebalance adjustment, check the button, |
| 1978 | + * if it's pressed, perform the one time operation. |
| 1979 | + */ |
| 1980 | + if (ctrls->awb == ISC_WB_NONE && |
| 1981 | + ctrl->cluster[ISC_CTRL_DO_WB]->is_new && |
| 1982 | + !(ctrl->cluster[ISC_CTRL_DO_WB]->flags & |
| 1983 | + V4L2_CTRL_FLAG_INACTIVE)) { |
| 1984 | + ctrls->awb = ISC_WB_ONETIME; |
| 1985 | + isc_set_histogram(isc, true); |
| 1986 | + v4l2_dbg(1, debug, &isc->v4l2_dev, |
| 1987 | + "One time white-balance started.\n"); |
| 1988 | + } |
| 1989 | + return 0; |
| 1990 | + } |
| 1991 | + return 0; |
| 1992 | +} |
| 1899 | 1993 | |
| 1900 | | − ctrls->awb = ISC_WB_ONETIME; |
| 1901 | | − isc_set_histogram(isc, true); |
| 1902 | | − v4l2_dbg(1, debug, &isc->v4l2_dev, |
| 1903 | | − "One time white-balance started.\n"); |
| 1994 | +static int isc_g_volatile_awb_ctrl(struct v4l2_ctrl *ctrl) |
| 1995 | +{ |
| 1996 | + struct isc_device *isc = container_of(ctrl->handler, |
| 1997 | + struct isc_device, ctrls.handler); |
| 1998 | + struct isc_ctrls *ctrls = &isc->ctrls; |
| 1999 | + |
| 2000 | + switch (ctrl->id) { |
| 2001 | + /* being a cluster, this id will be called for every control */ |
| 2002 | + case V4L2_CID_AUTO_WHITE_BALANCE: |
| 2003 | + ctrl->cluster[ISC_CTRL_R_GAIN]->val = |
| 2004 | + ctrls->gain[ISC_HIS_CFG_MODE_R]; |
| 2005 | + ctrl->cluster[ISC_CTRL_B_GAIN]->val = |
| 2006 | + ctrls->gain[ISC_HIS_CFG_MODE_B]; |
| 2007 | + ctrl->cluster[ISC_CTRL_GR_GAIN]->val = |
| 2008 | + ctrls->gain[ISC_HIS_CFG_MODE_GR]; |
| 2009 | + ctrl->cluster[ISC_CTRL_GB_GAIN]->val = |
| 2010 | + ctrls->gain[ISC_HIS_CFG_MODE_GB]; |
| 2011 | + |
| 2012 | + ctrl->cluster[ISC_CTRL_R_OFF]->val = |
| 2013 | + ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_R]); |
| 2014 | + ctrl->cluster[ISC_CTRL_B_OFF]->val = |
| 2015 | + ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_B]); |
| 2016 | + ctrl->cluster[ISC_CTRL_GR_OFF]->val = |
| 2017 | + ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_GR]); |
| 2018 | + ctrl->cluster[ISC_CTRL_GB_OFF]->val = |
| 2019 | + ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_GB]); |
| 1904 | 2020 | break; |
| 1905 | | − default: |
| 1906 | | − return -EINVAL; |
| 1907 | 2021 | } |
| 1908 | | − |
| 1909 | 2022 | return 0; |
| 1910 | 2023 | } |
| 1911 | 2024 | |
| 1912 | | −static const struct v4l2_ctrl_ops isc_ctrl_ops = { |
| 1913 | | − .s_ctrl = isc_s_ctrl, |
| 2025 | +static const struct v4l2_ctrl_ops isc_awb_ops = { |
| 2026 | + .s_ctrl = isc_s_awb_ctrl, |
| 2027 | + .g_volatile_ctrl = isc_g_volatile_awb_ctrl, |
| 1914 | 2028 | }; |
| 1915 | 2029 | |
| 2030 | +#define ISC_CTRL_OFF(_name, _id, _name_str) \ |
| 2031 | + static const struct v4l2_ctrl_config _name = { \ |
| 2032 | + .ops = &isc_awb_ops, \ |
| 2033 | + .id = _id, \ |
| 2034 | + .name = _name_str, \ |
| 2035 | + .type = V4L2_CTRL_TYPE_INTEGER, \ |
| 2036 | + .flags = V4L2_CTRL_FLAG_SLIDER, \ |
| 2037 | + .min = -4095, \ |
| 2038 | + .max = 4095, \ |
| 2039 | + .step = 1, \ |
| 2040 | + .def = 0, \ |
| 2041 | + } |
| 2042 | + |
| 2043 | +ISC_CTRL_OFF(isc_r_off_ctrl, ISC_CID_R_OFFSET, "Red Component Offset"); |
| 2044 | +ISC_CTRL_OFF(isc_b_off_ctrl, ISC_CID_B_OFFSET, "Blue Component Offset"); |
| 2045 | +ISC_CTRL_OFF(isc_gr_off_ctrl, ISC_CID_GR_OFFSET, "Green Red Component Offset"); |
| 2046 | +ISC_CTRL_OFF(isc_gb_off_ctrl, ISC_CID_GB_OFFSET, "Green Blue Component Offset"); |
| 2047 | + |
| 2048 | +#define ISC_CTRL_GAIN(_name, _id, _name_str) \ |
| 2049 | + static const struct v4l2_ctrl_config _name = { \ |
| 2050 | + .ops = &isc_awb_ops, \ |
| 2051 | + .id = _id, \ |
| 2052 | + .name = _name_str, \ |
| 2053 | + .type = V4L2_CTRL_TYPE_INTEGER, \ |
| 2054 | + .flags = V4L2_CTRL_FLAG_SLIDER, \ |
| 2055 | + .min = 0, \ |
| 2056 | + .max = 8191, \ |
| 2057 | + .step = 1, \ |
| 2058 | + .def = 512, \ |
| 2059 | + } |
| 2060 | + |
| 2061 | +ISC_CTRL_GAIN(isc_r_gain_ctrl, ISC_CID_R_GAIN, "Red Component Gain"); |
| 2062 | +ISC_CTRL_GAIN(isc_b_gain_ctrl, ISC_CID_B_GAIN, "Blue Component Gain"); |
| 2063 | +ISC_CTRL_GAIN(isc_gr_gain_ctrl, ISC_CID_GR_GAIN, "Green Red Component Gain"); |
| 2064 | +ISC_CTRL_GAIN(isc_gb_gain_ctrl, ISC_CID_GB_GAIN, "Green Blue Component Gain"); |
| 2065 | + |
| 1916 | 2066 | static int isc_ctrl_init(struct isc_device *isc) |
| 1917 | 2067 | { |
| 1918 | 2068 | const struct v4l2_ctrl_ops *ops = &isc_ctrl_ops; |
| @@ -1923,7 +2073,7 @@ static int isc_ctrl_init(struct isc_device *isc) · 4 unmodified lines |
| 1923 | 2073 | ctrls->hist_stat = HIST_INIT; |
| 1924 | 2074 | isc_reset_awb_ctrls(isc); |
| 1925 | 2075 | |
| 1926 | | − ret = v4l2_ctrl_handler_init(hdl, 5); |
| 2076 | + ret = v4l2_ctrl_handler_init(hdl, 13); |
| 1927 | 2077 | if (ret < 0) |
| 1928 | 2078 | return ret; |
| 1929 | 2079 | |
| @@ -1933,10 +2083,13 @@ static int isc_ctrl_init(struct isc_device *isc) · 3 unmodified lines |
| 1933 | 2083 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0); |
| 1934 | 2084 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256); |
| 1935 | 2085 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 2); |
| 1936 | | − v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); |
| 2086 | + isc->awb_ctrl = v4l2_ctrl_new_std(hdl, &isc_awb_ops, |
| 2087 | + V4L2_CID_AUTO_WHITE_BALANCE, |
| 2088 | + 0, 1, 1, 1); |
| 1937 | 2089 | |
| 1938 | 2090 | /* do_white_balance is a button, so min,max,step,default are ignored */ |
| 1939 | | − isc->do_wb_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_DO_WHITE_BALANCE, |
| 2091 | + isc->do_wb_ctrl = v4l2_ctrl_new_std(hdl, &isc_awb_ops, |
| 2092 | + V4L2_CID_DO_WHITE_BALANCE, |
| 1940 | 2093 | 0, 0, 0, 0); |
| 1941 | 2094 | |
| 1942 | 2095 | if (!isc->do_wb_ctrl) { |
| @@ -1947,6 +2100,21 @@ static int isc_ctrl_init(struct isc_device *isc) · 4 unmodified lines |
| 1947 | 2100 | |
| 1948 | 2101 | v4l2_ctrl_activate(isc->do_wb_ctrl, false); |
| 1949 | 2102 | |
| 2103 | + isc->r_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_r_gain_ctrl, NULL); |
| 2104 | + isc->b_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_b_gain_ctrl, NULL); |
| 2105 | + isc->gr_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gr_gain_ctrl, NULL); |
| 2106 | + isc->gb_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gb_gain_ctrl, NULL); |
| 2107 | + isc->r_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_r_off_ctrl, NULL); |
| 2108 | + isc->b_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_b_off_ctrl, NULL); |
| 2109 | + isc->gr_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gr_off_ctrl, NULL); |
| 2110 | + isc->gb_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gb_off_ctrl, NULL); |
| 2111 | + |
| 2112 | + /* |
| 2113 | + * The cluster is in auto mode with autowhitebalance enabled |
| 2114 | + * and manual mode otherwise. |
| 2115 | + */ |
| 2116 | + v4l2_ctrl_auto_cluster(10, &isc->awb_ctrl, 0, true); |
| 2117 | + |
| 1950 | 2118 | v4l2_ctrl_handler_setup(hdl); |
| 1951 | 2119 | |
| 1952 | 2120 | return 0; |