diff options
Diffstat (limited to 'driver/charger/isl9237.c')
-rw-r--r-- | driver/charger/isl9237.c | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/driver/charger/isl9237.c b/driver/charger/isl9237.c new file mode 100644 index 0000000000..29257f85f7 --- /dev/null +++ b/driver/charger/isl9237.c @@ -0,0 +1,233 @@ +/* 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, ®); + 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, ®); + 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, ®); + 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, ®); + if (rv) + return rv; + + controls = reg; + rv = raw_read16(ISL9237_REG_CONTROL1, ®); + 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, ®); + 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); +} + |