1 /*
2  * arch/arm/mach-u300/regulator.c
3  *
4  * Copyright (C) 2009 ST-Ericsson AB
5  * License terms: GNU General Public License (GPL) version 2
6  * Handle board-bound regulators and board power not related
7  * to any devices.
8  * Author: Linus Walleij <linus.walleij@stericsson.com>
9  */
10 #include <linux/device.h>
11 #include <linux/signal.h>
12 #include <linux/err.h>
13 #include <linux/of.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/regulator/machine.h>
17 #include <linux/regulator/consumer.h>
18 #include <linux/mfd/syscon.h>
19 #include <linux/regmap.h>
20 
21 /* Power Management Control 16bit (R/W) */
22 #define U300_SYSCON_PMCR					(0x50)
23 #define U300_SYSCON_PMCR_DCON_ENABLE				(0x0002)
24 #define U300_SYSCON_PMCR_PWR_MGNT_ENABLE			(0x0001)
25 
26 /*
27  * Regulators that power the board and chip and which are
28  * not copuled to specific drivers are hogged in these
29  * instances.
30  */
31 static struct regulator *main_power_15;
32 
33 /*
34  * This function is used from pm.h to shut down the system by
35  * resetting all regulators in turn and then disable regulator
36  * LDO D (main power).
37  */
u300_pm_poweroff(void)38 void u300_pm_poweroff(void)
39 {
40 	sigset_t old, all;
41 
42 	sigfillset(&all);
43 	if (!sigprocmask(SIG_BLOCK, &all, &old)) {
44 		/* Disable LDO D to shut down the system */
45 		if (main_power_15)
46 			regulator_disable(main_power_15);
47 		else
48 			pr_err("regulator not available to shut down system\n");
49 		(void) sigprocmask(SIG_SETMASK, &old, NULL);
50 	}
51 	return;
52 }
53 
54 /*
55  * Hog the regulators needed to power up the board.
56  */
__u300_init_boardpower(struct platform_device * pdev)57 static int __init __u300_init_boardpower(struct platform_device *pdev)
58 {
59 	struct device_node *np = pdev->dev.of_node;
60 	struct device_node *syscon_np;
61 	struct regmap *regmap;
62 	int err;
63 
64 	pr_info("U300: setting up board power\n");
65 
66 	syscon_np = of_parse_phandle(np, "syscon", 0);
67 	if (!syscon_np) {
68 		pr_crit("U300: no syscon node\n");
69 		return -ENODEV;
70 	}
71 	regmap = syscon_node_to_regmap(syscon_np);
72 	if (IS_ERR(regmap)) {
73 		pr_crit("U300: could not locate syscon regmap\n");
74 		return PTR_ERR(regmap);
75 	}
76 
77 	main_power_15 = regulator_get(&pdev->dev, "vana15");
78 
79 	if (IS_ERR(main_power_15)) {
80 		pr_err("could not get vana15");
81 		return PTR_ERR(main_power_15);
82 	}
83 	err = regulator_enable(main_power_15);
84 	if (err) {
85 		pr_err("could not enable vana15\n");
86 		return err;
87 	}
88 
89 	/*
90 	 * On U300 a special system controller register pulls up the DC
91 	 * until the vana15 (LDO D) regulator comes up. At this point, all
92 	 * regulators are set and we do not need power control via
93 	 * DC ON anymore. This function will likely be moved whenever
94 	 * the rest of the U300 power management is implemented.
95 	 */
96 	pr_info("U300: disable system controller pull-up\n");
97 	regmap_update_bits(regmap, U300_SYSCON_PMCR,
98 			   U300_SYSCON_PMCR_DCON_ENABLE, 0);
99 
100 	/* Register globally exported PM poweroff hook */
101 	pm_power_off = u300_pm_poweroff;
102 
103 	return 0;
104 }
105 
s365_board_probe(struct platform_device * pdev)106 static int __init s365_board_probe(struct platform_device *pdev)
107 {
108 	return __u300_init_boardpower(pdev);
109 }
110 
111 static const struct of_device_id s365_board_match[] = {
112 	{ .compatible = "stericsson,s365" },
113 	{},
114 };
115 
116 static struct platform_driver s365_board_driver = {
117 	.driver		= {
118 		.name   = "s365-board",
119 		.of_match_table = s365_board_match,
120 	},
121 };
122 
123 /*
124  * So at module init time we hog the regulator!
125  */
u300_init_boardpower(void)126 static int __init u300_init_boardpower(void)
127 {
128 	return platform_driver_probe(&s365_board_driver,
129 				     s365_board_probe);
130 }
131 
132 device_initcall(u300_init_boardpower);
133