mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-20 22:23:27 +00:00
145 lines
4.2 KiB
Diff
145 lines
4.2 KiB
Diff
|
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");
|