summaryrefslogtreecommitdiff
path: root/driver/pmu_tps65090_powerinfo.c
blob: 3ab4fb26b3dd1ee1ca3801aa8608d64acb115f5a (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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 *
 * TPSChrome powerinfo commands.
 */

#include "battery.h"
#include "console.h"
#include "extpower.h"
#include "host_command.h"
#include "pmu_tpschrome.h"
#include "util.h"

/*
 * All these constants are specific to the Pit board.  If we reuse this command
 * on other boards, we'll need to move the table to board.c.
 */
static const struct {
	const char *name;
	int voltage_mv;
	int current_range_ma;
} pmu_fet[] = {
	{"backlight", 11400, 1100},
	{"video"    ,  5000,  220},
	{"wwan"     ,  3300, 3300},
	{"sdcard"   ,  3300, 1100},
	{"camera"   ,  3300, 1100},
	{"lcd"      ,  3300, 1100},
	{"video_add",  5000, 1100},
}, pmu_dcdc[] = {
	{"p5000", 5050, 5000},
	{"p3300", 3333, 5000},
	{"p1350", 1350, 5000},
};

/* These constants may be Pit-specific as well. */
static const int pmu_voltage_range_mv = 17000;
static const int pmu_ac_sense_range_mv = 33;
static const int pmu_bat_sense_range_mv = 40;
static const int pmu_adc_resolution = 1024;
static const int pmu_sense_resistor_bat = CONFIG_CHARGER_SENSE_RESISTOR;
static const int pmu_sense_resistor_ac = CONFIG_CHARGER_SENSE_RESISTOR_AC;

static inline int calc_voltage(int adc_value, int range_mv)
{
	return adc_value * range_mv / pmu_adc_resolution;
}

static inline int calc_current(int adc_value, int range_ma)
{
	return adc_value * range_ma / pmu_adc_resolution;
}

static inline int calc_current_sr(int adc_value, int sense_resistor_mohm,
				  int range_mv)
{
	return adc_value * range_mv * 1000 / sense_resistor_mohm /
		pmu_adc_resolution;
}

static int command_powerinfo(int argc, char **argv)
{
	int voltage, current;
	int index;

	ccputs("[pmu powerinfo]\n");
	/* DC to DC converter */
	for (index = 0; index < ARRAY_SIZE(pmu_dcdc); index++) {
		current = calc_current(
			pmu_adc_read(ADC_IDCDC1 + index, ADC_FLAG_KEEP_ON),
			pmu_dcdc[index].current_range_ma);
		voltage = pmu_dcdc[index].voltage_mv;
		ccprintf("DCDC%d:%6d mV,%4d mA,%4d mW %s\n",
			 index + 1, voltage, current, voltage * current / 1000,
			 pmu_dcdc[index].name);
	}

	/* FET */
	for (index = 0; index < ARRAY_SIZE(pmu_fet); index++) {
		current = calc_current(
			pmu_adc_read(ADC_IFET1 + index, ADC_FLAG_KEEP_ON),
			pmu_fet[index].current_range_ma);
		voltage = pmu_fet[index].voltage_mv;
		ccprintf("FET%d :%6d mV,%4d mA,%4d mW %s\n",
			 index + 1, voltage, current, voltage * current / 1000,
			 pmu_fet[index].name);
	}

	/* Battery charging */
	voltage = calc_voltage(
		pmu_adc_read(ADC_VBAT, ADC_FLAG_KEEP_ON),
		pmu_voltage_range_mv);
	current = calc_current_sr(
		pmu_adc_read(ADC_IBAT, ADC_FLAG_KEEP_ON),
		pmu_sense_resistor_bat, pmu_bat_sense_range_mv);
	ccprintf("Chg  :%6d mV,%4d mA,%4d mW\n", voltage, current,
		 voltage * current / 1000);

	/* AC input */
	voltage = calc_voltage(
		pmu_adc_read(ADC_VAC, ADC_FLAG_KEEP_ON),
		pmu_voltage_range_mv);
	current = calc_current_sr(
		pmu_adc_read(ADC_IAC, 0),
		pmu_sense_resistor_ac, pmu_ac_sense_range_mv);
	ccprintf("AC   :%6d mV,%4d mA,%4d mW\n", voltage, current,
		 voltage * current / 1000);


	return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(powerinfo, command_powerinfo,
		NULL,
		"Show PMU power info");

/**
 * Host command to get power info from PMU
 *
 * This reuses the same EC_CMD_POWER_INFO host command as Spring, but doesn't
 * provide the full set of information because Pit doesn't take power over USB.
 */
static int power_command_info(struct host_cmd_handler_args *args)
{
	struct ec_response_power_info *r = args->response;

	r->voltage_ac = calc_voltage(
		pmu_adc_read(ADC_VAC, ADC_FLAG_KEEP_ON),
		pmu_voltage_range_mv);
	if (extpower_is_present()) {
		/* Power source = AC */
		r->voltage_system = r->voltage_ac;
		r->current_system = calc_current_sr(
			pmu_adc_read(ADC_IAC, ADC_FLAG_KEEP_ON),
			pmu_sense_resistor_ac, pmu_ac_sense_range_mv);
	} else {
		/* Power source == battery */
		struct batt_params batt;

		r->voltage_system = calc_voltage(
			pmu_adc_read(ADC_VBAT, ADC_FLAG_KEEP_ON),
			pmu_voltage_range_mv);
		/*
		 * PMU reads charging current. When battery is discharging, ADC
		 * returns 0. Use battery gas gauge output instead.
		 */
		battery_get_params(&batt);
		r->current_system = -batt.current;
	}

	/* Ignore USB powerinfo fields. */
	r->usb_dev_type = 0;
	r->usb_current_limit = 0;

	args->response_size = sizeof(*r);

	return EC_RES_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_POWER_INFO, power_command_info, EC_VER_MASK(0));