From patchwork Tue Aug 17 07:26:59 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 12440619 X-Patchwork-Delegate: kieran@bingham.xyz Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A0E71C43214 for ; Tue, 17 Aug 2021 07:34:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8622B60F5C for ; Tue, 17 Aug 2021 07:34:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234643AbhHQHf0 (ORCPT ); Tue, 17 Aug 2021 03:35:26 -0400 Received: from mslow1.mail.gandi.net ([217.70.178.240]:54983 "EHLO mslow1.mail.gandi.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234596AbhHQHfY (ORCPT ); Tue, 17 Aug 2021 03:35:24 -0400 Received: from relay9-d.mail.gandi.net (unknown [217.70.183.199]) by mslow1.mail.gandi.net (Postfix) with ESMTP id 21F21CD82F for ; Tue, 17 Aug 2021 07:26:50 +0000 (UTC) Received: (Authenticated sender: jacopo@jmondi.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 54EC9FF80B; Tue, 17 Aug 2021 07:26:26 +0000 (UTC) From: Jacopo Mondi To: Mauro Carvalho Chehab , Kieran Bingham , Laurent Pinchart , =?utf-8?q?Nik?= =?utf-8?q?las_S=C3=B6derlund?= Cc: Jacopo Mondi , Hans Verkuil , Sakari Ailus , Manivannan Sadhasivam , Thomas NIZAN , linux-renesas-soc@vger.kernel.org, linux-media@vger.kernel.org Subject: [RFC 1/5] media: i2c: max9271: Rename max9271 library driver Date: Tue, 17 Aug 2021 09:26:59 +0200 Message-Id: <20210817072703.1167-2-jacopo+renesas@jmondi.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210817072703.1167-1-jacopo+renesas@jmondi.org> References: <20210817072703.1167-1-jacopo+renesas@jmondi.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-renesas-soc@vger.kernel.org Support for the MAX9271 GMSL serializer was provided in the form of a library driver, with the RDACM20 and RDACM21 camera module drivers using the functions exported by the library. In preparation to introduce an i2c subdevice driver to support the MAX9271 serializer, rename the library driver from max9271 to max9271-lib. Signed-off-by: Jacopo Mondi Reviewed-by: Kieran Bingham Reviewed-by: Laurent Pinchart --- MAINTAINERS | 8 ++++---- drivers/media/i2c/Makefile | 2 +- drivers/media/i2c/{max9271.c => max9271-lib.c} | 2 +- drivers/media/i2c/{max9271.h => max9271-lib.h} | 0 drivers/media/i2c/rdacm20.c | 2 +- drivers/media/i2c/rdacm21.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) rename drivers/media/i2c/{max9271.c => max9271-lib.c} (99%) rename drivers/media/i2c/{max9271.h => max9271-lib.h} (100%) diff --git a/MAINTAINERS b/MAINTAINERS index 524eabe50d79..7ad89cac19b7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15625,8 +15625,8 @@ M: Niklas Söderlund L: linux-media@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/media/i2c/imi,rdacm2x-gmsl.yaml -F: drivers/media/i2c/max9271.c -F: drivers/media/i2c/max9271.h +F: drivers/media/i2c/max9271-lib.c +F: drivers/media/i2c/max9271-lib.h F: drivers/media/i2c/rdacm20.c RDACM21 Camera Sensor @@ -15637,8 +15637,8 @@ M: Niklas Söderlund L: linux-media@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/media/i2c/imi,rdacm2x-gmsl.yaml -F: drivers/media/i2c/max9271.c -F: drivers/media/i2c/max9271.h +F: drivers/media/i2c/max9271-lib.c +F: drivers/media/i2c/max9271-lib.h F: drivers/media/i2c/rdacm21.c RDC R-321X SoC diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 83268f20aa3a..4d879373bd48 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -129,7 +129,7 @@ obj-$(CONFIG_VIDEO_IMX335) += imx335.o obj-$(CONFIG_VIDEO_IMX355) += imx355.o obj-$(CONFIG_VIDEO_IMX412) += imx412.o obj-$(CONFIG_VIDEO_MAX9286) += max9286.o -obj-$(CONFIG_VIDEO_MAX9271_LIB) += max9271.o +obj-$(CONFIG_VIDEO_MAX9271_LIB) += max9271-lib.o obj-$(CONFIG_VIDEO_RDACM20) += rdacm20.o obj-$(CONFIG_VIDEO_RDACM21) += rdacm21.o obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o diff --git a/drivers/media/i2c/max9271.c b/drivers/media/i2c/max9271-lib.c similarity index 99% rename from drivers/media/i2c/max9271.c rename to drivers/media/i2c/max9271-lib.c index ff86c8c4ea61..c554bb0f42f4 100644 --- a/drivers/media/i2c/max9271.c +++ b/drivers/media/i2c/max9271-lib.c @@ -20,7 +20,7 @@ #include #include -#include "max9271.h" +#include "max9271-lib.h" static int max9271_read(struct max9271_device *dev, u8 reg) { diff --git a/drivers/media/i2c/max9271.h b/drivers/media/i2c/max9271-lib.h similarity index 100% rename from drivers/media/i2c/max9271.h rename to drivers/media/i2c/max9271-lib.h diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c index eb0e3dc22cc3..bf06a1c50306 100644 --- a/drivers/media/i2c/rdacm20.c +++ b/drivers/media/i2c/rdacm20.c @@ -27,7 +27,7 @@ #include #include -#include "max9271.h" +#include "max9271-lib.h" #define OV10635_I2C_ADDRESS 0x30 diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c index 35217782f693..3a05abe4e96c 100644 --- a/drivers/media/i2c/rdacm21.c +++ b/drivers/media/i2c/rdacm21.c @@ -21,7 +21,7 @@ #include #include #include -#include "max9271.h" +#include "max9271-lib.h" #define MAX9271_RESET_CYCLES 10 From patchwork Tue Aug 17 07:27:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 12440625 X-Patchwork-Delegate: kieran@bingham.xyz Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 321D1C4320E for ; Tue, 17 Aug 2021 07:34:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1498F60C3E for ; Tue, 17 Aug 2021 07:34:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234402AbhHQHf0 (ORCPT ); Tue, 17 Aug 2021 03:35:26 -0400 Received: from mslow1.mail.gandi.net ([217.70.178.240]:48541 "EHLO mslow1.mail.gandi.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234643AbhHQHfY (ORCPT ); Tue, 17 Aug 2021 03:35:24 -0400 Received: from relay9-d.mail.gandi.net (unknown [217.70.183.199]) by mslow1.mail.gandi.net (Postfix) with ESMTP id C8F34CD84B for ; Tue, 17 Aug 2021 07:26:52 +0000 (UTC) Received: (Authenticated sender: jacopo@jmondi.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id BE696FF804; Tue, 17 Aug 2021 07:26:28 +0000 (UTC) From: Jacopo Mondi To: Mauro Carvalho Chehab , Kieran Bingham , Laurent Pinchart , =?utf-8?q?Nik?= =?utf-8?q?las_S=C3=B6derlund?= Cc: Jacopo Mondi , Hans Verkuil , Sakari Ailus , Manivannan Sadhasivam , Thomas NIZAN , linux-renesas-soc@vger.kernel.org, linux-media@vger.kernel.org Subject: [RFC 2/5] media: i2c: Add MAX9271 I2C driver Date: Tue, 17 Aug 2021 09:27:00 +0200 Message-Id: <20210817072703.1167-3-jacopo+renesas@jmondi.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210817072703.1167-1-jacopo+renesas@jmondi.org> References: <20210817072703.1167-1-jacopo+renesas@jmondi.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-renesas-soc@vger.kernel.org The MAX9271 is a GMSL serializer that serializes a video stream received from an image sensor through the parallel video bus. The serializer it's usually found embedded with an image sensor and other ancillary chips in camera modules like RDACM20 and RDACM21. Signed-off-by: Jacopo Mondi --- MAINTAINERS | 9 + drivers/media/i2c/Kconfig | 12 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/max9271.c | 756 ++++++++++++++++++++++++++++++++++++ 4 files changed, 778 insertions(+) create mode 100644 drivers/media/i2c/max9271.c diff --git a/MAINTAINERS b/MAINTAINERS index 7ad89cac19b7..2dab25a08c9c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11244,6 +11244,15 @@ F: Documentation/hwmon/max6697.rst F: drivers/hwmon/max6697.c F: include/linux/platform_data/max6697.h +MAX9271 GMSL SERIALIZER DRIVER +M: Jacopo Mondi +M: Kieran Bingham +M: Laurent Pinchart +M: Niklas Söderlund +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/media/i2c/max9271.c + MAX9286 QUAD GMSL DESERIALIZER DRIVER M: Jacopo Mondi M: Kieran Bingham diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 08feb3e8c1bf..b793d1f322d9 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -1300,6 +1300,18 @@ source "drivers/media/i2c/m5mols/Kconfig" config VIDEO_MAX9271_LIB tristate +config VIDEO_MAX9271 + tristate "MAX9271 GMSL serializer support" + depends on I2C + select V4L2_FWNODE + select VIDEO_V4L2_SUBDEV_API + select MEDIA_CONTROLLER + help + This driver supports the Maxim MAX9271 GMSL serializer. + + To compile this driver as a module, choose M here: the + module will be called max9271. + config VIDEO_RDACM20 tristate "IMI RDACM20 camera support" depends on I2C diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 4d879373bd48..37bb51065574 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -130,6 +130,7 @@ obj-$(CONFIG_VIDEO_IMX355) += imx355.o obj-$(CONFIG_VIDEO_IMX412) += imx412.o obj-$(CONFIG_VIDEO_MAX9286) += max9286.o obj-$(CONFIG_VIDEO_MAX9271_LIB) += max9271-lib.o +obj-$(CONFIG_VIDEO_MAX9271) += max9271.o obj-$(CONFIG_VIDEO_RDACM20) += rdacm20.o obj-$(CONFIG_VIDEO_RDACM21) += rdacm21.o obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o diff --git a/drivers/media/i2c/max9271.c b/drivers/media/i2c/max9271.c new file mode 100644 index 000000000000..64987cba3d3e --- /dev/null +++ b/drivers/media/i2c/max9271.c @@ -0,0 +1,756 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2017-2021 Jacopo Mondi + * Copyright (C) 2017-2020 Kieran Bingham + * Copyright (C) 2017-2019 Laurent Pinchart + * Copyright (C) 2017-2019 Niklas Söderlund + * Copyright (C) 2016 Renesas Electronics Corporation + * Copyright (C) 2015 Cogent Embedded, Inc. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MAX9271_DEFAULT_ADDR 0x40 + +/* Register 0x02 */ +#define MAX9271_SPREAD_SPECT_0 (0 << 5) +#define MAX9271_SPREAD_SPECT_05 (1 << 5) +#define MAX9271_SPREAD_SPECT_15 (2 << 5) +#define MAX9271_SPREAD_SPECT_1 (5 << 5) +#define MAX9271_SPREAD_SPECT_2 (3 << 5) +#define MAX9271_SPREAD_SPECT_3 (6 << 5) +#define MAX9271_SPREAD_SPECT_4 (7 << 5) +#define MAX9271_R02_RES BIT(4) +#define MAX9271_PCLK_AUTODETECT (3 << 2) +#define MAX9271_SERIAL_AUTODETECT (0x03) +/* Register 0x04 */ +#define MAX9271_SEREN BIT(7) +#define MAX9271_CLINKEN BIT(6) +#define MAX9271_PRBSEN BIT(5) +#define MAX9271_SLEEP BIT(4) +#define MAX9271_INTTYPE_I2C (0 << 2) +#define MAX9271_INTTYPE_UART (1 << 2) +#define MAX9271_INTTYPE_NONE (2 << 2) +#define MAX9271_REVCCEN BIT(1) +#define MAX9271_FWDCCEN BIT(0) +/* Register 0x07 */ +#define MAX9271_DBL BIT(7) +#define MAX9271_DRS BIT(6) +#define MAX9271_BWS BIT(5) +#define MAX9271_ES BIT(4) +#define MAX9271_HVEN BIT(2) +#define MAX9271_EDC_1BIT_PARITY (0 << 0) +#define MAX9271_EDC_6BIT_CRC (1 << 0) +#define MAX9271_EDC_6BIT_HAMMING (2 << 0) +/* Register 0x08 */ +#define MAX9271_INVVS BIT(7) +#define MAX9271_INVHS BIT(6) +#define MAX9271_REV_LOGAIN BIT(3) +#define MAX9271_REV_HIVTH BIT(0) +/* Register 0x09 */ +#define MAX9271_ID 0x09 +/* Register 0x0d */ +#define MAX9271_I2CLOCACK BIT(7) +#define MAX9271_I2CSLVSH_1046NS_469NS (3 << 5) +#define MAX9271_I2CSLVSH_938NS_352NS (2 << 5) +#define MAX9271_I2CSLVSH_469NS_234NS (1 << 5) +#define MAX9271_I2CSLVSH_352NS_117NS (0 << 5) +#define MAX9271_I2CMSTBT_837KBPS (7 << 2) +#define MAX9271_I2CMSTBT_533KBPS (6 << 2) +#define MAX9271_I2CMSTBT_339KBPS (5 << 2) +#define MAX9271_I2CMSTBT_173KBPS (4 << 2) +#define MAX9271_I2CMSTBT_105KBPS (3 << 2) +#define MAX9271_I2CMSTBT_84KBPS (2 << 2) +#define MAX9271_I2CMSTBT_28KBPS (1 << 2) +#define MAX9271_I2CMSTBT_8KBPS (0 << 2) +#define MAX9271_I2CSLVTO_NONE (3 << 0) +#define MAX9271_I2CSLVTO_1024US (2 << 0) +#define MAX9271_I2CSLVTO_256US (1 << 0) +#define MAX9271_I2CSLVTO_64US (0 << 0) +/* Register 0x0f */ +#define MAX9271_GPIO5OUT BIT(5) +#define MAX9271_GPIO4OUT BIT(4) +#define MAX9271_GPIO3OUT BIT(3) +#define MAX9271_GPIO2OUT BIT(2) +#define MAX9271_GPIO1OUT BIT(1) +#define MAX9271_GPO BIT(0) +/* Register 0x15 */ +#define MAX9271_PCLKDET BIT(0) + +struct max9271_device { + struct device *dev; + struct i2c_client *client; + struct v4l2_subdev sd; +#define MAX9271_SOURCE_PAD 0 +#define MAX9271_SINK_PAD 1 + struct media_pad pads[2]; + struct v4l2_async_notifier notifier; + struct v4l2_async_subdev *asd; + struct v4l2_ctrl_handler ctrls; + struct v4l2_subdev *sensor; +}; + +static inline struct max9271_device *sd_to_max9271(struct v4l2_subdev *sd) +{ + return container_of(sd, struct max9271_device, sd); +} + +static inline struct max9271_device *i2c_to_max9271(struct i2c_client *client) +{ + return sd_to_max9271(i2c_get_clientdata(client)); +} + +static inline struct max9271_device *notifier_to_max9271( + struct v4l2_async_notifier *nf) +{ + return container_of(nf, struct max9271_device, notifier); +} + +/* --- MAX9271 hardware operations --- */ + +static int max9271_read(struct max9271_device *dev, u8 reg) +{ + int ret; + + dev_dbg(&dev->client->dev, "%s(0x%02x)\n", __func__, reg); + + ret = i2c_smbus_read_byte_data(dev->client, reg); + if (ret < 0) + dev_dbg(&dev->client->dev, + "%s: register 0x%02x read failed (%d)\n", + __func__, reg, ret); + + return ret; +} + +static int max9271_write(struct max9271_device *dev, u8 reg, u8 val) +{ + int ret; + + dev_dbg(&dev->client->dev, "%s(0x%02x, 0x%02x)\n", __func__, reg, val); + + ret = i2c_smbus_write_byte_data(dev->client, reg, val); + if (ret < 0) + dev_err(&dev->client->dev, + "%s: register 0x%02x write failed (%d)\n", + __func__, reg, ret); + + return ret; +} + +/* + * max9271_pclk_detect() - Detect valid pixel clock from image sensor + * + * Wait up to 10ms for a valid pixel clock. + * + * Returns 0 for success, < 0 for pixel clock not properly detected + */ +static int max9271_pclk_detect(struct max9271_device *dev) +{ + unsigned int i; + int ret; + + for (i = 0; i < 100; i++) { + ret = max9271_read(dev, 0x15); + if (ret < 0) + return ret; + + if (ret & MAX9271_PCLKDET) + return 0; + + usleep_range(50, 100); + } + + dev_err(&dev->client->dev, "Unable to detect valid pixel clock\n"); + + return -EIO; +} + +static void max9271_wake_up(struct max9271_device *dev) +{ + /* + * Use the chip default address as this function has to be called + * before any other one. + */ + dev->client->addr = MAX9271_DEFAULT_ADDR; + i2c_smbus_read_byte(dev->client); + usleep_range(5000, 8000); +} + +static int max9271_set_serial_link(struct max9271_device *dev, bool enable) +{ + int ret; + u8 val = MAX9271_REVCCEN | MAX9271_FWDCCEN; + + if (enable) { + ret = max9271_pclk_detect(dev); + if (ret) + return ret; + + val |= MAX9271_SEREN; + } else { + val |= MAX9271_CLINKEN; + } + + /* + * The serializer temporarily disables the reverse control channel for + * 350µs after starting/stopping the forward serial link, but the + * deserializer synchronization time isn't clearly documented. + * + * According to the serializer datasheet we should wait 3ms, while + * according to the deserializer datasheet we should wait 5ms. + * + * Short delays here appear to show bit-errors in the writes following. + * Therefore a conservative delay seems best here. + */ + ret = max9271_write(dev, 0x04, val); + if (ret < 0) + return ret; + + usleep_range(5000, 8000); + + return 0; +} + +static int max9271_configure_i2c(struct max9271_device *dev, u8 i2c_config) +{ + int ret; + + ret = max9271_write(dev, 0x0d, i2c_config); + if (ret < 0) + return ret; + + /* The delay required after an I2C bus configuration change is not + * characterized in the serializer manual. Sleep up to 5msec to + * stay safe. + */ + usleep_range(3500, 5000); + + return 0; +} + +static int max9271_set_high_threshold(struct max9271_device *dev, bool enable) +{ + int ret; + + ret = max9271_read(dev, 0x08); + if (ret < 0) + return ret; + + /* + * Enable or disable reverse channel high threshold to increase + * immunity to power supply noise. + */ + ret = max9271_write(dev, 0x08, enable ? ret | BIT(0) : ret & ~BIT(0)); + if (ret < 0) + return ret; + + usleep_range(2000, 2500); + + return 0; +} + +static int max9271_configure_gmsl_link(struct max9271_device *dev) +{ + int ret; + + /* + * Configure the GMSL link: + * + * - Double input mode, high data rate, 24-bit mode + * - Latch input data on PCLKIN rising edge + * - Enable HS/VS encoding + * - 1-bit parity error detection + * + * TODO: Make the GMSL link configuration parametric. + */ + ret = max9271_write(dev, 0x07, MAX9271_DBL | MAX9271_HVEN | + MAX9271_EDC_1BIT_PARITY); + if (ret < 0) + return ret; + + usleep_range(5000, 8000); + + /* + * Adjust spread spectrum to +4% and auto-detect pixel clock + * and serial link rate. + */ + ret = max9271_write(dev, 0x02, + MAX9271_SPREAD_SPECT_4 | MAX9271_R02_RES | + MAX9271_PCLK_AUTODETECT | + MAX9271_SERIAL_AUTODETECT); + if (ret < 0) + return ret; + + usleep_range(5000, 8000); + + return 0; +} + +static int max9271_set_gpios(struct max9271_device *dev, u8 gpio_mask) +{ + int ret; + + ret = max9271_read(dev, 0x0f); + if (ret < 0) + return 0; + + ret |= gpio_mask; + ret = max9271_write(dev, 0x0f, ret); + if (ret < 0) { + dev_err(&dev->client->dev, "Failed to set gpio (%d)\n", ret); + return ret; + } + + usleep_range(3500, 5000); + + return 0; +} + +static int max9271_clear_gpios(struct max9271_device *dev, u8 gpio_mask) +{ + int ret; + + ret = max9271_read(dev, 0x0f); + if (ret < 0) + return 0; + + ret &= ~gpio_mask; + ret = max9271_write(dev, 0x0f, ret); + if (ret < 0) { + dev_err(&dev->client->dev, "Failed to clear gpio (%d)\n", ret); + return ret; + } + + usleep_range(3500, 5000); + + return 0; +} + +static int max9271_enable_gpios(struct max9271_device *dev, u8 gpio_mask) +{ + int ret; + + ret = max9271_read(dev, 0x0e); + if (ret < 0) + return 0; + + /* BIT(0) reserved: GPO is always enabled. */ + ret |= (gpio_mask & ~BIT(0)); + ret = max9271_write(dev, 0x0e, ret); + if (ret < 0) { + dev_err(&dev->client->dev, "Failed to enable gpio (%d)\n", ret); + return ret; + } + + usleep_range(3500, 5000); + + return 0; +} + +static int max9271_verify_id(struct max9271_device *dev) +{ + int ret; + + ret = max9271_read(dev, 0x1e); + if (ret < 0) { + dev_err(&dev->client->dev, "MAX9271 ID read failed (%d)\n", + ret); + return ret; + } + + if (ret != MAX9271_ID) { + dev_err(&dev->client->dev, "MAX9271 ID mismatch (0x%02x)\n", + ret); + return -ENXIO; + } + + return 0; +} + +static int max9271_set_address(struct max9271_device *dev, u8 addr) +{ + int ret; + + ret = max9271_write(dev, 0x00, addr << 1); + if (ret < 0) { + dev_err(&dev->client->dev, + "MAX9271 I2C address change failed (%d)\n", ret); + return ret; + } + usleep_range(3500, 5000); + + return 0; +} + +/* --- V4L2 Subdev Ops --- */ + +static int max9271_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct max9271_device *max9271 = sd_to_max9271(sd); + + return max9271_set_serial_link(max9271, enable); +} + +static int max9271_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct max9271_device *max9271 = sd_to_max9271(sd); + + return v4l2_subdev_call(max9271->sensor, pad, enum_mbus_code, NULL, + code); +} + +static int max9271_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *format) +{ + struct max9271_device *max9271 = sd_to_max9271(sd); + + return v4l2_subdev_call(max9271->sensor, pad, get_fmt, NULL, + format); +} + +static int max9271_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *format) +{ + struct max9271_device *max9271 = sd_to_max9271(sd); + + return v4l2_subdev_call(max9271->sensor, pad, set_fmt, NULL, + format); +} + +static int max9271_post_register(struct v4l2_subdev *sd) +{ + struct max9271_device *max9271 = sd_to_max9271(sd); + int ret; + + ret = max9271_verify_id(max9271); + if (ret < 0) + return ret; + + ret = max9271_enable_gpios(max9271, MAX9271_GPIO1OUT); + if (ret) + return ret; + + ret = max9271_configure_gmsl_link(max9271); + if (ret) + return ret; + + return 0; +} + +static const struct v4l2_subdev_video_ops max9271_video_ops = { + .s_stream = max9271_s_stream, +}; + +static const struct v4l2_subdev_pad_ops max9271_subdev_pad_ops = { + .enum_mbus_code = max9271_enum_mbus_code, + .get_fmt = max9271_get_fmt, + .set_fmt = max9271_set_fmt, +}; + +static const struct v4l2_subdev_core_ops max9271_core_ops = { + .post_register = max9271_post_register, +}; + +static const struct v4l2_subdev_ops max9271_subdev_ops = { + .core = &max9271_core_ops, + .video = &max9271_video_ops, + .pad = &max9271_subdev_pad_ops, +}; + +/* --- V4L2 Async Notifier --- */ + +static int max9271_notify_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + struct max9271_device *max9271 = notifier_to_max9271(notifier); + int ret, pad; + + /* + * Reserve more space than necessary for controls inherited by the + * remote subdev. + */ + ret = v4l2_ctrl_handler_init(&max9271->ctrls, 16); + if (ret < 0) { + dev_err(max9271->dev, + "Unable to initialize control handler: %d\n", ret); + return ret; + } + + ret = v4l2_ctrl_add_handler(&max9271->ctrls, subdev->ctrl_handler, + NULL, true); + if (ret < 0) { + dev_err(max9271->dev, + "Unable to add subdev control handler: %d\n", ret); + goto error_free_handler; + } + max9271->sd.ctrl_handler = &max9271->ctrls; + + /* Create media link with the remote sensor source pad. */ + pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode, + MEDIA_PAD_FL_SOURCE); + if (pad < 0) { + dev_err(max9271->dev, + "Failed to find source pad for %s\n", subdev->name); + ret = pad; + goto error_free_handler; + } + + ret = media_create_pad_link(&subdev->entity, pad, + &max9271->sd.entity, MAX9271_SINK_PAD, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (ret) + goto error_free_handler; + + max9271->sensor = subdev; + + /* + * Hold OV10635 in reset during max9271 configuration. The reset signal + * has to be asserted for at least 200 microseconds. + */ + ret = max9271_clear_gpios(max9271, MAX9271_GPIO1OUT); + if (ret) + return ret; + usleep_range(200, 500); + + /* + * Release ov10635 from reset and initialize it. The image sensor + * requires at least 2048 XVCLK cycles (85 micro-seconds at 24MHz) + * before being available. Stay safe and wait up to 500 micro-seconds. + */ + ret = max9271_set_gpios(max9271, MAX9271_GPIO1OUT); + if (ret) + return ret; + usleep_range(100, 500); + + /* + * Call the sensor post_register operation to complete its + * initialization. + */ + ret = v4l2_subdev_call(max9271->sensor, core, post_register); + if (ret) { + dev_err(max9271->dev, "Failed to initialize sensor %u\n", ret); + goto error_remove_link; + } + + return 0; + +error_remove_link: + media_entity_remove_links(&max9271->sd.entity); + max9271->sensor = NULL; + +error_free_handler: + v4l2_ctrl_handler_free(&max9271->ctrls); + max9271->sd.ctrl_handler = NULL; + + return ret; +} + +static void max9271_notify_unbind(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + struct max9271_device *max9271 = notifier_to_max9271(notifier); + + media_entity_remove_links(&max9271->sd.entity); + max9271->sensor = NULL; +} + +static const struct v4l2_async_notifier_operations max9271_notifier_ops = { + .bound = max9271_notify_bound, + .unbind = max9271_notify_unbind, +}; + +static int max9271_parse_dt(struct max9271_device *max9271) +{ + struct fwnode_handle *ep, *remote; + struct v4l2_fwnode_endpoint vep = { + .bus_type = V4L2_MBUS_PARALLEL, + }; + int ret; + + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(max9271->dev), 1, 0, 0); + if (!ep) { + dev_err(max9271->dev, "Unable to get sensor endpoint: %pOF\n", + max9271->dev->of_node); + return -ENOENT; + } + + remote = fwnode_graph_get_remote_endpoint(ep); + if (!remote) { + dev_err(max9271->dev, "Unable to get remote endpoint: %pOF\n", + max9271->dev->of_node); + return -ENOENT; + } + + ret = v4l2_fwnode_endpoint_parse(ep, &vep); + fwnode_handle_put(ep); + if (ret) { + fwnode_handle_put(remote); + dev_err(max9271->dev, "Unable to parse endpoint: %pOF\n", + to_of_node(ep)); + return ret; + } + + v4l2_async_notifier_init(&max9271->notifier); + max9271->asd = v4l2_async_notifier_add_fwnode_subdev(&max9271->notifier, + remote, struct v4l2_async_subdev); + fwnode_handle_put(remote); + if (IS_ERR(max9271->asd)) + return PTR_ERR(max9271->asd); + + max9271->notifier.ops = &max9271_notifier_ops; + max9271->notifier.flags = V4L2_ASYNC_NOTIFIER_DEFER_POST_REGISTER; + ret = v4l2_async_subdev_notifier_register(&max9271->sd, + &max9271->notifier); + if (ret < 0) { + v4l2_async_notifier_cleanup(&max9271->notifier); + return ret; + } + + return 0; +} + +static int max9271_init(struct max9271_device *max9271) +{ + int ret; + u8 addr; + + max9271_wake_up(max9271); + + /* Re-program the chip address. */ + addr = max9271->client->addr; + max9271->client->addr = MAX9271_DEFAULT_ADDR; + ret = max9271_set_address(max9271, addr); + if (ret < 0) + return ret; + max9271->client->addr = addr; + + /* Serial link disabled during conf as it needs a valid pixel clock. */ + ret = max9271_set_serial_link(max9271, false); + if (ret) + return ret; + + /* + * Ensure that we have a good link configuration before attempting to + * identify the device. + */ + ret = max9271_configure_i2c(max9271, MAX9271_I2CSLVSH_469NS_234NS | + MAX9271_I2CSLVTO_1024US | + MAX9271_I2CMSTBT_105KBPS); + if (ret) + return ret; + + /* + * Set reverse channel high threshold to increase noise immunity. + * + * This should be compensated by increasing the reverse channel + * amplitude on the remote deserializer side. + */ + return max9271_set_high_threshold(max9271, true); +} + +static int max9271_probe(struct i2c_client *client) +{ + struct max9271_device *max9271; + struct fwnode_handle *ep; + int ret; + + max9271 = devm_kzalloc(&client->dev, sizeof(*max9271), GFP_KERNEL); + if (!max9271) + return -ENOMEM; + max9271->dev = &client->dev; + max9271->client = client; + + /* Initialize and register the subdevice. */ + v4l2_i2c_subdev_init(&max9271->sd, client, &max9271_subdev_ops); + max9271->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + max9271->pads[MAX9271_SOURCE_PAD].flags = MEDIA_PAD_FL_SOURCE; + max9271->pads[MAX9271_SINK_PAD].flags = MEDIA_PAD_FL_SINK; + max9271->sd.entity.flags |= MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; + ret = media_entity_pads_init(&max9271->sd.entity, 2, max9271->pads); + if (ret < 0) + return ret; + + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(max9271->dev), 0, 0, 0); + if (!ep) { + dev_err(max9271->dev, "Unable to get endpoint 0: %pOF\n", + max9271->dev->of_node); + ret = -ENODEV; + goto error_media_entity; + } + + max9271->sd.fwnode = ep; + ret = v4l2_async_register_subdev(&max9271->sd); + if (ret) + goto error_put_node; + + ret = max9271_parse_dt(max9271); + if (ret) + goto error_unregister_subdev; + + ret = max9271_init(max9271); + if (ret) + goto error_unregister_subdev; + + return 0; + +error_unregister_subdev: + v4l2_async_unregister_subdev(&max9271->sd); +error_put_node: + fwnode_handle_put(max9271->sd.fwnode); +error_media_entity: + media_entity_cleanup(&max9271->sd.entity); + + return ret; +} + +static int max9271_remove(struct i2c_client *client) +{ + struct max9271_device *max9271 = i2c_to_max9271(client); + + v4l2_ctrl_handler_free(&max9271->ctrls); + v4l2_async_notifier_cleanup(&max9271->notifier); + v4l2_async_unregister_subdev(&max9271->sd); + fwnode_handle_put(max9271->sd.fwnode); + media_entity_cleanup(&max9271->sd.entity); + + return 0; +} + +static const struct of_device_id max9271_of_ids[] = { + { .compatible = "imi,max9271", }, + { } +}; +MODULE_DEVICE_TABLE(of, max9271_of_ids); + +static struct i2c_driver max9271_i2c_driver = { + .driver = { + .name = "max9271", + .of_match_table = max9271_of_ids, + }, + .probe_new = max9271_probe, + .remove = max9271_remove, +}; + +module_i2c_driver(max9271_i2c_driver); + +MODULE_DESCRIPTION("MAX9271 GMSL serializer subdevice driver"); +MODULE_AUTHOR("Jacopo Mondi"); +MODULE_LICENSE("GPL"); From patchwork Tue Aug 17 07:27:01 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 12440621 X-Patchwork-Delegate: kieran@bingham.xyz Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E575CC4320A for ; Tue, 17 Aug 2021 07:34:53 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C4BBB60C3E for ; Tue, 17 Aug 2021 07:34:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234779AbhHQHfZ (ORCPT ); Tue, 17 Aug 2021 03:35:25 -0400 Received: from mslow1.mail.gandi.net ([217.70.178.240]:41719 "EHLO mslow1.mail.gandi.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234402AbhHQHfY (ORCPT ); Tue, 17 Aug 2021 03:35:24 -0400 Received: from relay9-d.mail.gandi.net (unknown [217.70.183.199]) by mslow1.mail.gandi.net (Postfix) with ESMTP id E1F12CD8D4 for ; Tue, 17 Aug 2021 07:26:57 +0000 (UTC) Received: (Authenticated sender: jacopo@jmondi.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 67E48FF80E; Tue, 17 Aug 2021 07:26:31 +0000 (UTC) From: Jacopo Mondi To: Mauro Carvalho Chehab , Kieran Bingham , Laurent Pinchart , =?utf-8?q?Nik?= =?utf-8?q?las_S=C3=B6derlund?= Cc: Jacopo Mondi , Hans Verkuil , Sakari Ailus , Manivannan Sadhasivam , Thomas NIZAN , linux-renesas-soc@vger.kernel.org, linux-media@vger.kernel.org Subject: [RFC 3/5] media: i2c: rdacm20: Adapt to work with MAX9271 Date: Tue, 17 Aug 2021 09:27:01 +0200 Message-Id: <20210817072703.1167-4-jacopo+renesas@jmondi.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210817072703.1167-1-jacopo+renesas@jmondi.org> References: <20210817072703.1167-1-jacopo+renesas@jmondi.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-renesas-soc@vger.kernel.org The rdacm20 camera module driver was designed to work with the MAX9271 library driver now named max9271-lib. With the introduction of an i2c subdevice driver for the MAX9271 serializer adapt the camera module driver to work with it by removing calls to the max9271 handling functions. Signed-off-by: Jacopo Mondi --- drivers/media/i2c/rdacm20.c | 139 ++++++------------------------------ 1 file changed, 23 insertions(+), 116 deletions(-) diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c index bf06a1c50306..1cc8a7478b6f 100644 --- a/drivers/media/i2c/rdacm20.c +++ b/drivers/media/i2c/rdacm20.c @@ -27,8 +27,6 @@ #include #include -#include "max9271-lib.h" - #define OV10635_I2C_ADDRESS 0x30 #define OV10635_SOFTWARE_RESET 0x0103 @@ -312,8 +310,7 @@ static const struct ov10635_reg { struct rdacm20_device { struct device *dev; - struct max9271_device serializer; - struct i2c_client *sensor; + struct i2c_client *client; struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler ctrls; @@ -335,14 +332,14 @@ static int ov10635_read16(struct rdacm20_device *dev, u16 reg) u8 buf[2] = { reg >> 8, reg & 0xff }; int ret; - ret = i2c_master_send(dev->sensor, buf, 2); + ret = i2c_master_send(dev->client, buf, 2); if (ret != 2) { dev_dbg(dev->dev, "%s: register 0x%04x write failed (%d)\n", __func__, reg, ret); return ret; } - ret = i2c_master_recv(dev->sensor, buf, 2); + ret = i2c_master_recv(dev->client, buf, 2); if (ret < 0) { dev_dbg(dev->dev, "%s: register 0x%04x read failed (%d)\n", __func__, reg, ret); @@ -359,7 +356,7 @@ static int __ov10635_write(struct rdacm20_device *dev, u16 reg, u8 val) dev_dbg(dev->dev, "%s(0x%04x, 0x%02x)\n", __func__, reg, val); - ret = i2c_master_send(dev->sensor, buf, 3); + ret = i2c_master_send(dev->client, buf, 3); return ret < 0 ? ret : 0; } @@ -379,11 +376,17 @@ static int ov10635_set_regs(struct rdacm20_device *dev, const struct ov10635_reg *regs, unsigned int nr_regs) { + unsigned int retry; unsigned int i; int ret; for (i = 0; i < nr_regs; i++) { + retry = 3; +again: ret = __ov10635_write(dev, regs[i].reg, regs[i].val); + if (ret && retry--) + goto again; + if (ret) { dev_err(dev->dev, "%s: register %u (0x%04x) write failed (%d)\n", @@ -397,9 +400,7 @@ static int ov10635_set_regs(struct rdacm20_device *dev, static int rdacm20_s_stream(struct v4l2_subdev *sd, int enable) { - struct rdacm20_device *dev = sd_to_rdacm20(sd); - - return max9271_set_serial_link(&dev->serializer, enable); + return 0; } static int rdacm20_enum_mbus_code(struct v4l2_subdev *sd, @@ -440,37 +441,10 @@ static int rdacm20_post_register(struct v4l2_subdev *sd) struct rdacm20_device *dev = sd_to_rdacm20(sd); unsigned int retry = 3; int ret; + u8 addr; - /* - * Hold OV10635 in reset during max9271 configuration. The reset signal - * has to be asserted for at least 200 microseconds. - */ - ret = max9271_enable_gpios(&dev->serializer, MAX9271_GPIO1OUT); - if (ret) - return ret; - - ret = max9271_clear_gpios(&dev->serializer, MAX9271_GPIO1OUT); - if (ret) - return ret; - usleep_range(200, 500); - - ret = max9271_configure_gmsl_link(&dev->serializer); - if (ret) - return ret; - - ret = max9271_verify_id(&dev->serializer); - if (ret < 0) - return ret; - - /* - * Release ov10635 from reset and initialize it. The image sensor - * requires at least 2048 XVCLK cycles (85 micro-seconds at 24MHz) - * before being available. Stay safe and wait up to 500 micro-seconds. - */ - ret = max9271_set_gpios(&dev->serializer, MAX9271_GPIO1OUT); - if (ret) - return ret; - usleep_range(100, 500); + addr = dev->client->addr; + dev->client->addr = OV10635_I2C_ADDRESS; again: ret = ov10635_read16(dev, OV10635_PID); @@ -492,23 +466,22 @@ static int rdacm20_post_register(struct v4l2_subdev *sd) return -ENXIO; } + /* Program the 0V10635 initial configuration. */ + ret = ov10635_set_regs(dev, ov10635_regs_wizard, + ARRAY_SIZE(ov10635_regs_wizard)); + if (ret) + return ret; + /* Change the sensor I2C address. */ ret = ov10635_write(dev, OV10635_SC_CMMN_SCCB_ID, - (dev->addrs[1] << 1) | - OV10635_SC_CMMN_SCCB_ID_SELECT); + (addr << 1) | OV10635_SC_CMMN_SCCB_ID_SELECT); if (ret < 0) { dev_err(dev->dev, "OV10635 I2C address change failed (%d)\n", ret); return ret; } - dev->sensor->addr = dev->addrs[1]; usleep_range(3500, 5000); - - /* Program the 0V10635 initial configuration. */ - ret = ov10635_set_regs(dev, ov10635_regs_wizard, - ARRAY_SIZE(ov10635_regs_wizard)); - if (ret) - return ret; + dev->client->addr = addr; dev_info(dev->dev, "Identified RDACM20 camera module\n"); @@ -535,48 +508,6 @@ static const struct v4l2_subdev_ops rdacm20_subdev_ops = { .pad = &rdacm20_subdev_pad_ops, }; -static int rdacm20_initialize(struct rdacm20_device *dev) -{ - int ret; - - max9271_wake_up(&dev->serializer); - - /* Serial link disabled during config as it needs a valid pixel clock. */ - ret = max9271_set_serial_link(&dev->serializer, false); - if (ret) - return ret; - - /* - * Ensure that we have a good link configuration before attempting to - * identify the device. - */ - ret = max9271_configure_i2c(&dev->serializer, - MAX9271_I2CSLVSH_469NS_234NS | - MAX9271_I2CSLVTO_1024US | - MAX9271_I2CMSTBT_105KBPS); - if (ret) - return ret; - - ret = max9271_set_address(&dev->serializer, dev->addrs[0]); - if (ret < 0) - return ret; - dev->serializer.client->addr = dev->addrs[0]; - - /* - * Set reverse channel high threshold to increase noise immunity. - * - * This should be compensated by increasing the reverse channel - * amplitude on the remote deserializer side. - * - * TODO Inspect the embedded MCU programming sequence to make sure - * there are no conflicts with the configuration applied here. - * - * TODO Clarify the embedded MCU startup delay to avoid write - * collisions on the I2C bus. - */ - return max9271_set_high_threshold(&dev->serializer, true); -} - static int rdacm20_probe(struct i2c_client *client) { struct rdacm20_device *dev; @@ -587,27 +518,7 @@ static int rdacm20_probe(struct i2c_client *client) if (!dev) return -ENOMEM; dev->dev = &client->dev; - dev->serializer.client = client; - - ret = of_property_read_u32_array(client->dev.of_node, "reg", - dev->addrs, 2); - if (ret < 0) { - dev_err(dev->dev, "Invalid DT reg property: %d\n", ret); - return -EINVAL; - } - - /* Create the dummy I2C client for the sensor. */ - dev->sensor = i2c_new_dummy_device(client->adapter, - OV10635_I2C_ADDRESS); - if (IS_ERR(dev->sensor)) { - ret = PTR_ERR(dev->sensor); - goto error; - } - - /* Initialize the hardware. */ - ret = rdacm20_initialize(dev); - if (ret < 0) - goto error; + dev->client = client; /* Initialize and register the subdevice. */ v4l2_i2c_subdev_init(&dev->sd, client, &rdacm20_subdev_ops); @@ -649,10 +560,7 @@ static int rdacm20_probe(struct i2c_client *client) fwnode_handle_put(ep); error_free_ctrls: v4l2_ctrl_handler_free(&dev->ctrls); -error: media_entity_cleanup(&dev->sd.entity); - if (dev->sensor) - i2c_unregister_device(dev->sensor); dev_err(&client->dev, "probe failed\n"); @@ -667,7 +575,6 @@ static int rdacm20_remove(struct i2c_client *client) v4l2_async_unregister_subdev(&dev->sd); v4l2_ctrl_handler_free(&dev->ctrls); media_entity_cleanup(&dev->sd.entity); - i2c_unregister_device(dev->sensor); return 0; } From patchwork Tue Aug 17 07:27:02 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 12440615 X-Patchwork-Delegate: kieran@bingham.xyz Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 45766C4338F for ; Tue, 17 Aug 2021 07:34:53 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1F77F60C3E for ; Tue, 17 Aug 2021 07:34:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234762AbhHQHfZ (ORCPT ); Tue, 17 Aug 2021 03:35:25 -0400 Received: from mslow1.mail.gandi.net ([217.70.178.240]:60157 "EHLO mslow1.mail.gandi.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234669AbhHQHfY (ORCPT ); Tue, 17 Aug 2021 03:35:24 -0400 Received: from relay9-d.mail.gandi.net (unknown [217.70.183.199]) by mslow1.mail.gandi.net (Postfix) with ESMTP id 0958FCD8F2 for ; Tue, 17 Aug 2021 07:27:00 +0000 (UTC) Received: (Authenticated sender: jacopo@jmondi.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id CBB20FF811; Tue, 17 Aug 2021 07:26:34 +0000 (UTC) From: Jacopo Mondi To: Mauro Carvalho Chehab , Kieran Bingham , Laurent Pinchart , =?utf-8?q?Nik?= =?utf-8?q?las_S=C3=B6derlund?= Cc: Jacopo Mondi , Hans Verkuil , Sakari Ailus , Manivannan Sadhasivam , Thomas NIZAN , linux-renesas-soc@vger.kernel.org, linux-media@vger.kernel.org Subject: [RFC 4/5] media: i2c: max9286: Fetch PIXEL_RATE in s_stream Date: Tue, 17 Aug 2021 09:27:02 +0200 Message-Id: <20210817072703.1167-5-jacopo+renesas@jmondi.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210817072703.1167-1-jacopo+renesas@jmondi.org> References: <20210817072703.1167-1-jacopo+renesas@jmondi.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-renesas-soc@vger.kernel.org The max9286 driver needs to fetch the remote serializer PIXEL_RATE control value in order to compute its own one, as the sum of the values reported by the connected subdevices. Currently the control is verified to be present at notifier's bound time, which requires the serializer driver to register the control at probe time. As the serializer driver might need to register the control later, by adding the control handler of its connected sensor, post-pone the max9286 check for the control availability at start stream time. Signed-off-by: Jacopo Mondi --- drivers/media/i2c/max9286.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c index 1b92d18a1f94..98fc90339a9e 100644 --- a/drivers/media/i2c/max9286.c +++ b/drivers/media/i2c/max9286.c @@ -595,7 +595,7 @@ static int max9286_notify_bound(struct v4l2_async_notifier *notifier, max9286_check_config_link(priv, priv->source_mask); max9286_configure_i2c(priv, false); - return max9286_set_pixelrate(priv); + return 0; } static void max9286_notify_unbind(struct v4l2_async_notifier *notifier, @@ -674,6 +674,10 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable) int ret; if (enable) { + ret = max9286_set_pixelrate(priv); + if (ret) + return ret; + /* * The frame sync between cameras is transmitted across the * reverse channel as GPIO. We must open all channels while From patchwork Tue Aug 17 07:27:03 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 12440623 X-Patchwork-Delegate: geert@linux-m68k.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0D1B1C00143 for ; Tue, 17 Aug 2021 07:34:55 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E982660F5E for ; Tue, 17 Aug 2021 07:34:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234816AbhHQHf0 (ORCPT ); Tue, 17 Aug 2021 03:35:26 -0400 Received: from mslow1.mail.gandi.net ([217.70.178.240]:40827 "EHLO mslow1.mail.gandi.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234772AbhHQHf0 (ORCPT ); Tue, 17 Aug 2021 03:35:26 -0400 Received: from relay9-d.mail.gandi.net (unknown [217.70.183.199]) by mslow1.mail.gandi.net (Postfix) with ESMTP id EA468CD941 for ; Tue, 17 Aug 2021 07:27:01 +0000 (UTC) Received: (Authenticated sender: jacopo@jmondi.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 4CC3AFF80A; Tue, 17 Aug 2021 07:26:37 +0000 (UTC) From: Jacopo Mondi To: Mauro Carvalho Chehab , Kieran Bingham , Laurent Pinchart , =?utf-8?q?Nik?= =?utf-8?q?las_S=C3=B6derlund?= Cc: Jacopo Mondi , Hans Verkuil , Sakari Ailus , Manivannan Sadhasivam , Thomas NIZAN , linux-renesas-soc@vger.kernel.org, linux-media@vger.kernel.org Subject: [RFC 5/5] arm64: dts: GMSL: Adapt to the use max9271 driver Date: Tue, 17 Aug 2021 09:27:03 +0200 Message-Id: <20210817072703.1167-6-jacopo+renesas@jmondi.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210817072703.1167-1-jacopo+renesas@jmondi.org> References: <20210817072703.1167-1-jacopo+renesas@jmondi.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-renesas-soc@vger.kernel.org Currently the whole RDACM20/21 camera module was handled by a single driver and a single device node entry was required in DTS to describe it. With the introduction of the max9271 subdevice driver the camera module is now described by two device nodes, one for the serializer and one for the image sensor connected to it. Signed-off-by: Jacopo Mondi --- arch/arm64/boot/dts/renesas/gmsl-cameras.dtsi | 34 ++++++++++++++++--- .../arm64/boot/dts/renesas/r8a77970-eagle.dts | 6 ++-- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/arch/arm64/boot/dts/renesas/gmsl-cameras.dtsi b/arch/arm64/boot/dts/renesas/gmsl-cameras.dtsi index d45f072f8cdf..7d8f2e979134 100644 --- a/arch/arm64/boot/dts/renesas/gmsl-cameras.dtsi +++ b/arch/arm64/boot/dts/renesas/gmsl-cameras.dtsi @@ -131,13 +131,37 @@ i2c-mux { i2c@0 { status = "okay"; - camera@51 { - compatible = GMSL_CAMERA_MODEL; - reg = <0x51>, <0x61>; + serializer@51 { + compatible = "maxim,max9271"; + reg = <0x51>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + fakra_con0: endpoint { + remote-endpoint = <&max9286_in0>; + }; + }; + + port@1 { + reg = <1>; + sensor_in0: endpoint { + remote-endpoint = <&sensor_out0>; + }; + }; + }; + }; + + camera@61 { + compatible = "imi,rdacm20"; + reg = <0x61>; port { - fakra_con0: endpoint { - remote-endpoint = <&max9286_in0>; + sensor_out0: endpoint { + remote-endpoint = <&sensor_in0>; }; }; }; diff --git a/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts b/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts index 96c807bf868c..22bb04914159 100644 --- a/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts +++ b/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts @@ -388,7 +388,7 @@ &scif0 { /* FAKRA Overlay */ #define GMSL_CAMERA_RDACM20 #define GMSL_CAMERA_0 -#define GMSL_CAMERA_1 -#define GMSL_CAMERA_2 -#define GMSL_CAMERA_3 +//#define GMSL_CAMERA_1 +//#define GMSL_CAMERA_2 +//#define GMSL_CAMERA_3 #include "gmsl-cameras.dtsi"