Skip to content

Commit

Permalink
[pmu] axp driver reconfiguration
Browse files Browse the repository at this point in the history
  • Loading branch information
YuzukiTsuru committed Mar 20, 2024
1 parent 9fbfbef commit 0036d7e
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 202 deletions.
27 changes: 27 additions & 0 deletions include/drivers/pmu/axp.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,33 @@ typedef struct _axp_contrl_info {
axp_step_info_t axp_step_tbl[4];// Voltage step table for the domain.
} axp_contrl_info;

/* Common function */

/**
* @brief Set the voltage for a specific power domain controlled by AXP.
*
* @param i2c_dev Pointer to the I2C device structure.
* @param name Name of the power domain.
* @param set_vol Voltage value to set.
* @param onoff Whether to turn on or off the power domain (1 for on, 0 for off).
* @param axp_ctrl_tbl Pointer to the AXP control information table.
* @param axp_ctrl_tbl_size Size of the AXP control information table.
* @param axp_addr AXP device address.
* @return Integer indicating the success status of the operation.
*/
int axp_set_vol(sunxi_i2c_t *i2c_dev, char *name, int set_vol, int onoff, axp_contrl_info *axp_ctrl_tbl, uint8_t axp_ctrl_tbl_size, uint8_t axp_addr);

/**
* @brief Get the voltage value for a specific power domain controlled by AXP.
*
* @param i2c_dev Pointer to the I2C device structure.
* @param name Name of the power domain.
* @param axp_ctrl_tbl Pointer to the AXP control information table.
* @param axp_ctrl_tbl_size Size of the AXP control information table.
* @param axp_addr AXP device address.
* @return The voltage value of the specified power domain.
*/
int axp_get_vol(sunxi_i2c_t *i2c_dev, char *name, axp_contrl_info *axp_ctrl_tbl, uint8_t axp_ctrl_tbl_size, uint8_t axp_addr);

/* AXP1530 */

Expand Down
1 change: 1 addition & 0 deletions src/drivers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ endif()

if (CONFIG_CHIP_WITHPMU)
set(DRIVER_PMU
pmu/axp.c
pmu/axp1530.c
pmu/axp2202.c
)
Expand Down
131 changes: 131 additions & 0 deletions src/drivers/pmu/axp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/* SPDX-License-Identifier: Apache-2.0 */

#include <io.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <types.h>

#include <common.h>
#include <log.h>

#include <pmu/axp.h>

/**
* Get control information from the table based on the given name.
*
* @param name The name of the control information to retrieve.
* @return A pointer to the axp_contrl_info structure corresponding to the given name,
* or NULL if the name is not found in the table.
*/
static axp_contrl_info *get_ctrl_info_from_tbl(char *name, axp_contrl_info *axp_ctrl_tbl, uint8_t axp_ctrl_tbl_size) {
int i = 0;
for (i = 0; i < axp_ctrl_tbl_size; i++) {
if (!strncmp(name, axp_ctrl_tbl[i].name, strlen(axp_ctrl_tbl[i].name))) {
break;
}
}
if (i >= axp_ctrl_tbl_size) {
return NULL;
}
return (axp_ctrl_tbl + i);
}

int axp_set_vol(sunxi_i2c_t *i2c_dev, char *name, int set_vol, int onoff, axp_contrl_info *axp_ctrl_tbl, uint8_t axp_ctrl_tbl_size, uint8_t axp_addr) {
uint8_t reg_value, i;
axp_contrl_info *p_item = NULL;
uint8_t base_step = 0;

p_item = get_ctrl_info_from_tbl(name, axp_ctrl_tbl, axp_ctrl_tbl_size);
if (!p_item) {
return -1;
}

if ((set_vol > 0) && (p_item->min_vol)) {
if (set_vol < p_item->min_vol) {
set_vol = p_item->min_vol;
} else if (set_vol > p_item->max_vol) {
set_vol = p_item->max_vol;
}

if (sunxi_i2c_read(i2c_dev, axp_addr, p_item->cfg_reg_addr, &reg_value)) {
return -1;
}

reg_value &= ~p_item->cfg_reg_mask;

for (i = 0; p_item->axp_step_tbl[i].step_max_vol != 0; i++) {
if ((set_vol > p_item->axp_step_tbl[i].step_max_vol) && (set_vol < p_item->axp_step_tbl[i + 1].step_min_vol)) {
set_vol = p_item->axp_step_tbl[i].step_max_vol;
}
if (p_item->axp_step_tbl[i].step_max_vol >= set_vol) {
reg_value |= ((base_step + ((set_vol - p_item->axp_step_tbl[i].step_min_vol) / p_item->axp_step_tbl[i].step_val)) << p_item->reg_addr_offset);
if (p_item->axp_step_tbl[i].regation) {
u8 reg_value_temp = (~reg_value & p_item->cfg_reg_mask);
reg_value &= ~p_item->cfg_reg_mask;
reg_value |= reg_value_temp;
}
break;
} else {
base_step += ((p_item->axp_step_tbl[i].step_max_vol - p_item->axp_step_tbl[i].step_min_vol + p_item->axp_step_tbl[i].step_val) / p_item->axp_step_tbl[i].step_val);
}
}

if (sunxi_i2c_write(i2c_dev, axp_addr, p_item->cfg_reg_addr, reg_value)) {
return -1;
}
}

if (onoff < 0) {
return 0;
}
if (sunxi_i2c_read(i2c_dev, axp_addr, p_item->ctrl_reg_addr, &reg_value)) {
return -1;
}
if (onoff == 0) {
reg_value &= ~(1 << p_item->ctrl_bit_ofs);
} else {
reg_value |= (1 << p_item->ctrl_bit_ofs);
}
if (sunxi_i2c_write(i2c_dev, axp_addr, p_item->ctrl_reg_addr, reg_value)) {
return -1;
}
return 0;
}

