Commit | Line | Data |
---|---|---|
7c795df5 EG |
1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* | |
3 | * v4l2-spi - SPI helpers for Video4Linux2 | |
4 | */ | |
5 | ||
6 | #include <linux/module.h> | |
7 | #include <linux/spi/spi.h> | |
8 | #include <media/v4l2-common.h> | |
9 | #include <media/v4l2-device.h> | |
10 | ||
a9cff393 EG |
11 | void v4l2_spi_subdev_unregister(struct v4l2_subdev *sd) |
12 | { | |
13 | struct spi_device *spi = v4l2_get_subdevdata(sd); | |
14 | ||
15 | if (spi && !spi->dev.of_node && !spi->dev.fwnode) | |
16 | spi_unregister_device(spi); | |
17 | } | |
18 | ||
7c795df5 | 19 | void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi, |
cc14c00c | 20 | const struct v4l2_subdev_ops *ops) |
7c795df5 EG |
21 | { |
22 | v4l2_subdev_init(sd, ops); | |
23 | sd->flags |= V4L2_SUBDEV_FL_IS_SPI; | |
24 | /* the owner is the same as the spi_device's driver owner */ | |
25 | sd->owner = spi->dev.driver->owner; | |
26 | sd->dev = &spi->dev; | |
27 | /* spi_device and v4l2_subdev point to one another */ | |
28 | v4l2_set_subdevdata(sd, spi); | |
29 | spi_set_drvdata(spi, sd); | |
30 | /* initialize name */ | |
31 | snprintf(sd->name, sizeof(sd->name), "%s %s", | |
cc14c00c | 32 | spi->dev.driver->name, dev_name(&spi->dev)); |
7c795df5 EG |
33 | } |
34 | EXPORT_SYMBOL_GPL(v4l2_spi_subdev_init); | |
35 | ||
36 | struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev, | |
cc14c00c MCC |
37 | struct spi_master *master, |
38 | struct spi_board_info *info) | |
7c795df5 EG |
39 | { |
40 | struct v4l2_subdev *sd = NULL; | |
41 | struct spi_device *spi = NULL; | |
42 | ||
1a065ee3 EG |
43 | if (!v4l2_dev) |
44 | return NULL; | |
7c795df5 EG |
45 | if (info->modalias[0]) |
46 | request_module(info->modalias); | |
47 | ||
48 | spi = spi_new_device(master, info); | |
49 | ||
cc14c00c | 50 | if (!spi || !spi->dev.driver) |
7c795df5 EG |
51 | goto error; |
52 | ||
53 | if (!try_module_get(spi->dev.driver->owner)) | |
54 | goto error; | |
55 | ||
56 | sd = spi_get_drvdata(spi); | |
57 | ||
cc14c00c MCC |
58 | /* |
59 | * Register with the v4l2_device which increases the module's | |
60 | * use count as well. | |
61 | */ | |
7c795df5 EG |
62 | if (v4l2_device_register_subdev(v4l2_dev, sd)) |
63 | sd = NULL; | |
64 | ||
65 | /* Decrease the module use count to match the first try_module_get. */ | |
66 | module_put(spi->dev.driver->owner); | |
67 | ||
68 | error: | |
cc14c00c MCC |
69 | /* |
70 | * If we have a client but no subdev, then something went wrong and | |
71 | * we must unregister the client. | |
72 | */ | |
7c795df5 EG |
73 | if (!sd) |
74 | spi_unregister_device(spi); | |
75 | ||
76 | return sd; | |
77 | } | |
78 | EXPORT_SYMBOL_GPL(v4l2_spi_new_subdev); |