#include #include #include #include #include #include #include "axp-regu.h" #include "axp-mem-device.h" static struct of_device_id axp_mem_device_match[] = { { .compatible = "allwinner,pmu0_regu", }, { } }; static axp_mem_data_t *regulator_count; static u32 ldo_count; static s32 axp_mem_device_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; u32 ldo_index = 0; char name[32] = {0}; s32 num = 0; struct axp_consumer_supply consumer_supply[20]; const char *regulator_string = NULL; if (!of_device_is_available(node)) { printk(KERN_ERR "%s: axp regu is disable", __func__); return -EPERM; } if (of_property_read_u32(node, "regulator_count", &ldo_count)) { printk(KERN_ERR "%s: axp regu get regulator_count failed", __func__); return -ENOENT; } regulator_count = (axp_mem_data_t *)kzalloc(sizeof(axp_mem_data_t)*(ldo_count), GFP_KERNEL); if (!regulator_count) { printk(KERN_ERR "%s: request regulator_count failed\n", __func__); return -1; } for (ldo_index = 1; ldo_index <= ldo_count; ldo_index++) { sprintf(name, "regulator%d", ldo_index); if (of_property_read_string(node, (const char *)&name, ®ulator_string)) { printk(KERN_ERR "node %s get failed!\n", name); continue; } num = sscanf(regulator_string, "%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s", consumer_supply[0].supply, consumer_supply[1].supply, consumer_supply[2].supply, consumer_supply[3].supply, consumer_supply[4].supply, consumer_supply[5].supply, consumer_supply[6].supply, consumer_supply[7].supply, consumer_supply[8].supply, consumer_supply[9].supply, consumer_supply[10].supply, consumer_supply[11].supply, consumer_supply[12].supply, consumer_supply[13].supply, consumer_supply[14].supply, consumer_supply[15].supply, consumer_supply[16].supply, consumer_supply[17].supply, consumer_supply[18].supply, consumer_supply[19].supply); if (num <= -1) { printk(KERN_ERR "parse ldo%d from sysconfig failed\n", ldo_index); return -1; } else { strcpy((char *)((regulator_count+ldo_index-1)->id_name), consumer_supply[0].supply); } } return 0; } int axp_mem_save(void) { u32 ldo_index = 0; struct regulator *regu = NULL; char *supply_id = NULL; char *rtc_id = NULL; int ret = 0; for (ldo_index = 0; ldo_index < ldo_count; ldo_index++) { supply_id = (char *)((regulator_count+ldo_index)->id_name); rtc_id = strstr(supply_id, "rtc"); if (NULL != rtc_id) { (regulator_count+ldo_index)->mem_data = 0; rtc_id = NULL; continue; } regu = regulator_get(NULL, supply_id); if (IS_ERR(regu)) { pr_err("%s: some error happen, fail to get regulator %s\n", __func__, supply_id); return -1; } ret = regulator_get_voltage(regu); if (0 > ret) { pr_err("%s: some error happen, fail to get %s voltage!\n", __func__, supply_id); return -1; } (regulator_count+ldo_index)->mem_data = ret; ret = regulator_is_enabled(regu); if (0 < ret) { (regulator_count+ldo_index)->mem_data |= (1 << 31); } else { (regulator_count+ldo_index)->mem_data &= (~(1 << 31)); } regulator_put(regu); } return 0; } EXPORT_SYMBOL(axp_mem_save); void axp_mem_restore(void) { u32 ldo_index = 0; struct regulator *regu = NULL; char *supply_id = NULL; int ret = 0, volt_value = 0; for (ldo_index = 0; ldo_index < ldo_count; ldo_index++) { if (0 == (regulator_count+ldo_index)->mem_data) continue; supply_id = (char *)((regulator_count+ldo_index)->id_name); regu = regulator_get(NULL, supply_id); if (IS_ERR(regu)) { pr_err("%s: some error happen, fail to get regulator %s\n", __func__, supply_id); } volt_value = (regulator_count+ldo_index)->mem_data & 0x0fffffff; ret = regulator_set_voltage(regu, volt_value, volt_value); if (0 != ret) { pr_err("%s: some error happen, fail to get %s voltage!\n", __func__, supply_id); } if ((regulator_count+ldo_index)->mem_data & (1 << 31)) { ret = regu->rdev->desc->ops->enable(regu->rdev); if (0 != ret) { pr_err("%s: some error happen, fail to enable %s!\n", __func__, supply_id); } } else { ret = regu->rdev->desc->ops->disable(regu->rdev); if (0 != ret) { pr_err("%s: some error happen, fail to enable %s!\n", __func__, supply_id); } } regulator_put(regu); } return; } EXPORT_SYMBOL(axp_mem_restore); static int axp_mem_device_remove(struct platform_device *pdev) { if (NULL != regulator_count) { kfree(regulator_count); regulator_count = NULL; } printk(KERN_INFO "%s: module unloaded\n", __func__); return 0; } static struct platform_driver axp_mem_device_driver = { .probe = axp_mem_device_probe, .remove = axp_mem_device_remove, .driver = { .name = "axp-mem-device", .owner = THIS_MODULE, .of_match_table = axp_mem_device_match, }, }; static int __init axp_mem_device_init(void) { s32 ret; ret = platform_driver_register(&axp_mem_device_driver); return ret; } static void __exit axp_mem_device_exit(void) { platform_driver_unregister(&axp_mem_device_driver); } module_init(axp_mem_device_init); module_exit(axp_mem_device_exit); MODULE_DESCRIPTION("axp mem driver"); MODULE_AUTHOR("Ming Li"); MODULE_LICENSE("GPL");