| From c175c735869b0dfa8c21fc57d5bd02ca370f9117 Mon Sep 17 00:00:00 2001 |
| From: Dave Stevenson <dave.stevenson@raspberrypi.com> |
| Date: Thu, 25 Jun 2020 08:28:51 +0100 |
| Subject: [PATCH] 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> |
| --- |
| drivers/media/i2c/imx290.c | 119 ++++++++++++++++++++++++++++++------- |
| 1 file changed, 97 insertions(+), 22 deletions(-) |
| |
| --- a/drivers/media/i2c/imx290.c |
| +++ b/drivers/media/i2c/imx290.c |
| @@ -1,6 +1,10 @@ |
| // 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. |
| * |
| @@ -22,6 +26,11 @@ |
| #include <media/v4l2-fwnode.h> |
| #include <media/v4l2-subdev.h> |
| |
| +enum imx290_clk_index { |
| + CLK_37_125, |
| + CLK_74_25, |
| +}; |
| + |
| #define IMX290_STANDBY 0x3000 |
| #define IMX290_REGHOLD 0x3001 |
| #define IMX290_XMSTA 0x3002 |
| @@ -60,11 +69,16 @@ struct imx290_mode { |
| |
| const struct imx290_regval *data; |
| 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 device *dev; |
| struct clk *xclk; |
| + u32 xclk_freq; |
| struct regmap *regmap; |
| u8 nlanes; |
| u8 bpp; |
| @@ -116,8 +130,6 @@ static const struct imx290_regval imx290 |
| { 0x3018, 0x65 }, |
| { 0x3019, 0x04 }, |
| { 0x301a, 0x00 }, |
| - { 0x3444, 0x20 }, |
| - { 0x3445, 0x25 }, |
| { 0x303a, 0x0c }, |
| { 0x3040, 0x00 }, |
| { 0x3041, 0x00 }, |
| @@ -171,6 +183,30 @@ static const struct imx290_regval imx290 |
| { 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[] = { |
| /* mode settings */ |
| { 0x3007, 0x00 }, |
| @@ -182,13 +218,6 @@ static const struct imx290_regval imx290 |
| { 0x3419, 0x04 }, |
| { 0x3012, 0x64 }, |
| { 0x3013, 0x00 }, |
| - { 0x305c, 0x18 }, |
| - { 0x305d, 0x03 }, |
| - { 0x305e, 0x20 }, |
| - { 0x305f, 0x01 }, |
| - { 0x315e, 0x1a }, |
| - { 0x3164, 0x1a }, |
| - { 0x3480, 0x49 }, |
| /* data rate settings */ |
| { 0x3405, 0x10 }, |
| { 0x3446, 0x57 }, |
| @@ -209,6 +238,30 @@ static const struct imx290_regval imx290 |
| { 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[] = { |
| /* mode settings */ |
| { 0x3007, 0x10 }, |
| @@ -220,13 +273,6 @@ static const struct imx290_regval imx290 |
| { 0x3419, 0x02 }, |
| { 0x3012, 0x64 }, |
| { 0x3013, 0x00 }, |
| - { 0x305c, 0x20 }, |
| - { 0x305d, 0x00 }, |
| - { 0x305e, 0x20 }, |
| - { 0x305f, 0x01 }, |
| - { 0x315e, 0x1a }, |
| - { 0x3164, 0x1a }, |
| - { 0x3480, 0x49 }, |
| /* data rate settings */ |
| { 0x3405, 0x10 }, |
| { 0x3446, 0x4f }, |
| @@ -312,6 +358,11 @@ static const struct imx290_mode imx290_m |
| .link_freq_index = FREQ_INDEX_1080P, |
| .data = 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, |
| @@ -320,6 +371,11 @@ static const struct imx290_mode imx290_m |
| .link_freq_index = FREQ_INDEX_720P, |
| .data = 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_m |
| .link_freq_index = FREQ_INDEX_1080P, |
| .data = 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, |
| @@ -339,6 +400,11 @@ static const struct imx290_mode imx290_m |
| .link_freq_index = FREQ_INDEX_720P, |
| .data = 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 |
| /* Start streaming */ |
| 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; |
| |
| /* Set init register settings */ |
| @@ -723,6 +791,14 @@ static int imx290_start_streaming(struct |
| 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 */ |
| ret = imx290_write_current_format(imx290); |
| if (ret < 0) { |
| @@ -939,7 +1015,6 @@ static int imx290_probe(struct i2c_clien |
| .bus_type = V4L2_MBUS_CSI2_DPHY |
| }; |
| struct imx290 *imx290; |
| - u32 xclk_freq; |
| s64 fq; |
| int ret; |
| |
| @@ -1003,21 +1078,21 @@ static int imx290_probe(struct i2c_clien |
| } |
| |
| ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", |
| - &xclk_freq); |
| + &imx290->xclk_freq); |
| if (ret) { |
| dev_err(dev, "Could not get xclk frequency\n"); |
| goto free_err; |
| } |
| |
| /* 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", |
| - xclk_freq); |
| + imx290->xclk_freq); |
| ret = -EINVAL; |
| goto free_err; |
| } |
| |
| - ret = clk_set_rate(imx290->xclk, xclk_freq); |
| + ret = clk_set_rate(imx290->xclk, imx290->xclk_freq); |
| if (ret) { |
| dev_err(dev, "Could not set xclk frequency\n"); |
| goto free_err; |