power: add power subsystem driver in uboot
[platform/kernel/u-boot.git] / drivers / power / regulator / starfive_regulator.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2023 Starfive, Inc.
4  * Author:      keith.zhao<keith.zhao@statfivetech.com>
5  */
6
7
8 #include <common.h>
9 #include <fdtdec.h>
10 #include <errno.h>
11 #include <dm.h>
12 #include <i2c.h>
13 #include <power/pmic.h>
14 #include <power/regulator.h>
15 #include <power/lp873x.h>
16
17 static const char lp873x_ldo_ctrl[LP873X_LDO_NUM] = {0x8, 0x9};
18 static const char lp873x_ldo_volt[LP873X_LDO_NUM] = {0xA, 0xB};
19
20
21 static int lp873x_ldo_enable(struct udevice *dev, int op, bool *enable)
22 {
23         int ret;
24         unsigned int adr;
25         struct dm_regulator_uclass_plat *uc_pdata;
26
27         uc_pdata = dev_get_uclass_plat(dev);
28         adr = uc_pdata->ctrl_reg;
29
30         ret = pmic_reg_read(dev->parent, adr);
31         if (ret < 0)
32                 return ret;
33
34         if (op == PMIC_OP_GET) {
35                 ret &= LP873X_LDO_MODE_MASK;
36
37                 if (ret)
38                         *enable = true;
39                 else
40                         *enable = false;
41
42                 return 0;
43         } else if (op == PMIC_OP_SET) {
44                 if (*enable)
45                         ret |= LP873X_LDO_MODE_MASK;
46                 else
47                         ret &= ~(LP873X_LDO_MODE_MASK);
48
49                 ret = pmic_reg_write(dev->parent, adr, ret);
50                 if (ret)
51                         return ret;
52         }
53
54         return 0;
55 }
56
57 static int lp873x_ldo_volt2hex(int uV)
58 {
59         if (uV > LP873X_LDO_VOLT_MAX)
60                 return -EINVAL;
61
62         return (uV - 800000) / 100000;
63 }
64
65 static int lp873x_ldo_hex2volt(int hex)
66 {
67         if (hex > LP873X_LDO_VOLT_MAX_HEX)
68                 return -EINVAL;
69
70         if (!hex)
71                 return 0;
72
73         return (hex * 100000) + 800000;
74 }
75
76 static int lp873x_ldo_val(struct udevice *dev, int op, int *uV)
77 {
78         unsigned int hex, adr;
79         int ret;
80
81         struct dm_regulator_uclass_plat *uc_pdata;
82
83         if (op == PMIC_OP_GET)
84                 *uV = 0;
85
86         uc_pdata = dev_get_uclass_plat(dev);
87
88         adr = uc_pdata->volt_reg;
89
90         ret = pmic_reg_read(dev->parent, adr);
91         if (ret < 0)
92                 return ret;
93
94         if (op == PMIC_OP_GET) {
95                 ret &= LP873X_LDO_VOLT_MASK;
96                 ret = lp873x_ldo_hex2volt(ret);
97                 if (ret < 0)
98                         return ret;
99                 *uV = ret;
100                 return 0;
101         }
102
103         hex = lp873x_ldo_volt2hex(*uV);
104         if (hex < 0)
105                 return hex;
106
107         ret &= ~LP873X_LDO_VOLT_MASK;
108         ret |= hex;
109         if (*uV > 1650000)
110                 ret |= 0x80;
111         ret = pmic_reg_write(dev->parent, adr, ret);
112
113         return ret;
114 }
115
116 static int lp873x_ldo_probe(struct udevice *dev)
117 {
118         struct dm_regulator_uclass_plat *uc_pdata;
119
120         uc_pdata = dev_get_uclass_plat(dev);
121         uc_pdata->type = REGULATOR_TYPE_LDO;
122
123         int idx = dev->driver_data;
124         if (idx >= LP873X_LDO_NUM) {
125                 return -1;
126         }
127
128         uc_pdata->ctrl_reg = lp873x_ldo_ctrl[idx];
129         uc_pdata->volt_reg = lp873x_ldo_volt[idx];
130
131         return 0;
132 }
133
134 static int ldo_get_value(struct udevice *dev)
135 {
136         int uV;
137         int ret;
138
139         ret = lp873x_ldo_val(dev, PMIC_OP_GET, &uV);
140         if (ret)
141                 return ret;
142
143         return uV;
144 }
145
146 static int ldo_set_value(struct udevice *dev, int uV)
147 {
148         return lp873x_ldo_val(dev, PMIC_OP_SET, &uV);
149 }
150
151 static int ldo_get_enable(struct udevice *dev)
152 {
153         bool enable = false;
154         int ret;
155
156         ret = lp873x_ldo_enable(dev, PMIC_OP_GET, &enable);
157         if (ret)
158                 return ret;
159
160         return enable;
161 }
162
163 static int ldo_set_enable(struct udevice *dev, bool enable)
164 {
165         return lp873x_ldo_enable(dev, PMIC_OP_SET, &enable);
166 }
167
168 static const struct dm_regulator_ops lp873x_ldo_ops = {
169         .get_value  = ldo_get_value,
170         .set_value  = ldo_set_value,
171         .get_enable = ldo_get_enable,
172         .set_enable = ldo_set_enable,
173 };
174
175 U_BOOT_DRIVER(lp873x_ldo) = {
176         .name = LP873X_LDO_DRIVER,
177         .id = UCLASS_REGULATOR,
178         .ops = &lp873x_ldo_ops,
179         .probe = lp873x_ldo_probe,
180 };