bcm27xx: add support for linux v5.15
[openwrt/staging/chunkeey.git] / target / linux / bcm27xx / patches-5.15 / 950-0722-media-i2c-Add-support-for-19.2MHz-clock-to-ov7251.patch
1 From 16af9ae925fdb05960f644b6cc84098af8aa3956 Mon Sep 17 00:00:00 2001
2 From: Daniel Scally <djrscally@gmail.com>
3 Date: Tue, 15 Feb 2022 23:07:33 +0000
4 Subject: [PATCH] media: i2c: Add support for 19.2MHz clock to ov7251
5
6 The OV7251 sensor is used as the IR camera sensor on the Microsoft
7 Surface line of tablets; this provides a 19.2MHz external clock. Add
8 the ability to support that rate to the driver by defining a new set
9 of PLL configs. Extend the clock handling in .probe() to check for
10 either supported frequency.
11
12 Signed-off-by: Daniel Scally <djrscally@gmail.com>
13 ---
14 drivers/media/i2c/ov7251.c | 61 ++++++++++++++++++++++++++++----------
15 1 file changed, 45 insertions(+), 16 deletions(-)
16
17 --- a/drivers/media/i2c/ov7251.c
18 +++ b/drivers/media/i2c/ov7251.c
19 @@ -134,10 +134,19 @@ static inline struct ov7251 *to_ov7251(s
20 }
21
22 enum xclk_rate {
23 + OV7251_19_2_MHZ,
24 OV7251_24_MHZ,
25 OV7251_NUM_SUPPORTED_RATES
26 };
27
28 +static const struct ov7251_pll1_config ov7251_pll1_config_19_2_mhz = {
29 + .pre_div = 0x03,
30 + .mult = 0x4b,
31 + .div = 0x01,
32 + .pix_div = 0x0a,
33 + .mipi_div = 0x05
34 +};
35 +
36 static const struct ov7251_pll1_config ov7251_pll1_config_24_mhz = {
37 .pre_div = 0x03,
38 .mult = 0x64,
39 @@ -146,6 +155,14 @@ static const struct ov7251_pll1_config o
40 .mipi_div = 0x05
41 };
42
43 +static const struct ov7251_pll2_config ov7251_pll2_config_19_2_mhz = {
44 + .pre_div = 0x04,
45 + .mult = 0x32,
46 + .div = 0x00,
47 + .sys_div = 0x05,
48 + .adc_div = 0x04
49 +};
50 +
51 static const struct ov7251_pll2_config ov7251_pll2_config_24_mhz = {
52 .pre_div = 0x04,
53 .mult = 0x28,
54 @@ -154,12 +171,18 @@ static const struct ov7251_pll2_config o
55 .adc_div = 0x04
56 };
57
58 +static const struct ov7251_pll_configs ov7251_pll_configs_19_2_mhz = {
59 + .pll1 = &ov7251_pll1_config_19_2_mhz,
60 + .pll2 = &ov7251_pll2_config_19_2_mhz
61 +};
62 +
63 static const struct ov7251_pll_configs ov7251_pll_configs_24_mhz = {
64 .pll1 = &ov7251_pll1_config_24_mhz,
65 .pll2 = &ov7251_pll2_config_24_mhz
66 };
67
68 static const struct ov7251_pll_configs *ov7251_pll_configs[] = {
69 + [OV7251_19_2_MHZ] = &ov7251_pll_configs_19_2_mhz,
70 [OV7251_24_MHZ] = &ov7251_pll_configs_24_mhz
71 };
72
73 @@ -553,6 +576,7 @@ static const struct reg_value ov7251_set
74 };
75
76 static const unsigned long supported_xclk_rates[] = {
77 + [OV7251_19_2_MHZ] = 19200000,
78 [OV7251_24_MHZ] = 24000000,
79 };
80
81 @@ -1424,6 +1448,7 @@ static int ov7251_probe(struct i2c_clien
82 struct device *dev = &client->dev;
83 struct ov7251 *ov7251;
84 u8 chip_id_high, chip_id_low, chip_rev;
85 + unsigned int rate = 0;
86 int ret;
87 int i;
88
89 @@ -1439,35 +1464,39 @@ static int ov7251_probe(struct i2c_clien
90 return ret;
91
92 /* get system clock (xclk) */
93 - ov7251->xclk = devm_clk_get(dev, "xclk");
94 + ov7251->xclk = devm_clk_get(dev, NULL);
95 if (IS_ERR(ov7251->xclk)) {
96 dev_err(dev, "could not get xclk");
97 return PTR_ERR(ov7251->xclk);
98 }
99
100 + /*
101 + * We could have either a 24MHz or 19.2MHz clock rate from either dt or
102 + * ACPI. We also need to support the IPU3 case which will have both an
103 + * external clock AND a clock-frequency property.
104 + */
105 ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency",
106 - &ov7251->xclk_freq);
107 - if (ret) {
108 - dev_err(dev, "could not get xclk frequency\n");
109 - return ret;
110 + &rate);
111 + if (!ret && ov7251->xclk) {
112 + ret = clk_set_rate(ov7251->xclk, rate);
113 + if (ret)
114 + return dev_err_probe(dev, ret,
115 + "failed to set clock rate\n");
116 + } else if (ret && !ov7251->xclk) {
117 + return dev_err_probe(dev, ret, "invalid clock config\n");
118 }
119
120 - /* external clock must be 24MHz, allow 1% tolerance */
121 - if (ov7251->xclk_freq < 23760000 || ov7251->xclk_freq > 24240000) {
122 - dev_err(dev, "external clock frequency %u is not supported\n",
123 - ov7251->xclk_freq);
124 - return -EINVAL;
125 - }
126 + ov7251->xclk_freq = rate ? rate : clk_get_rate(ov7251->xclk);
127
128 - ret = clk_set_rate(ov7251->xclk, ov7251->xclk_freq);
129 - if (ret) {
130 - dev_err(dev, "could not set xclk frequency\n");
131 - return ret;
132 - }
133 for (i = 0; i < ARRAY_SIZE(supported_xclk_rates); i++)
134 if (ov7251->xclk_freq == supported_xclk_rates[i])
135 break;
136
137 + if (i == ARRAY_SIZE(supported_xclk_rates))
138 + return dev_err_probe(dev, -EINVAL,
139 + "clock rate %u Hz is unsupported\n",
140 + ov7251->xclk_freq);
141 +
142 ov7251->pll_configs = ov7251_pll_configs[i];
143
144 ov7251->io_regulator = devm_regulator_get(dev, "vdddo");