aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power/max17047_config.c
blob: 71208867dd19d46a0988a198a6c096b0b6a0fdef (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/*
 *  max17047_config.c
 *  fuel-gauge systems for lithium-ion (Li+) batteries
 *
 *  Copyright (C) 2012 Hardkernel
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/power_supply.h>
#include <linux/power/max17047_battery.h>
#include <linux/slab.h>

const	unsigned short	CustomModel[] = {
	// Write Start Reg 0x80
	0x8AE0,	0xB5A0,	0xB990,	0xBA20,	0xBA90,	0xBAF0,	0xBB60,	0xBC40,	
	0xBD40,	0xBF50,	0xC080,	0xC310,	0xC5D0,	0xC970,	0xCCF0,	0xD0D0,	
	
	// Write Start Reg 0x90
	0x0080,	0x0600,	0x2900,	0x0020,	0x3B00,	0x3C60,	0x1840,	0x10B0,
	0x1800,	0x1600,	0x0E20,	0x0AC0,	0x0B60,	0x07B0,	0x08E0,	0x08E0,

	// Write Start Reg 0xA0
	0x0100,	0x0100,	0x0100,	0x0100,	0x0100,	0x0100,	0x0100,	0x0100,
	0x0100,	0x0100,	0x0100,	0x0100,	0x0100,	0x0100,	0x0100,	0x0100,
};

const	unsigned short	RCOMP0		= 0x0082;
const	unsigned short	TempCo		= 0x041D;
const	unsigned short	ICHGTerm	= 0x0166;
const	unsigned short	V_empty		= 0xACDA;
const	unsigned short	QRTable00	= 0x3F80;
const	unsigned short	QRTable10	= 0x2C80;
const	unsigned short	QRTable20	= 0x1A04;
const	unsigned short	QRTable30	= 0x1905;
const	unsigned short	Capacity	= 0x2F22;
const	unsigned short	TGAIN		= 0xE3E1;
const	unsigned short	TOFF		= 0x290E;

static int max17047_read_reg(struct i2c_client *client, u8 reg)
{
	int ret;

	ret = i2c_smbus_read_word_data(client, reg);

	if (ret < 0)
		dev_err(&client->dev, "%s: err %d\n", __func__, ret);

	return ret;
}

static int max17047_write_reg(struct i2c_client *client, u8 reg, u16 value)
{
	int ret;

	ret = i2c_smbus_write_word_data(client, reg, value);

	if (ret < 0)
		dev_err(&client->dev, "%s: err %d\n", __func__, ret);

	return ret;
}

static int max17047_write_verify(struct i2c_client *client, u8 reg, u16 value)
{
	int ret;

	ret = i2c_smbus_write_word_data(client, reg, value);

	if (ret < 0)
		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
		
	ret = i2c_smbus_read_word_data(client, reg);
	
	if (ret < 0)
		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
		
	if(ret == value)	return	0;

	dev_err(&client->dev, "%s : reg(0x%02X) write(0x%04X) read(0x%04X)\n", __func__, reg, value, ret);
	
	return ret;
}

static int max17047_reset_check(struct i2c_client *client)
{
	return	(max17047_read_reg(client, 0x00) & 0x0002);
}

void max17047_set_config(struct i2c_client *client)
{
	int		cnt, VFSOC, FullCap0, RemCap, RepCap, dQ_acc, Status;
	
	if(!max17047_reset_check(client))		return;
	
restart:
	// 1. Delay 500ms
	mdelay(500);
	// 2. Initialize Configuration
	max17047_write_reg(client, 0x2A, 0x506B);	// Write RelaxCFG
	max17047_write_reg(client, 0x1D, 0x2210);	// Write CONFIG(10kohm thermistor from battery pack)
	max17047_write_reg(client, 0x29, 0x87A2);	// Write FilterCFG
	max17047_write_reg(client, 0x28, 0x2607);	// Write LearnCFG
	max17047_write_reg(client, 0x13, 0x5F00);	// Write FullSOCthr=95%
	// LOAD CUSTOM MODEL AND PARAMETERS
	// 4. Unlock Model Access
	max17047_write_reg(client, 0x62, 0x0059);	// Unlock Model Access
	max17047_write_reg(client, 0x63, 0x00C4);
	// 5. Write/Read/Verify the Custom Model
write_custom_model:	
	for(cnt = 0; cnt < sizeof(CustomModel)/sizeof(CustomModel[0]); cnt++)	{
		if(max17047_write_verify(client, 0x80 + cnt, CustomModel[cnt]))	goto write_custom_model;
	}
	
	// 8. Lock Model Access	
lock_model:	
	max17047_write_reg(client, 0x62, 0x0000);
	max17047_write_reg(client, 0x63, 0x0000);
	
	for(cnt = 0; cnt < sizeof(CustomModel)/sizeof(CustomModel[0]); cnt++)	{
		if(max17047_read_reg(client, 0x80 + cnt) != 0x0000)	goto lock_model;
	}

	// 10. Write Custom Parameters
	max17047_write_verify(client, 0x38, RCOMP0);	// Write and Verify RCOMP0 = 0082h
	max17047_write_verify(client, 0x39, TempCo);	// Write and Verify TempCo = 041Dh
	max17047_write_reg(client, 0x1E, ICHGTerm);		// Write ICHGTerm = 0166h
	max17047_write_verify(client, 0x3A, V_empty);	// Write and Verify Vempty = ACDAh
	max17047_write_verify(client, 0x12, QRTable00);	// Write and Verify QRTable00 = 3F80h
	max17047_write_verify(client, 0x22, QRTable10);	// Write and Verify QRTable10 = 2C80h
	max17047_write_verify(client, 0x32, QRTable20);	// Write and Verify QRTable20 = 1A04h
	max17047_write_verify(client, 0x42, QRTable30);	// Write and Verify QRTable30 = 1905h

	// 11. Update Full Capacity Parameters
	// Capacity is value provide by Maxim. (Capacity = 6033 x 2 = 2F22h)
	max17047_write_verify(client, 0x10, Capacity);	// Write and Verify FullCap
	max17047_write_reg(client, 0x18, Capacity);		// Write DesignCap
	max17047_write_verify(client, 0x23, Capacity);	// Write and Verify FullCapNom

	// 13. Delay at least 350ms
	mdelay(350);
	
	// 14. Write VFSOC value to VFSOC0
	VFSOC = max17047_read_reg(client, 0xFF);		// read VFSOC
	max17047_write_reg(client, 0x60, 0x0080);		// Enable Write Access to VFSOC0
	max17047_write_verify(client, 0x48, VFSOC);		// Write and Verify VFSOC0
	max17047_write_reg(client, 0x60, 0x0000);		// Disable Write Access to VFSOC0

	// 15. Advance to Coulomb-Counter Mode
	// To advance to Coulomb-Counter Mode, simply write the Cycle register to value of 96% for MAX17047
	max17047_write_verify(client, 0x17, 0x0060);

	// 16, Load New Capacity Parameters
	// VFSOC was read in step 14
	FullCap0 = max17047_read_reg(client, 0x35);		// Read FullCap0
	RemCap = (VFSOC * FullCap0) / 25600;
	max17047_write_verify(client, 0x0F, RemCap);	// Write and Verify RemCap
	RepCap = RemCap;
	max17047_write_verify(client, 0x05, RepCap);	// Write and Verify RepCap
	// Write dQ_acc to 200% of Capacity and dP_acc to 200%
	dQ_acc = (Capacity / 4);
	max17047_write_verify(client, 0x45, dQ_acc);	// Write and Verify dQ_acc
	max17047_write_verify(client, 0x46, 0x3200);	// Write and Verify dP_acc
	max17047_write_verify(client, 0x10, Capacity);	// Write and Verify FullCap
	max17047_write_reg(client, 0x18, Capacity);		// Write DesignCap
	max17047_write_verify(client, 0x23, Capacity);	// Write and Verify FullCapNom

	// 16.1 Set Gain and Offset Register Values
	max17047_write_reg(client, 0x2C, TGAIN);		// Write TGAIN = E3E1h
	max17047_write_reg(client, 0x2D, TOFF);			// Write TOFF = 290Eh

	// 17. Initialization Complet
	// Clear the POR & Bi bit to indicate that the custom model and parameters were successfully loaded.
	Status = max17047_read_reg(client, 0x00);		// Read Status
	max17047_write_verify(client, 0x00, Status & 0xFFFD);	// Write and Verify Status with POR bit Cleared
	
	// 17.5 Check for MAX17047 Reset
	Status = max17047_read_reg(client, 0x00);		// Read Status
	if(Status & 0x0002)		goto restart;
}