/* * Copyright (C) 2019 Allwinner. * weidonghui * * SUNXI AXP152 Driver * * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include /*#include */ #ifdef PMU_DEBUG #define axp_info(fmt...) tick_printf("[axp][info]: " fmt) #define axp_err(fmt...) tick_printf("[axp][err]: " fmt) #else #define axp_info(fmt...) #define axp_err(fmt...) tick_printf("[axp][err]: " fmt) #endif typedef struct _axp_step_info { u32 step_min_vol; u32 step_max_vol; u32 step_val; u32 regation; } _axp_step_info; typedef struct _axp_contrl_info { char name[16]; u32 min_vol; u32 max_vol; u32 cfg_reg_addr; u32 cfg_reg_mask; u32 ctrl_reg_addr; u32 ctrl_bit_ofs; u32 reg_addr_offest; _axp_step_info axp_step_tbl[4]; } axp_contrl_info; __attribute__((section(".data"))) axp_contrl_info pmu_axp152_ctrl_tbl[] = { { "dcdc1", 1700, 3500, AXP152_DC1OUT_VOL, 0x0f, AXP152_OUTPUT_CTL, 7, 0, { {1700, 2100, 100}, {2400, 2800, 100}, {3000, 3500, 100} } }, { "dcdc2", 700, 2275, AXP152_DC2OUT_VOL, 0x3f, AXP152_OUTPUT_CTL, 6, 0, { {700, 2275, 25}, } }, { "dcdc3", 700, 3500, AXP152_DC3OUT_VOL, 0x3f, AXP152_OUTPUT_CTL, 5, 0, { {700, 3500, 50}, } }, { "dcdc4", 700, 3500, AXP152_DC4OUT_VOL, 0x7f, AXP152_OUTPUT_CTL, 4, 0, { {700, 3500, 25}, } }, { "aldo1", 1200, 3300, AXP152_ALDO12OUT_VOL, 0xf0, AXP152_OUTPUT_CTL, 3, 4, { {1200, 2000, 100}, {2500, 2700, 200}, {2800, 3000, 200}, {3100, 3300, 100} } }, { "aldo2", 1200, 3300, AXP152_ALDO12OUT_VOL, 0x0f, AXP152_OUTPUT_CTL, 2, 0, { {1200, 2000, 100}, {2500, 2700, 200}, {2800, 3000, 200}, {3100, 3300, 100} } }, { "dldo1", 700, 3500, AXP152_DLDO1OUT_VOL, 0x1f, AXP152_OUTPUT_CTL, 1, 0, { {700, 3500, 100}, } }, { "dldo2", 700, 3500, AXP152_DLDO2OUT_VOL, 0x1f, AXP152_OUTPUT_CTL, 0, 0, { {700, 3500, 100}, } }, { "ldo0", 2500, 5000, AXP152_LDO0_VOL, 0x30, AXP152_LDO0_VOL, 7, 4, { {2500, 2800, 300, 1}, {3300, 5000, 1700, 1}, }, }, { "gpio2ldo", 1800, 3300, AXP152_GPIO2_LDO_MOD, 0x0f, AXP152_GPIO2_CTL, 7, 0, { {1800, 3300, 100}, } }, }; static axp_contrl_info *get_ctrl_info_from_tbl(char *name) { int i = 0; int size = ARRAY_SIZE(pmu_axp152_ctrl_tbl); axp_contrl_info *p; for (i = 0; i < size; i++) { if (!strncmp(name, pmu_axp152_ctrl_tbl[i].name, strlen(pmu_axp152_ctrl_tbl[i].name))) { break; } } if (i >= size) { axp_err("can't find %s from table\n", name); return NULL; } p = pmu_axp152_ctrl_tbl + i; return p; } static int pmu_axp152_probe(void) { u8 pmu_chip_id; if (pmic_bus_init(AXP152_DEVICE_ADDR, AXP152_RUNTIME_ADDR)) { tick_printf("%s pmic_bus_init fail\n", __func__); return -1; } if (pmic_bus_read(AXP152_RUNTIME_ADDR, AXP152_VERSION, &pmu_chip_id)) { tick_printf("%s pmic_bus_read fail\n", __func__); return -1; } pmu_chip_id &= 0X0F; if (pmu_chip_id == AXP152_CHIP_ID) { /*pmu type AXP152*/ tick_printf("PMU: AXP152\n"); return 0; } return -1; } static int pmu_axp152_get_info(char *name, unsigned char *chipid) { strncpy(name, "axp152", sizeof("axp152")); *chipid = AXP152_CHIP_ID; return 0; } static int pmu_set_vol(char *name, uint set_vol, uint onoff) { u8 reg_value, i; axp_contrl_info *p_item = NULL; u8 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 (pmic_bus_read(AXP152_RUNTIME_ADDR, p_item->cfg_reg_addr, ®_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_offest); 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; } axp_info("sum:0x%x\n", (base_step + ((set_vol - p_item->axp_step_tbl[i].step_min_vol)/p_item->axp_step_tbl[i].step_val))); 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); axp_info("base_step:0x%x\n", base_step); } } if (pmic_bus_write(AXP152_RUNTIME_ADDR, p_item->cfg_reg_addr, reg_value)) { axp_err("unable to set %s\n", name); return -1; } } if (onoff < 0) { return 0; } if (pmic_bus_read(AXP152_RUNTIME_ADDR, p_item->ctrl_reg_addr, ®_value)) { return -1; } if (onoff == 0) { reg_value &= ~(1 << p_item->ctrl_bit_ofs); } else { reg_value |= (1 << p_item->ctrl_bit_ofs); } if (pmic_bus_write(AXP152_RUNTIME_ADDR, p_item->ctrl_reg_addr, reg_value)) { axp_err("unable to onoff %s\n", name); return -1; } return 0; } static int pmu_axp152_get_voltage(char *name) { u8 reg_value, i; axp_contrl_info *p_item = NULL; u8 base_step1 = 0; u8 base_step2 = 0; int vol; p_item = get_ctrl_info_from_tbl(name); if (!p_item) { return -1; } if (pmic_bus_read(AXP152_RUNTIME_ADDR, p_item->ctrl_reg_addr, ®_value)) { return -1; } if (!(reg_value & (0x01 << p_item->ctrl_bit_ofs))) { return 0; } if (pmic_bus_read(AXP152_RUNTIME_ADDR, p_item->cfg_reg_addr, ®_value)) { return -1; } reg_value &= p_item->cfg_reg_mask; reg_value >>= p_item->reg_addr_offest; 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 (p_item->axp_step_tbl[i].regation) reg_value = (~reg_value & (p_item->cfg_reg_mask >> p_item->reg_addr_offest)); 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; } if (p_item->axp_step_tbl[i].regation) reg_value = (~reg_value & (p_item->cfg_reg_mask >> p_item->reg_addr_offest)); 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; } static int pmu_axp152_set_voltage(char *name, uint set_vol, uint onoff) { int i, temp_vol, src_vol = pmu_axp152_get_voltage(name); u32 step_voltage = 0xffff; axp_contrl_info *p_item = NULL; p_item = get_ctrl_info_from_tbl(name); if (!p_item) { return -1; } for (i = 0; p_item->axp_step_tbl[i].step_val != 0; i++) { step_voltage = min(step_voltage, p_item->axp_step_tbl[i].step_val); } if (step_voltage == 0xffff) return -1; if (set_vol == 0) { pmu_set_vol(name, set_vol, onoff); } else if (src_vol > set_vol) { for (temp_vol = src_vol; temp_vol >= set_vol; temp_vol -= step_voltage) { pmu_set_vol(name, temp_vol, onoff); } udelay(step_voltage*10/25); } else if (src_vol < set_vol) { for (temp_vol = src_vol; temp_vol <= set_vol; temp_vol += step_voltage) { pmu_set_vol(name, temp_vol, onoff); } udelay(step_voltage*10/25); } return 0; } static int pmu_axp152_set_power_off(void) { u8 reg_value; if (pmic_bus_read(AXP152_RUNTIME_ADDR, AXP152_OFF_CTL, ®_value)) { return -1; } reg_value |= 1 << 7; if (pmic_bus_write(AXP152_RUNTIME_ADDR, AXP152_OFF_CTL, reg_value)) { return -1; } return 0; } static int pmu_axp152_get_key_irq(void) { u8 reg_value; if (pmic_bus_read(AXP152_RUNTIME_ADDR, AXP152_INTSTS2, ®_value)) { return -1; } reg_value &= (0x03); if (reg_value) { if (pmic_bus_write(AXP152_RUNTIME_ADDR, AXP152_INTSTS2, reg_value | (0x01 << 1))) { return -1; } } return reg_value & 3; } unsigned char pmu_axp152_get_reg_value(unsigned char reg_addr) { u8 reg_value; if (pmic_bus_read(AXP152_RUNTIME_ADDR, reg_addr, ®_value)) { return -1; } return reg_value; } unsigned char pmu_axp152_set_reg_value(unsigned char reg_addr, unsigned char reg_value) { unsigned char reg; if (pmic_bus_write(AXP152_RUNTIME_ADDR, reg_addr, reg_value)) { return -1; } if (pmic_bus_read(AXP152_RUNTIME_ADDR, reg_addr, ®)) { return -1; } return reg; } U_BOOT_AXP_PMU_INIT(pmu_axp152) = { .pmu_name = "pmu_axp152", .probe = pmu_axp152_probe, .get_info = pmu_axp152_get_info, .set_voltage = pmu_axp152_set_voltage, .get_voltage = pmu_axp152_get_voltage, .set_power_off = pmu_axp152_set_power_off, /*.set_sys_mode = pmu_axp152_set_sys_mode,*/ /*.get_sys_mode = pmu_axp152_get_sys_mode,*/ .get_key_irq = pmu_axp152_get_key_irq, /*.set_bus_vol_limit = pmu_axp152_set_bus_vol_limit,*/ .get_reg_value = pmu_axp152_get_reg_value, .set_reg_value = pmu_axp152_set_reg_value, };