1 /*
2  * Copyright (C) 2020 allwinnertech Ltd.
3  */
4 
5 #include <ffs.h>
6 #include <log.h>
7 #include <stddef.h>
8 #include <sunxi_hal_regulator.h>
9 #include <sunxi_hal_regulator_private.h>
10 
voltage2val(struct regulator_desc * info,int voltage,u8 * reg_val)11 static int voltage2val(struct regulator_desc *info, int voltage, u8 *reg_val)
12 {
13     const struct regulator_linear_range *range;
14     int i;
15 
16     if (!info->linear_ranges) {
17         *reg_val = (voltage - info->min_uv + info->step1_uv - 1)
18             / info->step1_uv;
19         return 0;
20     }
21 
22     for (i = 0; i < info->n_linear_ranges; i++) {
23         int linear_max_uV;
24 
25         range = &info->linear_ranges[i];
26         linear_max_uV = range->min_uV +
27             (range->max_sel - range->min_sel) * range->uV_step;
28 
29         if (!(voltage <= linear_max_uV && voltage >= range->min_uV))
30             continue;
31 
32         /* range->uV_step == 0 means fixed voltage range */
33         if (range->uV_step == 0) {
34             *reg_val = 0;
35         } else {
36             *reg_val = (voltage - range->min_uV) / range->uV_step;
37         }
38 
39         *reg_val += range->min_sel;
40         return 0;
41     }
42 
43     return -1;
44 }
45 
val2voltage(struct regulator_desc * info,u8 reg_val,int * voltage)46 static int val2voltage(struct regulator_desc *info, u8 reg_val, int *voltage)
47 {
48     const struct regulator_linear_range *range = info->linear_ranges;
49     int i;
50 
51     if (!info->linear_ranges) {
52         *voltage = info->min_uv + info->step1_uv * reg_val;
53         return 0;
54     }
55 
56     for (i = 0; i < info->n_linear_ranges; i++, range++) {
57         if (!(reg_val <= range->max_sel && reg_val >= range->min_sel))
58             continue;
59 
60         *voltage = (reg_val - range->min_sel) * range->uV_step +
61                range->min_uV;
62         return 0;
63     }
64 
65     return -1;
66 }
67 
axp_regulator_set_voltage(struct regulator_dev * rdev,int target_uV)68 static int axp_regulator_set_voltage(struct regulator_dev *rdev, int target_uV)
69 {
70     unsigned char id = REGULATOR_ID(rdev->flag);
71     struct regulator_desc *pd = (struct regulator_desc *)rdev->private;
72     struct regulator_desc *info = &pd[id];
73     u8 val;
74 
75     if (voltage2val(info, target_uV, &val))
76         return -1;
77 
78     val <<= ffs(info->vol_mask) - 1;
79     return hal_axp_byte_update(rdev, info->vol_reg, val, info->vol_mask);
80 }
81 
axp_regulator_get_voltage(struct regulator_dev * rdev,int * vol_uV)82 static int axp_regulator_get_voltage(struct regulator_dev *rdev, int *vol_uV)
83 {
84     unsigned char id = REGULATOR_ID(rdev->flag);
85     struct regulator_desc *pd = (struct regulator_desc *)rdev->private;
86     struct regulator_desc *info = &pd[id];
87     u8 val;
88     int ret;
89 
90     ret = hal_axp_byte_read(rdev, info->vol_reg, &val);
91     if (ret)
92         return ret;
93 
94     val &= info->vol_mask;
95     val >>= ffs(info->vol_mask) - 1;
96     if (val2voltage(info, val, vol_uV))
97         return -1;
98 
99     return 0;
100 }
101 
axp_regulator_enable(struct regulator_dev * rdev)102 static int axp_regulator_enable(struct regulator_dev *rdev)
103 {
104     unsigned char id = REGULATOR_ID(rdev->flag);
105     struct regulator_desc *pd = (struct regulator_desc *)rdev->private;
106     struct regulator_desc *info = &pd[id];
107     u8 reg_val = 0;
108 
109     reg_val = info->enable_val;
110     if (!reg_val)
111         reg_val = info->enable_mask;
112 
113     return hal_axp_byte_update(rdev, info->enable_reg,
114                    reg_val, info->enable_mask);
115 }
116 
axp_regulator_disable(struct regulator_dev * rdev)117 static int axp_regulator_disable(struct regulator_dev *rdev)
118 {
119     unsigned char id = REGULATOR_ID(rdev->flag);
120     struct regulator_desc *pd = (struct regulator_desc *)rdev->private;
121     struct regulator_desc *info = &pd[id];
122     u8 reg_val = 0;
123 
124     reg_val = info->disable_val;
125     if (!reg_val)
126         reg_val = ~info->enable_mask;
127 
128     return hal_axp_byte_update(rdev, info->enable_reg,
129                    reg_val, info->enable_mask);
130 }
131 
132 struct regulator_ops axp_regulator_ops = {
133     .set_voltage    = axp_regulator_set_voltage,
134     .get_voltage    = axp_regulator_get_voltage,
135     .enable     = axp_regulator_enable,
136     .disable    = axp_regulator_disable,
137 };
138