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