From: Richard Acayan <mailingradian@gmail.com>
To: Bjorn Andersson <andersson@kernel.org>,
Konrad Dybcio <konradybcio@kernel.org>,
Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Sakari Ailus <sakari.ailus@linux.intel.com>,
Tianshu Qiu <tian.shu.qiu@intel.com>,
Mauro Carvalho Chehab <mchehab@kernel.org>,
linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org,
linux-media@vger.kernel.org
Cc: Robert Mader <robert.mader@collabora.com>,
Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>,
Richard Acayan <mailingradian@gmail.com>
Subject: [PATCH v4 2/5] media: i2c: imx355: Support devicetree and power management
Date: Wed, 10 Dec 2025 20:48:43 -0500 [thread overview]
Message-ID: <20251211014846.16602-3-mailingradian@gmail.com> (raw)
In-Reply-To: <20251211014846.16602-1-mailingradian@gmail.com>
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 <mailingradian@gmail.com>
---
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 <linux/acpi.h>
#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
#include <linux/unaligned.h>
#include <media/v4l2-ctrls.h>
@@ -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
next prev parent reply other threads:[~2025-12-11 1:48 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-11 1:48 [PATCH v4 0/5] media: i2c: IMX355 for the Pixel 3a Richard Acayan
2025-12-11 1:48 ` [PATCH v4 1/5] dt-bindings: media: i2c: Add Sony IMX355 Richard Acayan
2025-12-11 3:12 ` Krzysztof Kozlowski
2025-12-11 3:26 ` Rob Herring (Arm)
2025-12-11 5:02 ` Krzysztof Kozlowski
2025-12-12 0:23 ` Richard Acayan
2025-12-11 5:05 ` Krzysztof Kozlowski
2025-12-11 9:35 ` Vladimir Zapolskiy
2025-12-11 11:02 ` Vladimir Zapolskiy
2025-12-13 21:50 ` Richard Acayan
2025-12-13 21:52 ` Richard Acayan
2025-12-11 1:48 ` Richard Acayan [this message]
2025-12-11 9:37 ` [PATCH v4 2/5] media: i2c: imx355: Support devicetree and power management David Heidelberg
2025-12-11 11:00 ` Vladimir Zapolskiy
2025-12-12 1:43 ` Krzysztof Kozlowski
2025-12-12 1:45 ` Krzysztof Kozlowski
2025-12-12 1:49 ` Bryan O'Donoghue
2025-12-11 1:48 ` [PATCH v4 3/5] arm64: dts: qcom: sdm670: remove camss endpoint nodes Richard Acayan
2025-12-11 10:46 ` Vladimir Zapolskiy
2025-12-12 1:39 ` Bryan O'Donoghue
2025-12-11 1:48 ` [PATCH v4 4/5] arm64: dts: qcom: sdm670: add camera mclk pins Richard Acayan
2025-12-11 10:47 ` Vladimir Zapolskiy
2025-12-12 1:40 ` Bryan O'Donoghue
2025-12-13 11:01 ` David Heidelberg
2025-12-11 1:48 ` [PATCH v4 5/5] arm64: dts: qcom: sdm670-google-sargo: add imx355 front camera Richard Acayan
2025-12-11 5:16 ` Dmitry Baryshkov
2025-12-12 0:41 ` Richard Acayan
2025-12-12 1:45 ` Bryan O'Donoghue
2025-12-12 2:19 ` Richard Acayan
2025-12-12 2:20 ` Bryan O'Donoghue
2025-12-12 19:22 ` Dmitry Baryshkov
2025-12-11 10:49 ` Vladimir Zapolskiy
2025-12-12 22:41 ` David Heidelberg
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251211014846.16602-3-mailingradian@gmail.com \
--to=mailingradian@gmail.com \
--cc=andersson@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=konradybcio@kernel.org \
--cc=krzk+dt@kernel.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=mchehab@kernel.org \
--cc=robert.mader@collabora.com \
--cc=robh@kernel.org \
--cc=sakari.ailus@linux.intel.com \
--cc=tian.shu.qiu@intel.com \
--cc=vladimir.zapolskiy@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).