linux/drivers/media/i2c/s5k5baf.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Driver for Samsung S5K5BAF UXGA 1/5" 2M CMOS Image Sensor
 * with embedded SoC ISP.
 *
 * Copyright (C) 2013, Samsung Electronics Co., Ltd.
 * Andrzej Hajda <[email protected]>
 *
 * Based on S5K6AA driver authored by Sylwester Nawrocki
 * Copyright (C) 2013, Samsung Electronics Co., Ltd.
 */

#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/media.h>
#include <linux/module.h>
#include <linux/of_graph.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>

#include <media/media-entity.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-mediabus.h>
#include <media/v4l2-fwnode.h>

static int debug;
module_param(debug, int, 0644);

#define S5K5BAF_DRIVER_NAME
#define S5K5BAF_DEFAULT_MCLK_FREQ
#define S5K5BAF_CLK_NAME

#define S5K5BAF_FW_FILENAME
#define S5K5BAF_FW_TAG
#define S5K5BAG_FW_TAG_LEN
#define S5K5BAG_FW_MAX_COUNT

#define S5K5BAF_CIS_WIDTH
#define S5K5BAF_CIS_HEIGHT
#define S5K5BAF_WIN_WIDTH_MIN
#define S5K5BAF_WIN_HEIGHT_MIN
#define S5K5BAF_GAIN_RED_DEF
#define S5K5BAF_GAIN_GREEN_DEF
#define S5K5BAF_GAIN_BLUE_DEF
/* Default number of MIPI CSI-2 data lanes used */
#define S5K5BAF_DEF_NUM_LANES

#define AHB_MSB_ADDR_PTR

/*
 * Register interface pages (the most significant word of the address)
 */
#define PAGE_IF_HW
#define PAGE_IF_SW

/*
 * H/W register Interface (PAGE_IF_HW)
 */
#define REG_SW_LOAD_COMPLETE
#define REG_CMDWR_PAGE
#define REG_CMDWR_ADDR
#define REG_CMDRD_PAGE
#define REG_CMDRD_ADDR
#define REG_CMD_BUF
#define REG_SET_HOST_INT
#define REG_CLEAR_HOST_INT
#define REG_PATTERN_SET
#define REG_PATTERN_WIDTH
#define REG_PATTERN_HEIGHT
#define REG_PATTERN_PARAM

/*
 * S/W register interface (PAGE_IF_SW)
 */

/* Firmware revision information */
#define REG_FW_APIVER
#define S5K5BAF_FW_APIVER
#define REG_FW_REVISION
#define REG_FW_SENSOR_ID

/* Initialization parameters */
/* Master clock frequency in KHz */
#define REG_I_INCLK_FREQ_L
#define REG_I_INCLK_FREQ_H
#define MIN_MCLK_FREQ_KHZ
#define MAX_MCLK_FREQ_KHZ
#define REG_I_USE_NPVI_CLOCKS
#define NPVI_CLOCKS
#define REG_I_USE_NMIPI_CLOCKS
#define NMIPI_CLOCKS
#define REG_I_BLOCK_INTERNAL_PLL_CALC

/* Clock configurations, n = 0..2. REG_I_* frequency unit is 4 kHz. */
#define REG_I_OPCLK_4KHZ(n)
#define REG_I_MIN_OUTRATE_4KHZ(n)
#define REG_I_MAX_OUTRATE_4KHZ(n)
#define SCLK_PVI_FREQ
#define SCLK_MIPI_FREQ
#define PCLK_MIN_FREQ
#define PCLK_MAX_FREQ
#define REG_I_USE_REGS_API
#define REG_I_INIT_PARAMS_UPDATED
#define REG_I_ERROR_INFO

/* General purpose parameters */
#define REG_USER_BRIGHTNESS
#define REG_USER_CONTRAST
#define REG_USER_SATURATION
#define REG_USER_SHARPBLUR

