1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * (C) Copyright 2020 Rockchip Electronics Co., Ltd
4 *
5 */
6
7 #include <common.h>
8 #include <dm.h>
9 #include <i2c.h>
10 #include <power/fuel_gauge.h>
11
12 #define DIV(div) ((div) ? (div) : 1)
13 #define BAT_VOL_H 0x0078
14 #define BAT_VOL_L 0x0079
15 #define VCALIB0_H 0x0093
16 #define VCALIB0_L 0x0094
17 #define VCALIB1_H 0x0095
18 #define VCALIB1_L 0x0096
19 #define GG_CON 0x0056
20 #define VIRTUAL_POWER_VOL 3600
21 #define INSTANT_MODE 0x02
22
23 struct rk817_battery_device {
24 struct udevice *dev;
25 int voltage_k;
26 int voltage_b;
27 u32 virtual_power;
28 u32 bat_res_up;
29 u32 bat_res_down;
30 };
31
rk817_bat_read(struct rk817_battery_device * battery,u8 reg)32 static u8 rk817_bat_read(struct rk817_battery_device *battery, u8 reg)
33 {
34 int ret;
35 u8 buf;
36
37 ret = dm_i2c_read(battery->dev, reg, &buf, 1);
38 if (ret) {
39 printf("%s: read reg 0x%02x failed, ret=%d\n",
40 __func__, reg, ret);
41 return ret;
42 }
43
44 return buf;
45 }
46
rk817_bat_write(struct rk817_battery_device * battery,u8 reg,u8 buf)47 static int rk817_bat_write(struct rk817_battery_device *battery,
48 u8 reg, u8 buf)
49 {
50 int ret;
51
52 ret = dm_i2c_write(battery->dev, reg, &buf, 1);
53 if (ret) {
54 printf("%s: write reg 0x%02x failed, ret=%d\n",
55 __func__, reg, ret);
56 return ret;
57 }
58
59 return 0;
60 }
61
rk817_bat_get_vaclib0(struct rk817_battery_device * battery)62 static int rk817_bat_get_vaclib0(struct rk817_battery_device *battery)
63 {
64 int val = 0;
65
66 val |= rk817_bat_read(battery, VCALIB0_L) << 0;
67 val |= rk817_bat_read(battery, VCALIB0_H) << 8;
68
69 return val;
70 }
71
rk817_bat_get_vaclib1(struct rk817_battery_device * battery)72 static int rk817_bat_get_vaclib1(struct rk817_battery_device *battery)
73 {
74 int val = 0;
75
76 val |= rk817_bat_read(battery, VCALIB1_L) << 0;
77 val |= rk817_bat_read(battery, VCALIB1_H) << 8;
78
79 return val;
80 }
81
rk817_bat_init_voltage_kb(struct rk817_battery_device * battery)82 static void rk817_bat_init_voltage_kb(struct rk817_battery_device *battery)
83 {
84 int vcalib0, vcalib1;
85
86 vcalib0 = rk817_bat_get_vaclib0(battery);
87 vcalib1 = rk817_bat_get_vaclib1(battery);
88
89 battery->voltage_k = (1050 - 600) * 1000 / DIV(vcalib1 - vcalib0);
90 battery->voltage_b = 1050 - (battery->voltage_k * vcalib1) / 1000;
91 }
92
rk817_bat_get_battery_voltage(struct rk817_battery_device * battery)93 static int rk817_bat_get_battery_voltage(struct rk817_battery_device *battery)
94 {
95 int vol, val = 0;
96
97 val |= rk817_bat_read(battery, BAT_VOL_L) << 0;
98 val |= rk817_bat_read(battery, BAT_VOL_H) << 8;
99 vol = battery->voltage_k * val / 1000 + battery->voltage_b;
100
101 return (vol * battery->bat_res_up / battery->bat_res_down + vol);
102 }
103
rk817_bat_update_get_voltage(struct udevice * dev)104 static int rk817_bat_update_get_voltage(struct udevice *dev)
105 {
106 struct rk817_battery_device *battery = dev_get_priv(dev);
107
108 if (!battery->virtual_power && battery->voltage_k)
109 return rk817_bat_get_battery_voltage(battery);
110 else
111 return VIRTUAL_POWER_VOL;
112 }
113
114 static struct dm_fuel_gauge_ops fg_ops = {
115 .get_voltage = rk817_bat_update_get_voltage,
116 };
117
rk817_fg_ofdata_to_platdata(struct udevice * dev)118 static int rk817_fg_ofdata_to_platdata(struct udevice *dev)
119 {
120 struct rk817_battery_device *battery = dev_get_priv(dev);
121
122 battery->dev = dev;
123 battery->bat_res_up = dev_read_u32_default(dev, "bat_res_up", -1);
124 if (battery->bat_res_up < 0) {
125 printf("can't read bat_res_up\n");
126 return -EINVAL;
127 }
128
129 battery->bat_res_down = dev_read_u32_default(dev, "bat_res_down", -1);
130 if (battery->bat_res_down < 0) {
131 printf("can't read bat_res_down\n");
132 return -EINVAL;
133 }
134
135 battery->virtual_power = dev_read_u32_default(dev, "virtual_power", -1);
136
137 return 0;
138 }
139
rk817_fg_init(struct rk817_battery_device * battery)140 static int rk817_fg_init(struct rk817_battery_device *battery)
141 {
142 u8 val;
143
144 val = rk817_bat_read(battery, GG_CON);
145 if (!(val & INSTANT_MODE)) {
146 val |= INSTANT_MODE;
147 rk817_bat_write(battery, GG_CON, val);
148 }
149
150 rk817_bat_init_voltage_kb(battery);
151
152 return 0;
153 }
154
rk817_fg_probe(struct udevice * dev)155 static int rk817_fg_probe(struct udevice *dev)
156 {
157 return rk817_fg_init(dev_get_priv(dev));
158 }
159
160 static const struct udevice_id rk817_battery_ids[] = {
161 { .compatible = "rk817,battery" },
162 { }
163 };
164
165 U_BOOT_DRIVER(rk817_fg) = {
166 .name = "rk817_fg",
167 .id = UCLASS_FG,
168 .of_match = rk817_battery_ids,
169 .probe = rk817_fg_probe,
170 .ops = &fg_ops,
171 .ofdata_to_platdata = rk817_fg_ofdata_to_platdata,
172 .priv_auto_alloc_size = sizeof(struct rk817_battery_device),
173 };
174