4690b3c6d450d4dab176d29bf700baa7e6328be9
[openwrt.git] / target / linux / mxs / patches-4.4 / 102-mxs-add-regulator-driver.patch
1 --- a/drivers/regulator/Kconfig
2 +++ b/drivers/regulator/Kconfig
3 @@ -450,6 +450,14 @@ config REGULATOR_MT6397
4           This driver supports the control of different power rails of device
5           through regulator interface.
6  
7 +config REGULATOR_MXS
8 +       tristate "Freescale MXS on-chip regulators"
9 +       depends on (MXS_POWER || COMPILE_TEST)
10 +       help
11 +         Say y here to support Freescale MXS on-chip regulators.
12 +         It is recommended that this option be enabled on i.MX23,
13 +         i.MX28 platform.
14 +
15  config REGULATOR_PALMAS
16         tristate "TI Palmas PMIC Regulators"
17         depends on MFD_PALMAS
18 --- a/drivers/regulator/Makefile
19 +++ b/drivers/regulator/Makefile
20 @@ -60,6 +60,7 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc137
21  obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
22  obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
23  obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
24 +obj-$(CONFIG_REGULATOR_MXS) += mxs-regulator.o
25  obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
26  obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
27  obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
28 --- /dev/null
29 +++ b/drivers/regulator/mxs-regulator.c
30 @@ -0,0 +1,540 @@
31 +/*
32 + * Freescale MXS on-chip regulators
33 + *
34 + * Embedded Alley Solutions, Inc <source@embeddedalley.com>
35 + *
36 + * Copyright (C) 2014 Stefan Wahren
37 + * Copyright (C) 2010 Freescale Semiconductor, Inc.
38 + * Copyright (C) 2008 Embedded Alley Solutions, Inc All Rights Reserved.
39 + *
40 + * Inspired by imx-bootlets
41 + */
42 +
43 +/*
44 + * The code contained herein is licensed under the GNU General Public
45 + * License. You may obtain a copy of the GNU General Public License
46 + * Version 2 or later at the following locations:
47 + *
48 + * http://www.opensource.org/licenses/gpl-license.html
49 + * http://www.gnu.org/copyleft/gpl.html
50 + */
51 +
52 +#include <linux/delay.h>
53 +#include <linux/device.h>
54 +#include <linux/err.h>
55 +#include <linux/kernel.h>
56 +#include <linux/mfd/syscon.h>
57 +#include <linux/module.h>
58 +#include <linux/of.h>
59 +#include <linux/of_device.h>
60 +#include <linux/platform_device.h>
61 +#include <linux/regmap.h>
62 +#include <linux/regulator/driver.h>
63 +#include <linux/regulator/machine.h>
64 +#include <linux/regulator/of_regulator.h>
65 +#include <linux/slab.h>
66 +
67 +/* Powered by linear regulator.  DCDC output is gated off and
68 +   the linreg output is equal to the target. */
69 +#define HW_POWER_LINREG_DCDC_OFF               1
70 +
71 +/* Powered by linear regulator.  DCDC output is not gated off
72 +   and is ready for the automatic hardware transistion after a 5V
73 +   event.  The converters are not enabled when 5V is present. LinReg output
74 +   is 25mV below target. */
75 +#define HW_POWER_LINREG_DCDC_READY             2
76 +
77 +/* Powered by DCDC converter and the LinReg is on. LinReg output
78 +   is 25mV below target. */
79 +#define HW_POWER_DCDC_LINREG_ON                        3
80 +
81 +/* Powered by DCDC converter and the LinReg is off. LinReg output
82 +   is 25mV below target. */
83 +#define HW_POWER_DCDC_LINREG_OFF               4
84 +
85 +/* Powered by DCDC converter and the LinReg is ready for the
86 +   automatic hardware transfer.  The LinReg output is not enabled and
87 +   depends on the 5V presence to enable the LinRegs.  LinReg offset is 25mV
88 +   below target. */
89 +#define HW_POWER_DCDC_LINREG_READY             5
90 +
91 +/* Powered by an external source when 5V is present.  This does not
92 +   necessarily mean the external source is powered by 5V,but the chip needs
93 +   to be aware that 5V is present. */
94 +#define HW_POWER_EXTERNAL_SOURCE_5V            6
95 +
96 +/* Powered by an external source when 5V is not present.This doesn't
97 +   necessarily mean the external source is powered by the battery, but the
98 +   chip needs to be aware that the battery is present */
99 +#define HW_POWER_EXTERNAL_SOURCE_BATTERY       7
100 +
101 +/* Unknown configuration.  This is an error. */
102 +#define HW_POWER_UNKNOWN_SOURCE                        8
103 +
104 +/* TODO: Move power register offsets into header file */
105 +#define HW_POWER_5VCTRL                0x00000010
106 +#define HW_POWER_VDDDCTRL      0x00000040
107 +#define HW_POWER_VDDACTRL      0x00000050
108 +#define HW_POWER_VDDIOCTRL     0x00000060
109 +#define HW_POWER_MISC          0x00000090
110 +#define HW_POWER_STS           0x000000c0
111 +
112 +#define BM_POWER_STS_VBUSVALID0_STATUS BIT(15)
113 +#define BM_POWER_STS_DC_OK             BIT(9)
114 +
115 +#define BM_POWER_5VCTRL_ILIMIT_EQ_ZERO BIT(2)
116 +#define BM_POWER_5VCTRL_ENABLE_DCDC    BIT(0)
117 +
118 +#define BM_POWER_LINREG_OFFSET_DCDC_MODE       BIT(1)
119 +
120 +#define SHIFT_FREQSEL                  4
121 +
122 +#define BM_POWER_MISC_FREQSEL          (7 << SHIFT_FREQSEL)
123 +
124 +/* Recommended DC-DC clock source values */
125 +#define HW_POWER_MISC_FREQSEL_20000_KHZ        1
126 +#define HW_POWER_MISC_FREQSEL_24000_KHZ        2
127 +#define HW_POWER_MISC_FREQSEL_19200_KHZ        3
128 +
129 +#define HW_POWER_MISC_SEL_PLLCLK       BIT(0)
130 +
131 +/* Regulator IDs */
132 +#define MXS_DCDC       1
133 +#define MXS_VDDIO      2
134 +#define MXS_VDDA       3
135 +#define MXS_VDDD       4
136 +
137 +struct mxs_reg_info {
138 +       /* regulator descriptor */
139 +       struct regulator_desc desc;
140 +
141 +       /* regulator control register */
142 +       int ctrl_reg;
143 +
144 +       /* disable DC-DC output */
145 +       unsigned int disable_fet_mask;
146 +
147 +       /* steps between linreg output and DC-DC target */
148 +       unsigned int linreg_offset_mask;
149 +       u8 linreg_offset_shift;
150 +
151 +       /* function which determine power source */
152 +       u8 (*get_power_source)(struct regulator_dev *);
153 +};
154 +
155 +static inline u8 get_linreg_offset(struct mxs_reg_info *ldo, u32 regs)
156 +{
157 +       return (regs & ldo->linreg_offset_mask) >> ldo->linreg_offset_shift;
158 +}
159 +
160 +static u8 get_vddio_power_source(struct regulator_dev *reg)
161 +{
162 +       struct mxs_reg_info *ldo = rdev_get_drvdata(reg);
163 +       u32 v5ctrl, status, base;
164 +       u8 offset;
165 +
166 +       if (regmap_read(reg->regmap, HW_POWER_5VCTRL, &v5ctrl))
167 +               return HW_POWER_UNKNOWN_SOURCE;
168 +
169 +       if (regmap_read(reg->regmap, HW_POWER_STS, &status))
170 +               return HW_POWER_UNKNOWN_SOURCE;
171 +
172 +       if (regmap_read(reg->regmap, ldo->ctrl_reg, &base))
173 +               return HW_POWER_UNKNOWN_SOURCE;
174 +
175 +       offset = get_linreg_offset(ldo, base);
176 +
177 +       /* If VBUS valid then 5 V power supply present */
178 +       if (status & BM_POWER_STS_VBUSVALID0_STATUS) {
179 +               /* Powered by Linreg, DC-DC is off */
180 +               if ((base & ldo->disable_fet_mask) &&
181 +                   !(offset & BM_POWER_LINREG_OFFSET_DCDC_MODE)) {
182 +                       return HW_POWER_LINREG_DCDC_OFF;
183 +               }
184 +
185 +               if (v5ctrl & BM_POWER_5VCTRL_ENABLE_DCDC) {
186 +                       /* Powered by DC-DC, Linreg is on */
187 +                       if (offset & BM_POWER_LINREG_OFFSET_DCDC_MODE)
188 +                               return HW_POWER_DCDC_LINREG_ON;
189 +               } else {
190 +                       /* Powered by Linreg, DC-DC is off */
191 +                       if (!(offset & BM_POWER_LINREG_OFFSET_DCDC_MODE))
192 +                               return HW_POWER_LINREG_DCDC_OFF;
193 +               }
194 +       } else {
195 +               /* Powered by DC-DC, Linreg is on */
196 +               if (offset & BM_POWER_LINREG_OFFSET_DCDC_MODE)
197 +                       return HW_POWER_DCDC_LINREG_ON;
198 +       }
199 +
200 +       return HW_POWER_UNKNOWN_SOURCE;
201 +}
202 +
203 +static u8 get_vdda_vddd_power_source(struct regulator_dev *reg)
204 +{
205 +       struct mxs_reg_info *ldo = rdev_get_drvdata(reg);
206 +       struct regulator_desc *desc = &ldo->desc;
207 +       u32 v5ctrl, status, base;
208 +       u8 offset;
209 +
210 +       if (regmap_read(reg->regmap, HW_POWER_5VCTRL, &v5ctrl))
211 +               return HW_POWER_UNKNOWN_SOURCE;
212 +
213 +       if (regmap_read(reg->regmap, HW_POWER_STS, &status))
214 +               return HW_POWER_UNKNOWN_SOURCE;
215 +
216 +       if (regmap_read(reg->regmap, ldo->ctrl_reg, &base))
217 +               return HW_POWER_UNKNOWN_SOURCE;
218 +
219 +       offset = get_linreg_offset(ldo, base);
220 +
221 +       /* DC-DC output is disabled */
222 +       if (base & ldo->disable_fet_mask) {
223 +               /* Powered by 5 V supply */
224 +               if (status & BM_POWER_STS_VBUSVALID0_STATUS)
225 +                       return HW_POWER_EXTERNAL_SOURCE_5V;
226 +
227 +               /* Powered by Linreg, DC-DC is off */
228 +               if (!(offset & BM_POWER_LINREG_OFFSET_DCDC_MODE))
229 +                       return HW_POWER_LINREG_DCDC_OFF;
230 +       }
231 +
232 +       /* If VBUS valid then 5 V power supply present */
233 +       if (status & BM_POWER_STS_VBUSVALID0_STATUS) {
234 +               /* Powered by DC-DC, Linreg is on */
235 +               if (v5ctrl & BM_POWER_5VCTRL_ENABLE_DCDC)
236 +                       return HW_POWER_DCDC_LINREG_ON;
237 +
238 +               /* Powered by Linreg, DC-DC is off */
239 +               return HW_POWER_LINREG_DCDC_OFF;
240 +       }
241 +
242 +       /* DC-DC is on */
243 +       if (offset & BM_POWER_LINREG_OFFSET_DCDC_MODE) {
244 +               /* Powered by DC-DC, Linreg is on */
245 +               if (base & desc->enable_mask)
246 +                       return HW_POWER_DCDC_LINREG_ON;
247 +
248 +               /* Powered by DC-DC, Linreg is off */
249 +               return HW_POWER_DCDC_LINREG_OFF;
250 +       }
251 +
252 +       return HW_POWER_UNKNOWN_SOURCE;
253 +}
254 +
255 +static int mxs_set_dcdc_freq(struct regulator_dev *reg, u32 hz)
256 +{
257 +       struct mxs_reg_info *dcdc = rdev_get_drvdata(reg);
258 +       u32 val;
259 +       int ret;
260 +
261 +       if (dcdc->desc.id != MXS_DCDC) {
262 +               dev_warn(&reg->dev, "Setting switching freq is not supported\n");
263 +               return -EINVAL;
264 +       }
265 +
266 +       ret = regmap_read(reg->regmap, HW_POWER_MISC, &val);
267 +       if (ret)
268 +               return ret;
269 +
270 +       val &= ~BM_POWER_MISC_FREQSEL;
271 +       val &= ~HW_POWER_MISC_SEL_PLLCLK;
272 +
273 +       /*
274 +        * Select the PLL/PFD based frequency that the DC-DC converter uses.
275 +        * The actual switching frequency driving the power inductor is
276 +        * DCDC_CLK/16. Accept only values recommend by Freescale.
277 +        */
278 +       switch (hz) {
279 +       case 1200000:
280 +               val |= HW_POWER_MISC_FREQSEL_19200_KHZ << SHIFT_FREQSEL;
281 +               break;
282 +       case 1250000:
283 +               val |= HW_POWER_MISC_FREQSEL_20000_KHZ << SHIFT_FREQSEL;
284 +               break;
285 +       case 1500000:
286 +               val |= HW_POWER_MISC_FREQSEL_24000_KHZ << SHIFT_FREQSEL;
287 +               break;
288 +       default:
289 +               dev_warn(&reg->dev, "Switching freq: %u Hz not supported\n",
290 +                        hz);
291 +               return -EINVAL;
292 +       }
293 +
294 +       /* First program FREQSEL */
295 +       ret = regmap_write(reg->regmap, HW_POWER_MISC, val);
296 +       if (ret)
297 +               return ret;
298 +
299 +       /* then set PLL as clock for DC-DC converter */
300 +       val |= HW_POWER_MISC_SEL_PLLCLK;
301 +
302 +       return regmap_write(reg->regmap, HW_POWER_MISC, val);
303 +}
304 +
305 +static int mxs_ldo_set_voltage_sel(struct regulator_dev *reg, unsigned sel)
306 +{
307 +       struct mxs_reg_info *ldo = rdev_get_drvdata(reg);
308 +       struct regulator_desc *desc = &ldo->desc;
309 +       u32 status = 0;
310 +       int timeout;
311 +       int ret;
312 +
313 +       ret = regmap_update_bits(reg->regmap, desc->vsel_reg, desc->vsel_mask,
314 +                                sel);
315 +       if (ret)
316 +               return ret;
317 +
318 +       if (ldo->get_power_source) {
319 +               switch (ldo->get_power_source(reg)) {
320 +               case HW_POWER_LINREG_DCDC_OFF:
321 +               case HW_POWER_LINREG_DCDC_READY:
322 +               case HW_POWER_EXTERNAL_SOURCE_5V:
323 +                       /*
324 +                        * Since the DC-DC converter is off we can't
325 +                        * trigger on DC_OK. So wait at least 1 ms
326 +                        * for stabilization.
327 +                        */
328 +                       usleep_range(1000, 2000);
329 +                       return 0;
330 +               }
331 +       }
332 +
333 +       /* Make sure DC_OK has changed */
334 +       usleep_range(15, 20);
335 +
336 +       for (timeout = 0; timeout < 20; timeout++) {
337 +               ret = regmap_read(reg->regmap, HW_POWER_STS, &status);
338 +
339 +               if (ret)
340 +                       break;
341 +
342 +               /* DC-DC converter control loop has stabilized */
343 +               if (status & BM_POWER_STS_DC_OK)
344 +                       return 0;
345 +
346 +               udelay(1);
347 +       }
348 +
349 +       if (!ret)
350 +               dev_warn_ratelimited(&reg->dev, "%s: timeout status=0x%08x\n",
351 +                                    __func__, status);
352 +
353 +       msleep(20);
354 +
355 +       return -ETIMEDOUT;
356 +}
357 +
358 +static int mxs_ldo_is_enabled(struct regulator_dev *reg)
359 +{
360 +       struct mxs_reg_info *ldo = rdev_get_drvdata(reg);
361 +
362 +       if (ldo->get_power_source) {
363 +               switch (ldo->get_power_source(reg)) {
364 +               case HW_POWER_LINREG_DCDC_OFF:
365 +               case HW_POWER_LINREG_DCDC_READY:
366 +               case HW_POWER_DCDC_LINREG_ON:
367 +                       return 1;
368 +               }
369 +       }
370 +
371 +       return 0;
372 +}
373 +
374 +static struct regulator_ops mxs_dcdc_ops = {
375 +       .is_enabled             = regulator_is_enabled_regmap,
376 +};
377 +
378 +static struct regulator_ops mxs_ldo_ops = {
379 +       .list_voltage           = regulator_list_voltage_linear,
380 +       .map_voltage            = regulator_map_voltage_linear,
381 +       .set_voltage_sel        = mxs_ldo_set_voltage_sel,
382 +       .get_voltage_sel        = regulator_get_voltage_sel_regmap,
383 +       .is_enabled             = mxs_ldo_is_enabled,
384 +};
385 +
386 +static const struct mxs_reg_info mxs_info_dcdc = {
387 +       .desc = {
388 +               .name = "dcdc",
389 +               .id = MXS_DCDC,
390 +               .type = REGULATOR_VOLTAGE,
391 +               .owner = THIS_MODULE,
392 +               .ops = &mxs_dcdc_ops,
393 +               .enable_reg = HW_POWER_STS,
394 +               .enable_mask = (1 << 0),
395 +       },
396 +};
397 +
398 +static const struct mxs_reg_info imx23_info_vddio = {
399 +       .desc = {
400 +               .name = "vddio",
401 +               .id = MXS_VDDIO,
402 +               .type = REGULATOR_VOLTAGE,
403 +               .owner = THIS_MODULE,
404 +               .n_voltages = 0x20,
405 +               .uV_step = 25000,
406 +               .linear_min_sel = 0,
407 +               .min_uV = 2800000,
408 +               .vsel_reg = HW_POWER_VDDIOCTRL,
409 +               .vsel_mask = 0x1f,
410 +               .ops = &mxs_ldo_ops,
411 +       },
412 +       .ctrl_reg = HW_POWER_VDDIOCTRL,
413 +       .disable_fet_mask = 1 << 16,
414 +       .linreg_offset_mask = 3 << 12,
415 +       .linreg_offset_shift = 12,
416 +       .get_power_source = get_vddio_power_source,
417 +};
418 +
419 +static const struct mxs_reg_info imx28_info_vddio = {
420 +       .desc = {
421 +               .name = "vddio",
422 +               .id = MXS_VDDIO,
423 +               .type = REGULATOR_VOLTAGE,
424 +               .owner = THIS_MODULE,
425 +               .n_voltages = 0x11,
426 +               .uV_step = 50000,
427 +               .linear_min_sel = 0,
428 +               .min_uV = 2800000,
429 +               .vsel_reg = HW_POWER_VDDIOCTRL,
430 +               .vsel_mask = 0x1f,
431 +               .ops = &mxs_ldo_ops,
432 +       },
433 +       .ctrl_reg = HW_POWER_VDDIOCTRL,
434 +       .disable_fet_mask = 1 << 16,
435 +       .linreg_offset_mask = 3 << 12,
436 +       .linreg_offset_shift = 12,
437 +       .get_power_source = get_vddio_power_source,
438 +};
439 +
440 +static const struct mxs_reg_info mxs_info_vdda = {
441 +       .desc = {
442 +               .name = "vdda",
443 +               .id = MXS_VDDA,
444 +               .type = REGULATOR_VOLTAGE,
445 +               .owner = THIS_MODULE,
446 +               .n_voltages = 0x20,
447 +               .uV_step = 25000,
448 +               .linear_min_sel = 0,
449 +               .min_uV = 1500000,
450 +               .vsel_reg = HW_POWER_VDDACTRL,
451 +               .vsel_mask = 0x1f,
452 +               .ops = &mxs_ldo_ops,
453 +               .enable_mask = (1 << 17),
454 +       },
455 +       .ctrl_reg = HW_POWER_VDDACTRL,
456 +       .disable_fet_mask = 1 << 16,
457 +       .linreg_offset_mask = 3 << 12,
458 +       .linreg_offset_shift = 12,
459 +       .get_power_source = get_vdda_vddd_power_source,
460 +};
461 +
462 +static const struct mxs_reg_info mxs_info_vddd = {
463 +       .desc = {
464 +               .name = "vddd",
465 +               .id = MXS_VDDD,
466 +               .type = REGULATOR_VOLTAGE,
467 +               .owner = THIS_MODULE,
468 +               .n_voltages = 0x20,
469 +               .uV_step = 25000,
470 +               .linear_min_sel = 0,
471 +               .min_uV = 800000,
472 +               .vsel_reg = HW_POWER_VDDDCTRL,
473 +               .vsel_mask = 0x1f,
474 +               .ops = &mxs_ldo_ops,
475 +               .enable_mask = (1 << 21),
476 +       },
477 +       .ctrl_reg = HW_POWER_VDDDCTRL,
478 +       .disable_fet_mask = 1 << 20,
479 +       .linreg_offset_mask = 3 << 16,
480 +       .linreg_offset_shift = 16,
481 +       .get_power_source = get_vdda_vddd_power_source,
482 +};
483 +
484 +static const struct of_device_id of_mxs_regulator_match[] = {
485 +       { .compatible = "fsl,imx23-dcdc",  .data = &mxs_info_dcdc },
486 +       { .compatible = "fsl,imx28-dcdc",  .data = &mxs_info_dcdc },
487 +       { .compatible = "fsl,imx23-vddio", .data = &imx23_info_vddio },
488 +       { .compatible = "fsl,imx23-vdda",  .data = &mxs_info_vdda },
489 +       { .compatible = "fsl,imx23-vddd",  .data = &mxs_info_vddd },
490 +       { .compatible = "fsl,imx28-vddio", .data = &imx28_info_vddio },
491 +       { .compatible = "fsl,imx28-vdda",  .data = &mxs_info_vdda },
492 +       { .compatible = "fsl,imx28-vddd",  .data = &mxs_info_vddd },
493 +       { /* end */ }
494 +};
495 +MODULE_DEVICE_TABLE(of, of_mxs_regulator_match);
496 +
497 +static int mxs_regulator_probe(struct platform_device *pdev)
498 +{
499 +       struct device *dev = &pdev->dev;
500 +       const struct of_device_id *match;
501 +       struct device_node *parent_np;
502 +       struct regulator_dev *rdev = NULL;
503 +       struct mxs_reg_info *info;
504 +       struct regulator_init_data *initdata;
505 +       struct regulator_config config = { };
506 +       u32 switch_freq;
507 +
508 +       match = of_match_device(of_mxs_regulator_match, dev);
509 +       if (!match) {
510 +               /* We do not expect this to happen */
511 +               dev_err(dev, "%s: Unable to match device\n", __func__);
512 +               return -ENODEV;
513 +       }
514 +
515 +       info = devm_kmemdup(dev, match->data, sizeof(struct mxs_reg_info),
516 +                           GFP_KERNEL);
517 +       if (!info)
518 +               return -ENOMEM;
519 +
520 +       initdata = of_get_regulator_init_data(dev, dev->of_node, &info->desc);
521 +       if (!initdata) {
522 +               dev_err(dev, "missing regulator init data\n");
523 +               return -EINVAL;
524 +       }
525 +
526 +       parent_np = of_get_parent(dev->of_node);
527 +       if (!parent_np)
528 +               return -ENODEV;
529 +       config.regmap = syscon_node_to_regmap(parent_np);
530 +       of_node_put(parent_np);
531 +       if (IS_ERR(config.regmap))
532 +               return PTR_ERR(config.regmap);
533 +
534 +       config.dev = dev;
535 +       config.init_data = initdata;
536 +       config.driver_data = info;
537 +       config.of_node = dev->of_node;
538 +
539 +       rdev = devm_regulator_register(dev, &info->desc, &config);
540 +       if (IS_ERR(rdev)) {
541 +               int ret = PTR_ERR(rdev);
542 +
543 +               dev_err(dev, "%s: failed to register regulator(%d)\n",
544 +                       __func__, ret);
545 +               return ret;
546 +       }
547 +
548 +       if (!of_property_read_u32(dev->of_node, "switching-frequency",
549 +                                 &switch_freq))
550 +               mxs_set_dcdc_freq(rdev, switch_freq);
551 +
552 +       platform_set_drvdata(pdev, rdev);
553 +
554 +       return 0;
555 +}
556 +
557 +static struct platform_driver mxs_regulator_driver = {
558 +       .driver = {
559 +               .name   = "mxs_regulator",
560 +               .of_match_table = of_mxs_regulator_match,
561 +       },
562 +       .probe  = mxs_regulator_probe,
563 +};
564 +
565 +module_platform_driver(mxs_regulator_driver);
566 +
567 +MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>");
568 +MODULE_DESCRIPTION("Freescale MXS regulators");
569 +MODULE_LICENSE("GPL v2");
570 +MODULE_ALIAS("platform:mxs_regulator");