int axp_get_vol(sunxi_i2c_t *i2c_dev, char *name, axp_contrl_info *axp_ctrl_tbl, uint8_t axp_ctrl_tbl_size, uint8_t axp_addr) {
uint8_t reg_value, i;
axp_contrl_info *p_item = NULL;
uint8_t base_step1 = 0;
uint8_t base_step2 = 0;
int vol;

p_item = get_ctrl_info_from_tbl(name, axp_ctrl_tbl, axp_ctrl_tbl_size);
if (!p_item) {
return -1;
}

if (sunxi_i2c_read(i2c_dev, axp_addr, p_item->ctrl_reg_addr, &reg_value)) {
return -1;
}

if (!(reg_value & (0x01 << p_item->ctrl_bit_ofs))) {
return 0;
}

if (sunxi_i2c_read(i2c_dev, axp_addr, p_item->cfg_reg_addr, &reg_value)) {
return -1;
}
reg_value &= p_item->cfg_reg_mask;
reg_value >>= p_item->reg_addr_offset;
for (i = 0; p_item->axp_step_tbl[i].step_max_vol != 0; i++) {
base_step1 += ((p_item->axp_step_tbl[i].step_max_vol - p_item->axp_step_tbl[i].step_min_vol + p_item->axp_step_tbl[i].step_val) / p_item->axp_step_tbl[i].step_val);
if (reg_value < base_step1) {
vol = (reg_value - base_step2) * p_item->axp_step_tbl[i].step_val + p_item->axp_step_tbl[i].step_min_vol;
return vol;
}
base_step2 += ((p_item->axp_step_tbl[i].step_max_vol - p_item->axp_step_tbl[i].step_min_vol + p_item->axp_step_tbl[i].step_val) / p_item->axp_step_tbl[i].step_val);
}
return -1;
}
115 changes: 2 additions & 113 deletions src/drivers/pmu/axp1530.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,27 +31,6 @@ static axp_contrl_info axp_ctrl_tbl[] = {
};
/* clang-format on */

/**
* Get control information from the table based on the given name.
*
* @param name The name of the control information to retrieve.
* @return A pointer to the axp_contrl_info structure corresponding to the given name,
* or NULL if the name is not found in the table.
*/
static axp_contrl_info *get_ctrl_info_from_tbl(char *name) {
int i = 0;
int size = ARRAY_SIZE(axp_ctrl_tbl);
for (i = 0; i < size; i++) {
if (!strncmp(name, axp_ctrl_tbl[i].name, strlen(axp_ctrl_tbl[i].name))) {
break;
}
}
if (i >= size) {
return NULL;
}
return (axp_ctrl_tbl + i);
}

