Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 96e442c1 authored by Alberto Panizzo's avatar Alberto Panizzo Committed by Mauro Carvalho Chehab
Browse files

[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: default avatarAlberto Panizzo <maramaopercheseimorto@gmail.com>
Signed-off-by: default avatarGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 3153ac9c
Loading
Loading
Loading
Loading
+65 −21
Original line number Diff line number Diff line
@@ -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);
		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 @@ static int soc_camera_open(struct file *file)
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");
	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 @@ static int soc_camera_probe(struct device *dev)
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;
}

+5 −0
Original line number Diff line number Diff line
@@ -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