linux/drivers/media/i2c/thp7312.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (C) 2021 THine Electronics, Inc.
 * Copyright (C) 2023 Ideas on Board Oy
 */

#include <linux/unaligned.h>

#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mtd/spi-nor.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/types.h>

#include <media/v4l2-async.h>
#include <media/v4l2-cci.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>

#include <uapi/linux/thp7312.h>

/* ISP registers */

#define THP7312_REG_FIRMWARE_VERSION_1
#define THP7312_REG_CAMERA_STATUS
#define THP7312_REG_FIRMWARE_VERSION_2
#define THP7312_REG_SET_OUTPUT_ENABLE
#define THP7312_OUTPUT_ENABLE
#define THP7312_OUTPUT_DISABLE
#define THP7312_REG_SET_OUTPUT_COLOR_COMPRESSION
#define THP7312_REG_SET_OUTPUT_COLOR_UYVY
#define THP7312_REG_SET_OUTPUT_COLOR_YUY2
#define THP7312_REG_FLIP_MIRROR
#define THP7312_REG_FLIP_MIRROR_FLIP
#define THP7312_REG_FLIP_MIRROR_MIRROR
#define THP7312_REG_VIDEO_IMAGE_SIZE
#define THP7312_VIDEO_IMAGE_SIZE_640x360
#define THP7312_VIDEO_IMAGE_SIZE_640x460
#define THP7312_VIDEO_IMAGE_SIZE_1280x720
#define THP7312_VIDEO_IMAGE_SIZE_1920x1080
#define THP7312_VIDEO_IMAGE_SIZE_3840x2160
#define THP7312_VIDEO_IMAGE_SIZE_4160x3120
#define THP7312_VIDEO_IMAGE_SIZE_2016x1512
#define THP7312_VIDEO_IMAGE_SIZE_2048x1536
#define THP7312_REG_VIDEO_FRAME_RATE_MODE
#define THP7312_VIDEO_FRAME_RATE_MODE1
#define THP7312_VIDEO_FRAME_RATE_MODE2
#define THP7312_VIDEO_FRAME_RATE_MODE3
#define THP7312_REG_SET_DRIVING_MODE
#define THP7312_REG_DRIVING_MODE_STATUS
#define THP7312_REG_JPEG_COMPRESSION_FACTOR
#define THP7312_REG_AE_EXPOSURE_COMPENSATION
#define THP7312_REG_AE_FLICKER_MODE
#define THP7312_AE_FLICKER_MODE_50
#define THP7312_AE_FLICKER_MODE_60
#define THP7312_AE_FLICKER_MODE_DISABLE
#define THP7312_REG_AE_FIX_FRAME_RATE
#define THP7312_REG_MANUAL_WB_RED_GAIN
#define THP7312_REG_MANUAL_WB_BLUE_GAIN
#define THP7312_REG_WB_MODE
#define THP7312_WB_MODE_AUTO
#define THP7312_WB_MODE_MANUAL
#define THP7312_REG_MANUAL_FOCUS_POSITION
#define THP7312_REG_AF_CONTROL
#define THP7312_REG_AF_CONTROL_AF
#define THP7312_REG_AF_CONTROL_MANUAL
#define THP7312_REG_AF_CONTROL_LOCK
#define THP7312_REG_AF_SETTING
#define THP7312_REG_AF_SETTING_ONESHOT_CONTRAST
#define THP7312_REG_AF_SETTING_ONESHOT_PDAF
#define THP7312_REG_AF_SETTING_ONESHOT_HYBRID
#define THP7312_REG_AF_SETTING_CONTINUOUS_CONTRAST
#define THP7312_REG_AF_SETTING_CONTINUOUS_PDAF
#define THP7312_REG_AF_SETTING_CONTINUOUS_HYBRID
#define THP7312_REG_AF_SUPPORT
#define THP7312_AF_SUPPORT_PDAF
#define THP7312_AF_SUPPORT_CONTRAST
#define THP7312_REG_SATURATION
#define THP7312_REG_SHARPNESS
#define THP7312_REG_BRIGHTNESS
#define THP7312_REG_CONTRAST
#define THP7312_REG_NOISE_REDUCTION
#define THP7312_REG_NOISE_REDUCTION_FIXED

