diff options
author | Dmitri Belimov <d.belimov@gmail.com> | 2010-03-23 10:23:29 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-05-17 23:50:24 -0400 |
commit | 85e092190b5f7dfe9b78556440472c5590a32b4e (patch) | |
tree | 95b38198c6b048d43fbda277ba6476eb9e8fbd55 | |
parent | 443fed9fa42bbeacdb8d336b8a5002a262cac15c (diff) |
V4L/DVB: Add SPI support to V4L2
Add support SPI bus to v4l2. Useful for control some device with SPI bus like
hardware MPEG2 encoders and etc.
Signed-off-by: Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/video/v4l2-common.c | 63 | ||||
-rw-r--r-- | drivers/media/video/v4l2-device.c | 11 | ||||
-rw-r--r-- | include/media/v4l2-common.h | 19 | ||||
-rw-r--r-- | include/media/v4l2-subdev.h | 2 |
4 files changed, 95 insertions, 0 deletions
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 6a3d0b71f78f..cd1f21d9b079 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c | |||
@@ -51,6 +51,9 @@ | |||
51 | #include <linux/string.h> | 51 | #include <linux/string.h> |
52 | #include <linux/errno.h> | 52 | #include <linux/errno.h> |
53 | #include <linux/i2c.h> | 53 | #include <linux/i2c.h> |
54 | #if defined(CONFIG_SPI) | ||
55 | #include <linux/spi/spi.h> | ||
56 | #endif | ||
54 | #include <asm/uaccess.h> | 57 | #include <asm/uaccess.h> |
55 | #include <asm/system.h> | 58 | #include <asm/system.h> |
56 | #include <asm/pgtable.h> | 59 | #include <asm/pgtable.h> |
@@ -955,6 +958,66 @@ EXPORT_SYMBOL_GPL(v4l2_i2c_tuner_addrs); | |||
955 | 958 | ||
956 | #endif /* defined(CONFIG_I2C) */ | 959 | #endif /* defined(CONFIG_I2C) */ |
957 | 960 | ||
961 | #if defined(CONFIG_SPI) | ||
962 | |||
963 | /* Load a spi sub-device. */ | ||
964 | |||
965 | void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi, | ||
966 | const struct v4l2_subdev_ops *ops) | ||
967 | { | ||
968 | v4l2_subdev_init(sd, ops); | ||
969 | sd->flags |= V4L2_SUBDEV_FL_IS_SPI; | ||
970 | /* the owner is the same as the spi_device's driver owner */ | ||
971 | sd->owner = spi->dev.driver->owner; | ||
972 | /* spi_device and v4l2_subdev point to one another */ | ||
973 | v4l2_set_subdevdata(sd, spi); | ||
974 | spi_set_drvdata(spi, sd); | ||
975 | /* initialize name */ | ||
976 | strlcpy(sd->name, spi->dev.driver->name, sizeof(sd->name)); | ||
977 | } | ||
978 | EXPORT_SYMBOL_GPL(v4l2_spi_subdev_init); | ||
979 | |||
980 | struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev, | ||
981 | struct spi_master *master, struct spi_board_info *info) | ||
982 | { | ||
983 | struct v4l2_subdev *sd = NULL; | ||
984 | struct spi_device *spi = NULL; | ||
985 | |||
986 | BUG_ON(!v4l2_dev); | ||
987 | |||
988 | if (info->modalias) | ||
989 | request_module(info->modalias); | ||
990 | |||
991 | spi = spi_new_device(master, info); | ||
992 | |||
993 | if (spi == NULL || spi->dev.driver == NULL) | ||
994 | goto error; | ||
995 | |||
996 | if (!try_module_get(spi->dev.driver->owner)) | ||
997 | goto error; | ||
998 | |||
999 | sd = spi_get_drvdata(spi); | ||
1000 | |||
1001 | /* Register with the v4l2_device which increases the module's | ||
1002 | use count as well. */ | ||
1003 | if (v4l2_device_register_subdev(v4l2_dev, sd)) | ||
1004 | sd = NULL; | ||
1005 | |||
1006 | /* Decrease the module use count to match the first try_module_get. */ | ||
1007 | module_put(spi->dev.driver->owner); | ||
1008 | |||
1009 | error: | ||
1010 | /* If we have a client but no subdev, then something went wrong and | ||
1011 | we must unregister the client. */ | ||
1012 | if (spi && sd == NULL) | ||
1013 | spi_unregister_device(spi); | ||
1014 | |||
1015 | return sd; | ||
1016 | } | ||
1017 | EXPORT_SYMBOL_GPL(v4l2_spi_new_subdev); | ||
1018 | |||
1019 | #endif /* defined(CONFIG_SPI) */ | ||
1020 | |||
958 | /* Clamp x to be between min and max, aligned to a multiple of 2^align. min | 1021 | /* Clamp x to be between min and max, aligned to a multiple of 2^align. min |
959 | * and max don't have to be aligned, but there must be at least one valid | 1022 | * and max don't have to be aligned, but there must be at least one valid |
960 | * value. E.g., min=17,max=31,align=4 is not allowed as there are no multiples | 1023 | * value. E.g., min=17,max=31,align=4 is not allowed as there are no multiples |
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index 0d06e7cbd5b3..5a7dc4afe92a 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c | |||
@@ -21,6 +21,9 @@ | |||
21 | #include <linux/types.h> | 21 | #include <linux/types.h> |
22 | #include <linux/ioctl.h> | 22 | #include <linux/ioctl.h> |
23 | #include <linux/i2c.h> | 23 | #include <linux/i2c.h> |
24 | #if defined(CONFIG_SPI) | ||
25 | #include <linux/spi/spi.h> | ||
26 | #endif | ||
24 | #include <linux/videodev2.h> | 27 | #include <linux/videodev2.h> |
25 | #include <media/v4l2-device.h> | 28 | #include <media/v4l2-device.h> |
26 | 29 | ||
@@ -97,6 +100,14 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev) | |||
97 | i2c_unregister_device(client); | 100 | i2c_unregister_device(client); |
98 | } | 101 | } |
99 | #endif | 102 | #endif |
103 | #if defined(CONFIG_SPI) | ||
104 | if (sd->flags & V4L2_SUBDEV_FL_IS_SPI) { | ||
105 | struct spi_device *spi = v4l2_get_subdevdata(sd); | ||
106 | |||
107 | if (spi) | ||
108 | spi_unregister_device(spi); | ||
109 | } | ||
110 | #endif | ||
100 | } | 111 | } |
101 | } | 112 | } |
102 | EXPORT_SYMBOL_GPL(v4l2_device_unregister); | 113 | EXPORT_SYMBOL_GPL(v4l2_device_unregister); |
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index 1c7b259f341c..3b2efdc6d065 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h | |||
@@ -184,6 +184,25 @@ const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type); | |||
184 | 184 | ||
185 | /* ------------------------------------------------------------------------- */ | 185 | /* ------------------------------------------------------------------------- */ |
186 | 186 | ||
187 | /* SPI Helper functions */ | ||
188 | #if defined(CONFIG_SPI) | ||
189 | |||
190 | #include <linux/spi/spi.h> | ||
191 | |||
192 | struct spi_device; | ||
193 | |||
194 | /* Load an spi module and return an initialized v4l2_subdev struct. | ||
195 | The client_type argument is the name of the chip that's on the adapter. */ | ||
196 | struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev, | ||
197 | struct spi_master *master, struct spi_board_info *info); | ||
198 | |||
199 | /* Initialize an v4l2_subdev with data from an spi_device struct */ | ||
200 | void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi, | ||
201 | const struct v4l2_subdev_ops *ops); | ||
202 | #endif | ||
203 | |||
204 | /* ------------------------------------------------------------------------- */ | ||
205 | |||
187 | /* Note: these remaining ioctls/structs should be removed as well, but they are | 206 | /* Note: these remaining ioctls/structs should be removed as well, but they are |
188 | still used in tuner-simple.c (TUNER_SET_CONFIG), cx18/ivtv (RESET) and | 207 | still used in tuner-simple.c (TUNER_SET_CONFIG), cx18/ivtv (RESET) and |
189 | v4l2-int-device.h (v4l2_routing). To remove these ioctls some more cleanup | 208 | v4l2-int-device.h (v4l2_routing). To remove these ioctls some more cleanup |
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 2bcdca0a57fc..09758789be02 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h | |||
@@ -387,6 +387,8 @@ struct v4l2_subdev_ops { | |||
387 | 387 | ||
388 | /* Set this flag if this subdev is a i2c device. */ | 388 | /* Set this flag if this subdev is a i2c device. */ |
389 | #define V4L2_SUBDEV_FL_IS_I2C (1U << 0) | 389 | #define V4L2_SUBDEV_FL_IS_I2C (1U << 0) |
390 | /* Set this flag if this subdev is a spi device. */ | ||
391 | #define V4L2_SUBDEV_FL_IS_SPI (1U << 1) | ||
390 | 392 | ||
391 | /* Each instance of a subdev driver should create this struct, either | 393 | /* Each instance of a subdev driver should create this struct, either |
392 | stand-alone or embedded in a larger struct. | 394 | stand-alone or embedded in a larger struct. |