Commit | Line | Data |
---|---|---|
31e54086 PM |
1 | /* |
2 | * This program is free software; you can redistribute it and/or modify | |
3 | * it under the terms of the GNU General Public License version 2 as | |
4 | * published by the Free Software Foundation. | |
5 | * | |
6 | * This program is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
9 | * GNU General Public License for more details. | |
10 | * | |
11 | * Copyright (C) 2012 ARM Limited | |
12 | */ | |
13 | ||
14 | #define DRVNAME "vexpress-regulator" | |
15 | #define pr_fmt(fmt) DRVNAME ": " fmt | |
16 | ||
17 | #include <linux/device.h> | |
18 | #include <linux/err.h> | |
19 | #include <linux/module.h> | |
20 | #include <linux/of_device.h> | |
21 | #include <linux/regulator/driver.h> | |
22 | #include <linux/regulator/machine.h> | |
23 | #include <linux/regulator/of_regulator.h> | |
24 | #include <linux/vexpress.h> | |
25 | ||
26 | struct vexpress_regulator { | |
27 | struct regulator_desc desc; | |
28 | struct regulator_dev *regdev; | |
3b9334ac | 29 | struct regmap *regmap; |
31e54086 PM |
30 | }; |
31 | ||
32 | static int vexpress_regulator_get_voltage(struct regulator_dev *regdev) | |
33 | { | |
34 | struct vexpress_regulator *reg = rdev_get_drvdata(regdev); | |
35 | u32 uV; | |
3b9334ac | 36 | int err = regmap_read(reg->regmap, 0, &uV); |
31e54086 PM |
37 | |
38 | return err ? err : uV; | |
39 | } | |
40 | ||
41 | static int vexpress_regulator_set_voltage(struct regulator_dev *regdev, | |
42 | int min_uV, int max_uV, unsigned *selector) | |
43 | { | |
44 | struct vexpress_regulator *reg = rdev_get_drvdata(regdev); | |
45 | ||
3b9334ac | 46 | return regmap_write(reg->regmap, 0, min_uV); |
31e54086 PM |
47 | } |
48 | ||
49 | static struct regulator_ops vexpress_regulator_ops_ro = { | |
50 | .get_voltage = vexpress_regulator_get_voltage, | |
51 | }; | |
52 | ||
53 | static struct regulator_ops vexpress_regulator_ops = { | |
54 | .get_voltage = vexpress_regulator_get_voltage, | |
55 | .set_voltage = vexpress_regulator_set_voltage, | |
56 | }; | |
57 | ||
58 | static int vexpress_regulator_probe(struct platform_device *pdev) | |
59 | { | |
31e54086 PM |
60 | struct vexpress_regulator *reg; |
61 | struct regulator_init_data *init_data; | |
62 | struct regulator_config config = { }; | |
63 | ||
64 | reg = devm_kzalloc(&pdev->dev, sizeof(*reg), GFP_KERNEL); | |
3b9334ac PM |
65 | if (!reg) |
66 | return -ENOMEM; | |
31e54086 | 67 | |
3b9334ac PM |
68 | reg->regmap = devm_regmap_init_vexpress_config(&pdev->dev); |
69 | if (IS_ERR(reg->regmap)) | |
70 | return PTR_ERR(reg->regmap); | |
31e54086 PM |
71 | |
72 | reg->desc.name = dev_name(&pdev->dev); | |
73 | reg->desc.type = REGULATOR_VOLTAGE; | |
74 | reg->desc.owner = THIS_MODULE; | |
75 | reg->desc.continuous_voltage_range = true; | |
76 | ||
072e78b1 JMC |
77 | init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node, |
78 | ®->desc); | |
3b9334ac PM |
79 | if (!init_data) |
80 | return -EINVAL; | |
31e54086 PM |
81 | |
82 | init_data->constraints.apply_uV = 0; | |
83 | if (init_data->constraints.min_uV && init_data->constraints.max_uV) | |
84 | reg->desc.ops = &vexpress_regulator_ops; | |
85 | else | |
86 | reg->desc.ops = &vexpress_regulator_ops_ro; | |
87 | ||
88 | config.dev = &pdev->dev; | |
89 | config.init_data = init_data; | |
90 | config.driver_data = reg; | |
91 | config.of_node = pdev->dev.of_node; | |
92 | ||
abf92a3d | 93 | reg->regdev = devm_regulator_register(&pdev->dev, ®->desc, &config); |
3b9334ac PM |
94 | if (IS_ERR(reg->regdev)) |
95 | return PTR_ERR(reg->regdev); | |
31e54086 PM |
96 | |
97 | platform_set_drvdata(pdev, reg); | |
98 | ||
31e54086 PM |
99 | return 0; |
100 | } | |
101 | ||
1439afd8 | 102 | static const struct of_device_id vexpress_regulator_of_match[] = { |
31e54086 | 103 | { .compatible = "arm,vexpress-volt", }, |
9f4e45f7 | 104 | { } |
31e54086 PM |
105 | }; |
106 | ||
107 | static struct platform_driver vexpress_regulator_driver = { | |
108 | .probe = vexpress_regulator_probe, | |
31e54086 PM |
109 | .driver = { |
110 | .name = DRVNAME, | |
31e54086 PM |
111 | .of_match_table = vexpress_regulator_of_match, |
112 | }, | |
113 | }; | |
114 | ||
115 | module_platform_driver(vexpress_regulator_driver); | |
116 | ||
117 | MODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>"); | |
118 | MODULE_DESCRIPTION("Versatile Express regulator"); | |
119 | MODULE_LICENSE("GPL"); | |
120 | MODULE_ALIAS("platform:vexpress-regulator"); |