Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/bdk/power/max17050.c
1476 views
1
/*
2
* Fuel gauge driver for Nintendo Switch's Maxim 17050
3
*
4
* Copyright (c) 2011 Samsung Electronics
5
* MyungJoo Ham <[email protected]>
6
* Copyright (c) 2018 CTCaer
7
*
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
12
*
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
17
*
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
*
22
* This driver is based on max17040_battery.c
23
*/
24
25
#include "max17050.h"
26
#include <soc/i2c.h>
27
#include <soc/timer.h>
28
29
#define BASE_SNS_UOHM 5000
30
31
/* Status register bits */
32
#define STATUS_POR_BIT BIT(1)
33
#define STATUS_BST_BIT BIT(3)
34
#define STATUS_VMN_BIT BIT(8)
35
#define STATUS_TMN_BIT BIT(9)
36
#define STATUS_SMN_BIT BIT(10)
37
#define STATUS_BI_BIT BIT(11)
38
#define STATUS_VMX_BIT BIT(12)
39
#define STATUS_TMX_BIT BIT(13)
40
#define STATUS_SMX_BIT BIT(14)
41
#define STATUS_BR_BIT BIT(15)
42
43
#define VFSOC0_LOCK 0x0000
44
#define VFSOC0_UNLOCK 0x0080
45
46
#define MAX17050_VMAX_TOLERANCE 50 /* 50 mV */
47
48
static u32 battery_voltage = 0;
49
u32 max17050_get_cached_batt_volt()
50
{
51
return battery_voltage;
52
}
53
54
static u16 max17050_get_reg(u8 reg)
55
{
56
u16 data = 0;
57
58
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, reg);
59
60
return data;
61
}
62
63
int max17050_get_property(enum MAX17050_reg reg, int *value)
64
{
65
u16 data;
66
67
switch (reg)
68
{
69
case MAX17050_Age: // Age (percent). Based on 100% x (FullCAP Register/DesignCap).
70
data = max17050_get_reg(MAX17050_Age);
71
*value = data >> 8; /* Show MSB. 1% increments */
72
break;
73
case MAX17050_Cycles: // Cycle count.
74
*value = max17050_get_reg(MAX17050_Cycles);
75
break;
76
case MAX17050_MinVolt: // Voltage max/min
77
data = max17050_get_reg(MAX17050_MinMaxVolt);
78
*value = (data & 0xff) * 20; /* Voltage MIN. Units of 20mV */
79
break;
80
case MAX17050_MaxVolt: // Voltage max/min
81
data = max17050_get_reg(MAX17050_MinMaxVolt);
82
*value = (data >> 8) * 20; /* Voltage MAX. Units of LSB = 20mV */
83
break;
84
case MAX17050_V_empty: // Voltage min design.
85
data = max17050_get_reg(MAX17050_V_empty);
86
*value = (data >> 7) * 10; /* Units of LSB = 10mV */
87
break;
88
case MAX17050_VCELL: // Voltage now.
89
data = max17050_get_reg(MAX17050_VCELL);
90
*value = (data >> 3) * 625 / 1000; /* Units of LSB = 0.625mV */
91
battery_voltage = *value;
92
break;
93
case MAX17050_AvgVCELL: // Voltage avg.
94
data = max17050_get_reg(MAX17050_AvgVCELL);
95
*value = (data >> 3) * 625 / 1000; /* Units of LSB = 0.625mV */
96
break;
97
case MAX17050_OCVInternal: // Voltage ocv.
98
data = max17050_get_reg(MAX17050_OCVInternal);
99
*value = (data >> 3) * 625 / 1000; /* Units of LSB = 0.625mV */
100
break;
101
case MAX17050_RepSOC: // Capacity %.
102
*value = max17050_get_reg(MAX17050_RepSOC);
103
break;
104
case MAX17050_DesignCap: // Charge full design.
105
data = max17050_get_reg(MAX17050_DesignCap);
106
*value = data * (BASE_SNS_UOHM / MAX17050_BOARD_SNS_RESISTOR_UOHM) / MAX17050_BOARD_CGAIN;
107
break;
108
case MAX17050_FullCAP: // Charge full.
109
data = max17050_get_reg(MAX17050_FullCAP);
110
*value = data * (BASE_SNS_UOHM / MAX17050_BOARD_SNS_RESISTOR_UOHM) / MAX17050_BOARD_CGAIN;
111
break;
112
case MAX17050_RepCap: // Charge now.
113
data = max17050_get_reg(MAX17050_RepCap);
114
*value = data * (BASE_SNS_UOHM / MAX17050_BOARD_SNS_RESISTOR_UOHM) / MAX17050_BOARD_CGAIN;
115
break;
116
case MAX17050_TEMP: // Temp.
117
data = max17050_get_reg(MAX17050_TEMP);
118
*value = (s16)data;
119
*value = *value * 10 / 256;
120
break;
121
case MAX17050_Current: // Current now.
122
data = max17050_get_reg(MAX17050_Current);
123
*value = (s16)data;
124
*value *= 1562500 / (MAX17050_BOARD_SNS_RESISTOR_UOHM * MAX17050_BOARD_CGAIN);
125
break;
126
case MAX17050_AvgCurrent: // Current avg.
127
data = max17050_get_reg(MAX17050_AvgCurrent);
128
*value = (s16)data;
129
*value *= 1562500 / (MAX17050_BOARD_SNS_RESISTOR_UOHM * MAX17050_BOARD_CGAIN);
130
break;
131
default:
132
return -1;
133
}
134
return 0;
135
}
136
137
static int _max17050_write_verify_reg(u8 reg, u16 value)
138
{
139
int retries = 8;
140
int ret;
141
u16 read_value;
142
143
do
144
{
145
ret = i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, reg, (u8 *)&value, 2);
146
read_value = max17050_get_reg(reg);
147
if (read_value != value)
148
{
149
ret = -1;
150
retries--;
151
}
152
} while (retries && read_value != value);
153
154
return ret;
155
}
156
157
static void _max17050_override_por(u8 reg, u16 value)
158
{
159
if (value)
160
i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, reg, (u8 *)&value, 2);
161
}
162
163
static void _max17050_load_new_capacity_params()
164
{
165
u16 fullcap, repSoc, dq_acc, dp_acc;
166
167
fullcap = 0x2476; // 4667mAh design capacity.
168
dq_acc = 0x10bc; // From a healthy fuel gauge.
169
dp_acc = 0x5e09; // =||=
170
repSoc = 0x6400; // 100%.
171
172
_max17050_write_verify_reg(MAX17050_RemCap, fullcap);
173
_max17050_write_verify_reg(MAX17050_RepCap, fullcap);
174
175
_max17050_write_verify_reg(MAX17050_dQacc, dq_acc);
176
_max17050_write_verify_reg(MAX17050_dPacc, dp_acc);
177
178
_max17050_write_verify_reg(MAX17050_FullCAP, fullcap);
179
//i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_DesignCap, (u8 *)&fullcap, 2);
180
_max17050_write_verify_reg(MAX17050_FullCAPNom, fullcap);
181
/* Update SOC register with new SOC */
182
i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_RepSOC, (u8 *)&repSoc, 2);
183
}
184
185
static void _max17050_reset_vfsoc0_reg()
186
{
187
u16 lockVal = 0;
188
u16 vfSoc = 0x6440; // >100% for fully charged battery
189
190
lockVal = VFSOC0_UNLOCK;
191
i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_VFSOC0Enable, (u8 *)&lockVal, 2);
192
193
_max17050_write_verify_reg(MAX17050_VFSOC0, vfSoc);
194
195
lockVal = VFSOC0_LOCK;
196
i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_VFSOC0Enable, (u8 *)&lockVal, 2);
197
}
198
199
static void _max17050_update_capacity_regs()
200
{
201
u16 value = 0x2476; // Set to 4667mAh design capacity.
202
_max17050_write_verify_reg(MAX17050_FullCAP, value);
203
_max17050_write_verify_reg(MAX17050_FullCAPNom, value);
204
//i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_DesignCap, config->design_cap, 2);
205
}
206
207
static void _max17050_write_config_regs()
208
{
209
u16 value = 0;
210
211
value = 0x7254;
212
i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_CONFIG, (u8 *)&value, 2);
213
value = 0x2473;
214
i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_LearnCFG, (u8 *)&value, 2);
215
//i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_FilterCFG, (u8 *)&value, 2)
216
//i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_RelaxCFG, (u8 *)&value, 2)
217
//i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_FullSOCThr, (u8 *)&value, 2)
218
}
219
220
/*
221
* Block write all the override values coming from platform data.
222
* This function MUST be called before the POR initialization proceedure
223
* specified by maxim.
224
*/
225
static void _max17050_override_por_values()
226
{
227
u16 dq_acc = 0x10bc; // From a healthy fuel gauge.
228
u16 dp_acc = 0x5e09; // =||=
229
230
_max17050_override_por(MAX17050_dQacc, dq_acc);
231
_max17050_override_por(MAX17050_dPacc, dp_acc);
232
233
//_max17050_override_por(MAX17050_RCOMP0, config->rcomp0); //0x58
234
//_max17050_override_por(MAX17050_TempCo, config->tcompc0); //0x1b22
235
236
//u16 k_empty0 = 0x439;
237
//_max17050_override_por(map, MAX17050_K_empty0, k_empty0); // Unknown cell data
238
}
239
240
static void _max17050_set_por_bit(u16 value)
241
{
242
_max17050_write_verify_reg(MAX17050_STATUS, value);
243
}
244
245
int max17050_fix_configuration()
246
{
247
/* Init phase, set the POR bit */
248
_max17050_set_por_bit(STATUS_POR_BIT);
249
250
/* Override POR values */
251
_max17050_override_por_values();
252
/* After Power up, the MAX17050 requires 500ms in order
253
* to perform signal debouncing and initial SOC reporting
254
*/
255
msleep(500);
256
257
/* Initialize configaration */
258
_max17050_write_config_regs();
259
260
/* update capacity params */
261
_max17050_update_capacity_regs();
262
263
/* delay must be atleast 350mS to allow VFSOC
264
* to be calculated from the new configuration
265
*/
266
msleep(350);
267
268
/* reset vfsoc0 reg */
269
_max17050_reset_vfsoc0_reg();
270
271
/* load new capacity params */
272
_max17050_load_new_capacity_params();
273
274
/* Init complete, Clear the POR bit */
275
//_max17050_set_por_bit(0); // Should we? Or let the switch to reconfigure POR?
276
277
// Sets POR, BI, BR.
278
_max17050_set_por_bit(0x8801);
279
280
return 0;
281
}
282
283
void max17050_dump_regs(void *buf)
284
{
285
u16 *buff = (u16 *)buf;
286
287
// Unlock model table.
288
u16 unlock = 0x59;
289
i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MODELEnable1, (u8 *)&unlock, 2);
290
unlock = 0xC4;
291
i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MODELEnable2, (u8 *)&unlock, 2);
292
293
// Dump all battery fuel gauge registers.
294
for (u32 i = 0; i < 0x100; i++)
295
{
296
buff[i] = max17050_get_reg(i);
297
msleep(1);
298
}
299
300
// Lock model table.
301
unlock = 0;
302
i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MODELEnable1, (u8 *)&unlock, 2);
303
i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MODELEnable2, (u8 *)&unlock, 2);
304
}
305
306