1/*
2 * Device driver for regulators in Hi655x IC
3 *
4 * Copyright (c) 2016 Hisilicon.
5 *
6 * Authors:
7 * Chen Feng <puck.chen@hisilicon.com>
8 * Fei Wang <w.f@huawei.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/bitops.h>
16#include <linux/device.h>
17#include <linux/err.h>
18#include <linux/module.h>
19#include <linux/io.h>
20#include <linux/of.h>
21#include <linux/platform_device.h>
22#include <linux/regmap.h>
23#include <linux/regulator/driver.h>
24#include <linux/regulator/machine.h>
25#include <linux/regulator/of_regulator.h>
26#include <linux/mfd/hi655x-pmic.h>
27
28struct hi655x_regulator {
29 unsigned int disable_reg;
30 unsigned int status_reg;
31 unsigned int ctrl_mask;
32 struct regulator_desc rdesc;
33};
34
35/* LDO7 & LDO10 */
36static const unsigned int ldo7_voltages[] = {
37 1800000, 1850000, 2850000, 2900000,
38 3000000, 3100000, 3200000, 3300000,
39};
40
41static const unsigned int ldo19_voltages[] = {
42 1800000, 1850000, 1900000, 1750000,
43 2800000, 2850000, 2900000, 3000000,
44};
45
46static const unsigned int ldo22_voltages[] = {
47 900000, 1000000, 1050000, 1100000,
48 1150000, 1175000, 1185000, 1200000,
49};
50
51enum hi655x_regulator_id {
52 HI655X_LDO0,
53 HI655X_LDO1,
54 HI655X_LDO2,
55 HI655X_LDO3,
56 HI655X_LDO4,
57 HI655X_LDO5,
58 HI655X_LDO6,
59 HI655X_LDO7,
60 HI655X_LDO8,
61 HI655X_LDO9,
62 HI655X_LDO10,
63 HI655X_LDO11,
64 HI655X_LDO12,
65 HI655X_LDO13,
66 HI655X_LDO14,
67 HI655X_LDO15,
68 HI655X_LDO16,
69 HI655X_LDO17,
70 HI655X_LDO18,
71 HI655X_LDO19,
72 HI655X_LDO20,
73 HI655X_LDO21,
74 HI655X_LDO22,
75};
76
77static int hi655x_is_enabled(struct regulator_dev *rdev)
78{
79 unsigned int value = 0;
80
81 struct hi655x_regulator *regulator = rdev_get_drvdata(rdev);
82
83 regmap_read(rdev->regmap, regulator->status_reg, &value);
84 return (value & BIT(regulator->ctrl_mask));
85}
86
87static int hi655x_disable(struct regulator_dev *rdev)
88{
89 int ret = 0;
90
91 struct hi655x_regulator *regulator = rdev_get_drvdata(rdev);
92
93 ret = regmap_write(rdev->regmap, regulator->disable_reg,
94 BIT(regulator->ctrl_mask));
95 return ret;
96}
97
98static const struct regulator_ops hi655x_regulator_ops = {
99 .enable = regulator_enable_regmap,
100 .disable = hi655x_disable,
101 .is_enabled = hi655x_is_enabled,
102 .list_voltage = regulator_list_voltage_table,
103 .get_voltage_sel = regulator_get_voltage_sel_regmap,
104 .set_voltage_sel = regulator_set_voltage_sel_regmap,
105};
106
107static const struct regulator_ops hi655x_ldo_linear_ops = {
108 .enable = regulator_enable_regmap,
109 .disable = hi655x_disable,
110 .is_enabled = hi655x_is_enabled,
111 .list_voltage = regulator_list_voltage_linear,
112 .get_voltage_sel = regulator_get_voltage_sel_regmap,
113 .set_voltage_sel = regulator_set_voltage_sel_regmap,
114};
115
116#define HI655X_LDO(_ID, vreg, vmask, ereg, dreg, \
117 sreg, cmask, vtable) { \
118 .rdesc = { \
119 .name = #_ID, \
120 .of_match = of_match_ptr(#_ID), \
121 .ops = &hi655x_regulator_ops, \
122 .regulators_node = of_match_ptr("regulators"), \
123 .type = REGULATOR_VOLTAGE, \
124 .id = HI655X_##_ID, \
125 .owner = THIS_MODULE, \
126 .n_voltages = ARRAY_SIZE(vtable), \
127 .volt_table = vtable, \
128 .vsel_reg = HI655X_BUS_ADDR(vreg), \
129 .vsel_mask = vmask, \
130 .enable_reg = HI655X_BUS_ADDR(ereg), \
131 .enable_mask = BIT(cmask), \
132 }, \
133 .disable_reg = HI655X_BUS_ADDR(dreg), \
134 .status_reg = HI655X_BUS_ADDR(sreg), \
135 .ctrl_mask = cmask, \
136}
137
138#define HI655X_LDO_LINEAR(_ID, vreg, vmask, ereg, dreg, \
139 sreg, cmask, minv, nvolt, vstep) { \
140 .rdesc = { \
141 .name = #_ID, \
142 .of_match = of_match_ptr(#_ID), \
143 .ops = &hi655x_ldo_linear_ops, \
144 .regulators_node = of_match_ptr("regulators"), \
145 .type = REGULATOR_VOLTAGE, \
146 .id = HI655X_##_ID, \
147 .owner = THIS_MODULE, \
148 .min_uV = minv, \
149 .n_voltages = nvolt, \
150 .uV_step = vstep, \
151 .vsel_reg = HI655X_BUS_ADDR(vreg), \
152 .vsel_mask = vmask, \
153 .enable_reg = HI655X_BUS_ADDR(ereg), \
154 .enable_mask = BIT(cmask), \
155 }, \
156 .disable_reg = HI655X_BUS_ADDR(dreg), \
157 .status_reg = HI655X_BUS_ADDR(sreg), \
158 .ctrl_mask = cmask, \
159}
160
161static struct hi655x_regulator regulators[] = {
162 HI655X_LDO_LINEAR(LDO2, 0x72, 0x07, 0x29, 0x2a, 0x2b, 0x01,
163 2500000, 8, 100000),
164 HI655X_LDO(LDO7, 0x78, 0x07, 0x29, 0x2a, 0x2b, 0x06, ldo7_voltages),
165 HI655X_LDO(LDO10, 0x78, 0x07, 0x29, 0x2a, 0x2b, 0x01, ldo7_voltages),
166 HI655X_LDO_LINEAR(LDO13, 0x7e, 0x07, 0x2c, 0x2d, 0x2e, 0x04,
167 1600000, 8, 50000),
168 HI655X_LDO_LINEAR(LDO14, 0x7f, 0x07, 0x2c, 0x2d, 0x2e, 0x05,
169 2500000, 8, 100000),
170 HI655X_LDO_LINEAR(LDO15, 0x80, 0x07, 0x2c, 0x2d, 0x2e, 0x06,
171 1600000, 8, 50000),
172 HI655X_LDO_LINEAR(LDO17, 0x82, 0x07, 0x2f, 0x30, 0x31, 0x00,
173 2500000, 8, 100000),
174 HI655X_LDO(LDO19, 0x84, 0x07, 0x2f, 0x30, 0x31, 0x02, ldo19_voltages),
175 HI655X_LDO_LINEAR(LDO21, 0x86, 0x07, 0x2f, 0x30, 0x31, 0x04,
176 1650000, 8, 50000),
177 HI655X_LDO(LDO22, 0x87, 0x07, 0x2f, 0x30, 0x31, 0x05, ldo22_voltages),
178};
179
180static int hi655x_regulator_probe(struct platform_device *pdev)
181{
182 unsigned int i;
183 struct hi655x_regulator *regulator;
184 struct hi655x_pmic *pmic;
185 struct regulator_config config = { };
186 struct regulator_dev *rdev;
187
188 pmic = dev_get_drvdata(pdev->dev.parent);
189 if (!pmic) {
190 dev_err(&pdev->dev, "no pmic in the regulator parent node\n");
191 return -ENODEV;
192 }
193
194 regulator = devm_kzalloc(&pdev->dev, sizeof(*regulator), GFP_KERNEL);
195 if (!regulator)
196 return -ENOMEM;
197
198 platform_set_drvdata(pdev, regulator);
199
200 config.dev = pdev->dev.parent;
201 config.regmap = pmic->regmap;
202 config.driver_data = regulator;
203 for (i = 0; i < ARRAY_SIZE(regulators); i++) {
204 rdev = devm_regulator_register(&pdev->dev,
205 &regulators[i].rdesc,
206 &config);
207 if (IS_ERR(rdev)) {
208 dev_err(&pdev->dev, "failed to register regulator %s\n",
209 regulator->rdesc.name);
210 return PTR_ERR(rdev);
211 }
212 }
213 return 0;
214}
215
216static const struct platform_device_id hi655x_regulator_table[] = {
217 { .name = "hi655x-regulator" },
218 {},
219};
220MODULE_DEVICE_TABLE(platform, hi655x_regulator_table);
221
222static struct platform_driver hi655x_regulator_driver = {
223 .id_table = hi655x_regulator_table,
224 .driver = {
225 .name = "hi655x-regulator",
226 },
227 .probe = hi655x_regulator_probe,
228};
229module_platform_driver(hi655x_regulator_driver);
230
231MODULE_AUTHOR("Chen Feng <puck.chen@hisilicon.com>");
232MODULE_DESCRIPTION("Hisilicon Hi655x regulator driver");
233MODULE_LICENSE("GPL v2");
234