summaryrefslogtreecommitdiffstats
path: root/drivers/power/mfd/fg_max77693.c
blob: 983a6d4a2bde6d815f18fe5c1b2950a328eed5dc (plain)
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
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2013 Samsung Electronics
 * Piotr Wilczek <p.wilczek@samsung.com>
 */

#include <common.h>
#include <log.h>
#include <power/pmic.h>
#include <power/max77693_fg.h>
#include <i2c.h>
#include <power/power_chrg.h>
#include <power/battery.h>
#include <power/fg_battery_cell_params.h>
#include <errno.h>

static int max77693_get_vcell(u32 *vcell)
{
	u16 value;
	u8 ret;

	ret = i2c_read(MAX77693_FUEL_I2C_ADDR, MAX77693_VCELL, 1,
		       (u8 *)&value, 2);
	if (ret)
		return ret;

	*vcell = (u32)(value >> 3);
	*vcell = *vcell * 625;

	return 0;
}

static int max77693_get_soc(u32 *soc)
{
	u16 value;
	u8 ret;

	ret = i2c_read(MAX77693_FUEL_I2C_ADDR, MAX77693_VFSOC, 1,
		       (u8 *)&value, 2);
	if (ret)
		return ret;

	*soc = (u32)(value >> 8);

	return 0;
}

static int power_update_battery(struct pmic *p, struct pmic *bat)
{
	struct power_battery *pb = bat->pbat;
	int ret;

	if (pmic_probe(p)) {
		puts("Can't find max77693 fuel gauge\n");
		return -ENODEV;
	}

	ret = max77693_get_soc(&pb->bat->state_of_chrg);
	if (ret)
		return ret;

	max77693_get_vcell(&pb->bat->voltage_uV);

	return 0;
}

static int power_check_battery(struct pmic *p, struct pmic *bat)
{
	struct power_battery *pb = bat->pbat;
	unsigned int val;
	int ret = 0;

	if (pmic_probe(p)) {
		puts("Can't find max77693 fuel gauge\n");
		return -ENODEV;
	}

	ret = pmic_reg_read(p, MAX77693_STATUS, &val);
	if (ret)
		return ret;
	debug("fg status: 0x%x\n", val);

	ret = pmic_reg_read(p, MAX77693_VERSION, &pb->bat->version);
	if (ret)
		return ret;

	ret = power_update_battery(p, bat);
	if (ret)
		return ret;
	debug("fg ver: 0x%x\n", pb->bat->version);
	printf("BAT: state_of_charge(SOC):%d%%\n",
	       pb->bat->state_of_chrg);

	printf("     voltage: %d.%6.6d [V] (expected to be %d [mAh])\n",
	       pb->bat->voltage_uV / 1000000,
	       pb->bat->voltage_uV % 1000000,
	       pb->bat->capacity);

	if (pb->bat->voltage_uV > 3850000)
		pb->bat->state = EXT_SOURCE;
	else if (pb->bat->voltage_uV < 3600000 || pb->bat->state_of_chrg < 5)
		pb->bat->state = CHARGE;
	else
		pb->bat->state = NORMAL;

	return 0;
}

static struct power_fg power_fg_ops = {
	.fg_battery_check = power_check_battery,
	.fg_battery_update = power_update_battery,
};

int power_fg_init(unsigned char bus)
{
	static const char name[] = "MAX77693_FG";
	struct pmic *p = pmic_alloc();

	if (!p) {
		printf("%s: POWER allocation error!\n", __func__);
		return -ENOMEM;
	}

	debug("Board Fuel Gauge init\n");

	p->name = name;
	p->interface = PMIC_I2C;
	p->number_of_regs = FG_NUM_OF_REGS;
	p->hw.i2c.addr = MAX77693_FUEL_I2C_ADDR;
	p->hw.i2c.tx_num = 2;
	p->sensor_byte_order = PMIC_SENSOR_BYTE_ORDER_BIG;
	p->bus = bus;

	p->fg = &power_fg_ops;

	return 0;
}