diff options
author | Alberto Panizzo <maramaopercheseimorto@gmail.com> | 2010-12-02 05:43:37 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-12-30 19:29:37 -0500 |
commit | 96e442c1b2ef2ba9476e5da2607ba666ce09664d (patch) | |
tree | d0bcf51f63ff89b1740ebd6764492ac5db7e7be6 | |
parent | 3153ac9c6208892ee237caccdbe2290f8247e236 (diff) |
[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>
-rw-r--r-- | drivers/media/video/soc_camera.c | 86 | ||||
-rw-r--r-- | include/media/soc_camera.h | 5 |
2 files changed, 70 insertions, 21 deletions
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index aba4ce92a86b..a66811b43710 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/mutex.h> | 24 | #include <linux/mutex.h> |
25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
27 | #include <linux/regulator/consumer.h> | ||
27 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
28 | #include <linux/pm_runtime.h> | 29 | #include <linux/pm_runtime.h> |
29 | #include <linux/vmalloc.h> | 30 | #include <linux/vmalloc.h> |
@@ -43,6 +44,51 @@ static LIST_HEAD(hosts); | |||
43 | static LIST_HEAD(devices); | 44 | static LIST_HEAD(devices); |
44 | static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ | 45 | static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ |
45 | 46 | ||
47 | static int soc_camera_power_set(struct soc_camera_device *icd, | ||
48 | struct soc_camera_link *icl, | ||
49 | int power_on) | ||
50 | { | ||
51 | int ret; | ||
52 | |||
53 | if (power_on) { | ||
54 | ret = regulator_bulk_enable(icl->num_regulators, | ||
55 | icl->regulators); | ||
56 | if (ret < 0) { | ||
57 | dev_err(&icd->dev, "Cannot enable regulators\n"); | ||
58 | return ret; | ||
59 | } | ||
60 | |||
61 | if (icl->power) | ||
62 | ret = icl->power(icd->pdev, power_on); | ||
63 | if (ret < 0) { | ||
64 | dev_err(&icd->dev, | ||
65 | "Platform failed to power-on the camera.\n"); | ||
66 | |||
67 | regulator_bulk_disable(icl->num_regulators, | ||
68 | icl->regulators); | ||
69 | return ret; | ||
70 | } | ||
71 | } else { | ||
72 | ret = 0; | ||
73 | if (icl->power) | ||
74 | ret = icl->power(icd->pdev, 0); | ||
75 | if (ret < 0) { | ||
76 | dev_err(&icd->dev, | ||
77 | "Platform failed to power-off the camera.\n"); | ||
78 | return ret; | ||
79 | } | ||
80 | |||
81 | ret = regulator_bulk_disable(icl->num_regulators, | ||
82 | icl->regulators); | ||
83 | if (ret < 0) { | ||
84 | dev_err(&icd->dev, "Cannot disable regulators\n"); | ||
85 | return ret; | ||
86 | } | ||
87 | } | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | |||
46 | const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( | 92 | const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( |
47 | struct soc_camera_device *icd, unsigned int fourcc) | 93 | struct soc_camera_device *icd, unsigned int fourcc) |
48 | { | 94 | { |
@@ -369,11 +415,9 @@ static int soc_camera_open(struct file *file) | |||
369 | }, | 415 | }, |
370 | }; | 416 | }; |
371 | 417 | ||
372 | if (icl->power) { | 418 | ret = soc_camera_power_set(icd, icl, 1); |
373 | ret = icl->power(icd->pdev, 1); | 419 | if (ret < 0) |
374 | if (ret < 0) | 420 | goto epower; |
375 | goto epower; | ||
376 | } | ||
377 | 421 | ||
378 | /* The camera could have been already on, try to reset */ | 422 | /* The camera could have been already on, try to reset */ |
379 | if (icl->reset) | 423 | if (icl->reset) |
@@ -417,8 +461,7 @@ esfmt: | |||
417 | eresume: | 461 | eresume: |
418 | ici->ops->remove(icd); | 462 | ici->ops->remove(icd); |
419 | eiciadd: | 463 | eiciadd: |
420 | if (icl->power) | 464 | soc_camera_power_set(icd, icl, 0); |
421 | icl->power(icd->pdev, 0); | ||
422 | epower: | 465 | epower: |
423 | icd->use_count--; | 466 | icd->use_count--; |
424 | module_put(ici->ops->owner); | 467 | module_put(ici->ops->owner); |
@@ -440,8 +483,7 @@ static int soc_camera_close(struct file *file) | |||
440 | 483 | ||
441 | ici->ops->remove(icd); | 484 | ici->ops->remove(icd); |
442 | 485 | ||
443 | if (icl->power) | 486 | soc_camera_power_set(icd, icl, 0); |
444 | icl->power(icd->pdev, 0); | ||
445 | } | 487 | } |
446 | 488 | ||
447 | if (icd->streamer == file) | 489 | if (icd->streamer == file) |
@@ -908,14 +950,14 @@ static int soc_camera_probe(struct device *dev) | |||
908 | 950 | ||
909 | dev_info(dev, "Probing %s\n", dev_name(dev)); | 951 | dev_info(dev, "Probing %s\n", dev_name(dev)); |
910 | 952 | ||
911 | if (icl->power) { | 953 | ret = regulator_bulk_get(icd->pdev, icl->num_regulators, |
912 | ret = icl->power(icd->pdev, 1); | 954 | icl->regulators); |
913 | if (ret < 0) { | 955 | if (ret < 0) |
914 | dev_err(dev, | 956 | goto ereg; |
915 | "Platform failed to power-on the camera.\n"); | 957 | |
916 | goto epower; | 958 | ret = soc_camera_power_set(icd, icl, 1); |
917 | } | 959 | if (ret < 0) |
918 | } | 960 | goto epower; |
919 | 961 | ||
920 | /* The camera could have been already on, try to reset */ | 962 | /* The camera could have been already on, try to reset */ |
921 | if (icl->reset) | 963 | if (icl->reset) |
@@ -994,8 +1036,7 @@ static int soc_camera_probe(struct device *dev) | |||
994 | 1036 | ||
995 | ici->ops->remove(icd); | 1037 | ici->ops->remove(icd); |
996 | 1038 | ||
997 | if (icl->power) | 1039 | soc_camera_power_set(icd, icl, 0); |
998 | icl->power(icd->pdev, 0); | ||
999 | 1040 | ||
1000 | mutex_unlock(&icd->video_lock); | 1041 | mutex_unlock(&icd->video_lock); |
1001 | 1042 | ||
@@ -1017,9 +1058,10 @@ eadddev: | |||
1017 | evdc: | 1058 | evdc: |
1018 | ici->ops->remove(icd); | 1059 | ici->ops->remove(icd); |
1019 | eadd: | 1060 | eadd: |
1020 | if (icl->power) | 1061 | soc_camera_power_set(icd, icl, 0); |
1021 | icl->power(icd->pdev, 0); | ||
1022 | epower: | 1062 | epower: |
1063 | regulator_bulk_free(icl->num_regulators, icl->regulators); | ||
1064 | ereg: | ||
1023 | return ret; | 1065 | return ret; |
1024 | } | 1066 | } |
1025 | 1067 | ||
@@ -1052,6 +1094,8 @@ static int soc_camera_remove(struct device *dev) | |||
1052 | } | 1094 | } |
1053 | soc_camera_free_user_formats(icd); | 1095 | soc_camera_free_user_formats(icd); |
1054 | 1096 | ||
1097 | regulator_bulk_free(icl->num_regulators, icl->regulators); | ||
1098 | |||
1055 | return 0; | 1099 | return 0; |
1056 | } | 1100 | } |
1057 | 1101 | ||
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 86e3631764ef..9386db829fb7 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h | |||
@@ -97,6 +97,7 @@ struct soc_camera_host_ops { | |||
97 | #define SOCAM_SENSOR_INVERT_DATA (1 << 4) | 97 | #define SOCAM_SENSOR_INVERT_DATA (1 << 4) |
98 | 98 | ||
99 | struct i2c_board_info; | 99 | struct i2c_board_info; |
100 | struct regulator_bulk_data; | ||
100 | 101 | ||
101 | struct soc_camera_link { | 102 | struct soc_camera_link { |
102 | /* Camera bus id, used to match a camera and a bus */ | 103 | /* Camera bus id, used to match a camera and a bus */ |
@@ -108,6 +109,10 @@ struct soc_camera_link { | |||
108 | const char *module_name; | 109 | const char *module_name; |
109 | void *priv; | 110 | void *priv; |
110 | 111 | ||
112 | /* Optional regulators that have to be managed on power on/off events */ | ||
113 | struct regulator_bulk_data *regulators; | ||
114 | int num_regulators; | ||
115 | |||
111 | /* | 116 | /* |
112 | * For non-I2C devices platform platform has to provide methods to | 117 | * For non-I2C devices platform platform has to provide methods to |
113 | * add a device to the system and to remove | 118 | * add a device to the system and to remove |