All of lore.kernel.org
 help / color / mirror / Atom feed
From: Danila Tikhonov <danila@mainlining.org>
To: Bjorn Andersson <andersson@kernel.org>,
	Konrad Dybcio <konradybcio@kernel.org>,
	Rob Herring <robh@kernel.org>,
	Krzysztof Kozlowski <krzk+dt@kernel.org>,
	Conor Dooley <conor+dt@kernel.org>,
	Sakari Ailus <sakari.ailus@linux.intel.com>,
	Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>,
	Mauro Carvalho Chehab <mchehab@kernel.org>,
	Eugene Lepshy <fekz115@gmail.com>,
	Vasiliy Doylov <neko@altlinux.org>,
	Achill Gilgenast <achill@achill.org>,
	Luca Weiss <luca.weiss@fairphone.com>
Cc: linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-media@vger.kernel.org,
	~postmarketos/upstreaming@lists.sr.ht,
	Danila Tikhonov <danila@mainlining.org>
Subject: [PATCH 1/2] drivers: media: i2c: s5kjn1: Add support for 19.2MHz MCLK
Date: Sat,  1 Aug 2026 17:31:24 +0300	[thread overview]
Message-ID: <20260801143125.267054-2-danila@mainlining.org> (raw)
In-Reply-To: <20260801143125.267054-1-danila@mainlining.org>

The S5KJN1 sensor supports a range of external clock frequencies (MCLK),
while the driver currently only supports a 24MHz MCLK.

The 19.2MHz clock is used by the S5KJN1 camera sensor on the
Nothing Phone (1) aka sm7325-nothing-spacewar.

Add support for this frequency.

While splitting the clock settings into separate register sequences,
add definitions for the known clock-related registers and values instead
of using raw register addresses and magic values.

Signed-off-by: Danila Tikhonov <danila@mainlining.org>
---
 drivers/media/i2c/s5kjn1.c | 183 ++++++++++++++++++++++++++++++-------
 1 file changed, 151 insertions(+), 32 deletions(-)

diff --git a/drivers/media/i2c/s5kjn1.c b/drivers/media/i2c/s5kjn1.c
index a707cb740556..1036e629758f 100644
--- a/drivers/media/i2c/s5kjn1.c
+++ b/drivers/media/i2c/s5kjn1.c
@@ -15,6 +15,7 @@
 #include <media/v4l2-fwnode.h>
 
 #define S5KJN1_LINK_FREQ_700MHZ		(700ULL * HZ_PER_MHZ)
+#define S5KJN1_MCLK_FREQ_19P2MHZ	(19200 * HZ_PER_KHZ)
 #define S5KJN1_MCLK_FREQ_24MHZ		(24 * HZ_PER_MHZ)
 #define S5KJN1_DATA_LANES		4
 
@@ -25,6 +26,24 @@
 #define S5KJN1_REG_CTRL_MODE		CCI_REG8(0x0100)
 #define S5KJN1_MODE_STREAMING		BIT(0)
 
+#define S5KJN1_REG_EXTCLK_INTEGER	CCI_REG16(0x0136)
+#define S5KJN1_REG_EXTCLK_FRACTION	CCI_REG16(0x013e)
+#define S5KJN1_REG_VT_PIX_CLK_DIV	CCI_REG16(0x0300)
+#define S5KJN1_REG_VT_SYS_CLK_DIV	CCI_REG16(0x0302)
+#define S5KJN1_REG_VT_PRE_PLL_CLK_DIV	CCI_REG16(0x0304)
+#define S5KJN1_REG_VT_PLL_MULTIPLIER	CCI_REG16(0x0306)
+
+#define S5KJN1_EXTCLK_19P2MHZ_INTEGER	0x1300
+#define S5KJN1_EXTCLK_19P2MHZ_FRACTION	0x00c8
+#define S5KJN1_EXTCLK_24MHZ_INTEGER	0x1800
+#define S5KJN1_EXTCLK_24MHZ_FRACTION	0x0000
+#define S5KJN1_VT_PIX_CLK_DIV		0x0006
+#define S5KJN1_VT_SYS_CLK_DIV		0x0001
+#define S5KJN1_VT_PRE_PLL_DIV_19P2MHZ	0x0003
+#define S5KJN1_VT_PRE_PLL_DIV_24MHZ	0x0004
+#define S5KJN1_VT_PLL_MUL_19P2MHZ	0x0083
+#define S5KJN1_VT_PLL_MUL_24MHZ		0x008c
+
 #define S5KJN1_REG_ORIENTATION		CCI_REG8(0x0101)
 #define S5KJN1_VFLIP			BIT(1)
 #define S5KJN1_HFLIP			BIT(0)
