diff options
Diffstat (limited to 'drivers/media/video/soc_camera.c')
-rw-r--r-- | drivers/media/video/soc_camera.c | 106 |
1 files changed, 76 insertions, 30 deletions
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 0e890cc23377..16f595d4337a 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c | |||
@@ -16,19 +16,21 @@ | |||
16 | * published by the Free Software Foundation. | 16 | * published by the Free Software Foundation. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/device.h> | 19 | #include <linux/device.h> |
22 | #include <linux/list.h> | ||
23 | #include <linux/err.h> | 20 | #include <linux/err.h> |
21 | #include <linux/i2c.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/list.h> | ||
24 | #include <linux/module.h> | ||
24 | #include <linux/mutex.h> | 25 | #include <linux/mutex.h> |
26 | #include <linux/platform_device.h> | ||
25 | #include <linux/vmalloc.h> | 27 | #include <linux/vmalloc.h> |
26 | 28 | ||
29 | #include <media/soc_camera.h> | ||
27 | #include <media/v4l2-common.h> | 30 | #include <media/v4l2-common.h> |
28 | #include <media/v4l2-ioctl.h> | ||
29 | #include <media/v4l2-dev.h> | 31 | #include <media/v4l2-dev.h> |
32 | #include <media/v4l2-ioctl.h> | ||
30 | #include <media/videobuf-core.h> | 33 | #include <media/videobuf-core.h> |
31 | #include <media/soc_camera.h> | ||
32 | 34 | ||
33 | /* Default to VGA resolution */ | 35 | /* Default to VGA resolution */ |
34 | #define DEFAULT_WIDTH 640 | 36 | #define DEFAULT_WIDTH 640 |
@@ -279,7 +281,7 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf, | |||
279 | return ret; | 281 | return ret; |
280 | } else if (!icd->current_fmt || | 282 | } else if (!icd->current_fmt || |
281 | icd->current_fmt->fourcc != pix->pixelformat) { | 283 | icd->current_fmt->fourcc != pix->pixelformat) { |
282 | dev_err(&ici->dev, | 284 | dev_err(ici->dev, |
283 | "Host driver hasn't set up current format correctly!\n"); | 285 | "Host driver hasn't set up current format correctly!\n"); |
284 | return -EINVAL; | 286 | return -EINVAL; |
285 | } | 287 | } |
@@ -794,7 +796,7 @@ static void scan_add_host(struct soc_camera_host *ici) | |||
794 | 796 | ||
795 | list_for_each_entry(icd, &devices, list) { | 797 | list_for_each_entry(icd, &devices, list) { |
796 | if (icd->iface == ici->nr) { | 798 | if (icd->iface == ici->nr) { |
797 | icd->dev.parent = &ici->dev; | 799 | icd->dev.parent = ici->dev; |
798 | device_register_link(icd); | 800 | device_register_link(icd); |
799 | } | 801 | } |
800 | } | 802 | } |
@@ -818,7 +820,7 @@ static int scan_add_device(struct soc_camera_device *icd) | |||
818 | list_for_each_entry(ici, &hosts, list) { | 820 | list_for_each_entry(ici, &hosts, list) { |
819 | if (icd->iface == ici->nr) { | 821 | if (icd->iface == ici->nr) { |
820 | ret = 1; | 822 | ret = 1; |
821 | icd->dev.parent = &ici->dev; | 823 | icd->dev.parent = ici->dev; |
822 | break; | 824 | break; |
823 | } | 825 | } |
824 | } | 826 | } |
@@ -952,7 +954,6 @@ static void dummy_release(struct device *dev) | |||
952 | 954 | ||
953 | int soc_camera_host_register(struct soc_camera_host *ici) | 955 | int soc_camera_host_register(struct soc_camera_host *ici) |
954 | { | 956 | { |
955 | int ret; | ||
956 | struct soc_camera_host *ix; | 957 | struct soc_camera_host *ix; |
957 | 958 | ||
958 | if (!ici || !ici->ops || | 959 | if (!ici || !ici->ops || |
@@ -965,12 +966,10 @@ int soc_camera_host_register(struct soc_camera_host *ici) | |||
965 | !ici->ops->reqbufs || | 966 | !ici->ops->reqbufs || |
966 | !ici->ops->add || | 967 | !ici->ops->add || |
967 | !ici->ops->remove || | 968 | !ici->ops->remove || |
968 | !ici->ops->poll) | 969 | !ici->ops->poll || |
970 | !ici->dev) | ||
969 | return -EINVAL; | 971 | return -EINVAL; |
970 | 972 | ||
971 | /* Number might be equal to the platform device ID */ | ||
972 | dev_set_name(&ici->dev, "camera_host%d", ici->nr); | ||
973 | |||
974 | mutex_lock(&list_lock); | 973 | mutex_lock(&list_lock); |
975 | list_for_each_entry(ix, &hosts, list) { | 974 | list_for_each_entry(ix, &hosts, list) { |
976 | if (ix->nr == ici->nr) { | 975 | if (ix->nr == ici->nr) { |
@@ -979,26 +978,14 @@ int soc_camera_host_register(struct soc_camera_host *ici) | |||
979 | } | 978 | } |
980 | } | 979 | } |
981 | 980 | ||
981 | dev_set_drvdata(ici->dev, ici); | ||
982 | |||
982 | list_add_tail(&ici->list, &hosts); | 983 | list_add_tail(&ici->list, &hosts); |
983 | mutex_unlock(&list_lock); | 984 | mutex_unlock(&list_lock); |
984 | 985 | ||
985 | ici->dev.release = dummy_release; | ||
986 | |||
987 | ret = device_register(&ici->dev); | ||
988 | |||
989 | if (ret) | ||
990 | goto edevr; | ||
991 | |||
992 | scan_add_host(ici); | 986 | scan_add_host(ici); |
993 | 987 | ||
994 | return 0; | 988 | return 0; |
995 | |||
996 | edevr: | ||
997 | mutex_lock(&list_lock); | ||
998 | list_del(&ici->list); | ||
999 | mutex_unlock(&list_lock); | ||
1000 | |||
1001 | return ret; | ||
1002 | } | 989 | } |
1003 | EXPORT_SYMBOL(soc_camera_host_register); | 990 | EXPORT_SYMBOL(soc_camera_host_register); |
1004 | 991 | ||
@@ -1012,7 +999,7 @@ void soc_camera_host_unregister(struct soc_camera_host *ici) | |||
1012 | list_del(&ici->list); | 999 | list_del(&ici->list); |
1013 | 1000 | ||
1014 | list_for_each_entry(icd, &devices, list) { | 1001 | list_for_each_entry(icd, &devices, list) { |
1015 | if (icd->dev.parent == &ici->dev) { | 1002 | if (icd->dev.parent == ici->dev) { |
1016 | device_unregister(&icd->dev); | 1003 | device_unregister(&icd->dev); |
1017 | /* Not before device_unregister(), .remove | 1004 | /* Not before device_unregister(), .remove |
1018 | * needs parent to call ici->ops->remove() */ | 1005 | * needs parent to call ici->ops->remove() */ |
@@ -1023,7 +1010,7 @@ void soc_camera_host_unregister(struct soc_camera_host *ici) | |||
1023 | 1010 | ||
1024 | mutex_unlock(&list_lock); | 1011 | mutex_unlock(&list_lock); |
1025 | 1012 | ||
1026 | device_unregister(&ici->dev); | 1013 | dev_set_drvdata(ici->dev, NULL); |
1027 | } | 1014 | } |
1028 | EXPORT_SYMBOL(soc_camera_host_unregister); | 1015 | EXPORT_SYMBOL(soc_camera_host_unregister); |
1029 | 1016 | ||
@@ -1130,7 +1117,7 @@ int soc_camera_video_start(struct soc_camera_device *icd) | |||
1130 | vdev = video_device_alloc(); | 1117 | vdev = video_device_alloc(); |
1131 | if (!vdev) | 1118 | if (!vdev) |
1132 | goto evidallocd; | 1119 | goto evidallocd; |
1133 | dev_dbg(&ici->dev, "Allocated video_device %p\n", vdev); | 1120 | dev_dbg(ici->dev, "Allocated video_device %p\n", vdev); |
1134 | 1121 | ||
1135 | strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name)); | 1122 | strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name)); |
1136 | 1123 | ||
@@ -1174,6 +1161,57 @@ void soc_camera_video_stop(struct soc_camera_device *icd) | |||
1174 | } | 1161 | } |
1175 | EXPORT_SYMBOL(soc_camera_video_stop); | 1162 | EXPORT_SYMBOL(soc_camera_video_stop); |
1176 | 1163 | ||
1164 | static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev) | ||
1165 | { | ||
1166 | struct soc_camera_link *icl = pdev->dev.platform_data; | ||
1167 | struct i2c_adapter *adap; | ||
1168 | struct i2c_client *client; | ||
1169 | |||
1170 | if (!icl) | ||
1171 | return -EINVAL; | ||
1172 | |||
1173 | adap = i2c_get_adapter(icl->i2c_adapter_id); | ||
1174 | if (!adap) { | ||
1175 | dev_warn(&pdev->dev, "Cannot get adapter #%d. No driver?\n", | ||
1176 | icl->i2c_adapter_id); | ||
1177 | /* -ENODEV and -ENXIO do not produce an error on probe()... */ | ||
1178 | return -ENOENT; | ||
1179 | } | ||
1180 | |||
1181 | icl->board_info->platform_data = icl; | ||
1182 | client = i2c_new_device(adap, icl->board_info); | ||
1183 | if (!client) { | ||
1184 | i2c_put_adapter(adap); | ||
1185 | return -ENOMEM; | ||
1186 | } | ||
1187 | |||
1188 | platform_set_drvdata(pdev, client); | ||
1189 | |||
1190 | return 0; | ||
1191 | } | ||
1192 | |||
1193 | static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev) | ||
1194 | { | ||
1195 | struct i2c_client *client = platform_get_drvdata(pdev); | ||
1196 | |||
1197 | if (!client) | ||
1198 | return -ENODEV; | ||
1199 | |||
1200 | i2c_unregister_device(client); | ||
1201 | i2c_put_adapter(client->adapter); | ||
1202 | |||
1203 | return 0; | ||
1204 | } | ||
1205 | |||
1206 | static struct platform_driver __refdata soc_camera_pdrv = { | ||
1207 | .probe = soc_camera_pdrv_probe, | ||
1208 | .remove = __devexit_p(soc_camera_pdrv_remove), | ||
1209 | .driver = { | ||
1210 | .name = "soc-camera-pdrv", | ||
1211 | .owner = THIS_MODULE, | ||
1212 | }, | ||
1213 | }; | ||
1214 | |||
1177 | static int __init soc_camera_init(void) | 1215 | static int __init soc_camera_init(void) |
1178 | { | 1216 | { |
1179 | int ret = bus_register(&soc_camera_bus_type); | 1217 | int ret = bus_register(&soc_camera_bus_type); |
@@ -1183,8 +1221,14 @@ static int __init soc_camera_init(void) | |||
1183 | if (ret) | 1221 | if (ret) |
1184 | goto edrvr; | 1222 | goto edrvr; |
1185 | 1223 | ||
1224 | ret = platform_driver_register(&soc_camera_pdrv); | ||
1225 | if (ret) | ||
1226 | goto epdr; | ||
1227 | |||
1186 | return 0; | 1228 | return 0; |
1187 | 1229 | ||
1230 | epdr: | ||
1231 | driver_unregister(&ic_drv); | ||
1188 | edrvr: | 1232 | edrvr: |
1189 | bus_unregister(&soc_camera_bus_type); | 1233 | bus_unregister(&soc_camera_bus_type); |
1190 | return ret; | 1234 | return ret; |
@@ -1192,6 +1236,7 @@ edrvr: | |||
1192 | 1236 | ||
1193 | static void __exit soc_camera_exit(void) | 1237 | static void __exit soc_camera_exit(void) |
1194 | { | 1238 | { |
1239 | platform_driver_unregister(&soc_camera_pdrv); | ||
1195 | driver_unregister(&ic_drv); | 1240 | driver_unregister(&ic_drv); |
1196 | bus_unregister(&soc_camera_bus_type); | 1241 | bus_unregister(&soc_camera_bus_type); |
1197 | } | 1242 | } |
@@ -1202,3 +1247,4 @@ module_exit(soc_camera_exit); | |||
1202 | MODULE_DESCRIPTION("Image capture bus driver"); | 1247 | MODULE_DESCRIPTION("Image capture bus driver"); |
1203 | MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>"); | 1248 | MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>"); |
1204 | MODULE_LICENSE("GPL"); | 1249 | MODULE_LICENSE("GPL"); |
1250 | MODULE_ALIAS("platform:soc-camera-pdrv"); | ||