aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-5.15/950-0722-media-i2c-Add-support-for-19.2MHz-clock-to-ov7251.patch
blob: 6052cfa479b9f30772c261c59f3cfcdcb799624f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
From 16af9ae925fdb05960f644b6cc84098af8aa3956 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Tue, 15 Feb 2022 23:07:33 +0000
Subject: [PATCH] media: i2c: Add support for 19.2MHz clock to ov7251

The OV7251 sensor is used as the IR camera sensor on the Microsoft
Surface line of tablets; this provides a 19.2MHz external clock. Add
the ability to support that rate to the driver by defining a new set
of PLL configs. Extend the clock handling in .probe() to check for
either supported frequency.

Signed-off-by: Daniel Scally <djrscally@gmail.com>
---
 drivers/media/i2c/ov7251.c | 61 ++++++++++++++++++++++++++++----------
 1 file changed, 45 insertions(+), 16 deletions(-)

--- a/drivers/media/i2c/ov7251.c
+++ b/drivers/media/i2c/ov7251.c
@@ -134,10 +134,19 @@ static inline struct ov7251 *to_ov7251(s
 }
 
 enum xclk_rate {
+	OV7251_19_2_MHZ,
 	OV7251_24_MHZ,
 	OV7251_NUM_SUPPORTED_RATES
 };
 
+static const struct ov7251_pll1_config ov7251_pll1_config_19_2_mhz = {
+	.pre_div = 0x03,
+	.mult = 0x4b,
+	.div = 0x01,
+	.pix_div = 0x0a,
+	.mipi_div = 0x05
+};
+
 static const struct ov7251_pll1_config ov7251_pll1_config_24_mhz = {
 	.pre_div = 0x03,
 	.mult = 0x64,
@@ -146,6 +155,14 @@ static const struct ov7251_pll1_config o
 	.mipi_div = 0x05
 };
 
+static const struct ov7251_pll2_config ov7251_pll2_config_19_2_mhz = {
+	.pre_div = 0x04,
+	.mult = 0x32,
+	.div = 0x00,
+	.sys_div = 0x05,
+	.adc_div = 0x04
+};
+
 static const struct ov7251_pll2_config ov7251_pll2_config_24_mhz = {
 	.pre_div = 0x04,
 	.mult = 0x28,
@@ -154,12 +171,18 @@ static const struct ov7251_pll2_config o
 	.adc_div = 0x04
 };
 
+static const struct ov7251_pll_configs ov7251_pll_configs_19_2_mhz = {
+	.pll1 = &ov7251_pll1_config_19_2_mhz,
+	.pll2 = &ov7251_pll2_config_19_2_mhz
+};
+
 static const struct ov7251_pll_configs ov7251_pll_configs_24_mhz = {
 	.pll1 = &ov7251_pll1_config_24_mhz,
 	.pll2 = &ov7251_pll2_config_24_mhz
 };
 
 static const struct ov7251_pll_configs *ov7251_pll_configs[] = {
+	[OV7251_19_2_MHZ] = &ov7251_pll_configs_19_2_mhz,
 	[OV7251_24_MHZ] = &ov7251_pll_configs_24_mhz
 };
 
@@ -553,6 +576,7 @@ static const struct reg_value ov7251_set
 };
 
 static const unsigned long supported_xclk_rates[] = {
+	[OV7251_19_2_MHZ] = 19200000,
 	[OV7251_24_MHZ] = 24000000,
 };
 
@@ -1424,6 +1448,7 @@ static int ov7251_probe(struct i2c_clien
 	struct device *dev = &client->dev;
 	struct ov7251 *ov7251;
 	u8 chip_id_high, chip_id_low, chip_rev;
+	unsigned int rate = 0;
 	int ret;
 	int i;
 
@@ -1439,35 +1464,39 @@ static int ov7251_probe(struct i2c_clien
 		return ret;
 
 	/* get system clock (xclk) */
-	ov7251->xclk = devm_clk_get(dev, "xclk");
+	ov7251->xclk = devm_clk_get(dev, NULL);
 	if (IS_ERR(ov7251->xclk)) {
 		dev_err(dev, "could not get xclk");
 		return PTR_ERR(ov7251->xclk);
 	}
 
+	/*
+	 * We could have either a 24MHz or 19.2MHz clock rate from either dt or
+	 * ACPI. We also need to support the IPU3 case which will have both an
+	 * external clock AND a clock-frequency property.
+	 */
 	ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency",
-				       &ov7251->xclk_freq);
-	if (ret) {
-		dev_err(dev, "could not get xclk frequency\n");
-		return ret;
+				       &rate);
+	if (!ret && ov7251->xclk) {
+		ret = clk_set_rate(ov7251->xclk, rate);
+		if (ret)
+			return dev_err_probe(dev, ret,
+					     "failed to set clock rate\n");
+	} else if (ret && !ov7251->xclk) {
+		return dev_err_probe(dev, ret, "invalid clock config\n");
 	}
 
-	/* external clock must be 24MHz, allow 1% tolerance */
-	if (ov7251->xclk_freq < 23760000 || ov7251->xclk_freq > 24240000) {
-		dev_err(dev, "external clock frequency %u is not supported\n",
-			ov7251->xclk_freq);
-		return -EINVAL;
-	}
+	ov7251->xclk_freq = rate ? rate : clk_get_rate(ov7251->xclk);
 
-	ret = clk_set_rate(ov7251->xclk, ov7251->xclk_freq);
-	if (ret) {
-		dev_err(dev, "could not set xclk frequency\n");
-		return ret;
-	}
 	for (i = 0; i < ARRAY_SIZE(supported_xclk_rates); i++)
 		if (ov7251->xclk_freq == supported_xclk_rates[i])
 			break;
 
+	if (i == ARRAY_SIZE(supported_xclk_rates))
+		return dev_err_probe(dev, -EINVAL,
+				     "clock rate %u Hz is unsupported\n",
+				     ov7251->xclk_freq);
+
 	ov7251->pll_configs = ov7251_pll_configs[i];
 
 	ov7251->io_regulator = devm_regulator_get(dev, "vdddo");