blob: a07b13d4fd5a3efc846bd39197de5e33cb698516 [file] [log] [blame]
Matt Wagantallfc727212012-01-06 18:18:25 -08001/*
Matt Wagantall3ef52422013-04-10 20:29:19 -07002 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Matt Wagantallfc727212012-01-06 18:18:25 -08003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/kernel.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070015#include <linux/module.h>
Matt Wagantallfc727212012-01-06 18:18:25 -080016#include <linux/io.h>
17#include <linux/iopoll.h>
18#include <linux/delay.h>
19#include <linux/err.h>
20#include <linux/of.h>
21#include <linux/platform_device.h>
22#include <linux/regulator/driver.h>
23#include <linux/regulator/machine.h>
24#include <linux/regulator/of_regulator.h>
Matt Wagantall3ef52422013-04-10 20:29:19 -070025#include <linux/clk.h>
26#include <mach/clk.h>
Matt Wagantallfc727212012-01-06 18:18:25 -080027
28#define PWR_ON_MASK BIT(31)
29#define EN_REST_WAIT_MASK (0xF << 20)
30#define EN_FEW_WAIT_MASK (0xF << 16)
31#define CLK_DIS_WAIT_MASK (0xF << 12)
32#define SW_OVERRIDE_MASK BIT(2)
33#define HW_CONTROL_MASK BIT(1)
34#define SW_COLLAPSE_MASK BIT(0)
35
36/* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */
37#define EN_REST_WAIT_VAL (0x2 << 20)
Subbaraman Narayanamurthy4da45022013-03-22 19:48:52 -070038#define EN_FEW_WAIT_VAL (0x8 << 16)
Matt Wagantallfc727212012-01-06 18:18:25 -080039#define CLK_DIS_WAIT_VAL (0x2 << 12)
40
Matt Wagantall9d2040e2013-04-14 13:29:53 -070041#define TIMEOUT_US 1000
Matt Wagantallfc727212012-01-06 18:18:25 -080042
43struct gdsc {
44 struct regulator_dev *rdev;
45 struct regulator_desc rdesc;
46 void __iomem *gdscr;
Matt Wagantall3ef52422013-04-10 20:29:19 -070047 struct clk *core_clk;
Matt Wagantallfc727212012-01-06 18:18:25 -080048};
49
50static int gdsc_is_enabled(struct regulator_dev *rdev)
51{
52 struct gdsc *sc = rdev_get_drvdata(rdev);
53
54 return !!(readl_relaxed(sc->gdscr) & PWR_ON_MASK);
55}
56
57static int gdsc_enable(struct regulator_dev *rdev)
58{
59 struct gdsc *sc = rdev_get_drvdata(rdev);
60 uint32_t regval;
61 int ret;
62
63 regval = readl_relaxed(sc->gdscr);
64 regval &= ~SW_COLLAPSE_MASK;
65 writel_relaxed(regval, sc->gdscr);
66
67 ret = readl_tight_poll_timeout(sc->gdscr, regval, regval & PWR_ON_MASK,
68 TIMEOUT_US);
Matt Wagantall64df1332012-06-26 12:00:19 -070069 if (ret) {
Matt Wagantallfc727212012-01-06 18:18:25 -080070 dev_err(&rdev->dev, "%s enable timed out\n", sc->rdesc.name);
Matt Wagantall64df1332012-06-26 12:00:19 -070071 return ret;
72 }
Matt Wagantallfc727212012-01-06 18:18:25 -080073
Matt Wagantall64df1332012-06-26 12:00:19 -070074 /*
75 * If clocks to this power domain were already on, they will take an
76 * additional 4 clock cycles to re-enable after the rail is enabled.
77 */
78 udelay(1);
79
80 return 0;
Matt Wagantallfc727212012-01-06 18:18:25 -080081}
82
83static int gdsc_disable(struct regulator_dev *rdev)
84{
85 struct gdsc *sc = rdev_get_drvdata(rdev);
86 uint32_t regval;
87 int ret;
88
89 regval = readl_relaxed(sc->gdscr);
90 regval |= SW_COLLAPSE_MASK;
91 writel_relaxed(regval, sc->gdscr);
92
93 ret = readl_tight_poll_timeout(sc->gdscr, regval,
94 !(regval & PWR_ON_MASK), TIMEOUT_US);
95 if (ret)
96 dev_err(&rdev->dev, "%s disable timed out\n", sc->rdesc.name);
97
98 return ret;
99}
100
101static struct regulator_ops gdsc_ops = {
102 .is_enabled = gdsc_is_enabled,
103 .enable = gdsc_enable,
104 .disable = gdsc_disable,
105};
106
107static int __devinit gdsc_probe(struct platform_device *pdev)
108{
109 static atomic_t gdsc_count = ATOMIC_INIT(-1);
110 struct regulator_init_data *init_data;
111 struct resource *res;
112 struct gdsc *sc;
113 uint32_t regval;
Matt Wagantall3ef52422013-04-10 20:29:19 -0700114 bool retain_mems;
Matt Wagantallfc727212012-01-06 18:18:25 -0800115 int ret;
116
117 sc = devm_kzalloc(&pdev->dev, sizeof(struct gdsc), GFP_KERNEL);
118 if (sc == NULL)
119 return -ENOMEM;
120
Steve Mucklef132c6c2012-06-06 18:30:57 -0700121 init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node);
Matt Wagantallfc727212012-01-06 18:18:25 -0800122 if (init_data == NULL)
123 return -ENOMEM;
124
125 if (of_get_property(pdev->dev.of_node, "parent-supply", NULL))
126 init_data->supply_regulator = "parent";
127
128 ret = of_property_read_string(pdev->dev.of_node, "regulator-name",
129 &sc->rdesc.name);
130 if (ret)
131 return ret;
132
133 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
134 if (res == NULL)
135 return -EINVAL;
136 sc->gdscr = devm_ioremap(&pdev->dev, res->start, resource_size(res));
137 if (sc->gdscr == NULL)
138 return -ENOMEM;
139
140 sc->rdesc.id = atomic_inc_return(&gdsc_count);
141 sc->rdesc.ops = &gdsc_ops;
142 sc->rdesc.type = REGULATOR_VOLTAGE;
143 sc->rdesc.owner = THIS_MODULE;
144 platform_set_drvdata(pdev, sc);
145
146 /*
147 * Disable HW trigger: collapse/restore occur based on registers writes.
148 * Disable SW override: Use hardware state-machine for sequencing.
149 */
150 regval = readl_relaxed(sc->gdscr);
151 regval &= ~(HW_CONTROL_MASK | SW_OVERRIDE_MASK);
152
153 /* Configure wait time between states. */
154 regval &= ~(EN_REST_WAIT_MASK | EN_FEW_WAIT_MASK | CLK_DIS_WAIT_MASK);
155 regval |= EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
156 writel_relaxed(regval, sc->gdscr);
157
Matt Wagantall3ef52422013-04-10 20:29:19 -0700158 retain_mems = of_property_read_bool(pdev->dev.of_node,
159 "qcom,retain-mems");
160 if (retain_mems) {
161 sc->core_clk = devm_clk_get(&pdev->dev, "core_clk");
162 if (IS_ERR(sc->core_clk))
163 return PTR_ERR(sc->core_clk);
164 clk_set_flags(sc->core_clk, CLKFLAG_RETAIN_MEM);
165 clk_set_flags(sc->core_clk, CLKFLAG_RETAIN_PERIPH);
166 }
167
Matt Wagantallfc727212012-01-06 18:18:25 -0800168 sc->rdev = regulator_register(&sc->rdesc, &pdev->dev, init_data, sc,
169 pdev->dev.of_node);
170 if (IS_ERR(sc->rdev)) {
171 dev_err(&pdev->dev, "regulator_register(\"%s\") failed.\n",
172 sc->rdesc.name);
173 return PTR_ERR(sc->rdev);
174 }
175
176 return 0;
177}
178
179static int __devexit gdsc_remove(struct platform_device *pdev)
180{
181 struct gdsc *sc = platform_get_drvdata(pdev);
182 regulator_unregister(sc->rdev);
183 return 0;
184}
185
186static struct of_device_id gdsc_match_table[] = {
187 { .compatible = "qcom,gdsc" },
188 {}
189};
190
191static struct platform_driver gdsc_driver = {
192 .probe = gdsc_probe,
193 .remove = __devexit_p(gdsc_remove),
194 .driver = {
195 .name = "gdsc",
196 .of_match_table = gdsc_match_table,
197 .owner = THIS_MODULE,
198 },
199};
200
201static int __init gdsc_init(void)
202{
203 return platform_driver_register(&gdsc_driver);
204}
205subsys_initcall(gdsc_init);
206
207static void __exit gdsc_exit(void)
208{
209 platform_driver_unregister(&gdsc_driver);
210}
211module_exit(gdsc_exit);
212
213MODULE_LICENSE("GPL v2");
Abhimanyu Kapur90ced6e2012-06-26 17:41:25 -0700214MODULE_DESCRIPTION("MSM8974 GDSC power rail regulator driver");