#define TH7312_REG_CUSTOM_MIPI_SET
#define TH7312_REG_CUSTOM_MIPI_STATUS
#define TH7312_REG_CUSTOM_MIPI_RD
#define TH7312_REG_CUSTOM_MIPI_TD

/*
 * Firmware update registers. Those use a different address space than the
 * normal operation ISP registers.
 */

#define THP7312_REG_FW_DRIVABILITY
#define THP7312_REG_FW_DEST_BANK_ADDR
#define THP7312_REG_FW_VERIFY_RESULT
#define THP7312_REG_FW_RESET_FLASH
#define THP7312_REG_FW_MEMORY_IO_SETTING
#define THP7312_FW_MEMORY_IO_GPIO0
#define THP7312_FW_MEMORY_IO_GPIO1
#define THP7312_REG_FW_CRC_RESULT
#define THP7312_REG_FW_STATUS

#define THP7312_FW_VERSION(major, minor)
#define THP7312_FW_VERSION_MAJOR(v)
#define THP7312_FW_VERSION_MINOR(v)

enum thp7312_focus_method {};

/*
 * enum thp7312_focus_state - State of the focus handler
 *
 * @THP7312_FOCUS_STATE_MANUAL: Manual focus, controlled through the
 *	V4L2_CID_FOCUS_ABSOLUTE control
 * @THP7312_FOCUS_STATE_AUTO: Continuous auto-focus
 * @THP7312_FOCUS_STATE_LOCKED: Lock the focus to a fixed position. This state
 *	is entered when switching from auto to manual mode.
 * @THP7312_FOCUS_STATE_ONESHOT: One-shot auto-focus
 *
 * Valid transitions are as follow:
 *
 * digraph fsm {
 *         node [shape=circle];
 *
 *         manual [label="MANUAL"];
 *         auto [label="AUTO"];
 *         locked [label="LOCKED"];
 *         oneshot [label="ONESHOT"];
 *
 *         manual -> auto [label="FOCUS_AUTO <- true"]
 *         locked -> auto [label="FOCUS_AUTO <- true"]
 *         oneshot -> auto [label="FOCUS_AUTO <- true"]
 *         auto -> locked [label="FOCUS_AUTO <- false"]
 *
 *         locked -> manual [label="FOCUS_ABSOLUTE <- *"]
 *         oneshot -> manual [label="FOCUS_ABSOLUTE <- *"]
 *
 *         manual -> oneshot [label="FOCUS_START <- *"]
 *         locked -> oneshot [label="FOCUS_START <- *"]
 * }
 */
enum thp7312_focus_state {};

enum thp7312_boot_mode {};

struct thp7312_frame_rate {};

struct thp7312_mode_info {};

static const u32 thp7312_colour_fmts[] =;

/* regulator supplies */
static const char * const thp7312_supply_name[] =;

static const struct thp7312_mode_info thp7312_mode_info_data[] =;

struct thp7312_device;

struct thp7312_sensor_info {};

struct thp7312_sensor {};

struct thp7312_device {};

static const struct thp7312_sensor_info thp7312_sensor_info[] =;

static inline struct thp7312_device *to_thp7312_dev(struct v4l2_subdev *sd)
{}

static const struct thp7312_mode_info *
thp7312_find_mode(unsigned int width, unsigned int height, bool nearest)
{}

static const struct thp7312_frame_rate *
thp7312_find_rate(const struct thp7312_mode_info *mode, unsigned int fps,
		  bool nearest)
{}

/* -----------------------------------------------------------------------------
 * Device Access & Configuration
 */

#define thp7312_read_poll_timeout(dev, addr, val, cond, sleep_us, timeout_us)

static int thp7312_map_data_lanes(u8 *lane_remap, const u8 *lanes, u8 num_lanes)
{}

static int thp7312_set_mipi_lanes(struct thp7312_device *thp7312)
{}

static int thp7312_change_mode(struct thp7312_device *thp7312,
			       const struct thp7312_mode_info *mode,
			       const struct thp7312_frame_rate *rate)
{}

static int thp7312_set_framefmt(struct thp7312_device *thp7312,
				struct v4l2_mbus_framefmt *format)
{}

