]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/regulator/arizona-micsupp.c
regulator: arizona-micsupp: Move pdata into a separate structure
[linux.git] / drivers / regulator / arizona-micsupp.c
1 /*
2  * arizona-micsupp.c  --  Microphone supply for Arizona devices
3  *
4  * Copyright 2012 Wolfson Microelectronics PLC.
5  *
6  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7  *
8  *  This program is free software; you can redistribute  it and/or modify it
9  *  under  the terms of  the GNU General  Public License as published by the
10  *  Free Software Foundation;  either version 2 of the  License, or (at your
11  *  option) any later version.
12  */
13
14 #include <linux/module.h>
15 #include <linux/moduleparam.h>
16 #include <linux/init.h>
17 #include <linux/bitops.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 #include <linux/gpio.h>
25 #include <linux/slab.h>
26 #include <linux/workqueue.h>
27 #include <sound/soc.h>
28
29 #include <linux/mfd/arizona/core.h>
30 #include <linux/mfd/arizona/pdata.h>
31 #include <linux/mfd/arizona/registers.h>
32
33 #include <linux/regulator/arizona-micsupp.h>
34
35 struct arizona_micsupp {
36         struct regulator_dev *regulator;
37         struct arizona *arizona;
38
39         struct regulator_consumer_supply supply;
40         struct regulator_init_data init_data;
41
42         struct work_struct check_cp_work;
43 };
44
45 static void arizona_micsupp_check_cp(struct work_struct *work)
46 {
47         struct arizona_micsupp *micsupp =
48                 container_of(work, struct arizona_micsupp, check_cp_work);
49         struct snd_soc_dapm_context *dapm = micsupp->arizona->dapm;
50         struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
51         struct arizona *arizona = micsupp->arizona;
52         struct regmap *regmap = arizona->regmap;
53         unsigned int reg;
54         int ret;
55
56         ret = regmap_read(regmap, ARIZONA_MIC_CHARGE_PUMP_1, &reg);
57         if (ret != 0) {
58                 dev_err(arizona->dev, "Failed to read CP state: %d\n", ret);
59                 return;
60         }
61
62         if (dapm) {
63                 if ((reg & (ARIZONA_CPMIC_ENA | ARIZONA_CPMIC_BYPASS)) ==
64                     ARIZONA_CPMIC_ENA)
65                         snd_soc_component_force_enable_pin(component,
66                                                            "MICSUPP");
67                 else
68                         snd_soc_component_disable_pin(component, "MICSUPP");
69
70                 snd_soc_dapm_sync(dapm);
71         }
72 }
73
74 static int arizona_micsupp_enable(struct regulator_dev *rdev)
75 {
76         struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
77         int ret;
78
79         ret = regulator_enable_regmap(rdev);
80
81         if (ret == 0)
82                 schedule_work(&micsupp->check_cp_work);
83
84         return ret;
85 }
86
87 static int arizona_micsupp_disable(struct regulator_dev *rdev)
88 {
89         struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
90         int ret;
91
92         ret = regulator_disable_regmap(rdev);
93         if (ret == 0)
94                 schedule_work(&micsupp->check_cp_work);
95
96         return ret;
97 }
98
99 static int arizona_micsupp_set_bypass(struct regulator_dev *rdev, bool ena)
100 {
101         struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
102         int ret;
103
104         ret = regulator_set_bypass_regmap(rdev, ena);
105         if (ret == 0)
106                 schedule_work(&micsupp->check_cp_work);
107
108         return ret;
109 }
110
111 static const struct regulator_ops arizona_micsupp_ops = {
112         .enable = arizona_micsupp_enable,
113         .disable = arizona_micsupp_disable,
114         .is_enabled = regulator_is_enabled_regmap,
115
116         .list_voltage = regulator_list_voltage_linear_range,
117         .map_voltage = regulator_map_voltage_linear_range,
118
119         .get_voltage_sel = regulator_get_voltage_sel_regmap,
120         .set_voltage_sel = regulator_set_voltage_sel_regmap,
121
122         .get_bypass = regulator_get_bypass_regmap,
123         .set_bypass = arizona_micsupp_set_bypass,
124 };
125
126 static const struct regulator_linear_range arizona_micsupp_ranges[] = {
127         REGULATOR_LINEAR_RANGE(1700000, 0,    0x1e, 50000),
128         REGULATOR_LINEAR_RANGE(3300000, 0x1f, 0x1f, 0),
129 };
130
131 static const struct regulator_desc arizona_micsupp = {
132         .name = "MICVDD",
133         .supply_name = "CPVDD",
134         .type = REGULATOR_VOLTAGE,
135         .n_voltages = 32,
136         .ops = &arizona_micsupp_ops,
137
138         .vsel_reg = ARIZONA_LDO2_CONTROL_1,
139         .vsel_mask = ARIZONA_LDO2_VSEL_MASK,
140         .enable_reg = ARIZONA_MIC_CHARGE_PUMP_1,
141         .enable_mask = ARIZONA_CPMIC_ENA,
142         .bypass_reg = ARIZONA_MIC_CHARGE_PUMP_1,
143         .bypass_mask = ARIZONA_CPMIC_BYPASS,
144
145         .linear_ranges = arizona_micsupp_ranges,
146         .n_linear_ranges = ARRAY_SIZE(arizona_micsupp_ranges),
147
148         .enable_time = 3000,
149
150         .owner = THIS_MODULE,
151 };
152
153 static const struct regulator_linear_range arizona_micsupp_ext_ranges[] = {
154         REGULATOR_LINEAR_RANGE(900000,  0,    0x14, 25000),
155         REGULATOR_LINEAR_RANGE(1500000, 0x15, 0x27, 100000),
156 };
157
158 static const struct regulator_desc arizona_micsupp_ext = {
159         .name = "MICVDD",
160         .supply_name = "CPVDD",
161         .type = REGULATOR_VOLTAGE,
162         .n_voltages = 40,
163         .ops = &arizona_micsupp_ops,
164
165         .vsel_reg = ARIZONA_LDO2_CONTROL_1,
166         .vsel_mask = ARIZONA_LDO2_VSEL_MASK,
167         .enable_reg = ARIZONA_MIC_CHARGE_PUMP_1,
168         .enable_mask = ARIZONA_CPMIC_ENA,
169         .bypass_reg = ARIZONA_MIC_CHARGE_PUMP_1,
170         .bypass_mask = ARIZONA_CPMIC_BYPASS,
171
172         .linear_ranges = arizona_micsupp_ext_ranges,
173         .n_linear_ranges = ARRAY_SIZE(arizona_micsupp_ext_ranges),
174
175         .enable_time = 3000,
176
177         .owner = THIS_MODULE,
178 };
179
180 static const struct regulator_init_data arizona_micsupp_default = {
181         .constraints = {
182                 .valid_ops_mask = REGULATOR_CHANGE_STATUS |
183                                 REGULATOR_CHANGE_VOLTAGE |
184                                 REGULATOR_CHANGE_BYPASS,
185                 .min_uV = 1700000,
186                 .max_uV = 3300000,
187         },
188
189         .num_consumer_supplies = 1,
190 };
191
192 static const struct regulator_init_data arizona_micsupp_ext_default = {
193         .constraints = {
194                 .valid_ops_mask = REGULATOR_CHANGE_STATUS |
195                                 REGULATOR_CHANGE_VOLTAGE |
196                                 REGULATOR_CHANGE_BYPASS,
197                 .min_uV = 900000,
198                 .max_uV = 3300000,
199         },
200
201         .num_consumer_supplies = 1,
202 };
203
204 static int arizona_micsupp_of_get_pdata(struct arizona_micsupp_pdata *pdata,
205                                         struct regulator_config *config,
206                                         const struct regulator_desc *desc)
207 {
208         struct arizona_micsupp *micsupp = config->driver_data;
209         struct device_node *np;
210         struct regulator_init_data *init_data;
211
212         np = of_get_child_by_name(config->dev->of_node, "micvdd");
213
214         if (np) {
215                 config->of_node = np;
216
217                 init_data = of_get_regulator_init_data(config->dev, np, desc);
218
219                 if (init_data) {
220                         init_data->consumer_supplies = &micsupp->supply;
221                         init_data->num_consumer_supplies = 1;
222
223                         pdata->init_data = init_data;
224                 }
225         }
226
227         return 0;
228 }
229
230 static int arizona_micsupp_probe(struct platform_device *pdev)
231 {
232         struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
233         const struct regulator_desc *desc;
234         struct regulator_config config = { };
235         struct arizona_micsupp_pdata *pdata = &arizona->pdata.micvdd;
236         struct arizona_micsupp *micsupp;
237         int ret;
238
239         micsupp = devm_kzalloc(&pdev->dev, sizeof(*micsupp), GFP_KERNEL);
240         if (!micsupp)
241                 return -ENOMEM;
242
243         micsupp->arizona = arizona;
244         INIT_WORK(&micsupp->check_cp_work, arizona_micsupp_check_cp);
245
246         /*
247          * Since the chip usually supplies itself we provide some
248          * default init_data for it.  This will be overridden with
249          * platform data if provided.
250          */
251         switch (arizona->type) {
252         case WM5110:
253         case WM8280:
254                 desc = &arizona_micsupp_ext;
255                 micsupp->init_data = arizona_micsupp_ext_default;
256                 break;
257         default:
258                 desc = &arizona_micsupp;
259                 micsupp->init_data = arizona_micsupp_default;
260                 break;
261         }
262
263         micsupp->init_data.consumer_supplies = &micsupp->supply;
264         micsupp->supply.supply = "MICVDD";
265         micsupp->supply.dev_name = dev_name(arizona->dev);
266
267         config.dev = arizona->dev;
268         config.driver_data = micsupp;
269         config.regmap = arizona->regmap;
270
271         if (IS_ENABLED(CONFIG_OF)) {
272                 if (!dev_get_platdata(arizona->dev)) {
273                         ret = arizona_micsupp_of_get_pdata(pdata, &config,
274                                                            desc);
275                         if (ret < 0)
276                                 return ret;
277                 }
278         }
279
280         if (pdata->init_data)
281                 config.init_data = pdata->init_data;
282         else
283                 config.init_data = &micsupp->init_data;
284
285         /* Default to regulated mode until the API supports bypass */
286         regmap_update_bits(arizona->regmap, ARIZONA_MIC_CHARGE_PUMP_1,
287                            ARIZONA_CPMIC_BYPASS, 0);
288
289         micsupp->regulator = devm_regulator_register(&pdev->dev,
290                                                      desc,
291                                                      &config);
292
293         of_node_put(config.of_node);
294
295         if (IS_ERR(micsupp->regulator)) {
296                 ret = PTR_ERR(micsupp->regulator);
297                 dev_err(arizona->dev, "Failed to register mic supply: %d\n",
298                         ret);
299                 return ret;
300         }
301
302         platform_set_drvdata(pdev, micsupp);
303
304         return 0;
305 }
306
307 static struct platform_driver arizona_micsupp_driver = {
308         .probe = arizona_micsupp_probe,
309         .driver         = {
310                 .name   = "arizona-micsupp",
311         },
312 };
313
314 module_platform_driver(arizona_micsupp_driver);
315
316 /* Module information */
317 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
318 MODULE_DESCRIPTION("Arizona microphone supply driver");
319 MODULE_LICENSE("GPL");
320 MODULE_ALIAS("platform:arizona-micsupp");