// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2025 Linaro Ltd
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/units.h>
#include <media/v4l2-cci.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
#define S5K3M5_LINK_FREQ_602P5MHZ (602500ULL * HZ_PER_KHZ)
#define S5K3M5_MCLK_FREQ_24MHZ (24 * HZ_PER_MHZ)
#define S5K3M5_DATA_LANES 4
/* Register map is similar to MIPI CCS compliant camera sensors */
#define S5K3M5_REG_CHIP_ID CCI_REG16(0x0000)
#define S5K3M5_CHIP_ID 0x30d5
/* Both streaming and flipping settings are controlled at the same time */
#define S5K3M5_REG_CTRL_MODE CCI_REG16(0x0100)
#define S5K3M5_MODE_STREAMING BIT(8)
#define S5K3M5_VFLIP BIT(1)
#define S5K3M5_HFLIP BIT(0)
#define S5K3M5_REG_EXPOSURE CCI_REG16(0x0202)
#define S5K3M5_EXPOSURE_MIN 8
#define S5K3M5_EXPOSURE_STEP 1
#define S5K3M5_EXPOSURE_MARGIN 4
#define S5K3M5_REG_AGAIN CCI_REG16(0x0204)
#define S5K3M5_AGAIN_MIN 1
#define S5K3M5_AGAIN_MAX 16
#define S5K3M5_AGAIN_STEP 1
#define S5K3M5_AGAIN_DEFAULT 1
#define S5K3M5_AGAIN_SHIFT 5
#define S5K3M5_REG_VTS CCI_REG16(0x0340)
#define S5K3M5_VTS_MAX 0xffff
#define S5K3M5_REG_HTS CCI_REG16(0x0342)
#define S5K3M5_REG_X_ADDR_START CCI_REG16(0x0344)
#define S5K3M5_REG_Y_ADDR_START CCI_REG16(0x0346)
#define S5K3M5_REG_X_ADDR_END CCI_REG16(0x0348)
#define S5K3M5_REG_Y_ADDR_END CCI_REG16(0x034a)
#define S5K3M5_REG_X_OUTPUT_SIZE CCI_REG16(0x034c)
#define S5K3M5_REG_Y_OUTPUT_SIZE CCI_REG16(0x034e)
#define S5K3M5_REG_TEST_PATTERN CCI_REG16(0x0600)
#define to_s5k3m5(_sd) container_of(_sd, struct s5k3m5, sd)
static const s64 s5k3m5_link_freq_menu[] = {
S5K3M5_LINK_FREQ_602P5MHZ,
};
/* List of supported formats to cover horizontal and vertical flip controls */
static const u32 s5k3m5_mbus_formats[] = {
MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10,
MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10,
};
struct s5k3m5_reg_list {
const struct cci_reg_sequence *regs;
unsigned int num_regs;
};
struct s5k3m5_mode {
u32 width; /* Frame width in pixels */
u32 height; /* Frame height in pixels */
u32 hts; /* Horizontal timing size */
u32 vts; /* Default vertical timing size */
u32 exposure; /* Default exposure value */
const struct s5k3m5_reg_list reg_list; /* Sensor register setting */
};
static const char * const s5k3m5_test_pattern_menu[] = {
"Disabled",
"Solid colour",
"Colour bars",
"Fade to grey colour bars",
"PN9",
};
static const char * const s5k3m5_supply_names[] = {