static int thp7312_init_mode(struct thp7312_device *thp7312,
			     struct v4l2_subdev_state *sd_state)
{}

static int thp7312_stream_enable(struct thp7312_device *thp7312, bool enable)
{}

static int thp7312_check_status_stream_mode(struct thp7312_device *thp7312)
{}

static void thp7312_reset(struct thp7312_device *thp7312)
{}

/* -----------------------------------------------------------------------------
 * Power Management
 */

static void __thp7312_power_off(struct thp7312_device *thp7312)
{}

static void thp7312_power_off(struct thp7312_device *thp7312)
{}

static int __thp7312_power_on(struct thp7312_device *thp7312)
{}

static int thp7312_power_on(struct thp7312_device *thp7312)
{}

static int __maybe_unused thp7312_pm_runtime_suspend(struct device *dev)
{}

static int __maybe_unused thp7312_pm_runtime_resume(struct device *dev)
{}

static const struct dev_pm_ops thp7312_pm_ops =;

/* -----------------------------------------------------------------------------
 * V4L2 Subdev Operations
 */

static bool thp7312_find_bus_code(u32 code)
{}

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

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

static int thp7312_enum_frame_interval(struct v4l2_subdev *sd,
				       struct v4l2_subdev_state *sd_state,
				       struct v4l2_subdev_frame_interval_enum *fie)
{}

static int thp7312_set_fmt(struct v4l2_subdev *sd,
			   struct v4l2_subdev_state *sd_state,
			   struct v4l2_subdev_format *format)
{}

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

static int thp7312_s_stream(struct v4l2_subdev *sd, int enable)
{}

static int thp7312_init_state(struct v4l2_subdev *sd,
			      struct v4l2_subdev_state *sd_state)
{}

static const struct v4l2_subdev_core_ops thp7312_core_ops =;

static const struct v4l2_subdev_video_ops thp7312_video_ops =;

static const struct v4l2_subdev_pad_ops thp7312_pad_ops =;

static const struct v4l2_subdev_ops thp7312_subdev_ops =;

static const struct v4l2_subdev_internal_ops thp7312_internal_ops =;

/* -----------------------------------------------------------------------------
 * V4L2 Control Operations
 */

static inline struct thp7312_device *to_thp7312_from_ctrl(struct v4l2_ctrl *ctrl)
{}

/* 0: 3000cm, 18: 8cm */
static const u16 thp7312_focus_values[] =;

static int thp7312_set_focus(struct thp7312_device *thp7312)
{}

static int thp7312_s_ctrl(struct v4l2_ctrl *ctrl)
{}

static const struct v4l2_ctrl_ops thp7312_ctrl_ops =;

/*
 * Refer to Documentation/userspace-api/media/drivers/thp7312.rst for details.
 */
static const struct v4l2_ctrl_config thp7312_ctrl_focus_method_cdaf =;

static const struct v4l2_ctrl_config thp7312_ctrl_focus_method_pdaf =;

static const struct v4l2_ctrl_config thp7312_v4l2_ctrls_custom[] =;

static const s64 exp_bias_qmenu[] =;

static int thp7312_init_controls(struct thp7312_device *thp7312)
{}

/* -----------------------------------------------------------------------------
 * Firmware Update
 */

/*
 * The firmware data is made of 128kB of RAM firmware, followed by a
 * variable-size "header". Both are stored in flash memory.
 */
#define THP7312_FW_RAM_SIZE
#define THP7312_FW_MIN_SIZE
#define THP7312_FW_MAX_SIZE

/*
 * Data is first uploaded to the THP7312 128kB SRAM, and then written to flash.
 * The SRAM is exposed over I2C as 32kB banks, and up to 4kB of data can be
 * transferred in a single I2C write.
 */
#define THP7312_RAM_BANK_SIZE
#define THP7312_FW_DOWNLOAD_UNIT

#define THP7312_FLASH_MEMORY_ERASE_TIMEOUT

#define THP7312_FLASH_MAX_REG_READ_SIZE
#define THP7312_FLASH_MAX_REG_DATA_SIZE

static const u8 thp7312_cmd_config_flash_mem_if[] =;

static const u8 thp7312_cmd_write_to_reg[] =;

