/* * drivers/power/axp/axp2101/axp2101-regu.c * (C) Copyright 2010-2016 * Allwinner Technology Co., Ltd. * Pannan * * regulator driver of axp2101 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. */ #include #include #include #include #include #include #include #include #include #include "../axp-core.h" #include "../axp-regulator.h" #include "axp2101.h" #include "axp2101-regu.h" enum AXP_REGLS { VCC_DCDC1, VCC_DCDC2, VCC_DCDC3, VCC_DCDC4, VCC_LDO1, VCC_LDO2, VCC_LDO3, VCC_LDO4, VCC_LDO5, VCC_LDO6, VCC_LDO7, VCC_LDO8, VCC_LDO9, VCC_LDO10, VCC_LDO11, VCC_DCDC5, VCC_2101_MAX, }; struct axp2101_regulators { struct regulator_dev *regulators[VCC_2101_MAX]; struct axp_dev *chip; }; #define AXP2101_LDO(_id, min, max, step1, vreg, shift, nbits, ereg, emask, \ enval, disval, switch_vol, step2, new_level, mode_addr, \ freq_addr, dvm_ereg, dvm_ebit, dvm_flag) \ AXP_LDO(AXP2101, _id, min, max, step1, vreg, shift, nbits, ereg, \ emask, enval, disval, switch_vol, step2, new_level, mode_addr, \ freq_addr, dvm_ereg, dvm_ebit, dvm_flag) #define AXP2101_DCDC(_id, min, max, step1, vreg, shift, nbits, ereg, emask, \ enval, disval, switch_vol, step2, new_level, mode_addr, \ mode_mask, freq_addr, dvm_ereg, dvm_ebit, dvm_flag) \ AXP_DCDC(AXP2101, _id, min, max, step1, vreg, shift, nbits, ereg, \ emask, enval, disval, switch_vol, step2, new_level, \ mode_addr, mode_mask, freq_addr, dvm_ereg, dvm_ebit, \ dvm_flag) #define AXP2101_SW(_id, min, max, step1, vreg, shift, nbits, ereg, emask, \ enval, disval, switch_vol, step2, new_level, mode_addr, \ freq_addr, dvm_ereg, dvm_ebit, dvm_flag) \ AXP_SW(AXP2101, _id, min, max, step1, vreg, shift, nbits, ereg, emask, \ enval, disval, switch_vol, step2, new_level, mode_addr, \ freq_addr, dvm_ereg, dvm_ebit, dvm_flag) static struct axp_regulator_info axp2101_regulator_info[] = { AXP2101_DCDC(1, 1500, 3400, 100, DCDC1, 0, 5, DCDC1EN, 0x01, 0x01, 0x00, 0, 1, 0, 0x81, BIT(2), 0x3B, 0, 0, 0), AXP2101_DCDC(2, 500, 1540, 10, DCDC2, 0, 7, DCDC2EN, 0x02, 0x02, 0x00, 1200, 20, 0, 0x81, BIT(3), 0x3B, 0x83, 7, 1), AXP2101_DCDC(3, 500, 1540, 10, DCDC3, 0, 7, DCDC3EN, 0x04, 0x04, 0x00, 1200, 20, 0, 0x81, BIT(4), 0x3B, 0x84, 7, 1), AXP2101_DCDC(4, 500, 1840, 10, DCDC4, 0, 7, DCDC4EN, 0x08, 0x08, 0x00, 1200, 20, 0, 0x81, BIT(5), 0x3B, 0, 0, 0), AXP2101_LDO(1, 3000, 3000, 1, LDO1, 0, 0, LDO1EN, 0x01, 0x01, 0x00, 0, 1, 0, 0, 0, 0, 0, 0), AXP2101_LDO(2, 3000, 3000, 1, LDO2, 0, 0, LDO2EN, 0x01, 0x01, 0x00, 0, 1, 0, 0, 0, 0, 0, 0), AXP2101_LDO(3, 500, 3500, 100, LDO3, 0, 5, LDO3EN, BIT(0), BIT(0), 0x00, 0, 1, 0, 0, 0, 0, 0, 0), AXP2101_LDO(4, 500, 3500, 100, LDO4, 0, 5, LDO4EN, BIT(1), BIT(1), 0x00, 0, 1, 0, 0, 0, 0, 0, 0), AXP2101_LDO(5, 500, 3500, 100, LDO5, 0, 5, LDO5EN, BIT(2), BIT(2), 0x00, 0, 1, 0, 0, 0, 0, 0, 0), AXP2101_LDO(6, 500, 3500, 100, LDO6, 0, 5, LDO6EN, BIT(3), BIT(3), 0x00, 3400, 200, 0, 0, 0, 0, 0, 0), AXP2101_LDO(7, 500, 3500, 100, LDO7, 0, 5, LDO7EN, BIT(4), BIT(4), 0x00, 0, 1, 0, 0, 0, 0, 0, 0), AXP2101_LDO(8, 500, 3500, 100, LDO8, 0, 5, LDO8EN, BIT(5), BIT(5), 0x00, 0, 1, 0, 0, 0, 0, 0, 0), AXP2101_LDO(9, 500, 1400, 50, LDO9, 0, 5, LDO9EN, BIT(6), BIT(6), 0x00, 0, 1, 0, 0, 0, 0, 0, 0), AXP2101_LDO(10, 500, 3500, 100, LDO10, 0, 5, LDO10EN, BIT(7), BIT(7), 0x00, 0, 1, 0, 0, 0, 0, 0, 0), AXP2101_LDO(11, 500, 1400, 50, LDO11, 0, 5, LDO11EN, BIT(0), BIT(0), 0x00, 0, 1, 0, 0, 0, 0, 0, 0), /* dcdc5 must enable accross factory efuse to enable it */ AXP2101_DCDC(5, 1400, 3700, 100, DCDC5, 0, 5, DCDC5EN, 0x10, 0x10, 0x00, 0, 1, 0, 0x86, BIT(5), 0x3B, 0, 0, 0), }; static struct regulator_init_data axp_regl_init_data[] = { [VCC_DCDC1] = { .constraints = { .name = "axp2101_dcdc1", .min_uV = 1500000, .max_uV = 3400000, .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, }, }, [VCC_DCDC2] = { .constraints = { .name = "axp2101_dcdc2", .min_uV = 500000, .max_uV = 1540000, .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, }, }, [VCC_DCDC3] = { .constraints = { .name = "axp2101_dcdc3", .min_uV = 500000, .max_uV = 1540000, .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, #ifdef CONFIG_ARCH_SUN8IW16 .always_on = 1, #endif }, }, [VCC_DCDC4] = { .constraints = { .name = "axp2101_dcdc4", .min_uV = 500000, .max_uV = 1840000, .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, }, }, [VCC_LDO1] = { .constraints = { .name = "axp2101_rtc", .min_uV = 3000000, .max_uV = 3000000, }, }, [VCC_LDO2] = { .constraints = { .name = "axp2101_rtc1", .min_uV = 3000000, .max_uV = 3000000, .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, }, }, [VCC_LDO3] = { .constraints = { .name = "axp2101_aldo1", .min_uV = 500000, .max_uV = 3500000, .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, #ifdef CONFIG_ARCH_SUN8IW16 .always_on = 1, #endif }, }, [VCC_LDO4] = { .constraints = { .name = "axp2101_aldo2", .min_uV = 500000, .max_uV = 3500000, .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, }, }, [VCC_LDO5] = { .constraints = { .name = "axp2101_aldo3", .min_uV = 500000, .max_uV = 3500000, .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, }, }, [VCC_LDO6] = { .constraints = { .name = "axp2101_aldo4", .min_uV = 500000, .max_uV = 3500000, .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, }, }, [VCC_LDO7] = { .constraints = { .name = "axp2101_bldo1", .min_uV = 500000, .max_uV = 3500000, .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, }, }, [VCC_LDO8] = { .constraints = { .name = "axp2101_bldo2", .min_uV = 500000, .max_uV = 3500000, .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, }, }, [VCC_LDO9] = { .constraints = { .name = "axp2101_cpuldos", .min_uV = 500000, .max_uV = 1400000, .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, }, }, [VCC_LDO10] = { .constraints = { .name = "axp2101_dldo1", .min_uV = 500000, .max_uV = 3500000, .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, }, }, [VCC_LDO11] = { .constraints = { .name = "axp2101_dldo2", .min_uV = 500000, .max_uV = 1400000, .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, }, }, [VCC_DCDC5] = { .constraints = { .name = "axp2101_dcdc5", .min_uV = 1400000, .max_uV = 3700000, .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, }, }, }; static ssize_t workmode_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret; uint8_t val; struct regulator_dev *rdev; struct axp_regulator_info *info; struct axp_regmap *regmap; rdev = container_of(dev, struct regulator_dev, dev); info = rdev_get_drvdata(rdev); regmap = info->regmap; ret = axp_regmap_read(regmap, info->mode_reg, &val); if (ret) return sprintf(buf, "IO ERROR\n"); if ((val & info->mode_mask) == info->mode_mask) return sprintf(buf, "PWM\n"); else return sprintf(buf, "AUTO\n"); } static ssize_t workmode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { uint8_t val; struct regulator_dev *rdev; struct axp_regulator_info *info; struct axp_regmap *regmap; unsigned int mode; int ret; rdev = container_of(dev, struct regulator_dev, dev); info = rdev_get_drvdata(rdev); regmap = info->regmap; ret = sscanf(buf, "%u", &mode); if (ret != 1) return -EINVAL; val = !!mode; if (val) axp_regmap_set_bits(regmap, info->mode_reg, info->mode_mask); else axp_regmap_clr_bits(regmap, info->mode_reg, info->mode_mask); return count; } static struct device_attribute axp_regu_attrs[] = { AXP_REGULATOR_ATTR(workmode), }; static int axp_regu_create_attrs(struct device *dev) { int j, ret; for (j = 0; j < ARRAY_SIZE(axp_regu_attrs); j++) { ret = device_create_file(dev, &axp_regu_attrs[j]); if (ret) goto sysfs_failed; } return 0; sysfs_failed: while (j--) device_remove_file(dev, &axp_regu_attrs[j]); return ret; } static s32 axp2101_regu_dependence(const char *ldo_name) { s32 axp2101_dependence = 0; if (strstr(ldo_name, "dcdc1") != NULL) axp2101_dependence |= AXP2101_DCDC1_BIT; else if (strstr(ldo_name, "dcdc2") != NULL) axp2101_dependence |= AXP2101_DCDC2_BIT; else if (strstr(ldo_name, "dcdc3") != NULL) axp2101_dependence |= AXP2101_DCDC3_BIT; else if (strstr(ldo_name, "dcdc4") != NULL) axp2101_dependence |= AXP2101_DCDC4_BIT; else if (strstr(ldo_name, "aldo1") != NULL) axp2101_dependence |= AXP2101_ALDO1_BIT; else if (strstr(ldo_name, "aldo2") != NULL) axp2101_dependence |= AXP2101_ALDO2_BIT; else if (strstr(ldo_name, "aldo3") != NULL) axp2101_dependence |= AXP2101_ALDO3_BIT; else if (strstr(ldo_name, "aldo4") != NULL) axp2101_dependence |= AXP2101_ALDO4_BIT; else if (strstr(ldo_name, "bldo1") != NULL) axp2101_dependence |= AXP2101_BLDO1_BIT; else if (strstr(ldo_name, "bldo2") != NULL) axp2101_dependence |= AXP2101_BLDO2_BIT; else if (strstr(ldo_name, "dldo1") != NULL) axp2101_dependence |= AXP2101_DLDO1_BIT; else if (strstr(ldo_name, "dldo2") != NULL) axp2101_dependence |= AXP2101_DLDO2_BIT; else if (strstr(ldo_name, "cpuldos") != NULL) axp2101_dependence |= AXP2101_CPULDOS_BIT; else if (strstr(ldo_name, "rtc1") != NULL) axp2101_dependence |= AXP2101_RTC1_BIT; else if (strstr(ldo_name, "rtc") != NULL) axp2101_dependence |= AXP2101_RTC_BIT; else if (strstr(ldo_name, "dcdc5") != NULL) axp2101_dependence |= AXP2101_DCDC5_BIT; else return -1; axp2101_dependence |= (0 << 30); return axp2101_dependence; } static int axp2101_regulator_probe(struct platform_device *pdev) { s32 i, ret = 0; struct axp_regulator_info *info; struct axp2101_regulators *regu_data; struct axp_dev *axp_dev = dev_get_drvdata(pdev->dev.parent); if (pdev->dev.of_node) { ret = axp_regulator_dt_parse(pdev->dev.of_node, axp_regl_init_data, axp2101_regu_dependence); if (ret) { pr_err("%s parse device tree err\n", __func__); return -EINVAL; } } else { pr_err("axp2101 regulator device tree err!\n"); return -EBUSY; } regu_data = devm_kzalloc(&pdev->dev, sizeof(*regu_data), GFP_KERNEL); if (!regu_data) return -ENOMEM; regu_data->chip = axp_dev; platform_set_drvdata(pdev, regu_data); /* * set dcdc1 mode to pwm * dcdc1 always load high */ axp_regmap_set_bits(axp_dev->regmap, AXP2101_DCDCMODE, BIT(2)); for (i = 0; i < VCC_2101_MAX; i++) { info = &axp2101_regulator_info[i]; info->pmu_num = axp_dev->pmu_num; regu_data->regulators[i] = axp_regulator_register(&pdev->dev, axp_dev->regmap, &axp_regl_init_data[i], info); if (IS_ERR(regu_data->regulators[i])) { dev_err(&pdev->dev, "failed to register regulator %s\n", info->desc.name); while (--i >= 0) axp_regulator_unregister( regu_data->regulators[i]); return -1; } if (info->desc.id >= AXP_DCDC_ID_START) { ret = axp_regu_create_attrs( ®u_data->regulators[i]->dev); if (ret) dev_err(&pdev->dev, "failed to register regulator attr %s\n", info->desc.name); } } /* voltage not to the OTP default when wakeup */ /* axp_regmap_set_bits(axp_dev->regmap, axp2101_TEMPERATURE, 0x02); */ return 0; } static int axp2101_regulator_remove(struct platform_device *pdev) { struct axp2101_regulators *regu_data = platform_get_drvdata(pdev); int i; for (i = 0; i < VCC_2101_MAX; i++) regulator_unregister(regu_data->regulators[i]); return 0; } static const struct of_device_id axp2101_regu_dt_ids[] = { { .compatible = "axp2101-regulator", }, {}, }; MODULE_DEVICE_TABLE(of, axp2101_regu_dt_ids); static struct platform_driver axp2101_regulator_driver = { .driver = { .name = "axp2101-regulator", .of_match_table = axp2101_regu_dt_ids, }, .probe = axp2101_regulator_probe, .remove = axp2101_regulator_remove, }; static int __init axp2101_regulator_initcall(void) { int ret; ret = platform_driver_register(&axp2101_regulator_driver); if (IS_ERR_VALUE(ret)) { pr_err("%s: failed, errno %d\n", __func__, ret); return -EINVAL; } return 0; } subsys_initcall(axp2101_regulator_initcall); MODULE_DESCRIPTION("Regulator Driver of AXP2101"); MODULE_AUTHOR("pannan"); MODULE_LICENSE("GPL");