media: ov2740: Add regulator support

On some designs the regulators for the AVDD / DOVDD / DVDD power rails
are controlled by Linux.

Add support to the driver for getting regulators for these 3 rails and
for enabling these regulators when necessary.

The datasheet specifies a delay of 0ns between enabling the regulators,
IOW they can all 3 be enabled at the same time. This allows using the bulk
regulator API.

The regulator core will provide dummy regulators for the 3 power-rails
when necessary.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Ricardo Ribalda <ribalda@chromium.org>
Tested-by: Stanislaw Gruszka <stanislaw.gruszka@linux.intel.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
This commit is contained in:
Hans de Goede 2024-11-28 16:23:38 +01:00 committed by Mauro Carvalho Chehab
parent fa3772f390
commit fb6ba073ff

View File

@ -11,6 +11,7 @@
#include <linux/pm_runtime.h>
#include <linux/nvmem-provider.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
@ -76,6 +77,14 @@
/* OTP registers from sensor */
#define OV2740_REG_OTP_CUSTOMER 0x7010
static const char * const ov2740_supply_name[] = {
"AVDD",
"DOVDD",
"DVDD",
};
#define OV2740_NUM_SUPPLIES ARRAY_SIZE(ov2740_supply_name)
struct nvm_data {
struct nvmem_device *nvmem;
struct regmap *regmap;
@ -523,10 +532,11 @@ struct ov2740 {
struct v4l2_ctrl *hblank;
struct v4l2_ctrl *exposure;
/* GPIOs, clocks */
/* GPIOs, clocks, regulators */
struct gpio_desc *reset_gpio;
struct gpio_desc *powerdown_gpio;
struct clk *clk;
struct regulator_bulk_data supplies[OV2740_NUM_SUPPLIES];
/* Current mode */
const struct ov2740_mode *cur_mode;
@ -1309,6 +1319,7 @@ static int ov2740_suspend(struct device *dev)
gpiod_set_value_cansleep(ov2740->reset_gpio, 1);
gpiod_set_value_cansleep(ov2740->powerdown_gpio, 1);
clk_disable_unprepare(ov2740->clk);
regulator_bulk_disable(OV2740_NUM_SUPPLIES, ov2740->supplies);
return 0;
}
@ -1318,10 +1329,16 @@ static int ov2740_resume(struct device *dev)
struct ov2740 *ov2740 = to_ov2740(sd);
int ret;
ret = clk_prepare_enable(ov2740->clk);
ret = regulator_bulk_enable(OV2740_NUM_SUPPLIES, ov2740->supplies);
if (ret)
return ret;
ret = clk_prepare_enable(ov2740->clk);
if (ret) {
regulator_bulk_disable(OV2740_NUM_SUPPLIES, ov2740->supplies);
return ret;
}
gpiod_set_value_cansleep(ov2740->powerdown_gpio, 0);
gpiod_set_value_cansleep(ov2740->reset_gpio, 0);
msleep(20);
@ -1334,7 +1351,7 @@ static int ov2740_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct ov2740 *ov2740;
bool full_power;
int ret;
int i, ret;
ov2740 = devm_kzalloc(&client->dev, sizeof(*ov2740), GFP_KERNEL);
if (!ov2740)
@ -1372,6 +1389,13 @@ static int ov2740_probe(struct i2c_client *client)
return dev_err_probe(dev, PTR_ERR(ov2740->clk),
"failed to get clock\n");
for (i = 0; i < OV2740_NUM_SUPPLIES; i++)
ov2740->supplies[i].supply = ov2740_supply_name[i];
ret = devm_regulator_bulk_get(dev, OV2740_NUM_SUPPLIES, ov2740->supplies);
if (ret)
return dev_err_probe(dev, ret, "failed to get regulators\n");
full_power = acpi_dev_state_d0(&client->dev);
if (full_power) {
/* ACPI does not always clear the reset GPIO / enable the clock */