#define REG_G_SPEC_EFFECTS
#define REG_G_ENABLE_PREV
#define REG_G_ENABLE_PREV_CHG
#define REG_G_NEW_CFG_SYNC
#define REG_G_PREVREQ_IN_WIDTH
#define REG_G_PREVREQ_IN_HEIGHT
#define REG_G_PREVREQ_IN_XOFFS
#define REG_G_PREVREQ_IN_YOFFS
#define REG_G_PREVZOOM_IN_WIDTH
#define REG_G_PREVZOOM_IN_HEIGHT
#define REG_G_PREVZOOM_IN_XOFFS
#define REG_G_PREVZOOM_IN_YOFFS
#define REG_G_INPUTS_CHANGE_REQ
#define REG_G_ACTIVE_PREV_CFG
#define REG_G_PREV_CFG_CHG
#define REG_G_PREV_OPEN_AFTER_CH
#define REG_G_PREV_CFG_ERROR
#define CFG_ERROR_RANGE
#define REG_G_PREV_CFG_BYPASS_CHANGED
#define REG_G_ACTUAL_P_FR_TIME
#define REG_G_ACTUAL_P_OUT_RATE
#define REG_G_ACTUAL_C_FR_TIME
#define REG_G_ACTUAL_C_OUT_RATE

/* Preview control section. n = 0...4. */
#define PREG(n, x)
#define REG_P_OUT_WIDTH(n)
#define REG_P_OUT_HEIGHT(n)
#define REG_P_FMT(n)
#define REG_P_MAX_OUT_RATE(n)
#define REG_P_MIN_OUT_RATE(n)
#define REG_P_PVI_MASK(n)
#define PVI_MASK_MIPI
#define REG_P_CLK_INDEX(n)
#define CLK_PVI_INDEX
#define CLK_MIPI_INDEX
#define REG_P_FR_RATE_TYPE(n)
#define FR_RATE_DYNAMIC
#define FR_RATE_FIXED
#define FR_RATE_FIXED_ACCURATE
#define REG_P_FR_RATE_Q_TYPE(n)
#define FR_RATE_Q_DYNAMIC
#define FR_RATE_Q_BEST_FRRATE
#define FR_RATE_Q_BEST_QUALITY
/* Frame period in 0.1 ms units */
#define REG_P_MAX_FR_TIME(n)
#define REG_P_MIN_FR_TIME(n)
#define S5K5BAF_MIN_FR_TIME
#define S5K5BAF_MAX_FR_TIME
/* The below 5 registers are for "device correction" values */
#define REG_P_SATURATION(n)
#define REG_P_SHARP_BLUR(n)
#define REG_P_GLAMOUR(n)
#define REG_P_COLORTEMP(n)
#define REG_P_GAMMA_INDEX(n)
#define REG_P_PREV_MIRROR(n)
#define REG_P_CAP_MIRROR(n)
#define REG_P_CAP_ROTATION(n)

/* Extended image property controls */
/* Exposure time in 10 us units */
#define REG_SF_USR_EXPOSURE_L
#define REG_SF_USR_EXPOSURE_H
#define REG_SF_USR_EXPOSURE_CHG
#define REG_SF_USR_TOT_GAIN
#define REG_SF_USR_TOT_GAIN_CHG
#define REG_SF_RGAIN
#define REG_SF_RGAIN_CHG
#define REG_SF_GGAIN
#define REG_SF_GGAIN_CHG
#define REG_SF_BGAIN
#define REG_SF_BGAIN_CHG
#define REG_SF_WBGAIN_CHG
#define REG_SF_FLICKER_QUANT
#define REG_SF_FLICKER_QUANT_CHG

/* Output interface (parallel/MIPI) setup */
#define REG_OIF_EN_MIPI_LANES
#define REG_OIF_EN_PACKETS
#define EN_PACKETS_CSI2
#define REG_OIF_CFG_CHG

