Branch data Line data Source code
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 : : 11 : 0 : 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 : 0 : if (client && !client->dev.of_node && !client->dev.fwnode) 28 : 0 : i2c_unregister_device(client); 29 : 0 : } 30 : : 31 : 0 : void v4l2_i2c_subdev_set_name(struct v4l2_subdev *sd, 32 : : struct i2c_client *client, 33 : : const char *devname, const char *postfix) 34 : : { 35 : 0 : if (!devname) 36 : 0 : devname = client->dev.driver->name; 37 : 0 : if (!postfix) 38 : : postfix = ""; 39 : : 40 : 0 : snprintf(sd->name, sizeof(sd->name), "%s%s %d-%04x", devname, postfix, 41 : 0 : i2c_adapter_id(client->adapter), client->addr); 42 : 0 : } 43 : : EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_set_name); 44 : : 45 : 0 : void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client, 46 : : const struct v4l2_subdev_ops *ops) 47 : : { 48 : 0 : v4l2_subdev_init(sd, ops); 49 : 0 : sd->flags |= V4L2_SUBDEV_FL_IS_I2C; 50 : : /* the owner is the same as the i2c_client's driver owner */ 51 : 0 : sd->owner = client->dev.driver->owner; 52 : 0 : 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 : 0 : v4l2_i2c_subdev_set_name(sd, client, NULL, NULL); 57 : 0 : } 58 : : EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init); 59 : : 60 : : /* Load an i2c sub-device. */ 61 : : struct v4l2_subdev 62 : 0 : *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) 66 : : { 67 : : struct v4l2_subdev *sd = NULL; 68 : : struct i2c_client *client; 69 : : 70 : 0 : if (!v4l2_dev) 71 : : return NULL; 72 : : 73 : 0 : request_module(I2C_MODULE_PREFIX "%s", info->type); 74 : : 75 : : /* Create the i2c client */ 76 : 0 : if (info->addr == 0 && probe_addrs) 77 : 0 : client = i2c_new_probed_device(adapter, info, probe_addrs, 78 : : NULL); 79 : : else 80 : 0 : client = i2c_new_device(adapter, info); 81 : : 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 : : */ 91 : 0 : if (!client || !client->dev.driver) 92 : : goto error; 93 : : 94 : : /* Lock the module so we can safely get the v4l2_subdev pointer */ 95 : 0 : if (!try_module_get(client->dev.driver->owner)) 96 : : goto error; 97 : : sd = i2c_get_clientdata(client); 98 : : 99 : : /* 100 : : * Register with the v4l2_device which increases the module's 101 : : * use count as well. 102 : : */ 103 : 0 : 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 : 0 : module_put(client->dev.driver->owner); 107 : : 108 : : error: 109 : : /* 110 : : * If we have a client but no subdev, then something went wrong and 111 : : * we must unregister the client. 112 : : */ 113 : 0 : if (client && !sd) 114 : 0 : i2c_unregister_device(client); 115 : 0 : return sd; 116 : : } 117 : : EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board); 118 : : 119 : 0 : struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev, 120 : : struct i2c_adapter *adapter, 121 : : const char *client_type, 122 : : u8 addr, 123 : : const unsigned short *probe_addrs) 124 : : { 125 : : struct i2c_board_info info; 126 : : 127 : : /* 128 : : * Setup the i2c board info with the device type and 129 : : * the device address. 130 : : */ 131 : 0 : memset(&info, 0, sizeof(info)); 132 : 0 : strscpy(info.type, client_type, sizeof(info.type)); 133 : 0 : info.addr = addr; 134 : : 135 : 0 : return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, 136 : : probe_addrs); 137 : : } 138 : : EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev); 139 : : 140 : : /* Return i2c client address of v4l2_subdev. */ 141 : 0 : unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd) 142 : : { 143 : : struct i2c_client *client = v4l2_get_subdevdata(sd); 144 : : 145 : 0 : return client ? client->addr : I2C_CLIENT_END; 146 : : } 147 : : EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_addr); 148 : : 149 : : /* 150 : : * Return a list of I2C tuner addresses to probe. Use only if the tuner 151 : : * addresses are unknown. 152 : : */ 153 : 0 : 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 : 0 : switch (type) { 173 : : case ADDRS_RADIO: 174 : : return radio_addrs; 175 : : case ADDRS_DEMOD: 176 : 0 : return demod_addrs; 177 : : case ADDRS_TV: 178 : 0 : return tv_addrs; 179 : : case ADDRS_TV_WITH_DEMOD: 180 : 0 : return tv_addrs + 4; 181 : : } 182 : 0 : return NULL; 183 : : } 184 : : EXPORT_SYMBOL_GPL(v4l2_i2c_tuner_addrs);