Files
OpenCellular/driver/charger/isl9237.c
Rong Chang 26410eedde charger: Add Intersil charger ISL9237
ISL9237 is a buck-boost narrow output voltage DC charger. This change
provides interfaces to satisfy external dependencies for
charge_state_v2.

ISL9237's charging voltage control is different from smart battery
chargers. And there's no SBC compatible charging mode and status. So
this CL modified charger_set_voltage() behavior by controlling VSYS
voltage.

BRANCH=none
BUG=none
TEST=ran on reworked glados

Signed-off-by: Rong Chang <rongchang@chromium.org>
Change-Id: Ibbbf805bbbe1ee06f87a41cde3e39acbf2e105b4
Reviewed-on: https://chromium-review.googlesource.com/272882
Reviewed-by: Alec Berg <alecaberg@chromium.org>
Commit-Queue: Aaron Durbin <adurbin@chromium.org>
Trybot-Ready: Aaron Durbin <adurbin@chromium.org>
Tested-by: Aaron Durbin <adurbin@chromium.org>
2015-06-08 21:49:02 +00:00

234 lines
4.7 KiB
C

/* Copyright 2015 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.
*
* Intersil ISL9237 battery charger driver.
*/
#include "battery.h"
#include "battery_smart.h"
#include "charger.h"
#include "console.h"
#include "common.h"
#include "i2c.h"
#include "isl9237.h"
#include "util.h"
#define DEFAULT_R_AC 20
#define DEFAULT_R_SNS 10
#define R_AC CONFIG_CHARGER_SENSE_RESISTOR_AC
#define R_SNS CONFIG_CHARGER_SENSE_RESISTOR
#define REG_TO_CURRENT(REG) ((REG) * DEFAULT_R_SNS / R_SNS)
#define CURRENT_TO_REG(CUR) ((CUR) * R_SNS / DEFAULT_R_SNS)
#define AC_REG_TO_CURRENT(REG) ((REG) * DEFAULT_R_AC / R_AC)
#define AC_CURRENT_TO_REG(CUR) ((CUR) * R_AC / DEFAULT_R_AC)
/* Charger parameters */
static const struct charger_info isl9237_charger_info = {
.name = CHARGER_NAME,
.voltage_max = CHARGE_V_MAX,
.voltage_min = CHARGE_V_MIN,
.voltage_step = CHARGE_V_STEP,
.current_max = REG_TO_CURRENT(CHARGE_I_MAX),
.current_min = REG_TO_CURRENT(CHARGE_I_MIN),
.current_step = REG_TO_CURRENT(CHARGE_I_STEP),
.input_current_max = AC_REG_TO_CURRENT(INPUT_I_MAX),
.input_current_min = AC_REG_TO_CURRENT(INPUT_I_MIN),
.input_current_step = AC_REG_TO_CURRENT(INPUT_I_STEP),
};
static inline int raw_read8(int offset, int *value)
{
return i2c_read8(I2C_PORT_CHARGER, I2C_ADDR_CHARGER, offset, value);
}
static inline int raw_read16(int offset, int *value)
{
return i2c_read16(I2C_PORT_CHARGER, I2C_ADDR_CHARGER, offset, value);
}
static inline int raw_write16(int offset, int value)
{
return i2c_write16(I2C_PORT_CHARGER, I2C_ADDR_CHARGER, offset, value);
}
static int isl9237_set_current(uint16_t current)
{
return raw_write16(ISL9237_REG_CHG_CURRENT, CURRENT_TO_REG(current));
}
static int isl9237_set_voltage(uint16_t voltage)
{
return raw_write16(ISL9237_REG_SYS_VOLTAGE_MAX, voltage);
}
/* chip specific interfaces */
int charger_set_input_current(int input_current)
{
int rv;
uint16_t reg = AC_CURRENT_TO_REG(input_current);
rv = raw_write16(ISL9237_REG_ADAPTER_CURRENT1, reg);
if (rv)
return rv;
return raw_write16(ISL9237_REG_ADAPTER_CURRENT2, reg);
}
int charger_get_input_current(int *input_current)
{
int rv;
int reg;
rv = raw_read16(ISL9237_REG_ADAPTER_CURRENT1, &reg);
if (rv)
return rv;
*input_current = AC_REG_TO_CURRENT(reg);
return EC_SUCCESS;
}
int charger_manufacturer_id(int *id)
{
int rv;
int reg;
rv = raw_read16(ISL9237_REG_MANUFACTURER_ID, &reg);
if (rv)
return rv;
*id = reg;
return EC_SUCCESS;
}
int charger_device_id(int *id)
{
int rv;
int reg;
rv = raw_read16(ISL9237_REG_DEVICE_ID, &reg);
if (rv)
return rv;
*id = reg;
return EC_SUCCESS;
}
int charger_get_option(int *option)
{
int rv;
uint32_t controls;
int reg;
rv = raw_read8(ISL9237_REG_CONTROL0, &reg);
if (rv)
return rv;
controls = reg;
rv = raw_read16(ISL9237_REG_CONTROL1, &reg);
if (rv)
return rv;
controls |= reg << 16;
*option = controls;
return EC_SUCCESS;
}
int charger_set_option(int option)
{
int rv;
uint16_t reg;
reg = option & 0xffff;
rv = raw_write16(ISL9237_REG_CONTROL0, reg);
if (rv)
return rv;
reg = (option >> 16) & 0xffff;
return raw_write16(ISL9237_REG_CONTROL1, reg);
}
/* Charger interfaces */
const struct charger_info *charger_get_info(void)
{
return &isl9237_charger_info;
}
int charger_get_status(int *status)
{
*status = CHARGER_LEVEL_2;
return EC_SUCCESS;
}
int charger_set_mode(int mode)
{
/* ISL9237 does not support inhibit mode setting. */
return EC_SUCCESS;
}
int charger_get_current(int *current)
{
int rv;
int reg;
rv = raw_read16(ISL9237_REG_CHG_CURRENT, &reg);
if (rv)
return rv;
*current = REG_TO_CURRENT(reg);
return EC_SUCCESS;
}
int charger_set_current(int current)
{
return isl9237_set_current(current);
}
int charger_get_voltage(int *voltage)
{
return raw_read16(ISL9237_REG_SYS_VOLTAGE_MAX, voltage);
}
int charger_set_voltage(int voltage)
{
/* The ISL9237 will drop voltage to as low as requested. As the
* charger state machine will pass in 0 voltage, protect the system
* voltage by capping to the minimum. The reason is that the ISL9237
* only can regulate the system voltage which will kill the board's
* power if below 0. */
if (voltage == 0) {
const struct battery_info *bi = battery_get_info();
voltage = bi->voltage_min;
}
return isl9237_set_voltage(voltage);
}
int charger_post_init(void)
{
return EC_SUCCESS;
}
int charger_discharge_on_ac(int enable)
{
int rv;
int control1;
rv = raw_read16(ISL9237_REG_CONTROL1, &control1);
if (rv)
return rv;
control1 &= ~ISL9237_C1_LEARN_MODE_AUTOEXIT;
if (enable)
control1 |= ISL9237_C1_LEARN_MODE_ENABLE;
else
control1 &= ~ISL9237_C1_LEARN_MODE_ENABLE;
return raw_write16(ISL9237_REG_CONTROL1, control1);
}