diff options
Diffstat (limited to 'driver/bc12/mt6360.c')
-rw-r--r-- | driver/bc12/mt6360.c | 576 |
1 files changed, 0 insertions, 576 deletions
diff --git a/driver/bc12/mt6360.c b/driver/bc12/mt6360.c deleted file mode 100644 index 50aa4d0e45..0000000000 --- a/driver/bc12/mt6360.c +++ /dev/null @@ -1,576 +0,0 @@ -/* Copyright 2020 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. - */ - -#include "charger.h" -#include "charge_manager.h" -#include "console.h" -#include "crc8.h" -#include "mt6360.h" -#include "ec_commands.h" -#include "hooks.h" -#include "i2c.h" -#include "task.h" -#include "timer.h" -#include "usb_charge.h" -#include "usb_pd.h" -#include "util.h" - -/* Console output macros */ -#define CPRINTF(format, args...) cprintf(CC_CHARGER, format, ## args) -#define CPRINTS(format, args...) \ - cprints(CC_USBCHARGE, "%s " format, "MT6360", ## args) - -static enum ec_error_list mt6360_read8(int reg, int *val) -{ - return i2c_read8(mt6360_config.i2c_port, mt6360_config.i2c_addr_flags, - reg, val); -} - -static enum ec_error_list mt6360_write8(int reg, int val) -{ - return i2c_write8(mt6360_config.i2c_port, mt6360_config.i2c_addr_flags, - reg, val); -} - -static int mt6360_update_bits(int reg, int mask, int val) -{ - int rv; - int reg_val; - - rv = mt6360_read8(reg, ®_val); - if (rv) - return rv; - reg_val &= ~mask; - reg_val |= (mask & val); - rv = mt6360_write8(reg, reg_val); - return rv; -} - -static inline int mt6360_set_bit(int reg, int mask) -{ - return mt6360_update_bits(reg, mask, mask); -} - -static inline int mt6360_clr_bit(int reg, int mask) -{ - return mt6360_update_bits(reg, mask, 0x00); -} - -static int mt6360_get_bc12_device_type(void) -{ - int reg; - - if (mt6360_read8(MT6360_REG_USB_STATUS_1, ®)) - return CHARGE_SUPPLIER_NONE; - - switch (reg & MT6360_MASK_USB_STATUS) { - case MT6360_MASK_SDP: - CPRINTS("BC12 SDP"); - return CHARGE_SUPPLIER_BC12_SDP; - case MT6360_MASK_CDP: - CPRINTS("BC12 CDP"); - return CHARGE_SUPPLIER_BC12_CDP; - case MT6360_MASK_DCP: - CPRINTS("BC12 DCP"); - return CHARGE_SUPPLIER_BC12_DCP; - default: - CPRINTS("BC12 NONE"); - return CHARGE_SUPPLIER_NONE; - } -} - -static int mt6360_get_bc12_ilim(int charge_supplier) -{ - switch (charge_supplier) { - case CHARGE_SUPPLIER_BC12_DCP: - case CHARGE_SUPPLIER_BC12_CDP: - return USB_CHARGER_MAX_CURR_MA; - case CHARGE_SUPPLIER_BC12_SDP: - default: - return USB_CHARGER_MIN_CURR_MA; - } -} - -static int mt6360_enable_bc12_detection(int en) -{ - int rv; - - if (en) { -#ifdef CONFIG_MT6360_BC12_GPIO - gpio_set_level(GPIO_BC12_DET_EN, 1); -#endif - return mt6360_set_bit(MT6360_REG_DEVICE_TYPE, - MT6360_MASK_USBCHGEN); - } - - rv = mt6360_clr_bit(MT6360_REG_DEVICE_TYPE, MT6360_MASK_USBCHGEN); -#ifdef CONFIG_MT6360_BC12_GPIO - gpio_set_level(GPIO_BC12_DET_EN, 0); -#endif - return rv; -} - -static void mt6360_update_charge_manager(int port, - enum charge_supplier new_bc12_type) -{ - static enum charge_supplier current_bc12_type = CHARGE_SUPPLIER_NONE; - - if (new_bc12_type != current_bc12_type) { - if (current_bc12_type >= 0) - charge_manager_update_charge(current_bc12_type, port, - NULL); - - if (new_bc12_type != CHARGE_SUPPLIER_NONE) { - struct charge_port_info chg = { - .current = mt6360_get_bc12_ilim(new_bc12_type), - .voltage = USB_CHARGER_VOLTAGE_MV, - }; - - charge_manager_update_charge(new_bc12_type, port, &chg); - } - - current_bc12_type = new_bc12_type; - } -} - -static void mt6360_handle_bc12_irq(int port) -{ - int reg; - - mt6360_read8(MT6360_REG_DPDMIRQ, ®); - - if (reg & MT6360_MASK_DPDMIRQ_ATTACH) { - /* Check vbus again to avoid timing issue */ - if (pd_snk_is_vbus_provided(port)) - mt6360_update_charge_manager( - port, mt6360_get_bc12_device_type()); - else - mt6360_update_charge_manager( - 0, CHARGE_SUPPLIER_NONE); - } - - /* write clear */ - mt6360_write8(MT6360_REG_DPDMIRQ, reg); -} - -static void mt6360_usb_charger_task(const int port) -{ - mt6360_clr_bit(MT6360_REG_DPDM_MASK1, - MT6360_REG_DPDM_MASK1_CHGDET_DONEI_M); - mt6360_enable_bc12_detection(0); - - while (1) { - uint32_t evt = task_wait_event(-1); - - /* vbus change, start bc12 detection */ - if (evt & USB_CHG_EVENT_VBUS) { - if (pd_snk_is_vbus_provided(port)) - mt6360_enable_bc12_detection(1); - else - mt6360_update_charge_manager( - 0, CHARGE_SUPPLIER_NONE); - } - - /* detection done, update charge_manager and stop detection */ - if (evt & USB_CHG_EVENT_BC12) { - mt6360_handle_bc12_irq(port); - mt6360_enable_bc12_detection(0); - } - } -} - -/* Regulator: LDO & BUCK */ -static int mt6360_regulator_write8(uint8_t addr, int reg, int val) -{ - /* - * Note: The checksum from I2C_FLAG_PEC happens to be correct because - * length == 1 -> the high 3 bits of the offset byte is 0. - */ - return i2c_write8(mt6360_config.i2c_port, - addr | I2C_FLAG_PEC, reg, val); -} - -static int mt6360_regulator_read8(int addr, int reg, int *val) -{ - int rv; - uint8_t crc = 0, real_crc; - uint8_t out[3] = {(addr << 1) | 1, reg}; - - rv = i2c_read16(mt6360_config.i2c_port, addr, reg, val); - if (rv) - return rv; - - real_crc = (*val >> 8) & 0xFF; - *val &= 0xFF; - out[2] = *val; - crc = cros_crc8(out, ARRAY_SIZE(out)); - - if (crc != real_crc) - return EC_ERROR_CRC; - - return EC_SUCCESS; -} - -static int mt6360_regulator_update_bits(int addr, int reg, int mask, int val) -{ - int rv; - int reg_val = 0; - - rv = mt6360_regulator_read8(addr, reg, ®_val); - if (rv) - return rv; - reg_val &= ~mask; - reg_val |= (mask & val); - rv = mt6360_regulator_write8(addr, reg, reg_val); - return rv; -} - -struct mt6360_regulator_data { - const char *name; - const uint16_t *ldo_vosel_table; - uint16_t ldo_vosel_table_len; - uint8_t addr; - uint8_t reg_en_ctrl2; - uint8_t reg_ctrl3; - uint8_t mask_vosel; - uint8_t shift_vosel; - uint8_t mask_vocal; -}; - -static const uint16_t MT6360_LDO3_VOSEL_TABLE[16] = { - [0x4] = 1800, - [0xA] = 2900, - [0xB] = 3000, - [0xD] = 3300, -}; - -static const uint16_t MT6360_LDO5_VOSEL_TABLE[8] = { - [0x2] = 2900, - [0x3] = 3000, - [0x5] = 3300, -}; - -static const uint16_t MT6360_LDO6_VOSEL_TABLE[16] = { - [0x0] = 500, - [0x1] = 600, - [0x2] = 700, - [0x3] = 800, - [0x4] = 900, - [0x5] = 1000, - [0x6] = 1100, - [0x7] = 1200, - [0x8] = 1300, - [0x9] = 1400, - [0xA] = 1500, - [0xB] = 1600, - [0xC] = 1700, - [0xD] = 1800, - [0xE] = 1900, - [0xF] = 2000, -}; - -/* LDO7 VOSEL table is the same as LDO6's. */ -static const uint16_t *const MT6360_LDO7_VOSEL_TABLE = MT6360_LDO6_VOSEL_TABLE; -static const uint16_t MT6360_LDO7_VOSEL_TABLE_SIZE = - ARRAY_SIZE(MT6360_LDO6_VOSEL_TABLE); - -static const -struct mt6360_regulator_data regulator_data[MT6360_REGULATOR_COUNT] = { - [MT6360_LDO3] = { - .name = "mt6360_ldo3", - .ldo_vosel_table = MT6360_LDO3_VOSEL_TABLE, - .ldo_vosel_table_len = ARRAY_SIZE(MT6360_LDO3_VOSEL_TABLE), - .addr = MT6360_LDO_I2C_ADDR_FLAGS, - .reg_en_ctrl2 = MT6360_REG_LDO3_EN_CTRL2, - .reg_ctrl3 = MT6360_REG_LDO3_CTRL3, - .mask_vosel = MT6360_MASK_LDO3_VOSEL, - .shift_vosel = MT6360_MASK_LDO3_VOSEL_SHIFT, - .mask_vocal = MT6360_MASK_LDO3_VOCAL, - }, - [MT6360_LDO5] = { - .name = "mt6360_ldo5", - .ldo_vosel_table = MT6360_LDO5_VOSEL_TABLE, - .ldo_vosel_table_len = ARRAY_SIZE(MT6360_LDO5_VOSEL_TABLE), - .addr = MT6360_LDO_I2C_ADDR_FLAGS, - .reg_en_ctrl2 = MT6360_REG_LDO5_EN_CTRL2, - .reg_ctrl3 = MT6360_REG_LDO5_CTRL3, - .mask_vosel = MT6360_MASK_LDO5_VOSEL, - .shift_vosel = MT6360_MASK_LDO5_VOSEL_SHIFT, - .mask_vocal = MT6360_MASK_LDO5_VOCAL, - }, - [MT6360_LDO6] = { - .name = "mt6360_ldo6", - .ldo_vosel_table = MT6360_LDO6_VOSEL_TABLE, - .ldo_vosel_table_len = ARRAY_SIZE(MT6360_LDO6_VOSEL_TABLE), - .addr = MT6360_PMIC_I2C_ADDR_FLAGS, - .reg_en_ctrl2 = MT6360_REG_LDO6_EN_CTRL2, - .reg_ctrl3 = MT6360_REG_LDO6_CTRL3, - .mask_vosel = MT6360_MASK_LDO6_VOSEL, - .shift_vosel = MT6360_MASK_LDO6_VOSEL_SHIFT, - .mask_vocal = MT6360_MASK_LDO6_VOCAL, - }, - [MT6360_LDO7] = { - .name = "mt6360_ldo7", - .ldo_vosel_table = MT6360_LDO7_VOSEL_TABLE, - .ldo_vosel_table_len = MT6360_LDO7_VOSEL_TABLE_SIZE, - .addr = MT6360_PMIC_I2C_ADDR_FLAGS, - .reg_en_ctrl2 = MT6360_REG_LDO7_EN_CTRL2, - .reg_ctrl3 = MT6360_REG_LDO7_CTRL3, - .mask_vosel = MT6360_MASK_LDO7_VOSEL, - .shift_vosel = MT6360_MASK_LDO7_VOSEL_SHIFT, - .mask_vocal = MT6360_MASK_LDO7_VOCAL, - }, - [MT6360_BUCK1] = { - .name = "mt6360_buck1", - .addr = MT6360_PMIC_I2C_ADDR_FLAGS, - .reg_en_ctrl2 = MT6360_REG_BUCK1_EN_CTRL2, - .reg_ctrl3 = MT6360_REG_BUCK1_VOSEL, - .mask_vosel = MT6360_MASK_BUCK1_VOSEL, - .shift_vosel = MT6360_MASK_BUCK1_VOSEL_SHIFT, - .mask_vocal = MT6360_MASK_BUCK1_VOCAL, - }, - [MT6360_BUCK2] = { - .name = "mt6360_buck2", - .addr = MT6360_PMIC_I2C_ADDR_FLAGS, - .reg_en_ctrl2 = MT6360_REG_BUCK2_EN_CTRL2, - .reg_ctrl3 = MT6360_REG_BUCK2_VOSEL, - .mask_vosel = MT6360_MASK_BUCK2_VOSEL, - .shift_vosel = MT6360_MASK_BUCK2_VOSEL_SHIFT, - .mask_vocal = MT6360_MASK_BUCK2_VOCAL, - }, -}; - -static bool is_buck_regulator(const struct mt6360_regulator_data *data) -{ - /* There's no ldo_vosel_table, it's a buck. */ - return !(data->ldo_vosel_table); -} - -int mt6360_regulator_get_info(enum mt6360_regulator_id id, char *name, - uint16_t *num_voltages, uint16_t *voltages_mv) -{ - int i; - int cnt = 0; - const struct mt6360_regulator_data *data; - - if (id >= MT6360_REGULATOR_COUNT) - return EC_ERROR_INVAL; - data = ®ulator_data[id]; - - strzcpy(name, data->name, EC_REGULATOR_NAME_MAX_LEN); - - if (is_buck_regulator(data)) { - for (i = 0; i < MT6360_BUCK_VOSEL_MAX_STEP; ++i) { - int mv = MT6360_BUCK_VOSEL_MIN + - i * MT6360_BUCK_VOSEL_STEP_MV; - - if (cnt < EC_REGULATOR_VOLTAGE_MAX_COUNT) - voltages_mv[cnt++] = mv; - else - CPRINTS("%s voltage info overflow: %d-%d", - data->name, mv, MT6360_BUCK_VOSEL_MAX); - } - } else { - /* It's a LDO */ - for (i = 0; i < data->ldo_vosel_table_len; i++) { - int mv = data->ldo_vosel_table[i]; - - if (!mv) - continue; - if (cnt < EC_REGULATOR_VOLTAGE_MAX_COUNT) - voltages_mv[cnt++] = mv; - else - CPRINTS("%s voltage info overflow: %d", - data->name, mv); - } - } - - *num_voltages = cnt; - return EC_SUCCESS; -} - -int mt6360_regulator_enable(enum mt6360_regulator_id id, uint8_t enable) -{ - const struct mt6360_regulator_data *data; - - if (id >= MT6360_REGULATOR_COUNT) - return EC_ERROR_INVAL; - data = ®ulator_data[id]; - - if (enable) - return mt6360_regulator_update_bits( - data->addr, - data->reg_en_ctrl2, - MT6360_MASK_RGL_SW_OP_EN | MT6360_MASK_RGL_SW_EN, - MT6360_MASK_RGL_SW_OP_EN | MT6360_MASK_RGL_SW_EN); - else - return mt6360_regulator_update_bits( - data->addr, - data->reg_en_ctrl2, - MT6360_MASK_RGL_SW_OP_EN | MT6360_MASK_RGL_SW_EN, - MT6360_MASK_RGL_SW_OP_EN); -} - -int mt6360_regulator_is_enabled(enum mt6360_regulator_id id, uint8_t *enabled) -{ - int rv; - int value; - const struct mt6360_regulator_data *data; - - if (id >= MT6360_REGULATOR_COUNT) - return EC_ERROR_INVAL; - data = ®ulator_data[id]; - - rv = mt6360_regulator_read8(data->addr, data->reg_en_ctrl2, &value); - if (rv) { - CPRINTS("Error reading %s enabled: %d", data->name, rv); - return rv; - } - *enabled = !!(value & MT6360_MASK_RGL_SW_EN); - return EC_SUCCESS; -} - -int mt6360_regulator_set_voltage(enum mt6360_regulator_id id, int min_mv, - int max_mv) -{ - int i; - const struct mt6360_regulator_data *data; - - if (id >= MT6360_REGULATOR_COUNT) - return EC_ERROR_INVAL; - data = ®ulator_data[id]; - - if (is_buck_regulator(data)) { - int mv; - int step; - - if (max_mv < MT6360_BUCK_VOSEL_MIN) - goto error; - - if (min_mv > MT6360_BUCK_VOSEL_MAX) - goto error; - - mv = DIV_ROUND_UP((min_mv + max_mv) / 2, - MT6360_BUCK_VOSEL_STEP_MV) * - MT6360_BUCK_VOSEL_STEP_MV; - mv = MIN(MAX(mv, MT6360_BUCK_VOSEL_MIN), MT6360_BUCK_VOSEL_MAX); - - step = (mv - MT6360_BUCK_VOSEL_MIN) / MT6360_BUCK_VOSEL_STEP_MV; - - return mt6360_regulator_update_bits(data->addr, - data->reg_ctrl3, - data->mask_vosel, step); - } - - /* It's a LDO. */ - for (i = 0; i < data->ldo_vosel_table_len; i++) { - int mv = data->ldo_vosel_table[i]; - int step = 0; - - if (!mv) - continue; - if (mv + MT6360_LDO_VOCAL_STEP_MV * MT6360_LDO_VOCAL_MAX_STEP < - min_mv) - continue; - if (mv < min_mv) - step = DIV_ROUND_UP(min_mv - mv, - MT6360_LDO_VOCAL_STEP_MV); - if (mv + step * MT6360_LDO_VOCAL_STEP_MV > max_mv) - continue; - return mt6360_regulator_update_bits( - data->addr, - data->reg_ctrl3, - data->mask_vosel | data->mask_vocal, - (i << data->shift_vosel) | step); - } - -error: - CPRINTS("%s voltage %d - %d out of range", data->name, min_mv, max_mv); - return EC_ERROR_INVAL; -} - -int mt6360_regulator_get_voltage(enum mt6360_regulator_id id, int *voltage_mv) -{ - int value; - int rv; - const struct mt6360_regulator_data *data; - - if (id >= MT6360_REGULATOR_COUNT) - return EC_ERROR_INVAL; - data = ®ulator_data[id]; - - rv = mt6360_regulator_read8(data->addr, data->reg_ctrl3, &value); - if (rv) { - CPRINTS("Error reading %s ctrl3: %d", data->name, rv); - return rv; - } - - /* BUCK */ - if (is_buck_regulator(data)) { - *voltage_mv = MT6360_BUCK_VOSEL_MIN + - value * MT6360_BUCK_VOSEL_STEP_MV; - return EC_SUCCESS; - } - - /* LDO */ - *voltage_mv = data->ldo_vosel_table[(value & data->mask_vosel) >> - data->shift_vosel]; - if (*voltage_mv == 0) { - CPRINTS("Unknown %s voltage value: %d", data->name, value); - return EC_ERROR_INVAL; - } - *voltage_mv += - MIN(MT6360_LDO_VOCAL_MAX_STEP, value & data->mask_vocal) * - MT6360_LDO_VOCAL_STEP_MV; - return EC_SUCCESS; -} - -/* RGB LED */ -void mt6360_led_init(void) -{ - /* Enable LED1 software mode */ - mt6360_set_bit(MT6360_REG_RGB_EN, MT6360_ISINK1_CHRIND_EN_SEL); -} -DECLARE_HOOK(HOOK_INIT, mt6360_led_init, HOOK_PRIO_DEFAULT); - -int mt6360_led_enable(enum mt6360_led_id led_id, int enable) -{ - if (!IN_RANGE(led_id, 0, MT6360_LED_COUNT)) - return EC_ERROR_INVAL; - - if (enable) - return mt6360_set_bit(MT6360_REG_RGB_EN, - MT6360_MASK_ISINK_EN(led_id)); - return mt6360_clr_bit(MT6360_REG_RGB_EN, MT6360_MASK_ISINK_EN(led_id)); -} - -int mt6360_led_set_brightness(enum mt6360_led_id led_id, int brightness) -{ - int val; - - if (!IN_RANGE(led_id, 0, MT6360_LED_COUNT)) - return EC_ERROR_INVAL; - if (!IN_RANGE(brightness, 0, 16)) - return EC_ERROR_INVAL; - - RETURN_ERROR(mt6360_read8(MT6360_REG_RGB_ISINK(led_id), &val)); - val &= ~MT6360_MASK_CUR_SEL; - val |= brightness; - - return mt6360_write8(MT6360_REG_RGB_ISINK(led_id), val); -} - -const struct bc12_drv mt6360_drv = { - .usb_charger_task = mt6360_usb_charger_task, -}; - -#ifdef CONFIG_BC12_SINGLE_DRIVER -/* provide a default bc12_ports[] for backward compatibility */ -struct bc12_config bc12_ports[CHARGE_PORT_COUNT] = { - [0 ... (CHARGE_PORT_COUNT - 1)] = { - .drv = &mt6360_drv, - }, -}; -#endif /* CONFIG_BC12_SINGLE_DRIVER */ |