From: Alberto Panizzo <maramaopercheseimorto@gmail.com>
To: Mauro Carvalho Chehab <mchehab@infradead.org>
Cc: "Guennadi Liakhovetski" <g.liakhovetski@gmx.de>,
"Hans Verkuil" <hverkuil@xs4all.nl>,
"Laurent Pinchart" <laurent.pinchart@ideasonboard.com>,
"Magnus Damm" <damm@opensource.se>,
"Márton Németh" <nm127@freemail.hu>,
linux-media@vger.kernel.org,
linux-kernel <linux-kernel@vger.kernel.org>
Subject: [PATCH 1/3] soc_camera: Add the ability to bind regulators to soc_camedra devices
Date: Sun, 28 Nov 2010 18:18:07 +0100 [thread overview]
Message-ID: <1290964687.3016.5.camel@realization> (raw)
In certain machines, camera devices are supplied directly
by a number of regulators. This patch add the ability to drive
these regulators directly by the soc_camera driver.
What the machine code have to do to use this functionality is to:
1- Define a number of useful regulator supply descriptions such as:
static struct regulator_consumer_supply camera_reg1_consumers[] = {
...
REGULATOR_SUPPLY("camera_reg1", "soc-camera-pdrv.0"),
...
};
(Pay attention at the .N suffix of "soc-camera-pdrv" in case of
a system with multiple cameras)
2- Define the list of regulators to bind to a specific instance of
soc-camera-pdrv with their voltages:
static struct soc_camera_regulator_desc soc_camera_regs[] = {
SOCAM_REG_DESC("camera_reg1", 1300000, 1300000),
SOCAM_REG_DESC("camera_reg2", 2800000, 2800000),
...
};
3- Add the list to the corresponding soc_camera_link description:
static struct soc_camera_link iclink_my_camera = {
...
.soc_regulator_descs = soc_camera_regs,
.num_soc_regulator_descs = ARRAY_SIZE(soc_camera_regs),
};
4- And register it as usual with the platform device description:
static struct platform_device machine_my_camera = {
.name = "soc-camera-pdrv",
.id = 0,
.dev = {
.platform_data = &iclink_my_camera,
},
};
Signed-off-by: Alberto Panizzo <maramaopercheseimorto@gmail.com>
---
drivers/media/video/soc_camera.c | 135 +++++++++++++++++++++++++++++++------
include/media/soc_camera.h | 16 +++++
2 files changed, 129 insertions(+), 22 deletions(-)
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index 43848a7..8fc5831 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -43,6 +43,96 @@ static LIST_HEAD(hosts);
static LIST_HEAD(devices);
static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */
+static int soc_camera_setup_regulators(struct soc_camera_device *icd,
+ struct soc_camera_link *icl)
+{
+ int i, ret;
+
+ icd->soc_regulators = kzalloc(icl->num_soc_regulator_descs *
+ sizeof(struct regulator *), GFP_KERNEL);
+ if (!icd->soc_regulators) {
+ dev_err(icd->pdev, "Not enough memory.\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0; i < icl->num_soc_regulator_descs; i++) {
+ dev_dbg(icd->pdev, "Looking for reg:'%s' bound to dev:'%s'",
+ icl->soc_regulator_descs[i].supply,
+ dev_name(icd->pdev));
+ icd->soc_regulators[i] = regulator_get(icd->pdev,
+ icl->soc_regulator_descs[i].supply);
+ if (IS_ERR(icd->soc_regulators[i])) {
+ icd->soc_regulators[i] = NULL;
+ dev_err(icd->pdev, "Unable to get regulator: \"%s\".\n",
+ icl->soc_regulator_descs[i].supply);
+ ret = -ENODEV;
+ goto free_regs;
+ }
+ }
+
+ icd->num_soc_regulators = icl->num_soc_regulator_descs;
+
+ return 0;
+
+free_regs:
+ for (i--; i >= 0; i--)
+ regulator_put(icd->soc_regulators[i]);
+err:
+ return ret;
+}
+
+static int soc_camera_power_set(struct soc_camera_device *icd,
+ struct soc_camera_link *icl,
+ int power_on)
+{
+ int ret, i;
+
+ for (i = 0; i < icd->num_soc_regulators; i++) {
+ if (power_on) {
+ ret = regulator_set_voltage(icd->soc_regulators[i],
+ icl->soc_regulator_descs[i].value_on_min,
+ icl->soc_regulator_descs[i].value_on_max);
+ if (ret) {
+ dev_err(icd->pdev, "Cannot set '%s' to %d:%d",
+ icl->soc_regulator_descs[i].supply,
+ icl->soc_regulator_descs[i].value_on_min,
+ icl->soc_regulator_descs[i].value_on_max);
+ goto err;
+ }
+
+ ret = regulator_enable(icd->soc_regulators[i]);
+ if (ret < 0) {
+ dev_err(icd->pdev, "Cannot enable reg '%s'",
+ icl->soc_regulator_descs[i].supply);
+ goto err;
+ }
+ } else {
+ ret = regulator_disable(icd->soc_regulators[i]);
+ if (ret) {
+ dev_err(icd->pdev, "Cannot disable reg '%s'",
+ icl->soc_regulator_descs[i].supply);
+ goto err;
+ }
+ }
+ }
+
+ if (icl->power) {
+ ret = icl->power(icd->pdev, power_on);
+ if (ret < 0) {
+ dev_err(icd->pdev,
+ "Platform failed to power-%s the camera.\n",
+ power_on ? "ON" : "OFF");
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ return ret;
+}
+
const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
struct soc_camera_device *icd, unsigned int fourcc)
{
@@ -375,11 +465,9 @@ static int soc_camera_open(struct file *file)
},
};
- if (icl->power) {
- ret = icl->power(icd->pdev, 1);
- if (ret < 0)
- goto epower;
- }
+ ret = soc_camera_power_set(icd, icl, 1);
+ if (ret < 0)
+ goto epower;
/* The camera could have been already on, try to reset */
if (icl->reset)
@@ -425,8 +513,7 @@ esfmt:
eresume:
ici->ops->remove(icd);
eiciadd:
- if (icl->power)
- icl->power(icd->pdev, 0);
+ soc_camera_power_set(icd, icl, 0);
epower:
icd->use_count--;
mutex_unlock(&icd->video_lock);
@@ -450,8 +537,7 @@ static int soc_camera_close(struct file *file)
ici->ops->remove(icd);
- if (icl->power)
- icl->power(icd->pdev, 0);
+ soc_camera_power_set(icd, icl, 0);
}
if (icd->streamer == file)
@@ -937,18 +1023,18 @@ static int soc_camera_probe(struct device *dev)
struct device *control = NULL;
struct v4l2_subdev *sd;
struct v4l2_mbus_framefmt mf;
- int ret;
+ int ret = 0, i;
dev_info(dev, "Probing %s\n", dev_name(dev));
- if (icl->power) {
- ret = icl->power(icd->pdev, 1);
- if (ret < 0) {
- dev_err(dev,
- "Platform failed to power-on the camera.\n");
- goto epower;
- }
- }
+ if (icl->num_soc_regulator_descs)
+ ret = soc_camera_setup_regulators(icd, icl);
+ if (ret)
+ goto err;
+
+ ret = soc_camera_power_set(icd, icl, 1);
+ if (ret < 0)
+ goto epower;
/* The camera could have been already on, try to reset */
if (icl->reset)
@@ -1021,8 +1107,7 @@ static int soc_camera_probe(struct device *dev)
ici->ops->remove(icd);
- if (icl->power)
- icl->power(icd->pdev, 0);
+ soc_camera_power_set(icd, icl, 0);
mutex_unlock(&icd->video_lock);
@@ -1044,9 +1129,11 @@ eadddev:
evdc:
ici->ops->remove(icd);
eadd:
- if (icl->power)
- icl->power(icd->pdev, 0);
+ soc_camera_power_set(icd, icl, 0);
epower:
+ for (i = icd->num_soc_regulators; i >= 0; i--)
+ regulator_put(icd->soc_regulators[i]);
+err:
return ret;
}
@@ -1059,6 +1146,7 @@ static int soc_camera_remove(struct device *dev)
struct soc_camera_device *icd = to_soc_camera_dev(dev);
struct soc_camera_link *icl = to_soc_camera_link(icd);
struct video_device *vdev = icd->vdev;
+ int i;
BUG_ON(!dev->parent);
@@ -1081,6 +1169,9 @@ static int soc_camera_remove(struct device *dev)
}
soc_camera_free_user_formats(icd);
+ for (i = icd->num_soc_regulators; i >= 0; i--)
+ regulator_put(icd->soc_regulators[i]);
+
return 0;
}
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index 86e3631..ae589a4 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -15,6 +15,7 @@
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/pm.h>
+#include <linux/regulator/consumer.h>
#include <linux/videodev2.h>
#include <media/videobuf-core.h>
#include <media/v4l2-device.h>
@@ -45,6 +46,8 @@ struct soc_camera_device {
struct mutex video_lock; /* Protects device data */
struct file *streamer; /* stream owner */
struct videobuf_queue vb_vidq;
+ struct regulator **soc_regulators;
+ int num_soc_regulators;
};
struct soc_camera_host {
@@ -96,6 +99,15 @@ struct soc_camera_host_ops {
#define SOCAM_SENSOR_INVERT_VSYNC (1 << 3)
#define SOCAM_SENSOR_INVERT_DATA (1 << 4)
+struct soc_camera_regulator_desc {
+ const char *supply;
+ int value_on_min;
+ int value_on_max;
+};
+
+#define SOCAM_REG_DESC(s, min, max) \
+ { .supply = s , .value_on_min = min , .value_on_max = max }
+
struct i2c_board_info;
struct soc_camera_link {
@@ -108,6 +120,10 @@ struct soc_camera_link {
const char *module_name;
void *priv;
+ /* Optional regulators that have to be managed on power on/off events */
+ struct soc_camera_regulator_desc *soc_regulator_descs;
+ int num_soc_regulator_descs;
+
/*
* For non-I2C devices platform platform has to provide methods to
* add a device to the system and to remove
--
1.6.3.3
next reply other threads:[~2010-11-28 17:18 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-11-28 17:18 Alberto Panizzo [this message]
2010-11-28 17:24 ` [PATCH 2/3] mx3_camera: Support correctly the YUV222 and BAYER configurations of CSI Alberto Panizzo
2010-11-28 17:26 ` [PATCH 3/3] V4L2: Add a v4l2-subdev (soc-camera) driver for OmniVision OV2640 sensor Alberto Panizzo
2010-12-01 23:32 ` Guennadi Liakhovetski
2010-12-02 10:33 ` Alberto Panizzo
2010-12-02 14:53 ` [PATCH v2] " Alberto Panizzo
2010-11-30 14:25 ` [PATCH 2/3] mx3_camera: Support correctly the YUV222 and BAYER configurations of CSI Alberto Panizzo
2010-11-30 14:31 ` Guennadi Liakhovetski
2010-11-30 14:39 ` Alberto Panizzo
2010-12-01 18:54 ` Guennadi Liakhovetski
2010-12-18 16:24 ` Guennadi Liakhovetski
2010-12-30 19:38 ` Guennadi Liakhovetski
2011-01-03 11:46 ` Alberto Panizzo
2011-01-03 17:33 ` Alberto Panizzo
2011-01-03 19:37 ` Guennadi Liakhovetski
2011-01-03 22:07 ` Alberto Panizzo
2011-01-11 17:29 ` Alberto Panizzo
2011-01-12 11:13 ` [PATCH 0/2] Fix the way mx3_camera manage non 8-bpp pixel formats Alberto Panizzo
2011-01-12 11:16 ` [PATCH 1/2] soc_mediabus: export a useful method to obtain the number of samples that makes up a pixel format Alberto Panizzo
2011-01-12 11:20 ` [PATCH 2/2] Fix capture issues for non 8-bit per pixel formats Alberto Panizzo
2011-01-15 21:35 ` Guennadi Liakhovetski
2011-01-17 9:41 ` Alberto Panizzo
2011-01-17 9:52 ` [PATCH 2/2 v2] " Alberto Panizzo
2011-01-03 16:06 ` [PATCH 2/3] mx3_camera: Support correctly the YUV222 and BAYER configurations of CSI Alberto Panizzo
2011-01-03 16:24 ` Guennadi Liakhovetski
2010-11-28 19:05 ` [PATCH 1/3] soc_camera: Add the ability to bind regulators to soc_camedra devices Guennadi Liakhovetski
2010-11-29 9:34 ` Alberto Panizzo
2010-11-29 15:51 ` Mark Brown
2010-11-30 10:45 ` Alberto Panizzo
2010-11-30 11:05 ` Mark Brown
2010-11-29 15:44 ` Mark Brown
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=1290964687.3016.5.camel@realization \
--to=maramaopercheseimorto@gmail.com \
--cc=damm@opensource.se \
--cc=g.liakhovetski@gmx.de \
--cc=hverkuil@xs4all.nl \
--cc=laurent.pinchart@ideasonboard.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=mchehab@infradead.org \
--cc=nm127@freemail.hu \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.