18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * arch/arm/mach-u300/regulator.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2009 ST-Ericsson AB 68c2ecf20Sopenharmony_ci * Handle board-bound regulators and board power not related 78c2ecf20Sopenharmony_ci * to any devices. 88c2ecf20Sopenharmony_ci * Author: Linus Walleij <linus.walleij@stericsson.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci#include <linux/device.h> 118c2ecf20Sopenharmony_ci#include <linux/signal.h> 128c2ecf20Sopenharmony_ci#include <linux/err.h> 138c2ecf20Sopenharmony_ci#include <linux/of.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci#include <linux/regulator/machine.h> 178c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 188c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 198c2ecf20Sopenharmony_ci#include <linux/regmap.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* Power Management Control 16bit (R/W) */ 228c2ecf20Sopenharmony_ci#define U300_SYSCON_PMCR (0x50) 238c2ecf20Sopenharmony_ci#define U300_SYSCON_PMCR_DCON_ENABLE (0x0002) 248c2ecf20Sopenharmony_ci#define U300_SYSCON_PMCR_PWR_MGNT_ENABLE (0x0001) 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* 278c2ecf20Sopenharmony_ci * Regulators that power the board and chip and which are 288c2ecf20Sopenharmony_ci * not copuled to specific drivers are hogged in these 298c2ecf20Sopenharmony_ci * instances. 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_cistatic struct regulator *main_power_15; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* 348c2ecf20Sopenharmony_ci * This function is used from pm.h to shut down the system by 358c2ecf20Sopenharmony_ci * resetting all regulators in turn and then disable regulator 368c2ecf20Sopenharmony_ci * LDO D (main power). 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_civoid u300_pm_poweroff(void) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci sigset_t old, all; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci sigfillset(&all); 438c2ecf20Sopenharmony_ci if (!sigprocmask(SIG_BLOCK, &all, &old)) { 448c2ecf20Sopenharmony_ci /* Disable LDO D to shut down the system */ 458c2ecf20Sopenharmony_ci if (main_power_15) 468c2ecf20Sopenharmony_ci regulator_disable(main_power_15); 478c2ecf20Sopenharmony_ci else 488c2ecf20Sopenharmony_ci pr_err("regulator not available to shut down system\n"); 498c2ecf20Sopenharmony_ci (void) sigprocmask(SIG_SETMASK, &old, NULL); 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci return; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* 558c2ecf20Sopenharmony_ci * Hog the regulators needed to power up the board. 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_cistatic int __init __u300_init_boardpower(struct platform_device *pdev) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 608c2ecf20Sopenharmony_ci struct device_node *syscon_np; 618c2ecf20Sopenharmony_ci struct regmap *regmap; 628c2ecf20Sopenharmony_ci int err; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci pr_info("U300: setting up board power\n"); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci syscon_np = of_parse_phandle(np, "syscon", 0); 678c2ecf20Sopenharmony_ci if (!syscon_np) { 688c2ecf20Sopenharmony_ci pr_crit("U300: no syscon node\n"); 698c2ecf20Sopenharmony_ci return -ENODEV; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci regmap = syscon_node_to_regmap(syscon_np); 728c2ecf20Sopenharmony_ci if (IS_ERR(regmap)) { 738c2ecf20Sopenharmony_ci pr_crit("U300: could not locate syscon regmap\n"); 748c2ecf20Sopenharmony_ci return PTR_ERR(regmap); 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci main_power_15 = regulator_get(&pdev->dev, "vana15"); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (IS_ERR(main_power_15)) { 808c2ecf20Sopenharmony_ci pr_err("could not get vana15"); 818c2ecf20Sopenharmony_ci return PTR_ERR(main_power_15); 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci err = regulator_enable(main_power_15); 848c2ecf20Sopenharmony_ci if (err) { 858c2ecf20Sopenharmony_ci pr_err("could not enable vana15\n"); 868c2ecf20Sopenharmony_ci return err; 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci /* 908c2ecf20Sopenharmony_ci * On U300 a special system controller register pulls up the DC 918c2ecf20Sopenharmony_ci * until the vana15 (LDO D) regulator comes up. At this point, all 928c2ecf20Sopenharmony_ci * regulators are set and we do not need power control via 938c2ecf20Sopenharmony_ci * DC ON anymore. This function will likely be moved whenever 948c2ecf20Sopenharmony_ci * the rest of the U300 power management is implemented. 958c2ecf20Sopenharmony_ci */ 968c2ecf20Sopenharmony_ci pr_info("U300: disable system controller pull-up\n"); 978c2ecf20Sopenharmony_ci regmap_update_bits(regmap, U300_SYSCON_PMCR, 988c2ecf20Sopenharmony_ci U300_SYSCON_PMCR_DCON_ENABLE, 0); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci /* Register globally exported PM poweroff hook */ 1018c2ecf20Sopenharmony_ci pm_power_off = u300_pm_poweroff; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci return 0; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic int __init s365_board_probe(struct platform_device *pdev) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci return __u300_init_boardpower(pdev); 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic const struct of_device_id s365_board_match[] = { 1128c2ecf20Sopenharmony_ci { .compatible = "stericsson,s365" }, 1138c2ecf20Sopenharmony_ci {}, 1148c2ecf20Sopenharmony_ci}; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic struct platform_driver s365_board_driver = { 1178c2ecf20Sopenharmony_ci .driver = { 1188c2ecf20Sopenharmony_ci .name = "s365-board", 1198c2ecf20Sopenharmony_ci .of_match_table = s365_board_match, 1208c2ecf20Sopenharmony_ci }, 1218c2ecf20Sopenharmony_ci}; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* 1248c2ecf20Sopenharmony_ci * So at module init time we hog the regulator! 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_cistatic int __init u300_init_boardpower(void) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci return platform_driver_probe(&s365_board_driver, 1298c2ecf20Sopenharmony_ci s365_board_probe); 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cidevice_initcall(u300_init_boardpower); 1338c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1348c2ecf20Sopenharmony_ciMODULE_AUTHOR("Linus Walleij"); 135