/* Auto-algorithms enable mask */
#define REG_DBG_AUTOALG_EN
#define AALG_ALL_EN
#define AALG_AE_EN
#define AALG_DIVLEI_EN
#define AALG_WB_EN
#define AALG_USE_WB_FOR_ISP
#define AALG_FLICKER_EN
#define AALG_FIT_EN
#define AALG_WRHW_EN

/* Pointers to color correction matrices */
#define REG_PTR_CCM_HORIZON
#define REG_PTR_CCM_INCANDESCENT
#define REG_PTR_CCM_WARM_WHITE
#define REG_PTR_CCM_COOL_WHITE
#define REG_PTR_CCM_DL50
#define REG_PTR_CCM_DL65
#define REG_PTR_CCM_OUTDOOR

#define REG_ARR_CCM(n)

static const char * const s5k5baf_supply_names[] =;
#define S5K5BAF_NUM_SUPPLIES

enum s5k5baf_gpio_id {};

#define PAD_CIS
#define PAD_OUT
#define NUM_CIS_PADS
#define NUM_ISP_PADS

struct s5k5baf_pixfmt {};

struct s5k5baf_ctrls {};

enum {};

struct s5k5baf_fw {};

struct s5k5baf {};

static const struct s5k5baf_pixfmt s5k5baf_formats[] =;

static struct v4l2_rect s5k5baf_cis_rect =;

/* Setfile contains set of I2C command sequences. Each sequence has its ID.
 * setfile format:
 *	u8 magic[4];
 *	u16 count;		number of sequences
 *	struct {
 *		u16 id;		sequence id
 *		u16 offset;	sequence offset in data array
 *	} seq[count];
 *	u16 data[*];		array containing sequences
 *
 */
static int s5k5baf_fw_parse(struct device *dev, struct s5k5baf_fw **fw,
			    size_t count, const __le16 *data)
{}

static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
{}

static inline bool s5k5baf_is_cis_subdev(struct v4l2_subdev *sd)
{}

static inline struct s5k5baf *to_s5k5baf(struct v4l2_subdev *sd)
{}

static u16 s5k5baf_i2c_read(struct s5k5baf *state, u16 addr)
{}

static void s5k5baf_i2c_write(struct s5k5baf *state, u16 addr, u16 val)
{}

static u16 s5k5baf_read(struct s5k5baf *state, u16 addr)
{}

static void s5k5baf_write(struct s5k5baf *state, u16 addr, u16 val)
{}

static void s5k5baf_write_arr_seq(struct s5k5baf *state, u16 addr,
				  u16 count, const u16 *seq)
{}

#define s5k5baf_write_seq(state, addr, seq...)

/* add items count at the beginning of the list */
#define NSEQ(seq...)

/*
 * s5k5baf_write_nseq() - Writes sequences of values to sensor memory via i2c
 * @nseq: sequence of u16 words in format:
 *	(N, address, value[1]...value[N-1])*,0
 * Ex.:
 *	u16 seq[] = { NSEQ(0x4000, 1, 1), NSEQ(0x4010, 640, 480), 0 };
 *	ret = s5k5baf_write_nseq(c, seq);
 */
static void s5k5baf_write_nseq(struct s5k5baf *state, const u16 *nseq)
{}

static void s5k5baf_synchronize(struct s5k5baf *state, int timeout, u16 addr)
{}

static u16 *s5k5baf_fw_get_seq(struct s5k5baf *state, u16 seq_id)
{}

static void s5k5baf_hw_patch(struct s5k5baf *state)
{}

static void s5k5baf_hw_set_clocks(struct s5k5baf *state)
{}

/* set custom color correction matrices for various illuminations */
static void s5k5baf_hw_set_ccm(struct s5k5baf *state)
{}

/* CIS sensor tuning, based on undocumented android driver code */
static void s5k5baf_hw_set_cis(struct s5k5baf *state)
{}

static void s5k5baf_hw_sync_cfg(struct s5k5baf *state)
{}
/* Set horizontal and vertical image flipping */
static void s5k5baf_hw_set_mirror(struct s5k5baf *state)
{}

static void s5k5baf_hw_set_alg(struct s5k5baf *state, u16 alg, bool enable)
{}

