From patchwork Tue Apr 12 13:55:30 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adam Ford X-Patchwork-Id: 560129 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 66035C433EF for ; Tue, 12 Apr 2022 13:56:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1356617AbiDLN6U (ORCPT ); Tue, 12 Apr 2022 09:58:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:32828 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1356547AbiDLN6E (ORCPT ); Tue, 12 Apr 2022 09:58:04 -0400 Received: from mail-il1-x134.google.com (mail-il1-x134.google.com [IPv6:2607:f8b0:4864:20::134]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 949AE5F95; Tue, 12 Apr 2022 06:55:46 -0700 (PDT) Received: by mail-il1-x134.google.com with SMTP id r11so13626994ila.1; Tue, 12 Apr 2022 06:55:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=BFygX3e7jf6/dIYH8/lrT+A75jVZH0A2pgBQWAXlxbw=; b=fj/affBQ8bmBfZ2qeG9uXS2pjNKW82Mcyb26Wfy2NltfalDzmUh3qXowxqbZMdwsi0 xVDQDTAZkdR9z3MNaeOQyvHnBBfPMF50RlV9Z720F10CAmKZcwh9DY+aMKsJBV1Y2HTj VWDaJWmK7bF9sPxxaLWhY5faR1GCEZ6GG/XDF6+G6T+oz0u8vYlXy+4t77LCOXHZG33q PUmW/KHJT6LXxRqINtfeRCQuBRTRmVC6DSBJVBA3tTCZGsXa4j5QtNH6Pol6Yf+puCar LF+jU7CAbM+mpQuEMdKONE1ajmg2mPPjRwzAb9qVIA/fv8REUHqqklfd9QA0OzOdugj2 Fz+g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=BFygX3e7jf6/dIYH8/lrT+A75jVZH0A2pgBQWAXlxbw=; b=AFC3srrae4kNHbAjVkSMxEL/z/oxKLD2oFOFk4Z4OkAK02Njps9uo/ryCk/18RSifq l53mIYQJ6aC8FKYd94wO4FzaLWHP1WhBk+9CdUhSikA/Qbneh3qzck1NUlXF7WAjgP9n FCiYvruVrFqWmocmImswlMsk0PmLNTRezwa2N18U4DmB8l3mPX36B7AyDgl9cK2xyTW5 URppNS4VBC7mqcotFa4ub4ND2AZVDYJWkioKBsbL1n/ZtpDsDAMMdZe3m1QIzr1JXoa+ Y02RKGCRJX4PEb/naTay8f/OyErlRfAT1XdXqrVNRxutfwuD2RwDSoK+t5p8axZEqNIy sSBQ== X-Gm-Message-State: AOAM530KbrbsLhuevExDT79YrqBw68TolUPQAfc9LhZ7nT4su6S5OcgB HEIIyd/c0o8DGXfVOmtwL0WKm0u22Frb8A== X-Google-Smtp-Source: ABdhPJzskXSdeHIbPNslR7qV78wRjFqJ+Mllhg5OdadDMxDVhmYYvGTuHKv8MSOnuv6j4RFUJNPMag== X-Received: by 2002:a05:6e02:1566:b0:2ca:a34a:a673 with SMTP id k6-20020a056e02156600b002caa34aa673mr5970257ilu.1.1649771745533; Tue, 12 Apr 2022 06:55:45 -0700 (PDT) Received: from aford-IdeaCentre-A730.lan ([2601:448:8400:9e8:2611:a7ae:f1c9:5ec2]) by smtp.gmail.com with ESMTPSA id n12-20020a92dd0c000000b002cac22690b6sm2280748ilm.0.2022.04.12.06.55.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 12 Apr 2022 06:55:44 -0700 (PDT) From: Adam Ford To: linux-media@vger.kernel.org Cc: prabhakar.mahadev-lad.rj@bp.renesas.com, tharvey@gateworks.com, cstevens@beaconembedded.com, aford@beaconembedded.com, laurent.pinchart@ideasonboard.com, Adam Ford , Dave Stevenson , Mauro Carvalho Chehab , linux-kernel@vger.kernel.org Subject: [PATCH 1/4] media: i2c: imx219: Split common registers from mode tables Date: Tue, 12 Apr 2022 08:55:30 -0500 Message-Id: <20220412135534.2796158-2-aford173@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220412135534.2796158-1-aford173@gmail.com> References: <20220412135534.2796158-1-aford173@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org There are four modes, and each mode has a table of registers. Some of the registers are common to all modes, so create new tables for these common registers to reduce duplicate code. Signed-off-by: Adam Ford --- drivers/media/i2c/imx219.c | 103 ++++++++++++++----------------------- 1 file changed, 39 insertions(+), 64 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index e10af3f74b38..b7cc36b16547 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -145,19 +145,36 @@ struct imx219_mode { struct imx219_reg_list reg_list; }; -/* - * Register sets lifted off the i2C interface from the Raspberry Pi firmware - * driver. - * 3280x2464 = mode 2, 1920x1080 = mode 1, 1640x1232 = mode 4, 640x480 = mode 7. - */ -static const struct imx219_reg mode_3280x2464_regs[] = { - {0x0100, 0x00}, +/* To Access Addresses 3000-5fff, send the following commands */ +static const struct imx219_reg mfg_specific_reg[] = { + {0x0100, 0x00}, /* Mode Select */ {0x30eb, 0x0c}, {0x30eb, 0x05}, {0x300a, 0xff}, {0x300b, 0xff}, {0x30eb, 0x05}, {0x30eb, 0x09}, +}; + +static const struct imx219_reg pll_clk_table[] = { + + {0x0301, 0x05}, /* VTPXCK_DIV */ + {0x0303, 0x01}, /* VTSYSCK_DIV */ + {0x0304, 0x03}, /* PREPLLCK_VT_DIV 0x03 = AUTO set */ + {0x0305, 0x03}, /* PREPLLCK_OP_DIV 0x03 = AUTO set */ + {0x0306, 0x00}, /* PLL_VT_MPY */ + {0x0307, 0x39}, + {0x030b, 0x01}, /* OP_SYS_CLK_DIV */ + {0x030c, 0x00}, /* PLL_OP_MPY */ + {0x030d, 0x72}, +}; + +/* + * Register sets lifted off the i2C interface from the Raspberry Pi firmware + * driver. + * 3280x2464 = mode 2, 1920x1080 = mode 1, 1640x1232 = mode 4, 640x480 = mode 7. + */ +static const struct imx219_reg mode_3280x2464_regs[] = { {0x0114, 0x01}, {0x0128, 0x00}, {0x012a, 0x18}, @@ -178,15 +195,6 @@ static const struct imx219_reg mode_3280x2464_regs[] = { {0x0171, 0x01}, {0x0174, 0x00}, {0x0175, 0x00}, - {0x0301, 0x05}, - {0x0303, 0x01}, - {0x0304, 0x03}, - {0x0305, 0x03}, - {0x0306, 0x00}, - {0x0307, 0x39}, - {0x030b, 0x01}, - {0x030c, 0x00}, - {0x030d, 0x72}, {0x0624, 0x0c}, {0x0625, 0xd0}, {0x0626, 0x09}, @@ -208,13 +216,6 @@ static const struct imx219_reg mode_3280x2464_regs[] = { }; static const struct imx219_reg mode_1920_1080_regs[] = { - {0x0100, 0x00}, - {0x30eb, 0x05}, - {0x30eb, 0x0c}, - {0x300a, 0xff}, - {0x300b, 0xff}, - {0x30eb, 0x05}, - {0x30eb, 0x09}, {0x0114, 0x01}, {0x0128, 0x00}, {0x012a, 0x18}, @@ -237,15 +238,6 @@ static const struct imx219_reg mode_1920_1080_regs[] = { {0x0171, 0x01}, {0x0174, 0x00}, {0x0175, 0x00}, - {0x0301, 0x05}, - {0x0303, 0x01}, - {0x0304, 0x03}, - {0x0305, 0x03}, - {0x0306, 0x00}, - {0x0307, 0x39}, - {0x030b, 0x01}, - {0x030c, 0x00}, - {0x030d, 0x72}, {0x0624, 0x07}, {0x0625, 0x80}, {0x0626, 0x04}, @@ -265,13 +257,6 @@ static const struct imx219_reg mode_1920_1080_regs[] = { }; static const struct imx219_reg mode_1640_1232_regs[] = { - {0x0100, 0x00}, - {0x30eb, 0x0c}, - {0x30eb, 0x05}, - {0x300a, 0xff}, - {0x300b, 0xff}, - {0x30eb, 0x05}, - {0x30eb, 0x09}, {0x0114, 0x01}, {0x0128, 0x00}, {0x012a, 0x18}, @@ -292,15 +277,6 @@ static const struct imx219_reg mode_1640_1232_regs[] = { {0x0171, 0x01}, {0x0174, 0x01}, {0x0175, 0x01}, - {0x0301, 0x05}, - {0x0303, 0x01}, - {0x0304, 0x03}, - {0x0305, 0x03}, - {0x0306, 0x00}, - {0x0307, 0x39}, - {0x030b, 0x01}, - {0x030c, 0x00}, - {0x030d, 0x72}, {0x0624, 0x06}, {0x0625, 0x68}, {0x0626, 0x04}, @@ -322,13 +298,6 @@ static const struct imx219_reg mode_1640_1232_regs[] = { }; static const struct imx219_reg mode_640_480_regs[] = { - {0x0100, 0x00}, - {0x30eb, 0x05}, - {0x30eb, 0x0c}, - {0x300a, 0xff}, - {0x300b, 0xff}, - {0x30eb, 0x05}, - {0x30eb, 0x09}, {0x0114, 0x01}, {0x0128, 0x00}, {0x012a, 0x18}, @@ -351,15 +320,6 @@ static const struct imx219_reg mode_640_480_regs[] = { {0x0171, 0x01}, {0x0174, 0x03}, {0x0175, 0x03}, - {0x0301, 0x05}, - {0x0303, 0x01}, - {0x0304, 0x03}, - {0x0305, 0x03}, - {0x0306, 0x00}, - {0x0307, 0x39}, - {0x030b, 0x01}, - {0x030c, 0x00}, - {0x030d, 0x72}, {0x0624, 0x06}, {0x0625, 0x68}, {0x0626, 0x04}, @@ -1041,6 +1001,13 @@ static int imx219_start_streaming(struct imx219 *imx219) if (ret < 0) return ret; + /* Send the Manufacturing Header common to all modes */ + ret = imx219_write_regs(imx219, mfg_specific_reg, ARRAY_SIZE(mfg_specific_reg)); + if (ret) { + dev_err(&client->dev, "%s failed to send mfg header\n", __func__); + goto err_rpm_put; + } + /* Apply default values of current mode */ reg_list = &imx219->mode->reg_list; ret = imx219_write_regs(imx219, reg_list->regs, reg_list->num_of_regs); @@ -1056,6 +1023,14 @@ static int imx219_start_streaming(struct imx219 *imx219) goto err_rpm_put; } + /* Configure the PLL clocks */ + ret = imx219_write_regs(imx219, pll_clk_table, ARRAY_SIZE(pll_clk_table)); + if (ret) { + dev_err(&client->dev, "%s failed to sent PLL clocks\n", __func__); + goto err_rpm_put; + } + + /* Apply customized values from user */ ret = __v4l2_ctrl_handler_setup(imx219->sd.ctrl_handler); if (ret) From patchwork Tue Apr 12 13:55:31 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adam Ford X-Patchwork-Id: 560131 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 752B6C433EF for ; Tue, 12 Apr 2022 13:56:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1356482AbiDLN6Q (ORCPT ); Tue, 12 Apr 2022 09:58:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:32998 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1356551AbiDLN6G (ORCPT ); Tue, 12 Apr 2022 09:58:06 -0400 Received: from mail-io1-xd36.google.com (mail-io1-xd36.google.com [IPv6:2607:f8b0:4864:20::d36]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 348145C363; Tue, 12 Apr 2022 06:55:48 -0700 (PDT) Received: by mail-io1-xd36.google.com with SMTP id 9so22359972iou.5; Tue, 12 Apr 2022 06:55:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Z8DeuU4bXc6zU0q+bgkdN6fbdKB+U/wdEnUo15LU1Nc=; b=QnlX9EilNA8BiDeOisYscb5ns5BE43Aq1VmpvLkYJqwkmonoaIUpo/5rSvKq3gkazK THXifA6e77zCxsPBbrzgptTmWWAhWYmCCabRqYuNscENpjM36Q7vjuttvpLWhTFYQFbG fY/kQrDGcsIFt+JOwhF7X0Dre/8jQ/tB6eQkGsQIkEXDr0X+vHnGa+zQnOBG1RGjNbI8 GvdmmedIegLhHyqImOrqi7cBx8th3R2L2cypPFKpoHJd0btz1qAfwylQsWAveGjRmOWw /Wk26FP5sWy0R5OrbYX5uZQ1qdIbQZniRP5O4NsWGIsjwnH7XdbOSj5FbKS23WFpnqIk vR8g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Z8DeuU4bXc6zU0q+bgkdN6fbdKB+U/wdEnUo15LU1Nc=; b=naHccf6H+hIA4QTlAzkcaW623nQ93krFrdj30ilXU9pxujOeZ6pAPeRerpN1vWTYkv UBHGBTtgbZ40O161aCCPSW6dAKMXVG1HqYpzbsXXfEW3FDLqCjsPn2PfJr1r39ctVKI4 8ghd8i4SHbJaWbTtzI6ww+yKmWjabnH6ybqJpz3KoUEM/0gaFfklx8NUK+E716l+cp3H TjBskUadoX0RsLFaJEPDfJjhFXHKv4n7ImskjOxcEot7qkFAUfiSUomBLPQsf8DWYuvT lvQ8kTe0dEJ+NpAdbjs7hgCzhlY4DxqYeEh/xeWC6vYjw6QNRXmREKdunhDqwsaS6PXn YXrg== X-Gm-Message-State: AOAM531vqZZ/UXukMGxpRtf6QMPr+qDovqQhpMKLID32sR2kGiHW0y6/ n4X+vqc1gboxSHjzxsVMdHaFE+lEBm+57g== X-Google-Smtp-Source: ABdhPJw4jLdO5Vlakce9yzwJiCHyVez7b4GNZPVyrDslqPWh+rn6M0zcpKSTD6XI/2kkDlZNbWbKVA== X-Received: by 2002:a05:6638:1301:b0:323:3b47:8b3f with SMTP id r1-20020a056638130100b003233b478b3fmr18100042jad.291.1649771747175; Tue, 12 Apr 2022 06:55:47 -0700 (PDT) Received: from aford-IdeaCentre-A730.lan ([2601:448:8400:9e8:2611:a7ae:f1c9:5ec2]) by smtp.gmail.com with ESMTPSA id n12-20020a92dd0c000000b002cac22690b6sm2280748ilm.0.2022.04.12.06.55.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 12 Apr 2022 06:55:46 -0700 (PDT) From: Adam Ford To: linux-media@vger.kernel.org Cc: prabhakar.mahadev-lad.rj@bp.renesas.com, tharvey@gateworks.com, cstevens@beaconembedded.com, aford@beaconembedded.com, laurent.pinchart@ideasonboard.com, Adam Ford , Dave Stevenson , Mauro Carvalho Chehab , linux-kernel@vger.kernel.org Subject: [PATCH 2/4] media: i2c: imx219: Support four-lane operation Date: Tue, 12 Apr 2022 08:55:31 -0500 Message-Id: <20220412135534.2796158-3-aford173@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220412135534.2796158-1-aford173@gmail.com> References: <20220412135534.2796158-1-aford173@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org The imx219 camera is capable of either two-lane or four-lane operation. When operating in four-lane, both the pixel rate and link frequency change. Regardless of the mode, however, both frequencies remain fixed. Helper functions are needed to read and set pixel and link frequencies which also reduces the number of fixed registers in the table of modes. Since the link frequency and number of lanes is extracted from the endpoint, move the endpoint handling into the probe function and out of the imx219_check_hwcfg. This simplifies the imx219_check_hwcfg just a bit, and places all the parameters into the imx219 structure. It then allows imx219_check_hwcfg to simply validate the settings. Signed-off-by: Adam Ford --- drivers/media/i2c/imx219.c | 144 ++++++++++++++++++++++++------------- 1 file changed, 96 insertions(+), 48 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index b7cc36b16547..d13ce5c1ece6 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -42,10 +42,16 @@ /* External clock frequency is 24.0M */ #define IMX219_XCLK_FREQ 24000000 -/* Pixel rate is fixed at 182.4M for all the modes */ +/* Pixel rate is fixed for all the modes */ #define IMX219_PIXEL_RATE 182400000 +#define IMX219_PIXEL_RATE_4LANE 280800000 #define IMX219_DEFAULT_LINK_FREQ 456000000 +#define IMX219_DEFAULT_LINK_FREQ_4LANE 702000000 + +#define IMX219_REG_CSI_LANE_MODE 0x0114 +#define IMX219_CSI_2_LANE_MODE 0x01 +#define IMX219_CSI_4_LANE_MODE 0x03 /* V_TIMING internal */ #define IMX219_REG_VTS 0x0160 @@ -175,7 +181,6 @@ static const struct imx219_reg pll_clk_table[] = { * 3280x2464 = mode 2, 1920x1080 = mode 1, 1640x1232 = mode 4, 640x480 = mode 7. */ static const struct imx219_reg mode_3280x2464_regs[] = { - {0x0114, 0x01}, {0x0128, 0x00}, {0x012a, 0x18}, {0x012b, 0x00}, @@ -216,7 +221,6 @@ static const struct imx219_reg mode_3280x2464_regs[] = { }; static const struct imx219_reg mode_1920_1080_regs[] = { - {0x0114, 0x01}, {0x0128, 0x00}, {0x012a, 0x18}, {0x012b, 0x00}, @@ -257,7 +261,6 @@ static const struct imx219_reg mode_1920_1080_regs[] = { }; static const struct imx219_reg mode_1640_1232_regs[] = { - {0x0114, 0x01}, {0x0128, 0x00}, {0x012a, 0x18}, {0x012b, 0x00}, @@ -298,7 +301,6 @@ static const struct imx219_reg mode_1640_1232_regs[] = { }; static const struct imx219_reg mode_640_480_regs[] = { - {0x0114, 0x01}, {0x0128, 0x00}, {0x012a, 0x18}, {0x012b, 0x00}, @@ -352,6 +354,7 @@ static const struct imx219_reg raw10_framefmt_regs[] = { static const s64 imx219_link_freq_menu[] = { IMX219_DEFAULT_LINK_FREQ, + IMX219_DEFAULT_LINK_FREQ_4LANE, }; static const char * const imx219_test_pattern_menu[] = { @@ -529,6 +532,13 @@ struct imx219 { /* Streaming on/off */ bool streaming; + + /* Two or Four lanes */ + u8 lanes; + + /* Link Frequency info */ + unsigned int nr_of_link_frequencies; + u64 link_frequency; }; static inline struct imx219 *to_imx219(struct v4l2_subdev *_sd) @@ -991,6 +1001,20 @@ static int imx219_get_selection(struct v4l2_subdev *sd, return -EINVAL; } +static int imx219_configure_lanes(struct imx219 *imx219) +{ + int ret; + + /* imx219->lanes has already been validated to be either 2 or 4 */ + if (imx219->lanes == 2) + ret = imx219_write_reg(imx219, IMX219_REG_CSI_LANE_MODE, + IMX219_REG_VALUE_08BIT, IMX219_CSI_2_LANE_MODE); + else + ret = imx219_write_reg(imx219, IMX219_REG_CSI_LANE_MODE, + IMX219_REG_VALUE_08BIT, IMX219_CSI_4_LANE_MODE); + return ret; +}; + static int imx219_start_streaming(struct imx219 *imx219) { struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); @@ -1008,6 +1032,13 @@ static int imx219_start_streaming(struct imx219 *imx219) goto err_rpm_put; } + /* Configure two or four Lane mode */ + ret = imx219_configure_lanes(imx219); + if (ret) { + dev_err(&client->dev, "%s failed to configure lanes\n", __func__); + goto err_rpm_put; + } + /* Apply default values of current mode */ reg_list = &imx219->mode->reg_list; ret = imx219_write_regs(imx219, reg_list->regs, reg_list->num_of_regs); @@ -1247,6 +1278,14 @@ static const struct v4l2_subdev_internal_ops imx219_internal_ops = { .open = imx219_open, }; +static unsigned long imx219_get_pixel_rate(struct imx219 *imx219) +{ + if (imx219->lanes == 2) + return IMX219_PIXEL_RATE; + else + return IMX219_PIXEL_RATE_4LANE; +} + /* Initialize control handlers */ static int imx219_init_controls(struct imx219 *imx219) { @@ -1268,14 +1307,15 @@ static int imx219_init_controls(struct imx219 *imx219) /* By default, PIXEL_RATE is read only */ imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_PIXEL_RATE, - IMX219_PIXEL_RATE, - IMX219_PIXEL_RATE, 1, - IMX219_PIXEL_RATE); + imx219_get_pixel_rate(imx219), + imx219_get_pixel_rate(imx219), 1, + imx219_get_pixel_rate(imx219)); imx219->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_LINK_FREQ, - ARRAY_SIZE(imx219_link_freq_menu) - 1, 0, + ARRAY_SIZE(imx219_link_freq_menu) - 1, + (imx219->lanes == 4), imx219_link_freq_menu); if (imx219->link_freq) imx219->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; @@ -1371,67 +1411,75 @@ static void imx219_free_controls(struct imx219 *imx219) mutex_destroy(&imx219->mutex); } -static int imx219_check_hwcfg(struct device *dev) +static int imx219_check_hwcfg(struct imx219 *imx219) { - struct fwnode_handle *endpoint; + struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); + + /* Check the number of MIPI CSI2 data lanes */ + if (imx219->lanes != 2 && imx219->lanes != 4) { + dev_err(&client->dev, "only 2 or 4 data lanes are currently supported\n"); + return -EINVAL; + } + + if (imx219->link_frequency != IMX219_DEFAULT_LINK_FREQ && + imx219->link_frequency != IMX219_DEFAULT_LINK_FREQ_4LANE) { + dev_err(&client->dev, "Link frequency not supported: %lld\n", + imx219->link_frequency); + return -EINVAL; + } + + return 0; +} + +static int imx219_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct imx219 *imx219; struct v4l2_fwnode_endpoint ep_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; - int ret = -EINVAL; + struct fwnode_handle *endpoint; + int ret = 0; + + imx219 = devm_kzalloc(&client->dev, sizeof(*imx219), GFP_KERNEL); + if (!imx219) + return -ENOMEM; + v4l2_i2c_subdev_init(&imx219->sd, client, &imx219_subdev_ops); + + /* Fetch the endpoint to extract lanes and link-frequency */ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); if (!endpoint) { dev_err(dev, "endpoint node not found\n"); - return -EINVAL; + ret = -EINVAL; + goto fwnode_cleanup; } if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) { dev_err(dev, "could not parse endpoint\n"); - goto error_out; + ret = -EINVAL; + goto fwnode_cleanup; } - /* Check the number of MIPI CSI2 data lanes */ - if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2) { - dev_err(dev, "only 2 data lanes are currently supported\n"); - goto error_out; - } + imx219->lanes = ep_cfg.bus.mipi_csi2.num_data_lanes; + imx219->nr_of_link_frequencies = ep_cfg.nr_of_link_frequencies; - /* Check the link frequency set in device tree */ - if (!ep_cfg.nr_of_link_frequencies) { + if (imx219->nr_of_link_frequencies != 1) { dev_err(dev, "link-frequency property not found in DT\n"); - goto error_out; - } - - if (ep_cfg.nr_of_link_frequencies != 1 || - ep_cfg.link_frequencies[0] != IMX219_DEFAULT_LINK_FREQ) { - dev_err(dev, "Link frequency not supported: %lld\n", - ep_cfg.link_frequencies[0]); - goto error_out; + ret = -EINVAL; + goto fwnode_cleanup; } + imx219->link_frequency = ep_cfg.link_frequencies[0]; - ret = 0; - -error_out: + /* Cleanup endpoint and handle any errors from above */ +fwnode_cleanup: v4l2_fwnode_endpoint_free(&ep_cfg); fwnode_handle_put(endpoint); - - return ret; -} - -static int imx219_probe(struct i2c_client *client) -{ - struct device *dev = &client->dev; - struct imx219 *imx219; - int ret; - - imx219 = devm_kzalloc(&client->dev, sizeof(*imx219), GFP_KERNEL); - if (!imx219) - return -ENOMEM; - - v4l2_i2c_subdev_init(&imx219->sd, client, &imx219_subdev_ops); + if (ret) + return ret; /* Check the hardware configuration in device tree */ - if (imx219_check_hwcfg(dev)) + if (imx219_check_hwcfg(imx219)) return -EINVAL; /* Get system clock (xclk) */ From patchwork Tue Apr 12 13:55:32 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adam Ford X-Patchwork-Id: 560130 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EBC0CC433FE for ; Tue, 12 Apr 2022 13:56:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1356601AbiDLN6S (ORCPT ); Tue, 12 Apr 2022 09:58:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33102 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1356561AbiDLN6H (ORCPT ); Tue, 12 Apr 2022 09:58:07 -0400 Received: from mail-io1-xd33.google.com (mail-io1-xd33.google.com [IPv6:2607:f8b0:4864:20::d33]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E7EF2F51; Tue, 12 Apr 2022 06:55:49 -0700 (PDT) Received: by mail-io1-xd33.google.com with SMTP id e22so22309930ioe.11; Tue, 12 Apr 2022 06:55:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=dsEjLgvTaSnJWB0qaHEaU7KaeVze6U1DoRRKehYbw4I=; b=EpCGAJdbnJSAP3mcFMIgp0gM/CzioJACPjZshjTi4vmru4ciSmQtESmIdyJkH1RxBL WXyJ0dvOzc69IinOb/3/LpEnG8zbYWceeKDcGuOReh4XqXf2OKIQBPJkV+ltT/qfC+qK qFswdp+pBK9043p7hCsGclNSm7zsVgkaywgH72qCBkSPeYDRSPFojSJlVq375DQkgRse cCrcS6TEEAFqLwf9828xlRtHylk/LbIavVWh9qgQLNpuijau9hqsmkWiFM5uoivqM9H3 rGNvklr+5Wc2Rz0zlwUXRmpP+qTGGLD0S9tYvb2btfJ58qYXH+Ot7gy7Z//vQ8jR9GIj uNZA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=dsEjLgvTaSnJWB0qaHEaU7KaeVze6U1DoRRKehYbw4I=; b=JQGcnEQmGAwDp4+7zK6yj7OrTSXg+Qv0IjjGja21WgZ38iAwBDFuEihBitO2ha0OsB 6TV3zvbIoUP6HtSMsbTyrBfL3Taz3K4gxMddNoI7ujtIV1u+UPwhiFDRnT84Ii0vy+0D Nx09pVw4H1StXGieI7qU0Mv/UkMikk0PRVwJAOWt4EzYOjQR+EWNbofeyDfbsFGBQZNC zV2ewRq/47eVbxDbYP5G3QGq4ZOeTO+4GCcqMg2qoDIBCx7WxYnJ8G0WPoiP7MV9JTqv d967ShAydb/qpXdX3jQgO0H67AIeb7zwIVqqsio7QM8nh2WGOqyk24Q2ay5Q3mEtk0EE E7Xw== X-Gm-Message-State: AOAM532+nuY3gB9CBuM60yd19WZvcLjPTtfoAWgptI8OqVw8kSUvmRz/ kmog0yyLQQq+VKMfXompT6pthkP8/zWczw== X-Google-Smtp-Source: ABdhPJzQiDj980Uywa9g5DatCrWtmN2Guk7U5Sn5Ec5jtD1hNewqjrmQ8R1mSKrXK1dbyH3o9GQgrg== X-Received: by 2002:a05:6638:22c5:b0:326:2b3a:b08b with SMTP id j5-20020a05663822c500b003262b3ab08bmr6534540jat.250.1649771748824; Tue, 12 Apr 2022 06:55:48 -0700 (PDT) Received: from aford-IdeaCentre-A730.lan ([2601:448:8400:9e8:2611:a7ae:f1c9:5ec2]) by smtp.gmail.com with ESMTPSA id n12-20020a92dd0c000000b002cac22690b6sm2280748ilm.0.2022.04.12.06.55.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 12 Apr 2022 06:55:48 -0700 (PDT) From: Adam Ford To: linux-media@vger.kernel.org Cc: prabhakar.mahadev-lad.rj@bp.renesas.com, tharvey@gateworks.com, cstevens@beaconembedded.com, aford@beaconembedded.com, laurent.pinchart@ideasonboard.com, Adam Ford , Dave Stevenson , Mauro Carvalho Chehab , linux-kernel@vger.kernel.org Subject: [PATCH 3/4] media: i2c: imx219: Enable variable XCLK Date: Tue, 12 Apr 2022 08:55:32 -0500 Message-Id: <20220412135534.2796158-4-aford173@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220412135534.2796158-1-aford173@gmail.com> References: <20220412135534.2796158-1-aford173@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org The datasheet shows the external clock can be anything from 6MHz to 27MHz, but EXCK, PREPLLCK_VT_DIV and PREPLLCK_OP_DIV need to change based on the clock, so create helper functions to set these registers based on the rate of xclk. Move the validation of the clock rate into imx219_check_hwcfg which means delaying the call to it until after xclk has been determined. Signed-off-by: Adam Ford --- drivers/media/i2c/imx219.c | 79 ++++++++++++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 16 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index d13ce5c1ece6..08e7d0e72430 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -39,8 +39,12 @@ #define IMX219_REG_CHIP_ID 0x0000 #define IMX219_CHIP_ID 0x0219 -/* External clock frequency is 24.0M */ -#define IMX219_XCLK_FREQ 24000000 +/* Default external clock frequency is 24.0M */ +#define IMX219_XCLK_MIN_FREQ 6000000 +#define IMX219_XCLK_MAX_FREQ 27000000 +#define IMX219_REG_EXCK 0x012a +#define IMX219_REG_PREPLLCK_VT_DIV 0x0304 +#define IMX219_REG_PREPLLCK_OP_DIV 0x0305 /* Pixel rate is fixed for all the modes */ #define IMX219_PIXEL_RATE 182400000 @@ -166,8 +170,6 @@ static const struct imx219_reg pll_clk_table[] = { {0x0301, 0x05}, /* VTPXCK_DIV */ {0x0303, 0x01}, /* VTSYSCK_DIV */ - {0x0304, 0x03}, /* PREPLLCK_VT_DIV 0x03 = AUTO set */ - {0x0305, 0x03}, /* PREPLLCK_OP_DIV 0x03 = AUTO set */ {0x0306, 0x00}, /* PLL_VT_MPY */ {0x0307, 0x39}, {0x030b, 0x01}, /* OP_SYS_CLK_DIV */ @@ -182,7 +184,6 @@ static const struct imx219_reg pll_clk_table[] = { */ static const struct imx219_reg mode_3280x2464_regs[] = { {0x0128, 0x00}, - {0x012a, 0x18}, {0x012b, 0x00}, {0x0164, 0x00}, {0x0165, 0x00}, @@ -222,7 +223,6 @@ static const struct imx219_reg mode_3280x2464_regs[] = { static const struct imx219_reg mode_1920_1080_regs[] = { {0x0128, 0x00}, - {0x012a, 0x18}, {0x012b, 0x00}, {0x0162, 0x0d}, {0x0163, 0x78}, @@ -262,7 +262,6 @@ static const struct imx219_reg mode_1920_1080_regs[] = { static const struct imx219_reg mode_1640_1232_regs[] = { {0x0128, 0x00}, - {0x012a, 0x18}, {0x012b, 0x00}, {0x0164, 0x00}, {0x0165, 0x00}, @@ -302,7 +301,6 @@ static const struct imx219_reg mode_1640_1232_regs[] = { static const struct imx219_reg mode_640_480_regs[] = { {0x0128, 0x00}, - {0x012a, 0x18}, {0x012b, 0x00}, {0x0162, 0x0d}, {0x0163, 0x78}, @@ -1015,6 +1013,50 @@ static int imx219_configure_lanes(struct imx219 *imx219) return ret; }; +static int imx219_set_exck_freq(struct imx219 *imx219) +{ + int ret; + /* The imx219 registers need MHz not Hz */ + u8 clk = (u8) (imx219->xclk_freq/1000000U); + + /* Set the clock frequency in MHz */ + ret = imx219_write_reg(imx219, IMX219_REG_EXCK, + IMX219_REG_VALUE_08BIT, clk); + + /* Configure the PREPLLCK_VT_DIV and PREPLLCK_OP_DIV for automatic */ + switch (clk) { + case 6 ... 11: + ret = imx219_write_reg(imx219, IMX219_REG_PREPLLCK_VT_DIV, + IMX219_REG_VALUE_08BIT, 0x01); + if (ret) + return ret; + ret = imx219_write_reg(imx219, IMX219_REG_PREPLLCK_OP_DIV, + IMX219_REG_VALUE_08BIT, 0x01); + return ret; + case 12 ... 23: + ret = imx219_write_reg(imx219, IMX219_REG_PREPLLCK_VT_DIV, + IMX219_REG_VALUE_08BIT, 0x02); + if (ret) + return ret; + + ret = imx219_write_reg(imx219, IMX219_REG_PREPLLCK_OP_DIV, + IMX219_REG_VALUE_08BIT, 0x02); + + return ret; + case 24 ... 27: + ret = imx219_write_reg(imx219, IMX219_REG_PREPLLCK_VT_DIV, + IMX219_REG_VALUE_08BIT, 0x03); + if (ret) + return ret; + ret = imx219_write_reg(imx219, IMX219_REG_PREPLLCK_OP_DIV, + IMX219_REG_VALUE_08BIT, 0x03); + return ret; + default: + /* Should never get here */ + return -EINVAL; + } +} + static int imx219_start_streaming(struct imx219 *imx219) { struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); @@ -1039,6 +1081,9 @@ static int imx219_start_streaming(struct imx219 *imx219) goto err_rpm_put; } + /* Configure clock based on reference clock frequency */ + imx219_set_exck_freq(imx219); + /* Apply default values of current mode */ reg_list = &imx219->mode->reg_list; ret = imx219_write_regs(imx219, reg_list->regs, reg_list->num_of_regs); @@ -1428,6 +1473,13 @@ static int imx219_check_hwcfg(struct imx219 *imx219) return -EINVAL; } + if ((imx219->xclk_freq < IMX219_XCLK_MIN_FREQ) || + imx219->xclk_freq > IMX219_XCLK_MAX_FREQ) { + dev_err(&client->dev, "xclk frequency not supported: %d Hz\n", + imx219->xclk_freq); + return -EINVAL; + } + return 0; } @@ -1478,10 +1530,6 @@ static int imx219_probe(struct i2c_client *client) if (ret) return ret; - /* Check the hardware configuration in device tree */ - if (imx219_check_hwcfg(imx219)) - return -EINVAL; - /* Get system clock (xclk) */ imx219->xclk = devm_clk_get(dev, NULL); if (IS_ERR(imx219->xclk)) { @@ -1490,11 +1538,10 @@ static int imx219_probe(struct i2c_client *client) } imx219->xclk_freq = clk_get_rate(imx219->xclk); - if (imx219->xclk_freq != IMX219_XCLK_FREQ) { - dev_err(dev, "xclk frequency not supported: %d Hz\n", - imx219->xclk_freq); + + /* Check the hardware configuration in device tree */ + if (imx219_check_hwcfg(imx219)) return -EINVAL; - } ret = imx219_get_regulators(imx219); if (ret) {