blob: a77ac24272e69bfa7c7a47f3ffa32e8682849ea4 [file] [log] [blame]
Matt Wagantallfc727212012-01-06 18:18:25 -08001/*
2 * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
3 *
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>
15#include <linux/io.h>
16#include <linux/iopoll.h>
17#include <linux/delay.h>
18#include <linux/err.h>
19#include <linux/of.h>
20#include <linux/platform_device.h>
21#include <linux/regulator/driver.h>
22#include <linux/regulator/machine.h>
23#include <linux/regulator/of_regulator.h>
24
25#define PWR_ON_MASK BIT(31)
26#define EN_REST_WAIT_MASK (0xF << 20)
27#define EN_FEW_WAIT_MASK (0xF << 16)
28#define CLK_DIS_WAIT_MASK (0xF << 12)
29#define SW_OVERRIDE_MASK BIT(2)
30#define HW_CONTROL_MASK BIT(1)
31#define SW_COLLAPSE_MASK BIT(0)
32
33/* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */
34#define EN_REST_WAIT_VAL (0x2 << 20)
35#define EN_FEW_WAIT_VAL (0x2 << 16)
36#define CLK_DIS_WAIT_VAL (0x2 << 12)
37
38#define TIMEOUT_US 10
39
40struct gdsc {
41 struct regulator_dev *rdev;
42 struct regulator_desc rdesc;
43 void __iomem *gdscr;
44};
45
46static int gdsc_is_enabled(struct regulator_dev *rdev)
47{
48 struct gdsc *sc = rdev_get_drvdata(rdev);
49
50 return !!(readl_relaxed(sc->gdscr) & PWR_ON_MASK);
51}
52
53static int gdsc_enable(struct regulator_dev *rdev)
54{
55 struct gdsc *sc = rdev_get_drvdata(rdev);
56 uint32_t regval;
57 int ret;
58
59 regval = readl_relaxed(sc->gdscr);
60 regval &= ~SW_COLLAPSE_MASK;
61 writel_relaxed(regval, sc->gdscr);
62
63 ret = readl_tight_poll_timeout(sc->gdscr, regval, regval & PWR_ON_MASK,
64 TIMEOUT_US);
65 if (ret)
66 dev_err(&rdev->dev, "%s enable timed out\n", sc->rdesc.name);
67
68 return ret;
69}
70
71static int gdsc_disable(struct regulator_dev *rdev)
72{
73 struct gdsc *sc = rdev_get_drvdata(rdev);
74 uint32_t regval;
75 int ret;
76
77 regval = readl_relaxed(sc->gdscr);
78 regval |= SW_COLLAPSE_MASK;
79 writel_relaxed(regval, sc->gdscr);
80
81 ret = readl_tight_poll_timeout(sc->gdscr, regval,
82 !(regval & PWR_ON_MASK), TIMEOUT_US);
83 if (ret)
84 dev_err(&rdev->dev, "%s disable timed out\n", sc->rdesc.name);
85
86 return ret;
87}
88
89static struct regulator_ops gdsc_ops = {
90 .is_enabled = gdsc_is_enabled,
91 .enable = gdsc_enable,
92 .disable = gdsc_disable,
93};
94
95static int __devinit gdsc_probe(struct platform_device *pdev)
96{
97 static atomic_t gdsc_count = ATOMIC_INIT(-1);
98 struct regulator_init_data *init_data;
99 struct resource *res;
100 struct gdsc *sc;
101 uint32_t regval;
102 int ret;
103
104 sc = devm_kzalloc(&pdev->dev, sizeof(struct gdsc), GFP_KERNEL);
105 if (sc == NULL)
106 return -ENOMEM;
107
108 init_data = of_get_regulator_init_data(&pdev->dev);
109 if (init_data == NULL)
110 return -ENOMEM;
111
112 if (of_get_property(pdev->dev.of_node, "parent-supply", NULL))
113 init_data->supply_regulator = "parent";
114
115 ret = of_property_read_string(pdev->dev.of_node, "regulator-name",
116 &sc->rdesc.name);
117 if (ret)
118 return ret;
119
120 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
121 if (res == NULL)
122 return -EINVAL;
123 sc->gdscr = devm_ioremap(&pdev->dev, res->start, resource_size(res));
124 if (sc->gdscr == NULL)
125 return -ENOMEM;
126
127 sc->rdesc.id = atomic_inc_return(&gdsc_count);
128 sc->rdesc.ops = &gdsc_ops;
129 sc->rdesc.type = REGULATOR_VOLTAGE;
130 sc->rdesc.owner = THIS_MODULE;
131 platform_set_drvdata(pdev, sc);
132
133 /*
134 * Disable HW trigger: collapse/restore occur based on registers writes.
135 * Disable SW override: Use hardware state-machine for sequencing.
136 */
137 regval = readl_relaxed(sc->gdscr);
138 regval &= ~(HW_CONTROL_MASK | SW_OVERRIDE_MASK);
139
140 /* Configure wait time between states. */
141 regval &= ~(EN_REST_WAIT_MASK | EN_FEW_WAIT_MASK | CLK_DIS_WAIT_MASK);
142 regval |= EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
143 writel_relaxed(regval, sc->gdscr);
144
145 sc->rdev = regulator_register(&sc->rdesc, &pdev->dev, init_data, sc,
146 pdev->dev.of_node);
147 if (IS_ERR(sc->rdev)) {
148 dev_err(&pdev->dev, "regulator_register(\"%s\") failed.\n",
149 sc->rdesc.name);
150 return PTR_ERR(sc->rdev);
151 }
152
153 return 0;
154}
155
156static int __devexit gdsc_remove(struct platform_device *pdev)
157{
158 struct gdsc *sc = platform_get_drvdata(pdev);
159 regulator_unregister(sc->rdev);
160 return 0;
161}
162
163static struct of_device_id gdsc_match_table[] = {
164 { .compatible = "qcom,gdsc" },
165 {}
166};
167
168static struct platform_driver gdsc_driver = {
169 .probe = gdsc_probe,
170 .remove = __devexit_p(gdsc_remove),
171 .driver = {
172 .name = "gdsc",
173 .of_match_table = gdsc_match_table,
174 .owner = THIS_MODULE,
175 },
176};
177
178static int __init gdsc_init(void)
179{
180 return platform_driver_register(&gdsc_driver);
181}
182subsys_initcall(gdsc_init);
183
184static void __exit gdsc_exit(void)
185{
186 platform_driver_unregister(&gdsc_driver);
187}
188module_exit(gdsc_exit);
189
190MODULE_LICENSE("GPL v2");
191MODULE_DESCRIPTION("Copper GDSC power rail regulator driver");