18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * v4l2-i2c - I2C helpers for Video4Linux2
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/i2c.h>
78c2ecf20Sopenharmony_ci#include <linux/module.h>
88c2ecf20Sopenharmony_ci#include <media/v4l2-common.h>
98c2ecf20Sopenharmony_ci#include <media/v4l2-device.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_civoid v4l2_i2c_subdev_unregister(struct v4l2_subdev *sd)
128c2ecf20Sopenharmony_ci{
138c2ecf20Sopenharmony_ci	struct i2c_client *client = v4l2_get_subdevdata(sd);
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci	/*
168c2ecf20Sopenharmony_ci	 * We need to unregister the i2c client
178c2ecf20Sopenharmony_ci	 * explicitly. We cannot rely on
188c2ecf20Sopenharmony_ci	 * i2c_del_adapter to always unregister
198c2ecf20Sopenharmony_ci	 * clients for us, since if the i2c bus is a
208c2ecf20Sopenharmony_ci	 * platform bus, then it is never deleted.
218c2ecf20Sopenharmony_ci	 *
228c2ecf20Sopenharmony_ci	 * Device tree or ACPI based devices must not
238c2ecf20Sopenharmony_ci	 * be unregistered as they have not been
248c2ecf20Sopenharmony_ci	 * registered by us, and would not be
258c2ecf20Sopenharmony_ci	 * re-created by just probing the V4L2 driver.
268c2ecf20Sopenharmony_ci	 */
278c2ecf20Sopenharmony_ci	if (client && !client->dev.of_node && !client->dev.fwnode)
288c2ecf20Sopenharmony_ci		i2c_unregister_device(client);
298c2ecf20Sopenharmony_ci}
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_civoid v4l2_i2c_subdev_set_name(struct v4l2_subdev *sd,
328c2ecf20Sopenharmony_ci			      struct i2c_client *client,
338c2ecf20Sopenharmony_ci			      const char *devname, const char *postfix)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	if (!devname)
368c2ecf20Sopenharmony_ci		devname = client->dev.driver->name;
378c2ecf20Sopenharmony_ci	if (!postfix)
388c2ecf20Sopenharmony_ci		postfix = "";
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	snprintf(sd->name, sizeof(sd->name), "%s%s %d-%04x", devname, postfix,
418c2ecf20Sopenharmony_ci		 i2c_adapter_id(client->adapter), client->addr);
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(v4l2_i2c_subdev_set_name);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_civoid v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
468c2ecf20Sopenharmony_ci			  const struct v4l2_subdev_ops *ops)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	v4l2_subdev_init(sd, ops);
498c2ecf20Sopenharmony_ci	sd->flags |= V4L2_SUBDEV_FL_IS_I2C;
508c2ecf20Sopenharmony_ci	/* the owner is the same as the i2c_client's driver owner */
518c2ecf20Sopenharmony_ci	sd->owner = client->dev.driver->owner;
528c2ecf20Sopenharmony_ci	sd->dev = &client->dev;
538c2ecf20Sopenharmony_ci	/* i2c_client and v4l2_subdev point to one another */
548c2ecf20Sopenharmony_ci	v4l2_set_subdevdata(sd, client);
558c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, sd);
568c2ecf20Sopenharmony_ci	v4l2_i2c_subdev_set_name(sd, client, NULL, NULL);
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci/* Load an i2c sub-device. */
618c2ecf20Sopenharmony_cistruct v4l2_subdev
628c2ecf20Sopenharmony_ci*v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
638c2ecf20Sopenharmony_ci			   struct i2c_adapter *adapter,
648c2ecf20Sopenharmony_ci			   struct i2c_board_info *info,
658c2ecf20Sopenharmony_ci			   const unsigned short *probe_addrs)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = NULL;
688c2ecf20Sopenharmony_ci	struct i2c_client *client;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	if (!v4l2_dev)
718c2ecf20Sopenharmony_ci		return NULL;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	request_module(I2C_MODULE_PREFIX "%s", info->type);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	/* Create the i2c client */
768c2ecf20Sopenharmony_ci	if (info->addr == 0 && probe_addrs)
778c2ecf20Sopenharmony_ci		client = i2c_new_scanned_device(adapter, info, probe_addrs,
788c2ecf20Sopenharmony_ci						NULL);
798c2ecf20Sopenharmony_ci	else
808c2ecf20Sopenharmony_ci		client = i2c_new_client_device(adapter, info);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	/*
838c2ecf20Sopenharmony_ci	 * Note: by loading the module first we are certain that c->driver
848c2ecf20Sopenharmony_ci	 * will be set if the driver was found. If the module was not loaded
858c2ecf20Sopenharmony_ci	 * first, then the i2c core tries to delay-load the module for us,
868c2ecf20Sopenharmony_ci	 * and then c->driver is still NULL until the module is finally
878c2ecf20Sopenharmony_ci	 * loaded. This delay-load mechanism doesn't work if other drivers
888c2ecf20Sopenharmony_ci	 * want to use the i2c device, so explicitly loading the module
898c2ecf20Sopenharmony_ci	 * is the best alternative.
908c2ecf20Sopenharmony_ci	 */
918c2ecf20Sopenharmony_ci	if (!i2c_client_has_driver(client))
928c2ecf20Sopenharmony_ci		goto error;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	/* Lock the module so we can safely get the v4l2_subdev pointer */
958c2ecf20Sopenharmony_ci	if (!try_module_get(client->dev.driver->owner))
968c2ecf20Sopenharmony_ci		goto error;
978c2ecf20Sopenharmony_ci	sd = i2c_get_clientdata(client);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	/*
1008c2ecf20Sopenharmony_ci	 * Register with the v4l2_device which increases the module's
1018c2ecf20Sopenharmony_ci	 * use count as well.
1028c2ecf20Sopenharmony_ci	 */
1038c2ecf20Sopenharmony_ci	if (v4l2_device_register_subdev(v4l2_dev, sd))
1048c2ecf20Sopenharmony_ci		sd = NULL;
1058c2ecf20Sopenharmony_ci	/* Decrease the module use count to match the first try_module_get. */
1068c2ecf20Sopenharmony_ci	module_put(client->dev.driver->owner);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cierror:
1098c2ecf20Sopenharmony_ci	/*
1108c2ecf20Sopenharmony_ci	 * If we have a client but no subdev, then something went wrong and
1118c2ecf20Sopenharmony_ci	 * we must unregister the client.
1128c2ecf20Sopenharmony_ci	 */
1138c2ecf20Sopenharmony_ci	if (!IS_ERR(client) && !sd)
1148c2ecf20Sopenharmony_ci		i2c_unregister_device(client);
1158c2ecf20Sopenharmony_ci	return sd;
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistruct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
1208c2ecf20Sopenharmony_ci					struct i2c_adapter *adapter,
1218c2ecf20Sopenharmony_ci					const char *client_type,
1228c2ecf20Sopenharmony_ci					u8 addr,
1238c2ecf20Sopenharmony_ci					const unsigned short *probe_addrs)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	struct i2c_board_info info;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	/*
1288c2ecf20Sopenharmony_ci	 * Setup the i2c board info with the device type and
1298c2ecf20Sopenharmony_ci	 * the device address.
1308c2ecf20Sopenharmony_ci	 */
1318c2ecf20Sopenharmony_ci	memset(&info, 0, sizeof(info));
1328c2ecf20Sopenharmony_ci	strscpy(info.type, client_type, sizeof(info.type));
1338c2ecf20Sopenharmony_ci	info.addr = addr;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info,
1368c2ecf20Sopenharmony_ci					 probe_addrs);
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci/* Return i2c client address of v4l2_subdev. */
1418c2ecf20Sopenharmony_ciunsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	struct i2c_client *client = v4l2_get_subdevdata(sd);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	return client ? client->addr : I2C_CLIENT_END;
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(v4l2_i2c_subdev_addr);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci/*
1508c2ecf20Sopenharmony_ci * Return a list of I2C tuner addresses to probe. Use only if the tuner
1518c2ecf20Sopenharmony_ci * addresses are unknown.
1528c2ecf20Sopenharmony_ci */
1538c2ecf20Sopenharmony_ciconst unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	static const unsigned short radio_addrs[] = {
1568c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_MEDIA_TUNER_TEA5761)
1578c2ecf20Sopenharmony_ci		0x10,
1588c2ecf20Sopenharmony_ci#endif
1598c2ecf20Sopenharmony_ci		0x60,
1608c2ecf20Sopenharmony_ci		I2C_CLIENT_END
1618c2ecf20Sopenharmony_ci	};
1628c2ecf20Sopenharmony_ci	static const unsigned short demod_addrs[] = {
1638c2ecf20Sopenharmony_ci		0x42, 0x43, 0x4a, 0x4b,
1648c2ecf20Sopenharmony_ci		I2C_CLIENT_END
1658c2ecf20Sopenharmony_ci	};
1668c2ecf20Sopenharmony_ci	static const unsigned short tv_addrs[] = {
1678c2ecf20Sopenharmony_ci		0x42, 0x43, 0x4a, 0x4b,		/* tda8290 */
1688c2ecf20Sopenharmony_ci		0x60, 0x61, 0x62, 0x63, 0x64,
1698c2ecf20Sopenharmony_ci		I2C_CLIENT_END
1708c2ecf20Sopenharmony_ci	};
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	switch (type) {
1738c2ecf20Sopenharmony_ci	case ADDRS_RADIO:
1748c2ecf20Sopenharmony_ci		return radio_addrs;
1758c2ecf20Sopenharmony_ci	case ADDRS_DEMOD:
1768c2ecf20Sopenharmony_ci		return demod_addrs;
1778c2ecf20Sopenharmony_ci	case ADDRS_TV:
1788c2ecf20Sopenharmony_ci		return tv_addrs;
1798c2ecf20Sopenharmony_ci	case ADDRS_TV_WITH_DEMOD:
1808c2ecf20Sopenharmony_ci		return tv_addrs + 4;
1818c2ecf20Sopenharmony_ci	}
1828c2ecf20Sopenharmony_ci	return NULL;
1838c2ecf20Sopenharmony_ci}
1848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(v4l2_i2c_tuner_addrs);
185