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 | |
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 | |
19 | void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi, |
20 | const struct v4l2_subdev_ops *ops) |
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, p: spi); |
29 | spi_set_drvdata(spi, data: sd); |
30 | /* initialize name */ |
31 | snprintf(buf: sd->name, size: sizeof(sd->name), fmt: "%s %s" , |
32 | spi->dev.driver->name, dev_name(dev: &spi->dev)); |
33 | } |
34 | EXPORT_SYMBOL_GPL(v4l2_spi_subdev_init); |
35 | |
36 | struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev, |
37 | struct spi_controller *ctlr, |
38 | struct spi_board_info *info) |
39 | { |
40 | struct v4l2_subdev *sd = NULL; |
41 | struct spi_device *spi = NULL; |
42 | |
43 | if (!v4l2_dev) |
44 | return NULL; |
45 | if (info->modalias[0]) |
46 | request_module(info->modalias); |
47 | |
48 | spi = spi_new_device(ctlr, info); |
49 | |
50 | if (!spi || !spi->dev.driver) |
51 | goto error; |
52 | |
53 | if (!try_module_get(module: spi->dev.driver->owner)) |
54 | goto error; |
55 | |
56 | sd = spi_get_drvdata(spi); |
57 | |
58 | /* |
59 | * Register with the v4l2_device which increases the module's |
60 | * use count as well. |
61 | */ |
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(module: spi->dev.driver->owner); |
67 | |
68 | error: |
69 | /* |
70 | * If we have a client but no subdev, then something went wrong and |
71 | * we must unregister the client. |
72 | */ |
73 | if (!sd) |
74 | spi_unregister_device(spi); |
75 | |
76 | return sd; |
77 | } |
78 | EXPORT_SYMBOL_GPL(v4l2_spi_new_subdev); |
79 | |