Strtoul command

本文介绍了 C 语言中的 strtoul 函数,该函数用于将字符串转换为无符号长整型数值。文章详细解释了函数参数的意义及返回值的情况,并通过一个示例程序展示了如何使用此函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

function
>

strtoul                                                                           #include <stdlib.h> 

unsigned long int strtoul (const char* str, char** endptr, int base);
Convert string to unsigned long integer
Parses the C-string str, interpreting its content as an integral number of the specified base, which is returned as an value of type unsigned long int.

This function operates like strtol to interpret the string, but produces numbers of type unsigned long int (see strtolfor details on the interpretation process).

Parameters

str
C-string containing the representation of an integral number.
endptr
Reference to an object of type char*, whose value is set by the function to the next character in str after the numerical value.
This parameter can also be a null pointer, in which case it is not used.
base
Numerical base (radix) that determines the valid characters and their interpretation.
If this is 0, the base used is determined by the format in the sequence (see strtol for details).

Return Value

On success, the function returns the converted integral number as an unsigned long int value.
If no valid conversion could be performed, a zero value is returned.
If the value read is out of the range of representable values by an unsigned long int, the function returns ULONG_MAX(defined in <climits>), and errno is set to ERANGE.

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* strtoul example */
#include <stdio.h>      /* printf, NULL */
#include <stdlib.h>     /* strtoul */

int main ()
{
  char buffer [256];
  unsigned long ul;
  printf ("Enter an unsigned number: ");
  fgets (buffer, 256, stdin);
  ul = strtoul (buffer, NULL, 0);
  printf ("Value entered: %lu. Its double: %lu\n",ul,ul*2);
  return 0;
}


Possible output:

Enter an unsigned number: 0x7ff
Value entered: 2047. Its double: 4094

