// SPDX-License-Identifier: GPL-2.0 /* * imx274.c - IMX274 CMOS Image Sensor driver * * Copyright (C) 2017, Leopard Imaging, Inc. * * Leon Luo <[email protected]> * Edwin Zou <[email protected]> * Luca Ceresoli <[email protected]> */ #include <linux/clk.h> #include <linux/delay.h> #include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> #include <linux/v4l2-mediabus.h> #include <linux/videodev2.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h> /* * See "SHR, SVR Setting" in datasheet */ #define IMX274_DEFAULT_FRAME_LENGTH … #define IMX274_MAX_FRAME_LENGTH … /* * See "Frame Rate Adjustment" in datasheet */ #define IMX274_PIXCLK_CONST1 … #define IMX274_PIXCLK_CONST2 … /* * The input gain is shifted by IMX274_GAIN_SHIFT to get * decimal number. The real gain is * (float)input_gain_value / (1 << IMX274_GAIN_SHIFT) */ #define IMX274_GAIN_SHIFT … #define IMX274_GAIN_SHIFT_MASK … /* * See "Analog Gain" and "Digital Gain" in datasheet * min gain is 1X * max gain is calculated based on IMX274_GAIN_REG_MAX */ #define IMX274_GAIN_REG_MAX … #define IMX274_MIN_GAIN … #define IMX274_MAX_ANALOG_GAIN … #define IMX274_MAX_DIGITAL_GAIN … #define IMX274_DEF_GAIN … #define IMX274_GAIN_CONST … /* * 1 line time in us = (HMAX / 72), minimal is 4 lines */ #define IMX274_MIN_EXPOSURE_TIME … #define IMX274_MAX_WIDTH … #define IMX274_MAX_HEIGHT … #define IMX274_MAX_FRAME_RATE … #define IMX274_MIN_FRAME_RATE … #define IMX274_DEF_FRAME_RATE … /* * register SHR is limited to (SVR value + 1) x VMAX value - 4 */ #define IMX274_SHR_LIMIT_CONST … /* * Min and max sensor reset delay (microseconds) */ #define IMX274_RESET_DELAY1 … #define IMX274_RESET_DELAY2 … /* * shift and mask constants */ #define IMX274_SHIFT_8_BITS … #define IMX274_SHIFT_16_BITS … #define IMX274_MASK_LSB_2_BITS … #define IMX274_MASK_LSB_3_BITS … #define IMX274_MASK_LSB_4_BITS … #define IMX274_MASK_LSB_8_BITS … #define DRIVER_NAME … /* * IMX274 register definitions */ #define IMX274_SHR_REG_MSB … #define IMX274_SHR_REG_LSB … #define IMX274_SVR_REG_MSB … #define IMX274_SVR_REG_LSB … #define IMX274_HTRIM_EN_REG … #define IMX274_HTRIM_START_REG_LSB … #define IMX274_HTRIM_START_REG_MSB … #define IMX274_HTRIM_END_REG_LSB … #define IMX274_HTRIM_END_REG_MSB … #define IMX274_VWIDCUTEN_REG … #define IMX274_VWIDCUT_REG_LSB … #define IMX274_VWIDCUT_REG_MSB … #define IMX274_VWINPOS_REG_LSB … #define IMX274_VWINPOS_REG_MSB … #define IMX274_WRITE_VSIZE_REG_LSB … #define IMX274_WRITE_VSIZE_REG_MSB … #define IMX274_Y_OUT_SIZE_REG_LSB … #define IMX274_Y_OUT_SIZE_REG_MSB … #define IMX274_VMAX_REG_1 … #define IMX274_VMAX_REG_2 … #define IMX274_VMAX_REG_3 … #define IMX274_HMAX_REG_MSB … #define IMX274_HMAX_REG_LSB … #define IMX274_ANALOG_GAIN_ADDR_LSB … #define IMX274_ANALOG_GAIN_ADDR_MSB … #define IMX274_DIGITAL_GAIN_REG … #define IMX274_VFLIP_REG … #define IMX274_TEST_PATTERN_REG … #define IMX274_STANDBY_REG … #define IMX274_TABLE_WAIT_MS … #define IMX274_TABLE_END … /* regulator supplies */ static const char * const imx274_supply_names[] = …; #define IMX274_NUM_SUPPLIES … /* * imx274 I2C operation related structure */ struct reg_8 { … }; static const struct regmap_config imx274_regmap_config = …; /* * Parameters for each imx274 readout mode. * * These are the values to configure the sensor in one of the * implemented modes. * * @init_regs: registers to initialize the mode * @wbin_ratio: width downscale factor (e.g. 3 for 1280; 3 = 3840/1280) * @hbin_ratio: height downscale factor (e.g. 3 for 720; 3 = 2160/720) * @min_frame_len: Minimum frame length for each mode (see "Frame Rate * Adjustment (CSI-2)" in the datasheet) * @min_SHR: Minimum SHR register value (see "Shutter Setting (CSI-2)" in the * datasheet) * @max_fps: Maximum frames per second * @nocpiop: Number of clocks per internal offset period (see "Integration Time * in Each Readout Drive Mode (CSI-2)" in the datasheet) */ struct imx274_mode { … }; /* * imx274 test pattern related structure */ enum { … }; static const char * const tp_qmenu[] = …; /* * All-pixel scan mode (10-bit) * imx274 mode1(refer to datasheet) register configuration with * 3840x2160 resolution, raw10 data and mipi four lane output */ static const struct reg_8 imx274_mode1_3840x2160_raw10[] = …; /* * Horizontal/vertical 2/2-line binning * (Horizontal and vertical weightedbinning, 10-bit) * imx274 mode3(refer to datasheet) register configuration with * 1920x1080 resolution, raw10 data and mipi four lane output */ static const struct reg_8 imx274_mode3_1920x1080_raw10[] = …; /* * Vertical 2/3 subsampling binning horizontal 3 binning * imx274 mode5(refer to datasheet) register configuration with * 1280x720 resolution, raw10 data and mipi four lane output */ static const struct reg_8 imx274_mode5_1280x720_raw10[] = …; /* * Vertical 2/8 subsampling horizontal 3 binning * imx274 mode6(refer to datasheet) register configuration with * 1280x540 resolution, raw10 data and mipi four lane output */ static const struct reg_8 imx274_mode6_1280x540_raw10[] = …; /* * imx274 first step register configuration for * starting stream */ static const struct reg_8 imx274_start_1[] = …; /* * imx274 second step register configuration for * starting stream */ static const struct reg_8 imx274_start_2[] = …; /* * imx274 third step register configuration for * starting stream */ static const struct reg_8 imx274_start_3[] = …; /* * imx274 register configuration for stopping stream */ static const struct reg_8 imx274_stop[] = …; /* * imx274 disable test pattern register configuration */ static const struct reg_8 imx274_tp_disabled[] = …; /* * imx274 test pattern register configuration * reg 0x303D defines the test pattern modes */ static const struct reg_8 imx274_tp_regs[] = …; /* nocpiop happens to be the same number for the implemented modes */ static const struct imx274_mode imx274_modes[] = …; /* * struct imx274_ctrls - imx274 ctrl structure * @handler: V4L2 ctrl handler structure * @exposure: Pointer to expsure ctrl structure * @gain: Pointer to gain ctrl structure * @vflip: Pointer to vflip ctrl structure * @test_pattern: Pointer to test pattern ctrl structure */ struct imx274_ctrls { … }; /* * struct stim274 - imx274 device structure * @sd: V4L2 subdevice structure * @pad: Media pad structure * @client: Pointer to I2C client * @ctrls: imx274 control structure * @crop: rect to be captured * @compose: compose rect, i.e. output resolution * @format: V4L2 media bus frame format structure * (width and height are in sync with the compose rect) * @frame_rate: V4L2 frame rate structure * @regmap: Pointer to regmap structure * @reset_gpio: Pointer to reset gpio * @supplies: List of analog and digital supply regulators * @inck: Pointer to sensor input clock * @lock: Mutex structure * @mode: Parameters for the selected readout mode */ struct stimx274 { … }; #define IMX274_ROUND(dim, step, flags) … /* * Function declaration */ static int imx274_set_gain(struct stimx274 *priv, struct v4l2_ctrl *ctrl); static int imx274_set_exposure(struct stimx274 *priv, int val); static int imx274_set_vflip(struct stimx274 *priv, int val); static int imx274_set_test_pattern(struct stimx274 *priv, int val); static int __imx274_set_frame_interval(struct stimx274 *priv, struct v4l2_fract frame_interval); static inline void msleep_range(unsigned int delay_base) { … } /* * v4l2_ctrl and v4l2_subdev related operations */ static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) { … } static inline struct stimx274 *to_imx274(struct v4l2_subdev *sd) { … } /* * Writing a register table * * @priv: Pointer to device * @table: Table containing register values (with optional delays) * * This is used to write register table into sensor's reg map. * * Return: 0 on success, errors otherwise */ static int imx274_write_table(struct stimx274 *priv, const struct reg_8 table[]) { … } static inline int imx274_write_reg(struct stimx274 *priv, u16 addr, u8 val) { … } /** * imx274_read_mbreg - Read a multibyte register. * * Uses a bulk read where possible. * * @priv: Pointer to device structure * @addr: Address of the LSB register. Other registers must be * consecutive, least-to-most significant. * @val: Pointer to store the register value (cpu endianness) * @nbytes: Number of bytes to read (range: [1..3]). * Other bytes are zet to 0. * * Return: 0 on success, errors otherwise */ static int imx274_read_mbreg(struct stimx274 *priv, u16 addr, u32 *val, size_t nbytes) { … } /** * imx274_write_mbreg - Write a multibyte register. * * Uses a bulk write where possible. * * @priv: Pointer to device structure * @addr: Address of the LSB register. Other registers must be * consecutive, least-to-most significant. * @val: Value to be written to the register (cpu endianness) * @nbytes: Number of bytes to write (range: [1..3]) */ static int imx274_write_mbreg(struct stimx274 *priv, u16 addr, u32 val, size_t nbytes) { … } /* * Set mode registers to start stream. * @priv: Pointer to device structure * * Return: 0 on success, errors otherwise */ static int imx274_mode_regs(struct stimx274 *priv) { … } /* * imx274_start_stream - Function for starting stream per mode index * @priv: Pointer to device structure * * Return: 0 on success, errors otherwise */ static int imx274_start_stream(struct stimx274 *priv) { … } /* * imx274_reset - Function called to reset the sensor * @priv: Pointer to device structure * @rst: Input value for determining the sensor's end state after reset * * Set the senor in reset and then * if rst = 0, keep it in reset; * if rst = 1, bring it out of reset. * */ static void imx274_reset(struct stimx274 *priv, int rst) { … } static int imx274_power_on(struct device *dev) { … } static int imx274_power_off(struct device *dev) { … } static int imx274_regulators_get(struct device *dev, struct stimx274 *imx274) { … } /** * imx274_s_ctrl - This is used to set the imx274 V4L2 controls * @ctrl: V4L2 control to be set * * This function is used to set the V4L2 controls for the imx274 sensor. * * Return: 0 on success, errors otherwise */ static int imx274_s_ctrl(struct v4l2_ctrl *ctrl) { … } static int imx274_binning_goodness(struct stimx274 *imx274, int w, int ask_w, int h, int ask_h, u32 flags) { … } /** * __imx274_change_compose - Helper function to change binning and set both * compose and format. * * We have two entry points to change binning: set_fmt and * set_selection(COMPOSE). Both have to compute the new output size * and set it in both the compose rect and the frame format size. We * also need to do the same things after setting cropping to restore * 1:1 binning. * * This function contains the common code for these three cases, it * has many arguments in order to accommodate the needs of all of * them. * * Must be called with imx274->lock locked. * * @imx274: The device object * @sd_state: The subdev state we are editing for TRY requests * @which: V4L2_SUBDEV_FORMAT_ACTIVE or V4L2_SUBDEV_FORMAT_TRY from the caller * @width: Input-output parameter: set to the desired width before * the call, contains the chosen value after returning successfully * @height: Input-output parameter for height (see @width) * @flags: Selection flags from struct v4l2_subdev_selection, or 0 if not * available (when called from set_fmt) */ static int __imx274_change_compose(struct stimx274 *imx274, struct v4l2_subdev_state *sd_state, u32 which, u32 *width, u32 *height, u32 flags) { … } /** * imx274_get_fmt - Get the pad format * @sd: Pointer to V4L2 Sub device structure * @sd_state: Pointer to sub device state structure * @fmt: Pointer to pad level media bus format * * This function is used to get the pad format information. * * Return: 0 on success */ static int imx274_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { … } /** * imx274_set_fmt - This is used to set the pad format * @sd: Pointer to V4L2 Sub device structure * @sd_state: Pointer to sub device state information structure * @format: Pointer to pad level media bus format * * This function is used to set the pad format. * * Return: 0 on success */ static int imx274_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { … } static int imx274_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { … } static int imx274_set_selection_crop(struct stimx274 *imx274, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { … } static int imx274_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { … } static int imx274_apply_trimming(struct stimx274 *imx274) { … } static int imx274_get_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_interval *fi) { … } static int imx274_set_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_interval *fi) { … } /** * imx274_load_default - load default control values * @priv: Pointer to device structure * * Return: 0 on success, errors otherwise */ static void imx274_load_default(struct stimx274 *priv) { … } /** * imx274_s_stream - It is used to start/stop the streaming. * @sd: V4L2 Sub device * @on: Flag (True / False) * * This function controls the start or stop of streaming for the * imx274 sensor. * * Return: 0 on success, errors otherwise */ static int imx274_s_stream(struct v4l2_subdev *sd, int on) { … } /* * imx274_get_frame_length - Function for obtaining current frame length * @priv: Pointer to device structure * @val: Pointer to obtained value * * frame_length = vmax x (svr + 1), in unit of hmax. * * Return: 0 on success */ static int imx274_get_frame_length(struct stimx274 *priv, u32 *val) { … } static int imx274_clamp_coarse_time(struct stimx274 *priv, u32 *val, u32 *frame_length) { … } /* * imx274_set_digital gain - Function called when setting digital gain * @priv: Pointer to device structure * @dgain: Value of digital gain. * * Digital gain has only 4 steps: 1x, 2x, 4x, and 8x * * Return: 0 on success */ static int imx274_set_digital_gain(struct stimx274 *priv, u32 dgain) { … } /* * imx274_set_gain - Function called when setting gain * @priv: Pointer to device structure * @val: Value of gain. the real value = val << IMX274_GAIN_SHIFT; * @ctrl: v4l2 control pointer * * Set the gain based on input value. * The caller should hold the mutex lock imx274->lock if necessary * * Return: 0 on success */ static int imx274_set_gain(struct stimx274 *priv, struct v4l2_ctrl *ctrl) { … } /* * imx274_set_coarse_time - Function called when setting SHR value * @priv: Pointer to device structure * @val: Value for exposure time in number of line_length, or [HMAX] * * Set SHR value based on input value. * * Return: 0 on success */ static int imx274_set_coarse_time(struct stimx274 *priv, u32 *val) { … } /* * imx274_set_exposure - Function called when setting exposure time * @priv: Pointer to device structure * @val: Variable for exposure time, in the unit of micro-second * * Set exposure time based on input value. * The caller should hold the mutex lock imx274->lock if necessary * * Return: 0 on success */ static int imx274_set_exposure(struct stimx274 *priv, int val) { … } /* * imx274_set_vflip - Function called when setting vertical flip * @priv: Pointer to device structure * @val: Value for vflip setting * * Set vertical flip based on input value. * val = 0: normal, no vertical flip * val = 1: vertical flip enabled * The caller should hold the mutex lock imx274->lock if necessary * * Return: 0 on success */ static int imx274_set_vflip(struct stimx274 *priv, int val) { … } /* * imx274_set_test_pattern - Function called when setting test pattern * @priv: Pointer to device structure * @val: Variable for test pattern * * Set to different test patterns based on input value. * * Return: 0 on success */ static int imx274_set_test_pattern(struct stimx274 *priv, int val) { … } /* * imx274_set_frame_length - Function called when setting frame length * @priv: Pointer to device structure * @val: Variable for frame length (= VMAX, i.e. vertical drive period length) * * Set frame length based on input value. * * Return: 0 on success */ static int imx274_set_frame_length(struct stimx274 *priv, u32 val) { … } /* * __imx274_set_frame_interval - Function called when setting frame interval * @priv: Pointer to device structure * @frame_interval: Variable for frame interval * * Change frame interval by updating VMAX value * The caller should hold the mutex lock imx274->lock if necessary * * Return: 0 on success */ static int __imx274_set_frame_interval(struct stimx274 *priv, struct v4l2_fract frame_interval) { … } static int imx274_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { … } static const struct v4l2_subdev_pad_ops imx274_pad_ops = …; static const struct v4l2_subdev_video_ops imx274_video_ops = …; static const struct v4l2_subdev_ops imx274_subdev_ops = …; static const struct v4l2_ctrl_ops imx274_ctrl_ops = …; static const struct of_device_id imx274_of_id_table[] = …; MODULE_DEVICE_TABLE(of, imx274_of_id_table); static const struct i2c_device_id imx274_id[] = …; MODULE_DEVICE_TABLE(i2c, imx274_id); static int imx274_fwnode_parse(struct device *dev) { … } static int imx274_probe(struct i2c_client *client) { … } static void imx274_remove(struct i2c_client *client) { … } static const struct dev_pm_ops imx274_pm_ops = …; static struct i2c_driver imx274_i2c_driver = …; module_i2c_driver(…) …; MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;