@@ -70,6 +89,17 @@ struct s5kjn1_reg_list {
 	unsigned int num_regs;
 };
 
+enum s5kjn1_mclk {
+	S5KJN1_MCLK_19P2MHZ,
+	S5KJN1_MCLK_24MHZ,
+	S5KJN1_NUM_MCLKS,
+};
+
+static const unsigned long s5kjn1_mclk_freqs[S5KJN1_NUM_MCLKS] = {
+	[S5KJN1_MCLK_19P2MHZ] = S5KJN1_MCLK_FREQ_19P2MHZ,
+	[S5KJN1_MCLK_24MHZ] = S5KJN1_MCLK_FREQ_24MHZ,
+};
+
 struct s5kjn1_mode {
 	u32 width;			/* Frame width in pixels */
 	u32 height;			/* Frame height in pixels */
@@ -78,7 +108,10 @@ struct s5kjn1_mode {
 	u32 exposure;			/* Default exposure value */
 	u32 exposure_margin;		/* Exposure margin */
 
-	const struct s5kjn1_reg_list reg_list;	/* Sensor register setting */
+	/* Sensor register setting */
+	const struct s5kjn1_reg_list mode_setup_reg_list;
+	const struct s5kjn1_reg_list clk_reg_list[S5KJN1_NUM_MCLKS];
+	const struct s5kjn1_reg_list frame_timing_reg_list;
 };
 
 static const char * const s5kjn1_test_pattern_menu[] = {
@@ -93,6 +126,7 @@ struct s5kjn1 {
 	struct device *dev;
 	struct regmap *regmap;
 	struct clk *mclk;
+	unsigned int mclk_index;
 	struct gpio_desc *reset_gpio;
 	struct regulator *afvdd;	/* Autofocus actuator power */
 	struct regulator *vdda;		/* Analog power */
@@ -147,7 +181,7 @@ static const struct cci_reg_sequence init_array_setting[] = {
 	{ CCI_REG16(0x011a), 0x0001 },
 };
 
-static const struct cci_reg_sequence s5kjn1_4080x3072_30fps_mode[] = {
+static const struct cci_reg_sequence s5kjn1_4080x3072_30fps_mode_setup[] = {
 	{ CCI_REG16(0x6028), 0x2400 },
 	{ CCI_REG16(0x602a), 0x1a28 },
 	{ CCI_REG16(0x6f12), 0x4c00 },
@@ -403,21 +437,39 @@ static const struct cci_reg_sequence s5kjn1_4080x3072_30fps_mode[] = {
 	{ CCI_REG16(0x0110), 0x1002 },
 	{ CCI_REG16(0x0114), 0x0301 },
 	{ CCI_REG16(0x0116), 0x3000 },
+};
 
-	/* Clock settings */
-	{ CCI_REG16(0x0136), 0x1800 },
-	{ CCI_REG16(0x013e), 0x0000 },
-	{ CCI_REG16(0x0300), 0x0006 },
-	{ CCI_REG16(0x0302), 0x0001 },
-	{ CCI_REG16(0x0304), 0x0004 },
-	{ CCI_REG16(0x0306), 0x008c },
+static const struct cci_reg_sequence s5kjn1_4080x3072_30fps_19p2mhz_clk[] = {
+	{ S5KJN1_REG_EXTCLK_INTEGER, S5KJN1_EXTCLK_19P2MHZ_INTEGER },
+	{ S5KJN1_REG_EXTCLK_FRACTION, S5KJN1_EXTCLK_19P2MHZ_FRACTION },
+	{ S5KJN1_REG_VT_PIX_CLK_DIV, S5KJN1_VT_PIX_CLK_DIV },
+	{ S5KJN1_REG_VT_SYS_CLK_DIV, S5KJN1_VT_SYS_CLK_DIV },
+	{ S5KJN1_REG_VT_PRE_PLL_CLK_DIV, S5KJN1_VT_PRE_PLL_DIV_19P2MHZ },
+	{ S5KJN1_REG_VT_PLL_MULTIPLIER, S5KJN1_VT_PLL_MUL_19P2MHZ },
+	{ CCI_REG16(0x0308), 0x0008 },
+	{ CCI_REG16(0x030a), 0x0001 },
+	{ CCI_REG16(0x030c), 0x0000 },
+	{ CCI_REG16(0x030e), 0x0003 },
+	{ CCI_REG16(0x0310), 0x0089 },
+	{ CCI_REG16(0x0312), 0x0000 },
+};
+
+static const struct cci_reg_sequence s5kjn1_4080x3072_30fps_24mhz_clk[] = {
+	{ S5KJN1_REG_EXTCLK_INTEGER, S5KJN1_EXTCLK_24MHZ_INTEGER },
+	{ S5KJN1_REG_EXTCLK_FRACTION, S5KJN1_EXTCLK_24MHZ_FRACTION },
+	{ S5KJN1_REG_VT_PIX_CLK_DIV, S5KJN1_VT_PIX_CLK_DIV },
+	{ S5KJN1_REG_VT_SYS_CLK_DIV, S5KJN1_VT_SYS_CLK_DIV },
+	{ S5KJN1_REG_VT_PRE_PLL_CLK_DIV, S5KJN1_VT_PRE_PLL_DIV_24MHZ },
+	{ S5KJN1_REG_VT_PLL_MULTIPLIER, S5KJN1_VT_PLL_MUL_24MHZ },
 	{ CCI_REG16(0x0308), 0x0008 },
 	{ CCI_REG16(0x030a), 0x0001 },
 	{ CCI_REG16(0x030c), 0x0000 },
 	{ CCI_REG16(0x030e), 0x0004 },
 	{ CCI_REG16(0x0310), 0x0092 },
 	{ CCI_REG16(0x0312), 0x0000 },
+};
 
+static const struct cci_reg_sequence s5kjn1_4080x3072_30fps_frame_timing[] = {
 	{ CCI_REG16(0x080e), 0x0000 },
 	{ S5KJN1_REG_VTS,    0x10c0 },
 	{ S5KJN1_REG_HTS,    0x1100 },
@@ -431,7 +483,7 @@ static const struct cci_reg_sequence s5kjn1_4080x3072_30fps_mode[] = {
 	{ CCI_REG16(0x0816), 0x1c00 },
 };
 
-static const struct cci_reg_sequence s5kjn1_8160x6144_10fps_mode[] = {
+static const struct cci_reg_sequence s5kjn1_8160x6144_10fps_mode_setup[] = {
 	{ CCI_REG16(0x6028), 0x2400 },
 	{ CCI_REG16(0x602a), 0x1a28 },
 	{ CCI_REG16(0x6f12), 0x4c00 },
@@ -687,21 +739,39 @@ static const struct cci_reg_sequence s5kjn1_8160x6144_10fps_mode[] = {
 	{ CCI_REG16(0x0110), 0x1002 },
 	{ CCI_REG16(0x0114), 0x0300 },
 	{ CCI_REG16(0x0116), 0x3000 },
+};
+
+static const struct cci_reg_sequence s5kjn1_8160x6144_10fps_19p2mhz_clk[] = {
+	{ S5KJN1_REG_EXTCLK_INTEGER, S5KJN1_EXTCLK_19P2MHZ_INTEGER },
+	{ S5KJN1_REG_EXTCLK_FRACTION, S5KJN1_EXTCLK_19P2MHZ_FRACTION },
+	{ S5KJN1_REG_VT_PIX_CLK_DIV, S5KJN1_VT_PIX_CLK_DIV },
+	{ S5KJN1_REG_VT_SYS_CLK_DIV, S5KJN1_VT_SYS_CLK_DIV },
+	{ S5KJN1_REG_VT_PRE_PLL_CLK_DIV, S5KJN1_VT_PRE_PLL_DIV_19P2MHZ },
+	{ S5KJN1_REG_VT_PLL_MULTIPLIER, S5KJN1_VT_PLL_MUL_19P2MHZ },
+	{ CCI_REG16(0x0308), 0x0008 },
+	{ CCI_REG16(0x030a), 0x0001 },
+	{ CCI_REG16(0x030c), 0x0000 },
+	{ CCI_REG16(0x030e), 0x0003 },
+	{ CCI_REG16(0x0310), 0x006d },
+	{ CCI_REG16(0x0312), 0x0000 },
+};
 
-	/* Clock settings */
-	{ CCI_REG16(0x0136), 0x1800 },
-	{ CCI_REG16(0x013e), 0x0000 },
-	{ CCI_REG16(0x0300), 0x0006 },
-	{ CCI_REG16(0x0302), 0x0001 },
-	{ CCI_REG16(0x0304), 0x0004 },
-	{ CCI_REG16(0x0306), 0x008c },
+static const struct cci_reg_sequence s5kjn1_8160x6144_10fps_24mhz_clk[] = {
+	{ S5KJN1_REG_EXTCLK_INTEGER, S5KJN1_EXTCLK_24MHZ_INTEGER },
+	{ S5KJN1_REG_EXTCLK_FRACTION, S5KJN1_EXTCLK_24MHZ_FRACTION },
+	{ S5KJN1_REG_VT_PIX_CLK_DIV, S5KJN1_VT_PIX_CLK_DIV },
+	{ S5KJN1_REG_VT_SYS_CLK_DIV, S5KJN1_VT_SYS_CLK_DIV },
+	{ S5KJN1_REG_VT_PRE_PLL_CLK_DIV, S5KJN1_VT_PRE_PLL_DIV_24MHZ },
+	{ S5KJN1_REG_VT_PLL_MULTIPLIER, S5KJN1_VT_PLL_MUL_24MHZ },
 	{ CCI_REG16(0x0308), 0x0008 },
 	{ CCI_REG16(0x030a), 0x0001 },
 	{ CCI_REG16(0x030c), 0x0000 },
 	{ CCI_REG16(0x030e), 0x0004 },
 	{ CCI_REG16(0x0310), 0x0074 },
 	{ CCI_REG16(0x0312), 0x0000 },
+};
 
+static const struct cci_reg_sequence s5kjn1_8160x6144_10fps_frame_timing[] = {
 	{ CCI_REG16(0x080e), 0x0000 },
 	{ S5KJN1_REG_VTS,    0x1900 },
 	{ S5KJN1_REG_HTS,    0x21f0 },
@@ -722,9 +792,23 @@ static const struct s5kjn1_mode s5kjn1_supported_modes[] = {
 		.vts = 4288,
 		.exposure = 3840,
 		.exposure_margin = 22,
-		.reg_list = {
-			.regs = s5kjn1_4080x3072_30fps_mode,
-			.num_regs = ARRAY_SIZE(s5kjn1_4080x3072_30fps_mode),
+		.mode_setup_reg_list = {
+			.regs = s5kjn1_4080x3072_30fps_mode_setup,
+			.num_regs = ARRAY_SIZE(s5kjn1_4080x3072_30fps_mode_setup),
+		},
+		.clk_reg_list = {
+			[S5KJN1_MCLK_19P2MHZ] = {
+				.regs = s5kjn1_4080x3072_30fps_19p2mhz_clk,
+				.num_regs = ARRAY_SIZE(s5kjn1_4080x3072_30fps_19p2mhz_clk),
+			},
+			[S5KJN1_MCLK_24MHZ] = {
+				.regs = s5kjn1_4080x3072_30fps_24mhz_clk,
+				.num_regs = ARRAY_SIZE(s5kjn1_4080x3072_30fps_24mhz_clk),
+			},
+		},
+		.frame_timing_reg_list = {
+			.regs = s5kjn1_4080x3072_30fps_frame_timing,
+			.num_regs = ARRAY_SIZE(s5kjn1_4080x3072_30fps_frame_timing),
 		},
 	},
 	{
@@ -734,9 +818,23 @@ static const struct s5kjn1_mode s5kjn1_supported_modes[] = {
 		.vts = 6400,
 		.exposure = 6144,
 		.exposure_margin = 44,
-		.reg_list = {
-			.regs = s5kjn1_8160x6144_10fps_mode,
-			.num_regs = ARRAY_SIZE(s5kjn1_8160x6144_10fps_mode),
+		.mode_setup_reg_list = {
+			.regs = s5kjn1_8160x6144_10fps_mode_setup,
+			.num_regs = ARRAY_SIZE(s5kjn1_8160x6144_10fps_mode_setup),
+		},
+		.clk_reg_list = {
+			[S5KJN1_MCLK_19P2MHZ] = {
+				.regs = s5kjn1_8160x6144_10fps_19p2mhz_clk,
+				.num_regs = ARRAY_SIZE(s5kjn1_8160x6144_10fps_19p2mhz_clk),
+			},
+			[S5KJN1_MCLK_24MHZ] = {
+				.regs = s5kjn1_8160x6144_10fps_24mhz_clk,
+				.num_regs = ARRAY_SIZE(s5kjn1_8160x6144_10fps_24mhz_clk),
+			},
+		},
+		.frame_timing_reg_list = {
+			.regs = s5kjn1_8160x6144_10fps_frame_timing,
+			.num_regs = ARRAY_SIZE(s5kjn1_8160x6144_10fps_frame_timing),
 		},
 	},
 };
@@ -894,9 +992,12 @@ static int s5kjn1_enable_streams(struct v4l2_subdev *sd,
 				 u64 streams_mask)
 {
 	struct s5kjn1 *s5kjn1 = to_s5kjn1(sd);
-	const struct s5kjn1_reg_list *reg_list = &s5kjn1->mode->reg_list;
+	const struct s5kjn1_mode *mode = s5kjn1->mode;
+	const struct s5kjn1_reg_list *clk_reg_list;
 	int ret;
 
+	clk_reg_list = &mode->clk_reg_list[s5kjn1->mclk_index];
+
 	ret = pm_runtime_resume_and_get(s5kjn1->dev);
 	if (ret)
 		return ret;
@@ -924,8 +1025,12 @@ static int s5kjn1_enable_streams(struct v4l2_subdev *sd,
 	/* Sensor init settings */
 	cci_multi_reg_write(s5kjn1->regmap, init_array_setting,
 			    ARRAY_SIZE(init_array_setting), &ret);
-	cci_multi_reg_write(s5kjn1->regmap, reg_list->regs,
-			    reg_list->num_regs, &ret);
+	cci_multi_reg_write(s5kjn1->regmap, mode->mode_setup_reg_list.regs,
+			    mode->mode_setup_reg_list.num_regs, &ret);
+	cci_multi_reg_write(s5kjn1->regmap, clk_reg_list->regs,
+			    clk_reg_list->num_regs, &ret);
+	cci_multi_reg_write(s5kjn1->regmap, mode->frame_timing_reg_list.regs,
+			    mode->frame_timing_reg_list.num_regs, &ret);
 	if (ret)
 		goto error;
 
@@ -1199,6 +1304,23 @@ static int s5kjn1_check_hwcfg(struct s5kjn1 *s5kjn1)
 	return ret;
 }
 
+static int s5kjn1_get_mclk_index(struct s5kjn1 *s5kjn1)
+{
+	unsigned long freq = clk_get_rate(s5kjn1->mclk);
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(s5kjn1_mclk_freqs); i++) {
+		if (freq == s5kjn1_mclk_freqs[i]) {
+			s5kjn1->mclk_index = i;
+			return 0;
+		}
+	}
+
+	return dev_err_probe(s5kjn1->dev, -EINVAL,
+			     "MCLK clock frequency %lu is not supported\n",
+			     freq);
+}
+
 static int s5kjn1_power_on(struct device *dev)
 {
 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
@@ -1290,7 +1412,6 @@ static int s5kjn1_power_off(struct device *dev)
 static int s5kjn1_probe(struct i2c_client *client)
 {
 	struct s5kjn1 *s5kjn1;
-	unsigned long freq;
 	int ret;
 
 	s5kjn1 = devm_kzalloc(&client->dev, sizeof(*s5kjn1), GFP_KERNEL);
@@ -1310,11 +1431,9 @@ static int s5kjn1_probe(struct i2c_client *client)
 		return dev_err_probe(s5kjn1->dev, PTR_ERR(s5kjn1->mclk),
 				     "failed to get MCLK clock\n");
 
-	freq = clk_get_rate(s5kjn1->mclk);
-	if (freq != S5KJN1_MCLK_FREQ_24MHZ)
-		return dev_err_probe(s5kjn1->dev, -EINVAL,
-				     "MCLK clock frequency %lu is not supported\n",
-				     freq);
+	ret = s5kjn1_get_mclk_index(s5kjn1);
+	if (ret)
+		return ret;
 
 	ret = s5kjn1_check_hwcfg(s5kjn1);
 	if (ret)
-- 
2.55.0


  reply	other threads:[~2026-08-01 14:31 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-01 14:31 [PATCH 0/2] Add Ultra Wide Camera Support for Nothing Phone (1) Danila Tikhonov
2026-08-01 14:31 ` Danila Tikhonov [this message]
2026-08-01 14:39   ` [PATCH 1/2] drivers: media: i2c: s5kjn1: Add support for 19.2MHz MCLK Neko
2026-08-01 14:31 ` [PATCH 2/2] arm64: dts: qcom: sm7325-nothing-spacewar: Add ultra wide camera support Danila Tikhonov
2026-08-01 14:40   ` Neko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260801143125.267054-2-danila@mainlining.org \
    --to=danila@mainlining.org \
    --cc=achill@achill.org \
    --cc=andersson@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=fekz115@gmail.com \
    --cc=konradybcio@kernel.org \
    --cc=krzk+dt@kernel.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=luca.weiss@fairphone.com \
    --cc=mchehab@kernel.org \
    --cc=neko@altlinux.org \
    --cc=robh@kernel.org \
    --cc=sakari.ailus@linux.intel.com \
    --cc=vladimir.zapolskiy@linaro.org \
    --cc=~postmarketos/upstreaming@lists.sr.ht \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.