/* Configure auto/manual white balance and R/G/B gains */
static void s5k5baf_hw_set_awb(struct s5k5baf *state, int awb)
{}

/* Program FW with exposure time, 'exposure' in us units */
static void s5k5baf_hw_set_user_exposure(struct s5k5baf *state, int exposure)
{}

static void s5k5baf_hw_set_user_gain(struct s5k5baf *state, int gain)
{}

/* Set auto/manual exposure and total gain */
static void s5k5baf_hw_set_auto_exposure(struct s5k5baf *state, int value)
{}

static void s5k5baf_hw_set_anti_flicker(struct s5k5baf *state, int v)
{}

static void s5k5baf_hw_set_colorfx(struct s5k5baf *state, int val)
{}

static int s5k5baf_find_pixfmt(struct v4l2_mbus_framefmt *mf)
{}

static int s5k5baf_clear_error(struct s5k5baf *state)
{}

static int s5k5baf_hw_set_video_bus(struct s5k5baf *state)
{}

static u16 s5k5baf_get_cfg_error(struct s5k5baf *state)
{}

static void s5k5baf_hw_set_fiv(struct s5k5baf *state, u16 fiv)
{}

static void s5k5baf_hw_find_min_fiv(struct s5k5baf *state)
{}

static void s5k5baf_hw_validate_cfg(struct s5k5baf *state)
{}

static void s5k5baf_rescale(struct v4l2_rect *r, const struct v4l2_rect *v,
			    const struct v4l2_rect *n,
			    const struct v4l2_rect *d)
{}

static int s5k5baf_hw_set_crop_rects(struct s5k5baf *state)
{}

static void s5k5baf_hw_set_config(struct s5k5baf *state)
{}


static void s5k5baf_hw_set_test_pattern(struct s5k5baf *state, int id)
{}

static void s5k5baf_gpio_assert(struct s5k5baf *state, int id)
{}

static void s5k5baf_gpio_deassert(struct s5k5baf *state, int id)
{}

static int s5k5baf_power_on(struct s5k5baf *state)
{}

static int s5k5baf_power_off(struct s5k5baf *state)
{}

static void s5k5baf_hw_init(struct s5k5baf *state)
{}

/*
 * V4L2 subdev core and video operations
 */

static void s5k5baf_initialize_data(struct s5k5baf *state)
{}

static int s5k5baf_load_setfile(struct s5k5baf *state)
{}

static int s5k5baf_set_power(struct v4l2_subdev *sd, int on)
{}

static void s5k5baf_hw_set_stream(struct s5k5baf *state, int enable)
{}

static int s5k5baf_s_stream(struct v4l2_subdev *sd, int on)
{}

static int s5k5baf_get_frame_interval(struct v4l2_subdev *sd,
				      struct v4l2_subdev_state *sd_state,
				      struct v4l2_subdev_frame_interval *fi)
{}

static void __s5k5baf_set_frame_interval(struct s5k5baf *state,
					 struct v4l2_subdev_frame_interval *fi)
{}

static int s5k5baf_set_frame_interval(struct v4l2_subdev *sd,
				      struct v4l2_subdev_state *sd_state,
				      struct v4l2_subdev_frame_interval *fi)
{}

/*
 * V4L2 subdev pad level and video operations
 */
static int s5k5baf_enum_frame_interval(struct v4l2_subdev *sd,
			      struct v4l2_subdev_state *sd_state,
			      struct v4l2_subdev_frame_interval_enum *fie)
{}

static int s5k5baf_enum_mbus_code(struct v4l2_subdev *sd,
				 struct v4l2_subdev_state *sd_state,
				 struct v4l2_subdev_mbus_code_enum *code)
{}

static int s5k5baf_enum_frame_size(struct v4l2_subdev *sd,
				  struct v4l2_subdev_state *sd_state,
				  struct v4l2_subdev_frame_size_enum *fse)
{}

