From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-qk1-f174.google.com (mail-qk1-f174.google.com [209.85.222.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 22599256C71 for ; Thu, 11 Dec 2025 01:48:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.174 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1765417740; cv=none; b=Lk9fExfGpHdY5/zw3uEGCY4KAht2WUv6UnffJ4R71yvAyPYCnDVYVV+y5PJ2UYUyOeWM5xzHBkBRo8nNx1PzYzDQf3rotRjNY3h467BMbNYy5SOuy/+IrSLyH5ZAKWSS6Uj9KumagrLxdAsBhSewq83uDLPZqqaDcgrk2QeQUkU= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1765417740; c=relaxed/simple; bh=5MekM4wnWt3V5sjUG5FO0tQe+T6oQGfdT11Ipp7BIic=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=R/FHcCggDaGfkDVijGwQccWGu2KvPt1fWK0ppP0o1hs0Jufs3Brh5s9LR8Tjxo4B2qh7hG8CJqCauJVB+X//hflsuUUSrNSVb8OMIB+039K536LeBOHG6onWoHJ3a/+iZihj10KA+MJXhmzq6qDUCLSd51cBOaZZh4bN0bV+xsU= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=hDiMcAKj; arc=none smtp.client-ip=209.85.222.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="hDiMcAKj" Received: by mail-qk1-f174.google.com with SMTP id af79cd13be357-8b5ed9e7500so39268185a.0 for ; Wed, 10 Dec 2025 17:48:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1765417737; x=1766022537; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ZEI/TDA9RuaQuNOKsu3UcI/lBvXx5e4df+fKE/DAHu4=; b=hDiMcAKj7+C1++imki3C7aJuRlaY7S5gLj9rKdAJ95lgIky5egYn1zHZaEcGAhDtHB epFzVk9E5xbw/P9jjYThhxZfgYhyhz17CNBPY7xuqS67DUXieBJUb+96mG30/Pwpq+EK TsGoU4YhOBbPTFrweciXbS9/+GxtTXpsrf8ZBL9xEpdCB4qA7/om8IlAtmpqhZFLKq/c gN821qiVFV8D1o8dmWlSPxQc5wHsE/xh2se7z3Jv6l4AsLbDWn78tOx2GtjmFXMtef7q 4UlJoULbgYKZ+gRM7rkd24N/xita7taYYV6sKw4p6ql6X8DlHiJhFpqUQeOTwWnvEfqr sn7A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1765417737; x=1766022537; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=ZEI/TDA9RuaQuNOKsu3UcI/lBvXx5e4df+fKE/DAHu4=; b=cCh+lfLuBlL3dtzav5jTc0ZAs5D+QjdUAG5TG3oAJZ7dz1Ln0q4V759/yxg/04Q7IC xpZTthPsFCC53xBOGXoffGUA7+6RIuBOYfuywDaR+G9gGoZG97pPjZfl2f85Xhtx84gk 9JawZgIpJgQxLfIi0oJf8/Fk6+fwpPiNyDHFXeUJ1n8FTAaCA01ZtmhQXR8Z5jzPB5A0 rYn5AporB431vkUgFbS2TLFyVjXUZnBYobwcikAa5prJybDXb2QCsHx2oc7ZLAr9wwRK rJjEcSCszCr+SUS8/8jvpI+xmjMXUFN1WsRitizJ4m5luOUnkWx39gvtzK9KM+ir+Bhk +SXg== X-Forwarded-Encrypted: i=1; AJvYcCX79OtUq03iBB6fvHNqRbiGwKz9sUzLmbs4CW43Gu5qAuVnRVPuwtdTr0EHWPHEqB2hpiR7u3xo5248@vger.kernel.org X-Gm-Message-State: AOJu0Yy8o3OgZCLn16gm740E8LS4m4JhaggtrWHDCHSUzeIDb7SVNBQq ho4N9Any4hl5krUrnkhRPu/QMFS/hLPGop3mAq2XSqEZ3Luz9BKKFmzG X-Gm-Gg: ASbGnctRsFeqgv0yQmJDrqH2NBzshPdGx1pCnwx4yFoF2negcizOsutuW8dICjr4mYR X77h59Ut2QzCwpXM+pyk5TK/jodoTI7hEHr5S2CSLTZbFiN0JmLqOo3DKUauwPVwbVPNRv24lK9 xAruEGvN076ud+3q2J7vSbYw9qudtKuikKUPJUrFVWz+CmDTHPz79Mqk9ZOugh1qZdupB/vx4OL j4nR9e4H89tchJcCj4Bc7Rcl2Ls9rbpNgH/bIrhAUUVfKyirdta1VRJHRUa4Yd2Utv/79Lk1gHQ JWWZORN9KHq4Viy/mNy+5cOSwubXRom1cQVnXw+rF8LY7H5Yc1Rc/Gpo4zNsCcm1ANLJePrwovp WITKoX5JFOtpVpT7sTbljXAsyRNBUbxTrAytGQh4r9Pl8h7q0B2j59+2b/oITaEpQEHvXnfQCE1 wbOoxYHXXU/maRlA== X-Google-Smtp-Source: AGHT+IFIbBWXx2prf3L63/VMLVLYvYdUaI7SLOuUqClOeBLUtStROYnkPoiSKfHNBiSDpzIMrxiGbw== X-Received: by 2002:a05:620a:2942:b0:8b2:1568:82e8 with SMTP id af79cd13be357-8ba39f3fa28mr709223985a.35.1765417736914; Wed, 10 Dec 2025 17:48:56 -0800 (PST) Received: from localhost ([184.144.58.243]) by smtp.gmail.com with ESMTPSA id af79cd13be357-8bab566610esm96625585a.16.2025.12.10.17.48.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Dec 2025 17:48:56 -0800 (PST) From: Richard Acayan To: Bjorn Andersson , Konrad Dybcio , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Sakari Ailus , Tianshu Qiu , Mauro Carvalho Chehab , linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-media@vger.kernel.org Cc: Robert Mader , Vladimir Zapolskiy , Richard Acayan Subject: [PATCH v4 2/5] media: i2c: imx355: Support devicetree and power management Date: Wed, 10 Dec 2025 20:48:43 -0500 Message-ID: <20251211014846.16602-3-mailingradian@gmail.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20251211014846.16602-1-mailingradian@gmail.com> References: <20251211014846.16602-1-mailingradian@gmail.com> Precedence: bulk X-Mailing-List: devicetree@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit A device tree compatible makes it possible for this driver to be used on Open Firmware devices. Initialization of power-managed resources such as the reset GPIO and voltage regulators can be specified in the device tree and handled by the driver. Add support for this so the Pixel 3a can use the driver. Signed-off-by: Richard Acayan --- drivers/media/i2c/imx355.c | 118 ++++++++++++++++++++++++++++++++++--- 1 file changed, 110 insertions(+), 8 deletions(-) diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c index 776107efe386..c225bb8959bd 100644 --- a/drivers/media/i2c/imx355.c +++ b/drivers/media/i2c/imx355.c @@ -3,9 +3,13 @@ #include #include +#include +#include #include #include +#include #include +#include #include #include @@ -125,6 +129,15 @@ struct imx355 { * Protect access to sensor v4l2 controls. */ struct mutex mutex; + + struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[3]; +}; + +static const char * const imx355_supply_names[] = { + "avdd", + "dvdd", + "dovdd", }; static const struct imx355_reg imx355_global_regs[] = { @@ -1515,6 +1528,54 @@ static const struct v4l2_subdev_internal_ops imx355_internal_ops = { .open = imx355_open, }; +static int imx355_power_off(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx355 *imx355 = to_imx355(sd); + + gpiod_set_value_cansleep(imx355->reset_gpio, 0); + + regulator_bulk_disable(ARRAY_SIZE(imx355->supplies), imx355->supplies); + clk_disable_unprepare(imx355->clk); + + return 0; +} + +static int imx355_power_on(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx355 *imx355 = to_imx355(sd); + int ret; + + ret = clk_prepare_enable(imx355->clk); + if (ret) { + dev_err(dev, "failed to enable clocks: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(imx355->supplies), + imx355->supplies); + if (ret) { + dev_err(dev, "failed to enable regulators: %d\n", ret); + goto error_disable_clocks; + } + + usleep_range(5000, 5100); + gpiod_set_value_cansleep(imx355->reset_gpio, 1); + usleep_range(8000, 8100); + + return 0; + +error_disable_clocks: + clk_disable_unprepare(imx355->clk); + return ret; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(imx355_pm_ops, imx355_power_off, + imx355_power_on, NULL); + /* Initialize control handlers */ static int imx355_init_controls(struct imx355 *imx355) { @@ -1668,6 +1729,7 @@ static int imx355_probe(struct i2c_client *client) { struct imx355 *imx355; unsigned long freq; + size_t i; int ret; imx355 = devm_kzalloc(&client->dev, sizeof(*imx355), GFP_KERNEL); @@ -1678,7 +1740,7 @@ static int imx355_probe(struct i2c_client *client) mutex_init(&imx355->mutex); - imx355->clk = devm_v4l2_sensor_clk_get(imx355->dev, NULL); + imx355->clk = devm_v4l2_sensor_clk_get(imx355->dev, "mclk"); if (IS_ERR(imx355->clk)) return dev_err_probe(imx355->dev, PTR_ERR(imx355->clk), "failed to get clock\n"); @@ -1689,16 +1751,28 @@ static int imx355_probe(struct i2c_client *client) "external clock %lu is not supported\n", freq); - /* Initialize subdev */ - v4l2_i2c_subdev_init(&imx355->sd, client, &imx355_subdev_ops); + for (i = 0; i < ARRAY_SIZE(imx355_supply_names); i++) + imx355->supplies[i].supply = imx355_supply_names[i]; - /* Check module identity */ - ret = imx355_identify_module(imx355); + ret = devm_regulator_bulk_get(imx355->dev, + ARRAY_SIZE(imx355->supplies), + imx355->supplies); if (ret) { - dev_err(imx355->dev, "failed to find sensor: %d", ret); + dev_err_probe(imx355->dev, ret, "could not get regulators"); goto error_probe; } + imx355->reset_gpio = devm_gpiod_get_optional(imx355->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(imx355->reset_gpio)) { + ret = dev_err_probe(imx355->dev, PTR_ERR(imx355->reset_gpio), + "failed to get gpios"); + goto error_probe; + } + + /* Initialize subdev */ + v4l2_i2c_subdev_init(&imx355->sd, client, &imx355_subdev_ops); + imx355->hwcfg = imx355_get_hwcfg(imx355->dev); if (!imx355->hwcfg) { dev_err(imx355->dev, "failed to get hwcfg"); @@ -1706,13 +1780,26 @@ static int imx355_probe(struct i2c_client *client) goto error_probe; } + ret = imx355_power_on(imx355->dev); + if (ret) { + dev_err(imx355->dev, "failed to power on sensor: %d", ret); + goto error_probe; + } + + /* Check module identity */ + ret = imx355_identify_module(imx355); + if (ret) { + dev_err(imx355->dev, "failed to find sensor: %d", ret); + goto error_power_off; + } + /* Set default mode to max resolution */ imx355->cur_mode = &supported_modes[0]; ret = imx355_init_controls(imx355); if (ret) { dev_err(imx355->dev, "failed to init controls: %d", ret); - goto error_probe; + goto error_power_off; } /* Initialize subdev */ @@ -1752,6 +1839,9 @@ static int imx355_probe(struct i2c_client *client) error_handler_free: v4l2_ctrl_handler_free(imx355->sd.ctrl_handler); +error_power_off: + imx355_power_off(imx355->dev); + error_probe: mutex_destroy(&imx355->mutex); @@ -1768,7 +1858,11 @@ static void imx355_remove(struct i2c_client *client) v4l2_ctrl_handler_free(sd->ctrl_handler); pm_runtime_disable(imx355->dev); - pm_runtime_set_suspended(imx355->dev); + + if (!pm_runtime_status_suspended(imx355->dev)) { + imx355_power_off(imx355->dev); + pm_runtime_set_suspended(imx355->dev); + } mutex_destroy(&imx355->mutex); } @@ -1779,10 +1873,18 @@ static const struct acpi_device_id imx355_acpi_ids[] __maybe_unused = { }; MODULE_DEVICE_TABLE(acpi, imx355_acpi_ids); +static const struct of_device_id imx355_match_table[] __maybe_unused = { + { .compatible = "sony,imx355", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx355_match_table); + static struct i2c_driver imx355_i2c_driver = { .driver = { .name = "imx355", .acpi_match_table = ACPI_PTR(imx355_acpi_ids), + .of_match_table = imx355_match_table, + .pm = &imx355_pm_ops, }, .probe = imx355_probe, .remove = imx355_remove, -- 2.52.0