int pmu_axp1530_init(sunxi_i2c_t *i2c_dev) {
uint8_t axp_val;
int ret;
Expand Down Expand Up @@ -121,101 +100,11 @@ int pmu_axp1530_set_dual_phase(sunxi_i2c_t *i2c_dev) {
}

int pmu_axp1530_set_vol(sunxi_i2c_t *i2c_dev, char *name, int set_vol, int onoff) {
uint8_t reg_value, i;
axp_contrl_info *p_item = NULL;
uint8_t base_step = 0;

p_item = get_ctrl_info_from_tbl(name);
if (!p_item) {
return -1;
}

if ((set_vol > 0) && (p_item->min_vol)) {
if (set_vol < p_item->min_vol) {
set_vol = p_item->min_vol;
} else if (set_vol > p_item->max_vol) {
set_vol = p_item->max_vol;
}

if (sunxi_i2c_read(i2c_dev, AXP1530_RUNTIME_ADDR, p_item->cfg_reg_addr, &reg_value)) {
return -1;
}

reg_value &= ~p_item->cfg_reg_mask;

for (i = 0; p_item->axp_step_tbl[i].step_max_vol != 0; i++) {
if ((set_vol > p_item->axp_step_tbl[i].step_max_vol) && (set_vol < p_item->axp_step_tbl[i + 1].step_min_vol)) {
set_vol = p_item->axp_step_tbl[i].step_max_vol;
}
if (p_item->axp_step_tbl[i].step_max_vol >= set_vol) {
reg_value |= ((base_step + ((set_vol - p_item->axp_step_tbl[i].step_min_vol) / p_item->axp_step_tbl[i].step_val)) << p_item->reg_addr_offset);
if (p_item->axp_step_tbl[i].regation) {
u8 reg_value_temp = (~reg_value & p_item->cfg_reg_mask);
reg_value &= ~p_item->cfg_reg_mask;
reg_value |= reg_value_temp;
}
break;
} else {
base_step += ((p_item->axp_step_tbl[i].step_max_vol - p_item->axp_step_tbl[i].step_min_vol + p_item->axp_step_tbl[i].step_val) / p_item->axp_step_tbl[i].step_val);
}
}

if (sunxi_i2c_write(i2c_dev, AXP1530_RUNTIME_ADDR, p_item->cfg_reg_addr, reg_value)) {
return -1;
}
}

if (onoff < 0) {
return 0;
}
if (sunxi_i2c_read(i2c_dev, AXP1530_RUNTIME_ADDR, p_item->ctrl_reg_addr, &reg_value)) {
return -1;
}
if (onoff == 0) {
reg_value &= ~(1 << p_item->ctrl_bit_ofs);
} else {
reg_value |= (1 << p_item->ctrl_bit_ofs);
}
if (sunxi_i2c_write(i2c_dev, AXP1530_RUNTIME_ADDR, p_item->ctrl_reg_addr, reg_value)) {
return -1;
}
return 0;
return axp_set_vol(i2c_dev, name, set_vol, onoff, axp_ctrl_tbl, ARRAY_SIZE(axp_ctrl_tbl), AXP1530_RUNTIME_ADDR);
}

int pmu_axp1530_get_vol(sunxi_i2c_t *i2c_dev, char *name) {
uint8_t reg_value, i;
axp_contrl_info *p_item = NULL;
uint8_t base_step1 = 0;
uint8_t base_step2 = 0;
int vol;

p_item = get_ctrl_info_from_tbl(name);
if (!p_item) {
return -1;
}

if (sunxi_i2c_read(i2c_dev, AXP1530_RUNTIME_ADDR, p_item->ctrl_reg_addr, &reg_value)) {
return -1;
}

if (!(reg_value & (0x01 << p_item->ctrl_bit_ofs))) {
return 0;
}

if (sunxi_i2c_read(i2c_dev, AXP1530_RUNTIME_ADDR, p_item->cfg_reg_addr, &reg_value)) {
return -1;
}
reg_value &= p_item->cfg_reg_mask;
reg_value >>= p_item->reg_addr_offset;
for (i = 0; p_item->axp_step_tbl[i].step_max_vol != 0; i++) {
base_step1 += ((p_item->axp_step_tbl[i].step_max_vol - p_item->axp_step_tbl[i].step_min_vol + p_item->axp_step_tbl[i].step_val) / p_item->axp_step_tbl[i].step_val);
if (reg_value < base_step1) {
vol = (reg_value - base_step2) * p_item->axp_step_tbl[i].step_val + p_item->axp_step_tbl[i].step_min_vol;
return vol;
}
base_step2 += ((p_item->axp_step_tbl[i].step_max_vol - p_item->axp_step_tbl[i].step_min_vol + p_item->axp_step_tbl[i].step_val) / p_item->axp_step_tbl[i].step_val);
}
return -1;
return axp_get_vol(i2c_dev, name, axp_ctrl_tbl, ARRAY_SIZE(axp_ctrl_tbl), AXP1530_RUNTIME_ADDR);
}

void pmu_axp1530_dump(sunxi_i2c_t *i2c_dev) {
Expand Down
Loading

0 comments on commit 0036d7e

Please sign in to comment.