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
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.
12 Signed-off-by: Daniel Scally <djrscally@gmail.com>
14 drivers/media/i2c/ov7251.c | 61 ++++++++++++++++++++++++++++----------
15 1 file changed, 45 insertions(+), 16 deletions(-)
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
25 OV7251_NUM_SUPPORTED_RATES
28 +static const struct ov7251_pll1_config ov7251_pll1_config_19_2_mhz = {
36 static const struct ov7251_pll1_config ov7251_pll1_config_24_mhz = {
39 @@ -146,6 +155,14 @@ static const struct ov7251_pll1_config o
43 +static const struct ov7251_pll2_config ov7251_pll2_config_19_2_mhz = {
51 static const struct ov7251_pll2_config ov7251_pll2_config_24_mhz = {
54 @@ -154,12 +171,18 @@ static const struct ov7251_pll2_config o
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
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
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
73 @@ -553,6 +576,7 @@ static const struct reg_value ov7251_set
76 static const unsigned long supported_xclk_rates[] = {
77 + [OV7251_19_2_MHZ] = 19200000,
78 [OV7251_24_MHZ] = 24000000,
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;
89 @@ -1439,35 +1464,39 @@ static int ov7251_probe(struct i2c_clien
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);
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.
105 ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency",
106 - &ov7251->xclk_freq);
108 - dev_err(dev, "could not get xclk frequency\n");
111 + if (!ret && ov7251->xclk) {
112 + ret = clk_set_rate(ov7251->xclk, rate);
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");
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);
126 + ov7251->xclk_freq = rate ? rate : clk_get_rate(ov7251->xclk);
128 - ret = clk_set_rate(ov7251->xclk, ov7251->xclk_freq);
130 - dev_err(dev, "could not set xclk frequency\n");
133 for (i = 0; i < ARRAY_SIZE(supported_xclk_rates); i++)
134 if (ov7251->xclk_freq == supported_xclk_rates[i])
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);
142 ov7251->pll_configs = ov7251_pll_configs[i];
144 ov7251->io_regulator = devm_regulator_get(dev, "vdddo");