diff options
author | Dmitri Belimov <d.belimov@gmail.com> | 2010-03-23 15:23:29 +0100 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-05-18 05:50:24 +0200 |
commit | 85e092190b5f7dfe9b78556440472c5590a32b4e (patch) | |
tree | 95b38198c6b048d43fbda277ba6476eb9e8fbd55 /drivers/media/video/v4l2-common.c | |
parent | V4L/DVB: em28xx: add em286x/tvp5150 reference design (diff) | |
download | linux-85e092190b5f7dfe9b78556440472c5590a32b4e.tar.xz linux-85e092190b5f7dfe9b78556440472c5590a32b4e.zip |
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>
Diffstat (limited to 'drivers/media/video/v4l2-common.c')
-rw-r--r-- | drivers/media/video/v4l2-common.c | 63 |
1 files changed, 63 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 @@ #include <linux/string.h> #include <linux/errno.h> #include <linux/i2c.h> +#if defined(CONFIG_SPI) +#include <linux/spi/spi.h> +#endif #include <asm/uaccess.h> #include <asm/system.h> #include <asm/pgtable.h> @@ -955,6 +958,66 @@ EXPORT_SYMBOL_GPL(v4l2_i2c_tuner_addrs); #endif /* defined(CONFIG_I2C) */ +#if defined(CONFIG_SPI) + +/* Load a spi sub-device. */ + +void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi, + const struct v4l2_subdev_ops *ops) +{ + v4l2_subdev_init(sd, ops); + sd->flags |= V4L2_SUBDEV_FL_IS_SPI; + /* the owner is the same as the spi_device's driver owner */ + sd->owner = spi->dev.driver->owner; + /* spi_device and v4l2_subdev point to one another */ + v4l2_set_subdevdata(sd, spi); + spi_set_drvdata(spi, sd); + /* initialize name */ + strlcpy(sd->name, spi->dev.driver->name, sizeof(sd->name)); +} +EXPORT_SYMBOL_GPL(v4l2_spi_subdev_init); + +struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev, + struct spi_master *master, struct spi_board_info *info) +{ + struct v4l2_subdev *sd = NULL; + struct spi_device *spi = NULL; + + BUG_ON(!v4l2_dev); + + if (info->modalias) + request_module(info->modalias); + + spi = spi_new_device(master, info); + + if (spi == NULL || spi->dev.driver == NULL) + goto error; + + if (!try_module_get(spi->dev.driver->owner)) + goto error; + + sd = spi_get_drvdata(spi); + + /* Register with the v4l2_device which increases the module's + use count as well. */ + if (v4l2_device_register_subdev(v4l2_dev, sd)) + sd = NULL; + + /* Decrease the module use count to match the first try_module_get. */ + module_put(spi->dev.driver->owner); + +error: + /* If we have a client but no subdev, then something went wrong and + we must unregister the client. */ + if (spi && sd == NULL) + spi_unregister_device(spi); + + return sd; +} +EXPORT_SYMBOL_GPL(v4l2_spi_new_subdev); + +#endif /* defined(CONFIG_SPI) */ + /* Clamp x to be between min and max, aligned to a multiple of 2^align. min * and max don't have to be aligned, but there must be at least one valid * value. E.g., min=17,max=31,align=4 is not allowed as there are no multiples |