Commit | Line | Data |
---|---|---|
02283b98 EG |
1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* | |
3 | * v4l2-i2c - I2C helpers for Video4Linux2 | |
4 | */ | |
5 | ||
6 | #include <linux/i2c.h> | |
7 | #include <linux/module.h> | |
8 | #include <media/v4l2-common.h> | |
9 | #include <media/v4l2-device.h> | |
10 | ||
51ff392c EG |
11 | void v4l2_i2c_subdev_unregister(struct v4l2_subdev *sd) |
12 | { | |
13 | struct i2c_client *client = v4l2_get_subdevdata(sd); | |
14 | ||
15 | /* | |
16 | * We need to unregister the i2c client | |
17 | * explicitly. We cannot rely on | |
18 | * i2c_del_adapter to always unregister | |
19 | * clients for us, since if the i2c bus is a | |
20 | * platform bus, then it is never deleted. | |
21 | * | |
22 | * Device tree or ACPI based devices must not | |
23 | * be unregistered as they have not been | |
24 | * registered by us, and would not be | |
25 | * re-created by just probing the V4L2 driver. | |
26 | */ | |
27 | if (client && !client->dev.of_node && !client->dev.fwnode) | |
28 | i2c_unregister_device(client); | |
29 | } | |
30 | ||
cc14c00c MCC |
31 | void v4l2_i2c_subdev_set_name(struct v4l2_subdev *sd, |
32 | struct i2c_client *client, | |
02283b98 EG |
33 | const char *devname, const char *postfix) |
34 | { | |
35 | if (!devname) | |
36 | devname = client->dev.driver->name; | |
37 | if (!postfix) | |
38 | postfix = ""; | |
39 | ||
40 | snprintf(sd->name, sizeof(sd->name), "%s%s %d-%04x", devname, postfix, | |
41 | i2c_adapter_id(client->adapter), client->addr); | |
42 | } | |
43 | EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_set_name); | |
44 | ||
45 | void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client, | |
cc14c00c | 46 | const struct v4l2_subdev_ops *ops) |
02283b98 EG |
47 | { |
48 | v4l2_subdev_init(sd, ops); | |
49 | sd->flags |= V4L2_SUBDEV_FL_IS_I2C; | |
50 | /* the owner is the same as the i2c_client's driver owner */ | |
51 | sd->owner = client->dev.driver->owner; | |
52 | sd->dev = &client->dev; | |
53 | /* i2c_client and v4l2_subdev point to one another */ | |
54 | v4l2_set_subdevdata(sd, client); | |
55 | i2c_set_clientdata(client, sd); | |
56 | v4l2_i2c_subdev_set_name(sd, client, NULL, NULL); | |
57 | } | |
58 | EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init); | |
59 | ||
60 | /* Load an i2c sub-device. */ | |
cc14c00c MCC |
61 | struct v4l2_subdev |
62 | *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev, | |
63 | struct i2c_adapter *adapter, | |
64 | struct i2c_board_info *info, | |
65 | const unsigned short *probe_addrs) | |
02283b98 EG |
66 | { |
67 | struct v4l2_subdev *sd = NULL; | |
68 | struct i2c_client *client; | |
69 | ||
1a065ee3 EG |
70 | if (!v4l2_dev) |
71 | return NULL; | |
02283b98 EG |
72 | |
73 | request_module(I2C_MODULE_PREFIX "%s", info->type); | |
74 | ||
75 | /* Create the i2c client */ | |
76 | if (info->addr == 0 && probe_addrs) | |
2e1b100c WS |
77 | client = i2c_new_scanned_device(adapter, info, probe_addrs, |
78 | NULL); | |
02283b98 | 79 | else |
2e1b100c | 80 | client = i2c_new_client_device(adapter, info); |
02283b98 | 81 | |
cc14c00c MCC |
82 | /* |
83 | * Note: by loading the module first we are certain that c->driver | |
84 | * will be set if the driver was found. If the module was not loaded | |
85 | * first, then the i2c core tries to delay-load the module for us, | |
86 | * and then c->driver is still NULL until the module is finally | |
87 | * loaded. This delay-load mechanism doesn't work if other drivers | |
88 | * want to use the i2c device, so explicitly loading the module | |
89 | * is the best alternative. | |
90 | */ | |
2e1b100c | 91 | if (!i2c_client_has_driver(client)) |
02283b98 EG |
92 | goto error; |
93 | ||
94 | /* Lock the module so we can safely get the v4l2_subdev pointer */ | |
95 | if (!try_module_get(client->dev.driver->owner)) | |
96 | goto error; | |
97 | sd = i2c_get_clientdata(client); | |
98 | ||
cc14c00c MCC |
99 | /* |
100 | * Register with the v4l2_device which increases the module's | |
101 | * use count as well. | |
102 | */ | |
02283b98 EG |
103 | if (v4l2_device_register_subdev(v4l2_dev, sd)) |
104 | sd = NULL; | |
105 | /* Decrease the module use count to match the first try_module_get. */ | |
106 | module_put(client->dev.driver->owner); | |
107 | ||
108 | error: | |
cc14c00c MCC |
109 | /* |
110 | * If we have a client but no subdev, then something went wrong and | |
111 | * we must unregister the client. | |
112 | */ | |
2e1b100c | 113 | if (!IS_ERR(client) && !sd) |
02283b98 EG |
114 | i2c_unregister_device(client); |
115 | return sd; | |
116 | } | |
117 | EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board); | |
118 | ||
119 | struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev, | |
cc14c00c MCC |
120 | struct i2c_adapter *adapter, |
121 | const char *client_type, | |
122 | u8 addr, | |
123 | const unsigned short *probe_addrs) | |
02283b98 EG |
124 | { |
125 | struct i2c_board_info info; | |
126 | ||
cc14c00c MCC |
127 | /* |
128 | * Setup the i2c board info with the device type and | |
129 | * the device address. | |
130 | */ | |
02283b98 EG |
131 | memset(&info, 0, sizeof(info)); |
132 | strscpy(info.type, client_type, sizeof(info.type)); | |
133 | info.addr = addr; | |
134 | ||
cc14c00c MCC |
135 | return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, |
136 | probe_addrs); | |
02283b98 EG |
137 | } |
138 | EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev); | |
139 | ||
140 | /* Return i2c client address of v4l2_subdev. */ | |
141 | unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd) | |
142 | { | |
143 | struct i2c_client *client = v4l2_get_subdevdata(sd); | |
144 | ||
145 | return client ? client->addr : I2C_CLIENT_END; | |
146 | } | |
147 | EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_addr); | |
148 | ||
cc14c00c MCC |
149 | /* |
150 | * Return a list of I2C tuner addresses to probe. Use only if the tuner | |
151 | * addresses are unknown. | |
152 | */ | |
02283b98 EG |
153 | const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type) |
154 | { | |
155 | static const unsigned short radio_addrs[] = { | |
156 | #if IS_ENABLED(CONFIG_MEDIA_TUNER_TEA5761) | |
157 | 0x10, | |
158 | #endif | |
159 | 0x60, | |
160 | I2C_CLIENT_END | |
161 | }; | |
162 | static const unsigned short demod_addrs[] = { | |
163 | 0x42, 0x43, 0x4a, 0x4b, | |
164 | I2C_CLIENT_END | |
165 | }; | |
166 | static const unsigned short tv_addrs[] = { | |
167 | 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */ | |
168 | 0x60, 0x61, 0x62, 0x63, 0x64, | |
169 | I2C_CLIENT_END | |
170 | }; | |
171 | ||
172 | switch (type) { | |
173 | case ADDRS_RADIO: | |
174 | return radio_addrs; | |
175 | case ADDRS_DEMOD: | |
176 | return demod_addrs; | |
177 | case ADDRS_TV: | |
178 | return tv_addrs; | |
179 | case ADDRS_TV_WITH_DEMOD: | |
180 | return tv_addrs + 4; | |
181 | } | |
182 | return NULL; | |
183 | } | |
184 | EXPORT_SYMBOL_GPL(v4l2_i2c_tuner_addrs); |