[media] soc_camera: Add the ability to bind regulators to soc_camedra devices
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. Signed-off-by: Alberto Panizzo <maramaopercheseimorto@gmail.com> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
3153ac9c62
commit
96e442c1b2
2 changed files with 70 additions and 21 deletions
|
@ -24,6 +24,7 @@
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/regulator/consumer.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/vmalloc.h>
|
#include <linux/vmalloc.h>
|
||||||
|
@ -43,6 +44,51 @@ static LIST_HEAD(hosts);
|
||||||
static LIST_HEAD(devices);
|
static LIST_HEAD(devices);
|
||||||
static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */
|
static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */
|
||||||
|
|
||||||
|
static int soc_camera_power_set(struct soc_camera_device *icd,
|
||||||
|
struct soc_camera_link *icl,
|
||||||
|
int power_on)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (power_on) {
|
||||||
|
ret = regulator_bulk_enable(icl->num_regulators,
|
||||||
|
icl->regulators);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(&icd->dev, "Cannot enable regulators\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (icl->power)
|
||||||
|
ret = icl->power(icd->pdev, power_on);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(&icd->dev,
|
||||||
|
"Platform failed to power-on the camera.\n");
|
||||||
|
|
||||||
|
regulator_bulk_disable(icl->num_regulators,
|
||||||
|
icl->regulators);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = 0;
|
||||||
|
if (icl->power)
|
||||||
|
ret = icl->power(icd->pdev, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(&icd->dev,
|
||||||
|
"Platform failed to power-off the camera.\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = regulator_bulk_disable(icl->num_regulators,
|
||||||
|
icl->regulators);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(&icd->dev, "Cannot disable regulators\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
|
const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
|
||||||
struct soc_camera_device *icd, unsigned int fourcc)
|
struct soc_camera_device *icd, unsigned int fourcc)
|
||||||
{
|
{
|
||||||
|
@ -369,11 +415,9 @@ static int soc_camera_open(struct file *file)
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (icl->power) {
|
ret = soc_camera_power_set(icd, icl, 1);
|
||||||
ret = icl->power(icd->pdev, 1);
|
if (ret < 0)
|
||||||
if (ret < 0)
|
goto epower;
|
||||||
goto epower;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The camera could have been already on, try to reset */
|
/* The camera could have been already on, try to reset */
|
||||||
if (icl->reset)
|
if (icl->reset)
|
||||||
|
@ -417,8 +461,7 @@ esfmt:
|
||||||
eresume:
|
eresume:
|
||||||
ici->ops->remove(icd);
|
ici->ops->remove(icd);
|
||||||
eiciadd:
|
eiciadd:
|
||||||
if (icl->power)
|
soc_camera_power_set(icd, icl, 0);
|
||||||
icl->power(icd->pdev, 0);
|
|
||||||
epower:
|
epower:
|
||||||
icd->use_count--;
|
icd->use_count--;
|
||||||
module_put(ici->ops->owner);
|
module_put(ici->ops->owner);
|
||||||
|
@ -440,8 +483,7 @@ static int soc_camera_close(struct file *file)
|
||||||
|
|
||||||
ici->ops->remove(icd);
|
ici->ops->remove(icd);
|
||||||
|
|
||||||
if (icl->power)
|
soc_camera_power_set(icd, icl, 0);
|
||||||
icl->power(icd->pdev, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (icd->streamer == file)
|
if (icd->streamer == file)
|
||||||
|
@ -908,14 +950,14 @@ static int soc_camera_probe(struct device *dev)
|
||||||
|
|
||||||
dev_info(dev, "Probing %s\n", dev_name(dev));
|
dev_info(dev, "Probing %s\n", dev_name(dev));
|
||||||
|
|
||||||
if (icl->power) {
|
ret = regulator_bulk_get(icd->pdev, icl->num_regulators,
|
||||||
ret = icl->power(icd->pdev, 1);
|
icl->regulators);
|
||||||
if (ret < 0) {
|
if (ret < 0)
|
||||||
dev_err(dev,
|
goto ereg;
|
||||||
"Platform failed to power-on the camera.\n");
|
|
||||||
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 */
|
/* The camera could have been already on, try to reset */
|
||||||
if (icl->reset)
|
if (icl->reset)
|
||||||
|
@ -994,8 +1036,7 @@ static int soc_camera_probe(struct device *dev)
|
||||||
|
|
||||||
ici->ops->remove(icd);
|
ici->ops->remove(icd);
|
||||||
|
|
||||||
if (icl->power)
|
soc_camera_power_set(icd, icl, 0);
|
||||||
icl->power(icd->pdev, 0);
|
|
||||||
|
|
||||||
mutex_unlock(&icd->video_lock);
|
mutex_unlock(&icd->video_lock);
|
||||||
|
|
||||||
|
@ -1017,9 +1058,10 @@ eadddev:
|
||||||
evdc:
|
evdc:
|
||||||
ici->ops->remove(icd);
|
ici->ops->remove(icd);
|
||||||
eadd:
|
eadd:
|
||||||
if (icl->power)
|
soc_camera_power_set(icd, icl, 0);
|
||||||
icl->power(icd->pdev, 0);
|
|
||||||
epower:
|
epower:
|
||||||
|
regulator_bulk_free(icl->num_regulators, icl->regulators);
|
||||||
|
ereg:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1052,6 +1094,8 @@ static int soc_camera_remove(struct device *dev)
|
||||||
}
|
}
|
||||||
soc_camera_free_user_formats(icd);
|
soc_camera_free_user_formats(icd);
|
||||||
|
|
||||||
|
regulator_bulk_free(icl->num_regulators, icl->regulators);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,7 @@ struct soc_camera_host_ops {
|
||||||
#define SOCAM_SENSOR_INVERT_DATA (1 << 4)
|
#define SOCAM_SENSOR_INVERT_DATA (1 << 4)
|
||||||
|
|
||||||
struct i2c_board_info;
|
struct i2c_board_info;
|
||||||
|
struct regulator_bulk_data;
|
||||||
|
|
||||||
struct soc_camera_link {
|
struct soc_camera_link {
|
||||||
/* Camera bus id, used to match a camera and a bus */
|
/* Camera bus id, used to match a camera and a bus */
|
||||||
|
@ -108,6 +109,10 @@ struct soc_camera_link {
|
||||||
const char *module_name;
|
const char *module_name;
|
||||||
void *priv;
|
void *priv;
|
||||||
|
|
||||||
|
/* Optional regulators that have to be managed on power on/off events */
|
||||||
|
struct regulator_bulk_data *regulators;
|
||||||
|
int num_regulators;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For non-I2C devices platform platform has to provide methods to
|
* For non-I2C devices platform platform has to provide methods to
|
||||||
* add a device to the system and to remove
|
* add a device to the system and to remove
|
||||||
|
|
Loading…
Reference in a new issue