/* The torch watchdog timer must be refreshed within an interval of 13 seconds. */ #define TPS6131X_TORCH_REFRESH_INTERVAL_JIFFIES msecs_to_jiffies(10000)
struct tps6131x { struct device *dev; struct regmap *regmap; struct gpio_desc *reset_gpio; /* * Registers 0, 1, 2, and 3 control parts of the controller that are not completely * independent of each other. Since some operations require the registers to be written in * a specific order to avoid unwanted side effects, they are synchronized with a lock.
*/ struct mutex lock; /* Hardware access lock for register 0, 1, 2 and 3 */ struct delayed_work torch_refresh_work; bool valley_current_limit; bool chan1_en; bool chan2_en; bool chan3_en; struct fwnode_handle *led_node;
u32 max_flash_current_ma;
u32 step_flash_current_ma;
u32 max_torch_current_ma;
u32 step_torch_current_ma;
u32 max_timeout_us; struct led_classdev_flash fled_cdev; struct v4l2_flash *v4l2_flash;
};
/* * These registers contain flags that are reset when read.
*/ staticbool tps6131x_regmap_precious(struct device *dev, unsignedint reg)
{ switch (reg) { case TPS6131X_REG_3: case TPS6131X_REG_4: case TPS6131X_REG_6: returntrue; default: returnfalse;
}
}
/* * The brightness parameter uses the number of current steps as the unit (not the current * value itself). Since the reported step size can vary depending on the configuration, * this value must be converted into actual register steps.
*/
steps_remaining = (brightness * tps6131x->step_torch_current_ma) / TPS6131X_TORCH_STEP_I_MA;
/* * The currents are distributed as evenly as possible across the activated channels. * Since channels 1 and 3 share the same register setting, they always use the same current * value. Channel 2 supports higher currents and thus takes over the remaining additional * portion that cannot be covered by the other channels.
*/
steps_chan13 = min_t(u32, steps_remaining / num_chans,
TPS6131X_TORCH_MAX_I_CHAN13_MA / TPS6131X_TORCH_STEP_I_MA); if (tps6131x->chan1_en)
steps_remaining -= steps_chan13; if (tps6131x->chan3_en)
steps_remaining -= steps_chan13;
ret = tps6131x_set_mode(tps6131x, brightness ? TPS6131X_MODE_TORCH : TPS6131X_MODE_SHUTDOWN, true); if (ret < 0) return ret;
/* * In order to use both the flash and the video light functions purely via the I2C * interface, STRB1 must be low. If STRB1 is low, then the video light watchdog timer * is also active, which puts the device into the shutdown state after around 13 seconds. * To prevent this, the mode must be refreshed within the watchdog timeout.
*/ if (brightness)
schedule_delayed_work(&tps6131x->torch_refresh_work,
TPS6131X_TORCH_REFRESH_INTERVAL_JIFFIES);
tps6131x->led_node = fwnode_get_next_available_child_node(dev->fwnode, NULL); if (!tps6131x->led_node) {
dev_err(dev, "Missing LED node\n"); return -EINVAL;
}
num_channels = fwnode_property_count_u32(tps6131x->led_node, "led-sources"); if (num_channels <= 0) {
dev_err(dev, "Failed to read led-sources property\n"); return -EINVAL;
}
if (num_channels > TPS6131X_MAX_CHANNELS) {
dev_err(dev, "led-sources count %u exceeds maximum channel count %u\n",
num_channels, TPS6131X_MAX_CHANNELS); return -EINVAL;
}
ret = fwnode_property_read_u32_array(tps6131x->led_node, "led-sources", channels,
num_channels); if (ret < 0) {
dev_err(dev, "Failed to read led-sources property\n"); return ret;
}
max_current_flash_ma = 0;
max_current_torch_ma = 0; for (i = 0; i < num_channels; i++) { switch (channels[i]) { case 1:
tps6131x->chan1_en = true;
max_current_flash_ma += TPS6131X_FLASH_MAX_I_CHAN13_MA;
max_current_torch_ma += TPS6131X_TORCH_MAX_I_CHAN13_MA; break; case 2:
tps6131x->chan2_en = true;
max_current_flash_ma += TPS6131X_FLASH_MAX_I_CHAN2_MA;
max_current_torch_ma += TPS6131X_TORCH_MAX_I_CHAN2_MA; break; case 3:
tps6131x->chan3_en = true;
max_current_flash_ma += TPS6131X_FLASH_MAX_I_CHAN13_MA;
max_current_torch_ma += TPS6131X_TORCH_MAX_I_CHAN13_MA; break; default:
dev_err(dev, "led-source out of range [1-3]\n"); return -EINVAL;
}
}
/* * If only channels 1 and 3 are used, the step size is doubled because the two channels * share the same current control register.
*/
current_step_multiplier =
(tps6131x->chan1_en && tps6131x->chan3_en && !tps6131x->chan2_en) ? 2 : 1;
tps6131x->step_flash_current_ma = current_step_multiplier * TPS6131X_FLASH_STEP_I_MA;
tps6131x->step_torch_current_ma = current_step_multiplier * TPS6131X_TORCH_STEP_I_MA;
ret = fwnode_property_read_u32(tps6131x->led_node, "led-max-microamp", ¤t_ua); if (ret < 0) {
dev_err(dev, "Failed to read led-max-microamp property\n"); return ret;
}
if (!tps6131x->max_torch_current_ma ||
tps6131x->max_torch_current_ma > max_current_torch_ma ||
(tps6131x->max_torch_current_ma % tps6131x->step_torch_current_ma)) {
dev_err(dev, "led-max-microamp out of range or not a multiple of %u\n",
tps6131x->step_torch_current_ma); return -EINVAL;
}
ret = fwnode_property_read_u32(tps6131x->led_node, "flash-max-microamp", ¤t_ua); if (ret < 0) {
dev_err(dev, "Failed to read flash-max-microamp property\n"); return ret;
}
if (!tps6131x->max_flash_current_ma ||
tps6131x->max_flash_current_ma > max_current_flash_ma ||
(tps6131x->max_flash_current_ma % tps6131x->step_flash_current_ma)) {
dev_err(dev, "flash-max-microamp out of range or not a multiple of %u\n",
tps6131x->step_flash_current_ma); return -EINVAL;
}
ret = fwnode_property_read_u32(tps6131x->led_node, "flash-max-timeout-us", &timeout_us); if (ret < 0) {
dev_err(dev, "Failed to read flash-max-timeout-us property\n"); return ret;
}
setting = &tps6131x->fled_cdev.timeout;
timer_config = tps6131x_find_closest_timer_config(0);
setting->min = timer_config->time_us;
setting->max = tps6131x->max_timeout_us;
setting->step = 1; /* Only some specific time periods are supported. No fixed step size. */
setting->val = setting->min;
ret = tps6131x_parse_node(tps6131x); if (ret) return ret;
tps6131x->regmap = devm_regmap_init_i2c(client, &tps6131x_regmap); if (IS_ERR(tps6131x->regmap)) {
ret = PTR_ERR(tps6131x->regmap); return dev_err_probe(&client->dev, ret, "Failed to allocate register map\n");
}
tps6131x->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(tps6131x->reset_gpio)) {
ret = PTR_ERR(tps6131x->reset_gpio); return dev_err_probe(&client->dev, ret, "Failed to get reset GPIO\n");
}
ret = tps6131x_reset_chip(tps6131x); if (ret) return dev_err_probe(&client->dev, ret, "Failed to reset LED controller\n");
ret = tps6131x_init_chip(tps6131x); if (ret) return dev_err_probe(&client->dev, ret, "Failed to initialize LED controller\n");
ret = tps6131x_led_class_setup(tps6131x); if (ret) return dev_err_probe(&client->dev, ret, "Failed to setup LED class\n");
ret = tps6131x_v4l2_setup(tps6131x); if (ret) return dev_err_probe(&client->dev, ret, "Failed to setup v4l2 flash\n");
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.