#include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/seq_file.h> // single_open #include <linux/slab.h> // kfree kzalloc #include <linux/proc_fs.h> // proc_creat #include <linux/uaccess.h> // copy_from_user #include <linux/version.h> #include "kdrv_pmbus_api.h" static int pmbus_test_show(struct seq_file *seq, void *arg) { return 0; } static int pmbus_test_open(struct inode *pnode, struct file *pfile) { return single_open(pfile, pmbus_test_show, NULL); } int test_kdrv_pmbus_write_block_data(u32 bus_id, u32 slave_addr, u32 cmd, u32 len) { u8 *buf = NULL; int i; u32 ret; buf = (u8 *)kzalloc(len, GFP_KERNEL); if (buf == NULL) { pr_err("kzalloc err!\r\n"); return -ENOMEM; } buf[0] = len - 1; for (i = 1; i < len; i++) { buf[i] = i; } ret = kdrv_pmbus_write_block_data(bus_id, slave_addr, cmd, buf, len); if (ret) { pr_err("kdrv_pmbus_write_block_data fail\r\n"); kfree(buf); return ret; } kfree(buf); return 0; } int test_kdrv_pmbus_read_block_data(u32 bus_id, u32 slave_addr, u32 cmd, u32 len) { int ret; int i; u8 *buf = NULL; buf = (u8 *)kzalloc(len, GFP_KERNEL); if (buf == NULL) { pr_err("kzalloc err!\r\n"); return -ENOMEM; } ret = kdrv_pmbus_read_block_data(bus_id, slave_addr, cmd, buf, len); if (ret) { pr_err("kdrv_pmbus_read_block_data fail bus_id:%#x, addr:%#x, cmd:%#x\n", bus_id, slave_addr, cmd); kfree(buf); return ret; } for (i = 0; i < len; i++) { pr_info("read: bus_id:%#x, addr:%#x, cmd:%#x, buf[%d]:[0x%02x], len:%u\n", bus_id, slave_addr, cmd, i, buf[i], len); } kfree(buf); return 0; } int test_kdrv_pmbus_read_byte(u32 bus_id, u32 slave_addr, u32 cmd) { int ret; u8 data; ret = kdrv_pmbus_read_byte(bus_id, slave_addr, cmd, &data); if (ret) { pr_err("kdrv_pmbus_read_byte fail bus_id:%u, addr:%#x, cmd:%#x\n", bus_id, slave_addr, cmd); return ret; } pr_info("read: bus_id:%#x, addr:%#x, cmd:%#x, data:%#x\n", bus_id, slave_addr, cmd, data); return 0; } int test_kdrv_pmbus_read_word(u32 bus_id, u32 slave_addr, u32 cmd) { int ret; u16 data; ret = kdrv_pmbus_read_word(bus_id, slave_addr, cmd, &data); if (ret) { pr_err("kdrv_pmbus_read_word fail bus_id:%u, addr:%#x, cmd:%#x\n", bus_id, slave_addr, cmd); return ret; } pr_info("read: bus_id:%#x, addr:%#x, cmd:%#x, data:%#x\n", bus_id, slave_addr, cmd, data); return 0; } int test_kdrv_pmbus_write_byte(u32 bus_id, u32 slave_addr, u32 cmd, u32 data) { int ret; ret = kdrv_pmbus_write_byte(bus_id, slave_addr, cmd, (u8)data); if (ret) { pr_err("kdrv_pmbus_write_byte fail bus_id:%u, addr:%#x, cmd:%#x\n", bus_id, slave_addr, cmd); return ret; } pr_info("write byte: bus_id:%#x, addr:%#x, cmd:%#x, data:%#x\n", bus_id, slave_addr, cmd, data); return 0; } int test_kdrv_pmbus_write_word(u32 bus_id, u32 slave_addr, u32 cmd, u32 data) { int ret; ret = kdrv_pmbus_write_word(bus_id, slave_addr, cmd, (u16)data); if (ret) { pr_err("kdrv_pmbus_write_word fail bus_id:%u, addr:%#x, cmd:%#x\n", bus_id, slave_addr, cmd); return ret; } pr_info("write word: bus_id:%#x, addr:%#x, cmd:%#x, data:%#x\n", bus_id, slave_addr, cmd, data); return 0; } int test_kdrv_pmbus_write_cmd(u32 bus_id, u32 slave_addr, u32 cmd) { int ret; ret = kdrv_pmbus_write_cmd(bus_id, slave_addr, cmd); if (ret) { pr_err("kdrv_pmbus_write_cmd fail bus_id:%u, addr:%#x, cmd:%#x\n", bus_id, slave_addr, cmd); return ret; } pr_info("write word: bus_id:%#x, addr:%#x, cmd:%#x\n", bus_id, slave_addr, cmd); return 0; } #define PMBUS_CMD_READ_BYTE 0 #define PMBUS_CMD_READ_WORD 1 #define PMBUS_CMD_WRITE_BYTE 2 #define PMBUS_CMD_WRITE_WORD 3 #define PMBUS_CMD_READ_BLOCK 4 #define PMBUS_CMD_WRITE_BLOCK 5 #define PMBUS_CMD_WRITE_CMD 6 #define PMBUS_CMD_RESET 7 #define PMBUS_CMD_INIT 8 #define CFG_LINE_SIZE 120 static ssize_t pmbus_test_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { u32 cmd; u32 bus_id; u32 command; u32 data; u32 slave_addr; char *next = NULL; char line[CFG_LINE_SIZE] = {0}; if (len > (CFG_LINE_SIZE - 1)) { return -E2BIG; } if (copy_from_user(line, buf, len)) { return -EINVAL; } /* usage: echo <cmd> [bus_id][slave_addr] [cmd] > pmbus_test */ cmd = simple_strtoul(line, &next, 0); bus_id = simple_strtoul(next + 1, &next, 0); switch (cmd) { case PMBUS_CMD_READ_BYTE: slave_addr = simple_strtoul(next + 1, &next, 0); command = simple_strtoul(next + 1, &next, 0); (void)test_kdrv_pmbus_read_byte(bus_id, slave_addr, command); break; case PMBUS_CMD_READ_WORD: slave_addr = simple_strtoul(next + 1, &next, 0); command = simple_strtoul(next + 1, &next, 0); (void)test_kdrv_pmbus_read_word(bus_id, slave_addr, command); break; case PMBUS_CMD_WRITE_BYTE: slave_addr = simple_strtoul(next + 1, &next, 0); command = simple_strtoul(next + 1, &next, 0); data = simple_strtoul(next + 1, &next, 0); (void)test_kdrv_pmbus_write_byte(bus_id, slave_addr, command, (u8)data); break; case PMBUS_CMD_WRITE_WORD: slave_addr = simple_strtoul(next + 1, &next, 0); command = simple_strtoul(next + 1, &next, 0); data = simple_strtoul(next + 1, &next, 0); (void)test_kdrv_pmbus_write_word(bus_id, slave_addr, command, (u16)data); break; case PMBUS_CMD_READ_BLOCK: slave_addr = simple_strtoul(next + 1, &next, 0); command = simple_strtoul(next + 1, &next, 0); data = simple_strtoul(next + 1, &next, 0); (void)test_kdrv_pmbus_read_block_data(bus_id, slave_addr, command, data); break; case PMBUS_CMD_WRITE_BLOCK: slave_addr = simple_strtoul(next + 1, &next, 0); command = simple_strtoul(next + 1, &next, 0); data = simple_strtoul(next + 1, &next, 0); (void)test_kdrv_pmbus_write_block_data(bus_id, slave_addr, command, data); break; case PMBUS_CMD_WRITE_CMD: slave_addr = simple_strtoul(next + 1, &next, 0); command = simple_strtoul(next + 1, &next, 0); (void)test_kdrv_pmbus_write_cmd(bus_id, slave_addr, command); break; case PMBUS_CMD_RESET: (void)kdrv_pmbus_reset(bus_id); break; case PMBUS_CMD_INIT: data = simple_strtoul(next + 1, &next, 0); (void)kdrv_pmbus_init(bus_id, data); break; default: break; } return len; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) static const struct proc_ops g_pmbus_operations = { .proc_open = pmbus_test_open, .proc_read = seq_read, .proc_write = pmbus_test_write, .proc_lseek = seq_lseek, .proc_release = single_release, }; #else static const struct file_operations g_pmbus_operations = { .open = pmbus_test_open, .read = seq_read, .write = pmbus_test_write, .llseek = seq_lseek, .release = single_release, }; #endif int __init pmbus_test_mod_init(void) { (void)proc_create("pmbus_test", S_IRUSR, NULL, &g_pmbus_operations); printk("pmbus_test_mod_init\r\n"); return 0; } void __exit pmbus_test_mod_exit(void) { (void)remove_proc_entry("pmbus_test", NULL); printk("pmbus_test_mod_exit\r\n"); } module_init(pmbus_test_mod_init); module_exit(pmbus_test_mod_exit); MODULE_DESCRIPTION("udrv pmbus api test"); MODULE_LICENSE("GPL");" #include <linux/delay.h> #include <linux/vmalloc.h> #include <linux/slab.h> #include <linux/io.h> #include <linux/iopoll.h> #include <linux/types.h> #include <linux/bitfield.h> #include "hisi_pmbus.h" #define STANDARD_MODE 1 #define FAST_MODE 2 #define GPIO_LEVEL_LOW 0 #define GPIO_LEVEL_HIGH 1 #define SET_LOW_HIGH_TIMES 9 #define AVS_WR_OPEN_REG 0x0004 #define AVS_INT_STATUS_REG 0x0008 #define AVS_INT_CLEAR_REG 0x0020 #define TRIGGER_CFG_REG 0x00B8 #define PMBUS_DISABLE 0x00 #define PMBUS_ENABLE 0x01 /* PMBUSIF_REG_GEN Base address of Module's Register */ #define PMBUSIF_REG_GEN_BASE (0x800) #define I2C_CON_REG (PMBUSIF_REG_GEN_BASE + 0x0) /* I2C控制寄存器。 */ #define I2C_CON_MASTER_ENABLE BIT(0) #define I2C_CON_SPEED_MASK (0x6U) #define I2C_CON_RESTART_EN BIT(5) #define I2C_CON_SLAVE_DISABLE BIT(6) #define I2C_DATA_CMD_REG (PMBUSIF_REG_GEN_BASE + 0x10) /* I2C数据操作寄存器。 */ #define I2C_SS_SCL_HCNT_REG (PMBUSIF_REG_GEN_BASE + 0x14) /* I2C标准速度模式SCL高电平配置寄存器。 */ #define I2C_SS_SCL_LCNT_REG (PMBUSIF_REG_GEN_BASE + 0x18) /* I2C标准速度模式SCL低电平配置寄存器。 */ #define I2C_FS_SCL_HCNT_REG (PMBUSIF_REG_GEN_BASE + 0x1C) /* I2C快速模式SCL高电平配置寄存器。 */ #define I2C_FS_SCL_LCNT_REG (PMBUSIF_REG_GEN_BASE + 0x20) /* I2C快速模式SCL低电平配置寄存器。 */ #define I2C_INTR_STAT_REG (PMBUSIF_REG_GEN_BASE + 0x2C) /* I2C屏蔽后中断状态寄存器。 */ #define I2C_INTR_MASK_REG (PMBUSIF_REG_GEN_BASE + 0x30) /* I2C中断屏蔽寄存器。 */ #define I2C_INTR_RAW_REG (PMBUSIF_REG_GEN_BASE + 0x34) /* I2C原始中断状态寄存器。 */ #define I2C_INTR_RAW_TX_ABRT BIT(6) #define I2C_INTR_RAW_ALERT_DET BIT(12) #define I2C_INTR_RAW_SCL_LOW_TOUT BIT(15) #define I2C_INTR_RAW_PMBUS_CMD_FINISH BIT(17) #define I2C_ENABLE_REG (PMBUSIF_REG_GEN_BASE + 0x6C) /* I2C工作使能寄存器。 */ #define I2C_STATUS_REG (PMBUSIF_REG_GEN_BASE + 0x70) /* I2C状态寄存器。 */ #define I2C_RXFLR_REG (PMBUSIF_REG_GEN_BASE + 0x78) /* RX_FIFO有效数据指示寄存器。 */ #define I2C_SDA_HOLD_REG (PMBUSIF_REG_GEN_BASE + 0x7C) /* SDA保持时间配置寄存器。 */ #define I2C_ENABLE_STATUS_REG (PMBUSIF_REG_GEN_BASE + 0x9C) /* I2C状态寄存器。 */ #define I2C_SCL_SWITCH_REG (PMBUSIF_REG_GEN_BASE + 0xA0) /* I2C防挂死SCL使能寄存器。 */ #define I2C_SCL_SIM_REG (PMBUSIF_REG_GEN_BASE + 0xA4) /* I2C防挂死SCL模拟寄存器。 */ #define I2C_LOCK_REG (PMBUSIF_REG_GEN_BASE + 0xAC) /* I2C lock寄存器。 */ #define I2C_SDA_SWITCH_REG (PMBUSIF_REG_GEN_BASE + 0xB0) /* I2C防挂死SDA使能寄存器。 */ #define I2C_SDA_SIM_REG (PMBUSIF_REG_GEN_BASE + 0xB4) /* I2C防挂死SDA模拟寄存器。 */ #define I2C_PMBUS_CTRL_REG (PMBUSIF_REG_GEN_BASE + 0x104) /* PMBUS全局控制寄存器。 */ #define I2C_PMBUS_CTRL_PEC_EN BIT(2) #define I2C_PMBUS_CTRL_ALERT_EN BIT(1) #define I2C_LOW_TIMEOUT_REG (PMBUSIF_REG_GEN_BASE + 0x108) /* SCL低电平超时值配置寄存器。 */ #define I2C_PMBUS_SCL_DET_REG (PMBUSIF_REG_GEN_BASE + 0x12C) /* PMBUS SCL检测寄存器。 */ #define I2C_PMBUS_SCL_DET_IDLE_DET_EN BIT(0) #define I2C_PMBUS_SCL_DET_TIMEOUT_EN BIT(1) #define I2C_PMBUS_IDLECNT_REG (PMBUSIF_REG_GEN_BASE + 0x130) /* SCL高电平空闲值配置寄存器。 */ #define I2C_PMBUS_RST_REG (PMBUSIF_REG_GEN_BASE + 0x134) /* 软件复位配置寄存器。 */ /* PMBUS_PROC_REG_GEN Base address of Module's Register */ #define PMBUS_PROC_REG_GEN_BASE (0xA00) #define PMBUS_WR_OPEN_REG (PMBUS_PROC_REG_GEN_BASE + 0x4) /* PMBUS全局参数保护寄存器。 */ #define PMBUS_INT_CLR_REG (PMBUS_PROC_REG_GEN_BASE + 0x10) /* PMBUS中断清除寄存器 */ #define PMBUS_WAIT_CNT 30000 /* PMU CMD */ #define STOP_EN (1U << 10) #define ADDR_EN (1U << 9) #define CMD_READ (1U << 8) #define SDA_IN BIT(9) #define PMBUS_I2C_RECOVERY_CYCLE_CNT 10 static inline void pmbus_reg_write(struct io_region *reg_region, u32 reg, u32 val) { pr_debug("[iWare][Debug] %s reg=%#x val =%#x\r\n", __FUNCTION__, reg, val); iowrite32(val, reg_region->io_base + reg); } static inline u32 pmbus_reg_read(struct io_region *reg_region, u32 reg) { u32 val; val = ioread32(reg_region->io_base + reg); pr_debug("[iWare][Debug] %s reg=%#x val =%#x\r\n", __FUNCTION__, reg, val); return val; } /* try to recovery the bus if sda locked to low level */ static void pmbus_recovery_bus(struct io_region *reg_region) { int i; u32 status; status = pmbus_reg_read(reg_region, I2C_STATUS_REG); /* if SDA keep low, assume the bus hang up */ if ((status & SDA_IN) == 0) { /* disable pmbus */ pmbus_reg_write(reg_region, I2C_ENABLE_REG, 0x0); /* enable output software simulaition */ pmbus_reg_write(reg_region, I2C_SCL_SWITCH_REG, 0x1); pmbus_reg_write(reg_region, I2C_SDA_SWITCH_REG, 0x1); /* output at least 9 clocks to try to recover the bus */ for (i = 0; i < PMBUS_I2C_RECOVERY_CYCLE_CNT; i++) { pmbus_reg_write(reg_region, I2C_SCL_SIM_REG, 0x0); udelay(50); // 延时50us pmbus_reg_write(reg_region, I2C_SCL_SIM_REG, 0x1); udelay(50); // 延时50us } /* disable output software simulaition */ pmbus_reg_write(reg_region, I2C_SCL_SWITCH_REG, 0x0); pmbus_reg_write(reg_region, I2C_SDA_SWITCH_REG, 0x0); /* enable pmbus */ pmbus_reg_write(reg_region, I2C_ENABLE_REG, 0x1); pr_info("[iWare][Info] pmbus hang recovery done\n"); } } static int pmbus_wait_write_finish(struct io_region *reg_region) { int i; u32 status = 0; for (i = 0; i < PMBUS_WAIT_CNT; i++) { status = pmbus_reg_read(reg_region, I2C_INTR_RAW_REG); if (((status & I2C_INTR_RAW_SCL_LOW_TOUT) == 0) && ((status & I2C_INTR_RAW_TX_ABRT) == 0) && ((status & I2C_INTR_RAW_PMBUS_CMD_FINISH) != 0)) { // 清除所有中断 pmbus_reg_write(reg_region, I2C_INTR_RAW_REG, 0xffffffff); return 0; } udelay(1); } pr_err("[iWare][Error] pmbus_write timeout! raw_int_status:0x%x\n", status); // 清除所有中断 pmbus_reg_write(reg_region, I2C_INTR_RAW_REG, 0xffffffff); pmbus_recovery_bus(reg_region); return -EBUSY; } static int pmbus_send_byte_v200(struct io_region *reg_region, struct pmbus_msg *msg) { pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, ADDR_EN | msg->slave_addr); if ((msg->type & PMBUS_FLAG_EXT) != 0) { pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, STOP_EN | msg->command); pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, STOP_EN | msg->command_ext); } else { pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, STOP_EN | msg->command); } return pmbus_wait_write_finish(reg_region); } static int pmbus_write_bytes_v200(struct io_region *reg_region, struct pmbus_msg *msg) { unsigned int i; pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, ADDR_EN | msg->slave_addr); pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, msg->command); if ((msg->type & PMBUS_FLAG_EXT) != 0) { pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, msg->command_ext); } for (i = 0; i < msg->data_len - 1; i++) { pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, msg->data[i]); } pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, STOP_EN | msg->data[msg->data_len - 1]); return pmbus_wait_write_finish(reg_region); } #define PMBUS_READ_WAIT_TIMEOUT 1000000ULL #define PMUBS_READ_WAIT_DELAY_US 1UL static int pmbus_wait_read_finish(struct io_region *reg_region, u8 read_len) { int ret; u32 data_num; ret = readl_poll_timeout(reg_region->io_base + I2C_RXFLR_REG, data_num, (data_num >= read_len), PMUBS_READ_WAIT_DELAY_US, PMBUS_READ_WAIT_TIMEOUT); if (ret != 0) { pr_err("[iWare][Error] wait read_finish timeout!! read_len[%u] fifo num[%u], raw_int_status:0x%x\n", read_len, data_num, pmbus_reg_read(reg_region, I2C_INTR_RAW_REG)); // 清除所有中断 pmbus_reg_write(reg_region, I2C_INTR_RAW_REG, 0xffffffff); pmbus_recovery_bus(reg_region); return ret; } return 0; } static void pmbus_clear_rx_fifo(struct io_region *reg_region) { u8 rx_fifo_data_num; u8 i; u32 tmp; /* clean rx fifo */ rx_fifo_data_num = (u8)pmbus_reg_read(reg_region, I2C_RXFLR_REG); for (i = 0; i < rx_fifo_data_num; i++) { tmp = pmbus_reg_read(reg_region, I2C_DATA_CMD_REG); // 把fifo读清 } } static int pmbus_read_bytes_v200(struct io_region *reg_region, struct pmbus_msg *msg) { int ret; unsigned int i; u32 status; /* 先把rx fifo读清 */ pmbus_clear_rx_fifo(reg_region); pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, ADDR_EN | msg->slave_addr); pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, msg->command); if ((msg->type & PMBUS_FLAG_EXT) != 0) { // 扩展16bit 命令 pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, msg->command_ext); } pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, ADDR_EN | CMD_READ | msg->slave_addr); for (i = 0; i < msg->data_len - 1; i++) { pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, CMD_READ); } pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, STOP_EN | CMD_READ); ret = pmbus_wait_read_finish(reg_region, msg->data_len); if (ret != 0) { pr_err("[iWare][Error] %s slave_addr(0x%x), cmd(0x%x), time out\n", __func__, msg->slave_addr, msg->command); pmbus_recovery_bus(reg_region); return -EAGAIN; } for (i = 0; i < msg->data_len; i++) { msg->data[i] = (u8)pmbus_reg_read(reg_region, I2C_DATA_CMD_REG); } /* for block read, first read code is data length */ if ((msg->type & PMBUS_FLAG_BLOCK) != 0) { if (msg->data[0] > msg->data_len) { pr_info("[iWare][Info] pmbus read slave[0x%02x] command[0x%02x] block data may lossed, toalLen[%u]\n", msg->slave_addr, msg->command, msg->data[0]); } } // 清中断 status = pmbus_reg_read(reg_region, I2C_INTR_RAW_REG); pmbus_reg_write(reg_region, I2C_INTR_RAW_REG, status); return 0; } static int pmbus_reset_v200(struct io_region *reg_region) { pmbus_reg_write(reg_region, I2C_PMBUS_RST_REG, 1); udelay(1); pmbus_reg_write(reg_region, I2C_PMBUS_RST_REG, 0); udelay(1); return 0; } /* 不同soc解锁码不同, chip dtsi里配置 309a 1260 avs_wr_unlock_key 0x5a5a5a5a 0x1ACCE551 pmbus_wr_unlock_key 0x5a5a5a5a 0x1ACCE551 i2c_unlock_key 0x5a5a5a5a 0x36313832 */ static void pmbus_unlock_reg(struct io_region *reg_region, struct pmbus_unlock_key *key) { /* unlock avs wr */ pmbus_reg_write(reg_region, AVS_WR_OPEN_REG, key->avs_wr_unlock_key); /* unlock pmbus wr */ pmbus_reg_write(reg_region, PMBUS_WR_OPEN_REG, key->pmbus_wr_unlock_key); /* unlock pmbus i2c wr */ pmbus_reg_write(reg_region, I2C_LOCK_REG, key->i2c_unlock_key); } static void pmbus_config_timing_cnt(struct io_region *reg_region, u8 speed_mode, struct pmbus_timings_cfg *pmbus_cfg) { if (speed_mode == STANDARD_MODE) { // 标准模式 pmbus_reg_write(reg_region, I2C_SS_SCL_LCNT_REG, pmbus_cfg->lcnt); pmbus_reg_write(reg_region, I2C_SS_SCL_HCNT_REG, pmbus_cfg->hcnt); } else { // 快速模式 pmbus_reg_write(reg_region, I2C_FS_SCL_LCNT_REG, pmbus_cfg->lcnt); pmbus_reg_write(reg_region, I2C_FS_SCL_HCNT_REG, pmbus_cfg->hcnt); } // 屏蔽所有中断 pmbus_reg_write(reg_region, I2C_INTR_MASK_REG, 0xFFFFFFFF); pmbus_reg_write(reg_region, I2C_SDA_HOLD_REG, pmbus_cfg->hold_cnt); // PMBus的SCL低电平超时值(PMBus协议规定为25~35ms) pmbus_reg_write(reg_region, I2C_LOW_TIMEOUT_REG, pmbus_cfg->timeout_cnt); // 默认30ms // PMBus的SCL高电平空闲值(PMBus协议规定为>50us) pmbus_reg_write(reg_region, I2C_PMBUS_IDLECNT_REG, pmbus_cfg->idle_cnt); // 默认100us } static int pmbus_init_v200(struct io_region *reg_region, u32 pec_en, u32 bus_freq_hz, struct pmbus_timings_cfg *cfg, struct pmbus_unlock_key *key) { u32 val = 0; u8 speed_mode; int ret; if (bus_freq_hz > PMBUS_MAX_FAST_MODE_FREQ) { pr_err("[iWare][Error] invalid para bus_freq_hz =%u\r\n", bus_freq_hz); return -EINVAL; } ret = pmbus_reset_v200(reg_region); if (ret != 0) { return ret; } /* unlock */ pmbus_unlock_reg(reg_region, key); /* stop triger */ pmbus_reg_write(reg_region, TRIGGER_CFG_REG, 0x0); /* disable pmbus */ pmbus_reg_write(reg_region, I2C_ENABLE_REG, PMBUS_DISABLE); speed_mode = (bus_freq_hz <= PMBUS_MAX_STANDARD_MODE_FREQ) ? STANDARD_MODE : FAST_MODE; val |= I2C_CON_MASTER_ENABLE | I2C_CON_SLAVE_DISABLE | I2C_CON_RESTART_EN; val |= (u32)FIELD_PREP(I2C_CON_SPEED_MASK, speed_mode); pmbus_reg_write(reg_region, I2C_CON_REG, val); pmbus_config_timing_cnt(reg_region, speed_mode, cfg); /* config scl detect */ pmbus_reg_write(reg_region, I2C_PMBUS_SCL_DET_REG, I2C_PMBUS_SCL_DET_IDLE_DET_EN | I2C_PMBUS_SCL_DET_TIMEOUT_EN); /* enable pec and alert */ val = I2C_PMBUS_CTRL_ALERT_EN; if (pec_en != 0) { pr_info("[iWare][Info] pmbus enable pec \r\n"); val |= I2C_PMBUS_CTRL_PEC_EN; } pmbus_reg_write(reg_region, I2C_PMBUS_CTRL_REG, val); /* enable pmbus */ pmbus_reg_write(reg_region, I2C_ENABLE_REG, PMBUS_ENABLE); // 清中断 pmbus_reg_write(reg_region, AVS_INT_CLEAR_REG, 0xFFFFFFFF); pmbus_reg_write(reg_region, PMBUS_INT_CLR_REG, 0xFFFFFFFF); pmbus_reg_write(reg_region, I2C_INTR_RAW_REG, 0xFFFFFFFF); return 0; } const struct hisi_pmbus_ops hisi_pmbus_v200_ops = { .init = pmbus_init_v200, .reset = pmbus_reset_v200, .send_byte = pmbus_send_byte_v200, .read_bytes = pmbus_read_bytes_v200, .write_bytes = pmbus_write_bytes_v200, }; const struct hisi_pmbus_ops *hisi_pmbus_get_ops(void) { return &hisi_pmbus_v200_ops; }" #include <linux/device.h> #include <linux/errno.h> #include "hisi_pmbus.h" #include "kdrv_pmbus_api.h" #define PMBUS_BLOCK_MAX 32 static void hisi_pmbus_fill_msg(struct pmbus_msg *msg, u8 type, u8 slave_addr, u16 command) { u8 cmd; cmd = (u8)(command >> 0x8); // 高8位为extended cmd 指示这是一条扩展命令 if ((cmd == PMBUS_MFR_SPECIFIC_COMMAND_EXT || cmd == PMBUS_COMMAND_EXT)) { msg->type = type | PMBUS_FLAG_EXT; msg->command = cmd; msg->command_ext = (u8)command; } else { msg->type = type; msg->command = (u8)command; } msg->slave_addr = slave_addr; } static int hisi_pmbus_xfer(struct hisi_pmbus_data *pmbus, struct pmbus_msg *msg) { int ret; if ((msg->data == NULL) && (msg->data_len > 0)) { dev_err(pmbus->dev, "[iWare][Error] msg->data = NULL, msg.data_len %zu\r\n", msg->data_len); return -EINVAL; } if ((msg->type & PMBUS_FLAG_NO_DATA) != 0) { ret = pmbus->ops->send_byte(&pmbus->reg_region, msg); } else if ((msg->type & PMBUS_FLAG_READ) != 0) { ret = pmbus->ops->read_bytes(&pmbus->reg_region, msg); } else { /* pmbus write */ ret = pmbus->ops->write_bytes(&pmbus->reg_region, msg); } return ret; } int kdrv_pmbus_reset(u32 bus_id) { struct hisi_pmbus_data *pmbus = NULL; pmbus = hisi_pmbus_data_get_by_id(bus_id); if (pmbus == NULL) { pr_err("[iWare][Error] get pmbus data fail: pmbus_id=%u,\n", bus_id); return -EPERM; } mutex_lock(&pmbus->lock); pmbus->ops->reset(&pmbus->reg_region); mutex_unlock(&pmbus->lock); return 0; } EXPORT_SYMBOL(kdrv_pmbus_reset); int kdrv_pmbus_init(u32 bus_id, u32 bus_freq_hz) { struct hisi_pmbus_data *pmbus = NULL; int ret; u32 total_cnt; pmbus = hisi_pmbus_data_get_by_id(bus_id); if (pmbus == NULL) { pr_err("[iWare][Error] get pmbus data fail: pmbus_id=%u,\n", bus_id); return -EPERM; } if (bus_freq_hz > PMBUS_MAX_FAST_MODE_FREQ || bus_freq_hz == 0) { pr_err("[iWare][Error] invalid para bus_freq_hz =%u \r\n", bus_freq_hz); return -EINVAL; } mutex_lock(&pmbus->lock); pmbus->timing.bus_freq_hz = bus_freq_hz; total_cnt = (u32)DIV_ROUND_UP_ULL(pmbus->timing.clk_freq_mhz * HZ_PER_MHZ, bus_freq_hz); pmbus->timing_cfg.hcnt = (pmbus->timing.scl_high_ratio * total_cnt) / 100; // 占空比放大了100倍 这里除以100 pmbus->timing_cfg.lcnt = total_cnt - pmbus->timing_cfg.hcnt; pr_info("[iWare][Info] %s bus_freq_hz %u, total_cnt %u, hcnt %u lcnt %u\n", __func__, bus_freq_hz, total_cnt, pmbus->timing_cfg.hcnt, pmbus->timing_cfg.lcnt); ret = pmbus->ops->init(&pmbus->reg_region, pmbus->pec_en, pmbus->timing.bus_freq_hz, &pmbus->timing_cfg, &pmbus->key); if (ret != 0) { mutex_unlock(&pmbus->lock); pr_err("[iWare][Error] kdrv_pmbus_init failed ret=%d\n", ret); return ret; } mutex_unlock(&pmbus->lock); return 0; } EXPORT_SYMBOL(kdrv_pmbus_init); int kdrv_pmbus_write_word(u32 bus_id, u8 slave_addr, u16 command, u16 data) { struct hisi_pmbus_data *pmbus = NULL; struct pmbus_msg msg = { 0 }; int ret; pmbus = hisi_pmbus_data_get_by_id(bus_id); if (pmbus == NULL) { pr_err("[iWare][Error] kdrv_pmbus_write_word,get pmbus data fail: pmbus_id=%u,\n", bus_id); return -EPERM; } mutex_lock(&pmbus->lock); msg.data = (u8 *)&data; msg.data_len = sizeof(u16); hisi_pmbus_fill_msg(&msg, PMBUS_WRITE_WORD, slave_addr, command); ret = hisi_pmbus_xfer(pmbus, &msg); if (ret != 0) { mutex_unlock(&pmbus->lock); return ret; } mutex_unlock(&pmbus->lock); return 0; } EXPORT_SYMBOL(kdrv_pmbus_write_word); int kdrv_pmbus_write_byte(u32 bus_id, u8 slave_addr, u16 command, u8 data) { struct hisi_pmbus_data *pmbus = NULL; struct pmbus_msg msg = { 0 }; int ret; pmbus = hisi_pmbus_data_get_by_id(bus_id); if (pmbus == NULL) { pr_err("[iWare][Error] kdrv_pmbus_write_byte, get pmbus data fail: pmbus_id=%u,\n", bus_id); return -EPERM; } mutex_lock(&pmbus->lock); msg.data = &data; msg.data_len = sizeof(u8); hisi_pmbus_fill_msg(&msg, PMBUS_WRITE_BYTE, slave_addr, command); ret = hisi_pmbus_xfer(pmbus, &msg); if (ret != 0) { mutex_unlock(&pmbus->lock); return ret; } mutex_unlock(&pmbus->lock); return 0; } EXPORT_SYMBOL(kdrv_pmbus_write_byte); int kdrv_pmbus_write_cmd(u32 bus_id, u8 slave_addr, u16 command) { struct hisi_pmbus_data *pmbus = NULL; struct pmbus_msg msg = { 0 }; int ret; pmbus = hisi_pmbus_data_get_by_id(bus_id); if (pmbus == NULL) { pr_err("[iWare][Error] kdrv_pmbus_write_cmd, get pmbus data fail: pmbus_id=%u,\n", bus_id); return -EPERM; } mutex_lock(&pmbus->lock); hisi_pmbus_fill_msg(&msg, PMBUS_SEND_BYTE, slave_addr, command); ret = hisi_pmbus_xfer(pmbus, &msg); if (ret != 0) { mutex_unlock(&pmbus->lock); return ret; } mutex_unlock(&pmbus->lock); return 0; } EXPORT_SYMBOL(kdrv_pmbus_write_cmd); int kdrv_pmbus_read_byte(u32 bus_id, u8 slave_addr, u16 command, u8 *data) { struct hisi_pmbus_data *pmbus = NULL; struct pmbus_msg msg = { 0 }; int ret; if (data == NULL) { pr_err("[iWare][Error] ivalid para, data is null point,\n"); return -EINVAL; } pmbus = hisi_pmbus_data_get_by_id(bus_id); if (pmbus == NULL) { pr_err("[iWare][Error] get pmbus data fail: pmbus_id=%u,\n", bus_id); return -EPERM; } mutex_lock(&pmbus->lock); msg.data = data; msg.data_len = sizeof(u8); hisi_pmbus_fill_msg(&msg, PMBUS_READ_BYTE, slave_addr, command); ret = hisi_pmbus_xfer(pmbus, &msg); if (ret != 0) { mutex_unlock(&pmbus->lock); return ret; } mutex_unlock(&pmbus->lock); return 0; } EXPORT_SYMBOL(kdrv_pmbus_read_byte); int kdrv_pmbus_read_word(u32 bus_id, u8 slave_addr, u16 command, u16 *data) { struct hisi_pmbus_data *pmbus = NULL; struct pmbus_msg msg = { 0 }; int ret; u8 tmp[2] = {0}; // 2个字节 if (data == NULL) { pr_err("[iWare][Error] ivalid para, data is null point,\n"); return -EINVAL; } pmbus = hisi_pmbus_data_get_by_id(bus_id); if (pmbus == NULL) { pr_err("[iWare][Error] get pmbus data fail: pmbus_id=%u,\n", bus_id); return -EPERM; } mutex_lock(&pmbus->lock); msg.data = tmp; msg.data_len = sizeof(u16); hisi_pmbus_fill_msg(&msg, PMBUS_READ_WORD, slave_addr, command); ret = hisi_pmbus_xfer(pmbus, &msg); if (ret != 0) { mutex_unlock(&pmbus->lock); return ret; } *data = (((u16)tmp[1]) << 8) + ((u16)tmp[0]); // 高8位 mutex_unlock(&pmbus->lock); return 0; } EXPORT_SYMBOL(kdrv_pmbus_read_word); int kdrv_pmbus_write_block_data(u32 bus_id, u8 slave_addr, u16 command, u8 *pbuf, u32 len) { struct hisi_pmbus_data *pmbus = NULL; struct pmbus_msg msg = { 0 }; int ret; if ((pbuf == NULL) || (len == 0)) { pr_err("[iWare][Error] para err: bus_id(%d),slave_addr(0x%x), len(%u)\n", bus_id, slave_addr, len); return -EINVAL; } if (len > PMBUS_BLOCK_MAX) { pr_err("[iWare][Error] para err: len(%u) exceed PMBUS_BLOCK_MAX(32)\n", len); return -EINVAL; } pmbus = hisi_pmbus_data_get_by_id(bus_id); if (pmbus == NULL) { pr_err("[iWare][Error] get pmbus data fail: pmbus_id=%u,\n", bus_id); return -EPERM; } mutex_lock(&pmbus->lock); msg.data = pbuf; msg.data_len = (u8)len; hisi_pmbus_fill_msg(&msg, PMBUS_WRITE_BLOCK, slave_addr, command); ret = hisi_pmbus_xfer(pmbus, &msg); if (ret != 0) { mutex_unlock(&pmbus->lock); return ret; } mutex_unlock(&pmbus->lock); return 0; } EXPORT_SYMBOL(kdrv_pmbus_write_block_data); int kdrv_pmbus_read_block_data(u32 bus_id, u8 slave_addr, u16 command, u8 *pbuf, u32 len) { struct hisi_pmbus_data *pmbus = NULL; struct pmbus_msg msg = { 0 }; int ret; if ((pbuf == NULL) || (len == 0)) { pr_err("[iWare][Error] para err: bus_id(%d),slave_addr(0x%x), len(%u)\n", bus_id, slave_addr, len); return -EINVAL; } if (len > PMBUS_BLOCK_MAX) { pr_err("[iWare][Error] para err: len(%u) exceed PMBUS_BLOCK_MAX(32)\n", len); return -EINVAL; } pmbus = hisi_pmbus_data_get_by_id(bus_id); if (pmbus == NULL) { pr_err("[iWare][Error] get pmbus data fail: pmbus_id=%u,\n", bus_id); return -EPERM; } mutex_lock(&pmbus->lock); msg.data = pbuf; msg.data_len = (u8)len; hisi_pmbus_fill_msg(&msg, PMBUS_READ_BLOCK, slave_addr, command); ret = hisi_pmbus_xfer(pmbus, &msg); if (ret != 0) { mutex_unlock(&pmbus->lock); return ret; } mutex_unlock(&pmbus->lock); return 0; } EXPORT_SYMBOL(kdrv_pmbus_read_block_data); " “测试步骤为 ”insmod /lib/udrivers/hi309a_pmbus_api_test.ko devmem 0xfa860204 w 0 devmem 0xfa860220 w 0 echo 3 1 0x70 0x21 0xf4 > /proc/pmbus_test (设置输出电压) “ 然后再设置输出电压之后报以下错误 [60585.219727] [iWare][Error] pmbus_write timeout! raw_int_status:0x10 [60585.227034] [iWare][Info] pmbus hang recovery done [60585.231848] kdrv_pmbus_write_word fail bus_id:1, addr:0x70, cmd:0x21 请根据以上几段代码,帮我分析我出现kdrv_pmbus_write_word fail bus_id:1, addr:0x70, cmd:0x21的原因可能是什么,并给出完整解决方案”
最新发布
08-07
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值