regulator: lochnagar: Use a consisent comment style for SPDX header
[sfrench/cifs-2.6.git] / drivers / regulator / lochnagar-regulator.c
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // Lochnagar regulator driver
4 //
5 // Copyright (c) 2017-2018 Cirrus Logic, Inc. and
6 //                         Cirrus Logic International Semiconductor Ltd.
7 //
8 // Author: Charles Keepax <ckeepax@opensource.cirrus.com>
9
10 #include <linux/bitops.h>
11 #include <linux/device.h>
12 #include <linux/err.h>
13 #include <linux/module.h>
14 #include <linux/mutex.h>
15 #include <linux/of.h>
16 #include <linux/platform_device.h>
17 #include <linux/regmap.h>
18 #include <linux/regulator/driver.h>
19 #include <linux/regulator/machine.h>
20 #include <linux/regulator/of_regulator.h>
21
22 #include <linux/mfd/lochnagar.h>
23
24 static const struct regulator_ops lochnagar_micvdd_ops = {
25         .enable = regulator_enable_regmap,
26         .disable = regulator_disable_regmap,
27         .is_enabled = regulator_is_enabled_regmap,
28
29         .list_voltage = regulator_list_voltage_linear_range,
30         .map_voltage = regulator_map_voltage_linear_range,
31
32         .get_voltage_sel = regulator_get_voltage_sel_regmap,
33         .set_voltage_sel = regulator_set_voltage_sel_regmap,
34 };
35
36 static const struct regulator_linear_range lochnagar_micvdd_ranges[] = {
37         REGULATOR_LINEAR_RANGE(1000000, 0,    0xC, 50000),
38         REGULATOR_LINEAR_RANGE(1700000, 0xD, 0x1F, 100000),
39 };
40
41 static int lochnagar_micbias_enable(struct regulator_dev *rdev)
42 {
43         struct lochnagar *lochnagar = rdev_get_drvdata(rdev);
44         int ret;
45
46         mutex_lock(&lochnagar->analogue_config_lock);
47
48         ret = regulator_enable_regmap(rdev);
49         if (ret < 0)
50                 goto err;
51
52         ret = lochnagar_update_config(lochnagar);
53
54 err:
55         mutex_unlock(&lochnagar->analogue_config_lock);
56
57         return ret;
58 }
59
60 static int lochnagar_micbias_disable(struct regulator_dev *rdev)
61 {
62         struct lochnagar *lochnagar = rdev_get_drvdata(rdev);
63         int ret;
64
65         mutex_lock(&lochnagar->analogue_config_lock);
66
67         ret = regulator_disable_regmap(rdev);
68         if (ret < 0)
69                 goto err;
70
71         ret = lochnagar_update_config(lochnagar);
72
73 err:
74         mutex_unlock(&lochnagar->analogue_config_lock);
75
76         return ret;
77 }
78
79 static const struct regulator_ops lochnagar_micbias_ops = {
80         .enable = lochnagar_micbias_enable,
81         .disable = lochnagar_micbias_disable,
82         .is_enabled = regulator_is_enabled_regmap,
83 };
84
85 static const struct regulator_ops lochnagar_vddcore_ops = {
86         .enable = regulator_enable_regmap,
87         .disable = regulator_disable_regmap,
88         .is_enabled = regulator_is_enabled_regmap,
89
90         .list_voltage = regulator_list_voltage_linear_range,
91         .map_voltage = regulator_map_voltage_linear_range,
92
93         .get_voltage_sel = regulator_get_voltage_sel_regmap,
94         .set_voltage_sel = regulator_set_voltage_sel_regmap,
95 };
96
97 static const struct regulator_linear_range lochnagar_vddcore_ranges[] = {
98         REGULATOR_LINEAR_RANGE(600000, 0x8, 0x41, 12500),
99 };
100
101 enum lochnagar_regulators {
102         LOCHNAGAR_MICVDD,
103         LOCHNAGAR_MIC1VDD,
104         LOCHNAGAR_MIC2VDD,
105         LOCHNAGAR_VDDCORE,
106 };
107
108 static int lochnagar_micbias_of_parse(struct device_node *np,
109                                       const struct regulator_desc *desc,
110                                       struct regulator_config *config)
111 {
112         struct lochnagar *lochnagar = config->driver_data;
113         int shift = (desc->id - LOCHNAGAR_MIC1VDD) *
114                     LOCHNAGAR2_P2_MICBIAS_SRC_SHIFT;
115         int mask = LOCHNAGAR2_P1_MICBIAS_SRC_MASK << shift;
116         unsigned int val;
117         int ret;
118
119         ret = of_property_read_u32(np, "cirrus,micbias-input", &val);
120         if (ret >= 0) {
121                 mutex_lock(&lochnagar->analogue_config_lock);
122                 ret = regmap_update_bits(lochnagar->regmap,
123                                          LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
124                                          mask, val << shift);
125                 mutex_unlock(&lochnagar->analogue_config_lock);
126                 if (ret < 0) {
127                         dev_err(lochnagar->dev,
128                                 "Failed to update micbias source: %d\n", ret);
129                         return ret;
130                 }
131         }
132
133         return 0;
134 }
135
136 static const struct regulator_desc lochnagar_regulators[] = {
137         [LOCHNAGAR_MICVDD] = {
138                 .name = "MICVDD",
139                 .supply_name = "SYSVDD",
140                 .type = REGULATOR_VOLTAGE,
141                 .n_voltages = 32,
142                 .ops = &lochnagar_micvdd_ops,
143
144                 .id = LOCHNAGAR_MICVDD,
145                 .of_match = of_match_ptr("MICVDD"),
146
147                 .enable_reg = LOCHNAGAR2_MICVDD_CTRL1,
148                 .enable_mask = LOCHNAGAR2_MICVDD_REG_ENA_MASK,
149                 .vsel_reg = LOCHNAGAR2_MICVDD_CTRL2,
150                 .vsel_mask = LOCHNAGAR2_MICVDD_VSEL_MASK,
151
152                 .linear_ranges = lochnagar_micvdd_ranges,
153                 .n_linear_ranges = ARRAY_SIZE(lochnagar_micvdd_ranges),
154
155                 .enable_time = 3000,
156                 .ramp_delay = 1000,
157
158                 .owner = THIS_MODULE,
159         },
160         [LOCHNAGAR_MIC1VDD] = {
161                 .name = "MIC1VDD",
162                 .supply_name = "MICBIAS1",
163                 .type = REGULATOR_VOLTAGE,
164                 .ops = &lochnagar_micbias_ops,
165
166                 .id = LOCHNAGAR_MIC1VDD,
167                 .of_match = of_match_ptr("MIC1VDD"),
168                 .of_parse_cb = lochnagar_micbias_of_parse,
169
170                 .enable_reg = LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
171                 .enable_mask = LOCHNAGAR2_P1_INPUT_BIAS_ENA_MASK,
172
173                 .owner = THIS_MODULE,
174         },
175         [LOCHNAGAR_MIC2VDD] = {
176                 .name = "MIC2VDD",
177                 .supply_name = "MICBIAS2",
178                 .type = REGULATOR_VOLTAGE,
179                 .ops = &lochnagar_micbias_ops,
180
181                 .id = LOCHNAGAR_MIC2VDD,
182                 .of_match = of_match_ptr("MIC2VDD"),
183                 .of_parse_cb = lochnagar_micbias_of_parse,
184
185                 .enable_reg = LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
186                 .enable_mask = LOCHNAGAR2_P2_INPUT_BIAS_ENA_MASK,
187
188                 .owner = THIS_MODULE,
189         },
190         [LOCHNAGAR_VDDCORE] = {
191                 .name = "VDDCORE",
192                 .supply_name = "SYSVDD",
193                 .type = REGULATOR_VOLTAGE,
194                 .n_voltages = 57,
195                 .ops = &lochnagar_vddcore_ops,
196
197                 .id = LOCHNAGAR_VDDCORE,
198                 .of_match = of_match_ptr("VDDCORE"),
199
200                 .enable_reg = LOCHNAGAR2_VDDCORE_CDC_CTRL1,
201                 .enable_mask = LOCHNAGAR2_VDDCORE_CDC_REG_ENA_MASK,
202                 .vsel_reg = LOCHNAGAR2_VDDCORE_CDC_CTRL2,
203                 .vsel_mask = LOCHNAGAR2_VDDCORE_CDC_VSEL_MASK,
204
205                 .linear_ranges = lochnagar_vddcore_ranges,
206                 .n_linear_ranges = ARRAY_SIZE(lochnagar_vddcore_ranges),
207
208                 .enable_time = 3000,
209                 .ramp_delay = 1000,
210
211                 .owner = THIS_MODULE,
212         },
213 };
214
215 static int lochnagar_regulator_probe(struct platform_device *pdev)
216 {
217         struct device *dev = &pdev->dev;
218         struct lochnagar *lochnagar = dev_get_drvdata(dev->parent);
219         struct regulator_config config = { };
220         struct regulator_dev *rdev;
221         int ret, i;
222
223         config.dev = lochnagar->dev;
224         config.regmap = lochnagar->regmap;
225         config.driver_data = lochnagar;
226
227         for (i = 0; i < ARRAY_SIZE(lochnagar_regulators); i++) {
228                 const struct regulator_desc *desc = &lochnagar_regulators[i];
229
230                 rdev = devm_regulator_register(dev, desc, &config);
231                 if (IS_ERR(rdev)) {
232                         ret = PTR_ERR(rdev);
233                         dev_err(dev, "Failed to register %s regulator: %d\n",
234                                 desc->name, ret);
235                         return ret;
236                 }
237         }
238
239         return 0;
240 }
241
242 static struct platform_driver lochnagar_regulator_driver = {
243         .driver = {
244                 .name = "lochnagar-regulator",
245         },
246
247         .probe = lochnagar_regulator_probe,
248 };
249 module_platform_driver(lochnagar_regulator_driver);
250
251 MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
252 MODULE_DESCRIPTION("Regulator driver for Cirrus Logic Lochnagar Board");
253 MODULE_LICENSE("GPL v2");
254 MODULE_ALIAS("platform:lochnagar-regulator");