/* * Some devices, such as Google Hana Chromebooks, are produced by multiple * vendors each using their preferred components. Such components are all * in the device tree. Instead of having all of them enabled and having each * driver separately try and probe its device while fighting over shared * resources, they can be marked as "fail-needs-probe" and have a prober * figure out which one is actually used beforehand. * * This prober assumes such drop-in parts are on the same I2C bus, have * non-conflicting addresses, and can be directly probed by seeing which * address responds. * * TODO: * - Support I2C muxes
*/
of_changeset_init(ocs);
ret = of_changeset_update_prop_string(ocs, node, "status", "okay"); if (ret) return ret;
ret = of_changeset_apply(ocs); if (ret) { /* ocs needs to be explicitly cleaned up before being freed. */
of_changeset_destroy(ocs);
} else { /* * ocs is intentionally kept around as it needs to * exist as long as the change is applied.
*/ void *ptr __always_unused = no_free_ptr(ocs);
}
/** * i2c_of_probe_component() - probe for devices of "type" on the same i2c bus * @dev: Pointer to the &struct device of the caller, only used for dev_printk() messages. * @cfg: Pointer to the &struct i2c_of_probe_cfg containing callbacks and other options * for the prober. * @ctx: Context data for callbacks. * * Probe for possible I2C components of the same "type" (&i2c_of_probe_cfg->type) * on the same I2C bus that have their status marked as "fail-needs-probe". * * Assumes that across the entire device tree the only instances of nodes * with "type" prefixed node names (not including the address portion) are * the ones that need handling for second source components. In other words, * if "type" is "touchscreen", then all device nodes named "touchscreen*" * are the ones that need probing. There cannot be another "touchscreen*" * node that is already enabled. * * Assumes that for each "type" of component, only one actually exists. In * other words, only one matching and existing device will be enabled. * * Context: Process context only. Does non-atomic I2C transfers. * Should only be used from a driver probe function, as the function * can return -EPROBE_DEFER if the I2C adapter or other resources * are unavailable. * Return: 0 on success or no-op, error code otherwise. * A no-op can happen when it seems like the device tree already * has components of the type to be probed already enabled. This * can happen when the device tree had not been updated to mark * the status of the to-be-probed components as "fail-needs-probe". * Or this function was already run with the same parameters and * succeeded in enabling a component. The latter could happen if * the user had multiple types of components to probe, and one of * them down the list caused a deferred probe. This is expected * behavior.
*/ int i2c_of_probe_component(struct device *dev, conststruct i2c_of_probe_cfg *cfg, void *ctx)
{ conststruct i2c_of_probe_ops *ops; constchar *type; struct i2c_adapter *i2c; int ret;
ops = cfg->ops ?: &i2c_of_probe_dummy_ops;
type = cfg->type;
/* * If any devices of the given "type" are already enabled then this function is a no-op. * Either the device tree hasn't been modified to work with this probe function, or the * function had already run before and enabled some component.
*/
for_each_child_of_node_with_prefix(i2c_node, node, type) if (of_device_is_available(node)) return 0;
i2c = of_get_i2c_adapter_by_node(i2c_node); if (!i2c) return dev_err_probe(dev, -EPROBE_DEFER, "Couldn't get I2C adapter\n");
/* Grab and enable resources */
ret = 0; if (ops->enable)
ret = ops->enable(dev, i2c_node, ctx); if (ret) goto out_put_i2c_adapter;
for_each_child_of_node_with_prefix(i2c_node, node, type) { union i2c_smbus_data data;
u32 addr;
if (of_property_read_u32(node, "reg", &addr)) continue; if (i2c_smbus_xfer(i2c, addr, 0, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data) < 0) continue;
/* Found a device that is responding */ if (ops->cleanup_early)
ops->cleanup_early(dev, ctx);
ret = i2c_of_probe_enable_node(dev, node); break;
}
if (ops->cleanup)
ops->cleanup(dev, ctx);
out_put_i2c_adapter:
i2c_put_adapter(i2c);
/* * It's entirely possible for the component's device node to not have the * regulator supplies. While it does not make sense from a hardware perspective, * the supplies could be always on or otherwise not modeled in the device tree, * but the device would still work.
*/
supply_name = ctx->opts->supply_name; if (!supply_name) return 0;
supply = of_regulator_get_optional(dev, node, supply_name); if (IS_ERR(supply)) { return dev_err_probe(dev, PTR_ERR(supply), "Failed to get regulator supply \"%s\" from %pOF\n",
supply_name, node);
}
/** * i2c_of_probe_simple_enable - Simple helper for I2C OF prober to get and enable resources * @dev: Pointer to the &struct device of the caller, only used for dev_printk() messages * @bus_node: Pointer to the &struct device_node of the I2C adapter. * @data: Pointer to &struct i2c_of_probe_simple_ctx helper context. * * If &i2c_of_probe_simple_opts->supply_name is given, request the named regulator supply. * If &i2c_of_probe_simple_opts->gpio_name is given, request the named GPIO. Or if it is * the empty string, request the unnamed GPIO. * If a regulator supply was found, enable that regulator. * If a GPIO line was found, configure the GPIO line to output and set value * according to given options. * * Return: %0 on success or no-op, or a negative error number on failure.
*/ int i2c_of_probe_simple_enable(struct device *dev, struct device_node *bus_node, void *data)
{ struct i2c_of_probe_simple_ctx *ctx = data; struct device_node *node; constchar *compat; int ret;
dev_dbg(dev, "Requesting resources for components under I2C bus %pOF\n", bus_node);
if (!ctx || !ctx->opts) return -EINVAL;
compat = ctx->opts->res_node_compatible; if (!compat) return -EINVAL;
node = of_get_compatible_child(bus_node, compat); if (!node) return dev_err_probe(dev, -ENODEV, "No device compatible with \"%s\" found\n",
compat);
ret = i2c_of_probe_simple_get_supply(dev, node, ctx); if (ret) goto out_put_node;
ret = i2c_of_probe_simple_get_gpiod(dev, node, ctx); if (ret) goto out_put_supply;
ret = i2c_of_probe_simple_enable_regulator(dev, ctx); if (ret) goto out_put_gpiod;
ret = i2c_of_probe_simple_set_gpio(dev, ctx); if (ret) goto out_disable_regulator;
/** * i2c_of_probe_simple_cleanup_early - \ * Simple helper for I2C OF prober to release GPIOs before component is enabled * @dev: Pointer to the &struct device of the caller; unused. * @data: Pointer to &struct i2c_of_probe_simple_ctx helper context. * * GPIO descriptors are exclusive and have to be released before the * actual driver probes so that the latter can acquire them.
*/ void i2c_of_probe_simple_cleanup_early(struct device *dev, void *data)
{ struct i2c_of_probe_simple_ctx *ctx = data;
/** * i2c_of_probe_simple_cleanup - Clean up and release resources for I2C OF prober simple helpers * @dev: Pointer to the &struct device of the caller, only used for dev_printk() messages * @data: Pointer to &struct i2c_of_probe_simple_ctx helper context. * * * If a GPIO line was found and not yet released, set its value to the opposite of that * set in i2c_of_probe_simple_enable() and release it. * * If a regulator supply was found, disable that regulator and release it.
*/ void i2c_of_probe_simple_cleanup(struct device *dev, void *data)
{ struct i2c_of_probe_simple_ctx *ctx = data;
/* GPIO operations here are no-ops if i2c_of_probe_simple_cleanup_early was called. */
i2c_of_probe_simple_disable_gpio(dev, ctx);
i2c_of_probe_simple_put_gpiod(ctx);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.