hc
2024-05-10 9999e48639b3cecb08ffb37358bcba3b48161b29
kernel/drivers/regulator/act8945a-regulator.c
....@@ -1,45 +1,50 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Voltage regulation driver for active-semi ACT8945A PMIC
34 *
45 * Copyright (C) 2015 Atmel Corporation
56 *
67 * Author: Wenyou Yang <wenyou.yang@atmel.com>
7
- *
8
- * This program is free software; you can redistribute it and/or
9
- * modify it under the terms of the GNU General Public License as
10
- * published by the Free Software Foundation; either version 2 of the
11
- * License, or (at your option) any later version.
12
- *
138 */
149
1510 #include <linux/module.h>
1611 #include <linux/of_device.h>
1712 #include <linux/platform_device.h>
13
+#include <linux/regmap.h>
1814 #include <linux/regulator/driver.h>
1915 #include <linux/regulator/machine.h>
16
+#include <dt-bindings/regulator/active-semi,8945a-regulator.h>
2017
2118 /**
2219 * ACT8945A Global Register Map.
2320 */
2421 #define ACT8945A_SYS_MODE 0x00
2522 #define ACT8945A_SYS_CTRL 0x01
23
+#define ACT8945A_SYS_UNLK_REGS 0x0b
2624 #define ACT8945A_DCDC1_VSET1 0x20
2725 #define ACT8945A_DCDC1_VSET2 0x21
2826 #define ACT8945A_DCDC1_CTRL 0x22
27
+#define ACT8945A_DCDC1_SUS 0x24
2928 #define ACT8945A_DCDC2_VSET1 0x30
3029 #define ACT8945A_DCDC2_VSET2 0x31
3130 #define ACT8945A_DCDC2_CTRL 0x32
31
+#define ACT8945A_DCDC2_SUS 0x34
3232 #define ACT8945A_DCDC3_VSET1 0x40
3333 #define ACT8945A_DCDC3_VSET2 0x41
3434 #define ACT8945A_DCDC3_CTRL 0x42
35
+#define ACT8945A_DCDC3_SUS 0x44
3536 #define ACT8945A_LDO1_VSET 0x50
3637 #define ACT8945A_LDO1_CTRL 0x51
38
+#define ACT8945A_LDO1_SUS 0x52
3739 #define ACT8945A_LDO2_VSET 0x54
3840 #define ACT8945A_LDO2_CTRL 0x55
41
+#define ACT8945A_LDO2_SUS 0x56
3942 #define ACT8945A_LDO3_VSET 0x60
4043 #define ACT8945A_LDO3_CTRL 0x61
44
+#define ACT8945A_LDO3_SUS 0x62
4145 #define ACT8945A_LDO4_VSET 0x64
4246 #define ACT8945A_LDO4_CTRL 0x65
47
+#define ACT8945A_LDO4_SUS 0x66
4348
4449 /**
4550 * Field Definitions.
....@@ -60,14 +65,157 @@
6065 ACT8945A_ID_LDO2,
6166 ACT8945A_ID_LDO3,
6267 ACT8945A_ID_LDO4,
63
- ACT8945A_REG_NUM,
68
+ ACT8945A_ID_MAX,
6469 };
6570
66
-static const struct regulator_linear_range act8945a_voltage_ranges[] = {
71
+struct act8945a_pmic {
72
+ struct regmap *regmap;
73
+ u32 op_mode[ACT8945A_ID_MAX];
74
+};
75
+
76
+static const struct linear_range act8945a_voltage_ranges[] = {
6777 REGULATOR_LINEAR_RANGE(600000, 0, 23, 25000),
6878 REGULATOR_LINEAR_RANGE(1200000, 24, 47, 50000),
6979 REGULATOR_LINEAR_RANGE(2400000, 48, 63, 100000),
7080 };
81
+
82
+static int act8945a_set_suspend_state(struct regulator_dev *rdev, bool enable)
83
+{
84
+ struct regmap *regmap = rdev->regmap;
85
+ int id = rdev_get_id(rdev);
86
+ int reg, val;
87
+
88
+ switch (id) {
89
+ case ACT8945A_ID_DCDC1:
90
+ reg = ACT8945A_DCDC1_SUS;
91
+ val = 0xa8;
92
+ break;
93
+ case ACT8945A_ID_DCDC2:
94
+ reg = ACT8945A_DCDC2_SUS;
95
+ val = 0xa8;
96
+ break;
97
+ case ACT8945A_ID_DCDC3:
98
+ reg = ACT8945A_DCDC3_SUS;
99
+ val = 0xa8;
100
+ break;
101
+ case ACT8945A_ID_LDO1:
102
+ reg = ACT8945A_LDO1_SUS;
103
+ val = 0xe8;
104
+ break;
105
+ case ACT8945A_ID_LDO2:
106
+ reg = ACT8945A_LDO2_SUS;
107
+ val = 0xe8;
108
+ break;
109
+ case ACT8945A_ID_LDO3:
110
+ reg = ACT8945A_LDO3_SUS;
111
+ val = 0xe8;
112
+ break;
113
+ case ACT8945A_ID_LDO4:
114
+ reg = ACT8945A_LDO4_SUS;
115
+ val = 0xe8;
116
+ break;
117
+ default:
118
+ return -EINVAL;
119
+ }
120
+
121
+ if (enable)
122
+ val |= BIT(4);
123
+
124
+ /*
125
+ * Ask the PMIC to enable/disable this output when entering hibernate
126
+ * mode.
127
+ */
128
+ return regmap_write(regmap, reg, val);
129
+}
130
+
131
+static int act8945a_set_suspend_enable(struct regulator_dev *rdev)
132
+{
133
+ return act8945a_set_suspend_state(rdev, true);
134
+}
135
+
136
+static int act8945a_set_suspend_disable(struct regulator_dev *rdev)
137
+{
138
+ return act8945a_set_suspend_state(rdev, false);
139
+}
140
+
141
+static unsigned int act8945a_of_map_mode(unsigned int mode)
142
+{
143
+ switch (mode) {
144
+ case ACT8945A_REGULATOR_MODE_FIXED:
145
+ case ACT8945A_REGULATOR_MODE_NORMAL:
146
+ return REGULATOR_MODE_NORMAL;
147
+ case ACT8945A_REGULATOR_MODE_LOWPOWER:
148
+ return REGULATOR_MODE_STANDBY;
149
+ default:
150
+ return REGULATOR_MODE_INVALID;
151
+ }
152
+}
153
+
154
+static int act8945a_set_mode(struct regulator_dev *rdev, unsigned int mode)
155
+{
156
+ struct act8945a_pmic *act8945a = rdev_get_drvdata(rdev);
157
+ struct regmap *regmap = rdev->regmap;
158
+ int id = rdev_get_id(rdev);
159
+ int reg, ret, val = 0;
160
+
161
+ switch (id) {
162
+ case ACT8945A_ID_DCDC1:
163
+ reg = ACT8945A_DCDC1_CTRL;
164
+ break;
165
+ case ACT8945A_ID_DCDC2:
166
+ reg = ACT8945A_DCDC2_CTRL;
167
+ break;
168
+ case ACT8945A_ID_DCDC3:
169
+ reg = ACT8945A_DCDC3_CTRL;
170
+ break;
171
+ case ACT8945A_ID_LDO1:
172
+ reg = ACT8945A_LDO1_CTRL;
173
+ break;
174
+ case ACT8945A_ID_LDO2:
175
+ reg = ACT8945A_LDO2_CTRL;
176
+ break;
177
+ case ACT8945A_ID_LDO3:
178
+ reg = ACT8945A_LDO3_CTRL;
179
+ break;
180
+ case ACT8945A_ID_LDO4:
181
+ reg = ACT8945A_LDO4_CTRL;
182
+ break;
183
+ default:
184
+ return -EINVAL;
185
+ }
186
+
187
+ switch (mode) {
188
+ case REGULATOR_MODE_STANDBY:
189
+ if (id > ACT8945A_ID_DCDC3)
190
+ val = BIT(5);
191
+ break;
192
+ case REGULATOR_MODE_NORMAL:
193
+ if (id <= ACT8945A_ID_DCDC3)
194
+ val = BIT(5);
195
+ break;
196
+ default:
197
+ return -EINVAL;
198
+ }
199
+
200
+ ret = regmap_update_bits(regmap, reg, BIT(5), val);
201
+ if (ret)
202
+ return ret;
203
+
204
+ act8945a->op_mode[id] = mode;
205
+
206
+ return 0;
207
+}
208
+
209
+static unsigned int act8945a_get_mode(struct regulator_dev *rdev)
210
+{
211
+ struct act8945a_pmic *act8945a = rdev_get_drvdata(rdev);
212
+ int id = rdev_get_id(rdev);
213
+
214
+ if (id < ACT8945A_ID_DCDC1 || id >= ACT8945A_ID_MAX)
215
+ return -EINVAL;
216
+
217
+ return act8945a->op_mode[id];
218
+}
71219
72220 static const struct regulator_ops act8945a_ops = {
73221 .list_voltage = regulator_list_voltage_linear_range,
....@@ -76,7 +224,11 @@
76224 .set_voltage_sel = regulator_set_voltage_sel_regmap,
77225 .enable = regulator_enable_regmap,
78226 .disable = regulator_disable_regmap,
227
+ .set_mode = act8945a_set_mode,
228
+ .get_mode = act8945a_get_mode,
79229 .is_enabled = regulator_is_enabled_regmap,
230
+ .set_suspend_enable = act8945a_set_suspend_enable,
231
+ .set_suspend_disable = act8945a_set_suspend_disable,
80232 };
81233
82234 #define ACT89xx_REG(_name, _family, _id, _vsel_reg, _supply) \
....@@ -84,6 +236,7 @@
84236 .name = _name, \
85237 .supply_name = _supply, \
86238 .of_match = of_match_ptr("REG_"#_id), \
239
+ .of_map_mode = act8945a_of_map_mode, \
87240 .regulators_node = of_match_ptr("regulators"), \
88241 .id = _family##_ID_##_id, \
89242 .type = REGULATOR_VOLTAGE, \
....@@ -122,9 +275,21 @@
122275 {
123276 struct regulator_config config = { };
124277 const struct regulator_desc *regulators;
278
+ struct act8945a_pmic *act8945a;
125279 struct regulator_dev *rdev;
126280 int i, num_regulators;
127281 bool voltage_select;
282
+
283
+ act8945a = devm_kzalloc(&pdev->dev, sizeof(*act8945a), GFP_KERNEL);
284
+ if (!act8945a)
285
+ return -ENOMEM;
286
+
287
+ act8945a->regmap = dev_get_regmap(pdev->dev.parent, NULL);
288
+ if (!act8945a->regmap) {
289
+ dev_err(&pdev->dev,
290
+ "could not retrieve regmap from parent device\n");
291
+ return -EINVAL;
292
+ }
128293
129294 voltage_select = of_property_read_bool(pdev->dev.parent->of_node,
130295 "active-semi,vsel-high");
....@@ -139,8 +304,10 @@
139304
140305 config.dev = &pdev->dev;
141306 config.dev->of_node = pdev->dev.parent->of_node;
307
+ config.driver_data = act8945a;
142308 for (i = 0; i < num_regulators; i++) {
143
- rdev = devm_regulator_register(&pdev->dev, &regulators[i], &config);
309
+ rdev = devm_regulator_register(&pdev->dev, &regulators[i],
310
+ &config);
144311 if (IS_ERR(rdev)) {
145312 dev_err(&pdev->dev,
146313 "failed to register %s regulator\n",
....@@ -149,14 +316,42 @@
149316 }
150317 }
151318
152
- return 0;
319
+ platform_set_drvdata(pdev, act8945a);
320
+
321
+ /* Unlock expert registers. */
322
+ return regmap_write(act8945a->regmap, ACT8945A_SYS_UNLK_REGS, 0xef);
323
+}
324
+
325
+static int __maybe_unused act8945a_suspend(struct device *pdev)
326
+{
327
+ struct act8945a_pmic *act8945a = dev_get_drvdata(pdev);
328
+
329
+ /*
330
+ * Ask the PMIC to enter the suspend mode on the next PWRHLD
331
+ * transition.
332
+ */
333
+ return regmap_write(act8945a->regmap, ACT8945A_SYS_CTRL, 0x42);
334
+}
335
+
336
+static SIMPLE_DEV_PM_OPS(act8945a_pm, act8945a_suspend, NULL);
337
+
338
+static void act8945a_pmic_shutdown(struct platform_device *pdev)
339
+{
340
+ struct act8945a_pmic *act8945a = platform_get_drvdata(pdev);
341
+
342
+ /*
343
+ * Ask the PMIC to shutdown everything on the next PWRHLD transition.
344
+ */
345
+ regmap_write(act8945a->regmap, ACT8945A_SYS_CTRL, 0x0);
153346 }
154347
155348 static struct platform_driver act8945a_pmic_driver = {
156349 .driver = {
157350 .name = "act8945a-regulator",
351
+ .pm = &act8945a_pm,
158352 },
159353 .probe = act8945a_pmic_probe,
354
+ .shutdown = act8945a_pmic_shutdown,
160355 };
161356 module_platform_driver(act8945a_pmic_driver);
162357