mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 18:09:56 +00:00
media: i2c: ov5647: Add support for regulator control.
The driver supported using GPIOs to control the shutdown line, but no regulator control. Add regulator hooks. Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
This commit is contained in:
committed by
Phil Elwell
parent
dc5feb98d5
commit
e331e963c2
@@ -27,6 +27,7 @@
|
|||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of_graph.h>
|
#include <linux/of_graph.h>
|
||||||
|
#include <linux/regulator/consumer.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/videodev2.h>
|
#include <linux/videodev2.h>
|
||||||
#include <media/v4l2-ctrls.h>
|
#include <media/v4l2-ctrls.h>
|
||||||
@@ -92,6 +93,15 @@
|
|||||||
#define OV5647_EXPOSURE_DEFAULT 1000
|
#define OV5647_EXPOSURE_DEFAULT 1000
|
||||||
#define OV5647_EXPOSURE_MAX 65535
|
#define OV5647_EXPOSURE_MAX 65535
|
||||||
|
|
||||||
|
/* regulator supplies */
|
||||||
|
static const char * const ov5647_supply_names[] = {
|
||||||
|
"avdd", /* Analog power */
|
||||||
|
"dovdd", /* Digital I/O power */
|
||||||
|
"dvdd", /* Digital core power */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define OV5647_NUM_SUPPLIES ARRAY_SIZE(ov5647_supply_names)
|
||||||
|
|
||||||
struct regval_list {
|
struct regval_list {
|
||||||
u16 addr;
|
u16 addr;
|
||||||
u8 data;
|
u8 data;
|
||||||
@@ -120,6 +130,7 @@ struct ov5647 {
|
|||||||
int power_count;
|
int power_count;
|
||||||
struct clk *xclk;
|
struct clk *xclk;
|
||||||
struct gpio_desc *pwdn;
|
struct gpio_desc *pwdn;
|
||||||
|
struct regulator_bulk_data supplies[OV5647_NUM_SUPPLIES];
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
struct v4l2_ctrl_handler ctrls;
|
struct v4l2_ctrl_handler ctrls;
|
||||||
struct v4l2_ctrl *pixel_rate;
|
struct v4l2_ctrl *pixel_rate;
|
||||||
@@ -949,6 +960,13 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
|
|||||||
if (on && !ov5647->power_count) {
|
if (on && !ov5647->power_count) {
|
||||||
dev_dbg(&client->dev, "OV5647 power on\n");
|
dev_dbg(&client->dev, "OV5647 power on\n");
|
||||||
|
|
||||||
|
ret = regulator_bulk_enable(OV5647_NUM_SUPPLIES,
|
||||||
|
ov5647->supplies);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(&client->dev, "Failed to enable regulators\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (ov5647->pwdn) {
|
if (ov5647->pwdn) {
|
||||||
gpiod_set_value_cansleep(ov5647->pwdn, 0);
|
gpiod_set_value_cansleep(ov5647->pwdn, 0);
|
||||||
msleep(PWDN_ACTIVE_DELAY_MS);
|
msleep(PWDN_ACTIVE_DELAY_MS);
|
||||||
@@ -956,6 +974,8 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
|
|||||||
|
|
||||||
ret = clk_prepare_enable(ov5647->xclk);
|
ret = clk_prepare_enable(ov5647->xclk);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
regulator_bulk_disable(OV5647_NUM_SUPPLIES,
|
||||||
|
ov5647->supplies);
|
||||||
dev_err(&client->dev, "clk prepare enable failed\n");
|
dev_err(&client->dev, "clk prepare enable failed\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -964,6 +984,8 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
|
|||||||
ARRAY_SIZE(sensor_oe_enable_regs));
|
ARRAY_SIZE(sensor_oe_enable_regs));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
clk_disable_unprepare(ov5647->xclk);
|
clk_disable_unprepare(ov5647->xclk);
|
||||||
|
regulator_bulk_disable(OV5647_NUM_SUPPLIES,
|
||||||
|
ov5647->supplies);
|
||||||
dev_err(&client->dev,
|
dev_err(&client->dev,
|
||||||
"write sensor_oe_enable_regs error\n");
|
"write sensor_oe_enable_regs error\n");
|
||||||
goto out;
|
goto out;
|
||||||
@@ -975,6 +997,8 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
|
|||||||
ret = ov5647_stream_off(sd);
|
ret = ov5647_stream_off(sd);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
clk_disable_unprepare(ov5647->xclk);
|
clk_disable_unprepare(ov5647->xclk);
|
||||||
|
regulator_bulk_disable(OV5647_NUM_SUPPLIES,
|
||||||
|
ov5647->supplies);
|
||||||
dev_err(&client->dev,
|
dev_err(&client->dev,
|
||||||
"Camera not available, check Power\n");
|
"Camera not available, check Power\n");
|
||||||
goto out;
|
goto out;
|
||||||
@@ -999,6 +1023,8 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
|
|||||||
clk_disable_unprepare(ov5647->xclk);
|
clk_disable_unprepare(ov5647->xclk);
|
||||||
|
|
||||||
gpiod_set_value_cansleep(ov5647->pwdn, 1);
|
gpiod_set_value_cansleep(ov5647->pwdn, 1);
|
||||||
|
|
||||||
|
regulator_bulk_disable(OV5647_NUM_SUPPLIES, ov5647->supplies);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update the power count. */
|
/* Update the power count. */
|
||||||
@@ -1557,6 +1583,18 @@ static const struct v4l2_ctrl_ops ov5647_ctrl_ops = {
|
|||||||
.s_ctrl = ov5647_s_ctrl,
|
.s_ctrl = ov5647_s_ctrl,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int ov5647_configure_regulators(struct device *dev,
|
||||||
|
struct ov5647 *ov5647)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < OV5647_NUM_SUPPLIES; i++)
|
||||||
|
ov5647->supplies[i].supply = ov5647_supply_names[i];
|
||||||
|
|
||||||
|
return devm_regulator_bulk_get(dev, OV5647_NUM_SUPPLIES,
|
||||||
|
ov5647->supplies);
|
||||||
|
}
|
||||||
|
|
||||||
static int ov5647_probe(struct i2c_client *client)
|
static int ov5647_probe(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct device *dev = &client->dev;
|
struct device *dev = &client->dev;
|
||||||
@@ -1597,6 +1635,12 @@ static int ov5647_probe(struct i2c_client *client)
|
|||||||
sensor->pwdn = devm_gpiod_get_optional(&client->dev, "pwdn",
|
sensor->pwdn = devm_gpiod_get_optional(&client->dev, "pwdn",
|
||||||
GPIOD_OUT_HIGH);
|
GPIOD_OUT_HIGH);
|
||||||
|
|
||||||
|
ret = ov5647_configure_regulators(dev, sensor);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "Failed to get power regulators\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
mutex_init(&sensor->lock);
|
mutex_init(&sensor->lock);
|
||||||
|
|
||||||
/* Initialise controls. */
|
/* Initialise controls. */
|
||||||
@@ -1701,6 +1745,12 @@ static int ov5647_probe(struct i2c_client *client)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto mutex_remove;
|
goto mutex_remove;
|
||||||
|
|
||||||
|
ret = regulator_bulk_enable(OV5647_NUM_SUPPLIES, sensor->supplies);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(dev, "Failed to enable regulators\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
if (sensor->pwdn) {
|
if (sensor->pwdn) {
|
||||||
gpiod_set_value_cansleep(sensor->pwdn, 0);
|
gpiod_set_value_cansleep(sensor->pwdn, 0);
|
||||||
msleep(PWDN_ACTIVE_DELAY_MS);
|
msleep(PWDN_ACTIVE_DELAY_MS);
|
||||||
@@ -1711,7 +1761,7 @@ static int ov5647_probe(struct i2c_client *client)
|
|||||||
gpiod_set_value_cansleep(sensor->pwdn, 1);
|
gpiod_set_value_cansleep(sensor->pwdn, 1);
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto power_down;
|
||||||
|
|
||||||
ret = v4l2_async_register_subdev(sd);
|
ret = v4l2_async_register_subdev(sd);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
@@ -1719,6 +1769,8 @@ static int ov5647_probe(struct i2c_client *client)
|
|||||||
|
|
||||||
dev_dbg(dev, "OmniVision OV5647 camera driver probed\n");
|
dev_dbg(dev, "OmniVision OV5647 camera driver probed\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
power_down:
|
||||||
|
regulator_bulk_disable(OV5647_NUM_SUPPLIES, sensor->supplies);
|
||||||
error:
|
error:
|
||||||
media_entity_cleanup(&sd->entity);
|
media_entity_cleanup(&sd->entity);
|
||||||
mutex_remove:
|
mutex_remove:
|
||||||
|
|||||||
Reference in New Issue
Block a user