blob: 3e312d6a1cc53610c8f068bb23533b80a97764de [file] [log] [blame]
/*
* Copyright (c) 2024 TOKITA Hiroshi
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/drivers/led.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(led_axp192, CONFIG_LED_LOG_LEVEL);
#define CHGLED_OUTPUT_HIZ 0x0
#define CHGLED_OUTPUT_SLOW_BLINK 0x1
#define CHGLED_OUTPUT_FAST_BLINK 0x2
#define CHGLED_OUTPUT_DRIVE_LOW 0x3
#define CHGLED_OUTPUT_OFFSET 4
#define CHGLED_ON (CHGLED_OUTPUT_DRIVE_LOW << CHGLED_OUTPUT_OFFSET)
#define CHGLED_OFF (CHGLED_OUTPUT_HIZ << CHGLED_OUTPUT_OFFSET)
#define CHGLED_BLINK_SLOW (CHGLED_OUTPUT_SLOW_BLINK << CHGLED_OUTPUT_OFFSET)
#define CHGLED_BLINK_FAST (CHGLED_OUTPUT_FAST_BLINK << CHGLED_OUTPUT_OFFSET)
#define CHGLED_OUTPUT_MASK (BIT_MASK(2) << CHGLED_OUTPUT_OFFSET)
#define SLOW_BLINK_DELAY_ON (((1000 / 4) / 1) * 1)
#define SLOW_BLINK_DELAY_OFF (((1000 / 4) / 1) * 3)
#define FAST_BLINK_DELAY_ON (((1000 / 4) / 4) * 1)
#define FAST_BLINK_DELAY_OFF (((1000 / 4) / 4) * 3)
#define CHGLED_CTRL_TYPE_A 0x0
#define CHGLED_CTRL_TYPE_B 0x1
#define CHGLED_CTRL_BY_REG 0x2
#define CHGLED_CTRL_BY_CHARGE 0x3
#define AXP192_REG_PWROFF_BATTCHK_CHGLED 0x32
#define AXP192_REG_CHGLED AXP192_REG_PWROFF_BATTCHK_CHGLED
#define AXP192_CHGLED_CTRL_MASK 0x2
#define AXP192_CHGLED_CTRL_OFFSET 2
#define AXP2101_REG_CHGLED 0x69
#define AXP2101_CHGLED_CTRL_MASK 0x3
#define AXP2101_CHGLED_CTRL_OFFSET 1
struct led_axp192_config {
struct i2c_dt_spec i2c;
uint8_t addr;
uint8_t mode;
uint8_t mode_mask;
uint8_t mode_offset;
};
static int led_axp192_on(const struct device *dev, uint32_t led)
{
const struct led_axp192_config *config = dev->config;
ARG_UNUSED(led);
if (config->mode != CHGLED_CTRL_BY_REG) {
return -EINVAL;
}
return i2c_reg_update_byte_dt(&config->i2c, config->addr, CHGLED_OUTPUT_MASK, CHGLED_ON);
}
static int led_axp192_off(const struct device *dev, uint32_t led)
{
const struct led_axp192_config *config = dev->config;
ARG_UNUSED(led);
if (config->mode != CHGLED_CTRL_BY_REG) {
return -EINVAL;
}
return i2c_reg_update_byte_dt(&config->i2c, config->addr, CHGLED_OUTPUT_MASK, CHGLED_OFF);
}
static int led_axp192_blink(const struct device *dev, uint32_t led, uint32_t delay_on,
uint32_t delay_off)
{
const struct led_axp192_config *config = dev->config;
ARG_UNUSED(led);
if (config->mode != CHGLED_CTRL_BY_REG) {
return -EINVAL;
}
if ((delay_on == SLOW_BLINK_DELAY_ON) && (delay_off == SLOW_BLINK_DELAY_OFF)) {
return i2c_reg_update_byte_dt(&config->i2c, config->addr, CHGLED_OUTPUT_MASK,
CHGLED_BLINK_SLOW);
} else if ((delay_on == FAST_BLINK_DELAY_ON) && (delay_off == FAST_BLINK_DELAY_OFF)) {
return i2c_reg_update_byte_dt(&config->i2c, config->addr, CHGLED_OUTPUT_MASK,
CHGLED_BLINK_FAST);
} else {
LOG_ERR("The AXP192 blink setting can only %d/%d or %d/%d. (%d/%d)",
SLOW_BLINK_DELAY_ON, SLOW_BLINK_DELAY_OFF, FAST_BLINK_DELAY_ON,
FAST_BLINK_DELAY_OFF, delay_on, delay_off);
}
return -ENOTSUP;
}
static DEVICE_API(led, led_axp192_api) = {
.on = led_axp192_on,
.off = led_axp192_off,
.blink = led_axp192_blink,
};
static int led_axp192_init(const struct device *dev)
{
const struct led_axp192_config *config = dev->config;
switch (config->mode) {
case CHGLED_CTRL_TYPE_A:
case CHGLED_CTRL_TYPE_B:
case CHGLED_CTRL_BY_REG:
case CHGLED_CTRL_BY_CHARGE:
return i2c_reg_update_byte_dt(&config->i2c, config->addr,
config->mode_mask << config->mode_offset,
config->mode << config->mode_offset);
}
return -EINVAL;
}
#define LED_AXPXXXX_DEFINE(n, model, compat) \
static const struct led_axp192_config led_axp_config_##model##_##n = { \
.i2c = I2C_DT_SPEC_GET(DT_PARENT(n)), \
.addr = AXP##model##_REG_CHGLED, \
.mode = UTIL_CAT(CHGLED_CTRL_, DT_STRING_UPPER_TOKEN(n, x_powers_mode)), \
.mode_mask = AXP##model##_CHGLED_CTRL_MASK, \
.mode_offset = AXP##model##_CHGLED_CTRL_OFFSET, \
}; \
\
DEVICE_DT_DEFINE(n, led_axp192_init, NULL, NULL, &led_axp_config_##model##_##n, \
POST_KERNEL, CONFIG_LED_INIT_PRIORITY, &led_axp192_api);
#define LED_AXP192_DEFINE(n) LED_AXPXXXX_DEFINE(n, 192, x_powers_axp192_led)
#define LED_AXP2101_DEFINE(n) LED_AXPXXXX_DEFINE(n, 2101, x_powers_axp2101_led)
DT_FOREACH_STATUS_OKAY(x_powers_axp192_led, LED_AXP192_DEFINE)
DT_FOREACH_STATUS_OKAY(x_powers_axp2101_led, LED_AXP2101_DEFINE)