History

media: atmel: atmel-isc-base: expose white balance as v4l2 controls

This exposes the white balance configuration of the ISC as v4l2 controls into userspace. There are 8 controls available: 4 gain controls, sliders, for each of the BAYER components: R, B, GR, GB. These gains are multipliers for each component, in format unsigned 0:4:9 with a default value of 512 (1.0 multiplier). 4 offset controls, sliders, for each of the BAYER components: R, B, GR, GB. These offsets are added/substracted from each component, in format signed 1:12:0 with a default value of 0 (+/- 0) To expose this to userspace, added 8 custom controls, in an auto cluster. To summarize the functionality: The auto cluster switch is the auto white balance control, and it works like this: AWB == 1: autowhitebalance is on, the do_white_balance button is inactive, the gains/offsets are inactive, but volatile and readable. Thus, the results of the whitebalance algorithm are available to userspace to read at any time. AWB == 0: autowhitebalance is off, cluster is in manual mode, user can configure the gain/offsets directly. More than that, if the do_white_balance button is pressed, the driver will perform one-time-adjustment, (preferably with color checker card) and the userspace can read again the new values. With this feature, the userspace can save the coefficients and reinstall them for example after reboot or reprobing the driver. [hverkuil: fix checkpatch warning] [hverkuil: minor spacing adjustments in the functionality description]

Eugen Hristev committed 6 years ago

Commit 4e528891 parent bfaaa204 files · +281 −28Browse files

Unified · Split

4 files
  1. drivers/media/platform/atmel/atmel-isc-base.c +195 −27
  2. drivers/media/platform/atmel/atmel-isc.h +22 −1
  3. include/linux/atmel-isc-media.h +58 −0
  4. include/uapi/linux/v4l2-controls.h +6 −0
