// SPDX-License-Identifier: GPL-2.0-only /* * TI LP8864/LP8866 4/6 Channel LED Driver * * Copyright (C) 2024 Siemens AG * * Based on LP8860 driver by Dan Murphy <dmurphy@ti.com>
*/
/* Textual meaning for status bits, starting from bit 1 */ staticconstchar *const lp8864_supply_status_msg[] = { "Vin under-voltage fault", "Vin over-voltage fault", "Vdd under-voltage fault", "Vin over-current fault", "Missing charge pump fault", "Charge pump fault", "Missing boost sync fault", "CRC error fault ",
};
/* Textual meaning for status bits, starting from bit 1 */ staticconstchar *const lp8864_boost_status_msg[] = { "Boost OVP low fault", "Boost OVP high fault", "Boost over-current fault", "Missing boost FSET resistor fault", "Missing MODE SEL resistor fault", "Missing LED resistor fault", "ISET resistor short to ground fault", "Thermal shutdown fault",
};
/* Textual meaning for every register bit */ staticconstchar *const lp8864_led_status_msg[] = { "LED 1 fault", "LED 2 fault", "LED 3 fault", "LED 4 fault", "LED 5 fault", "LED 6 fault", "LED open fault", "LED internal short fault", "LED short to GND fault",
NULL, NULL, NULL, "Invalid string configuration fault",
NULL, "I2C time out fault",
};
/** * struct lp8864_led * @client: Pointer to the I2C client * @led_dev: led class device pointer * @regmap: Devices register map * @led_status_mask: Helps to report LED fault only once
*/ struct lp8864_led { struct i2c_client *client; struct led_classdev led_dev; struct regmap *regmap;
u16 led_status_mask;
};
staticint lp8864_fault_check(struct lp8864_led *led)
{ int ret, i; unsignedint val;
ret = regmap_read(led->regmap, LP8864_SUPPLY_STATUS, &val); if (ret) goto err;
/* Odd bits are status bits, even bits are clear bits */ for (i = 0; i < ARRAY_SIZE(lp8864_supply_status_msg); i++) if (val & BIT(i * 2 + 1))
dev_warn(&led->client->dev, "%s\n", lp8864_supply_status_msg[i]);
/* * Clear bits have an index preceding the corresponding Status bits; * both have to be written "1" simultaneously to clear the corresponding * Status bit.
*/ if (val)
ret = regmap_write(led->regmap, LP8864_SUPPLY_STATUS, val >> 1 | val); if (ret) goto err;
ret = regmap_read(led->regmap, LP8864_BOOST_STATUS, &val); if (ret) goto err;
/* Odd bits are status bits, even bits are clear bits */ for (i = 0; i < ARRAY_SIZE(lp8864_boost_status_msg); i++) if (val & BIT(i * 2 + 1))
dev_warn(&led->client->dev, "%s\n", lp8864_boost_status_msg[i]);
if (val)
ret = regmap_write(led->regmap, LP8864_BOOST_STATUS, val >> 1 | val); if (ret) goto err;
ret = regmap_read(led->regmap, LP8864_LED_STATUS, &val); if (ret) goto err;
/* * Clear already reported faults that maintain their value until device * power-down
*/
val &= ~led->led_status_mask;
for (i = 0; i < ARRAY_SIZE(lp8864_led_status_msg); i++) if (lp8864_led_status_msg[i] && val & BIT(i))
dev_warn(&led->client->dev, "%s\n", lp8864_led_status_msg[i]);
/* * Mark those which maintain their value until device power-down as * "already reported"
*/
led->led_status_mask |= val & ~LP8864_LED_STATUS_WR_MASK;
/* * Only bits 14, 12, 10 have to be cleared here, but others are RO, * we don't care what we write to them.
*/ if (val & LP8864_LED_STATUS_WR_MASK)
ret = regmap_write(led->regmap, LP8864_LED_STATUS, val >> 1 | val); if (ret) goto err;
return 0;
err:
dev_err(&led->client->dev, "Failed to read/clear faults (%pe)\n", ERR_PTR(ret));
led = devm_kzalloc(&client->dev, sizeof(*led), GFP_KERNEL); if (!led) return -ENOMEM;
child_node = of_get_next_available_child(np, NULL); if (!child_node) {
dev_err(&client->dev, "No LED function defined\n"); return -EINVAL;
}
ret = devm_regulator_get_enable_optional(&client->dev, "vled"); if (ret && ret != -ENODEV) return dev_err_probe(&client->dev, ret, "Failed to enable vled regulator\n");
enable_gpio = devm_gpiod_get_optional(&client->dev, "enable", GPIOD_OUT_HIGH); if (IS_ERR(enable_gpio)) return dev_err_probe(&client->dev, PTR_ERR(enable_gpio), "Failed to get enable GPIO\n");
ret = devm_add_action_or_reset(&client->dev, lp8864_disable_gpio, enable_gpio); if (ret) return ret;
led->regmap = devm_regmap_init_i2c(client, &lp8864_regmap_config); if (IS_ERR(led->regmap)) return dev_err_probe(&client->dev, PTR_ERR(led->regmap), "Failed to allocate regmap\n");
/* Control brightness by DISPLAY_BRT register */
ret = regmap_update_bits(led->regmap, LP8864_USER_CONFIG1, LP8864_BRT_MODE_MASK,
LP8864_BRT_MODE_REG); if (ret) {
dev_err(&led->client->dev, "Failed to set brightness control mode\n"); return ret;
}
ret = lp8864_fault_check(led); if (ret) return ret;
ret = devm_led_classdev_register_ext(&client->dev, &led->led_dev, &init_data); if (ret)
dev_err(&client->dev, "Failed to register LED device (%pe)\n", ERR_PTR(ret));
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.