[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/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
@ -43,6 +44,51 @@ static LIST_HEAD(hosts);
|
|||
static LIST_HEAD(devices);
|
||||
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(
|
||||
struct soc_camera_device *icd, unsigned int fourcc)
|
||||
{
|
||||
|
@ -369,11 +415,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)
|
||||
|
@ -417,8 +461,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--;
|
||||
module_put(ici->ops->owner);
|
||||
|
@ -440,8 +483,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)
|
||||
|
@ -908,14 +950,14 @@ static int soc_camera_probe(struct device *dev)
|
|||
|
||||
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;
|
||||
}
|
||||
}
|
||||
ret = regulator_bulk_get(icd->pdev, icl->num_regulators,
|
||||
icl->regulators);
|
||||
if (ret < 0)
|
||||
goto ereg;
|
||||
|
||||
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)
|
||||
|
@ -994,8 +1036,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);
|
||||
|
||||
|
@ -1017,9 +1058,10 @@ eadddev:
|
|||
evdc:
|
||||
ici->ops->remove(icd);
|
||||
eadd:
|
||||
if (icl->power)
|
||||
icl->power(icd->pdev, 0);
|
||||
soc_camera_power_set(icd, icl, 0);
|
||||
epower:
|
||||
regulator_bulk_free(icl->num_regulators, icl->regulators);
|
||||
ereg:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1052,6 +1094,8 @@ static int soc_camera_remove(struct device *dev)
|
|||
}
|
||||
soc_camera_free_user_formats(icd);
|
||||
|
||||
regulator_bulk_free(icl->num_regulators, icl->regulators);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -97,6 +97,7 @@ struct soc_camera_host_ops {
|
|||
#define SOCAM_SENSOR_INVERT_DATA (1 << 4)
|
||||
|
||||
struct i2c_board_info;
|
||||
struct regulator_bulk_data;
|
||||
|
||||
struct soc_camera_link {
|
||||
/* Camera bus id, used to match a camera and a bus */
|
||||
|
@ -108,6 +109,10 @@ struct soc_camera_link {
|
|||
const char *module_name;
|
||||
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
|
||||
* add a device to the system and to remove
|
||||
|
|
Loading…
Reference in a new issue