1 // SPDX-License-Identifier: GPL-2.0
3 // Lochnagar regulator driver
5 // Copyright (c) 2017-2018 Cirrus Logic, Inc. and
6 // Cirrus Logic International Semiconductor Ltd.
8 // Author: Charles Keepax <ckeepax@opensource.cirrus.com>
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>
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>
22 #include <linux/mfd/lochnagar.h>
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
,
29 .list_voltage
= regulator_list_voltage_linear_range
,
30 .map_voltage
= regulator_map_voltage_linear_range
,
32 .get_voltage_sel
= regulator_get_voltage_sel_regmap
,
33 .set_voltage_sel
= regulator_set_voltage_sel_regmap
,
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),
41 static int lochnagar_micbias_enable(struct regulator_dev
*rdev
)
43 struct lochnagar
*lochnagar
= rdev_get_drvdata(rdev
);
46 mutex_lock(&lochnagar
->analogue_config_lock
);
48 ret
= regulator_enable_regmap(rdev
);
52 ret
= lochnagar_update_config(lochnagar
);
55 mutex_unlock(&lochnagar
->analogue_config_lock
);
60 static int lochnagar_micbias_disable(struct regulator_dev
*rdev
)
62 struct lochnagar
*lochnagar
= rdev_get_drvdata(rdev
);
65 mutex_lock(&lochnagar
->analogue_config_lock
);
67 ret
= regulator_disable_regmap(rdev
);
71 ret
= lochnagar_update_config(lochnagar
);
74 mutex_unlock(&lochnagar
->analogue_config_lock
);
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
,
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
,
90 .list_voltage
= regulator_list_voltage_linear_range
,
91 .map_voltage
= regulator_map_voltage_linear_range
,
93 .get_voltage_sel
= regulator_get_voltage_sel_regmap
,
94 .set_voltage_sel
= regulator_set_voltage_sel_regmap
,
97 static const struct regulator_linear_range lochnagar_vddcore_ranges
[] = {
98 REGULATOR_LINEAR_RANGE(600000, 0x8, 0x41, 12500),
101 enum lochnagar_regulators
{
108 static int lochnagar_micbias_of_parse(struct device_node
*np
,
109 const struct regulator_desc
*desc
,
110 struct regulator_config
*config
)
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
;
119 ret
= of_property_read_u32(np
, "cirrus,micbias-input", &val
);
121 mutex_lock(&lochnagar
->analogue_config_lock
);
122 ret
= regmap_update_bits(lochnagar
->regmap
,
123 LOCHNAGAR2_ANALOGUE_PATH_CTRL2
,
125 mutex_unlock(&lochnagar
->analogue_config_lock
);
127 dev_err(lochnagar
->dev
,
128 "Failed to update micbias source: %d\n", ret
);
136 static const struct regulator_desc lochnagar_regulators
[] = {
137 [LOCHNAGAR_MICVDD
] = {
139 .supply_name
= "SYSVDD",
140 .type
= REGULATOR_VOLTAGE
,
142 .ops
= &lochnagar_micvdd_ops
,
144 .id
= LOCHNAGAR_MICVDD
,
145 .of_match
= of_match_ptr("MICVDD"),
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
,
152 .linear_ranges
= lochnagar_micvdd_ranges
,
153 .n_linear_ranges
= ARRAY_SIZE(lochnagar_micvdd_ranges
),
158 .owner
= THIS_MODULE
,
160 [LOCHNAGAR_MIC1VDD
] = {
162 .supply_name
= "MICBIAS1",
163 .type
= REGULATOR_VOLTAGE
,
164 .ops
= &lochnagar_micbias_ops
,
166 .id
= LOCHNAGAR_MIC1VDD
,
167 .of_match
= of_match_ptr("MIC1VDD"),
168 .of_parse_cb
= lochnagar_micbias_of_parse
,
170 .enable_reg
= LOCHNAGAR2_ANALOGUE_PATH_CTRL2
,
171 .enable_mask
= LOCHNAGAR2_P1_INPUT_BIAS_ENA_MASK
,
173 .owner
= THIS_MODULE
,
175 [LOCHNAGAR_MIC2VDD
] = {
177 .supply_name
= "MICBIAS2",
178 .type
= REGULATOR_VOLTAGE
,
179 .ops
= &lochnagar_micbias_ops
,
181 .id
= LOCHNAGAR_MIC2VDD
,
182 .of_match
= of_match_ptr("MIC2VDD"),
183 .of_parse_cb
= lochnagar_micbias_of_parse
,
185 .enable_reg
= LOCHNAGAR2_ANALOGUE_PATH_CTRL2
,
186 .enable_mask
= LOCHNAGAR2_P2_INPUT_BIAS_ENA_MASK
,
188 .owner
= THIS_MODULE
,
190 [LOCHNAGAR_VDDCORE
] = {
192 .supply_name
= "SYSVDD",
193 .type
= REGULATOR_VOLTAGE
,
195 .ops
= &lochnagar_vddcore_ops
,
197 .id
= LOCHNAGAR_VDDCORE
,
198 .of_match
= of_match_ptr("VDDCORE"),
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
,
205 .linear_ranges
= lochnagar_vddcore_ranges
,
206 .n_linear_ranges
= ARRAY_SIZE(lochnagar_vddcore_ranges
),
211 .owner
= THIS_MODULE
,
215 static int lochnagar_regulator_probe(struct platform_device
*pdev
)
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
;
223 config
.dev
= lochnagar
->dev
;
224 config
.regmap
= lochnagar
->regmap
;
225 config
.driver_data
= lochnagar
;
227 for (i
= 0; i
< ARRAY_SIZE(lochnagar_regulators
); i
++) {
228 const struct regulator_desc
*desc
= &lochnagar_regulators
[i
];
230 rdev
= devm_regulator_register(dev
, desc
, &config
);
233 dev_err(dev
, "Failed to register %s regulator: %d\n",
242 static struct platform_driver lochnagar_regulator_driver
= {
244 .name
= "lochnagar-regulator",
247 .probe
= lochnagar_regulator_probe
,
249 module_platform_driver(lochnagar_regulator_driver
);
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");