Quoting Vladimir Zapolskiy (2024-08-13 11:20:35) > Omnivision OG01A1B camera sensor is supplied by tree power rails, three? > if supplies are present as device properties, include them into > sensor power up sequence. > > Signed-off-by: Vladimir Zapolskiy <vladimir.zapolskiy@xxxxxxxxxx> > --- > drivers/media/i2c/og01a1b.c | 86 ++++++++++++++++++++++++++++++++++++- > 1 file changed, 85 insertions(+), 1 deletion(-) > > diff --git a/drivers/media/i2c/og01a1b.c b/drivers/media/i2c/og01a1b.c > index 90a68201f43f..0150fdd2f424 100644 > --- a/drivers/media/i2c/og01a1b.c > +++ b/drivers/media/i2c/og01a1b.c > @@ -9,6 +9,7 @@ > #include <linux/i2c.h> > #include <linux/module.h> > #include <linux/pm_runtime.h> > +#include <linux/regulator/consumer.h> > #include <media/v4l2-ctrls.h> > #include <media/v4l2-device.h> > #include <media/v4l2-fwnode.h> > @@ -422,6 +423,9 @@ static const struct og01a1b_mode supported_modes[] = { > struct og01a1b { > struct clk *xvclk; > struct gpio_desc *reset_gpio; > + struct regulator *avdd; > + struct regulator *dovdd; > + struct regulator *dvdd; > > struct v4l2_subdev sd; > struct media_pad pad; > @@ -982,11 +986,46 @@ static int og01a1b_power_on(struct device *dev) > { > struct v4l2_subdev *sd = dev_get_drvdata(dev); > struct og01a1b *og01a1b = to_og01a1b(sd); > + int ret; > + > + if (og01a1b->avdd) { > + ret = regulator_enable(og01a1b->avdd); > + if (ret) > + return ret; > + } > + > + if (og01a1b->dovdd) { > + ret = regulator_enable(og01a1b->dovdd); > + if (ret) > + goto avdd_disable; > + } > + > + if (og01a1b->dvdd) { > + ret = regulator_enable(og01a1b->dvdd); > + if (ret) > + goto dovdd_disable; > + } Perhaps regulator_bulk_enable()/regulator_bulk_disable() would be suitable here to reduce lots of repetitive code and error handling? > > gpiod_set_value_cansleep(og01a1b->reset_gpio, 0); > usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC); > > - return clk_prepare_enable(og01a1b->xvclk); > + ret = clk_prepare_enable(og01a1b->xvclk); > + if (ret) > + goto dvdd_disable; > + > + return 0; > + > +dvdd_disable: > + if (og01a1b->dvdd) > + regulator_disable(og01a1b->dvdd); > +dovdd_disable: > + if (og01a1b->dovdd) > + regulator_disable(og01a1b->dovdd); > +avdd_disable: > + if (og01a1b->avdd) > + regulator_disable(og01a1b->avdd); > + > + return ret; > } > > static int og01a1b_power_off(struct device *dev) > @@ -998,6 +1037,15 @@ static int og01a1b_power_off(struct device *dev) > > gpiod_set_value_cansleep(og01a1b->reset_gpio, 1); > > + if (og01a1b->dvdd) > + regulator_disable(og01a1b->dvdd); > + > + if (og01a1b->dovdd) > + regulator_disable(og01a1b->dovdd); > + > + if (og01a1b->avdd) > + regulator_disable(og01a1b->avdd); > + > return 0; > } > > @@ -1045,6 +1093,42 @@ static int og01a1b_probe(struct i2c_client *client) > return PTR_ERR(og01a1b->reset_gpio); > } > > + og01a1b->avdd = devm_regulator_get_optional(&client->dev, "avdd"); > + if (IS_ERR(og01a1b->avdd)) { > + ret = PTR_ERR(og01a1b->avdd); > + if (ret != -ENODEV) { > + dev_err_probe(&client->dev, ret, > + "Failed to get 'avdd' regulator\n"); > + return ret; > + } > + > + og01a1b->avdd = NULL; > + } > + > + og01a1b->dovdd = devm_regulator_get_optional(&client->dev, "dovdd"); > + if (IS_ERR(og01a1b->dovdd)) { > + ret = PTR_ERR(og01a1b->dovdd); > + if (ret != -ENODEV) { > + dev_err_probe(&client->dev, ret, > + "Failed to get 'dovdd' regulator\n"); > + return ret; > + } > + > + og01a1b->dovdd = NULL; > + } > + > + og01a1b->dvdd = devm_regulator_get_optional(&client->dev, "dvdd"); > + if (IS_ERR(og01a1b->dvdd)) { > + ret = PTR_ERR(og01a1b->dvdd); > + if (ret != -ENODEV) { > + dev_err_probe(&client->dev, ret, > + "Failed to get 'dvdd' regulator\n"); > + return ret; > + } > + > + og01a1b->dvdd = NULL; > + } > + > /* The sensor must be powered on to read the CHIP_ID register */ > ret = og01a1b_power_on(&client->dev); > if (ret) > -- > 2.45.2 >