mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-07 02:19:54 +00:00
media: i2c: imx290: Add support for 74.25MHz clock
The existing driver only supported a clock of 37.125MHz, but the sensor also supports 74.25MHz. Add the relevant register modifications to support this alternate clock frequency. Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
This commit is contained in:
committed by
popcornmix
parent
93fad8890c
commit
6b0c094a5b
@@ -1,6 +1,10 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/*
|
/*
|
||||||
* Sony IMX290 CMOS Image Sensor Driver
|
* Sony IMX290/327 CMOS Image Sensor Driver
|
||||||
|
*
|
||||||
|
* The IMX290 and IMX327 are very similar 1920x1080 1/2.8 CMOS image sensors.
|
||||||
|
* IMX327 can support up to 60fps, whilst IMX290 support up to 120fps (only
|
||||||
|
* 10bit and when connected over 4 CSI-2 lanes).
|
||||||
*
|
*
|
||||||
* Copyright (C) 2019 FRAMOS GmbH.
|
* Copyright (C) 2019 FRAMOS GmbH.
|
||||||
*
|
*
|
||||||
@@ -22,6 +26,11 @@
|
|||||||
#include <media/v4l2-fwnode.h>
|
#include <media/v4l2-fwnode.h>
|
||||||
#include <media/v4l2-subdev.h>
|
#include <media/v4l2-subdev.h>
|
||||||
|
|
||||||
|
enum imx290_clk_index {
|
||||||
|
CLK_37_125,
|
||||||
|
CLK_74_25,
|
||||||
|
};
|
||||||
|
|
||||||
#define IMX290_STANDBY 0x3000
|
#define IMX290_STANDBY 0x3000
|
||||||
#define IMX290_REGHOLD 0x3001
|
#define IMX290_REGHOLD 0x3001
|
||||||
#define IMX290_XMSTA 0x3002
|
#define IMX290_XMSTA 0x3002
|
||||||
@@ -60,11 +69,16 @@ struct imx290_mode {
|
|||||||
|
|
||||||
const struct imx290_regval *data;
|
const struct imx290_regval *data;
|
||||||
u32 data_size;
|
u32 data_size;
|
||||||
|
|
||||||
|
/* Clock setup can vary. Index as enum imx290_clk_index */
|
||||||
|
const struct imx290_regval *clk_data[2];
|
||||||
|
u32 clk_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct imx290 {
|
struct imx290 {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct clk *xclk;
|
struct clk *xclk;
|
||||||
|
u32 xclk_freq;
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
u8 nlanes;
|
u8 nlanes;
|
||||||
u8 bpp;
|
u8 bpp;
|
||||||
@@ -116,8 +130,6 @@ static const struct imx290_regval imx290_global_init_settings[] = {
|
|||||||
{ 0x3018, 0x65 },
|
{ 0x3018, 0x65 },
|
||||||
{ 0x3019, 0x04 },
|
{ 0x3019, 0x04 },
|
||||||
{ 0x301a, 0x00 },
|
{ 0x301a, 0x00 },
|
||||||
{ 0x3444, 0x20 },
|
|
||||||
{ 0x3445, 0x25 },
|
|
||||||
{ 0x303a, 0x0c },
|
{ 0x303a, 0x0c },
|
||||||
{ 0x3040, 0x00 },
|
{ 0x3040, 0x00 },
|
||||||
{ 0x3041, 0x00 },
|
{ 0x3041, 0x00 },
|
||||||
@@ -171,6 +183,30 @@ static const struct imx290_regval imx290_global_init_settings[] = {
|
|||||||
{ 0x33b3, 0x04 },
|
{ 0x33b3, 0x04 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct imx290_regval imx290_37_125mhz_clock_1080p[] = {
|
||||||
|
{ 0x305c, 0x18 },
|
||||||
|
{ 0x305d, 0x03 },
|
||||||
|
{ 0x305e, 0x20 },
|
||||||
|
{ 0x305f, 0x01 },
|
||||||
|
{ 0x315e, 0x1a },
|
||||||
|
{ 0x3164, 0x1a },
|
||||||
|
{ 0x3444, 0x20 },
|
||||||
|
{ 0x3445, 0x25 },
|
||||||
|
{ 0x3480, 0x49 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct imx290_regval imx290_74_250mhz_clock_1080p[] = {
|
||||||
|
{ 0x305c, 0x0c },
|
||||||
|
{ 0x305d, 0x03 },
|
||||||
|
{ 0x305e, 0x10 },
|
||||||
|
{ 0x305f, 0x01 },
|
||||||
|
{ 0x315e, 0x1b },
|
||||||
|
{ 0x3164, 0x1b },
|
||||||
|
{ 0x3444, 0x40 },
|
||||||
|
{ 0x3445, 0x4a },
|
||||||
|
{ 0x3480, 0x92 },
|
||||||
|
};
|
||||||
|
|
||||||
static const struct imx290_regval imx290_1080p_settings[] = {
|
static const struct imx290_regval imx290_1080p_settings[] = {
|
||||||
/* mode settings */
|
/* mode settings */
|
||||||
{ 0x3007, 0x00 },
|
{ 0x3007, 0x00 },
|
||||||
@@ -182,13 +218,6 @@ static const struct imx290_regval imx290_1080p_settings[] = {
|
|||||||
{ 0x3419, 0x04 },
|
{ 0x3419, 0x04 },
|
||||||
{ 0x3012, 0x64 },
|
{ 0x3012, 0x64 },
|
||||||
{ 0x3013, 0x00 },
|
{ 0x3013, 0x00 },
|
||||||
{ 0x305c, 0x18 },
|
|
||||||
{ 0x305d, 0x03 },
|
|
||||||
{ 0x305e, 0x20 },
|
|
||||||
{ 0x305f, 0x01 },
|
|
||||||
{ 0x315e, 0x1a },
|
|
||||||
{ 0x3164, 0x1a },
|
|
||||||
{ 0x3480, 0x49 },
|
|
||||||
/* data rate settings */
|
/* data rate settings */
|
||||||
{ 0x3405, 0x10 },
|
{ 0x3405, 0x10 },
|
||||||
{ 0x3446, 0x57 },
|
{ 0x3446, 0x57 },
|
||||||
@@ -209,6 +238,30 @@ static const struct imx290_regval imx290_1080p_settings[] = {
|
|||||||
{ 0x3455, 0x00 },
|
{ 0x3455, 0x00 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct imx290_regval imx290_37_125mhz_clock_720p[] = {
|
||||||
|
{ 0x305c, 0x20 },
|
||||||
|
{ 0x305d, 0x00 },
|
||||||
|
{ 0x305e, 0x20 },
|
||||||
|
{ 0x305f, 0x01 },
|
||||||
|
{ 0x315e, 0x1a },
|
||||||
|
{ 0x3164, 0x1a },
|
||||||
|
{ 0x3444, 0x20 },
|
||||||
|
{ 0x3445, 0x25 },
|
||||||
|
{ 0x3480, 0x49 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct imx290_regval imx290_74_250mhz_clock_720p[] = {
|
||||||
|
{ 0x305c, 0x10 },
|
||||||
|
{ 0x305d, 0x00 },
|
||||||
|
{ 0x305e, 0x10 },
|
||||||
|
{ 0x305f, 0x01 },
|
||||||
|
{ 0x315e, 0x1b },
|
||||||
|
{ 0x3164, 0x1b },
|
||||||
|
{ 0x3444, 0x40 },
|
||||||
|
{ 0x3445, 0x4a },
|
||||||
|
{ 0x3480, 0x92 },
|
||||||
|
};
|
||||||
|
|
||||||
static const struct imx290_regval imx290_720p_settings[] = {
|
static const struct imx290_regval imx290_720p_settings[] = {
|
||||||
/* mode settings */
|
/* mode settings */
|
||||||
{ 0x3007, 0x10 },
|
{ 0x3007, 0x10 },
|
||||||
@@ -220,13 +273,6 @@ static const struct imx290_regval imx290_720p_settings[] = {
|
|||||||
{ 0x3419, 0x02 },
|
{ 0x3419, 0x02 },
|
||||||
{ 0x3012, 0x64 },
|
{ 0x3012, 0x64 },
|
||||||
{ 0x3013, 0x00 },
|
{ 0x3013, 0x00 },
|
||||||
{ 0x305c, 0x20 },
|
|
||||||
{ 0x305d, 0x00 },
|
|
||||||
{ 0x305e, 0x20 },
|
|
||||||
{ 0x305f, 0x01 },
|
|
||||||
{ 0x315e, 0x1a },
|
|
||||||
{ 0x3164, 0x1a },
|
|
||||||
{ 0x3480, 0x49 },
|
|
||||||
/* data rate settings */
|
/* data rate settings */
|
||||||
{ 0x3405, 0x10 },
|
{ 0x3405, 0x10 },
|
||||||
{ 0x3446, 0x4f },
|
{ 0x3446, 0x4f },
|
||||||
@@ -312,6 +358,11 @@ static const struct imx290_mode imx290_modes_2lanes[] = {
|
|||||||
.link_freq_index = FREQ_INDEX_1080P,
|
.link_freq_index = FREQ_INDEX_1080P,
|
||||||
.data = imx290_1080p_settings,
|
.data = imx290_1080p_settings,
|
||||||
.data_size = ARRAY_SIZE(imx290_1080p_settings),
|
.data_size = ARRAY_SIZE(imx290_1080p_settings),
|
||||||
|
.clk_data = {
|
||||||
|
[CLK_37_125] = imx290_37_125mhz_clock_1080p,
|
||||||
|
[CLK_74_25] = imx290_74_250mhz_clock_1080p,
|
||||||
|
},
|
||||||
|
.clk_size = ARRAY_SIZE(imx290_37_125mhz_clock_1080p),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.width = 1280,
|
.width = 1280,
|
||||||
@@ -320,6 +371,11 @@ static const struct imx290_mode imx290_modes_2lanes[] = {
|
|||||||
.link_freq_index = FREQ_INDEX_720P,
|
.link_freq_index = FREQ_INDEX_720P,
|
||||||
.data = imx290_720p_settings,
|
.data = imx290_720p_settings,
|
||||||
.data_size = ARRAY_SIZE(imx290_720p_settings),
|
.data_size = ARRAY_SIZE(imx290_720p_settings),
|
||||||
|
.clk_data = {
|
||||||
|
[CLK_37_125] = imx290_37_125mhz_clock_1080p,
|
||||||
|
[CLK_74_25] = imx290_74_250mhz_clock_1080p,
|
||||||
|
},
|
||||||
|
.clk_size = ARRAY_SIZE(imx290_37_125mhz_clock_1080p),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -331,6 +387,11 @@ static const struct imx290_mode imx290_modes_4lanes[] = {
|
|||||||
.link_freq_index = FREQ_INDEX_1080P,
|
.link_freq_index = FREQ_INDEX_1080P,
|
||||||
.data = imx290_1080p_settings,
|
.data = imx290_1080p_settings,
|
||||||
.data_size = ARRAY_SIZE(imx290_1080p_settings),
|
.data_size = ARRAY_SIZE(imx290_1080p_settings),
|
||||||
|
.clk_data = {
|
||||||
|
[CLK_37_125] = imx290_37_125mhz_clock_720p,
|
||||||
|
[CLK_74_25] = imx290_74_250mhz_clock_720p,
|
||||||
|
},
|
||||||
|
.clk_size = ARRAY_SIZE(imx290_37_125mhz_clock_720p),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.width = 1280,
|
.width = 1280,
|
||||||
@@ -339,6 +400,11 @@ static const struct imx290_mode imx290_modes_4lanes[] = {
|
|||||||
.link_freq_index = FREQ_INDEX_720P,
|
.link_freq_index = FREQ_INDEX_720P,
|
||||||
.data = imx290_720p_settings,
|
.data = imx290_720p_settings,
|
||||||
.data_size = ARRAY_SIZE(imx290_720p_settings),
|
.data_size = ARRAY_SIZE(imx290_720p_settings),
|
||||||
|
.clk_data = {
|
||||||
|
[CLK_37_125] = imx290_37_125mhz_clock_720p,
|
||||||
|
[CLK_74_25] = imx290_74_250mhz_clock_720p,
|
||||||
|
},
|
||||||
|
.clk_size = ARRAY_SIZE(imx290_37_125mhz_clock_720p),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -712,6 +778,8 @@ static int imx290_set_hmax(struct imx290 *imx290, u32 val)
|
|||||||
/* Start streaming */
|
/* Start streaming */
|
||||||
static int imx290_start_streaming(struct imx290 *imx290)
|
static int imx290_start_streaming(struct imx290 *imx290)
|
||||||
{
|
{
|
||||||
|
enum imx290_clk_index clk_idx = imx290->xclk_freq == 37125000 ?
|
||||||
|
CLK_37_125 : CLK_74_25;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Set init register settings */
|
/* Set init register settings */
|
||||||
@@ -723,6 +791,14 @@ static int imx290_start_streaming(struct imx290 *imx290)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = imx290_set_register_array(imx290,
|
||||||
|
imx290->current_mode->clk_data[clk_idx],
|
||||||
|
imx290->current_mode->clk_size);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(imx290->dev, "Could not set clock registers\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Apply the register values related to current frame format */
|
/* Apply the register values related to current frame format */
|
||||||
ret = imx290_write_current_format(imx290);
|
ret = imx290_write_current_format(imx290);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -939,7 +1015,6 @@ static int imx290_probe(struct i2c_client *client)
|
|||||||
.bus_type = V4L2_MBUS_CSI2_DPHY
|
.bus_type = V4L2_MBUS_CSI2_DPHY
|
||||||
};
|
};
|
||||||
struct imx290 *imx290;
|
struct imx290 *imx290;
|
||||||
u32 xclk_freq;
|
|
||||||
s64 fq;
|
s64 fq;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -1003,21 +1078,21 @@ static int imx290_probe(struct i2c_client *client)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency",
|
ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency",
|
||||||
&xclk_freq);
|
&imx290->xclk_freq);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "Could not get xclk frequency\n");
|
dev_err(dev, "Could not get xclk frequency\n");
|
||||||
goto free_err;
|
goto free_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* external clock must be 37.125 MHz */
|
/* external clock must be 37.125 MHz */
|
||||||
if (xclk_freq != 37125000) {
|
if (imx290->xclk_freq != 37125000 && imx290->xclk_freq != 74250000) {
|
||||||
dev_err(dev, "External clock frequency %u is not supported\n",
|
dev_err(dev, "External clock frequency %u is not supported\n",
|
||||||
xclk_freq);
|
imx290->xclk_freq);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto free_err;
|
goto free_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = clk_set_rate(imx290->xclk, xclk_freq);
|
ret = clk_set_rate(imx290->xclk, imx290->xclk_freq);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "Could not set xclk frequency\n");
|
dev_err(dev, "Could not set xclk frequency\n");
|
||||||
goto free_err;
|
goto free_err;
|
||||||
|
|||||||
Reference in New Issue
Block a user