static void s5k5baf_try_cis_format(struct v4l2_mbus_framefmt *mf)
{}

static int s5k5baf_try_isp_format(struct v4l2_mbus_framefmt *mf)
{}

static int s5k5baf_get_fmt(struct v4l2_subdev *sd,
			   struct v4l2_subdev_state *sd_state,
			   struct v4l2_subdev_format *fmt)
{}

static int s5k5baf_set_fmt(struct v4l2_subdev *sd,
			   struct v4l2_subdev_state *sd_state,
			   struct v4l2_subdev_format *fmt)
{}

enum selection_rect {};

static enum selection_rect s5k5baf_get_sel_rect(u32 pad, u32 target)
{}

static int s5k5baf_is_bound_target(u32 target)
{}

static int s5k5baf_get_selection(struct v4l2_subdev *sd,
				 struct v4l2_subdev_state *sd_state,
				 struct v4l2_subdev_selection *sel)
{}

/* bounds range [start, start+len) to [0, max) and aligns to 2 */
static void s5k5baf_bound_range(u32 *start, u32 *len, u32 max)
{}

static void s5k5baf_bound_rect(struct v4l2_rect *r, u32 width, u32 height)
{}

static void s5k5baf_set_rect_and_adjust(struct v4l2_rect **rects,
					enum selection_rect first,
					struct v4l2_rect *v)
{}

static bool s5k5baf_cmp_rect(const struct v4l2_rect *r1,
			     const struct v4l2_rect *r2)
{}

static int s5k5baf_set_selection(struct v4l2_subdev *sd,
				 struct v4l2_subdev_state *sd_state,
				 struct v4l2_subdev_selection *sel)
{}

static const struct v4l2_subdev_pad_ops s5k5baf_cis_pad_ops =;

static const struct v4l2_subdev_pad_ops s5k5baf_pad_ops =;

static const struct v4l2_subdev_video_ops s5k5baf_video_ops =;

/*
 * V4L2 subdev controls
 */

static int s5k5baf_s_ctrl(struct v4l2_ctrl *ctrl)
{}

static const struct v4l2_ctrl_ops s5k5baf_ctrl_ops =;

static const char * const s5k5baf_test_pattern_menu[] =;

static int s5k5baf_initialize_ctrls(struct s5k5baf *state)
{}

/*
 * V4L2 subdev internal operations
 */
static int s5k5baf_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{}

static int s5k5baf_check_fw_revision(struct s5k5baf *state)
{}

static int s5k5baf_registered(struct v4l2_subdev *sd)
{}

static void s5k5baf_unregistered(struct v4l2_subdev *sd)
{}

static const struct v4l2_subdev_ops s5k5baf_cis_subdev_ops =;

static const struct v4l2_subdev_internal_ops s5k5baf_cis_subdev_internal_ops =;

static const struct v4l2_subdev_internal_ops s5k5baf_subdev_internal_ops =;

static const struct v4l2_subdev_core_ops s5k5baf_core_ops =;

static const struct v4l2_subdev_ops s5k5baf_subdev_ops =;

static int s5k5baf_configure_gpios(struct s5k5baf *state)
{}

static int s5k5baf_parse_device_node(struct s5k5baf *state, struct device *dev)
{}

static int s5k5baf_configure_subdevs(struct s5k5baf *state,
				     struct i2c_client *c)
{}

static int s5k5baf_configure_regulators(struct s5k5baf *state)
{}

static int s5k5baf_probe(struct i2c_client *c)
{}

static void s5k5baf_remove(struct i2c_client *c)
{}

static const struct i2c_device_id s5k5baf_id[] =;
MODULE_DEVICE_TABLE(i2c, s5k5baf_id);

static const struct of_device_id s5k5baf_of_match[] =;
MODULE_DEVICE_TABLE(of, s5k5baf_of_match);

static struct i2c_driver s5k5baf_i2c_driver =;

module_i2c_driver();

MODULE_DESCRIPTION();
MODULE_AUTHOR();
MODULE_LICENSE();