Branch data Line data Source code
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;
29 : : struct vexpress_config_func *func;
30 : : };
31 : :
32 : 0 : static int vexpress_regulator_get_voltage(struct regulator_dev *regdev)
33 : : {
34 : 0 : struct vexpress_regulator *reg = rdev_get_drvdata(regdev);
35 : : u32 uV;
36 : 0 : int err = vexpress_config_read(reg->func, 0, &uV);
37 : :
38 [ # # ]: 0 : return err ? err : uV;
39 : : }
40 : :
41 : 0 : static int vexpress_regulator_set_voltage(struct regulator_dev *regdev,
42 : : int min_uV, int max_uV, unsigned *selector)
43 : : {
44 : 0 : struct vexpress_regulator *reg = rdev_get_drvdata(regdev);
45 : :
46 : 0 : return vexpress_config_write(reg->func, 0, min_uV);
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 : 0 : static int vexpress_regulator_probe(struct platform_device *pdev)
59 : : {
60 : : int err;
61 : : struct vexpress_regulator *reg;
62 : : struct regulator_init_data *init_data;
63 : 0 : struct regulator_config config = { };
64 : :
65 : 0 : reg = devm_kzalloc(&pdev->dev, sizeof(*reg), GFP_KERNEL);
66 [ # # ]: 0 : if (!reg) {
67 : : err = -ENOMEM;
68 : : goto error_kzalloc;
69 : : }
70 : :
71 : 0 : reg->func = vexpress_config_func_get_by_dev(&pdev->dev);
72 [ # # ]: 0 : if (!reg->func) {
73 : : err = -ENXIO;
74 : : goto error_get_func;
75 : : }
76 : :
77 : 0 : reg->desc.name = dev_name(&pdev->dev);
78 : 0 : reg->desc.type = REGULATOR_VOLTAGE;
79 : 0 : reg->desc.owner = THIS_MODULE;
80 : 0 : reg->desc.continuous_voltage_range = true;
81 : :
82 : 0 : init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node);
83 [ # # ]: 0 : if (!init_data) {
84 : : err = -EINVAL;
85 : : goto error_get_regulator_init_data;
86 : : }
87 : :
88 : 0 : init_data->constraints.apply_uV = 0;
89 [ # # ][ # # ]: 0 : if (init_data->constraints.min_uV && init_data->constraints.max_uV)
90 : 0 : reg->desc.ops = &vexpress_regulator_ops;
91 : : else
92 : 0 : reg->desc.ops = &vexpress_regulator_ops_ro;
93 : :
94 : 0 : config.dev = &pdev->dev;
95 : 0 : config.init_data = init_data;
96 : 0 : config.driver_data = reg;
97 : 0 : config.of_node = pdev->dev.of_node;
98 : :
99 : 0 : reg->regdev = devm_regulator_register(&pdev->dev, ®->desc, &config);
100 [ # # ]: 0 : if (IS_ERR(reg->regdev)) {
101 : : err = PTR_ERR(reg->regdev);
102 : 0 : goto error_regulator_register;
103 : : }
104 : :
105 : : platform_set_drvdata(pdev, reg);
106 : :
107 : 0 : return 0;
108 : :
109 : : error_regulator_register:
110 : : error_get_regulator_init_data:
111 : 0 : vexpress_config_func_put(reg->func);
112 : : error_get_func:
113 : : error_kzalloc:
114 : 0 : return err;
115 : : }
116 : :
117 : 0 : static int vexpress_regulator_remove(struct platform_device *pdev)
118 : : {
119 : : struct vexpress_regulator *reg = platform_get_drvdata(pdev);
120 : :
121 : 0 : vexpress_config_func_put(reg->func);
122 : :
123 : 0 : return 0;
124 : : }
125 : :
126 : : static struct of_device_id vexpress_regulator_of_match[] = {
127 : : { .compatible = "arm,vexpress-volt", },
128 : : { }
129 : : };
130 : :
131 : : static struct platform_driver vexpress_regulator_driver = {
132 : : .probe = vexpress_regulator_probe,
133 : : .remove = vexpress_regulator_remove,
134 : : .driver = {
135 : : .name = DRVNAME,
136 : : .owner = THIS_MODULE,
137 : : .of_match_table = vexpress_regulator_of_match,
138 : : },
139 : : };
140 : :
141 : 0 : module_platform_driver(vexpress_regulator_driver);
142 : :
143 : : MODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>");
144 : : MODULE_DESCRIPTION("Versatile Express regulator");
145 : : MODULE_LICENSE("GPL");
146 : : MODULE_ALIAS("platform:vexpress-regulator");
|