static const u8 thp7312_cmd_read_reg[] =;

/*
 * THP7312 Write data from RAM to Flash Memory
 * Command ID FF700F
 * Format: FF700F AA AA AA BB BB BB
 * AA AA AA: destination start address
 * BB BB BB: (write size - 1)
 * Source address always starts from 0
 */
static const u8 thp7312_cmd_write_ram_to_flash[] =;

/*
 * THP7312 Calculate CRC command
 * Command ID: FF70 09
 * Format: FF70 09 AA AA AA BB BB BB
 * AA AA AA: Start address of calculation
 * BB BB BB: (calculate size - 1)
 */
static const u8 thp7312_cmd_calc_crc[] =;

static const u8 thp7312_jedec_rdid[] =;
static const u8 thp7312_jedec_rdsr[] =;
static const u8 thp7312_jedec_wen[] =;

static int thp7312_read_firmware_version(struct thp7312_device *thp7312)
{}

static int thp7312_write_buf(struct thp7312_device *thp7312,
			     const u8 *write_buf, u16 write_size)
{}

static int __thp7312_flash_reg_write(struct thp7312_device *thp7312,
				     const u8 *write_buf, u16 write_size)
{}

static int __thp7312_flash_reg_read(struct thp7312_device *thp7312,
				    const u8 *write_buf, u16 write_size,
				    u8 *read_buf, u16 read_size)
{}

#define thp7312_flash_reg_write(thp7312, wrbuf)

#define thp7312_flash_reg_read(thp7312, wrbuf, rdbuf)

static enum fw_upload_err thp7312_fw_prepare_config(struct thp7312_device *thp7312)
{}

static enum fw_upload_err thp7312_fw_prepare_check(struct thp7312_device *thp7312)
{}

static enum fw_upload_err thp7312_fw_prepare_reset(struct thp7312_device *thp7312)
{}

/* TODO: Erase only the amount of blocks necessary */
static enum fw_upload_err thp7312_flash_erase(struct thp7312_device *thp7312)
{}

static enum fw_upload_err
thp7312_write_download_data_by_unit(struct thp7312_device *thp7312,
				    unsigned int addr, const u8 *data,
				    unsigned int size)
{}

static enum fw_upload_err thp7312_fw_load_to_ram(struct thp7312_device *thp7312,
						 const u8 *data, u32 size)
{}

static enum fw_upload_err thp7312_fw_write_to_flash(struct thp7312_device *thp7312,
						    u32 dest, u32 write_size)
{}

static enum fw_upload_err thp7312_fw_check_crc(struct thp7312_device *thp7312,
					       const u8 *fw_data, u32 fw_size)
{}

static enum fw_upload_err thp7312_fw_prepare(struct fw_upload *fw_upload,
					     const u8 *data, u32 size)
{}

static enum fw_upload_err thp7312_fw_write(struct fw_upload *fw_upload,
					   const u8 *data, u32 offset,
					   u32 size, u32 *written)
{}

static enum fw_upload_err thp7312_fw_poll_complete(struct fw_upload *fw_upload)
{}

/*
 * This may be called asynchronously with an on-going update.  All other
 * functions are called sequentially in a single thread. To avoid contention on
 * register accesses, only update the cancel_request flag. Other functions will
 * check this flag and handle the cancel request synchronously.
 */
static void thp7312_fw_cancel(struct fw_upload *fw_upload)
{}

static const struct fw_upload_ops thp7312_fw_upload_ops =;

static int thp7312_register_flash_mode(struct thp7312_device *thp7312)
{}

/* -----------------------------------------------------------------------------
 * Probe & Remove
 */

static int thp7312_get_regulators(struct thp7312_device *thp7312)
{}

static int thp7312_sensor_parse_dt(struct thp7312_device *thp7312,
				   struct fwnode_handle *node)
{}

static int thp7312_parse_dt(struct thp7312_device *thp7312)
{}

static int thp7312_probe(struct i2c_client *client)
{}

static void thp7312_remove(struct i2c_client *client)
{}

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

static struct i2c_driver thp7312_i2c_driver =;

module_i2c_driver();

MODULE_DESCRIPTION();
MODULE_LICENSE();