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