drivers/media/platform/atmel/atmel-isc-base.c+195−27
@@ -22,6 +22,7 @@ · 21 unmodified lines
22#include <linux/pm_runtime.h>22#include <linux/pm_runtime.h>
23#include <linux/regmap.h>23#include <linux/regmap.h>
24#include <linux/videodev2.h>24#include <linux/videodev2.h>
25#include <linux/atmel-isc-media.h>
25 26
26#include <media/v4l2-ctrls.h>27#include <media/v4l2-ctrls.h>
27#include <media/v4l2-device.h>28#include <media/v4l2-device.h>
@@ -224,10 +225,35 @@ const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = { · 196 unmodified lines
224 (((mbus_code) == MEDIA_BUS_FMT_Y10_1X10) | \225 (((mbus_code) == MEDIA_BUS_FMT_Y10_1X10) | \
225 (((mbus_code) == MEDIA_BUS_FMT_Y8_1X8)))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
231static 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
227static inline void isc_update_awb_ctrls(struct isc_device *isc)251static inline void isc_update_awb_ctrls(struct isc_device *isc)
228{252{
229 struct isc_ctrls *ctrls = &isc->ctrls;253 struct isc_ctrls *ctrls = &isc->ctrls;
230 254
255 /* In here we set our actual hw pipeline config */
256
231 regmap_write(isc->regmap, ISC_WB_O_RGR,257 regmap_write(isc->regmap, ISC_WB_O_RGR,
232 (ISC_WB_O_ZERO_VAL - (ctrls->offset[ISC_HIS_CFG_MODE_R])) |258 (ISC_WB_O_ZERO_VAL - (ctrls->offset[ISC_HIS_CFG_MODE_R])) |
233 ((ISC_WB_O_ZERO_VAL - ctrls->offset[ISC_HIS_CFG_MODE_GR]) << 16));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 bay_cfg = isc->config.sd_format->cfa_baycfg;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 regmap_write(regmap, ISC_WB_CFG, bay_cfg);691 regmap_write(regmap, ISC_WB_CFG, bay_cfg);
669 isc_update_awb_ctrls(isc);692 isc_update_awb_ctrls(isc);
693 isc_update_v4l2_ctrls(isc);
670 694
671 regmap_write(regmap, ISC_CFA_CFG, bay_cfg | ISC_CFA_CFG_EITPOL);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 isc->try_config.sd_format != isc->config.sd_format) {1420 isc->try_config.sd_format != isc->config.sd_format) {
1397 isc->ctrls.hist_stat = HIST_INIT;1421 isc->ctrls.hist_stat = HIST_INIT;
1398 isc_reset_awb_ctrls(isc);1422 isc_reset_awb_ctrls(isc);
1423 isc_update_v4l2_ctrls(isc);
1399 }1424 }
1400 /* make the try configuration active */1425 /* make the try configuration active */
1401 isc->config = isc->try_config;1426 isc->config = isc->try_config;
@@ -1814,10 +1839,6 @@ static void isc_awb_work(struct work_struct *w) · 412 unmodified lines
1814 ctrls->hist_id = hist_id;1839 ctrls->hist_id = hist_id;
1815 baysel = isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT;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 pm_runtime_get_sync(isc->dev);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 if (ctrls->awb == ISC_WB_ONETIME) {1863 if (ctrls->awb == ISC_WB_ONETIME) {
1843 v4l2_info(&isc->v4l2_dev,1864 v4l2_info(&isc->v4l2_dev,
1844 "Completed one time white-balance adjustment.\n");1865 "Completed one time white-balance adjustment.\n");
1866 /* update the v4l2 controls values */
1867 isc_update_v4l2_ctrls(isc);
1845 ctrls->awb = ISC_WB_NONE;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 case V4L2_CID_GAMMA:1896 case V4L2_CID_GAMMA:
1874 ctrls->gamma_index = ctrl->val;1897 ctrls->gamma_index = ctrl->val;
1875 break;1898 break;
1899 default:
1900 return -EINVAL;
1901 }
1902
1903 return 0;
1904}
1905
1906static const struct v4l2_ctrl_ops isc_ctrl_ops = {
1907 .s_ctrl = isc_s_ctrl,
1908};
1909
1910static 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 case V4L2_CID_AUTO_WHITE_BALANCE:1920 case V4L2_CID_AUTO_WHITE_BALANCE:
1877 if (ctrl->val == 1)1921 if (ctrl->val == 1)
1878 ctrls->awb = ISC_WB_AUTO;1922 ctrls->awb = ISC_WB_AUTO;
@@ -1883,36 +1927,142 @@ static int isc_s_ctrl(struct v4l2_ctrl *ctrl) · 4 unmodified lines
1883 if (!isc->config.sd_format)1927 if (!isc->config.sd_format)
1884 break;1928 break;
1885 1929
1886 if (ctrls->hist_stat != HIST_ENABLED)1930 /* configure the controls with new values from v4l2 */
1887 isc_reset_awb_ctrls(isc);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 vb2_is_streaming(&isc->vb2_vidq) &&1972 vb2_is_streaming(&isc->vb2_vidq) &&
1891 ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code))1973 ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code))
1892 isc_set_histogram(isc, true);1974 isc_set_histogram(isc, true);
1893 1975
1894 break;1976 /*
1895 case V4L2_CID_DO_WHITE_BALANCE:1977 * for one time whitebalance adjustment, check the button,
1896 /* if AWB is enabled, do nothing */1978 * if it's pressed, perform the one time operation.
1897 if (ctrls->awb == ISC_WB_AUTO)1979 */
1898 return 0;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;1994static int isc_g_volatile_awb_ctrl(struct v4l2_ctrl *ctrl)
1901 isc_set_histogram(isc, true);1995{
1902 v4l2_dbg(1, debug, &isc->v4l2_dev,1996 struct isc_device *isc = container_of(ctrl->handler,
1903 "One time white-balance started.\n");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 break;2020 break;
1905 default:
1906 return -EINVAL;
1907 }2021 }
1908
1909 return 0;2022 return 0;
1910}2023}
1911 2024
1912static const struct v4l2_ctrl_ops isc_ctrl_ops = {2025static const struct v4l2_ctrl_ops isc_awb_ops = {
1913 .s_ctrl = isc_s_ctrl,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
2043ISC_CTRL_OFF(isc_r_off_ctrl, ISC_CID_R_OFFSET, "Red Component Offset");
2044ISC_CTRL_OFF(isc_b_off_ctrl, ISC_CID_B_OFFSET, "Blue Component Offset");
2045ISC_CTRL_OFF(isc_gr_off_ctrl, ISC_CID_GR_OFFSET, "Green Red Component Offset");
2046ISC_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
2061ISC_CTRL_GAIN(isc_r_gain_ctrl, ISC_CID_R_GAIN, "Red Component Gain");
2062ISC_CTRL_GAIN(isc_b_gain_ctrl, ISC_CID_B_GAIN, "Blue Component Gain");
2063ISC_CTRL_GAIN(isc_gr_gain_ctrl, ISC_CID_GR_GAIN, "Green Red Component Gain");
2064ISC_CTRL_GAIN(isc_gb_gain_ctrl, ISC_CID_GB_GAIN, "Green Blue Component Gain");
2065
1916static int isc_ctrl_init(struct isc_device *isc)2066static int isc_ctrl_init(struct isc_device *isc)
1917{2067{
1918 const struct v4l2_ctrl_ops *ops = &isc_ctrl_ops;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 ctrls->hist_stat = HIST_INIT;2073 ctrls->hist_stat = HIST_INIT;
1924 isc_reset_awb_ctrls(isc);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 if (ret < 0)2077 if (ret < 0)
1928 return ret;2078 return ret;
1929 2079
@@ -1933,10 +2083,13 @@ static int isc_ctrl_init(struct isc_device *isc) · 3 unmodified lines
1933 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0);2083 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0);
1934 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256);2084 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256);
1935 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 2);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 /* do_white_balance is a button, so min,max,step,default are ignored */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 0, 0, 0, 0);2093 0, 0, 0, 0);
1941 2094
1942 if (!isc->do_wb_ctrl) {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 v4l2_ctrl_activate(isc->do_wb_ctrl, false);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 v4l2_ctrl_handler_setup(hdl);2118 v4l2_ctrl_handler_setup(hdl);
1951 2119
1952 return 0;2120 return 0;
drivers/media/platform/atmel/atmel-isc.h+22−1
@@ -213,7 +213,6 @@ struct isc_device { · 212 unmodified lines
213 struct fmt_config try_config;213 struct fmt_config try_config;
214 214
215 struct isc_ctrls ctrls;215 struct isc_ctrls ctrls;
216 struct v4l2_ctrl *do_wb_ctrl;
217 struct work_struct awb_work;216 struct work_struct awb_work;
218 217
219 struct mutex lock; /* serialize access to file operations */218 struct mutex lock; /* serialize access to file operations */
@@ -223,6 +222,28 @@ struct isc_device { · 3 unmodified lines
223 222
224 struct isc_subdev_entity *current_subdev;223 struct isc_subdev_entity *current_subdev;
225 struct list_head subdev_entities;224 struct list_head subdev_entities;
225
226 struct {
227#define ISC_CTRL_DO_WB 1
228#define ISC_CTRL_R_GAIN 2
229#define ISC_CTRL_B_GAIN 3
230#define ISC_CTRL_GR_GAIN 4
231#define ISC_CTRL_GB_GAIN 5
232#define ISC_CTRL_R_OFF 6
233#define ISC_CTRL_B_OFF 7
234#define ISC_CTRL_GR_OFF 8
235#define ISC_CTRL_GB_OFF 9
236 struct v4l2_ctrl *awb_ctrl;
237 struct v4l2_ctrl *do_wb_ctrl;
238 struct v4l2_ctrl *r_gain_ctrl;
239 struct v4l2_ctrl *b_gain_ctrl;
240 struct v4l2_ctrl *gr_gain_ctrl;
241 struct v4l2_ctrl *gb_gain_ctrl;
242 struct v4l2_ctrl *r_off_ctrl;
243 struct v4l2_ctrl *b_off_ctrl;
244 struct v4l2_ctrl *gr_off_ctrl;
245 struct v4l2_ctrl *gb_off_ctrl;
246 };
226};247};
227 248
228#define GAMMA_MAX 2249#define GAMMA_MAX 2
include/linux/atmel-isc-media.h+58−0
@@ -0,0 +1,58 @@
1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * Copyright (c) 2019 Microchip Technology Inc. and its subsidiaries
4 *
5 * Author: Eugen Hristev <eugen.hristev@microchip.com>
6 */
7
8#ifndef __LINUX_ATMEL_ISC_MEDIA_H__
9#define __LINUX_ATMEL_ISC_MEDIA_H__
10
11/*
12 * There are 8 controls available:
13 * 4 gain controls, sliders, for each of the BAYER components: R, B, GR, GB.
14 * These gains are multipliers for each component, in format unsigned 0:4:9 with
15 * a default value of 512 (1.0 multiplier).
16 * 4 offset controls, sliders, for each of the BAYER components: R, B, GR, GB.
17 * These offsets are added/substracted from each component, in format signed
18 * 1:12:0 with a default value of 0 (+/- 0)
19 *
20 * To expose this to userspace, added 8 custom controls, in an auto cluster.
21 *
22 * To summarize the functionality:
23 * The auto cluster switch is the auto white balance control, and it works
24 * like this:
25 * AWB == 1: autowhitebalance is on, the do_white_balance button is inactive,
26 * the gains/offsets are inactive, but volatile and readable.
27 * Thus, the results of the whitebalance algorithm are available to userspace to
28 * read at any time.
29 * AWB == 0: autowhitebalance is off, cluster is in manual mode, user can
30 * configure the gain/offsets directly.
31 * More than that, if the do_white_balance button is
32 * pressed, the driver will perform one-time-adjustment, (preferably with color
33 * checker card) and the userspace can read again the new values.
34 *
35 * With this feature, the userspace can save the coefficients and reinstall them
36 * for example after reboot or reprobing the driver.
37 */
38
39enum atmel_isc_ctrl_id {
40 /* Red component gain control */
41 ISC_CID_R_GAIN = (V4L2_CID_USER_ATMEL_ISC_BASE + 0),
42 /* Blue component gain control */
43 ISC_CID_B_GAIN,
44 /* Green Red component gain control */
45 ISC_CID_GR_GAIN,
46 /* Green Blue gain control */
47 ISC_CID_GB_GAIN,
48 /* Red component offset control */
49 ISC_CID_R_OFFSET,
50 /* Blue component offset control */
51 ISC_CID_B_OFFSET,
52 /* Green Red component offset control */
53 ISC_CID_GR_OFFSET,
54 /* Green Blue component offset control */
55 ISC_CID_GB_OFFSET,
56};
57
58#endif
include/uapi/linux/v4l2-controls.h+6−0
@@ -192,6 +192,12 @@ enum v4l2_colorfx { · 191 unmodified lines
192 * We reserve 16 controls for this driver. */192 * We reserve 16 controls for this driver. */
193#define V4L2_CID_USER_IMX_BASE (V4L2_CID_USER_BASE + 0x10b0)193#define V4L2_CID_USER_IMX_BASE (V4L2_CID_USER_BASE + 0x10b0)
194 194
195/*
196 * The base for the atmel isc driver controls.
197 * We reserve 32 controls for this driver.
198 */
199#define V4L2_CID_USER_ATMEL_ISC_BASE (V4L2_CID_USER_BASE + 0x10c0)
200
195/* MPEG-class control IDs */201/* MPEG-class control IDs */
196/* The MPEG controls are applicable to all codec controls202/* The MPEG controls are applicable to all codec controls
197 * and the 'MPEG' part of the define is historical */203 * and the 'MPEG' part of the define is historical */